mirror of
https://github.com/SlimeVR/SlimeVR-Tracker-ESP.git
synced 2026-04-06 02:01:57 +02:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcb2ad31f0 | ||
|
|
939ad705ce | ||
|
|
7d800efdbf | ||
|
|
12f4b22dac | ||
|
|
6cd29c7cea | ||
|
|
33dc84c00b | ||
|
|
37658155c7 | ||
|
|
c12c475fe0 | ||
|
|
a6aefdfe60 | ||
|
|
8469b6fac6 | ||
|
|
fcd49515e1 | ||
|
|
e6af00b161 | ||
|
|
cc42ad0aa9 | ||
|
|
afd376c427 | ||
|
|
72ce713079 | ||
|
|
060df4baec | ||
|
|
2a66d12031 | ||
|
|
79d2796039 | ||
|
|
c84e898d1e | ||
|
|
b6cec9cc10 | ||
|
|
2970f4e38d | ||
|
|
003128c3b6 | ||
|
|
91b6318a8a | ||
|
|
a17c1c2d3f | ||
|
|
61ab745b38 | ||
|
|
02df66129c | ||
|
|
f5c9648fbd | ||
|
|
106f00cf26 | ||
|
|
96b6b7acec | ||
|
|
1ddbcd4855 | ||
|
|
c07319f37f | ||
|
|
23390ddb39 | ||
|
|
1a7619e2e6 | ||
|
|
ba1da6054b | ||
|
|
a8e689784f | ||
|
|
51c7d15a8b |
10
.github/workflows/actions.yml
vendored
10
.github/workflows/actions.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: jidicula/clang-format-action@v4.14.0
|
||||
with:
|
||||
clang-format-version: "17"
|
||||
@@ -33,8 +33,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
~/.cache/pip
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
run: git fetch --tags origin --recurse-submodules=no --force
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
run: python ./ci/build.py
|
||||
|
||||
- name: Upload binaries
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: binaries
|
||||
path: ./build/*.bin
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,3 +5,6 @@ venv/
|
||||
cache/
|
||||
.idea/
|
||||
compile_commands.json
|
||||
node_modules/
|
||||
dist/
|
||||
.nix-platformio
|
||||
|
||||
590
board-defaults.json
Normal file
590
board-defaults.json
Normal file
@@ -0,0 +1,590 @@
|
||||
{
|
||||
"$schema": "board-defaults.schema.json",
|
||||
"toolchain": "platformio",
|
||||
"defaults": {
|
||||
"BOARD_SLIMEVR": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "16",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "12",
|
||||
"sda": "14"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "13",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "12",
|
||||
"sda": "14"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 10,
|
||||
"r2": 40.2,
|
||||
"shieldR": 0,
|
||||
"pin": "17"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "2",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 0,
|
||||
"needBootPress": true,
|
||||
"needManualReboot": true,
|
||||
"shouldOnlyUseDefaults": true
|
||||
}
|
||||
},
|
||||
"BOARD_SLIMEVR_V1_2": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "SPI",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "2",
|
||||
"cs": "15",
|
||||
"rotation": "DEG_270"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "16",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "5",
|
||||
"sda": "4"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 10,
|
||||
"r2": 40.2,
|
||||
"shieldR": 0,
|
||||
"pin": "17"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "2",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 0,
|
||||
"needBootPress": true,
|
||||
"needManualReboot": true,
|
||||
"shouldOnlyUseDefaults": true
|
||||
}
|
||||
},
|
||||
"BOARD_SLIMEVR_DEV": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "10",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "5",
|
||||
"sda": "4"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "13",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "5",
|
||||
"sda": "4"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 10,
|
||||
"r2": 40.2,
|
||||
"shieldR": 0,
|
||||
"pin": "17"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "2",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 0,
|
||||
"needBootPress": true,
|
||||
"needManualReboot": true,
|
||||
"shouldOnlyUseDefaults": true
|
||||
}
|
||||
},
|
||||
"BOARD_WEMOSD1MINI": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "D5",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "D1",
|
||||
"sda": "D2"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_AUTO",
|
||||
"int": "D6",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "D1",
|
||||
"sda": "D2"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "A0"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "2",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 0,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_NODEMCU": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "D5",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "D1",
|
||||
"sda": "D2"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "D6",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "D1",
|
||||
"sda": "D2"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "A0"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "2",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 0,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_ESP01": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "255",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "0",
|
||||
"sda": "2"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "255",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "0",
|
||||
"sda": "2"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_INTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "255"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "255",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 0,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_TTGO_TBASE": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "14",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "13",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 0,
|
||||
"pin": "A0"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "2",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 0,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_WROOM32": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "23",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "22",
|
||||
"sda": "21"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_BNO085",
|
||||
"int": "25",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "22",
|
||||
"sda": "21"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "36"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "255",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_LOLIN_C3_MINI": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "6",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "8",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "3"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "7",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_BEETLE32C3": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "6",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "9",
|
||||
"sda": "8"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "7",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "9",
|
||||
"sda": "8"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "3"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "10",
|
||||
"LED_INVERTED": false
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_ESP32C3DEVKITM1": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "6",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "7",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "3"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "LED_BUILTIN",
|
||||
"LED_INVERTED": false
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_ESP32C6DEVKITC1": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "6",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "7",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "4",
|
||||
"sda": "5"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "3"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "LED_BUILTIN",
|
||||
"LED_INVERTED": false
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_WEMOSWROOM02": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "0",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "14",
|
||||
"sda": "2"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "4",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "14",
|
||||
"sda": "2"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 220,
|
||||
"shieldR": 180,
|
||||
"pin": "A0"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "16",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_XIAO_ESP32C3": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "5",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "7",
|
||||
"sda": "6"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "10",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "7",
|
||||
"sda": "6"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 100,
|
||||
"r2": 100,
|
||||
"shieldR": 0,
|
||||
"pin": "2"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "4",
|
||||
"LED_INVERTED": false
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
},
|
||||
"BOARD_ESP32S3_SUPERMINI": {
|
||||
"values": {
|
||||
"SENSORS": [
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "5",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "6",
|
||||
"sda": "7"
|
||||
},
|
||||
{
|
||||
"protocol": "I2C",
|
||||
"imu": "IMU_ICM45686",
|
||||
"int": "4",
|
||||
"rotation": "DEG_270",
|
||||
"scl": "6",
|
||||
"sda": "7"
|
||||
}
|
||||
],
|
||||
"BATTERY": {
|
||||
"type": "BAT_EXTERNAL",
|
||||
"r1": 10,
|
||||
"r2": 40.2,
|
||||
"shieldR": 0,
|
||||
"pin": "A2"
|
||||
},
|
||||
"LED": {
|
||||
"LED_PIN": "LED_BUILTIN",
|
||||
"LED_INVERTED": true
|
||||
}
|
||||
},
|
||||
"flashingRules": {
|
||||
"applicationOffset": 65536,
|
||||
"needBootPress": false,
|
||||
"needManualReboot": false,
|
||||
"shouldOnlyUseDefaults": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
244
board-defaults.schema.json
Normal file
244
board-defaults.schema.json
Normal file
@@ -0,0 +1,244 @@
|
||||
{
|
||||
"$id": "board-defaults.schema.json",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
|
||||
"$defs": {
|
||||
"pin": {
|
||||
"type": "string",
|
||||
"pattern": "^[AD]?[0-9]\\d*$"
|
||||
},
|
||||
|
||||
"LED_PIN": {
|
||||
"type": "string",
|
||||
"pattern": "^([AD]?[0-9]\\d*|LED_BUILTIN)$"
|
||||
},
|
||||
|
||||
"IMU_TYPE": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"IMU_AUTO",
|
||||
"IMU_MPU9250",
|
||||
"IMU_MPU6500",
|
||||
"IMU_BNO080",
|
||||
"IMU_BNO085",
|
||||
"IMU_BNO055",
|
||||
"IMU_MPU6050",
|
||||
"IMU_BNO086",
|
||||
"IMU_BMI160",
|
||||
"IMU_ICM20948",
|
||||
"IMU_ICM42688",
|
||||
"IMU_BMI270",
|
||||
"IMU_LSM6DS3TRC",
|
||||
"IMU_LSM6DSV",
|
||||
"IMU_LSM6DSO",
|
||||
"IMU_LSM6DSR",
|
||||
"IMU_MPU6050_SF",
|
||||
"IMU_ICM45686",
|
||||
"IMU_ICM45605"
|
||||
],
|
||||
"description": "Imu Type"
|
||||
},
|
||||
|
||||
"PROTOCOL": {
|
||||
"type": "string",
|
||||
"enum": ["I2C", "SPI"],
|
||||
"description": "Protocol"
|
||||
},
|
||||
|
||||
"IMU_ROTATION": {
|
||||
"type": "string",
|
||||
"enum": ["DEG_0", "DEG_90", "DEG_180", "DEG_270"],
|
||||
"description": "Protocol"
|
||||
},
|
||||
|
||||
"I2C_IMU": {
|
||||
"type": "object",
|
||||
"description": "I2C Imu",
|
||||
"properties": {
|
||||
"protocol": { "const": "I2C" },
|
||||
"imu": { "$ref": "#/$defs/IMU_TYPE" },
|
||||
"sda": { "$ref": "#/$defs/pin", "description": "SDA Pin" },
|
||||
"scl": { "$ref": "#/$defs/pin", "description": "SCL Pin" },
|
||||
"int": { "$ref": "#/$defs/pin", "description": "INT Pin" },
|
||||
"address": {
|
||||
"type": "number",
|
||||
"description": "IMU Address"
|
||||
},
|
||||
"rotation": {
|
||||
"$ref": "#/$defs/IMU_ROTATION",
|
||||
"description": "IMU Rotation"
|
||||
}
|
||||
},
|
||||
"required": ["protocol", "imu", "sda", "scl"]
|
||||
},
|
||||
|
||||
"SPI_IMU": {
|
||||
"type": "object",
|
||||
"description": "SPI Imu",
|
||||
"properties": {
|
||||
"protocol": { "const": "SPI" },
|
||||
"imu": { "$ref": "#/$defs/IMU_TYPE" },
|
||||
"int": { "$ref": "#/$defs/pin", "description": "INT Pin" },
|
||||
"rotation": {
|
||||
"$ref": "#/$defs/IMU_ROTATION",
|
||||
"description": "IMU Rotation"
|
||||
},
|
||||
"cs": { "$ref": "#/$defs/pin", "description": "CS Pin" }
|
||||
},
|
||||
"required": ["protocol", "imu", "cs"]
|
||||
},
|
||||
|
||||
"IMU": {
|
||||
"type": "object",
|
||||
"discriminator": {
|
||||
"propertyName": "protocol"
|
||||
},
|
||||
"oneOf": [
|
||||
{ "$ref": "#/$defs/I2C_IMU" },
|
||||
{ "$ref": "#/$defs/SPI_IMU" }
|
||||
],
|
||||
"required": ["protocol"]
|
||||
},
|
||||
|
||||
"BOARD_TYPES": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"BOARD_SLIMEVR",
|
||||
"BOARD_SLIMEVR_V1_2",
|
||||
"BOARD_SLIMEVR_DEV",
|
||||
"BOARD_NODEMCU",
|
||||
"BOARD_WEMOSD1MINI",
|
||||
"BOARD_ESP01",
|
||||
"BOARD_TTGO_TBASE",
|
||||
"BOARD_WROOM32",
|
||||
"BOARD_LOLIN_C3_MINI",
|
||||
"BOARD_BEETLE32C3",
|
||||
"BOARD_ESP32C3DEVKITM1",
|
||||
"BOARD_ESP32C6DEVKITC1",
|
||||
"BOARD_WEMOSWROOM02",
|
||||
"BOARD_XIAO_ESP32C3",
|
||||
"BOARD_ESP32S3_SUPERMINI"
|
||||
],
|
||||
"description": "Board Type"
|
||||
},
|
||||
|
||||
"BATTERY": {
|
||||
"type": "object",
|
||||
"discriminator": {
|
||||
"propertyName": "type"
|
||||
},
|
||||
"description": "Battery Settings",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "BAT_EXTERNAL" },
|
||||
"shieldR": {
|
||||
"type": "number",
|
||||
"description": "Battery Shield Resistor (Ohms)"
|
||||
},
|
||||
"r1": { "type": "number", "description": "R1 (Ohms)" },
|
||||
"r2": { "type": "number", "description": "R2 (Ohms)" },
|
||||
"pin": {
|
||||
"$ref": "#/$defs/pin",
|
||||
"description": "Battery Pin"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "BAT_INTERNAL" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "BAT_MCP3021" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": { "const": "BAT_INTERNAL_MCP3021" }
|
||||
}
|
||||
}
|
||||
],
|
||||
"required": ["type"]
|
||||
},
|
||||
|
||||
"BASIC_IMU_BOARD_CONFIG": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"SENSORS": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/IMU" },
|
||||
"minItems": 1,
|
||||
"maxItems": 2,
|
||||
"description": "Sensors List"
|
||||
},
|
||||
"LED": {
|
||||
"type": "object",
|
||||
"description": "Led Settings",
|
||||
"properties": {
|
||||
"LED_PIN": {
|
||||
"$ref": "#/$defs/LED_PIN",
|
||||
"description": "Led pin"
|
||||
},
|
||||
"LED_INVERTED": {
|
||||
"type": "boolean",
|
||||
"description": "Led inverted"
|
||||
}
|
||||
},
|
||||
"required": ["LED_PIN", "LED_INVERTED"]
|
||||
},
|
||||
"BATTERY": { "$ref": "#/$defs/BATTERY" }
|
||||
},
|
||||
"required": ["SENSORS", "LED", "BATTERY"]
|
||||
},
|
||||
|
||||
"BoardConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"$ref": "#/$defs/BASIC_IMU_BOARD_CONFIG"
|
||||
},
|
||||
"flashingRules": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"needBootPress": { "type": "boolean" },
|
||||
"needManualReboot": { "type": "boolean" },
|
||||
"shouldOnlyUseDefaults": { "type": "boolean" },
|
||||
"applicationOffset": { "type": "integer" }
|
||||
},
|
||||
"required": [
|
||||
"needBootPress",
|
||||
"needManualReboot",
|
||||
"shouldOnlyUseDefaults",
|
||||
"applicationOffset"
|
||||
]
|
||||
},
|
||||
"ignored": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["values", "flashingRules"]
|
||||
}
|
||||
},
|
||||
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"toolchain": {
|
||||
"type": "string",
|
||||
"enum": ["platformio"]
|
||||
},
|
||||
"defaults": {
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"$ref": "#/$defs/BOARD_TYPES"
|
||||
},
|
||||
"additionalProperties": { "$ref": "#/$defs/BoardConfig" }
|
||||
}
|
||||
},
|
||||
"required": ["toolchain", "defaults"]
|
||||
}
|
||||
29
ci/build.py
29
ci/build.py
@@ -32,12 +32,13 @@ def get_matrix() -> List[DeviceConfiguration]:
|
||||
matrix: List[DeviceConfiguration] = []
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read("./platformio-tools.ini")
|
||||
config.read("./platformio.ini")
|
||||
for section in config.sections():
|
||||
if section == "env":
|
||||
split = section.split(":")
|
||||
if len(split) != 2 or split[0] != 'env':
|
||||
continue
|
||||
|
||||
board = section.split(":")[1]
|
||||
board = split[1]
|
||||
platform = config[section]["platform"]
|
||||
platformio_board = config[section]["board"]
|
||||
|
||||
@@ -51,36 +52,15 @@ def get_matrix() -> List[DeviceConfiguration]:
|
||||
|
||||
def prepare() -> None:
|
||||
print(f"🡢 {COLOR_CYAN}Preparation{COLOR_RESET}")
|
||||
|
||||
print(f" 🡢 {COLOR_GRAY}Backing up platformio.ini{COLOR_RESET}")
|
||||
shutil.copy("./platformio.ini", "platformio.ini.bak")
|
||||
|
||||
print(
|
||||
f" 🡢 {COLOR_GRAY}Switching platformio.ini to platformio-tools.ini{COLOR_RESET}")
|
||||
shutil.copy("./platformio-tools.ini", "platformio.ini")
|
||||
|
||||
if os.path.exists("./build"):
|
||||
print(f" 🡢 {COLOR_GRAY}Removing existing build folder...{COLOR_RESET}")
|
||||
shutil.rmtree("./build")
|
||||
|
||||
print(f" 🡢 {COLOR_GRAY}Creating build folder...{COLOR_RESET}")
|
||||
os.mkdir("./build")
|
||||
|
||||
print(f" 🡢 {COLOR_GREEN}Success!{COLOR_RESET}")
|
||||
|
||||
|
||||
def cleanup() -> None:
|
||||
print(f"🡢 {COLOR_CYAN}Cleanup{COLOR_RESET}")
|
||||
|
||||
print(f" 🡢 {COLOR_GRAY}Restoring platformio.ini...{COLOR_RESET}")
|
||||
shutil.copy("platformio.ini.bak", "platformio.ini")
|
||||
|
||||
print(f" 🡢 {COLOR_GRAY}Removing platformio.ini.bak...{COLOR_RESET}")
|
||||
os.remove("platformio.ini.bak")
|
||||
|
||||
print(f" 🡢 {COLOR_GREEN}Success!{COLOR_RESET}")
|
||||
|
||||
|
||||
def build() -> int:
|
||||
print(f"🡢 {COLOR_CYAN}Build{COLOR_RESET}")
|
||||
|
||||
@@ -135,7 +115,6 @@ def build_for_device(device: DeviceConfiguration) -> bool:
|
||||
def main() -> None:
|
||||
prepare()
|
||||
code = build()
|
||||
cleanup()
|
||||
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1760878510,
|
||||
"narHash": "sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5e2a59a5b1a82f89f2c7e598302a9cacebb72a67",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
80
flake.nix
Normal file
80
flake.nix
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
description = "PlatformIO development environment";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
# PlatformIO
|
||||
platformio
|
||||
platformio-core
|
||||
|
||||
# Python for PlatformIO with needed packages
|
||||
python3
|
||||
python3Packages.pip
|
||||
python3Packages.virtualenv
|
||||
|
||||
# Pre-install Python packages that need compilation
|
||||
python3Packages.jsonschema
|
||||
python3Packages.rpds-py
|
||||
python3Packages.attrs
|
||||
python3Packages.referencing
|
||||
|
||||
# Rust toolchain (in case compilation is needed)
|
||||
rustc
|
||||
cargo
|
||||
|
||||
# Build tools
|
||||
gcc
|
||||
gnumake
|
||||
cmake
|
||||
|
||||
# Serial communication
|
||||
picocom
|
||||
minicom
|
||||
|
||||
# USB access (for programming devices)
|
||||
libusb1
|
||||
pkg-config
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
# Set PlatformIO core directory to project-local directory
|
||||
export PLATFORMIO_CORE_DIR=$PWD/.nix-platformio
|
||||
|
||||
# Create and activate Python virtual environment
|
||||
if [ ! -d .venv ]; then
|
||||
echo "Creating Python virtual environment..."
|
||||
python3 -m venv .venv --system-site-packages
|
||||
fi
|
||||
source .venv/bin/activate
|
||||
|
||||
# Prefer binary wheels over building from source
|
||||
export PIP_PREFER_BINARY=1
|
||||
|
||||
echo "PlatformIO development environment loaded"
|
||||
echo "Python virtual environment activated: .venv"
|
||||
echo "PlatformIO version: $(pio --version)"
|
||||
echo "Python version: $(python --version)"
|
||||
echo ""
|
||||
echo "Available commands:"
|
||||
echo " pio init - Initialize a new PlatformIO project"
|
||||
echo " pio run - Build the project"
|
||||
echo " pio run -t upload - Upload to device"
|
||||
echo " pio device monitor - Open serial monitor"
|
||||
echo " pip install <package> - Install Python packages in venv"
|
||||
echo ""
|
||||
'';
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1,116 +1,156 @@
|
||||
#include "i2cscan.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "../../src/globals.h"
|
||||
#include "../../src/consts.h"
|
||||
|
||||
#ifdef ESP8266
|
||||
uint8_t portArray[] = {16, 5, 4, 2, 14, 12, 13};
|
||||
uint8_t portExclude[] = {LED_PIN};
|
||||
String portMap[] = {"D0", "D1", "D2", "D4", "D5", "D6", "D7"};
|
||||
#elif defined(ESP32C3)
|
||||
uint8_t portArray[] = {2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
uint8_t portExclude[] = {18, 19, 20, 21, LED_PIN};
|
||||
String portMap[] = {"2", "3", "4", "5", "6", "7", "8", "9", "10"};
|
||||
#elif defined(ESP32C6)
|
||||
uint8_t portArray[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 18, 19, 20, 21, 22, 23};
|
||||
String portMap[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "14", "15", "18", "19", "20", "21", "22", "23"};
|
||||
uint8_t portExclude[] = {12, 13, 16, 17, LED_PIN};
|
||||
#elif defined(ESP32)
|
||||
uint8_t portArray[] = {4, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33};
|
||||
String portMap[] = {"4", "13", "14", "15", "16", "17", "18", "19", "21", "22", "23", "25", "26", "27", "32", "33"};
|
||||
uint8_t portExclude[] = {LED_PIN};
|
||||
#endif
|
||||
|
||||
namespace I2CSCAN
|
||||
{
|
||||
enum class ScanState {
|
||||
namespace I2CSCAN {
|
||||
enum class ScanState : uint8_t {
|
||||
IDLE,
|
||||
SCANNING,
|
||||
DONE
|
||||
};
|
||||
|
||||
ScanState scanState = ScanState::IDLE;
|
||||
uint8_t currentSDA = 0;
|
||||
uint8_t currentSCL = 0;
|
||||
uint8_t currentAddress = 1;
|
||||
bool found = false;
|
||||
std::vector<uint8_t> validPorts;
|
||||
namespace {
|
||||
ScanState scanState = ScanState::IDLE;
|
||||
uint8_t currentSDA = 0;
|
||||
uint8_t currentSCL = 0;
|
||||
uint8_t currentAddress = 1;
|
||||
bool found = false;
|
||||
uint8_t txFails = 0;
|
||||
std::vector<uint8_t> validPorts;
|
||||
|
||||
void scani2cports()
|
||||
{
|
||||
#ifdef ESP8266
|
||||
std::array<uint8_t, 7> portArray = {16, 5, 4, 2, 14, 12, 13};
|
||||
std::array<std::string, 7> portMap = {"D0", "D1", "D2", "D4", "D5", "D6", "D7"};
|
||||
std::array<uint8_t, 1> portExclude = {LED_PIN};
|
||||
#elif defined(ESP32C3)
|
||||
std::array<uint8_t, 9> portArray = {2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
std::array<std::string, 9> portMap = {"2", "3", "4", "5", "6", "7", "8", "9", "10"};
|
||||
std::array<uint8_t, 5> portExclude = {18, 19, 20, 21, LED_PIN};
|
||||
#elif defined(ESP32C6)
|
||||
std::array<uint8_t, 20> portArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 18, 19, 20, 21, 22, 23};
|
||||
std::array<std::string, 20> portMap = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "14", "15", "18", "19", "20", "21", "22", "23"};
|
||||
std::array<uint8_t, 5> portExclude = {12, 13, 16, 17, LED_PIN};
|
||||
#elif defined(ESP32)
|
||||
std::array<uint8_t, 16> portArray = {4, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33};
|
||||
std::array<std::string, 16> portMap = {"4", "13", "14", "15", "16", "17", "18", "19", "21", "22", "23", "25", "26", "27", "32", "33"};
|
||||
std::array<uint8_t, 1> portExclude = {LED_PIN};
|
||||
#endif
|
||||
|
||||
bool selectNextPort() {
|
||||
currentSCL++;
|
||||
|
||||
if(validPorts[currentSCL] == validPorts[currentSDA]) currentSCL++;
|
||||
|
||||
if (currentSCL < validPorts.size()) {
|
||||
Wire.begin((int)validPorts[currentSDA], (int)validPorts[currentSCL]); //NOLINT
|
||||
return true;
|
||||
}
|
||||
|
||||
currentSCL = 0;
|
||||
currentSDA++;
|
||||
|
||||
if (currentSDA >= validPorts.size()) {
|
||||
if (!found) {
|
||||
Serial.println("[ERROR] I2C: No I2C devices found"); //NOLINT
|
||||
}
|
||||
#ifdef ESP32
|
||||
Wire.end();
|
||||
#endif
|
||||
Wire.begin(static_cast<int>(PIN_IMU_SDA), static_cast<int>(PIN_IMU_SCL));
|
||||
scanState = ScanState::DONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
Wire.begin((int)validPorts[currentSDA], (int)validPorts[currentSCL]);
|
||||
return true;
|
||||
}
|
||||
template <uint8_t size1, uint8_t size2>
|
||||
uint8_t countCommonElements(
|
||||
const std::array<uint8_t, size1>& array1,
|
||||
const std::array<uint8_t, size2>& array2) {
|
||||
|
||||
uint8_t count = 0;
|
||||
for (const auto& elem1 : array1) {
|
||||
for (const auto& elem2 : array2) {
|
||||
if (elem1 == elem2) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
void scani2cports() {
|
||||
if (scanState != ScanState::IDLE) {
|
||||
return;
|
||||
if (scanState == ScanState::DONE) {
|
||||
Serial.println("[DEBUG] I2C scan finished previously, resetting and scanning again..."); //NOLINT
|
||||
} else {
|
||||
return; // Already scanning, do not start again
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out excluded ports
|
||||
for (size_t i = 0; i < sizeof(portArray); i++) {
|
||||
if (!inArray(portArray[i], portExclude, sizeof(portExclude))) {
|
||||
validPorts.push_back(portArray[i]);
|
||||
}
|
||||
}
|
||||
validPorts.clear();
|
||||
uint8_t excludes = countCommonElements<portArray.size(), portExclude.size()>(portArray, portExclude);
|
||||
validPorts.reserve(portArray.size() - excludes); // Reserve space to avoid reallocations
|
||||
|
||||
for (const auto& port : portArray) {
|
||||
if (std::find(portExclude.begin(), portExclude.end(), port) == portExclude.end()) {
|
||||
validPorts.push_back(port); // Port is valid, add it to the list
|
||||
}
|
||||
}
|
||||
|
||||
// Reset scan variables and start scanning
|
||||
found = false;
|
||||
currentSDA = 0;
|
||||
currentSCL = 1;
|
||||
currentAddress = 1;
|
||||
txFails = 0;
|
||||
scanState = ScanState::SCANNING;
|
||||
}
|
||||
}
|
||||
|
||||
bool selectNextPort() {
|
||||
currentSCL++;
|
||||
if(validPorts[currentSCL] == validPorts[currentSDA])
|
||||
currentSCL++;
|
||||
if (currentSCL < validPorts.size()) {
|
||||
Wire.begin((int)validPorts[currentSDA], (int)validPorts[currentSCL]);
|
||||
return true;
|
||||
}
|
||||
|
||||
currentSCL = 0;
|
||||
currentSDA++;
|
||||
|
||||
if (currentSDA >= validPorts.size()) {
|
||||
if (!found) {
|
||||
Serial.println("[ERR] I2C: No I2C devices found");
|
||||
}
|
||||
#ifdef ESP32
|
||||
Wire.end();
|
||||
#endif
|
||||
Wire.begin(static_cast<int>(PIN_IMU_SDA), static_cast<int>(PIN_IMU_SCL));
|
||||
scanState = ScanState::DONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
Wire.begin((int)validPorts[currentSDA], (int)validPorts[currentSCL]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
void update() {
|
||||
if (scanState != ScanState::SCANNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentAddress == 1) {
|
||||
#ifdef ESP32
|
||||
if (currentAddress == 1) {
|
||||
Wire.end();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Wire.beginTransmission(currentAddress);
|
||||
byte error = Wire.endTransmission();
|
||||
const uint8_t error = Wire.endTransmission();
|
||||
|
||||
if (error == 0)
|
||||
{
|
||||
Serial.printf("[DBG] I2C (@ %s(%d) : %s(%d)): I2C device found at address 0x%02x !\n",
|
||||
if (error == 0) {
|
||||
Serial.printf("[INFO ] I2C (@ %s(%d) : %s(%d)): I2C device found at address 0x%02x!\n",
|
||||
portMap[currentSDA].c_str(), validPorts[currentSDA], portMap[currentSCL].c_str(), validPorts[currentSCL], currentAddress);
|
||||
found = true;
|
||||
}
|
||||
else if (error == 4)
|
||||
{
|
||||
Serial.printf("[ERR] I2C (@ %s(%d) : %s(%d)): Unknown error at address 0x%02x\n",
|
||||
} else if (error == 4) { // Unable to start transaction, log and warn
|
||||
Serial.printf("[WARN ] I2C (@ %s(%d) : %s(%d)): Unable to start transaction at address 0x%02x!\n",
|
||||
portMap[currentSDA].c_str(), validPorts[currentSDA], portMap[currentSCL].c_str(), validPorts[currentSCL], currentAddress);
|
||||
txFails++;
|
||||
}
|
||||
|
||||
currentAddress++;
|
||||
|
||||
if (currentAddress <= 127) {
|
||||
if (txFails > 5) {
|
||||
#if BOARD == BOARD_SLIMEVR_LEGACY || BOARD == BOARD_SLIMEVR_DEV || BOARD == BOARD_SLIMEVR || BOARD == BOARD_SLIMEVR_V1_2
|
||||
Serial.printf("[ERROR] I2C: Too many transaction errors (%d), please power off the tracker and contact SlimeVR support!\n", txFails);
|
||||
#else
|
||||
Serial.printf("[ERROR] I2C: Too many transaction errors (%d), please power off the tracker and check the IMU connections!\n", txFails);
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -118,19 +158,6 @@ namespace I2CSCAN
|
||||
selectNextPort();
|
||||
}
|
||||
|
||||
bool inArray(uint8_t value, uint8_t* array, size_t arraySize)
|
||||
{
|
||||
for (size_t i = 0; i < arraySize; i++)
|
||||
{
|
||||
if (value == array[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasDevOnBus(uint8_t addr) {
|
||||
byte error;
|
||||
#if ESP32C3
|
||||
@@ -165,9 +192,9 @@ namespace I2CSCAN
|
||||
*/
|
||||
|
||||
int clearBus(uint8_t SDA, uint8_t SCL) {
|
||||
#if defined(TWCR) && defined(TWEN)
|
||||
#if defined(TWCR) && defined(TWEN)
|
||||
TWCR &= ~(_BV(TWEN)); // Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly
|
||||
#endif
|
||||
#endif
|
||||
|
||||
pinMode(SDA, INPUT_PULLUP);
|
||||
pinMode(SCL, INPUT_PULLUP);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace I2CSCAN {
|
||||
bool hasDevOnBus(uint8_t addr);
|
||||
uint8_t pickDevice(uint8_t addr1, uint8_t addr2, bool scanIfNotFound);
|
||||
int clearBus(uint8_t SDA, uint8_t SCL);
|
||||
boolean inArray(uint8_t value, uint8_t* arr, size_t arrSize);
|
||||
bool inArray(uint8_t value, const uint8_t *array, size_t arraySize);
|
||||
}
|
||||
|
||||
#endif // _I2CSCAN_H_
|
||||
#endif // _I2CSCAN_H_
|
||||
|
||||
@@ -56,7 +56,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 3.0 s
|
||||
*/
|
||||
vqf_real_t tauAcc = 3.0;
|
||||
vqf_real_t tauAcc = 4.337983;
|
||||
/**
|
||||
* @brief Time constant \f$\tau_\mathrm{mag}\f$ for magnetometer update in seconds.
|
||||
*
|
||||
@@ -106,7 +106,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 0.5 °/s
|
||||
*/
|
||||
vqf_real_t biasSigmaInit = 0.5;
|
||||
vqf_real_t biasSigmaInit = 3.219453;
|
||||
/**
|
||||
* @brief Time in which the bias estimation uncertainty increases from 0 °/s to 0.1
|
||||
* °/s (in seconds).
|
||||
@@ -115,7 +115,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 100.0 s
|
||||
*/
|
||||
vqf_real_t biasForgettingTime = 100.0;
|
||||
vqf_real_t biasForgettingTime = 136.579346;
|
||||
/**
|
||||
* @brief Maximum expected gyroscope bias (in degrees per second).
|
||||
*
|
||||
@@ -126,7 +126,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 2.0 °/s
|
||||
*/
|
||||
vqf_real_t biasClip = 2.0;
|
||||
vqf_real_t biasClip = 5.0;
|
||||
#ifndef VQF_NO_MOTION_BIAS_ESTIMATION
|
||||
/**
|
||||
* @brief Standard deviation of the converged bias estimation uncertainty during
|
||||
@@ -137,7 +137,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 0.1 °/s
|
||||
*/
|
||||
vqf_real_t biasSigmaMotion = 0.1;
|
||||
vqf_real_t biasSigmaMotion = 0.348501;
|
||||
/**
|
||||
* @brief Forgetting factor for unobservable bias in vertical direction during
|
||||
* motion.
|
||||
@@ -149,7 +149,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 0.0001
|
||||
*/
|
||||
vqf_real_t biasVerticalForgettingFactor = 0.0001;
|
||||
vqf_real_t biasVerticalForgettingFactor = 0.007056;
|
||||
#endif
|
||||
/**
|
||||
* @brief Standard deviation of the converged bias estimation uncertainty during
|
||||
@@ -160,7 +160,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 0.03 °
|
||||
*/
|
||||
vqf_real_t biasSigmaRest = 0.03;
|
||||
vqf_real_t biasSigmaRest = 0.063616;
|
||||
|
||||
/**
|
||||
* @brief Time threshold for rest detection (in seconds).
|
||||
@@ -170,7 +170,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 1.5 s
|
||||
*/
|
||||
vqf_real_t restMinT = 1.5;
|
||||
vqf_real_t restMinT = 2.586910;
|
||||
/**
|
||||
* @brief Time constant for the low-pass filter used in rest detection (in seconds).
|
||||
*
|
||||
@@ -179,7 +179,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 0.5 s
|
||||
*/
|
||||
vqf_real_t restFilterTau = 0.5;
|
||||
vqf_real_t restFilterTau = 1.114532;
|
||||
/**
|
||||
* @brief Angular velocity threshold for rest detection (in °/s).
|
||||
*
|
||||
@@ -189,7 +189,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 2.0 °/s
|
||||
*/
|
||||
vqf_real_t restThGyr = 2.0;
|
||||
vqf_real_t restThGyr = 1.399189;
|
||||
/**
|
||||
* @brief Acceleration threshold for rest detection (in m/s²).
|
||||
*
|
||||
@@ -198,7 +198,7 @@ struct VQFParams {
|
||||
*
|
||||
* Default value: 0.5 m/s²
|
||||
*/
|
||||
vqf_real_t restThAcc = 0.5;
|
||||
vqf_real_t restThAcc = 1.418598;
|
||||
|
||||
/**
|
||||
* @brief Time constant for current norm/dip value in magnetic disturbance detection
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
[env]
|
||||
lib_deps=
|
||||
https://github.com/SlimeVR/CmdParser.git
|
||||
https://github.com/SlimeVR/base64_arduino.git
|
||||
https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library.git
|
||||
https://github.com/hideakitai/PCA9547.git
|
||||
monitor_speed = 115200
|
||||
framework = arduino
|
||||
build_flags =
|
||||
!python scripts/get_git_commit.py
|
||||
-O2
|
||||
-std=gnu++2a
|
||||
build_unflags =
|
||||
-Os
|
||||
-std=gnu++11 -std=gnu++17
|
||||
|
||||
[env:BOARD_SLIMEVR]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_SLIMEVR
|
||||
-D VENDOR_NAME='"SlimeVR"'
|
||||
-D VENDOR_URL='"https://slimevr.dev"'
|
||||
-D PRODUCT_NAME='"SlimeVR Tracker"'
|
||||
-D UPDATE_ADDRESS='"SlimeVR/SlimeVR-Tracker-ESP"'
|
||||
-D UPDATE_NAME='"BOARD_SLIMEVR-firmware"'
|
||||
|
||||
[env:BOARD_SLIMEVR_V1_2]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_SLIMEVR_V1_2
|
||||
-D VENDOR_NAME='"SlimeVR"'
|
||||
-D VENDOR_URL='"https://slimevr.dev"'
|
||||
-D PRODUCT_NAME='"SlimeVR Tracker v1.2"'
|
||||
-D UPDATE_ADDRESS='"SlimeVR/SlimeVR-Tracker-ESP"'
|
||||
-D UPDATE_NAME='"BOARD_SLIMEVR_V1_2-firmware"'
|
||||
|
||||
[env:BOARD_SLIMEVR_DEV]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_SLIMEVR_DEV
|
||||
-D VENDOR_NAME='"SlimeVR"'
|
||||
-D PRODUCT_NAME='"SlimeVR Tracker (dev)"'
|
||||
|
||||
[env:BOARD_GLOVE_IMU_SLIMEVR_DEV]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
-D BOARD=BOARD_GLOVE_IMU_SLIMEVR_DEV
|
||||
-D PRODUCT_NAME='"SlimeVR Glove (dev)"'
|
||||
board = lolin_c3_mini
|
||||
|
||||
[env:BOARD_NODEMCU]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_NODEMCU
|
||||
|
||||
[env:BOARD_WEMOSD1MINI]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_WEMOSD1MINI
|
||||
|
||||
[env:BOARD_TTGO_TBASE]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_TTGO_TBASE
|
||||
|
||||
[env:BOARD_WEMOSWROOM02]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_NODEMCU
|
||||
|
||||
[env:BOARD_WROOM32]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
board = esp32dev
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_WROOM32
|
||||
|
||||
[env:BOARD_ESP01]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
board = esp32dev
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_ESP01
|
||||
|
||||
[env:BOARD_LOLIN_C3_MINI]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
-D BOARD=BOARD_LOLIN_C3_MINI
|
||||
board = lolin_c3_mini
|
||||
|
||||
[env:BOARD_BEETLE32C3]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
-D BOARD=BOARD_BEETLE32C3
|
||||
board = dfrobot_beetle_esp32c3
|
||||
|
||||
[env:BOARD_ESP32C3DEVKITM1]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
-D BOARD=BOARD_ESP32C3DEVKITM1
|
||||
board = esp32-c3-devkitm-1
|
||||
|
||||
[env:BOARD_ESP32C6DEVKITC1]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.11/platform-espressif32.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C6
|
||||
-D BOARD=BOARD_ESP32C6DEVKITC1
|
||||
board = esp32-c6-devkitc-1
|
||||
|
||||
[env:BOARD_XIAO_ESP32C3]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
-D BOARD=BOARD_XIAO_ESP32C3
|
||||
board = seeed_xiao_esp32c3
|
||||
|
||||
[env:BOARD_ESP32S3_SUPERMINI]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DESP32S3
|
||||
-D BOARD=BOARD_ESP32S3_SUPERMINI
|
||||
board = esp32s3_supermini
|
||||
board_upload.use_1200bps_touch = 1
|
||||
board_upload.wait_for_upload_port = 1
|
||||
board_upload.require_upload_port = 1
|
||||
upload_speed = 921600
|
||||
231
platformio.ini
231
platformio.ini
@@ -13,6 +13,7 @@
|
||||
|
||||
[platformio]
|
||||
build_cache_dir = cache
|
||||
default_envs = BOARD_WEMOSD1MINI
|
||||
|
||||
[env]
|
||||
lib_deps=
|
||||
@@ -26,7 +27,8 @@ monitor_filters = colorize
|
||||
;monitor_rts = 0
|
||||
;monitor_dtr = 0
|
||||
framework = arduino
|
||||
build_flags =
|
||||
extra_scripts = pre:scripts/preprocessor.py
|
||||
build_flags =
|
||||
!python scripts/get_git_commit.py
|
||||
;If you want to set hardcoded WiFi SSID and password, uncomment and edit the lines below
|
||||
;To uncomment, only remove ";" and leave the two spaces in front of the tags
|
||||
@@ -60,39 +62,62 @@ build_unflags = -Os -std=gnu++11 -std=gnu++17
|
||||
;upload_flags =
|
||||
; --auth=SlimeVR-OTA
|
||||
|
||||
; Settings for different boards
|
||||
|
||||
[env:esp12e]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
; Comment out this line below if you have any trouble uploading the firmware
|
||||
; and if it has a CP2102 on it (a square chip next to the usb port): change to 3000000 (3 million) for even faster upload speed
|
||||
upload_speed = 921600
|
||||
|
||||
; Uncomment below if you want to build for ESP-01
|
||||
;[env:esp01_1m]
|
||||
;platform = espressif8266 @ 4.2.1
|
||||
;board = esp01_1m
|
||||
;board_build.arduino.ldscript = "eagle.flash.1m64.ld"
|
||||
|
||||
; Uncomment below if you want to build for ESP8285 (ESP8266 with embedded Flash)
|
||||
;[env:esp8285]
|
||||
;platform = espressif8266 @ 4.2.1
|
||||
;board = esp8285
|
||||
;board_build.arduino.ldscript = "eagle.flash.1m64.ld"
|
||||
;board_build.flash_mode = dout
|
||||
[env:BOARD_WEMOSD1MINI]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
custom_slime_board = BOARD_WEMOSD1MINI
|
||||
upload_speed = 921600
|
||||
|
||||
; Uncomment below if you want to build for esp32
|
||||
; Check your board name at https://docs.platformio.org/en/latest/platforms/espressif32.html#boards
|
||||
; [env:esp32]
|
||||
; platform = espressif32 @ 6.7.0
|
||||
; platform_packages =
|
||||
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
; framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
; board = esp32dev
|
||||
; Comment out this line below if you have any trouble uploading the firmware - and if it has a CP2102 on it (a square chip next to the usb port): change to 3000000 (3 million) for even faster upload speed
|
||||
;upload_speed = 921600
|
||||
[env:BOARD_NODEMCU]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
custom_slime_board = BOARD_NODEMCU
|
||||
upload_speed = 921600
|
||||
|
||||
[env:BOARD_TTGO_TBASE]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
custom_slime_board = BOARD_TTGO_TBASE
|
||||
upload_speed = 921600
|
||||
|
||||
[env:BOARD_WEMOSWROOM02]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
custom_slime_board = BOARD_WEMOSWROOM02
|
||||
upload_speed = 921600
|
||||
|
||||
[env:BOARD_WROOM32]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
board = esp32dev
|
||||
custom_slime_board = BOARD_WROOM32
|
||||
|
||||
[env:BOARD_ESP01]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp01_1m
|
||||
board_build.arduino.ldscript = "eagle.flash.1m64.ld"
|
||||
custom_slime_board = BOARD_ESP01
|
||||
upload_speed = 921600
|
||||
|
||||
[env:BOARD_LOLIN_C3_MINI]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
custom_slime_board = BOARD_LOLIN_C3_MINI
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
board = lolin_c3_mini
|
||||
monitor_filters = colorize, esp32_exception_decoder
|
||||
; If you want to use a ESP32C3, you can use this (experimental)
|
||||
; Check your board name at https://docs.platformio.org/en/latest/platforms/espressif32.html#boards
|
||||
; There are 2 main Boardtypes:
|
||||
@@ -102,38 +127,126 @@ upload_speed = 921600
|
||||
; -DARDUINO_USB_MODE=1
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
;[env:esp32c3]
|
||||
;platform = espressif32 @ 6.7.0
|
||||
;platform_packages =
|
||||
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
; framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
;build_flags =
|
||||
; ${env.build_flags}
|
||||
; -DESP32C3
|
||||
;board = lolin_c3_mini
|
||||
;monitor_filters = colorize, esp32_exception_decoder
|
||||
[env:BOARD_BEETLE32C3]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
custom_slime_board = BOARD_BEETLE32C3
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
board = dfrobot_beetle_esp32c3
|
||||
monitor_filters = colorize, esp32_exception_decoder
|
||||
; If you want to use a ESP32C3, you can use this (experimental)
|
||||
; Check your board name at https://docs.platformio.org/en/latest/platforms/espressif32.html#boards
|
||||
; There are 2 main Boardtypes:
|
||||
; 1. Boards that use a USB 2 Serial Chipset ( esp32-c3-devkitm-1, ttgo-t-oi-plus )
|
||||
; 2. Boards that relay on the USB interface of the ESP32C3 ( lolin_c3_mini , dfrobot_beetle_esp32c3)
|
||||
; On this board there are 2 type some of them need to have set the build flag (menuconfig)
|
||||
; -DARDUINO_USB_MODE=1
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
; If you want to use a ESP32C6, you can use this (experimental)
|
||||
;[env:esp32c6]
|
||||
;platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.11/platform-espressif32.zip
|
||||
;board = esp32-c6-devkitc-1
|
||||
;build_flags =
|
||||
; ${env.build_flags}
|
||||
; -DESP32C6
|
||||
; -DARDUINO_USB_MODE=1
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=1
|
||||
[env:BOARD_ESP32C3DEVKITM1]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
custom_slime_board = BOARD_ESP32C3DEVKITM1
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
board = esp32-c3-devkitm-1
|
||||
monitor_filters = colorize, esp32_exception_decoder
|
||||
; If you want to use a ESP32C3, you can use this (experimental)
|
||||
; Check your board name at https://docs.platformio.org/en/latest/platforms/espressif32.html#boards
|
||||
; There are 2 main Boardtypes:
|
||||
; 1. Boards that use a USB 2 Serial Chipset ( esp32-c3-devkitm-1, ttgo-t-oi-plus )
|
||||
; 2. Boards that relay on the USB interface of the ESP32C3 ( lolin_c3_mini , dfrobot_beetle_esp32c3)
|
||||
; On this board there are 2 type some of them need to have set the build flag (menuconfig)
|
||||
; -DARDUINO_USB_MODE=1
|
||||
; -DARDUINO_USB_CDC_ON_BOOT=1
|
||||
|
||||
;[env:BOARD_ESP32S3_SUPERMINI]
|
||||
;platform = espressif32 @ 6.7.0
|
||||
;platform_packages =
|
||||
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
; framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
;build_flags =
|
||||
; ${env.build_flags}
|
||||
; -DARDUINO_USB_MODE=1
|
||||
; -DESP32S3
|
||||
;board = esp32s3_supermini
|
||||
;board_upload.use_1200bps_touch = 1
|
||||
;board_upload.wait_for_upload_port = 1
|
||||
;board_upload.require_upload_port = 1
|
||||
;upload_speed = 921600
|
||||
[env:BOARD_ESP32C6DEVKITC1]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.06.11/platform-espressif32.zip
|
||||
custom_slime_board = BOARD_ESP32C6DEVKITC1
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C6
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
board = esp32-c6-devkitc-1
|
||||
|
||||
[env:BOARD_XIAO_ESP32C3]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
custom_slime_board = BOARD_XIAO_ESP32C3
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DESP32C3
|
||||
board = seeed_xiao_esp32c3
|
||||
monitor_filters = colorize, esp32_exception_decoder
|
||||
|
||||
[env:BOARD_ESP32S3_SUPERMINI]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
custom_slime_board = BOARD_ESP32S3_SUPERMINI
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-DARDUINO_USB_MODE=1
|
||||
-DESP32S3
|
||||
board = esp32s3_supermini
|
||||
board_upload.use_1200bps_touch = 1
|
||||
board_upload.wait_for_upload_port = 1
|
||||
board_upload.require_upload_port = 1
|
||||
upload_speed = 921600
|
||||
|
||||
[env:BOARD_SLIMEVR]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
custom_slime_board = BOARD_SLIMEVR
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D VENDOR_NAME='"SlimeVR"'
|
||||
-D VENDOR_URL='"https://slimevr.dev"'
|
||||
-D PRODUCT_NAME='"SlimeVR Tracker"'
|
||||
-D UPDATE_ADDRESS='"SlimeVR/SlimeVR-Tracker-ESP"'
|
||||
-D UPDATE_NAME='"BOARD_SLIMEVR-firmware"'
|
||||
|
||||
[env:BOARD_SLIMEVR_V1_2]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
custom_slime_board = BOARD_SLIMEVR_V1_2
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D VENDOR_NAME='"SlimeVR"'
|
||||
-D VENDOR_URL='"https://slimevr.dev"'
|
||||
-D PRODUCT_NAME='"SlimeVR Tracker v1.2"'
|
||||
-D UPDATE_ADDRESS='"SlimeVR/SlimeVR-Tracker-ESP"'
|
||||
-D UPDATE_NAME='"BOARD_SLIMEVR_V1_2-firmware"'
|
||||
|
||||
[env:BOARD_SLIMEVR_DEV]
|
||||
platform = espressif8266 @ 4.2.1
|
||||
board = esp12e
|
||||
custom_slime_board = BOARD_SLIMEVR_DEV
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D VENDOR_NAME='"SlimeVR"'
|
||||
-D PRODUCT_NAME='"SlimeVR Tracker (dev)"'
|
||||
|
||||
[env:BOARD_GLOVE_IMU_SLIMEVR_DEV]
|
||||
platform = espressif32 @ 6.7.0
|
||||
platform_packages =
|
||||
framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
|
||||
framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip
|
||||
build_flags =
|
||||
${env.build_flags}
|
||||
-D BOARD=BOARD_GLOVE_IMU_SLIMEVR_DEV
|
||||
-DESP32C3
|
||||
-D PRODUCT_NAME='"SlimeVR Glove (dev)"'
|
||||
board = lolin_c3_mini
|
||||
monitor_filters = colorize, esp32_exception_decoder
|
||||
|
||||
@@ -36,7 +36,10 @@ except Exception:
|
||||
|
||||
output = f"-DGIT_REV='\"{revision}\"'"
|
||||
|
||||
if tag != "":
|
||||
fwVersion = os.environ.get("FIRMWARE_VERSION")
|
||||
if fwVersion is not None and fwVersion != "":
|
||||
output += f" -DFIRMWARE_VERSION='\"{fwVersion}\"'"
|
||||
elif tag != "":
|
||||
output += f" -DFIRMWARE_VERSION='\"{tag}\"'"
|
||||
elif branch != "":
|
||||
output += f" -DFIRMWARE_VERSION='\"{branch}\"'"
|
||||
|
||||
210
scripts/preprocessor.py
Normal file
210
scripts/preprocessor.py
Normal file
@@ -0,0 +1,210 @@
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Union, Optional, Dict, Any, List
|
||||
|
||||
Import("env")
|
||||
|
||||
try:
|
||||
import jsonschema
|
||||
except:
|
||||
env.Execute(
|
||||
env.VerboseAction(
|
||||
'$PYTHONEXE -m pip install "jsonschema==4.22.0"',
|
||||
"Installing jsonschema for validation",
|
||||
)
|
||||
)
|
||||
|
||||
from jsonschema import Draft202012Validator, exceptions as jsonschema_exceptions
|
||||
|
||||
|
||||
|
||||
def _load_json(maybe_path_or_dict: Union[str, Path, dict]) -> dict:
|
||||
"""Load JSON file or accept dict directly."""
|
||||
if isinstance(maybe_path_or_dict, dict):
|
||||
return maybe_path_or_dict
|
||||
p = Path(maybe_path_or_dict)
|
||||
if not p.exists():
|
||||
raise FileNotFoundError(f"File not found: {p}")
|
||||
try:
|
||||
return json.loads(p.read_text(encoding="utf-8"))
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(f"Invalid JSON file {p}: {e}")
|
||||
|
||||
# Allow:
|
||||
# - unquoted alphanumerics, underscores, dots, dashes
|
||||
# - or single-quoted with optional escaped double quotes inside
|
||||
VALID_DEFINE_VALUE = re.compile(
|
||||
r"^(?:[A-Za-z0-9_.\-]*|'(\\\"[A-Za-z0-9_.\-\s]*\\\"|[A-Za-z0-9_.\-\s]*)')$"
|
||||
)
|
||||
|
||||
def _validate_define_value(value: str, key: str) -> None:
|
||||
if key == "SENSOR_DESC_LIST":
|
||||
return
|
||||
|
||||
"""Validate the formatted define value to prevent injection."""
|
||||
if not VALID_DEFINE_VALUE.fullmatch(value):
|
||||
raise ValueError(
|
||||
f"Invalid characters in value for {key!r}: {value!r} "
|
||||
"(only letters, digits, _, ., -, spaces, and optional quoted forms like '\"text\"' allowed)"
|
||||
)
|
||||
|
||||
def _format_raw_value(value: Any) -> str:
|
||||
"""Format booleans for C/C++, otherwise str(value)."""
|
||||
if isinstance(value, bool):
|
||||
return "true" if value else "false"
|
||||
return str(value)
|
||||
|
||||
def format_value(val: Any, typ: str, key: str = "<unknown>") -> str:
|
||||
"""Format a value according to type, with built-in validation."""
|
||||
if typ == "pin":
|
||||
if isinstance(val, str) and re.search(r"[AD]", val):
|
||||
result = f'{val}'
|
||||
else:
|
||||
result = _format_raw_value(val)
|
||||
|
||||
elif typ == "string":
|
||||
result = f"'\\\"{val}\\\"'"
|
||||
|
||||
elif typ in ("raw", "number"):
|
||||
result = _format_raw_value(val)
|
||||
|
||||
else:
|
||||
raise ValueError(f"Value type '{typ}' is not supported")
|
||||
|
||||
|
||||
_validate_define_value(result, key)
|
||||
return result
|
||||
|
||||
|
||||
def _build_board_flags(defaults: dict, board_name: str) -> List[str]:
|
||||
"""Construct list of -D flags for one board."""
|
||||
if "defaults" not in defaults:
|
||||
raise ValueError("Missing top-level 'defaults' key in defaults JSON.")
|
||||
if board_name not in defaults["defaults"]:
|
||||
raise ValueError(f"Invalid board selected - {board_name}")
|
||||
|
||||
board_defaults = defaults["defaults"][board_name]
|
||||
values = board_defaults.get("values", {})
|
||||
|
||||
args: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
def add(key: str, value: Any, value_type: str):
|
||||
if value is not None:
|
||||
args[key] = {"value": value, "type": value_type}
|
||||
|
||||
add('BOARD', board_name, 'raw')
|
||||
add('LED_PIN', values.get('LED').get('LED_PIN'), 'pin')
|
||||
add('LED_INVERTED', values.get('LED').get('LED_INVERTED'), 'raw')
|
||||
|
||||
sensors = values.get('SENSORS')
|
||||
if sensors:
|
||||
sensor_list = []
|
||||
|
||||
add('PIN_IMU_SDA', 255, 'pin') # FIXME fix the I2C Scanner so it use the sensor list and not be called when no I2C sensor
|
||||
add('PIN_IMU_SCL', 255, 'pin')
|
||||
add('PIN_IMU_INT_2', 255, 'pin') # FIXME: fix the CONFIG serial command so it use the sensor list
|
||||
|
||||
for index, sensor in enumerate(sensors):
|
||||
if sensor.get('protocol') == 'I2C':
|
||||
params = [
|
||||
format_value(sensor.get('imu'), 'raw'),
|
||||
format_value(sensor.get('address', 'PRIMARY_IMU_ADDRESS_ONE' if index == 0 else 'SECONDARY_IMU_ADDRESS_TWO'), 'number'),
|
||||
format_value(sensor.get('rotation'), 'raw'),
|
||||
f"DIRECT_WIRE({format_value(sensor.get('scl'), 'pin')}, {format_value(sensor.get('sda'), 'pin')})",
|
||||
'false' if index == 0 else 'true',
|
||||
f"DIRECT_PIN({format_value(sensor.get('int', 255), 'pin')})",
|
||||
'0'
|
||||
]
|
||||
sensor_list.append(f"SENSOR_DESC_ENTRY({','.join(params)})")
|
||||
add('PIN_IMU_SDA', sensor.get('sda'), 'pin')
|
||||
add('PIN_IMU_SCL', sensor.get('scl'), 'pin')
|
||||
|
||||
if sensor.get('protocol') == 'SPI':
|
||||
params = [
|
||||
format_value(sensor.get('imu'), 'raw'),
|
||||
f"DIRECT_PIN({format_value(sensor.get('cs'), 'pin')})",
|
||||
format_value(sensor.get('rotation'), 'raw'),
|
||||
"DIRECT_SPI(24'000'000, MSBFIRST, SPI_MODE3)",
|
||||
'false' if index == 0 else 'true',
|
||||
f"DIRECT_PIN({format_value(sensor.get('int', 255), 'pin')})",
|
||||
'0'
|
||||
]
|
||||
sensor_list.append(f"SENSOR_DESC_ENTRY({','.join(params)})")
|
||||
|
||||
if index == 0: # FIXME: fix the CONFIG serial command so it use the sensor list
|
||||
add('PIN_IMU_INT', sensor.get('int'), 'pin')
|
||||
elif index == 1:
|
||||
add('PIN_IMU_INT_2', sensor.get('int'), 'pin')
|
||||
add('SENSOR_DESC_LIST', f"'{' '.join(sensor_list)}'", 'raw')
|
||||
|
||||
|
||||
battery = values.get('BATTERY')
|
||||
if battery:
|
||||
add('BATTERY_MONITOR', battery.get('type'), 'raw')
|
||||
add('PIN_BATTERY_LEVEL', battery.get('pin', 255), 'pin')
|
||||
add('BATTERY_SHIELD_RESISTANCE', battery.get('shieldR', 180), 'number')
|
||||
add('BATTERY_SHIELD_R1', battery.get('r1', 100), 'number')
|
||||
add('BATTERY_SHIELD_R2', battery.get('r2', 220), 'number')
|
||||
|
||||
parts: List[str] = []
|
||||
for key, meta in args.items():
|
||||
formatted = format_value(meta["value"], meta["type"], key)
|
||||
parts.append(f"-D{key}={formatted}")
|
||||
|
||||
return parts
|
||||
|
||||
|
||||
def build_boards(
|
||||
schema_obj,
|
||||
defaults_obj,
|
||||
board_name: Optional[str] = None,
|
||||
) -> Dict[str, List[str]]:
|
||||
"""
|
||||
Validate defaults.json against board-defaults.schema.json using jsonschema,
|
||||
and return { board_name: [list of -D flags] }.
|
||||
"""
|
||||
validator = Draft202012Validator(schema_obj)
|
||||
errors = sorted(validator.iter_errors(defaults_obj), key=lambda e: e.path)
|
||||
|
||||
if errors:
|
||||
print("✖ JSON Schema validation failed:")
|
||||
for err in errors:
|
||||
path = "/".join(map(str, err.path)) or "(root)"
|
||||
print(f" • Path: {path}")
|
||||
print(f" Error: {err.message}")
|
||||
if err.context:
|
||||
for ctx in err.context:
|
||||
print(f" ↳ {ctx.message}")
|
||||
raise ValueError(f"{len(errors)} schema validation errors found.")
|
||||
|
||||
out: Dict[str, List[str]] = {}
|
||||
if board_name:
|
||||
out[board_name] = _build_board_flags(defaults_obj, board_name)
|
||||
else:
|
||||
for name in defaults_obj.get("defaults", {}).keys():
|
||||
out[name] = _build_board_flags(defaults_obj, name)
|
||||
|
||||
return out
|
||||
|
||||
schema_obj = _load_json("./board-defaults.schema.json")
|
||||
defaults_obj = _load_json("./board-defaults.json")
|
||||
slime_board = env.GetProjectOption("custom_slime_board", None)
|
||||
if slime_board:
|
||||
if 'SLIMEVR_OVERRIDE_DEFAULTS' in os.environ and slime_board in defaults_obj['defaults']:
|
||||
print(">>> OVERIDING BOARD DEFAULTS ", os.environ['SLIMEVR_OVERRIDE_DEFAULTS'])
|
||||
defaults_obj['defaults'][slime_board]['values'] = json.loads(os.environ['SLIMEVR_OVERRIDE_DEFAULTS'])
|
||||
|
||||
output_flags = build_boards(
|
||||
schema_obj,
|
||||
defaults_obj,
|
||||
slime_board,
|
||||
)
|
||||
output_flags = output_flags.get(slime_board, []) if isinstance(output_flags, dict) else []
|
||||
|
||||
separator = '\n '
|
||||
print(f">>> Appending build flags:\n {separator.join(output_flags)}")
|
||||
env.Append(BUILD_FLAGS=output_flags)
|
||||
else:
|
||||
print(">>> custom_slime_board not set - skipping")
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "configuration/Configuration.h"
|
||||
#include "network/connection.h"
|
||||
#include "network/manager.h"
|
||||
#include "network/wifihandler.h"
|
||||
#include "network/wifiprovisioning.h"
|
||||
#include "sensors/SensorManager.h"
|
||||
#include "status/LEDManager.h"
|
||||
#include "status/StatusManager.h"
|
||||
@@ -40,3 +42,5 @@ extern SlimeVR::Sensors::SensorManager sensorManager;
|
||||
extern SlimeVR::Network::Manager networkManager;
|
||||
extern SlimeVR::Network::Connection networkConnection;
|
||||
extern BatteryMonitor battery;
|
||||
extern SlimeVR::WiFiNetwork wifiNetwork;
|
||||
extern SlimeVR::WifiProvisioning wifiProvisioning;
|
||||
|
||||
@@ -27,166 +27,6 @@
|
||||
|
||||
#include "defines_helpers.h"
|
||||
|
||||
// Board-specific configurations
|
||||
#if BOARD == BOARD_SLIMEVR
|
||||
|
||||
SDA(14)
|
||||
SCL(12)
|
||||
INT(16)
|
||||
INT2(13)
|
||||
BATTERY(17)
|
||||
LED(2)
|
||||
INVERTED_LED(true)
|
||||
BATTERY_SHIELD_R(0)
|
||||
BATTERY_R1(10)
|
||||
BATTERY_R2(40.2)
|
||||
|
||||
#elif BOARD == BOARD_SLIMEVR_V1_2
|
||||
|
||||
SDA(4)
|
||||
SCL(5)
|
||||
INT(2)
|
||||
INT2(16)
|
||||
BATTERY(17)
|
||||
LED(2)
|
||||
INVERTED_LED(true)
|
||||
BATTERY_SHIELD_R(0)
|
||||
BATTERY_R1(10)
|
||||
BATTERY_R2(40.2)
|
||||
|
||||
#elif BOARD == BOARD_SLIMEVR_LEGACY || BOARD == BOARD_SLIMEVR_DEV
|
||||
|
||||
SDA(4)
|
||||
SCL(5)
|
||||
INT(10)
|
||||
INT2(13)
|
||||
BATTERY(17)
|
||||
LED(2)
|
||||
INVERTED_LED(true)
|
||||
BATTERY_SHIELD_R(0)
|
||||
BATTERY_R1(10)
|
||||
BATTERY_R2(40.2)
|
||||
|
||||
#elif BOARD == BOARD_NODEMCU || BOARD == BOARD_WEMOSD1MINI
|
||||
|
||||
SDA(D2)
|
||||
SCL(D1)
|
||||
INT(D5)
|
||||
INT2(D6)
|
||||
BATTERY(A0)
|
||||
BATTERY_SHIELD_R(180)
|
||||
BATTERY_R1(100)
|
||||
BATTERY_R2(220)
|
||||
|
||||
#elif BOARD == BOARD_ESP01
|
||||
|
||||
SDA(2)
|
||||
SCL(0)
|
||||
INT(255)
|
||||
INT2(255)
|
||||
BATTERY(255)
|
||||
LED(LED_OFF)
|
||||
INVERTED_LED(false)
|
||||
|
||||
#elif BOARD == BOARD_TTGO_TBASE
|
||||
|
||||
SDA(5)
|
||||
SCL(4)
|
||||
INT(14)
|
||||
INT2(13)
|
||||
BATTERY(A0)
|
||||
|
||||
#elif BOARD == BOARD_CUSTOM
|
||||
|
||||
// Define pins by the examples above
|
||||
|
||||
#elif BOARD == BOARD_WROOM32
|
||||
|
||||
SDA(21)
|
||||
SCL(22)
|
||||
INT(23)
|
||||
INT2(25)
|
||||
BATTERY(36)
|
||||
|
||||
#elif BOARD == BOARD_LOLIN_C3_MINI
|
||||
|
||||
SDA(5)
|
||||
SCL(4)
|
||||
INT(6)
|
||||
INT2(8)
|
||||
BATTERY(3)
|
||||
LED(7)
|
||||
|
||||
#elif BOARD == BOARD_BEETLE32C3
|
||||
|
||||
SDA(8)
|
||||
SCL(9)
|
||||
INT(6)
|
||||
INT2(7)
|
||||
BATTERY(3)
|
||||
LED(10)
|
||||
INVERTED_LED(false)
|
||||
|
||||
#elif BOARD == BOARD_ESP32C3DEVKITM1 || BOARD == BOARD_ESP32C6DEVKITC1
|
||||
|
||||
SDA(5)
|
||||
SCL(4)
|
||||
INT(6)
|
||||
INT2(7)
|
||||
BATTERY(3)
|
||||
LED(LED_OFF)
|
||||
|
||||
#elif BOARD == BOARD_WEMOSWROOM02
|
||||
|
||||
SDA(2)
|
||||
SCL(14)
|
||||
INT(0)
|
||||
INT2(4)
|
||||
BATTERY(A0)
|
||||
LED(16)
|
||||
INVERTED_LED(true)
|
||||
|
||||
#elif BOARD == BOARD_XIAO_ESP32C3
|
||||
|
||||
SDA(6)
|
||||
SCL(7) // D5
|
||||
INT(5) // D3
|
||||
INT2(10) // D10
|
||||
LED(4) // D2
|
||||
INVERTED_LED(false)
|
||||
BATTERY(2) // D0 / A0
|
||||
BATTERY_SHIELD_R(0)
|
||||
BATTERY_R1(100)
|
||||
BATTERY_R2(100)
|
||||
|
||||
#elif BOARD == BOARD_GLOVE_IMU_SLIMEVR_DEV
|
||||
|
||||
SDA(1)
|
||||
SCL(0)
|
||||
#define PCA_ADDR 0x70
|
||||
INT(16)
|
||||
INT2(13)
|
||||
BATTERY(3)
|
||||
LED(2)
|
||||
INVERTED_LED(true)
|
||||
BATTERY_SHIELD_R(0)
|
||||
BATTERY_R1(10)
|
||||
BATTERY_R2(40.2)
|
||||
|
||||
#elif BOARD == BOARD_ESP32S3_SUPERMINI
|
||||
|
||||
SDA(7)
|
||||
SCL(6)
|
||||
INT(5)
|
||||
INT2(4)
|
||||
BATTERY(A2) // IO3
|
||||
BATTERY_SHIELD_R(0)
|
||||
BATTERY_R1(10)
|
||||
BATTERY_R2(40.2)
|
||||
LED(LED_BUILTIN)
|
||||
|
||||
#endif
|
||||
|
||||
// Default IMU pinouts and definitions for default tracker types
|
||||
|
||||
#if BOARD != BOARD_GLOVE_IMU_SLIMEVR_DEV
|
||||
@@ -253,6 +93,18 @@ PIN_IMU_SDA, PRIMARY_IMU_OPTIONAL, BMI160_QMC_REMAP) \
|
||||
#endif
|
||||
#else // BOARD == BOARD_GLOVE_IMU_SLIMEVR_DEV
|
||||
|
||||
SDA(1)
|
||||
SCL(0)
|
||||
#define PCA_ADDR 0x70
|
||||
INT(16)
|
||||
INT2(13)
|
||||
BATTERY(3)
|
||||
LED(2)
|
||||
INVERTED_LED(true)
|
||||
BATTERY_SHIELD_R(0)
|
||||
BATTERY_R1(10)
|
||||
BATTERY_R2(40.2)
|
||||
|
||||
#include "glove_default.h"
|
||||
|
||||
#endif // BOARD != BOARD_GLOVE_IMU_SLIMEVR_DEV
|
||||
|
||||
@@ -29,5 +29,10 @@
|
||||
#define LED_BUILTIN LED_OFF
|
||||
#endif
|
||||
|
||||
#ifndef LED_PIN
|
||||
extern const uint8_t __attribute__((weak)) LED_PIN = LED_BUILTIN;
|
||||
#endif
|
||||
|
||||
#ifndef LED_INVERTED
|
||||
extern const bool __attribute__((weak)) LED_INVERTED = true;
|
||||
#endif
|
||||
|
||||
@@ -25,13 +25,18 @@
|
||||
|
||||
#include <LittleFS.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "../FSHelper.h"
|
||||
#include "consts.h"
|
||||
#include "sensors/SensorToggles.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define DIR_CALIBRATIONS "/calibrations"
|
||||
#define DIR_TEMPERATURE_CALIBRATIONS "/tempcalibrations"
|
||||
#define DIR_TOGGLES "/toggles"
|
||||
#define DIR_TOGGLES_OLD "/toggles"
|
||||
#define DIR_TOGGLES "/sensortoggles"
|
||||
|
||||
namespace SlimeVR::Configuration {
|
||||
void Configuration::setup() {
|
||||
@@ -118,13 +123,21 @@ void Configuration::save() {
|
||||
file.write((uint8_t*)&config, sizeof(SensorConfig));
|
||||
file.close();
|
||||
|
||||
sprintf(path, DIR_TOGGLES "/%zu", i);
|
||||
if (i < m_SensorToggles.size()) {
|
||||
sprintf(path, DIR_TOGGLES "/%zu", i);
|
||||
|
||||
m_Logger.trace("Saving sensor toggle state for %d", i);
|
||||
m_Logger.trace("Saving sensor toggle state for %d", i);
|
||||
|
||||
file = LittleFS.open(path, "w");
|
||||
file.write((uint8_t*)&m_SensorToggles[i], sizeof(SensorToggleState));
|
||||
file.close();
|
||||
file = LittleFS.open(path, "w");
|
||||
auto toggleValues = m_SensorToggles[i].getValues();
|
||||
file.write((uint8_t*)&toggleValues, sizeof(SensorToggleValues));
|
||||
file.close();
|
||||
} else {
|
||||
m_Logger.trace(
|
||||
"Skipping saving toggles for sensor %d, no toggles present",
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -133,6 +146,18 @@ void Configuration::save() {
|
||||
file.close();
|
||||
}
|
||||
|
||||
// Clean up old toggles directory
|
||||
if (LittleFS.exists(DIR_TOGGLES_OLD)) {
|
||||
char path[17] = DIR_TOGGLES_OLD;
|
||||
char* end = path + strlen(DIR_TOGGLES_OLD);
|
||||
Utils::forEachFile(DIR_TOGGLES_OLD, [&](SlimeVR::Utils::File file) {
|
||||
sprintf(end, "/%s", file.name());
|
||||
LittleFS.remove(path);
|
||||
file.close();
|
||||
});
|
||||
LittleFS.rmdir(DIR_TOGGLES_OLD);
|
||||
}
|
||||
|
||||
m_Logger.debug("Saved configuration");
|
||||
}
|
||||
|
||||
@@ -226,14 +251,34 @@ void Configuration::loadSensors() {
|
||||
setSensor(sensorId, sensorConfig);
|
||||
});
|
||||
|
||||
if (LittleFS.exists(DIR_TOGGLES_OLD)) {
|
||||
SlimeVR::Utils::forEachFile(DIR_TOGGLES_OLD, [&](SlimeVR::Utils::File f) {
|
||||
SensorToggleValues values;
|
||||
// Migration for pre 0.7.0 togglestate, the values started at offset 20 and
|
||||
// there were 3 of them
|
||||
f.seek(20);
|
||||
f.read(reinterpret_cast<uint8_t*>(&values), 3);
|
||||
|
||||
uint8_t sensorId = strtoul(f.name(), nullptr, 10);
|
||||
m_Logger.debug("Found sensor toggle state at index %d", sensorId);
|
||||
|
||||
setSensorToggles(sensorId, SensorToggleState{values});
|
||||
});
|
||||
}
|
||||
|
||||
SlimeVR::Utils::forEachFile(DIR_TOGGLES, [&](SlimeVR::Utils::File f) {
|
||||
SensorToggleState sensorToggleState;
|
||||
f.read((uint8_t*)&sensorToggleState, sizeof(SensorToggleState));
|
||||
if (f.size() > sizeof(SensorToggleValues)) {
|
||||
return;
|
||||
}
|
||||
SensorToggleValues values;
|
||||
// With the magic of C++ default initialization, the rest of the values should
|
||||
// be their default after reading
|
||||
f.read(reinterpret_cast<uint8_t*>(&values), f.size());
|
||||
|
||||
uint8_t sensorId = strtoul(f.name(), nullptr, 10);
|
||||
m_Logger.debug("Found sensor toggle state at index %d", sensorId);
|
||||
|
||||
setSensorToggles(sensorId, sensorToggleState);
|
||||
setSensorToggles(sensorId, SensorToggleState{values});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,9 @@ enum class SensorTypeID : uint8_t {
|
||||
#define BOARD_GESTURES 21 // Used by Gestures
|
||||
#define BOARD_SLIMEVR_V1_2 22 // SlimeVR v1.2
|
||||
#define BOARD_ESP32S3_SUPERMINI 23
|
||||
#define BOARD_GENERIC_NRF 24
|
||||
#define BOARD_SLIMEVR_BUTTERFLY_DEV 25
|
||||
#define BOARD_SLIMEVR_BUTTERFLY 26
|
||||
#define BOARD_DEV_RESERVED 250 // Reserved, should not be used in any release firmware
|
||||
|
||||
#define BAT_EXTERNAL 1
|
||||
@@ -152,6 +155,8 @@ enum class SensorTypeID : uint8_t {
|
||||
#define MCU_ESP32_C3 6
|
||||
#define MCU_MOCOPI 7 // Used by mocopi/moslime
|
||||
#define MCU_HARITORA 8 // Used by Haritora/SlimeTora
|
||||
#define MCU_NRF52 9
|
||||
#define MCU_NRF54L 10
|
||||
#define MCU_DEV_RESERVED 250 // Reserved, should not be used in any release firmware
|
||||
|
||||
enum class SensorDataType : uint8_t {
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
// disable if problems. Server does nothing with value so disabled atm
|
||||
#define SEND_ACCELERATION true // send linear acceleration to the server
|
||||
|
||||
#define EXT_SERIAL_COMMANDS false // Set to true to enable extra serial debug commands
|
||||
|
||||
// Debug information
|
||||
|
||||
#define LOG_LEVEL LOG_LEVEL_DEBUG
|
||||
@@ -94,7 +96,7 @@
|
||||
// Not recommended for production
|
||||
#define ENABLE_INSPECTION false
|
||||
|
||||
#define PROTOCOL_VERSION 21
|
||||
#define PROTOCOL_VERSION 22
|
||||
|
||||
#ifndef FIRMWARE_VERSION
|
||||
#define FIRMWARE_VERSION "UNKNOWN"
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
#define EXPERIMENTAL_BNO_DISABLE_ACCEL_CALIBRATION true
|
||||
#endif
|
||||
|
||||
#ifndef IMU_USE_EXTERNAL_CLOCK
|
||||
#define IMU_USE_EXTERNAL_CLOCK true // Use external clock for IMU (ICM-45686 only)
|
||||
#endif
|
||||
|
||||
#ifndef VENDOR_NAME
|
||||
#define VENDOR_NAME "Unknown"
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,8 @@ SlimeVR::Status::StatusManager statusManager;
|
||||
SlimeVR::Configuration::Configuration configuration;
|
||||
SlimeVR::Network::Manager networkManager;
|
||||
SlimeVR::Network::Connection networkConnection;
|
||||
SlimeVR::WiFiNetwork wifiNetwork;
|
||||
SlimeVR::WifiProvisioning wifiProvisioning;
|
||||
|
||||
#if DEBUG_MEASURE_SENSOR_TIME_TAKEN
|
||||
SlimeVR::Debugging::TimeTakenMeasurer sensorMeasurer{"Sensors"};
|
||||
|
||||
@@ -620,6 +620,9 @@ void Connection::reset() {
|
||||
|
||||
m_UDP.begin(m_ServerPort);
|
||||
|
||||
// Reset server address to broadcast if disconnected
|
||||
m_ServerHost = IPAddress(255, 255, 255, 255);
|
||||
|
||||
statusManager.setStatus(SlimeVR::Status::SERVER_CONNECTING, true);
|
||||
}
|
||||
|
||||
@@ -650,6 +653,9 @@ void Connection::update() {
|
||||
);
|
||||
m_Logger.warn("Connection to server timed out");
|
||||
|
||||
// Reset server address to broadcast if disconnected
|
||||
m_ServerHost = IPAddress(255, 255, 255, 255);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -658,7 +664,6 @@ void Connection::update() {
|
||||
return;
|
||||
}
|
||||
|
||||
m_LastPacketTimestamp = millis();
|
||||
int len = m_UDP.read(m_Packet, sizeof(m_Packet));
|
||||
|
||||
#ifdef DEBUG_NETWORK
|
||||
@@ -673,6 +678,12 @@ void Connection::update() {
|
||||
(void)packetSize;
|
||||
#endif
|
||||
|
||||
if (static_cast<ReceivePacketType>(m_Packet[3]) == ReceivePacketType::Handshake) {
|
||||
m_Logger.warn("Handshake received again, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
m_LastPacketTimestamp = millis();
|
||||
switch (static_cast<ReceivePacketType>(m_Packet[3])) {
|
||||
case ReceivePacketType::HeartBeat:
|
||||
sendHeartbeat();
|
||||
@@ -682,8 +693,7 @@ void Connection::update() {
|
||||
break;
|
||||
|
||||
case ReceivePacketType::Handshake:
|
||||
// Assume handshake successful
|
||||
m_Logger.warn("Handshake received again, ignoring");
|
||||
// handled above
|
||||
break;
|
||||
|
||||
case ReceivePacketType::Command:
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
|
||||
namespace SlimeVR::Network {
|
||||
|
||||
void Manager::setup() { ::WiFiNetwork::setUp(); }
|
||||
void Manager::setup() { wifiNetwork.setUp(); }
|
||||
|
||||
void Manager::update() {
|
||||
WiFiNetwork::upkeep();
|
||||
wifiNetwork.upkeep();
|
||||
|
||||
auto wasConnected = m_IsConnected;
|
||||
|
||||
m_IsConnected = ::WiFiNetwork::isConnected();
|
||||
m_IsConnected = wifiNetwork.isConnected();
|
||||
|
||||
if (!m_IsConnected) {
|
||||
return;
|
||||
|
||||
@@ -54,6 +54,7 @@ enum class SendPacketType : uint8_t {
|
||||
// RotationAcceleration = 23,
|
||||
AcknowledgeConfigChange = 24,
|
||||
FlexData = 26,
|
||||
// PositionData = 27,
|
||||
Bundle = 100,
|
||||
Inspection = 105,
|
||||
};
|
||||
|
||||
@@ -20,31 +20,25 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#include "network/wifihandler.h"
|
||||
|
||||
#include "GlobalVars.h"
|
||||
#include "globals.h"
|
||||
#include "logging/Logger.h"
|
||||
#if !ESP8266
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_types.h"
|
||||
#endif
|
||||
|
||||
unsigned long lastWifiReportTime = 0;
|
||||
unsigned long wifiConnectionTimeout = millis();
|
||||
bool isWifiConnected = false;
|
||||
uint8_t wifiState = SLIME_WIFI_NOT_SETUP;
|
||||
bool hadWifi = false;
|
||||
unsigned long last_rssi_sample = 0;
|
||||
namespace SlimeVR {
|
||||
|
||||
// TODO: Cleanup with proper classes
|
||||
SlimeVR::Logging::Logger wifiHandlerLogger("WiFiHandler");
|
||||
|
||||
void reportWifiError() {
|
||||
void WiFiNetwork::reportWifiProgress() {
|
||||
if (lastWifiReportTime + 1000 < millis()) {
|
||||
lastWifiReportTime = millis();
|
||||
Serial.print(".");
|
||||
}
|
||||
}
|
||||
|
||||
void setStaticIPIfDefined() {
|
||||
void WiFiNetwork::setStaticIPIfDefined() {
|
||||
#ifdef WIFI_USE_STATICIP
|
||||
const IPAddress ip(WIFI_STATIC_IP);
|
||||
const IPAddress gateway(WIFI_STATIC_GATEWAY);
|
||||
@@ -53,16 +47,17 @@ void setStaticIPIfDefined() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WiFiNetwork::isConnected() { return isWifiConnected; }
|
||||
bool WiFiNetwork::isConnected() const {
|
||||
return wifiState == WiFiReconnectionStatus::Success;
|
||||
}
|
||||
|
||||
void WiFiNetwork::setWiFiCredentials(const char* SSID, const char* pass) {
|
||||
stopProvisioning();
|
||||
setStaticIPIfDefined();
|
||||
WiFi.begin(SSID, pass);
|
||||
wifiProvisioning.stopProvisioning();
|
||||
tryConnecting(false, SSID, pass);
|
||||
retriedOnG = false;
|
||||
// Reset state, will get back into provisioning if can't connect
|
||||
hadWifi = false;
|
||||
wifiState = SLIME_WIFI_SERVER_CRED_ATTEMPT;
|
||||
wifiConnectionTimeout = millis();
|
||||
wifiState = WiFiReconnectionStatus::ServerCredAttempt;
|
||||
}
|
||||
|
||||
IPAddress WiFiNetwork::getAddress() { return WiFi.localIP(); }
|
||||
@@ -71,25 +66,14 @@ void WiFiNetwork::setUp() {
|
||||
wifiHandlerLogger.info("Setting up WiFi");
|
||||
WiFi.persistent(true);
|
||||
WiFi.mode(WIFI_STA);
|
||||
#if ESP8266
|
||||
#if USE_ATTENUATION
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_N);
|
||||
#endif
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
WiFi.hostname("SlimeVR FBT Tracker");
|
||||
wifiHandlerLogger.info(
|
||||
"Loaded credentials for SSID '%s' and pass length %d",
|
||||
WiFi.SSID().c_str(),
|
||||
WiFi.psk().length()
|
||||
getSSID().c_str(),
|
||||
getPassword().length()
|
||||
);
|
||||
setStaticIPIfDefined();
|
||||
wl_status_t status = WiFi.begin(
|
||||
); // Should connect to last used access point, see
|
||||
// https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/station-class.html#begin
|
||||
wifiHandlerLogger.debug("Status: %d", status);
|
||||
wifiState = SLIME_WIFI_SAVED_ATTEMPT;
|
||||
wifiConnectionTimeout = millis();
|
||||
|
||||
trySavedCredentials();
|
||||
|
||||
#if ESP8266
|
||||
#if POWERSAVING_MODE == POWER_SAVING_NONE
|
||||
@@ -121,156 +105,283 @@ void WiFiNetwork::setUp() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void onConnected() {
|
||||
WiFiNetwork::stopProvisioning();
|
||||
void WiFiNetwork::onConnected() {
|
||||
wifiState = WiFiReconnectionStatus::Success;
|
||||
wifiProvisioning.stopProvisioning();
|
||||
statusManager.setStatus(SlimeVR::Status::WIFI_CONNECTING, false);
|
||||
isWifiConnected = true;
|
||||
hadWifi = true;
|
||||
wifiHandlerLogger.info(
|
||||
"Connected successfully to SSID '%s', IP address %s",
|
||||
WiFi.SSID().c_str(),
|
||||
getSSID().c_str(),
|
||||
WiFi.localIP().toString().c_str()
|
||||
);
|
||||
// Reset it, in case we just connected with server creds
|
||||
}
|
||||
|
||||
uint8_t WiFiNetwork::getWiFiState() { return wifiState; }
|
||||
String WiFiNetwork::getSSID() {
|
||||
#if ESP8266
|
||||
return WiFi.SSID();
|
||||
#else
|
||||
// Necessary, because without a WiFi.begin(), ESP32 is not kind enough to load the
|
||||
// SSID on its own, for whatever reason
|
||||
wifi_config_t wifiConfig;
|
||||
esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, &wifiConfig);
|
||||
return {reinterpret_cast<char*>(wifiConfig.sta.ssid)};
|
||||
#endif
|
||||
}
|
||||
|
||||
String WiFiNetwork::getPassword() {
|
||||
#if ESP8266
|
||||
return WiFi.psk();
|
||||
#else
|
||||
// Same as above
|
||||
wifi_config_t wifiConfig;
|
||||
esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, &wifiConfig);
|
||||
return {reinterpret_cast<char*>(wifiConfig.sta.password)};
|
||||
#endif
|
||||
}
|
||||
|
||||
WiFiNetwork::WiFiReconnectionStatus WiFiNetwork::getWiFiState() { return wifiState; }
|
||||
|
||||
void WiFiNetwork::upkeep() {
|
||||
upkeepProvisioning();
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
if (isWifiConnected) {
|
||||
wifiHandlerLogger.warn("Connection to WiFi lost, reconnecting...");
|
||||
isWifiConnected = false;
|
||||
wifiProvisioning.upkeepProvisioning();
|
||||
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
if (!isConnected()) {
|
||||
onConnected();
|
||||
return;
|
||||
}
|
||||
statusManager.setStatus(SlimeVR::Status::WIFI_CONNECTING, true);
|
||||
reportWifiError();
|
||||
if (wifiConnectionTimeout + 11000 < millis()) {
|
||||
switch (wifiState) {
|
||||
case SLIME_WIFI_NOT_SETUP: // Wasn't set up
|
||||
return;
|
||||
case SLIME_WIFI_SAVED_ATTEMPT: // Couldn't connect with first set of
|
||||
// credentials
|
||||
#if ESP8266
|
||||
// Try again but with 11G but only if there are credentials,
|
||||
// otherwise we just waste time before switching to hardcoded
|
||||
// credentials.
|
||||
if (WiFi.SSID().length() > 0) {
|
||||
#if USE_ATTENUATION
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_G);
|
||||
#endif
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11G);
|
||||
setStaticIPIfDefined();
|
||||
WiFi.begin();
|
||||
wifiConnectionTimeout = millis();
|
||||
wifiHandlerLogger.error(
|
||||
"Can't connect from saved credentials, status: %d.",
|
||||
WiFi.status()
|
||||
);
|
||||
wifiHandlerLogger.debug(
|
||||
"Trying saved credentials with PHY Mode G..."
|
||||
);
|
||||
} else {
|
||||
wifiHandlerLogger.debug(
|
||||
"Skipping PHY Mode G attempt on 0-length SSID..."
|
||||
);
|
||||
}
|
||||
#endif
|
||||
wifiState = SLIME_WIFI_SAVED_G_ATTEMPT;
|
||||
return;
|
||||
case SLIME_WIFI_SAVED_G_ATTEMPT: // Couldn't connect with first set of
|
||||
// credentials with PHY Mode G
|
||||
#if defined(WIFI_CREDS_SSID) && defined(WIFI_CREDS_PASSWD)
|
||||
// Try hardcoded credentials now
|
||||
#if ESP8266
|
||||
#if USE_ATTENUATION
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_N);
|
||||
#endif
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
setStaticIPIfDefined();
|
||||
WiFi.begin(WIFI_CREDS_SSID, WIFI_CREDS_PASSWD);
|
||||
wifiConnectionTimeout = millis();
|
||||
wifiHandlerLogger.error(
|
||||
"Can't connect from saved credentials, status: %d.",
|
||||
WiFi.status()
|
||||
);
|
||||
wifiHandlerLogger.debug("Trying hardcoded credentials...");
|
||||
#endif
|
||||
wifiState = SLIME_WIFI_HARDCODE_ATTEMPT;
|
||||
return;
|
||||
case SLIME_WIFI_HARDCODE_ATTEMPT: // Couldn't connect with second set
|
||||
// of credentials
|
||||
#if defined(WIFI_CREDS_SSID) && defined(WIFI_CREDS_PASSWD) && ESP8266
|
||||
// Try hardcoded credentials again,
|
||||
// but with PHY Mode G
|
||||
#if USE_ATTENUATION
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_G);
|
||||
#endif
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11G);
|
||||
setStaticIPIfDefined();
|
||||
WiFi.begin(WIFI_CREDS_SSID, WIFI_CREDS_PASSWD);
|
||||
wifiConnectionTimeout = millis();
|
||||
wifiHandlerLogger.error(
|
||||
"Can't connect from saved credentials, status: %d.",
|
||||
WiFi.status()
|
||||
);
|
||||
wifiHandlerLogger.debug(
|
||||
"Trying hardcoded credentials with WiFi PHY Mode G..."
|
||||
);
|
||||
#endif
|
||||
wifiState = SLIME_WIFI_HARDCODE_G_ATTEMPT;
|
||||
return;
|
||||
case SLIME_WIFI_SERVER_CRED_ATTEMPT: // Couldn't connect with
|
||||
// server-sent credentials.
|
||||
#if ESP8266
|
||||
// Try again silently but with 11G
|
||||
#if USE_ATTENUATION
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_G);
|
||||
#endif
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11G);
|
||||
setStaticIPIfDefined();
|
||||
WiFi.begin();
|
||||
wifiConnectionTimeout = millis();
|
||||
wifiState = SLIME_WIFI_SERVER_CRED_G_ATTEMPT;
|
||||
#endif
|
||||
return;
|
||||
case SLIME_WIFI_HARDCODE_G_ATTEMPT: // Couldn't connect with second set
|
||||
// of credentials with PHY Mode G.
|
||||
case SLIME_WIFI_SERVER_CRED_G_ATTEMPT: // Or if couldn't connect with
|
||||
// server-sent credentials
|
||||
// Return to the default PHY Mode N.
|
||||
#if ESP8266
|
||||
#if USE_ATTENUATION
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_N);
|
||||
#endif
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
// Start smart config
|
||||
if (!hadWifi && !WiFi.smartConfigDone()
|
||||
&& wifiConnectionTimeout + 11000 < millis()) {
|
||||
if (WiFi.status() != WL_IDLE_STATUS) {
|
||||
wifiHandlerLogger.error(
|
||||
"Can't connect from any credentials, status: %d.",
|
||||
WiFi.status()
|
||||
);
|
||||
wifiConnectionTimeout = millis();
|
||||
}
|
||||
startProvisioning();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!isWifiConnected) {
|
||||
onConnected();
|
||||
return;
|
||||
} else {
|
||||
if (millis() - last_rssi_sample >= 2000) {
|
||||
last_rssi_sample = millis();
|
||||
|
||||
if (millis() - lastRssiSample >= 2000) {
|
||||
lastRssiSample = millis();
|
||||
uint8_t signalStrength = WiFi.RSSI();
|
||||
networkConnection.sendSignalStrength(signalStrength);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isConnected()) {
|
||||
statusManager.setStatus(SlimeVR::Status::WIFI_CONNECTING, true);
|
||||
wifiHandlerLogger.warn("Connection to WiFi lost, reconnecting...");
|
||||
trySavedCredentials();
|
||||
return;
|
||||
}
|
||||
|
||||
if (wifiState != WiFiReconnectionStatus::Failed) {
|
||||
reportWifiProgress();
|
||||
}
|
||||
|
||||
if (millis() - wifiConnectionTimeout
|
||||
< static_cast<uint32_t>(WiFiTimeoutSeconds * 1000)
|
||||
&& WiFi.status() == WL_DISCONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (wifiState) {
|
||||
case WiFiReconnectionStatus::NotSetup: // Wasn't set up
|
||||
return;
|
||||
case WiFiReconnectionStatus::SavedAttempt: // Couldn't connect with
|
||||
// first set of
|
||||
// credentials
|
||||
if (!trySavedCredentials()) {
|
||||
tryHardcodedCredentials();
|
||||
}
|
||||
return;
|
||||
case WiFiReconnectionStatus::HardcodeAttempt: // Couldn't connect with
|
||||
// second set of credentials
|
||||
if (!tryHardcodedCredentials()) {
|
||||
wifiState = WiFiReconnectionStatus::Failed;
|
||||
}
|
||||
return;
|
||||
case WiFiReconnectionStatus::ServerCredAttempt: // Couldn't connect with
|
||||
// server-sent credentials.
|
||||
if (!tryServerCredentials()) {
|
||||
wifiState = WiFiReconnectionStatus::Failed;
|
||||
}
|
||||
return;
|
||||
case WiFiReconnectionStatus::Failed: // Couldn't connect with second set of
|
||||
// credentials or server credentials
|
||||
// Return to the default PHY Mode N.
|
||||
#if ESP8266
|
||||
if constexpr (USE_ATTENUATION) {
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_N);
|
||||
}
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
// Start smart config
|
||||
if (!hadWifi && !WiFi.smartConfigDone()
|
||||
&& millis() - wifiConnectionTimeout
|
||||
>= static_cast<uint32_t>(WiFiTimeoutSeconds * 1000)) {
|
||||
if (WiFi.status() != WL_IDLE_STATUS) {
|
||||
wifiHandlerLogger.error(
|
||||
"Can't connect from any credentials, error: %d, reason: %s.",
|
||||
static_cast<int>(statusToFailure(WiFi.status())),
|
||||
statusToReasonString(WiFi.status())
|
||||
);
|
||||
wifiConnectionTimeout = millis();
|
||||
}
|
||||
wifiProvisioning.startProvisioning();
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const char* WiFiNetwork::statusToReasonString(wl_status_t status) {
|
||||
switch (status) {
|
||||
case WL_DISCONNECTED:
|
||||
return "Timeout";
|
||||
#ifdef ESP8266
|
||||
case WL_WRONG_PASSWORD:
|
||||
return "Wrong password";
|
||||
case WL_CONNECT_FAILED:
|
||||
return "Connection failed";
|
||||
#elif ESP32
|
||||
case WL_CONNECT_FAILED:
|
||||
return "Wrong password";
|
||||
#endif
|
||||
|
||||
case WL_NO_SSID_AVAIL:
|
||||
return "SSID not found";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
WiFiNetwork::WiFiFailureReason WiFiNetwork::statusToFailure(wl_status_t status) {
|
||||
switch (status) {
|
||||
case WL_DISCONNECTED:
|
||||
return WiFiFailureReason::Timeout;
|
||||
#ifdef ESP8266
|
||||
case WL_WRONG_PASSWORD:
|
||||
return WiFiFailureReason::WrongPassword;
|
||||
#elif ESP32
|
||||
case WL_CONNECT_FAILED:
|
||||
return WiFiFailureReason::WrongPassword;
|
||||
#endif
|
||||
|
||||
case WL_NO_SSID_AVAIL:
|
||||
return WiFiFailureReason::SSIDNotFound;
|
||||
default:
|
||||
return WiFiFailureReason::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiNetwork::showConnectionAttemptFailed(const char* type) const {
|
||||
wifiHandlerLogger.error(
|
||||
"Can't connect from %s credentials, error: %d, reason: %s.",
|
||||
type,
|
||||
static_cast<int>(statusToFailure(WiFi.status())),
|
||||
statusToReasonString(WiFi.status())
|
||||
);
|
||||
}
|
||||
|
||||
bool WiFiNetwork::trySavedCredentials() {
|
||||
if (getSSID().length() == 0) {
|
||||
wifiHandlerLogger.debug("Skipping saved credentials attempt on 0-length SSID..."
|
||||
);
|
||||
wifiState = WiFiReconnectionStatus::HardcodeAttempt;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wifiState == WiFiReconnectionStatus::SavedAttempt) {
|
||||
showConnectionAttemptFailed("saved");
|
||||
|
||||
if (WiFi.status() != WL_DISCONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (retriedOnG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
retriedOnG = true;
|
||||
wifiHandlerLogger.debug("Trying saved credentials with PHY Mode G...");
|
||||
return tryConnecting(true);
|
||||
}
|
||||
|
||||
retriedOnG = false;
|
||||
|
||||
wifiState = WiFiReconnectionStatus::SavedAttempt;
|
||||
return tryConnecting();
|
||||
}
|
||||
|
||||
bool WiFiNetwork::tryHardcodedCredentials() {
|
||||
#if defined(WIFI_CREDS_SSID) && defined(WIFI_CREDS_PASSWD)
|
||||
if (wifiState == WiFiReconnectionStatus::HardcodeAttempt) {
|
||||
showConnectionAttemptFailed("hardcoded");
|
||||
|
||||
if (WiFi.status() != WL_DISCONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (retriedOnG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
retriedOnG = true;
|
||||
wifiHandlerLogger.debug("Trying hardcoded credentials with PHY Mode G...");
|
||||
// Don't need to save hardcoded credentials
|
||||
WiFi.persistent(false);
|
||||
auto result = tryConnecting(true, WIFI_CREDS_SSID, WIFI_CREDS_PASSWD);
|
||||
WiFi.persistent(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
retriedOnG = false;
|
||||
|
||||
wifiState = WiFiReconnectionStatus::HardcodeAttempt;
|
||||
// Don't need to save hardcoded credentials
|
||||
WiFi.persistent(false);
|
||||
auto result = tryConnecting(false, WIFI_CREDS_SSID, WIFI_CREDS_PASSWD);
|
||||
WiFi.persistent(true);
|
||||
return result;
|
||||
#else
|
||||
wifiState = WiFiReconnectionStatus::HardcodeAttempt;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool WiFiNetwork::tryServerCredentials() {
|
||||
if (WiFi.status() != WL_DISCONNECTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (retriedOnG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
retriedOnG = true;
|
||||
|
||||
return tryConnecting(true);
|
||||
}
|
||||
|
||||
bool WiFiNetwork::tryConnecting(bool phyModeG, const char* SSID, const char* pass) {
|
||||
#if ESP8266
|
||||
if (phyModeG) {
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11G);
|
||||
if constexpr (USE_ATTENUATION) {
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_G);
|
||||
}
|
||||
} else {
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
if constexpr (USE_ATTENUATION) {
|
||||
WiFi.setOutputPower(20.0 - ATTENUATION_N);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (phyModeG) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
setStaticIPIfDefined();
|
||||
if (SSID == nullptr) {
|
||||
WiFi.begin();
|
||||
} else {
|
||||
WiFi.begin(SSID, pass);
|
||||
}
|
||||
wifiConnectionTimeout = millis();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace SlimeVR
|
||||
|
||||
@@ -20,33 +20,78 @@
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
#ifndef SLIMEVR_WIFI_H_
|
||||
#define SLIMEVR_WIFI_H_
|
||||
#pragma once
|
||||
|
||||
#include "logging/Logger.h"
|
||||
#ifdef ESP8266
|
||||
#include <ESP8266WiFi.h>
|
||||
#else
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
namespace WiFiNetwork {
|
||||
bool isConnected();
|
||||
void setUp();
|
||||
void upkeep();
|
||||
void setWiFiCredentials(const char* SSID, const char* pass);
|
||||
IPAddress getAddress();
|
||||
uint8_t getWiFiState();
|
||||
} // namespace WiFiNetwork
|
||||
namespace SlimeVR {
|
||||
|
||||
class WiFiNetwork {
|
||||
public:
|
||||
enum class WiFiReconnectionStatus {
|
||||
NotSetup = 0,
|
||||
SavedAttempt,
|
||||
HardcodeAttempt,
|
||||
ServerCredAttempt,
|
||||
Failed,
|
||||
Success
|
||||
};
|
||||
|
||||
enum class WiFiFailureReason {
|
||||
Timeout = 0,
|
||||
SSIDNotFound = 1,
|
||||
WrongPassword = 2,
|
||||
Unknown = 3,
|
||||
};
|
||||
|
||||
[[nodiscard]] bool isConnected() const;
|
||||
void setUp();
|
||||
void upkeep();
|
||||
void setWiFiCredentials(const char* SSID, const char* pass);
|
||||
static IPAddress getAddress();
|
||||
WiFiReconnectionStatus getWiFiState();
|
||||
|
||||
private:
|
||||
static constexpr float WiFiTimeoutSeconds = 11;
|
||||
|
||||
void reportWifiProgress();
|
||||
void setStaticIPIfDefined();
|
||||
void onConnected();
|
||||
|
||||
static String getSSID();
|
||||
static String getPassword();
|
||||
|
||||
bool trySavedCredentials();
|
||||
bool tryHardcodedCredentials();
|
||||
bool tryServerCredentials();
|
||||
bool tryConnecting(
|
||||
bool phyModeG = false,
|
||||
const char* SSID = nullptr,
|
||||
const char* pass = nullptr
|
||||
);
|
||||
|
||||
void showConnectionAttemptFailed(const char* type) const;
|
||||
|
||||
static const char* statusToReasonString(wl_status_t status);
|
||||
static WiFiFailureReason statusToFailure(wl_status_t status);
|
||||
|
||||
unsigned long lastWifiReportTime = 0;
|
||||
unsigned long wifiConnectionTimeout = millis();
|
||||
bool isWifiConnected = false;
|
||||
WiFiReconnectionStatus wifiState = WiFiReconnectionStatus::NotSetup;
|
||||
bool retriedOnG = false;
|
||||
bool hadWifi = false;
|
||||
unsigned long lastRssiSample = 0;
|
||||
|
||||
uint8_t lastFailStatus = 0;
|
||||
|
||||
SlimeVR::Logging::Logger wifiHandlerLogger{"WiFiHandler"};
|
||||
};
|
||||
|
||||
/** Wifi Reconnection Statuses **/
|
||||
typedef enum {
|
||||
SLIME_WIFI_NOT_SETUP = 0,
|
||||
SLIME_WIFI_SAVED_ATTEMPT,
|
||||
SLIME_WIFI_SAVED_G_ATTEMPT,
|
||||
SLIME_WIFI_HARDCODE_ATTEMPT,
|
||||
SLIME_WIFI_HARDCODE_G_ATTEMPT,
|
||||
SLIME_WIFI_SERVER_CRED_ATTEMPT,
|
||||
SLIME_WIFI_SERVER_CRED_G_ATTEMPT
|
||||
} wifi_reconnection_statuses;
|
||||
|
||||
#endif // SLIMEVR_WIFI_H_
|
||||
} // namespace SlimeVR
|
||||
|
||||
@@ -29,29 +29,31 @@
|
||||
// it sucks.
|
||||
// TODO: New implementation: https://github.com/SlimeVR/SlimeVR-Tracker-ESP/issues/71
|
||||
|
||||
// TODO: Cleanup with proper classes
|
||||
SlimeVR::Logging::Logger wifiProvisioningLogger("WiFiProvisioning");
|
||||
bool provisioning = false;
|
||||
namespace SlimeVR {
|
||||
|
||||
void WiFiNetwork::upkeepProvisioning() {
|
||||
void WifiProvisioning::upkeepProvisioning() {
|
||||
// Called even when not provisioning to do things like provide neighbours or other
|
||||
// upkeep
|
||||
}
|
||||
|
||||
void WiFiNetwork::startProvisioning() {
|
||||
void WifiProvisioning::startProvisioning() {
|
||||
if (WiFi.beginSmartConfig()) {
|
||||
provisioning = true;
|
||||
wifiProvisioningLogger.info("SmartConfig started");
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiNetwork::stopProvisioning() {
|
||||
void WifiProvisioning::stopProvisioning() {
|
||||
WiFi.stopSmartConfig();
|
||||
provisioning = false;
|
||||
}
|
||||
|
||||
void WiFiNetwork::provideNeighbours() {
|
||||
void WifiProvisioning::provideNeighbours() {
|
||||
// TODO: SmartConfig can't do this, created for future
|
||||
}
|
||||
|
||||
bool WiFiNetwork::isProvisioning() { return provisioning && !WiFi.smartConfigDone(); }
|
||||
bool WifiProvisioning::isProvisioning() const {
|
||||
return provisioning && !WiFi.smartConfigDone();
|
||||
}
|
||||
|
||||
} // namespace SlimeVR
|
||||
|
||||
@@ -23,12 +23,23 @@
|
||||
#ifndef SLIMEVR_WIFIPROVISIONING_H_
|
||||
#define SLIMEVR_WIFIPROVISIONING_H_
|
||||
|
||||
namespace WiFiNetwork {
|
||||
void upkeepProvisioning();
|
||||
void startProvisioning();
|
||||
void stopProvisioning();
|
||||
bool isProvisioning();
|
||||
void provideNeighbours();
|
||||
} // namespace WiFiNetwork
|
||||
#include "logging/Logger.h"
|
||||
|
||||
namespace SlimeVR {
|
||||
|
||||
class WifiProvisioning {
|
||||
public:
|
||||
void upkeepProvisioning();
|
||||
void startProvisioning();
|
||||
void stopProvisioning();
|
||||
bool isProvisioning() const;
|
||||
void provideNeighbours();
|
||||
|
||||
private:
|
||||
SlimeVR::Logging::Logger wifiProvisioningLogger{"WiFiProvisioning"};
|
||||
bool provisioning = false;
|
||||
};
|
||||
|
||||
} // namespace SlimeVR
|
||||
|
||||
#endif // SLIMEVR_WIFIPROVISIONING_H_
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
#include "SensorToggles.h"
|
||||
|
||||
SensorToggleState::SensorToggleState(SensorToggleValues values)
|
||||
: values{values} {}
|
||||
|
||||
void SensorToggleState::setToggle(SensorToggles toggle, bool state) {
|
||||
switch (toggle) {
|
||||
case SensorToggles::MagEnabled:
|
||||
magEnabled = state;
|
||||
values.magEnabled = state;
|
||||
break;
|
||||
case SensorToggles::CalibrationEnabled:
|
||||
calibrationEnabled = state;
|
||||
values.calibrationEnabled = state;
|
||||
break;
|
||||
case SensorToggles::TempGradientCalibrationEnabled:
|
||||
tempGradientCalibrationEnabled = state;
|
||||
values.tempGradientCalibrationEnabled = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -17,11 +20,11 @@ void SensorToggleState::setToggle(SensorToggles toggle, bool state) {
|
||||
bool SensorToggleState::getToggle(SensorToggles toggle) const {
|
||||
switch (toggle) {
|
||||
case SensorToggles::MagEnabled:
|
||||
return magEnabled;
|
||||
return values.magEnabled;
|
||||
case SensorToggles::CalibrationEnabled:
|
||||
return calibrationEnabled;
|
||||
return values.calibrationEnabled;
|
||||
case SensorToggles::TempGradientCalibrationEnabled:
|
||||
return tempGradientCalibrationEnabled;
|
||||
return values.tempGradientCalibrationEnabled;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -32,6 +35,8 @@ void SensorToggleState::onToggleChange(
|
||||
this->callback = callback;
|
||||
}
|
||||
|
||||
SensorToggleValues SensorToggleState::getValues() const { return values; }
|
||||
|
||||
void SensorToggleState::emitToggleChange(SensorToggles toggle, bool state) const {
|
||||
if (callback) {
|
||||
(*callback)(toggle, state);
|
||||
|
||||
@@ -35,8 +35,17 @@ enum class SensorToggles : uint16_t {
|
||||
TempGradientCalibrationEnabled = 3,
|
||||
};
|
||||
|
||||
struct SensorToggleValues {
|
||||
bool magEnabled = !USE_6_AXIS;
|
||||
bool calibrationEnabled = true;
|
||||
bool tempGradientCalibrationEnabled
|
||||
= false; // disable by default, it is not clear that it really helps
|
||||
};
|
||||
|
||||
class SensorToggleState {
|
||||
public:
|
||||
SensorToggleState() = default;
|
||||
explicit SensorToggleState(SensorToggleValues values);
|
||||
void setToggle(SensorToggles toggle, bool state);
|
||||
[[nodiscard]] bool getToggle(SensorToggles toggle) const;
|
||||
|
||||
@@ -44,12 +53,12 @@ public:
|
||||
|
||||
static const char* toggleToString(SensorToggles toggle);
|
||||
|
||||
[[nodiscard]] SensorToggleValues getValues() const;
|
||||
|
||||
private:
|
||||
std::optional<std::function<void(SensorToggles, bool)>> callback;
|
||||
|
||||
void emitToggleChange(SensorToggles toggle, bool state) const;
|
||||
|
||||
bool magEnabled = !USE_6_AXIS;
|
||||
bool calibrationEnabled = true;
|
||||
bool tempGradientCalibrationEnabled
|
||||
= false; // disable by default, it is not clear that it really helps
|
||||
SensorToggleValues values;
|
||||
};
|
||||
|
||||
@@ -33,6 +33,7 @@ SensorStatus Sensor::getSensorState() {
|
||||
|
||||
void Sensor::setAcceleration(Vector3 a) {
|
||||
acceleration = a;
|
||||
sensorOffset.sandwich(acceleration);
|
||||
newAcceleration = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
|
||||
virtual const uint8_t* getMotionlessCalibrationData() = 0;
|
||||
|
||||
virtual void signalOverwhelmed() {}
|
||||
virtual void provideAccelSample(const RawSensorT accelSample[3]) {}
|
||||
virtual void provideGyroSample(const RawSensorT gyroSample[3]) {}
|
||||
virtual void provideTempSample(float tempSample) {}
|
||||
|
||||
@@ -25,18 +25,20 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
#include "../../../sensorinterface/RegisterInterface.h"
|
||||
#include "callbacks.h"
|
||||
#include "vqf.h"
|
||||
|
||||
namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
|
||||
// Driver uses acceleration range at 4G
|
||||
// and gyroscope range at 1000DPS
|
||||
// Gyroscope ODR = 400Hz, accel ODR = 100Hz
|
||||
// Gyroscope ODR = 200Hz, accel ODR = 100Hz
|
||||
// Timestamps reading are not used
|
||||
|
||||
// Sensorhub to be implemented
|
||||
@@ -46,7 +48,7 @@ struct BMI160 {
|
||||
static constexpr auto Name = "BMI160";
|
||||
static constexpr auto Type = SensorTypeID::BMI160;
|
||||
|
||||
static constexpr float GyrTs = 1.0 / 400.0;
|
||||
static constexpr float GyrTs = 1.0 / 200.0;
|
||||
static constexpr float AccTs = 1.0 / 100.0;
|
||||
|
||||
static constexpr float MagTs = 1.0 / 100;
|
||||
@@ -57,14 +59,7 @@ struct BMI160 {
|
||||
static constexpr float TemperatureZROChange
|
||||
= 2.0f; // wow maybe BMI270 isn't that bad actually
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
// need to be refined, this IMU sucks
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 0.5f,
|
||||
.biasClip = 2.0f,
|
||||
.restThGyr = 0.5f,
|
||||
.restThAcc = 0.196f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
RegisterInterface& m_RegisterInterface;
|
||||
SlimeVR::Logging::Logger& m_Logger;
|
||||
@@ -101,7 +96,7 @@ struct BMI160 {
|
||||
|
||||
struct GyrConf {
|
||||
static constexpr uint8_t reg = 0x42;
|
||||
static constexpr uint8_t value = 0b0101010; // 400Hz, filter mode normal
|
||||
static constexpr uint8_t value = 0b0101001; // 200Hz, filter mode normal
|
||||
};
|
||||
|
||||
struct GyrRange {
|
||||
@@ -182,12 +177,7 @@ struct BMI160 {
|
||||
return to_ret;
|
||||
}
|
||||
|
||||
template <typename AccelCall, typename GyroCall, typename TempCall>
|
||||
void bulkRead(
|
||||
AccelCall&& processAccelSample,
|
||||
GyroCall&& processGyroSample,
|
||||
TempCall&& processTempSample
|
||||
) {
|
||||
bool bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
const auto fifo_bytes = m_RegisterInterface.readReg16(Regs::FifoLength) & 0x7FF;
|
||||
|
||||
const auto bytes_to_read = std::min(
|
||||
@@ -218,7 +208,7 @@ struct BMI160 {
|
||||
gyro[0] = getFromFifo<uint16_t>(i, read_buffer);
|
||||
gyro[1] = getFromFifo<uint16_t>(i, read_buffer);
|
||||
gyro[2] = getFromFifo<uint16_t>(i, read_buffer);
|
||||
processGyroSample(gyro, GyrTs);
|
||||
callbacks.processGyroSample(gyro, GyrTs);
|
||||
}
|
||||
|
||||
if (header & Fifo::AccelDataBit) {
|
||||
@@ -226,10 +216,11 @@ struct BMI160 {
|
||||
accel[0] = getFromFifo<uint16_t>(i, read_buffer);
|
||||
accel[1] = getFromFifo<uint16_t>(i, read_buffer);
|
||||
accel[2] = getFromFifo<uint16_t>(i, read_buffer);
|
||||
processAccelSample(accel, AccTs);
|
||||
callbacks.processAccelSample(accel, AccTs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return static_cast<size_t>(fifo_bytes) > static_cast<size_t>(bytes_to_read);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
|
||||
// Driver uses acceleration range at 16g
|
||||
// and gyroscope range at 1000dps
|
||||
// Gyroscope ODR = 400Hz, accel ODR = 100Hz
|
||||
// Gyroscope ODR = 200Hz, accel ODR = 100Hz
|
||||
// Timestamps reading are not used
|
||||
|
||||
struct BMI270 {
|
||||
@@ -46,7 +46,7 @@ struct BMI270 {
|
||||
static constexpr auto Name = "BMI270";
|
||||
static constexpr auto Type = SensorTypeID::BMI270;
|
||||
|
||||
static constexpr float GyrTs = 1.0 / 400.0;
|
||||
static constexpr float GyrTs = 1.0 / 200.0;
|
||||
static constexpr float AccTs = 1.0 / 100.0;
|
||||
|
||||
static constexpr float MagTs = 1.0 / 100;
|
||||
@@ -56,13 +56,7 @@ struct BMI270 {
|
||||
|
||||
static constexpr float TemperatureZROChange = 6.667f;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 0.5f,
|
||||
.biasClip = 1.0f,
|
||||
.restThGyr = 0.5f,
|
||||
.restThAcc = 0.196f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
struct MotionlessCalibrationData {
|
||||
bool valid;
|
||||
@@ -138,7 +132,7 @@ struct BMI270 {
|
||||
static constexpr uint8_t filterHighPerfMode = 1 << 7;
|
||||
|
||||
static constexpr uint8_t value
|
||||
= rate400Hz | DLPFModeNorm | noisePerfMode | filterHighPerfMode;
|
||||
= rate200Hz | DLPFModeNorm | noisePerfMode | filterHighPerfMode;
|
||||
};
|
||||
|
||||
struct GyrRange {
|
||||
@@ -434,7 +428,7 @@ struct BMI270 {
|
||||
return to_ret;
|
||||
}
|
||||
|
||||
void bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
bool bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
const auto fifo_bytes = m_RegisterInterface.readReg16(Regs::FifoCount);
|
||||
|
||||
const auto bytes_to_read = std::min(
|
||||
@@ -488,6 +482,8 @@ struct BMI270 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fifo_bytes > bytes_to_read;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -30,11 +30,13 @@
|
||||
#include "callbacks.h"
|
||||
#include "vqf.h"
|
||||
|
||||
constexpr static bool DEBUG_ICM42688_HIRES = false;
|
||||
|
||||
namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
|
||||
// Driver uses acceleration range at 8g
|
||||
// and gyroscope range at 1000dps
|
||||
// Gyroscope ODR = 500Hz, accel ODR = 100Hz
|
||||
// Gyroscope ODR = 200Hz, accel ODR = 100Hz
|
||||
// Timestamps reading not used, as they're useless (constant predefined increment)
|
||||
|
||||
struct ICM42688 {
|
||||
@@ -42,27 +44,27 @@ struct ICM42688 {
|
||||
static constexpr auto Name = "ICM-42688";
|
||||
static constexpr auto Type = SensorTypeID::ICM42688;
|
||||
|
||||
static constexpr float GyrTs = 1.0 / 500.0;
|
||||
static constexpr float GyrTs = 1.0 / 200.0;
|
||||
static constexpr float AccTs = 1.0 / 100.0;
|
||||
static constexpr float TempTs = 1.0 / 500.0;
|
||||
static constexpr float TempTs = 1.0 / 200.0;
|
||||
|
||||
static constexpr float MagTs = 1.0 / 100;
|
||||
|
||||
static constexpr float GyroSensitivity = 32.8f;
|
||||
static constexpr float AccelSensitivity = 4096.0f;
|
||||
// When 20-bits data format is used, the only FSR settings that are
|
||||
// operational are ±2000dps for gyroscope and ±16g for accelerometer, even if the
|
||||
// FSR selection register settings are configured for other FSR values. The
|
||||
// corresponding sensitivity scale factor values are 131 LSB/dps for gyroscope and
|
||||
// 8192 LSB/g for accelerometer.
|
||||
static constexpr float GyroSensitivity = (DEBUG_ICM42688_HIRES ? 131.0f : 32.8f);
|
||||
static constexpr float AccelSensitivity
|
||||
= (DEBUG_ICM42688_HIRES ? 8192.0f : 4096.0f);
|
||||
|
||||
static constexpr float TemperatureBias = 25.0f;
|
||||
static constexpr float TemperatureSensitivity = 2.07f;
|
||||
|
||||
static constexpr float TemperatureSensitivity
|
||||
= (DEBUG_ICM42688_HIRES ? 132.48f : 2.07f);
|
||||
static constexpr float TemperatureZROChange = 20.0f;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 0.5f,
|
||||
.biasClip = 1.0f,
|
||||
.restThGyr = 0.5f,
|
||||
.restThAcc = 0.196f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
RegisterInterface& m_RegisterInterface;
|
||||
SlimeVR::Logging::Logger& m_Logger;
|
||||
@@ -94,12 +96,14 @@ struct ICM42688 {
|
||||
static constexpr uint8_t reg = 0x5f;
|
||||
static constexpr uint8_t value
|
||||
= 0b1 | (0b1 << 1) | (0b1 << 2)
|
||||
| (0b0 << 4); // fifo accel en=1, gyro=1, temp=1, hires=1
|
||||
| (DEBUG_ICM42688_HIRES ? (0b1 << 4) : (0b0 << 4));
|
||||
// fifo accel en=1, gyro=1, temp=1,
|
||||
// hires=DEBUG_ICM42688_HIRES
|
||||
};
|
||||
struct GyroConfig {
|
||||
static constexpr uint8_t reg = 0x4f;
|
||||
static constexpr uint8_t value
|
||||
= (0b001 << 5) | 0b1111; // 1000dps, odr=500Hz
|
||||
= (0b001 << 5) | 0b0111; // 1000dps, odr=200Hz
|
||||
};
|
||||
struct AccelConfig {
|
||||
static constexpr uint8_t reg = 0x50;
|
||||
@@ -121,7 +125,7 @@ struct ICM42688 {
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct FifoEntryAligned {
|
||||
struct FifoEntryAlignedHires {
|
||||
union {
|
||||
struct {
|
||||
int16_t accel[3];
|
||||
@@ -134,10 +138,65 @@ struct ICM42688 {
|
||||
} part;
|
||||
uint8_t raw[19];
|
||||
};
|
||||
|
||||
void getGyro(int32_t out[3]) {
|
||||
// 6.1 Packet Structure for high resolution mode
|
||||
// https://invensense.tdk.com/wp-content/uploads/2020/04/ds-000347_icm-42688-p-datasheet.pdf
|
||||
// When 20-bits data format is used, gyroscope data consists of 19-bits
|
||||
// of actual data and the LSB is always set to 0
|
||||
out[0] = static_cast<int32_t>(part.gyro[0]) << 3 | ((part.xlsb & 0xe) >> 1);
|
||||
out[1] = static_cast<int32_t>(part.gyro[1]) << 3 | ((part.ylsb & 0xe) >> 1);
|
||||
out[2] = static_cast<int32_t>(part.gyro[2]) << 3 | ((part.zlsb & 0xe) >> 1);
|
||||
}
|
||||
void getAccel(int32_t out[3]) {
|
||||
// accelerometer data consists of 18-bits of actual data and the two
|
||||
// lowest order bits are always set to 0
|
||||
out[0] = static_cast<int32_t>(part.accel[0]) << 2
|
||||
| (static_cast<int32_t>((part.xlsb) & 0xf0) >> 6);
|
||||
out[1] = static_cast<int32_t>(part.accel[1]) << 2
|
||||
| (static_cast<int32_t>((part.ylsb) & 0xf0) >> 6);
|
||||
out[2] = static_cast<int32_t>(part.accel[2]) << 2
|
||||
| (static_cast<int32_t>((part.zlsb) & 0xf0) >> 6);
|
||||
}
|
||||
};
|
||||
|
||||
struct FifoEntryAlignedDefault {
|
||||
union {
|
||||
struct {
|
||||
int16_t accel[3];
|
||||
int16_t gyro[3];
|
||||
int8_t temp;
|
||||
uint16_t timestamp;
|
||||
} part;
|
||||
uint8_t raw[15];
|
||||
};
|
||||
|
||||
void getGyro(int32_t out[3]) {
|
||||
out[0] = static_cast<int32_t>(part.gyro[0]);
|
||||
out[1] = static_cast<int32_t>(part.gyro[1]);
|
||||
out[2] = static_cast<int32_t>(part.gyro[2]);
|
||||
}
|
||||
|
||||
void getAccel(int32_t out[3]) {
|
||||
out[0] = static_cast<int32_t>(part.accel[0]);
|
||||
out[1] = static_cast<int32_t>(part.accel[1]);
|
||||
out[2] = static_cast<int32_t>(part.accel[2]);
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(sizeof(FifoEntryAlignedHires) == 19);
|
||||
static_assert(sizeof(FifoEntryAlignedDefault) == 15);
|
||||
|
||||
using FifoEntryAligned = std::conditional<
|
||||
DEBUG_ICM42688_HIRES,
|
||||
FifoEntryAlignedHires,
|
||||
FifoEntryAlignedDefault>::type;
|
||||
|
||||
static constexpr size_t FullFifoEntrySize = sizeof(FifoEntryAligned) + 1;
|
||||
// max 4 readings in highres mode 8 readings delay too high 6 seems to be the
|
||||
// edge to work reliably. Tested on ESP8266 with 2 IMU
|
||||
static constexpr size_t MaxReadings = DEBUG_ICM42688_HIRES ? 4 : 8;
|
||||
|
||||
bool initialize() {
|
||||
// perform initialization step
|
||||
@@ -158,10 +217,11 @@ struct ICM42688 {
|
||||
return true;
|
||||
}
|
||||
|
||||
void bulkRead(DriverCallbacks<int32_t>&& callbacks) {
|
||||
bool bulkRead(DriverCallbacks<int32_t>&& callbacks) {
|
||||
const auto fifo_bytes = m_RegisterInterface.readReg16(Regs::FifoCount);
|
||||
|
||||
std::array<uint8_t, FullFifoEntrySize * 8> read_buffer; // max 8 readings
|
||||
std::array<uint8_t, FullFifoEntrySize * MaxReadings> read_buffer;
|
||||
|
||||
const auto bytes_to_read = std::min(
|
||||
static_cast<size_t>(read_buffer.size()),
|
||||
static_cast<size_t>(fifo_bytes)
|
||||
@@ -177,22 +237,13 @@ struct ICM42688 {
|
||||
sizeof(FifoEntryAligned)
|
||||
); // skip fifo header
|
||||
|
||||
const int32_t gyroData[3]{
|
||||
static_cast<int32_t>(entry.part.gyro[0]) << 4 | (entry.part.xlsb & 0xf),
|
||||
static_cast<int32_t>(entry.part.gyro[1]) << 4 | (entry.part.ylsb & 0xf),
|
||||
static_cast<int32_t>(entry.part.gyro[2]) << 4 | (entry.part.zlsb & 0xf),
|
||||
};
|
||||
int32_t gyroData[3];
|
||||
entry.getGyro(gyroData);
|
||||
callbacks.processGyroSample(gyroData, GyrTs);
|
||||
|
||||
if (entry.part.accel[0] != -32768) {
|
||||
const int32_t accelData[3]{
|
||||
static_cast<int32_t>(entry.part.accel[0]) << 4
|
||||
| (static_cast<int32_t>(entry.part.xlsb) & 0xf0 >> 4),
|
||||
static_cast<int32_t>(entry.part.accel[1]) << 4
|
||||
| (static_cast<int32_t>(entry.part.ylsb) & 0xf0 >> 4),
|
||||
static_cast<int32_t>(entry.part.accel[2]) << 4
|
||||
| (static_cast<int32_t>(entry.part.zlsb) & 0xf0 >> 4),
|
||||
};
|
||||
int32_t accelData[3];
|
||||
entry.getAccel(accelData);
|
||||
callbacks.processAccelSample(accelData, AccTs);
|
||||
}
|
||||
|
||||
@@ -203,6 +254,7 @@ struct ICM42688 {
|
||||
);
|
||||
}
|
||||
}
|
||||
return fifo_bytes > bytes_to_read;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,20 +32,14 @@ namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
// and gyroscope range at 4000dps
|
||||
// using high resolution mode
|
||||
// Uses 32.768kHz clock
|
||||
// Gyroscope ODR = 409.6Hz, accel ODR = 204.8Hz
|
||||
// Gyroscope ODR = 204.8Hz, accel ODR = 102.4Hz
|
||||
// Timestamps reading not used, as they're useless (constant predefined increment)
|
||||
|
||||
struct ICM45605 : public ICM45Base {
|
||||
static constexpr auto Name = "ICM-45605";
|
||||
static constexpr auto Type = SensorTypeID::ICM45605;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 0.3f,
|
||||
.biasClip = 0.6f,
|
||||
.restThGyr = 0.3f,
|
||||
.restThAcc = 0.0098f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
ICM45605(RegisterInterface& registerInterface, SlimeVR::Logging::Logger& logger)
|
||||
: ICM45Base{registerInterface, logger} {}
|
||||
|
||||
@@ -32,26 +32,14 @@ namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
// and gyroscope range at 4000dps
|
||||
// using high resolution mode
|
||||
// Uses 32.768kHz clock
|
||||
// Gyroscope ODR = 409.6Hz, accel ODR = 102.4Hz
|
||||
// Gyroscope ODR = 204.8Hz, accel ODR = 102.4Hz
|
||||
// Timestamps reading not used, as they're useless (constant predefined increment)
|
||||
|
||||
struct ICM45686 : public ICM45Base {
|
||||
static constexpr auto Name = "ICM-45686";
|
||||
static constexpr auto Type = SensorTypeID::ICM45686;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.tauAcc = 7.171490,
|
||||
.biasSigmaInit = 0.337976,
|
||||
.biasForgettingTime = 352.235500,
|
||||
.biasClip = 5.0,
|
||||
.biasSigmaMotion = 0.985346,
|
||||
.biasVerticalForgettingFactor = 0.007959,
|
||||
.biasSigmaRest = 0.028897,
|
||||
.restMinT = 4.648680,
|
||||
.restFilterTau = 1.900166,
|
||||
.restThGyr = 2.620598,
|
||||
.restThAcc = 2.142593,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
ICM45686(RegisterInterface& registerInterface, SlimeVR::Logging::Logger& logger)
|
||||
: ICM45Base{registerInterface, logger} {}
|
||||
@@ -75,8 +63,10 @@ struct ICM45686 : public ICM45Base {
|
||||
|
||||
bool initialize() {
|
||||
ICM45Base::softResetIMU();
|
||||
#if IMU_USE_EXTERNAL_CLOCK
|
||||
m_RegisterInterface.writeReg(Regs::Pin9Config::reg, Regs::Pin9Config::value);
|
||||
m_RegisterInterface.writeReg(Regs::RtcConfig::reg, Regs::RtcConfig::value);
|
||||
#endif
|
||||
return ICM45Base::initializeBase();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,13 +34,13 @@ namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
// and gyroscope range at 4000dps
|
||||
// using high resolution mode
|
||||
// Uses 32.768kHz clock
|
||||
// Gyroscope ODR = 409.6Hz, accel ODR = 102.4Hz
|
||||
// Gyroscope ODR = 204.8Hz, accel ODR = 102.4Hz
|
||||
// Timestamps reading not used, as they're useless (constant predefined increment)
|
||||
|
||||
struct ICM45Base {
|
||||
static constexpr uint8_t Address = 0x68;
|
||||
|
||||
static constexpr float GyrTs = 1.0 / 409.6;
|
||||
static constexpr float GyrTs = 1.0 / 204.8;
|
||||
static constexpr float AccTs = 1.0 / 102.4;
|
||||
static constexpr float TempTs = 1.0 / 409.6;
|
||||
|
||||
@@ -71,7 +71,7 @@ struct ICM45Base {
|
||||
struct GyroConfig {
|
||||
static constexpr uint8_t reg = 0x1c;
|
||||
static constexpr uint8_t value
|
||||
= (0b0000 << 4) | 0b0111; // 4000dps, odr=409.6Hz
|
||||
= (0b0000 << 4) | 0b1000; // 4000dps, odr=204.8Hz
|
||||
};
|
||||
|
||||
struct AccelConfig {
|
||||
@@ -238,13 +238,13 @@ struct ICM45Base {
|
||||
// stack overflow and panic
|
||||
std::vector<uint8_t> read_buffer;
|
||||
|
||||
void bulkRead(DriverCallbacks<int32_t>&& callbacks) {
|
||||
bool bulkRead(DriverCallbacks<int32_t>&& callbacks) {
|
||||
constexpr int16_t InvalidReading = -32768;
|
||||
|
||||
size_t fifo_packets = m_RegisterInterface.readReg16(BaseRegs::FifoCount);
|
||||
|
||||
if (fifo_packets <= 1) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// AN-000364
|
||||
@@ -264,9 +264,9 @@ struct ICM45Base {
|
||||
// can cause FIFO data corruption, from happening.
|
||||
--fifo_packets;
|
||||
|
||||
fifo_packets = std::min(fifo_packets, MaxReadings);
|
||||
auto packets_to_read = std::min(fifo_packets, MaxReadings);
|
||||
|
||||
size_t bytes_to_read = fifo_packets * FullFifoEntrySize;
|
||||
size_t bytes_to_read = packets_to_read * FullFifoEntrySize;
|
||||
m_RegisterInterface
|
||||
.readBytes(BaseRegs::FifoData, bytes_to_read, read_buffer.data());
|
||||
|
||||
@@ -307,6 +307,8 @@ struct ICM45Base {
|
||||
callbacks.processTempSample(static_cast<int16_t>(entry.temp), TempTs);
|
||||
}
|
||||
}
|
||||
|
||||
return fifo_packets > MaxReadings;
|
||||
}
|
||||
|
||||
template <typename Reg>
|
||||
|
||||
@@ -55,7 +55,7 @@ struct LSM6DSOutputHandler {
|
||||
static constexpr size_t FullFifoEntrySize = sizeof(FifoEntryAligned) + 1;
|
||||
|
||||
template <typename Regs>
|
||||
void bulkRead(
|
||||
bool bulkRead(
|
||||
DriverCallbacks<int16_t>&& callbacks,
|
||||
float GyrTs,
|
||||
float AccTs,
|
||||
@@ -103,6 +103,7 @@ struct LSM6DSOutputHandler {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fifo_bytes > bytes_to_read;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -33,37 +33,35 @@
|
||||
|
||||
namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
|
||||
// Driver uses acceleration range at 8g
|
||||
// Driver uses acceleration range at 4g
|
||||
// and gyroscope range at 1000dps
|
||||
// Gyroscope ODR = 416Hz, accel ODR = 416Hz
|
||||
// Gyroscope ODR = 208Hz, accel ODR = 104Hz
|
||||
|
||||
struct LSM6DS3TRC {
|
||||
static constexpr uint8_t Address = 0x6a;
|
||||
static constexpr auto Name = "LSM6DS3TR-C";
|
||||
static constexpr auto Type = SensorTypeID::LSM6DS3TRC;
|
||||
|
||||
static constexpr float Freq = 416;
|
||||
static constexpr float GyrFreq = 208.0f;
|
||||
static constexpr float AccFreq = 104.0f;
|
||||
static constexpr float MagFreq = 100.0f;
|
||||
static constexpr float TempFreq
|
||||
= 416.0f; // I guess it's just output at the FIFO ODR?
|
||||
|
||||
static constexpr float GyrTs = 1.0 / Freq;
|
||||
static constexpr float AccTs = 1.0 / Freq;
|
||||
static constexpr float MagTs = 1.0 / Freq;
|
||||
static constexpr float TempTs = 1.0 / Freq;
|
||||
static constexpr float GyrTs = 1.0 / GyrFreq;
|
||||
static constexpr float AccTs = 1.0 / AccFreq;
|
||||
static constexpr float MagTs = 1.0 / MagFreq;
|
||||
static constexpr float TempTs = 1.0 / TempFreq;
|
||||
|
||||
static constexpr float GyroSensitivity = 28.571428571f;
|
||||
static constexpr float AccelSensitivity = 4098.360655738f;
|
||||
static constexpr float AccelSensitivity = 1000 / 0.122f;
|
||||
|
||||
static constexpr float TemperatureBias = 25.0f;
|
||||
static constexpr float TemperatureSensitivity = 256.0f;
|
||||
|
||||
static constexpr float TemperatureZROChange = 2.0f;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 3.0f,
|
||||
.biasClip = 6.0f,
|
||||
.restThGyr = 3.0f,
|
||||
.restThAcc = 0.392f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
RegisterInterface& m_RegisterInterface;
|
||||
SlimeVR::Logging::Logger m_Logger;
|
||||
@@ -79,12 +77,12 @@ struct LSM6DS3TRC {
|
||||
};
|
||||
struct Ctrl1XL {
|
||||
static constexpr uint8_t reg = 0x10;
|
||||
static constexpr uint8_t value = (0b11 << 2) | (0b0110 << 4); // 8g, 416Hz
|
||||
static constexpr uint8_t value = (0b10 << 2) | (0b0100 << 4); // 4g, 104Hz
|
||||
};
|
||||
struct Ctrl2G {
|
||||
static constexpr uint8_t reg = 0x11;
|
||||
static constexpr uint8_t value
|
||||
= (0b10 << 2) | (0b0110 << 4); // 1000dps, 416Hz
|
||||
= (0b10 << 2) | (0b0101 << 4); // 1000dps, 208Hz
|
||||
};
|
||||
struct Ctrl3C {
|
||||
static constexpr uint8_t reg = 0x12;
|
||||
@@ -104,7 +102,7 @@ struct LSM6DS3TRC {
|
||||
struct FifoCtrl5 {
|
||||
static constexpr uint8_t reg = 0x0a;
|
||||
static constexpr uint8_t value
|
||||
= 0b110 | (0b0111 << 3); // continuous mode, odr = 833Hz
|
||||
= 0b110 | (0b0110 << 3); // continuous mode, odr = 416Hz
|
||||
};
|
||||
|
||||
static constexpr uint8_t FifoStatus = 0x3a;
|
||||
@@ -124,14 +122,14 @@ struct LSM6DS3TRC {
|
||||
return true;
|
||||
}
|
||||
|
||||
void bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
bool bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
const auto read_result = m_RegisterInterface.readReg16(Regs::FifoStatus);
|
||||
if (read_result & 0x4000) { // overrun!
|
||||
// disable and re-enable fifo to clear it
|
||||
m_Logger.debug("Fifo overrun, resetting...");
|
||||
m_RegisterInterface.writeReg(Regs::FifoCtrl5::reg, 0);
|
||||
m_RegisterInterface.writeReg(Regs::FifoCtrl5::reg, Regs::FifoCtrl5::value);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
const auto unread_entries = read_result & 0x7ff;
|
||||
constexpr auto single_measurement_words = 6;
|
||||
@@ -158,6 +156,8 @@ struct LSM6DS3TRC {
|
||||
callbacks.processAccelSample(&read_buffer[i + 3], AccTs);
|
||||
callbacks.processTempSample(read_buffer[i + 9], TempTs);
|
||||
}
|
||||
|
||||
return static_cast<size_t>(unread_entries) > read_buffer.size();
|
||||
}
|
||||
}; // namespace SlimeVR::Sensors::SoftFusion::Drivers
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
|
||||
// Driver uses acceleration range at 8g
|
||||
// Driver uses acceleration range at 4g
|
||||
// and gyroscope range at 1000dps
|
||||
// Gyroscope ODR = 416Hz, accel ODR = 104Hz
|
||||
|
||||
@@ -42,7 +42,7 @@ struct LSM6DSO : LSM6DSOutputHandler {
|
||||
static constexpr auto Name = "LSM6DSO";
|
||||
static constexpr auto Type = SensorTypeID::LSM6DSO;
|
||||
|
||||
static constexpr float GyrFreq = 416;
|
||||
static constexpr float GyrFreq = 208;
|
||||
static constexpr float AccFreq = 104;
|
||||
static constexpr float MagFreq = 120;
|
||||
static constexpr float TempFreq = 52;
|
||||
@@ -53,20 +53,14 @@ struct LSM6DSO : LSM6DSOutputHandler {
|
||||
static constexpr float TempTs = 1.0 / TempFreq;
|
||||
|
||||
static constexpr float GyroSensitivity = 1000 / 35.0f;
|
||||
static constexpr float AccelSensitivity = 1000 / 0.244f;
|
||||
static constexpr float AccelSensitivity = 1000 / 0.122f;
|
||||
|
||||
static constexpr float TemperatureBias = 25.0f;
|
||||
static constexpr float TemperatureSensitivity = 256.0f;
|
||||
|
||||
static constexpr float TemperatureZROChange = 10.0;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 1.0f,
|
||||
.biasClip = 2.0f,
|
||||
.restThGyr = 1.0f,
|
||||
.restThAcc = 0.192f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
struct Regs {
|
||||
struct WhoAmI {
|
||||
@@ -75,11 +69,11 @@ struct LSM6DSO : LSM6DSOutputHandler {
|
||||
};
|
||||
struct Ctrl1XL {
|
||||
static constexpr uint8_t reg = 0x10;
|
||||
static constexpr uint8_t value = (0b01001100); // XL at 104 Hz, 8g FS
|
||||
static constexpr uint8_t value = (0b01001000); // XL at 104 Hz, 4g FS
|
||||
};
|
||||
struct Ctrl2GY {
|
||||
static constexpr uint8_t reg = 0x11;
|
||||
static constexpr uint8_t value = (0b01101000); // GY at 416 Hz, 1000dps FS
|
||||
static constexpr uint8_t value = (0b01011000); // GY at 208 Hz, 1000dps FS
|
||||
};
|
||||
struct Ctrl3C {
|
||||
static constexpr uint8_t reg = 0x12;
|
||||
@@ -90,7 +84,7 @@ struct LSM6DSO : LSM6DSOutputHandler {
|
||||
struct FifoCtrl3BDR {
|
||||
static constexpr uint8_t reg = 0x09;
|
||||
static constexpr uint8_t value
|
||||
= (0b0110) | (0b0110 << 4); // gyro and accel batched at 417Hz
|
||||
= 0b01010100; // Gyroscope batched into FIFO at 208Hz, Accel at 104Hz
|
||||
};
|
||||
struct FifoCtrl4Mode {
|
||||
static constexpr uint8_t reg = 0x0a;
|
||||
@@ -123,8 +117,8 @@ struct LSM6DSO : LSM6DSOutputHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
void bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
LSM6DSOutputHandler::template bulkRead<Regs>(
|
||||
bool bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
return LSM6DSOutputHandler::template bulkRead<Regs>(
|
||||
std::move(callbacks),
|
||||
GyrTs,
|
||||
AccTs,
|
||||
|
||||
@@ -31,16 +31,16 @@
|
||||
|
||||
namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
|
||||
// Driver uses acceleration range at 8g
|
||||
// Driver uses acceleration range at 4g
|
||||
// and gyroscope range at 1000dps
|
||||
// Gyroscope ODR = 416Hz, accel ODR = 104Hz
|
||||
// Gyroscope ODR = 208Hz, accel ODR = 104Hz
|
||||
|
||||
struct LSM6DSR : LSM6DSOutputHandler {
|
||||
static constexpr uint8_t Address = 0x6a;
|
||||
static constexpr auto Name = "LSM6DSR";
|
||||
static constexpr auto Type = SensorTypeID::LSM6DSR;
|
||||
|
||||
static constexpr float GyrFreq = 416;
|
||||
static constexpr float GyrFreq = 208;
|
||||
static constexpr float AccFreq = 104;
|
||||
static constexpr float MagFreq = 120;
|
||||
static constexpr float TempFreq = 52;
|
||||
@@ -51,20 +51,14 @@ struct LSM6DSR : LSM6DSOutputHandler {
|
||||
static constexpr float TempTs = 1.0 / TempFreq;
|
||||
|
||||
static constexpr float GyroSensitivity = 1000 / 35.0f;
|
||||
static constexpr float AccelSensitivity = 1000 / 0.244f;
|
||||
static constexpr float AccelSensitivity = 1000 / 0.122f;
|
||||
|
||||
static constexpr float TemperatureBias = 25.0f;
|
||||
static constexpr float TemperatureSensitivity = 256.0f;
|
||||
|
||||
static constexpr float TemperatureZROChange = 20.0f;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 1.0f,
|
||||
.biasClip = 2.0f,
|
||||
.restThGyr = 1.0f,
|
||||
.restThAcc = 0.192f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
struct Regs {
|
||||
struct WhoAmI {
|
||||
@@ -73,11 +67,11 @@ struct LSM6DSR : LSM6DSOutputHandler {
|
||||
};
|
||||
struct Ctrl1XL {
|
||||
static constexpr uint8_t reg = 0x10;
|
||||
static constexpr uint8_t value = (0b01001100); // XL at 104 Hz, 8g FS
|
||||
static constexpr uint8_t value = (0b01001000); // XL at 104 Hz, 4g FS
|
||||
};
|
||||
struct Ctrl2GY {
|
||||
static constexpr uint8_t reg = 0x11;
|
||||
static constexpr uint8_t value = (0b01101000); // GY at 416 Hz, 1000dps FS
|
||||
static constexpr uint8_t value = (0b01011000); // GY at 208 Hz, 1000dps FS
|
||||
};
|
||||
struct Ctrl3C {
|
||||
static constexpr uint8_t reg = 0x12;
|
||||
@@ -88,7 +82,7 @@ struct LSM6DSR : LSM6DSOutputHandler {
|
||||
struct FifoCtrl3BDR {
|
||||
static constexpr uint8_t reg = 0x09;
|
||||
static constexpr uint8_t value
|
||||
= (0b0110) | (0b0110 << 4); // gyro and accel batched at 417Hz
|
||||
= 0b01010100; // Gyroscope batched into FIFO at 208Hz, Accel at 104Hz
|
||||
};
|
||||
struct FifoCtrl4Mode {
|
||||
static constexpr uint8_t reg = 0x0a;
|
||||
@@ -121,8 +115,8 @@ struct LSM6DSR : LSM6DSOutputHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
void bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
LSM6DSOutputHandler::template bulkRead<Regs>(
|
||||
bool bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
return LSM6DSOutputHandler::template bulkRead<Regs>(
|
||||
std::move(callbacks),
|
||||
GyrTs,
|
||||
AccTs,
|
||||
|
||||
@@ -32,16 +32,16 @@
|
||||
|
||||
namespace SlimeVR::Sensors::SoftFusion::Drivers {
|
||||
|
||||
// Driver uses acceleration range at 8g
|
||||
// Driver uses acceleration range at 4g
|
||||
// and gyroscope range at 1000dps
|
||||
// Gyroscope ODR = 480Hz, accel ODR = 120Hz
|
||||
// Gyroscope ODR = 240Hz, accel ODR = 120Hz
|
||||
|
||||
struct LSM6DSV : LSM6DSOutputHandler {
|
||||
static constexpr uint8_t Address = 0x6a;
|
||||
static constexpr auto Name = "LSM6DSV";
|
||||
static constexpr auto Type = SensorTypeID::LSM6DSV;
|
||||
|
||||
static constexpr float GyrFreq = 480;
|
||||
static constexpr float GyrFreq = 240;
|
||||
static constexpr float AccFreq = 120;
|
||||
static constexpr float MagFreq = 120;
|
||||
static constexpr float TempFreq = 60;
|
||||
@@ -52,20 +52,14 @@ struct LSM6DSV : LSM6DSOutputHandler {
|
||||
static constexpr float TempTs = 1.0 / TempFreq;
|
||||
|
||||
static constexpr float GyroSensitivity = 1000 / 35.0f;
|
||||
static constexpr float AccelSensitivity = 1000 / 0.244f;
|
||||
static constexpr float AccelSensitivity = 1000 / 0.122f;
|
||||
|
||||
static constexpr float TemperatureBias = 25.0f;
|
||||
static constexpr float TemperatureSensitivity = 256.0f;
|
||||
|
||||
static constexpr float TemperatureZROChange = 16.667f;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 1.0f,
|
||||
.biasClip = 2.0f,
|
||||
.restThGyr = 1.0f,
|
||||
.restThAcc = 0.192f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
struct Regs {
|
||||
struct WhoAmI {
|
||||
@@ -82,7 +76,7 @@ struct LSM6DSV : LSM6DSOutputHandler {
|
||||
};
|
||||
struct Ctrl2GODR {
|
||||
static constexpr uint8_t reg = 0x11;
|
||||
static constexpr uint8_t value = (0b0011000); // 480Hz, HAODR
|
||||
static constexpr uint8_t value = (0b0010111); // 240Hz, HAODR
|
||||
};
|
||||
struct Ctrl3C {
|
||||
static constexpr uint8_t reg = 0x12;
|
||||
@@ -96,12 +90,12 @@ struct LSM6DSV : LSM6DSOutputHandler {
|
||||
};
|
||||
struct Ctrl8XLFS {
|
||||
static constexpr uint8_t reg = 0x17;
|
||||
static constexpr uint8_t value = (0b10); // 8g
|
||||
static constexpr uint8_t value = (0b01); // 4g
|
||||
};
|
||||
struct FifoCtrl3BDR {
|
||||
static constexpr uint8_t reg = 0x09;
|
||||
static constexpr uint8_t value
|
||||
= (0b1000) | (0b1000 << 4); // gyro and accel batched at 480Hz
|
||||
= 0b01110110; // Gyroscope batched into FIFO at 240Hz, Accel at 120Hz
|
||||
};
|
||||
struct FifoCtrl4Mode {
|
||||
static constexpr uint8_t reg = 0x0a;
|
||||
@@ -137,8 +131,8 @@ struct LSM6DSV : LSM6DSOutputHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
void bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
LSM6DSOutputHandler::template bulkRead<Regs>(
|
||||
bool bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
return LSM6DSOutputHandler::template bulkRead<Regs>(
|
||||
std::move(callbacks),
|
||||
GyrTs,
|
||||
AccTs,
|
||||
|
||||
@@ -70,13 +70,7 @@ struct MPU6050 {
|
||||
|
||||
static constexpr float TemperatureZROChange = 1.6f;
|
||||
|
||||
static constexpr VQFParams SensorVQFParams{
|
||||
.motionBiasEstEnabled = true,
|
||||
.biasSigmaInit = 20.0f,
|
||||
.biasClip = 40.0f,
|
||||
.restThGyr = 20.0f,
|
||||
.restThAcc = 0.784f,
|
||||
};
|
||||
static constexpr VQFParams SensorVQFParams{};
|
||||
|
||||
RegisterInterface& m_RegisterInterface;
|
||||
SlimeVR::Logging::Logger& m_Logger;
|
||||
@@ -182,7 +176,7 @@ struct MPU6050 {
|
||||
return result;
|
||||
}
|
||||
|
||||
void bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
bool bulkRead(DriverCallbacks<int16_t>&& callbacks) {
|
||||
const auto status = m_RegisterInterface.readReg(Regs::IntStatus);
|
||||
|
||||
if (status & (1 << MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) {
|
||||
@@ -190,7 +184,7 @@ struct MPU6050 {
|
||||
// This necessitates a reset
|
||||
m_Logger.debug("Fifo overrun, resetting...");
|
||||
resetFIFO();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::array<uint8_t, 12 * 10>
|
||||
@@ -200,7 +194,7 @@ struct MPU6050 {
|
||||
auto readBytes = min(static_cast<size_t>(byteCount), readBuffer.size())
|
||||
/ sizeof(FifoSample) * sizeof(FifoSample);
|
||||
if (!readBytes) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_RegisterInterface.readBytes(Regs::FifoData, readBytes, readBuffer.data());
|
||||
@@ -219,6 +213,8 @@ struct MPU6050 {
|
||||
xyz[2] = MPU6050_FIFO_VALUE(sample, gyro_z);
|
||||
callbacks.processGyroSample(xyz, GyrTs);
|
||||
}
|
||||
|
||||
return byteCount > readBytes;
|
||||
}
|
||||
}; // namespace SlimeVR::Sensors::SoftFusion::Drivers
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@ public:
|
||||
virtual void cancel() = 0;
|
||||
|
||||
virtual bool requiresRest() { return true; }
|
||||
// Signals that the sensor had more packets than the MCU could read, which can
|
||||
// compromise calibration
|
||||
virtual void signalOverwhelmed() {}
|
||||
virtual void processAccelSample(const SensorRawT accelSample[3]) {}
|
||||
virtual void processGyroSample(const SensorRawT accelSample[3]) {}
|
||||
virtual void processTempSample(float tempSample) {}
|
||||
|
||||
@@ -99,7 +99,10 @@ public:
|
||||
|
||||
gyroBiasCalibrationStep.swapCalibrationIfNecessary();
|
||||
|
||||
computeNextCalibrationStep();
|
||||
currentStep = &sampleRateCalibrationStep;
|
||||
currentStep->start();
|
||||
nextCalibrationStep = CalibrationStepEnum::SAMPLING_RATE;
|
||||
|
||||
calculateZROChange();
|
||||
|
||||
printCalibration();
|
||||
@@ -139,10 +142,14 @@ public:
|
||||
|
||||
switch (result) {
|
||||
case CalibrationStep<RawSensorT>::TickResult::DONE:
|
||||
if (nextCalibrationStep == CalibrationStepEnum::SAMPLING_RATE) {
|
||||
stepCalibrationForward(true, false);
|
||||
break;
|
||||
}
|
||||
stepCalibrationForward();
|
||||
break;
|
||||
case CalibrationStep<RawSensorT>::TickResult::SKIP:
|
||||
stepCalibrationForward(false);
|
||||
stepCalibrationForward(false, false);
|
||||
break;
|
||||
case CalibrationStep<RawSensorT>::TickResult::CONTINUE:
|
||||
break;
|
||||
@@ -179,6 +186,12 @@ public:
|
||||
return activeCalibration.MotionlessData;
|
||||
}
|
||||
|
||||
void signalOverwhelmed() final {
|
||||
if (isCalibrating) {
|
||||
currentStep->signalOverwhelmed();
|
||||
}
|
||||
}
|
||||
|
||||
void provideAccelSample(const RawSensorT accelSample[3]) final {
|
||||
if (isCalibrating) {
|
||||
currentStep->processAccelSample(accelSample);
|
||||
@@ -229,10 +242,7 @@ private:
|
||||
};
|
||||
|
||||
void computeNextCalibrationStep() {
|
||||
if (!calibration.sensorTimestepsCalibrated) {
|
||||
nextCalibrationStep = CalibrationStepEnum::SAMPLING_RATE;
|
||||
currentStep = &sampleRateCalibrationStep;
|
||||
} else if (!calibration.motionlessCalibrated && Base::HasMotionlessCalib) {
|
||||
if (!calibration.motionlessCalibrated && Base::HasMotionlessCalib) {
|
||||
nextCalibrationStep = CalibrationStepEnum::MOTIONLESS;
|
||||
currentStep = &motionlessCalibrationStep;
|
||||
} else if (calibration.gyroPointsCalibrated == 0) {
|
||||
@@ -247,7 +257,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void stepCalibrationForward(bool save = true) {
|
||||
void stepCalibrationForward(bool print = true, bool save = true) {
|
||||
currentStep->cancel();
|
||||
switch (nextCalibrationStep) {
|
||||
case CalibrationStepEnum::NONE:
|
||||
@@ -255,14 +265,14 @@ private:
|
||||
case CalibrationStepEnum::SAMPLING_RATE:
|
||||
nextCalibrationStep = CalibrationStepEnum::MOTIONLESS;
|
||||
currentStep = &motionlessCalibrationStep;
|
||||
if (save) {
|
||||
if (print) {
|
||||
printCalibration(CalibrationPrintFlags::TIMESTEPS);
|
||||
}
|
||||
break;
|
||||
case CalibrationStepEnum::MOTIONLESS:
|
||||
nextCalibrationStep = CalibrationStepEnum::GYRO_BIAS;
|
||||
currentStep = &gyroBiasCalibrationStep;
|
||||
if (save) {
|
||||
if (print) {
|
||||
printCalibration(CalibrationPrintFlags::MOTIONLESS);
|
||||
}
|
||||
break;
|
||||
@@ -274,7 +284,7 @@ private:
|
||||
currentStep = &gyroBiasCalibrationStep;
|
||||
}
|
||||
|
||||
if (save) {
|
||||
if (print) {
|
||||
printCalibration(CalibrationPrintFlags::GYRO_BIAS);
|
||||
}
|
||||
break;
|
||||
@@ -282,7 +292,7 @@ private:
|
||||
nextCalibrationStep = CalibrationStepEnum::GYRO_BIAS;
|
||||
currentStep = &gyroBiasCalibrationStep;
|
||||
|
||||
if (save) {
|
||||
if (print) {
|
||||
printCalibration(CalibrationPrintFlags::ACCEL_BIAS);
|
||||
}
|
||||
|
||||
@@ -306,8 +316,6 @@ private:
|
||||
calibration.data.runtimeCalibration = this->calibration;
|
||||
configuration.setSensor(sensorId, calibration);
|
||||
configuration.save();
|
||||
|
||||
ledManager.blink(100);
|
||||
}
|
||||
|
||||
enum class CalibrationPrintFlags {
|
||||
@@ -323,12 +331,12 @@ private:
|
||||
|
||||
void printCalibration(CalibrationPrintFlags toPrint = PrintAllCalibration) {
|
||||
if (any(toPrint & CalibrationPrintFlags::TIMESTEPS)) {
|
||||
if (calibration.sensorTimestepsCalibrated) {
|
||||
if (activeCalibration.sensorTimestepsCalibrated) {
|
||||
logger.info(
|
||||
"Calibrated timesteps: Accel %f, Gyro %f, Temperature %f",
|
||||
calibration.A_Ts,
|
||||
calibration.G_Ts,
|
||||
calibration.T_Ts
|
||||
activeCalibration.A_Ts,
|
||||
activeCalibration.G_Ts,
|
||||
activeCalibration.T_Ts
|
||||
);
|
||||
} else {
|
||||
logger.info("Sensor timesteps not calibrated");
|
||||
@@ -389,12 +397,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
CalibrationStepEnum nextCalibrationStep = CalibrationStepEnum::MOTIONLESS;
|
||||
CalibrationStepEnum nextCalibrationStep = CalibrationStepEnum::SAMPLING_RATE;
|
||||
|
||||
static constexpr float initialStartupDelaySeconds = 5;
|
||||
uint64_t startupMillis = millis();
|
||||
|
||||
SampleRateCalibrationStep<RawSensorT> sampleRateCalibrationStep{calibration};
|
||||
SampleRateCalibrationStep<RawSensorT> sampleRateCalibrationStep{activeCalibration};
|
||||
MotionlessCalibrationStep<IMU, RawSensorT> motionlessCalibrationStep{
|
||||
calibration,
|
||||
sensor
|
||||
|
||||
@@ -67,6 +67,14 @@ public:
|
||||
void cancel() override final { calibrationData.reset(); }
|
||||
bool requiresRest() override final { return false; }
|
||||
|
||||
void signalOverwhelmed() override final {
|
||||
// Not good, restart
|
||||
calibrationData.value().accelSamples = 0;
|
||||
calibrationData.value().gyroSamples = 0;
|
||||
calibrationData.value().tempSamples = 0;
|
||||
calibrationData.value().startMillis = millis();
|
||||
}
|
||||
|
||||
void processAccelSample(const SensorRawT accelSample[3]) override final {
|
||||
calibrationData.value().accelSamples++;
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ public:
|
||||
constexpr uint32_t sendInterval = 1.0f / maxSendRateHz * 1e6f;
|
||||
elapsed = now - m_lastRotationPacketSent;
|
||||
if (elapsed >= sendInterval) {
|
||||
m_sensor.bulkRead({
|
||||
auto overwhelmed = m_sensor.bulkRead({
|
||||
[&](const auto sample[3], float AccTs) {
|
||||
processAccelSample(sample, AccTs);
|
||||
},
|
||||
@@ -252,6 +252,9 @@ public:
|
||||
processTempSample(sample, TempTs);
|
||||
},
|
||||
});
|
||||
if (overwhelmed) {
|
||||
calibrator.signalOverwhelmed();
|
||||
}
|
||||
if (!m_fusion.isUpdated()) {
|
||||
checkSensorTimeout();
|
||||
return;
|
||||
|
||||
@@ -35,10 +35,34 @@
|
||||
#include "nvs_flash.h"
|
||||
#endif
|
||||
|
||||
#ifdef EXT_SERIAL_COMMANDS
|
||||
#define CALLBACK_SIZE 7 // Increase callback size to allow for debug commands
|
||||
#include "i2cscan.h"
|
||||
#endif
|
||||
|
||||
#ifndef CALLBACK_SIZE
|
||||
#define CALLBACK_SIZE 6 // Default callback size
|
||||
#endif
|
||||
|
||||
#if defined(VENDOR_URL) && defined(VENDOR_NAME) && defined(PRODUCT_NAME) \
|
||||
&& defined(UPDATE_ADDRESS) && defined(UPDATE_NAME)
|
||||
constexpr const char* FULL_VENDOR_STR
|
||||
= "Vendor: " VENDOR_NAME " (" VENDOR_URL "), product: " PRODUCT_NAME
|
||||
", firmware update url: " UPDATE_ADDRESS ", name: " UPDATE_NAME;
|
||||
#elif defined(VENDOR_URL) && defined(VENDOR_NAME) && defined(PRODUCT_NAME)
|
||||
constexpr const char* FULL_VENDOR_STR
|
||||
= "Vendor: " VENDOR_NAME " (" VENDOR_URL "), product: " PRODUCT_NAME;
|
||||
#elif defined(VENDOR_NAME) && defined(PRODUCT_NAME)
|
||||
constexpr const char* FULL_VENDOR_STR
|
||||
= "Vendor: " VENDOR_NAME ", product: " PRODUCT_NAME;
|
||||
#else
|
||||
constexpr const char* FULL_VENDOR_STR = "Vendor: Unknown, product: Unknown";
|
||||
#endif
|
||||
|
||||
namespace SerialCommands {
|
||||
SlimeVR::Logging::Logger logger("SerialCommands");
|
||||
|
||||
CmdCallback<6> cmdCallbacks;
|
||||
CmdCallback<CALLBACK_SIZE> cmdCallbacks;
|
||||
CmdParser cmdParser;
|
||||
CmdBuffer<256> cmdBuffer;
|
||||
|
||||
@@ -85,7 +109,7 @@ void cmdSet(CmdParser* parser) {
|
||||
return;
|
||||
}
|
||||
|
||||
WiFiNetwork::setWiFiCredentials(sc_ssid, sc_pw);
|
||||
wifiNetwork.setWiFiCredentials(sc_ssid, sc_pw);
|
||||
logger.info("CMD SET WIFI OK: New wifi credentials set, reconnecting");
|
||||
}
|
||||
} else if (parser->equalCmdParam(1, "BWIFI")) {
|
||||
@@ -131,7 +155,7 @@ void cmdSet(CmdParser* parser) {
|
||||
// set the pointer for pass to null for no password
|
||||
ppass = NULL;
|
||||
}
|
||||
WiFiNetwork::setWiFiCredentials(ssid, ppass);
|
||||
wifiNetwork.setWiFiCredentials(ssid, ppass);
|
||||
logger.info("CMD SET BWIFI OK: New wifi credentials set, reconnecting");
|
||||
}
|
||||
} else {
|
||||
@@ -150,43 +174,13 @@ void printState() {
|
||||
HARDWARE_MCU,
|
||||
PROTOCOL_VERSION,
|
||||
FIRMWARE_VERSION,
|
||||
WiFiNetwork::getAddress().toString().c_str(),
|
||||
wifiNetwork.getAddress().toString().c_str(),
|
||||
WiFi.macAddress().c_str(),
|
||||
statusManager.getStatus(),
|
||||
WiFiNetwork::getWiFiState()
|
||||
wifiNetwork.getWiFiState()
|
||||
);
|
||||
|
||||
char vendorBuffer[512];
|
||||
size_t writtenLength;
|
||||
|
||||
if (strlen(VENDOR_URL) == 0) {
|
||||
sprintf(
|
||||
vendorBuffer,
|
||||
"Vendor: %s, product: %s%n",
|
||||
VENDOR_NAME,
|
||||
PRODUCT_NAME,
|
||||
&writtenLength
|
||||
);
|
||||
} else {
|
||||
sprintf(
|
||||
vendorBuffer,
|
||||
"Vendor: %s (%s), product: %s%n",
|
||||
VENDOR_NAME,
|
||||
VENDOR_URL,
|
||||
PRODUCT_NAME,
|
||||
&writtenLength
|
||||
);
|
||||
}
|
||||
|
||||
if (strlen(UPDATE_ADDRESS) > 0 && strlen(UPDATE_NAME) > 0) {
|
||||
sprintf(
|
||||
vendorBuffer + writtenLength,
|
||||
", firmware update url: %s, name: %s",
|
||||
UPDATE_ADDRESS,
|
||||
UPDATE_NAME
|
||||
);
|
||||
}
|
||||
logger.info("%s", vendorBuffer);
|
||||
logger.info("%s", FULL_VENDOR_STR);
|
||||
|
||||
for (auto& sensor : sensorManager.getSensors()) {
|
||||
logger.info(
|
||||
@@ -311,10 +305,10 @@ void cmdGet(CmdParser* parser) {
|
||||
HARDWARE_MCU,
|
||||
PROTOCOL_VERSION,
|
||||
FIRMWARE_VERSION,
|
||||
WiFiNetwork::getAddress().toString().c_str(),
|
||||
wifiNetwork.getAddress().toString().c_str(),
|
||||
WiFi.macAddress().c_str(),
|
||||
statusManager.getStatus(),
|
||||
WiFiNetwork::getWiFiState()
|
||||
wifiNetwork.getWiFiState()
|
||||
);
|
||||
auto& sensor0 = sensorManager.getSensors()[0];
|
||||
sensor0->motionLoop();
|
||||
@@ -347,8 +341,8 @@ void cmdGet(CmdParser* parser) {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
WiFi.disconnect();
|
||||
}
|
||||
if (WiFiNetwork::isProvisioning()) {
|
||||
WiFiNetwork::stopProvisioning();
|
||||
if (wifiProvisioning.isProvisioning()) {
|
||||
wifiProvisioning.stopProvisioning();
|
||||
}
|
||||
|
||||
WiFi.scanNetworks();
|
||||
@@ -457,6 +451,13 @@ void cmdDeleteCalibration(CmdParser* parser) {
|
||||
configuration.eraseSensors();
|
||||
}
|
||||
|
||||
#if EXT_SERIAL_COMMANDS
|
||||
void cmdScanI2C(CmdParser* parser) {
|
||||
logger.info("Forcing I2C scan...");
|
||||
I2CSCAN::scani2cports();
|
||||
}
|
||||
#endif
|
||||
|
||||
void setUp() {
|
||||
cmdCallbacks.addCmd("SET", &cmdSet);
|
||||
cmdCallbacks.addCmd("GET", &cmdGet);
|
||||
@@ -464,6 +465,9 @@ void setUp() {
|
||||
cmdCallbacks.addCmd("REBOOT", &cmdReboot);
|
||||
cmdCallbacks.addCmd("DELCAL", &cmdDeleteCalibration);
|
||||
cmdCallbacks.addCmd("TCAL", &cmdTemperatureCalibration);
|
||||
#if EXT_SERIAL_COMMANDS
|
||||
cmdCallbacks.addCmd("SCANI2C", &cmdScanI2C);
|
||||
#endif
|
||||
}
|
||||
|
||||
void update() { cmdCallbacks.updateCmdProcessing(&cmdParser, &cmdBuffer, &Serial); }
|
||||
|
||||
Reference in New Issue
Block a user