diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 37510c2..cc4c40a 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -71,3 +71,4 @@ jobs: generate_release_notes: true files: | ./build/BOARD_SLIMEVR-firmware.bin + ./build/BOARD_SLIMEVR_V1_2-firmware.bin diff --git a/ci/build.py b/ci/build.py index 9cbf47a..75df6a3 100644 --- a/ci/build.py +++ b/ci/build.py @@ -95,7 +95,7 @@ def build() -> int: status = build_for_device(device) if not status: - failed_builds.append(device.platformio_board) + failed_builds.append(device.board) if len(failed_builds) > 0: print(f" 🡢 {COLOR_RED}Failed!{COLOR_RESET}") diff --git a/lib/bno080/BNO080.cpp b/lib/bno080/BNO080.cpp index e97e2a2..9a2373b 100644 --- a/lib/bno080/BNO080.cpp +++ b/lib/bno080/BNO080.cpp @@ -12,7 +12,6 @@ This library handles the initialization of the BNO080 and is able to query the sensor for different readings. - https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library Development environment specifics: @@ -688,6 +687,16 @@ void BNO080::getAccel(float &x, float &y, float &z, uint8_t &accuracy) hasNewAccel_ = false; } +bool BNO080::getNewAccel(float &x, float &y, float &z, uint8_t &accuracy) +{ + if (hasNewAccel_) + { + getAccel(x, y, z, accuracy); + return true; + } + return false; +} + //Return the acceleration component float BNO080::getAccelX() { diff --git a/lib/bno080/BNO080.h b/lib/bno080/BNO080.h index eb31a99..678714b 100644 --- a/lib/bno080/BNO080.h +++ b/lib/bno080/BNO080.h @@ -214,6 +214,7 @@ public: uint8_t getQuatAccuracy(); void getAccel(float &x, float &y, float &z, uint8_t &accuracy); + bool getNewAccel(float &x, float &y, float &z, uint8_t &accuracy); float getAccelX(); float getAccelY(); float getAccelZ(); diff --git a/platformio-tools.ini b/platformio-tools.ini index f6c4239..542a710 100644 --- a/platformio-tools.ini +++ b/platformio-tools.ini @@ -17,26 +17,62 @@ build_unflags = [env:BOARD_SLIMEVR] platform = espressif8266 @ 4.2.1 board = esp12e +build_flags = + ${env.build_flags} + -D BOARD=BOARD_SLIMEVR + +[env:BOARD_SLIMEVR_V1_2] +platform = espressif8266 @ 4.2.1 +board = esp12e +build_flags = + ${env.build_flags} + -D BOARD=BOARD_SLIMEVR_V1_2 [env:BOARD_SLIMEVR_DEV] platform = espressif8266 @ 4.2.1 board = esp12e +build_flags = + ${env.build_flags} + -D BOARD=BOARD_SLIMEVR_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 +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 @@ -44,6 +80,9 @@ 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 @@ -51,6 +90,9 @@ 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 @@ -60,6 +102,7 @@ platform_packages = build_flags = ${env.build_flags} -DESP32C3 + -D BOARD=BOARD_LOLIN_C3_MINI board = lolin_c3_mini [env:BOARD_BEETLE32C3] @@ -70,6 +113,7 @@ platform_packages = build_flags = ${env.build_flags} -DESP32C3 + -D BOARD=BOARD_BEETLE32C3 board = dfrobot_beetle_esp32c3 [env:BOARD_ESP32C3DEVKITM1] @@ -80,6 +124,7 @@ platform_packages = build_flags = ${env.build_flags} -DESP32C3 + -D BOARD=BOARD_ESP32C3DEVKITM1 board = esp32-c3-devkitm-1 [env:BOARD_ESP32C6DEVKITC1] @@ -87,6 +132,7 @@ platform = https://github.com/tasmota/platform-espressif32/releases/download/202 build_flags = ${env.build_flags} -DESP32C6 + -D BOARD=BOARD_ESP32C6DEVKITC1 board = esp32-c6-devkitc-1 [env:BOARD_XIAO_ESP32C3] @@ -97,4 +143,5 @@ platform_packages = build_flags = ${env.build_flags} -DESP32C3 + -D BOARD=BOARD_XIAO_ESP32C3 board = seeed_xiao_esp32c3 diff --git a/src/FSHelper.cpp b/src/FSHelper.cpp index c30932d..fffdb0a 100644 --- a/src/FSHelper.cpp +++ b/src/FSHelper.cpp @@ -25,8 +25,7 @@ #include -namespace SlimeVR { -namespace Utils { +namespace SlimeVR::Utils { SlimeVR::Logging::Logger m_Logger("FSHelper"); bool ensureDirectory(const char* directory) { @@ -88,5 +87,4 @@ void forEachFile(const char* directory, std::function callback) } #endif } -} // namespace Utils -} // namespace SlimeVR +} // namespace SlimeVR::Utils diff --git a/src/FSHelper.h b/src/FSHelper.h index e99dd06..d407496 100644 --- a/src/FSHelper.h +++ b/src/FSHelper.h @@ -29,8 +29,7 @@ #include -namespace SlimeVR { -namespace Utils { +namespace SlimeVR::Utils { class File { public: @@ -62,7 +61,6 @@ bool ensureDirectory(const char* directory); File openFile(const char* path, const char* mode); void forEachFile(const char* directory, std::function callback); -} // namespace Utils -} // namespace SlimeVR +} // namespace SlimeVR::Utils #endif diff --git a/src/GlobalVars.h b/src/GlobalVars.h index 1d2f191..4c7cb3c 100644 --- a/src/GlobalVars.h +++ b/src/GlobalVars.h @@ -20,18 +20,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -#ifndef GLOBALVARS_H -#define GLOBALVARS_H +#pragma once #include -#include "LEDManager.h" #include "batterymonitor.h" #include "configuration/Configuration.h" #include "network/connection.h" #include "network/manager.h" #include "sensors/SensorManager.h" +#include "status/LEDManager.h" #include "status/StatusManager.h" extern Timer<> globalTimer; @@ -42,5 +40,3 @@ extern SlimeVR::Sensors::SensorManager sensorManager; extern SlimeVR::Network::Manager networkManager; extern SlimeVR::Network::Connection networkConnection; extern BatteryMonitor battery; - -#endif diff --git a/src/board_default.h b/src/boards/boards_default.h similarity index 52% rename from src/board_default.h rename to src/boards/boards_default.h index f990f32..72fb245 100644 --- a/src/board_default.h +++ b/src/boards/boards_default.h @@ -174,3 +174,73 @@ BATTERY_R1(10) BATTERY_R2(40.2) #endif + +// Default IMU pinouts and definitions for default tracker types + +#if BOARD != BOARD_GLOVE_IMU_SLIMEVR_DEV +// Defaunlt definitions for normal 2-sensor trackers +#ifndef MAX_SENSORS_COUNT +#define MAX_SENSORS_COUNT 2 +#endif +#ifndef TRACKER_TYPE +#define TRACKER_TYPE TrackerType::TRACKER_TYPE_SVR_ROTATION +#endif + +// Axis mapping example +/* +#include "sensors/axisremap.h" +#define BMI160_QMC_REMAP AXIS_REMAP_BUILD(AXIS_REMAP_USE_Y, AXIS_REMAP_USE_XN, +AXIS_REMAP_USE_Z, \ AXIS_REMAP_USE_YN, AXIS_REMAP_USE_X, AXIS_REMAP_USE_Z) + +SENSOR_DESC_ENTRY(IMU_BMP160, PRIMARY_IMU_ADDRESS_ONE, IMU_ROTATION, PIN_IMU_SCL, +PIN_IMU_SDA, PRIMARY_IMU_OPTIONAL, BMI160_QMC_REMAP) \ +*/ + +#ifndef SENSOR_DESC_LIST +#if BOARD == BOARD_SLIMEVR_V1_2 +#define SENSOR_DESC_LIST \ + SENSOR_DESC_ENTRY( \ + IMU, \ + DIRECT_PIN(15), \ + IMU_ROTATION, \ + DIRECT_SPI(24'000'000, MSBFIRST, SPI_MODE3), \ + PRIMARY_IMU_OPTIONAL, \ + DIRECT_PIN(PIN_IMU_INT), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + SECOND_IMU, \ + SECONDARY_IMU_ADDRESS_TWO, \ + SECOND_IMU_ROTATION, \ + DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ + SECONDARY_IMU_OPTIONAL, \ + DIRECT_PIN(PIN_IMU_INT_2), \ + 0 \ + ) +#else +#define SENSOR_DESC_LIST \ + SENSOR_DESC_ENTRY( \ + IMU, \ + PRIMARY_IMU_ADDRESS_ONE, \ + IMU_ROTATION, \ + DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ + PRIMARY_IMU_OPTIONAL, \ + DIRECT_PIN(PIN_IMU_INT), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + SECOND_IMU, \ + SECONDARY_IMU_ADDRESS_TWO, \ + SECOND_IMU_ROTATION, \ + DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ + SECONDARY_IMU_OPTIONAL, \ + DIRECT_PIN(PIN_IMU_INT_2), \ + 0 \ + ) +#endif +#endif +#else // BOARD == BOARD_GLOVE_IMU_SLIMEVR_DEV + +#include "glove_default.h" + +#endif // BOARD != BOARD_GLOVE_IMU_SLIMEVR_DEV diff --git a/src/defines_helpers.cpp b/src/boards/defines_helpers.cpp similarity index 98% rename from src/defines_helpers.cpp rename to src/boards/defines_helpers.cpp index a8613e5..a2c5ad7 100644 --- a/src/defines_helpers.cpp +++ b/src/boards/defines_helpers.cpp @@ -23,7 +23,7 @@ #include "defines_helpers.h" -#include "consts.h" +#include "../consts.h" #ifndef LED_BUILTIN #define LED_BUILTIN LED_OFF diff --git a/src/defines_helpers.h b/src/boards/defines_helpers.h similarity index 98% rename from src/defines_helpers.h rename to src/boards/defines_helpers.h index 166349e..dcb26f7 100644 --- a/src/defines_helpers.h +++ b/src/boards/defines_helpers.h @@ -63,7 +63,9 @@ #define LED(pin) #endif -extern const bool __attribute__((weak)) LED_INVERTED; +#ifndef LED_PIN +extern const uint8_t __attribute__((weak)) LED_PIN; +#endif #ifndef BATTERY_SHIELD_RESISTANCE #define BATTERY_SHIELD_R(value) constexpr float BATTERY_SHIELD_RESISTANCE = value; @@ -89,4 +91,6 @@ extern const bool __attribute__((weak)) LED_INVERTED; #define INVERTED_LED(value) #endif -extern const uint8_t __attribute__((weak)) LED_PIN; +#ifndef LED_INVERTED +extern const bool __attribute__((weak)) LED_INVERTED; +#endif diff --git a/src/boards/glove_default.h b/src/boards/glove_default.h new file mode 100644 index 0000000..e86ffab --- /dev/null +++ b/src/boards/glove_default.h @@ -0,0 +1,140 @@ +// default definitions for the GLOVE +#ifndef MAX_SENSORS_COUNT +#define MAX_SENSORS_COUNT 10 +#endif +#ifndef TRACKER_TYPE +#define TRACKER_TYPE TrackerType::TRACKER_TYPE_SVR_GLOVE_LEFT +#endif +#ifndef GLOVE_SIDE +#define GLOVE_SIDE GLOVE_LEFT +#endif +#ifndef PRIMARY_IMU_ADDRESS_ONE +#define PRIMARY_IMU_ADDRESS_ONE 0x4a +#endif +#ifndef SECONDARY_IMU_ADDRESS_TWO +#define SECONDARY_IMU_ADDRESS_TWO 0x4b +#endif + +#ifndef SENSOR_DESC_LIST +#define SENSOR_DESC_LIST \ + SENSOR_DESC_ENTRY( \ + IMU, \ + (PRIMARY_IMU_ADDRESS_ONE ^ 0x02), \ + IMU_ROTATION, \ + DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ + false, \ + MCP_PIN(MCP_GPA6), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + (SECONDARY_IMU_ADDRESS_TWO ^ 0x02), \ + IMU_ROTATION, \ + DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ + true, \ + MCP_PIN(MCP_GPA5), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + PRIMARY_IMU_ADDRESS_ONE, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 0), \ + true, \ + MCP_PIN(MCP_GPB0), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + SECONDARY_IMU_ADDRESS_TWO, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 0), \ + true, \ + MCP_PIN(MCP_GPB1), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + PRIMARY_IMU_ADDRESS_ONE, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 1), \ + true, \ + MCP_PIN(MCP_GPB2), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + SECONDARY_IMU_ADDRESS_TWO, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 1), \ + true, \ + MCP_PIN(MCP_GPB3), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + PRIMARY_IMU_ADDRESS_ONE, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 2), \ + true, \ + MCP_PIN(MCP_GPB4), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + SECONDARY_IMU_ADDRESS_TWO, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 2), \ + true, \ + MCP_PIN(MCP_GPB5), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + PRIMARY_IMU_ADDRESS_ONE, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 3), \ + true, \ + MCP_PIN(MCP_GPB6), \ + 0 \ + ) \ + SENSOR_DESC_ENTRY( \ + IMU, \ + SECONDARY_IMU_ADDRESS_TWO, \ + IMU_ROTATION, \ + PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 3), \ + true, \ + MCP_PIN(MCP_GPA1), \ + 0 \ + ) +#endif + +#ifndef SENSOR_INFO_LIST +#if GLOVE_SIDE == GLOVE_LEFT +#define SENSOR_INFO_LIST \ + SENSOR_INFO_ENTRY(0, SensorPosition::POSITION_LEFT_HAND) \ + SENSOR_INFO_ENTRY(1, SensorPosition::POSITION_LEFT_LITTLE_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(2, SensorPosition::POSITION_LEFT_RING_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(3, SensorPosition::POSITION_LEFT_RING_DISTAL) \ + SENSOR_INFO_ENTRY(4, SensorPosition::POSITION_LEFT_MIDDLE_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(5, SensorPosition::POSITION_LEFT_MIDDLE_DISTAL) \ + SENSOR_INFO_ENTRY(6, SensorPosition::POSITION_LEFT_INDEX_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(7, SensorPosition::POSITION_LEFT_INDEX_DISTAL) \ + SENSOR_INFO_ENTRY(8, SensorPosition::POSITION_LEFT_THUMB_PROXIMAL) \ + SENSOR_INFO_ENTRY(9, SensorPosition::POSITION_LEFT_THUMB_DISTAL) +#elif GLOVE_SDIE == GLOVE_RIGHT +#define SENSOR_INFO_LIST \ + SENSOR_INFO_ENTRY(0, SensorPosition::POSITION_RIGHT_HAND) \ + SENSOR_INFO_ENTRY(1, SensorPosition::POSITION_RIGHT_LITTLE_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(2, SensorPosition::POSITION_RIGHT_RING_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(3, SensorPosition::POSITION_RIGHT_RING_DISTAL) \ + SENSOR_INFO_ENTRY(4, SensorPosition::POSITION_RIGHT_MIDDLE_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(5, SensorPosition::POSITION_RIGHT_MIDDLE_DISTAL) \ + SENSOR_INFO_ENTRY(6, SensorPosition::POSITION_RIGHT_INDEX_INTERMEDIATE) \ + SENSOR_INFO_ENTRY(7, SensorPosition::POSITION_RIGHT_INDEX_DISTAL) \ + SENSOR_INFO_ENTRY(8, SensorPosition::POSITION_RIGHT_THUMB_PROXIMAL) \ + SENSOR_INFO_ENTRY(9, SensorPosition::POSITION_RIGHT_THUMB_DISTAL) +#else // GLOVE_SIDE +#error "Glove side not defined" +#endif // GLOVE_SIDE +#endif diff --git a/src/configuration/Configuration.cpp b/src/configuration/Configuration.cpp index 4e14e93..402056a 100644 --- a/src/configuration/Configuration.cpp +++ b/src/configuration/Configuration.cpp @@ -33,8 +33,7 @@ #define DIR_TEMPERATURE_CALIBRATIONS "/tempcalibrations" #define DIR_TOGGLES "/toggles" -namespace SlimeVR { -namespace Configuration { +namespace SlimeVR::Configuration { void Configuration::setup() { if (m_Loaded) { return; @@ -442,5 +441,4 @@ void Configuration::print() { } } } -} // namespace Configuration -} // namespace SlimeVR +} // namespace SlimeVR::Configuration diff --git a/src/configuration/Configuration.h b/src/configuration/Configuration.h index 7abb458..b8aff0d 100644 --- a/src/configuration/Configuration.h +++ b/src/configuration/Configuration.h @@ -31,8 +31,7 @@ #include "DeviceConfig.h" #include "logging/Logger.h" -namespace SlimeVR { -namespace Configuration { +namespace SlimeVR::Configuration { class Configuration { public: void setup(); @@ -72,7 +71,6 @@ private: Logging::Logger m_Logger = Logging::Logger("Configuration"); }; -} // namespace Configuration -} // namespace SlimeVR +} // namespace SlimeVR::Configuration #endif diff --git a/src/configuration/SensorConfig.cpp b/src/configuration/SensorConfig.cpp index 2cecdb3..aee7ae7 100644 --- a/src/configuration/SensorConfig.cpp +++ b/src/configuration/SensorConfig.cpp @@ -23,8 +23,7 @@ #include "SensorConfig.h" -namespace SlimeVR { -namespace Configuration { +namespace SlimeVR::Configuration { const char* calibrationConfigTypeToString(SensorConfigType type) { switch (type) { case SensorConfigType::NONE: @@ -60,5 +59,4 @@ bool SensorConfigBits::operator!=(const SensorConfigBits& rhs) const { return !(*this == rhs); } -} // namespace Configuration -} // namespace SlimeVR +} // namespace SlimeVR::Configuration diff --git a/src/configuration/SensorConfig.h b/src/configuration/SensorConfig.h index 16cff99..4e19725 100644 --- a/src/configuration/SensorConfig.h +++ b/src/configuration/SensorConfig.h @@ -28,8 +28,7 @@ #include "consts.h" -namespace SlimeVR { -namespace Configuration { +namespace SlimeVR::Configuration { struct BMI160SensorConfig { // accelerometer offsets and correction matrix float A_B[3]; @@ -196,7 +195,6 @@ struct SensorConfigBits { // If this fails, you forgot to do the above static_assert(sizeof(SensorConfigBits) == 2); -} // namespace Configuration -} // namespace SlimeVR +} // namespace SlimeVR::Configuration #endif diff --git a/src/defines.h b/src/defines.h index ee9d69c..819d551 100644 --- a/src/defines.h +++ b/src/defines.h @@ -26,214 +26,41 @@ // ================================================ // Set parameters of IMU and board used +#ifndef IMU #define IMU IMU_AUTO +#endif +#ifndef SECOND_IMU #define SECOND_IMU IMU_AUTO +#endif +#ifndef BOARD #define BOARD BOARD_SLIMEVR_V1_2 +#endif +#ifndef IMU_ROTATION #define IMU_ROTATION DEG_270 +#endif +#ifndef SECOND_IMU_ROTATION #define SECOND_IMU_ROTATION DEG_270 +#endif +#ifndef PRIMARY_IMU_OPTIONAL #define PRIMARY_IMU_OPTIONAL false +#endif +#ifndef SECONDARY_IMU_OPTIONAL #define SECONDARY_IMU_OPTIONAL true +#endif -#if BOARD != BOARD_GLOVE_IMU_SLIMEVR_DEV -#define MAX_SENSORS_COUNT 2 -#define TRACKER_TYPE TrackerType::TRACKER_TYPE_SVR_ROTATION // Set I2C address here or directly in IMU_DESC_ENTRY for each IMU used // If not set, default address is used based on the IMU and Sensor ID // #define PRIMARY_IMU_ADDRESS_ONE 0x4a // #define SECONDARY_IMU_ADDRESS_TWO 0x4b -// Axis mapping example -/* -#include "sensors/axisremap.h" -#define BMI160_QMC_REMAP AXIS_REMAP_BUILD(AXIS_REMAP_USE_Y, AXIS_REMAP_USE_XN, -AXIS_REMAP_USE_Z, \ AXIS_REMAP_USE_YN, AXIS_REMAP_USE_X, AXIS_REMAP_USE_Z) - -SENSOR_DESC_ENTRY(IMU_BMP160, PRIMARY_IMU_ADDRESS_ONE, IMU_ROTATION, PIN_IMU_SCL, -PIN_IMU_SDA, PRIMARY_IMU_OPTIONAL, BMI160_QMC_REMAP) \ -*/ - -#ifndef SENSOR_DESC_LIST -#if BOARD == BOARD_SLIMEVR_V1_2 -#define SENSOR_DESC_LIST \ - SENSOR_DESC_ENTRY( \ - IMU, \ - DIRECT_SPI(24'000'000, MSBFIRST, SPI_MODE3, DIRECT_PIN(15)), \ - IMU_ROTATION, \ - NO_WIRE, \ - PRIMARY_IMU_OPTIONAL, \ - DIRECT_PIN(PIN_IMU_INT), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - SECOND_IMU, \ - SECONDARY_IMU_ADDRESS_TWO, \ - SECOND_IMU_ROTATION, \ - DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ - SECONDARY_IMU_OPTIONAL, \ - DIRECT_PIN(PIN_IMU_INT_2), \ - 0 \ - ) -#else -#define SENSOR_DESC_LIST \ - SENSOR_DESC_ENTRY( \ - IMU, \ - PRIMARY_IMU_ADDRESS_ONE, \ - IMU_ROTATION, \ - DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ - PRIMARY_IMU_OPTIONAL, \ - DIRECT_PIN(PIN_IMU_INT), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - SECOND_IMU, \ - SECONDARY_IMU_ADDRESS_TWO, \ - SECOND_IMU_ROTATION, \ - DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ - SECONDARY_IMU_OPTIONAL, \ - DIRECT_PIN(PIN_IMU_INT_2), \ - 0 \ - ) -#endif -#endif -#else - -// Predefines for the GLOVE -#ifndef SENSOR_DESC_LIST -#define MAX_SENSORS_COUNT 10 -#define TRACKER_TYPE TrackerType::TRACKER_TYPE_SVR_GLOVE_LEFT -#define GLOVE_SIDE GLOVE_LEFT -#define PRIMARY_IMU_ADDRESS_ONE 0x4a -#define SECONDARY_IMU_ADDRESS_TWO 0x4b - -#define SENSOR_DESC_LIST \ - SENSOR_DESC_ENTRY( \ - IMU, \ - (PRIMARY_IMU_ADDRESS_ONE ^ 0x02), \ - IMU_ROTATION, \ - DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ - false, \ - MCP_PIN(MCP_GPA6), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - (SECONDARY_IMU_ADDRESS_TWO ^ 0x02), \ - IMU_ROTATION, \ - DIRECT_WIRE(PIN_IMU_SCL, PIN_IMU_SDA), \ - true, \ - MCP_PIN(MCP_GPA5), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - PRIMARY_IMU_ADDRESS_ONE, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 0), \ - true, \ - MCP_PIN(MCP_GPB0), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - SECONDARY_IMU_ADDRESS_TWO, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 0), \ - true, \ - MCP_PIN(MCP_GPB1), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - PRIMARY_IMU_ADDRESS_ONE, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 1), \ - true, \ - MCP_PIN(MCP_GPB2), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - SECONDARY_IMU_ADDRESS_TWO, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 1), \ - true, \ - MCP_PIN(MCP_GPB3), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - PRIMARY_IMU_ADDRESS_ONE, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 2), \ - true, \ - MCP_PIN(MCP_GPB4), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - SECONDARY_IMU_ADDRESS_TWO, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 2), \ - true, \ - MCP_PIN(MCP_GPB5), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - PRIMARY_IMU_ADDRESS_ONE, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 3), \ - true, \ - MCP_PIN(MCP_GPB6), \ - 0 \ - ) \ - SENSOR_DESC_ENTRY( \ - IMU, \ - SECONDARY_IMU_ADDRESS_TWO, \ - IMU_ROTATION, \ - PCA_WIRE(PIN_IMU_SCL, PIN_IMU_SDA, PCA_ADDR, 3), \ - true, \ - MCP_PIN(MCP_GPA1), \ - 0 \ - ) - -#if GLOVE_SIDE == GLOVE_LEFT -#define SENSOR_INFO_LIST \ - SENSOR_INFO_ENTRY(0, SensorPosition::POSITION_LEFT_HAND) \ - SENSOR_INFO_ENTRY(1, SensorPosition::POSITION_LEFT_LITTLE_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(2, SensorPosition::POSITION_LEFT_RING_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(3, SensorPosition::POSITION_LEFT_RING_DISTAL) \ - SENSOR_INFO_ENTRY(4, SensorPosition::POSITION_LEFT_MIDDLE_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(5, SensorPosition::POSITION_LEFT_MIDDLE_DISTAL) \ - SENSOR_INFO_ENTRY(6, SensorPosition::POSITION_LEFT_INDEX_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(7, SensorPosition::POSITION_LEFT_INDEX_DISTAL) \ - SENSOR_INFO_ENTRY(8, SensorPosition::POSITION_LEFT_THUMB_PROXIMAL) \ - SENSOR_INFO_ENTRY(9, SensorPosition::POSITION_LEFT_THUMB_DISTAL) -#elif GLOVE_SDIE == GLOVE_RIGHT -#define SENSOR_INFO_LIST \ - SENSOR_INFO_ENTRY(0, SensorPosition::POSITION_RIGHT_HAND) \ - SENSOR_INFO_ENTRY(1, SensorPosition::POSITION_RIGHT_LITTLE_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(2, SensorPosition::POSITION_RIGHT_RING_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(3, SensorPosition::POSITION_RIGHT_RING_DISTAL) \ - SENSOR_INFO_ENTRY(4, SensorPosition::POSITION_RIGHT_MIDDLE_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(5, SensorPosition::POSITION_RIGHT_MIDDLE_DISTAL) \ - SENSOR_INFO_ENTRY(6, SensorPosition::POSITION_RIGHT_INDEX_INTERMEDIATE) \ - SENSOR_INFO_ENTRY(7, SensorPosition::POSITION_RIGHT_INDEX_DISTAL) \ - SENSOR_INFO_ENTRY(8, SensorPosition::POSITION_RIGHT_THUMB_PROXIMAL) \ - SENSOR_INFO_ENTRY(9, SensorPosition::POSITION_RIGHT_THUMB_DISTAL) -#else // GLOVE_SDIE -#error "Glove side not defined" -#endif // GLOVE_SDIE - -#endif // SENSOR_DESC_LIST -#endif // BOARD != BOARD_GLOVE_IMU_SLIMEVR_DEV - +#ifndef BATTERY_MONITOR // Battery monitoring options (comment to disable): // BAT_EXTERNAL for ADC pin, // BAT_INTERNAL for internal - can detect only low battery, // BAT_MCP3021 for external ADC connected over I2C #define BATTERY_MONITOR BAT_EXTERNAL +#endif // --- OVERRIDES FOR DEFAULT PINS diff --git a/src/globals.h b/src/globals.h index 6433ee1..5f6da82 100644 --- a/src/globals.h +++ b/src/globals.h @@ -20,8 +20,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef SLIMEVR_GLOBALS_H_ -#define SLIMEVR_GLOBALS_H_ +#pragma once #include @@ -30,7 +29,7 @@ #include "defines.h" // clang-format off -#include "board_default.h" +#include "boards/boards_default.h" // clang-format on #ifndef SECOND_IMU @@ -53,5 +52,3 @@ #ifndef EXPERIMENTAL_BNO_DISABLE_ACCEL_CALIBRATION #define EXPERIMENTAL_BNO_DISABLE_ACCEL_CALIBRATION true #endif - -#endif // SLIMEVR_GLOBALS_H_ diff --git a/src/logging/Level.cpp b/src/logging/Level.cpp index 8c9b677..c85fb83 100644 --- a/src/logging/Level.cpp +++ b/src/logging/Level.cpp @@ -1,7 +1,6 @@ #include "Level.h" -namespace SlimeVR { -namespace Logging { +namespace SlimeVR::Logging { const char* levelToString(Level level) { switch (level) { case TRACE: @@ -20,5 +19,4 @@ const char* levelToString(Level level) { return "UNKNOWN"; } } -} // namespace Logging -} // namespace SlimeVR +} // namespace SlimeVR::Logging diff --git a/src/logging/Level.h b/src/logging/Level.h index b33ca55..7b5bcd4 100644 --- a/src/logging/Level.h +++ b/src/logging/Level.h @@ -7,8 +7,7 @@ #define LOG_LEVEL_ERROR 4 #define LOG_LEVEL_FATAL 5 -namespace SlimeVR { -namespace Logging { +namespace SlimeVR::Logging { enum Level { TRACE = LOG_LEVEL_TRACE, DEBUG = LOG_LEVEL_DEBUG, @@ -19,8 +18,7 @@ enum Level { }; const char* levelToString(Level level); -} // namespace Logging -} // namespace SlimeVR +} // namespace SlimeVR::Logging #define LOGGING_LEVEL_H #endif diff --git a/src/logging/Logger.cpp b/src/logging/Logger.cpp index 4508369..7223626 100644 --- a/src/logging/Logger.cpp +++ b/src/logging/Logger.cpp @@ -1,7 +1,6 @@ #include "Logger.h" -namespace SlimeVR { -namespace Logging { +namespace SlimeVR::Logging { void Logger::setTag(const char* tag) { m_Tag = (char*)malloc(strlen(tag) + 1); strcpy(m_Tag, tag); @@ -66,5 +65,4 @@ void Logger::log(Level level, const char* format, va_list args) const { Serial.printf("[%-5s] [%s] %s\n", levelToString(level), buf, buffer); } -} // namespace Logging -} // namespace SlimeVR +} // namespace SlimeVR::Logging diff --git a/src/logging/Logger.h b/src/logging/Logger.h index 1db5ac8..dc783d0 100644 --- a/src/logging/Logger.h +++ b/src/logging/Logger.h @@ -6,8 +6,7 @@ #include "Level.h" #include "debug.h" -namespace SlimeVR { -namespace Logging { +namespace SlimeVR::Logging { class Logger { public: Logger(const char* prefix) @@ -92,7 +91,6 @@ private: const char* const m_Prefix; char* m_Tag; }; -} // namespace Logging -} // namespace SlimeVR +} // namespace SlimeVR::Logging #endif diff --git a/src/motionprocessing/GyroTemperatureCalibrator.cpp b/src/motionprocessing/GyroTemperatureCalibrator.cpp index 8b4cc02..b7ec32e 100644 --- a/src/motionprocessing/GyroTemperatureCalibrator.cpp +++ b/src/motionprocessing/GyroTemperatureCalibrator.cpp @@ -227,7 +227,7 @@ bool GyroTemperatureCalibrator::loadConfig(float newSensitivity) { bool GyroTemperatureCalibrator::saveConfig() { if (configuration.saveTemperatureCalibration(sensorId, config)) { m_Logger.info( - "Saved temperature calibration config (%0.1f%) for sensorId:%i", + "Saved temperature calibration config (%0.1f%%) for sensorId:%i", config.getCalibrationDonePercent(), sensorId ); diff --git a/src/network/manager.cpp b/src/network/manager.cpp index c27329f..70477d7 100644 --- a/src/network/manager.cpp +++ b/src/network/manager.cpp @@ -24,8 +24,7 @@ #include "GlobalVars.h" -namespace SlimeVR { -namespace Network { +namespace SlimeVR::Network { void Manager::setup() { ::WiFiNetwork::setUp(); } @@ -48,5 +47,4 @@ void Manager::update() { networkConnection.update(); } -} // namespace Network -} // namespace SlimeVR +} // namespace SlimeVR::Network diff --git a/src/network/manager.h b/src/network/manager.h index d934c71..f5a68e8 100644 --- a/src/network/manager.h +++ b/src/network/manager.h @@ -28,8 +28,7 @@ #include "wifihandler.h" #include "wifiprovisioning.h" -namespace SlimeVR { -namespace Network { +namespace SlimeVR::Network { class Manager { public: @@ -40,7 +39,6 @@ private: bool m_IsConnected = false; }; -} // namespace Network -} // namespace SlimeVR +} // namespace SlimeVR::Network #endif // SLIMEVR_NETWORK_MANAGER_H_ diff --git a/src/sensorinterface/DirectSPIInterface.cpp b/src/sensorinterface/DirectSPIInterface.cpp new file mode 100644 index 0000000..85cabdf --- /dev/null +++ b/src/sensorinterface/DirectSPIInterface.cpp @@ -0,0 +1,54 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "DirectSPIInterface.h" + +#include +#include + +namespace SlimeVR { + +DirectSPIInterface::DirectSPIInterface(SPIClass& spiClass, SPISettings spiSettings) + : m_spiClass{spiClass} + , m_spiSettings{spiSettings} {} + +bool DirectSPIInterface::init() { + m_spiClass.begin(); + return true; +} + +void DirectSPIInterface::swapIn() {} + +void DirectSPIInterface::beginTransaction(PinInterface* csPin) { + m_spiClass.beginTransaction(m_spiSettings); + csPin->digitalWrite(LOW); +} + +void DirectSPIInterface::endTransaction(PinInterface* csPin) { + csPin->digitalWrite(HIGH); + m_spiClass.endTransaction(); +} + +const SPISettings& DirectSPIInterface::getSpiSettings() { return m_spiSettings; } + +} // namespace SlimeVR diff --git a/src/sensorinterface/DirectSPIInterface.h b/src/sensorinterface/DirectSPIInterface.h new file mode 100644 index 0000000..0f25387 --- /dev/null +++ b/src/sensorinterface/DirectSPIInterface.h @@ -0,0 +1,56 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#pragma once + +#include +#include + +#include "SensorInterface.h" + +namespace SlimeVR { + +class DirectSPIInterface : public SensorInterface { +public: + DirectSPIInterface(SPIClass& spiClass, SPISettings spiSettings); + bool init() final; + void swapIn() final; + + void beginTransaction(PinInterface* csPin); + void endTransaction(PinInterface* csPin); + + [[nodiscard]] std::string toString() const final { return std::string{"SPI"}; } + + template + auto transfer(Args... args) { + return m_spiClass.transfer(args...); + } + + const SPISettings& getSpiSettings(); + +private: + SPIClass& m_spiClass; + SPISettings m_spiSettings; +}; + +} // namespace SlimeVR diff --git a/src/sensorinterface/SPIImpl.h b/src/sensorinterface/SPIImpl.h index 1985de4..d810a9e 100644 --- a/src/sensorinterface/SPIImpl.h +++ b/src/sensorinterface/SPIImpl.h @@ -28,6 +28,7 @@ #include #include "../logging/Logger.h" +#include "DirectSPIInterface.h" #include "RegisterInterface.h" #define ICM_READ_FLAG 0x80 @@ -35,10 +36,10 @@ namespace SlimeVR::Sensors { struct SPIImpl : public RegisterInterface { - SPIImpl(SPIClass& spiClass, SPISettings spiSettings, PinInterface* csPin) - : m_spiClass(spiClass) - , m_spiSettings(spiSettings) + SPIImpl(DirectSPIInterface* spi, PinInterface* csPin) + : m_spi(spi) , m_csPin(csPin) { + auto& spiSettings = spi->getSpiSettings(); m_Logger.info( "SPI settings: clock: %d, bit order: 0x%02X, data mode: 0x%02X", spiSettings._clock, @@ -47,83 +48,69 @@ struct SPIImpl : public RegisterInterface { ); csPin->pinMode(OUTPUT); csPin->digitalWrite(HIGH); - spiClass.begin(); } uint8_t readReg(uint8_t regAddr) const override { - m_spiClass.beginTransaction(m_spiSettings); - m_csPin->digitalWrite(LOW); + m_spi->beginTransaction(m_csPin); - m_spiClass.transfer(regAddr | ICM_READ_FLAG); - uint8_t buffer = m_spiClass.transfer(0); + m_spi->transfer(regAddr | ICM_READ_FLAG); + uint8_t buffer = m_spi->transfer(0); - m_csPin->digitalWrite(HIGH); - m_spiClass.endTransaction(); + m_spi->endTransaction(m_csPin); return buffer; } uint16_t readReg16(uint8_t regAddr) const override { - m_spiClass.beginTransaction(m_spiSettings); - m_csPin->digitalWrite(LOW); + m_spi->beginTransaction(m_csPin); - m_spiClass.transfer(regAddr | ICM_READ_FLAG); - uint8_t b1 = m_spiClass.transfer(0); - uint8_t b2 = m_spiClass.transfer(0); + m_spi->transfer(regAddr | ICM_READ_FLAG); + uint8_t b1 = m_spi->transfer(0); + uint8_t b2 = m_spi->transfer(0); - m_csPin->digitalWrite(HIGH); - m_spiClass.endTransaction(); + m_spi->endTransaction(m_csPin); return b2 << 8 | b1; } void writeReg(uint8_t regAddr, uint8_t value) const override { - m_spiClass.beginTransaction(m_spiSettings); - m_csPin->digitalWrite(LOW); + m_spi->beginTransaction(m_csPin); - m_spiClass.transfer(regAddr); - m_spiClass.transfer(value); + m_spi->transfer(regAddr); + m_spi->transfer(value); - m_csPin->digitalWrite(HIGH); - m_spiClass.endTransaction(); + m_spi->endTransaction(m_csPin); } void writeReg16(uint8_t regAddr, uint16_t value) const override { - m_spiClass.beginTransaction(m_spiSettings); - m_csPin->digitalWrite(LOW); + m_spi->beginTransaction(m_csPin); - m_spiClass.transfer(regAddr); - m_spiClass.transfer(value & 0xFF); - m_spiClass.transfer(value >> 8); + m_spi->transfer(regAddr); + m_spi->transfer(value & 0xFF); + m_spi->transfer(value >> 8); - m_csPin->digitalWrite(HIGH); - m_spiClass.endTransaction(); + m_spi->endTransaction(m_csPin); } void readBytes(uint8_t regAddr, uint8_t size, uint8_t* buffer) const override { - m_spiClass.beginTransaction(m_spiSettings); - m_csPin->digitalWrite(LOW); - ; + m_spi->beginTransaction(m_csPin); - m_spiClass.transfer(regAddr | ICM_READ_FLAG); + m_spi->transfer(regAddr | ICM_READ_FLAG); for (uint8_t i = 0; i < size; ++i) { - buffer[i] = m_spiClass.transfer(0); + buffer[i] = m_spi->transfer(0); } - m_csPin->digitalWrite(HIGH); - m_spiClass.endTransaction(); + m_spi->endTransaction(m_csPin); } void writeBytes(uint8_t regAddr, uint8_t size, uint8_t* buffer) const override { - m_spiClass.beginTransaction(m_spiSettings); - m_csPin->digitalWrite(LOW); + m_spi->beginTransaction(m_csPin); - m_spiClass.transfer(regAddr); + m_spi->transfer(regAddr); for (uint8_t i = 0; i < size; ++i) { - m_spiClass.transfer(buffer[i]); + m_spi->transfer(buffer[i]); } - m_csPin->digitalWrite(HIGH); - m_spiClass.endTransaction(); + m_spi->endTransaction(m_csPin); } bool hasSensorOnBus() override { @@ -135,8 +122,7 @@ struct SPIImpl : public RegisterInterface { std::string toString() const override { return std::string("SPI"); } private: - SPIClass& m_spiClass; - SPISettings m_spiSettings; + DirectSPIInterface* m_spi; PinInterface* m_csPin; SlimeVR::Logging::Logger m_Logger = SlimeVR::Logging::Logger("SPI"); }; diff --git a/src/sensorinterface/SensorInterface.cpp b/src/sensorinterface/SensorInterface.cpp new file mode 100644 index 0000000..739b400 --- /dev/null +++ b/src/sensorinterface/SensorInterface.cpp @@ -0,0 +1,30 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "SensorInterface.h" + +namespace SlimeVR { + +EmptySensorInterface EmptySensorInterface::instance; + +} diff --git a/src/sensorinterface/SensorInterface.h b/src/sensorinterface/SensorInterface.h index 4215f87..4b999f9 100644 --- a/src/sensorinterface/SensorInterface.h +++ b/src/sensorinterface/SensorInterface.h @@ -39,8 +39,9 @@ public: EmptySensorInterface(){}; bool init() override final { return true; }; void swapIn() override final{}; - [[nodiscard]] std::string toString() const final { return "None"; } + + static EmptySensorInterface instance; }; } // namespace SlimeVR diff --git a/src/sensorinterface/SensorInterfaceManager.cpp b/src/sensorinterface/SensorInterfaceManager.cpp new file mode 100644 index 0000000..baa7182 --- /dev/null +++ b/src/sensorinterface/SensorInterfaceManager.cpp @@ -0,0 +1,46 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "SensorInterfaceManager.h" + +template +bool byteCompare(const T& lhs, const T& rhs) { + const auto* lhsBytes = reinterpret_cast(&lhs); + const auto* rhsBytes = reinterpret_cast(&rhs); + + for (size_t i = 0; i < sizeof(T); i++) { + if (lhsBytes[i] < rhsBytes[i]) { + return true; + } + } + + return false; +} + +bool operator<(const SPISettings& lhs, const SPISettings& rhs) { + return byteCompare(lhs, rhs); +} + +bool operator<(const SPIClass& lhs, const SPIClass& rhs) { + return byteCompare(lhs, rhs); +} diff --git a/src/sensorinterface/SensorInterfaceManager.h b/src/sensorinterface/SensorInterfaceManager.h index 06f9fb9..843a4b5 100644 --- a/src/sensorinterface/SensorInterfaceManager.h +++ b/src/sensorinterface/SensorInterfaceManager.h @@ -23,6 +23,9 @@ #pragma once +#include +#include + #include #include #include @@ -31,8 +34,17 @@ #include "I2CPCAInterface.h" #include "I2CWireSensorInterface.h" #include "MCP23X17PinInterface.h" +#include "SPIImpl.h" #include "SensorInterface.h" #include "i2cimpl.h" +#include "sensorinterface/DirectSPIInterface.h" +#include "sensorinterface/SPIImpl.h" + +bool operator<(const SPISettings& lhs, const SPISettings& rhs); +bool operator<(const SPIClass& lhs, const SPIClass& rhs); + +bool operator<(const SPISettings& lhs, const SPISettings& rhs); +bool operator<(const SPIClass& lhs, const SPIClass& rhs); namespace SlimeVR { @@ -54,7 +66,15 @@ private: if (!cache.contains(key)) { auto ptr = new InterfaceClass(args...); - if (!ptr->init()) { + + bool success; + if constexpr (requires { ptr->init(); }) { + success = ptr->init(); + } else { + success = true; + } + + if (!success) { cache[key] = nullptr; return nullptr; } @@ -74,6 +94,9 @@ public: inline auto& mcpPinInterface() { return mcpPinInterfaces; } inline auto& i2cWireInterface() { return i2cWireInterfaces; } inline auto& pcaWireInterface() { return pcaWireInterfaces; } + inline auto& i2cImpl() { return i2cImpls; } + inline auto& directSPIInterface() { return directSPIInterfaces; } + inline auto& spiImpl() { return spiImpls; } private: SensorInterface directPinInterfaces{[](int pin) { @@ -82,6 +105,9 @@ private: SensorInterface mcpPinInterfaces; SensorInterface i2cWireInterfaces; SensorInterface pcaWireInterfaces; + SensorInterface i2cImpls; + SensorInterface directSPIInterfaces; + SensorInterface spiImpls; }; } // namespace SlimeVR diff --git a/src/sensorinterface/i2cimpl.h b/src/sensorinterface/i2cimpl.h index 5dda198..032c240 100644 --- a/src/sensorinterface/i2cimpl.h +++ b/src/sensorinterface/i2cimpl.h @@ -74,12 +74,17 @@ struct I2CImpl : public RegisterInterface { I2Cdev::writeBytes(m_devAddr, regAddr, size, buffer); } - bool hasSensorOnBus() { return I2CSCAN::hasDevOnBus(m_devAddr); } + bool hasSensorOnBus() { + // Ask twice, because we're nice like this + return I2CSCAN::hasDevOnBus(m_devAddr) || I2CSCAN::hasDevOnBus(m_devAddr); + } uint8_t getAddress() const override { return m_devAddr; } std::string toString() const { - return std::string("I2C(") + std::to_string(m_devAddr) + std::string(")"); + char buf[16]; + std::snprintf(buf, sizeof(buf), "I2C(0x%02x)", m_devAddr); + return std::string(buf); } private: diff --git a/src/sensors/ErroneousSensor.cpp b/src/sensors/ErroneousSensor.cpp index 2cddadd..7fef5a1 100644 --- a/src/sensors/ErroneousSensor.cpp +++ b/src/sensors/ErroneousSensor.cpp @@ -25,8 +25,7 @@ #include "GlobalVars.h" -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { void ErroneousSensor::motionSetup() { m_Logger.error( "IMU of type %s failed to initialize", @@ -37,5 +36,4 @@ void ErroneousSensor::motionSetup() { } SensorStatus ErroneousSensor::getSensorState() { return SensorStatus::SENSOR_ERROR; }; -} // namespace Sensors -} // namespace SlimeVR +} // namespace SlimeVR::Sensors diff --git a/src/sensors/SensorBuilder.cpp b/src/sensors/SensorBuilder.cpp index 149393c..3c20e4b 100644 --- a/src/sensors/SensorBuilder.cpp +++ b/src/sensors/SensorBuilder.cpp @@ -28,284 +28,99 @@ namespace SlimeVR::Sensors { SensorBuilder::SensorBuilder(SensorManager* sensorManager) : m_Manager(sensorManager) {} -uint8_t SensorBuilder::buildAllSensors() { - SensorInterfaceManager interfaceManager; +#define SENSOR_DESC_ENTRY(ImuType, ...) \ + activeSensorCount += sensorDescEntry(sensorID, __VA_ARGS__) ? 1 : 0; \ + sensorID++; +#define SENSOR_INFO_ENTRY(ImuID, SensorPosition) \ + m_Manager->m_Sensors[ImuID]->setSensorInfo(SensorPosition); + +uint8_t SensorBuilder::buildAllSensors() { uint8_t sensorID = 0; uint8_t activeSensorCount = 0; -#define NO_PIN nullptr -#define NO_WIRE new EmptySensorInterface -#define DIRECT_PIN(pin) interfaceManager.directPinInterface().get(pin) -#define DIRECT_WIRE(scl, sda) interfaceManager.i2cWireInterface().get(scl, sda) -#define MCP_PIN(pin) interfaceManager.mcpPinInterface().get(&m_Manager->m_MCP, pin) -#define PCA_WIRE(scl, sda, addr, ch) \ - interfaceManager.pcaWireInterface().get(scl, sda, addr, ch) -#define DIRECT_SPI(clockfreq, bitorder, datamode, CS_PIN) \ - *(new SPIImpl(SPI, SPISettings(clockfreq, bitorder, datamode), CS_PIN)) - -#define SENSOR_DESC_ENTRY(ImuType, ...) \ - { \ - do { \ - std::unique_ptr<::Sensor> sensor; \ - if constexpr (std::is_same::value) { \ - auto sensorType = findSensorType(sensorID, __VA_ARGS__); \ - if (sensorType == SensorTypeID::Unknown) { \ - m_Manager->m_Logger.error( \ - "Can't find sensor type for sensor %d", \ - sensorID \ - ); \ - break; \ - } else { \ - m_Manager->m_Logger.info( \ - "Sensor %d automatically detected with %s", \ - sensorID, \ - getIMUNameByType(sensorType) \ - ); \ - sensor \ - = buildSensorDynamically(sensorType, sensorID, __VA_ARGS__); \ - } \ - } else { \ - sensor = buildSensor(sensorID, __VA_ARGS__); \ - } \ - if (sensor->isWorking()) { \ - m_Manager->m_Logger.info("Sensor %d configured", sensorID); \ - activeSensorCount++; \ - } \ - m_Manager->m_Sensors.push_back(std::move(sensor)); \ - } while (false); \ - sensorID++; \ - } + [[maybe_unused]] const auto NO_PIN = nullptr; + [[maybe_unused]] const auto NO_WIRE = &EmptySensorInterface::instance; + [[maybe_unused]] const auto DIRECT_PIN + = [&](uint8_t pin) { return interfaceManager.directPinInterface().get(pin); }; + [[maybe_unused]] const auto DIRECT_WIRE = [&](uint8_t scl, uint8_t sda) { + return interfaceManager.i2cWireInterface().get(scl, sda); + }; + [[maybe_unused]] const auto MCP_PIN = [&](uint8_t pin) { + return interfaceManager.mcpPinInterface().get(&m_Manager->m_MCP, pin); + }; + [[maybe_unused]] const auto PCA_WIRE + = [&](uint8_t scl, uint8_t sda, uint8_t addr, uint8_t ch) { + return interfaceManager.pcaWireInterface().get(scl, sda, addr, ch); + }; + [[maybe_unused]] const auto DIRECT_SPI + = [&](uint32_t clockFreq, uint8_t bitOrder, uint8_t dataMode) { + return interfaceManager.directSPIInterface().get( + SPI, + SPISettings(clockFreq, bitOrder, dataMode) + ); + }; // Apply descriptor list and expand to entries - SENSOR_DESC_LIST; + SENSOR_DESC_LIST -#define SENSOR_INFO_ENTRY(ImuID, ...) \ - { m_Manager->m_Sensors[ImuID]->setSensorInfo(__VA_ARGS__); } - - // Apply sensor info list - SENSOR_INFO_LIST; + // Apply sensor info list and expand to entries + SENSOR_INFO_LIST return activeSensorCount; } -#define BUILD_SENSOR_ARGS \ - sensorID, imuInterface, rotation, sensorInterface, optional, intPin, extraParam - -std::unique_ptr<::Sensor> SensorBuilder::buildSensorDynamically( - SensorTypeID type, - uint8_t sensorID, - RegisterInterface& imuInterface, - float rotation, - SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam -) { +std::unique_ptr<::Sensor> +SensorBuilder::buildSensorDynamically(SensorTypeID type, SensorDefinition sensorDef) { switch (type) { // case SensorTypeID::MPU9250: - // return buildSensor(BUILD_SENSOR_ARGS); + // return buildSensor(sensorDef); // case SensorTypeID::BNO080: - // return buildSensor(BUILD_SENSOR_ARGS); + // return buildSensor(sensorDef); case SensorTypeID::BNO085: - return buildSensor(BUILD_SENSOR_ARGS); + return buildSensor(sensorDef); // case SensorTypeID::BNO055: - // return buildSensor(BUILD_SENSOR_ARGS); + // return buildSensor(sensorDef); // case SensorTypeID::MPU6050: // return buildSensor( - // BUILD_SENSOR_ARGS + // sensorDef // ); // case SensorTypeID::BNO086: - // return buildSensor(BUILD_SENSOR_ARGS); + // return buildSensor(sensorDef); // case SensorTypeID::BMI160: - // return buildSensor(BUILD_SENSOR_ARGS); + // return buildSensor(sensorDef); // case SensorTypeID::ICM20948: - // return buildSensor(BUILD_SENSOR_ARGS); + // return buildSensor(sensorDef); // case SensorTypeID::ICM42688: // return buildSensor( - // BUILD_SENSOR_ARGS + // sensorDef // ); case SensorTypeID::BMI270: - return buildSensor(BUILD_SENSOR_ARGS); + return buildSensor(sensorDef); // case SensorTypeID::LSM6DS3TRC: // return buildSensor( - // BUILD_SENSOR_ARGS + // sensorDef // ); case SensorTypeID::LSM6DSV: - return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::LSM6DSO: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); - // case SensorTypeID::LSM6DSR: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); + return buildSensor(sensorDef); + case SensorTypeID::LSM6DSO: + return buildSensor(sensorDef); + case SensorTypeID::LSM6DSR: + return buildSensor(sensorDef); case SensorTypeID::ICM45686: - return buildSensor(BUILD_SENSOR_ARGS); + return buildSensor(sensorDef); // case SensorTypeID::ICM45605: // return buildSensor( - // BUILD_SENSOR_ARGS + // sensorDef // ); default: m_Manager->m_Logger.error( "Unable to create sensor with type %s (%d)", getIMUNameByType(type), - type + static_cast(type) ); } - return std::make_unique(sensorID); -} - -std::unique_ptr<::Sensor> SensorBuilder::buildSensorDynamically( - SensorTypeID type, - uint8_t sensorID, - uint8_t imuInterface, - float rotation, - SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam -) { - switch (type) { - // case SensorTypeID::MPU9250: - // return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::BNO080: - // return buildSensor(BUILD_SENSOR_ARGS); - case SensorTypeID::BNO085: - return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::BNO055: - // return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::MPU6050: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); - // case SensorTypeID::BNO086: - // return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::BMI160: - // return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::ICM20948: - // return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::ICM42688: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); - case SensorTypeID::BMI270: - return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::LSM6DS3TRC: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); - case SensorTypeID::LSM6DSV: - return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::LSM6DSO: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); - // case SensorTypeID::LSM6DSR: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); - case SensorTypeID::ICM45686: - return buildSensor(BUILD_SENSOR_ARGS); - // case SensorTypeID::ICM45605: - // return buildSensor( - // BUILD_SENSOR_ARGS - // ); - default: - m_Manager->m_Logger.error( - "Unable to create sensor with type %s (%d)", - getIMUNameByType(type), - type - ); - } - return std::make_unique(sensorID); -} - -SensorTypeID SensorBuilder::findSensorType( - uint8_t sensorID, - uint8_t imuAddress, - float rotation, - SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam -) { - sensorInterface->init(); - sensorInterface->swapIn(); - // if (SoftFusionLSM6DS3TRC::checkPresent(sensorID, imuAddress)) - // { return SensorTypeID::LSM6DS3TRC; - // } - // if (SoftFusionICM42688::checkPresent(sensorID, imuAddress)) { - // return SensorTypeID::ICM42688; - //} - if (SoftFusionBMI270::checkPresent(sensorID, imuAddress)) { - return SensorTypeID::BMI270; - } - if (SoftFusionLSM6DSV::checkPresent(sensorID, imuAddress)) { - return SensorTypeID::LSM6DSV; - } - // if (SoftFusionLSM6DSO::checkPresent(sensorID, imuAddress)) { - // return SensorTypeID::LSM6DSO; - // } - // if (SoftFusionLSM6DSR::checkPresent(sensorID, imuAddress)) { - // return SensorTypeID::LSM6DSR; - // } - // if (SoftFusionMPU6050::checkPresent(sensorID, imuAddress)) { - // return SensorTypeID::MPU6050; - // } - if (SoftFusionICM45686::checkPresent(sensorID, imuAddress)) { - return SensorTypeID::ICM45686; - } - return BNO080Sensor::checkPresent(sensorID, imuAddress, intPin); - // if (SoftFusionICM45605::checkPresent(sensorID, imuAddress)) { - // return SensorTypeID::ICM45605; - // } - - return SensorTypeID::Unknown; -} - -SensorTypeID SensorBuilder::findSensorType( - uint8_t sensorID, - RegisterInterface& imuInterface, - float rotation, - SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam -) { - sensorInterface->init(); - sensorInterface->swapIn(); - // if (SoftFusionLSM6DS3TRC::checkPresent(sensorID, imuInterface)) - // { return SensorTypeID::LSM6DS3TRC; - // } - // if (SoftFusionICM42688::checkPresent(sensorID, imuInterface)) { - // return SensorTypeID::ICM42688; - //} - if (SoftFusionBMI270::checkPresent(sensorID, imuInterface)) { - return SensorTypeID::BMI270; - } - if (SoftFusionLSM6DSV::checkPresent(sensorID, imuInterface)) { - return SensorTypeID::LSM6DSV; - } - // if (SoftFusionLSM6DSO::checkPresent(sensorID, imuInterface)) { - // return SensorTypeID::LSM6DSO; - // } - // if (SoftFusionLSM6DSR::checkPresent(sensorID, imuInterface)) { - // return SensorTypeID::LSM6DSR; - // } - // if (SoftFusionMPU6050::checkPresent(sensorID, imuInterface)) { - // return SensorTypeID::MPU6050; - // } - if (SoftFusionICM45686::checkPresent(sensorID, imuInterface)) { - return SensorTypeID::ICM45686; - } - return BNO080Sensor::checkPresent(sensorID, sensorInterface, intPin); - // if (SoftFusionICM45605::checkPresent(sensorID, imuInterface)) { - // return SensorTypeID::ICM45605; - // } - - // return SensorTypeID::Unknown; + return std::make_unique(sensorDef.sensorID); } } // namespace SlimeVR::Sensors diff --git a/src/sensors/SensorBuilder.h b/src/sensors/SensorBuilder.h index 1746ff5..5bed41d 100644 --- a/src/sensors/SensorBuilder.h +++ b/src/sensors/SensorBuilder.h @@ -29,9 +29,11 @@ #include "EmptySensor.h" #include "ErroneousSensor.h" +#include "PinInterface.h" #include "SensorManager.h" #include "bno055sensor.h" #include "bno080sensor.h" +#include "consts.h" #include "globals.h" #include "icm20948sensor.h" #include "logging/Logger.h" @@ -39,11 +41,13 @@ #include "mpu9250sensor.h" #include "sensor.h" #include "sensorinterface/DirectPinInterface.h" +#include "sensorinterface/DirectSPIInterface.h" #include "sensorinterface/I2CPCAInterface.h" #include "sensorinterface/I2CWireSensorInterface.h" #include "sensorinterface/MCP23X17PinInterface.h" #include "sensorinterface/RegisterInterface.h" #include "sensorinterface/SPIImpl.h" +#include "sensorinterface/SensorInterface.h" #include "sensorinterface/SensorInterfaceManager.h" #include "sensorinterface/i2cimpl.h" #include "softfusion/drivers/bmi160.h" @@ -59,11 +63,11 @@ #include "softfusion/softfusionsensor.h" #ifndef PRIMARY_IMU_ADDRESS_ONE -#define PRIMARY_IMU_ADDRESS_ONE 0 +#define PRIMARY_IMU_ADDRESS_ONE false #endif #ifndef SECONDARY_IMU_ADDRESS_TWO -#define SECONDARY_IMU_ADDRESS_TWO 0 +#define SECONDARY_IMU_ADDRESS_TWO true #endif #if USE_RUNTIME_CALIBRATION @@ -96,141 +100,263 @@ using SoftFusionBMI160 = SoftFusionSensor buildSensorDynamically( - SensorTypeID type, - uint8_t sensorID, - RegisterInterface& imuInterface, - float rotation, - SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam = 0 - ); + std::unique_ptr<::Sensor> + buildSensorDynamically(SensorTypeID type, SensorDefinition sensorDef); - std::unique_ptr<::Sensor> buildSensorDynamically( - SensorTypeID type, - uint8_t sensorID, - uint8_t imuInterface, - float rotation, + template + std::optional> checkSensorPresent( + uint8_t sensorId, SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam = 0 - ); + AccessInterface accessInterface + ) { + auto* registerInterface + = getRegisterInterface(sensorId, sensorInterface, accessInterface); - SensorTypeID findSensorType( - uint8_t sensorID, - uint8_t imuAddress, - float rotation, + if (!registerInterface->hasSensorOnBus()) { + return {}; + } + + if constexpr (requires { + { + Sensor::checkPresent(*registerInterface) + } -> std::same_as; + }) { + auto type = Sensor::checkPresent(*registerInterface); + + if (type == SensorTypeID::Unknown) { + return {}; + } + + return std::make_pair(type, registerInterface); + } else { + if (!Sensor::checkPresent(*registerInterface)) { + return {}; + } + } + + return std::make_pair(Sensor::TypeID, registerInterface); + } + + template + inline std::optional> + checkSensorsPresent(uint8_t, SensorInterface*, AccessInterface) { + return std::nullopt; + } + + template + inline std::optional> + checkSensorsPresent( + uint8_t sensorId, SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam = 0 - ); + AccessInterface accessInterface + ) { + auto result + = checkSensorPresent(sensorId, sensorInterface, accessInterface); + if (result) { + return result; + } - SensorTypeID findSensorType( + return checkSensorsPresent( + sensorId, + sensorInterface, + accessInterface + ); + } + + template + RegisterInterface* getRegisterInterface( + uint8_t sensorId, + SensorInterface* interface, + AccessInterface access + ) { + if constexpr (std::is_base_of_v< + PinInterface, + std::remove_pointer_t>) { + return interfaceManager.spiImpl().get( + static_cast(interface), + access + ); + } else if constexpr (std::is_same_v) { + uint8_t addressIncrement = access ? 1 : 0; + return interfaceManager.i2cImpl().get(Sensor::Address + addressIncrement); + } else if constexpr (std::is_integral_v) { + return interfaceManager.i2cImpl().get(access); + } + + return &EmptyRegisterInterface::instance; + } + + template + std::optional> findSensorType( uint8_t sensorID, - RegisterInterface& imuInterface, - float rotation, SensorInterface* sensorInterface, - bool optional, - PinInterface* intPin, - int extraParam = 0 - ); + AccessInterface accessInterface + ) { + sensorInterface->init(); + sensorInterface->swapIn(); - template - std::unique_ptr<::Sensor> buildSensor( + return checkSensorsPresent< + AccessInterface, + // SoftFusionLSM6DS3TRC, + // SoftFusionICM42688, + SoftFusionBMI270, + SoftFusionLSM6DSV, + SoftFusionLSM6DSO, + SoftFusionLSM6DSR, + // SoftFusionMPU6050, + SoftFusionICM45686, + // SoftFusionICM45605 + BNO085Sensor>(sensorID, sensorInterface, accessInterface); + } + + template + bool sensorDescEntry( uint8_t sensorID, - RegisterInterface& imuInterface, + AccessInterface accessInterface, float rotation, SensorInterface* sensorInterface, bool optional = false, PinInterface* intPin = nullptr, int extraParam = 0 ) { + std::unique_ptr<::Sensor> sensor; + if constexpr (std::is_same::value) { + auto result = findSensorType(sensorID, sensorInterface, accessInterface); + + if (!result) { + m_Manager->m_Logger.error( + "Can't find sensor type for sensor %d", + sensorID + ); + return false; + } + + auto sensorType = result->first; + auto& regInterface = *(result->second); + + m_Manager->m_Logger.info( + "Sensor %d automatically detected with %s", + sensorID, + getIMUNameByType(sensorType) + ); + sensor = buildSensorDynamically( + sensorType, + { + sensorID, + regInterface, + rotation, + sensorInterface, + optional, + intPin, + extraParam, + } + ); + } else { + auto& regInterface = *getRegisterInterface( + sensorID, + sensorInterface, + accessInterface + ); + + sensor = buildSensor({ + sensorID, + regInterface, + rotation, + sensorInterface, + optional, + intPin, + extraParam, + }); + } + if (sensor->isWorking()) { + m_Manager->m_Logger.info("Sensor %d configured", sensorID); + } + m_Manager->m_Sensors.push_back(std::move(sensor)); + + return true; + } + + template + std::unique_ptr<::Sensor> buildSensor(SensorDefinition sensorDef) { m_Manager->m_Logger.trace( "Building IMU with: id=%d,\n\ address=%s, rotation=%f,\n\ interface=%s, int=%s, extraParam=%d, optional=%d", - sensorID, - imuInterface.toString().c_str(), - rotation, - sensorInterface->toString().c_str(), - intPin->toString().c_str(), - extraParam, - optional + sensorDef.sensorID, + sensorDef.imuInterface.toString().c_str(), + sensorDef.rotation, + sensorDef.sensorInterface->toString().c_str(), + sensorDef.intPin ? sensorDef.intPin->toString().c_str() : "None", + sensorDef.extraParam, + sensorDef.optional ); // Now start detecting and building the IMU std::unique_ptr<::Sensor> sensor; // Init I2C bus for each sensor upon startup - sensorInterface->init(); - sensorInterface->swapIn(); + sensorDef.sensorInterface->init(); + sensorDef.sensorInterface->swapIn(); - if (!imuInterface.hasSensorOnBus()) { - if (!optional) { + if (!sensorDef.imuInterface.hasSensorOnBus()) { + if (!sensorDef.optional) { m_Manager->m_Logger.error( "Mandatory sensor %d not found at address %s", - sensorID + 1, - imuInterface.toString().c_str() + sensorDef.sensorID + 1, + sensorDef.imuInterface.toString().c_str() + ); + return std::make_unique( + sensorDef.sensorID, + ImuType::TypeID ); - return std::make_unique(sensorID, ImuType::TypeID); } else { m_Manager->m_Logger.debug( "Optional sensor %d not found at address %s", - sensorID + 1, - imuInterface.toString().c_str() + sensorDef.sensorID + 1, + sensorDef.imuInterface.toString().c_str() ); - return std::make_unique(sensorID); + return std::make_unique(sensorDef.sensorID); } } m_Manager->m_Logger.trace( "Sensor %d found at address %s", - sensorID + 1, - imuInterface.toString().c_str() + sensorDef.sensorID + 1, + sensorDef.imuInterface.toString().c_str() ); sensor = std::make_unique( - sensorID, - imuInterface, - rotation, - sensorInterface, - intPin, - extraParam + sensorDef.sensorID, + sensorDef.imuInterface, + sensorDef.rotation, + sensorDef.sensorInterface, + sensorDef.intPin, + sensorDef.extraParam ); sensor->motionSetup(); return sensor; } - template - std::unique_ptr<::Sensor> buildSensor( - uint8_t sensorID, - uint8_t imuAddress, - float rotation, - SensorInterface* sensorInterface, - bool optional = false, - PinInterface* intPin = nullptr, - int extraParam = 0 - ) { - uint8_t address = imuAddress > 0 ? imuAddress : ImuType::Address + sensorID; - return buildSensor( - sensorID, - *(new I2CImpl(address)), - rotation, - sensorInterface, - optional, - intPin, - extraParam - ); - } +private: + SensorInterfaceManager interfaceManager; }; + } // namespace SlimeVR::Sensors diff --git a/src/sensors/SensorFusion.cpp b/src/sensors/SensorFusion.cpp index 4502acf..d1c7a91 100644 --- a/src/sensors/SensorFusion.cpp +++ b/src/sensors/SensorFusion.cpp @@ -1,7 +1,6 @@ #include "SensorFusion.h" -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { void SensorFusion::update6D( sensor_real_t Axyz[3], @@ -218,5 +217,4 @@ void SensorFusion::updateBiasForgettingTime(float biasForgettingTime) { } #endif -} // namespace Sensors -} // namespace SlimeVR +} // namespace SlimeVR::Sensors diff --git a/src/sensors/SensorFusion.h b/src/sensors/SensorFusion.h index 7e82164..70929e8 100644 --- a/src/sensors/SensorFusion.h +++ b/src/sensors/SensorFusion.h @@ -35,8 +35,7 @@ #include "madgwick.h" #include "mahony.h" -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { #if SENSOR_USE_VQF constexpr VQFParams DefaultVQFParams = VQFParams{ .tauAcc = 2.0f, @@ -150,7 +149,6 @@ protected: sensor_real_t linAccel_guard; // Temporary patch for some weird ESP32 bug #endif }; -} // namespace Sensors -} // namespace SlimeVR +} // namespace SlimeVR::Sensors #endif // SLIMEVR_SENSORFUSION_H diff --git a/src/sensors/SensorFusionDMP.cpp b/src/sensors/SensorFusionDMP.cpp index 4208a53..af69eab 100644 --- a/src/sensors/SensorFusionDMP.cpp +++ b/src/sensors/SensorFusionDMP.cpp @@ -1,7 +1,6 @@ #include "SensorFusionDMP.h" -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { void SensorFusionDMP::updateAcc(sensor_real_t Axyz[3]) { std::copy(Axyz, Axyz + 3, bAxyz); } @@ -96,5 +95,4 @@ Vector3 SensorFusionDMP::getLinearAccVec() { getLinearAcc(); return Vector3(linAccel[0], linAccel[1], linAccel[2]); } -} // namespace Sensors -} // namespace SlimeVR +} // namespace SlimeVR::Sensors diff --git a/src/sensors/SensorFusionDMP.h b/src/sensors/SensorFusionDMP.h index 579c382..7d999c3 100644 --- a/src/sensors/SensorFusionDMP.h +++ b/src/sensors/SensorFusionDMP.h @@ -4,8 +4,7 @@ #include "SensorFusion.h" #include "dmpmag.h" -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { class SensorFusionDMP { public: void updateQuaternion(sensor_real_t nqwxyz[4]); @@ -41,7 +40,6 @@ protected: sensor_real_t linAccel_guard; // Temporary patch for some weird ESP32 bug #endif }; -} // namespace Sensors -} // namespace SlimeVR +} // namespace SlimeVR::Sensors #endif // SLIMEVR_SENSORFUSIONDMP_H diff --git a/src/sensors/SensorFusionRestDetect.cpp b/src/sensors/SensorFusionRestDetect.cpp index 9d04d03..79a02a6 100644 --- a/src/sensors/SensorFusionRestDetect.cpp +++ b/src/sensors/SensorFusionRestDetect.cpp @@ -1,7 +1,6 @@ #include "SensorFusionRestDetect.h" -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { #if !SENSOR_FUSION_WITH_RESTDETECT void SensorFusionRestDetect::updateAcc( const sensor_real_t Axyz[3], @@ -33,5 +32,4 @@ bool SensorFusionRestDetect::getRestDetected() { return vqf.getRestDetected(); #endif } -} // namespace Sensors -} // namespace SlimeVR +} // namespace SlimeVR::Sensors diff --git a/src/sensors/SensorFusionRestDetect.h b/src/sensors/SensorFusionRestDetect.h index 5cf6230..cb3acaa 100644 --- a/src/sensors/SensorFusionRestDetect.h +++ b/src/sensors/SensorFusionRestDetect.h @@ -10,8 +10,7 @@ #define SENSOR_FUSION_WITH_RESTDETECT 0 #endif -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { #if !SENSOR_FUSION_WITH_RESTDETECT struct SensorRestDetectionParams : RestDetectionParams { SensorRestDetectionParams() @@ -60,7 +59,6 @@ protected: RestDetection restDetection; #endif }; -} // namespace Sensors -} // namespace SlimeVR +} // namespace SlimeVR::Sensors #endif // SLIMEVR_SENSORFUSIONRESTDETECT_H_ diff --git a/src/sensors/bno080sensor.h b/src/sensors/bno080sensor.h index 56afb4a..71e497f 100644 --- a/src/sensors/bno080sensor.h +++ b/src/sensors/bno080sensor.h @@ -28,6 +28,7 @@ #include #include "sensor.h" +#include "sensorinterface/RegisterInterface.h" #define FLAG_SENSOR_BNO0XX_MAG_ENABLED 1 @@ -65,27 +66,10 @@ public: void sendTempIfNeeded(); static SensorTypeID checkPresent( - uint8_t sensorID, - SlimeVR::SensorInterface* sensorInterface, - PinInterface* intPin + SlimeVR::Sensors::RegisterInterface& registerInterface ) { - // Lazy check for if BNO is present, we only check if I2C has an address here - if (I2CSCAN::hasDevOnBus(Address + sensorID)) { - return SensorTypeID::BNO085; // Assume it's 085, more precise diff will - // require talking to it - } - return SensorTypeID::Unknown; - } - - static SensorTypeID - checkPresent(uint8_t sensorID, uint8_t imuAddress, PinInterface* intPin) { - uint8_t address = imuAddress > 0 ? imuAddress : Address + sensorID; - // Lazy check for if BNO is present, we only check if I2C has an address here - if (I2CSCAN::hasDevOnBus(address)) { - return SensorTypeID::BNO085; // Assume it's 085, more precise diff will - // require talking to it - } - return SensorTypeID::Unknown; + // For BNO, just assume it's there if the sensorOnBus check succeeded + return SensorTypeID::BNO085; } protected: diff --git a/src/sensors/icm20948sensor.cpp b/src/sensors/icm20948sensor.cpp index 2d66cb3..bffcea1 100644 --- a/src/sensors/icm20948sensor.cpp +++ b/src/sensors/icm20948sensor.cpp @@ -328,7 +328,7 @@ void ICM20948Sensor::checkSensorTimeout() { if (lastData + 2000 < currenttime) { working = false; m_Logger.error( - "Sensor timeout I2C Address 0x%02x delaytime: %d ms", + "Sensor timeout I2C Address 0x%02x delaytime: %ld ms", addr, currenttime - lastData ); diff --git a/src/sensors/sensor.cpp b/src/sensors/sensor.cpp index a62e294..42723ea 100644 --- a/src/sensors/sensor.cpp +++ b/src/sensors/sensor.cpp @@ -92,8 +92,6 @@ void Sensor::resetTemperatureCalibrationState() { }; SlimeVR::Configuration::SensorConfigBits Sensor::getSensorConfigData() { - SlimeVR::Configuration::SensorConfig sensorConfig - = configuration.getSensor(sensorId); return SlimeVR::Configuration::SensorConfigBits{ .magEnabled = toggles.getToggle(SensorToggles::MagEnabled), .magSupported = isFlagSupported(SensorToggles::MagEnabled), @@ -142,6 +140,8 @@ const char* getIMUNameByType(SensorTypeID imuType) { return "ICM45686"; case SensorTypeID::ICM45605: return "ICM45605"; + case SensorTypeID::ADC_RESISTANCE: + return "ADC Resistance"; case SensorTypeID::Unknown: case SensorTypeID::Empty: return "UNKNOWN"; diff --git a/src/sensors/sensor.h b/src/sensors/sensor.h index 287382f..cfb8112 100644 --- a/src/sensors/sensor.h +++ b/src/sensors/sensor.h @@ -130,6 +130,10 @@ protected: bool working = false; bool hadData = false; uint8_t calibrationAccuracy = 0; + /** + * Apply sensor offset to align it with tracker's axises + * (Y to top of the tracker, Z to front, X to left) + */ Quat sensorOffset; bool newFusedRotation = false; diff --git a/src/sensors/sensoraddress.h b/src/sensors/sensoraddress.h index e311138..4f027d2 100644 --- a/src/sensors/sensoraddress.h +++ b/src/sensors/sensoraddress.h @@ -24,8 +24,7 @@ #pragma once #include -namespace SlimeVR { -namespace Sensors { +namespace SlimeVR::Sensors { class ImuAddress { public: ImuAddress(bool isPrimary) @@ -49,5 +48,4 @@ public: return imuDefaultAddress + 1; } }; -} // namespace Sensors -} // namespace SlimeVR \ No newline at end of file +} // namespace SlimeVR::Sensors diff --git a/src/sensors/softfusion/drivers/bmi160.h b/src/sensors/softfusion/drivers/bmi160.h index 995e834..22493af 100644 --- a/src/sensors/softfusion/drivers/bmi160.h +++ b/src/sensors/softfusion/drivers/bmi160.h @@ -76,7 +76,8 @@ struct BMI160 { struct Regs { struct WhoAmI { static constexpr uint8_t reg = 0x00; - static constexpr uint8_t value = 0xD1; + static constexpr std::array values + = {0xD1, 0xD3}; // 0xD3 for rev3 (thanks bosch) }; static constexpr uint8_t TempData = 0x20; diff --git a/src/sensors/softfusion/drivers/bmi270fw.h b/src/sensors/softfusion/drivers/bmi270fw.h index 08479c8..02c3b5e 100644 --- a/src/sensors/softfusion/drivers/bmi270fw.h +++ b/src/sensors/softfusion/drivers/bmi270fw.h @@ -39,7 +39,7 @@ namespace SlimeVR::Sensors::SoftFusion::Drivers { -const uint8_t bmi270_firmware[] = { +const uint8_t PROGMEM bmi270_firmware[] = { 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x3d, 0xb1, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x91, 0x03, 0x80, 0x2e, 0xbc, 0xb0, 0x80, 0x2e, 0xa3, 0x03, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x00, 0xb0, 0x50, 0x30, 0x21, 0x2e, 0x59, 0xf5, 0x10, 0x30, 0x21, 0x2e, @@ -628,4 +628,4 @@ const uint8_t bmi270_firmware[] = { 0x00, 0xc1 }; -} \ No newline at end of file +} diff --git a/src/sensors/softfusion/drivers/lsm6ds3trc.h b/src/sensors/softfusion/drivers/lsm6ds3trc.h index 48a654d..113cbdc 100644 --- a/src/sensors/softfusion/drivers/lsm6ds3trc.h +++ b/src/sensors/softfusion/drivers/lsm6ds3trc.h @@ -73,7 +73,8 @@ struct LSM6DS3TRC { struct Regs { struct WhoAmI { static constexpr uint8_t reg = 0x0f; - static constexpr uint8_t value = 0x6a; + static constexpr std::array values + = {0x6a, 0x69}; // 0x6a for LSM6DS3TR-C, 0x69 for LSM6DS3 }; struct Ctrl1XL { static constexpr uint8_t reg = 0x10; diff --git a/src/sensors/softfusion/softfusionsensor.h b/src/sensors/softfusion/softfusionsensor.h index 87b3e40..20b9e79 100644 --- a/src/sensors/softfusion/softfusionsensor.h +++ b/src/sensors/softfusion/softfusionsensor.h @@ -32,6 +32,7 @@ #include "../SensorFusionRestDetect.h" #include "../sensor.h" #include "GlobalVars.h" +#include "PinInterface.h" #include "motionprocessing/types.h" #include "sensors/softfusion/TempGradientCalculator.h" @@ -76,7 +77,26 @@ class SoftFusionSensor : public Sensor { bool detected() const { const auto value = m_sensor.m_RegisterInterface.readReg(SensorType::Regs::WhoAmI::reg); - if (SensorType::Regs::WhoAmI::value != value) { + if constexpr (requires { SensorType::Regs::WhoAmI::values.size(); }) { + for (auto possible : SensorType::Regs::WhoAmI::values) { + if (value == possible) { + return true; + } + } + // this assumes there are only 2 values in the array + m_Logger.error( + "Sensor not detected, expected reg 0x%02x = [0x%02x, 0x%02x] but got " + "0x%02x", + SensorType::Regs::WhoAmI::reg, + SensorType::Regs::WhoAmI::values[0], + SensorType::Regs::WhoAmI::values[1], + value + ); + return false; + } else { + if (value == SensorType::Regs::WhoAmI::value) { + return true; + } m_Logger.error( "Sensor not detected, expected reg 0x%02x = 0x%02x but got 0x%02x", SensorType::Regs::WhoAmI::reg, @@ -85,8 +105,6 @@ class SoftFusionSensor : public Sensor { ); return false; } - - return true; } void sendData() { @@ -441,24 +459,23 @@ public: RestCalibrationDetector calibrationDetector; - static bool checkPresent(uint8_t sensorID, const RegisterInterface& imuInterface) { + static bool checkPresent(const RegisterInterface& imuInterface) { I2Cdev::readTimeout = 100; auto value = imuInterface.readReg(SensorType::Regs::WhoAmI::reg); I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; - if (SensorType::Regs::WhoAmI::value == value) { - return true; - } - return false; - } - - static bool checkPresent(uint8_t sensorID, uint8_t imuAddress) { - uint8_t address = imuAddress > 0 ? imuAddress : Address + sensorID; - // Ask twice, because we're nice like this - if (!I2CSCAN::hasDevOnBus(address) && !I2CSCAN::hasDevOnBus(address)) { + if constexpr (requires { SensorType::Regs::WhoAmI::values.size(); }) { + for (auto possible : SensorType::Regs::WhoAmI::values) { + if (value == possible) { + return true; + } + } + return false; + } else { + if (value == SensorType::Regs::WhoAmI::value) { + return true; + } return false; } - const I2CImpl& i2c = I2CImpl(address); - return checkPresent(sensorID, i2c); } }; diff --git a/src/LEDManager.cpp b/src/status/LEDManager.cpp similarity index 98% rename from src/LEDManager.cpp rename to src/status/LEDManager.cpp index bfdfc1b..c8a8f64 100644 --- a/src/LEDManager.cpp +++ b/src/status/LEDManager.cpp @@ -23,8 +23,8 @@ #include "LEDManager.h" -#include "GlobalVars.h" -#include "status/Status.h" +#include "../GlobalVars.h" +#include "Status.h" namespace SlimeVR { void LEDManager::setup() { diff --git a/src/LEDManager.h b/src/status/LEDManager.h similarity index 98% rename from src/LEDManager.h rename to src/status/LEDManager.h index 80a1042..9c6b1af 100644 --- a/src/LEDManager.h +++ b/src/status/LEDManager.h @@ -25,8 +25,8 @@ #include -#include "globals.h" -#include "logging/Logger.h" +#include "../globals.h" +#include "../logging/Logger.h" #define DEFAULT_LENGTH 300 #define DEFAULT_GAP 500 diff --git a/src/status/Status.cpp b/src/status/Status.cpp index b516935..e29c61f 100644 --- a/src/status/Status.cpp +++ b/src/status/Status.cpp @@ -1,7 +1,6 @@ #include "Status.h" -namespace SlimeVR { -namespace Status { +namespace SlimeVR::Status { const char* statusToString(Status status) { switch (status) { case LOADING: @@ -18,5 +17,4 @@ const char* statusToString(Status status) { return "UNKNOWN"; } } -} // namespace Status -} // namespace SlimeVR +} // namespace SlimeVR::Status diff --git a/src/status/Status.h b/src/status/Status.h index 1f54cd0..52d3c9c 100644 --- a/src/status/Status.h +++ b/src/status/Status.h @@ -1,8 +1,7 @@ #ifndef STATUS_STATUS_H #define STATUS_STATUS_H -namespace SlimeVR { -namespace Status { +namespace SlimeVR::Status { enum Status { LOADING = 1 << 0, LOW_BATTERY = 1 << 1, @@ -12,7 +11,6 @@ enum Status { }; const char* statusToString(Status status); -} // namespace Status -} // namespace SlimeVR +} // namespace SlimeVR::Status #endif diff --git a/src/status/StatusManager.cpp b/src/status/StatusManager.cpp index 4d8919d..e8e3df7 100644 --- a/src/status/StatusManager.cpp +++ b/src/status/StatusManager.cpp @@ -1,7 +1,6 @@ #include "StatusManager.h" -namespace SlimeVR { -namespace Status { +namespace SlimeVR::Status { void StatusManager::setStatus(Status status, bool value) { if (value) { if (m_Status & status) { @@ -23,5 +22,4 @@ void StatusManager::setStatus(Status status, bool value) { } bool StatusManager::hasStatus(Status status) { return (m_Status & status) == status; } -} // namespace Status -} // namespace SlimeVR +} // namespace SlimeVR::Status diff --git a/src/status/StatusManager.h b/src/status/StatusManager.h index 06c4b09..40a13c3 100644 --- a/src/status/StatusManager.h +++ b/src/status/StatusManager.h @@ -4,8 +4,7 @@ #include "Status.h" #include "logging/Logger.h" -namespace SlimeVR { -namespace Status { +namespace SlimeVR::Status { class StatusManager { public: void setStatus(Status status, bool value); @@ -17,7 +16,6 @@ private: Logging::Logger m_Logger = Logging::Logger("StatusManager"); }; -} // namespace Status -} // namespace SlimeVR +} // namespace SlimeVR::Status #endif