SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
sensor/accelerometer/bma/SensorBMA423.hpp
Go to the documentation of this file.
1
31#pragma once
32
33#include "../../../SensorBuildOpt.h"
34#if !SENSORLIB_EXCLUDE_BMA423
35
36#include "SensorBMA4XX.hpp"
37#include "../../../bosch/bma4xx/bma423.h"
38
43{
44public:
51 static float threshold5_11ToMg(uint16_t threshold_5_11)
52 {
53 float g_value = static_cast<float>(threshold_5_11) / 2048.0f;
54 return g_value * 1000.0f; // Convert g to mg
55 }
56
62 static uint16_t mgToThreshold5_11(float threshold_mg)
63 {
64 if (threshold_mg < 0 || threshold_mg > 1000.0f) {
65 SENSORLIB_LOG_E("Threshold out of range (0-1000mg): %.1f mg, will be clamped", threshold_mg);
66 threshold_mg = (threshold_mg < 0) ? 0 : 1000.0f;
67 }
68 float g_value = threshold_mg / 1000.0f; // Convert mg to g
69 return static_cast<uint16_t>(g_value * 2048.0f + 0.5f);
70 }
71
77 static float samples50HzToMs(uint16_t samples)
78 {
79 return static_cast<float>(samples) * 20.0f; // 20ms per sample at 50Hz
80 }
81
87 static uint16_t msToSamples50Hz(float ms)
88 {
89 return static_cast<uint16_t>(ms / 20.0f + 0.5f);
90 }
91
92};
93
95{
96 struct MotionCfg {
97 uint8_t motion_feature_enabled = 0; // Any-motion and No-motion feature enable flag
98 uint16_t any_motion_threshold = 0x00AA; // 83mg
99 uint16_t any_motion_duration = 0x0005; // 100ms
100 uint16_t no_motion_threshold = 0x00AA; // 83mg
101 uint16_t no_motion_duration = 0x0032; // 1000ms
102 };
103
107 enum class BMA423_TapType {
108 DOUBLE_TAP = 0,
110 };
111
112public:
113
118 enum class Platform {
121 };
122
130 std::function<void(TapType)> onTap = nullptr;
131 std::function<void()> onStepDetected = nullptr;
132 std::function<void(uint32_t)> onStepCount = nullptr;
133 std::function<void(ActivityType)> onActivity = nullptr;
134 std::function<void()> onAnyMotion = nullptr;
135 std::function<void()> onNoMotion = nullptr;
136 std::function<void()> onTiltDetected = nullptr;
137 std::function<void(AccelerometerData &)> onDataReady = nullptr;
138 };
139
146 {
147 _remap_reg_offset = BMA423_AXES_REMAP_OFFSET;
148 _mon_cfg.any_motion_threshold = 0x00AA;
149 _mon_cfg.any_motion_duration = 0x0005;
150 _mon_cfg.no_motion_threshold = 0x00AA;
151 _mon_cfg.no_motion_duration = 0x0032;
152 _tapType = BMA423_TapType::DOUBLE_TAP;
153 }
154
159 ~SensorBMA423() = default;
160
162
175
181 void setOnTapCallback(std::function<void(TapType)> cb)
182 {
183 callbacks.onTap = std::move(cb);
184 }
185
190 void setOnStepDetectedCallback(std::function<void()> cb)
191 {
192 callbacks.onStepDetected = std::move(cb);
193 }
194
200 void setOnStepCountCallback(std::function<void(uint32_t)> cb)
201 {
202 callbacks.onStepCount = std::move(cb);
203 }
204
210 void setOnActivityCallback(std::function<void(ActivityType)> cb)
211 {
212 callbacks.onActivity = std::move(cb);
213 }
214
220 void setOnAnyMotionCallback(std::function<void(void)> cb)
221 {
222 callbacks.onAnyMotion = std::move(cb);
223 }
224
230 void setOnNoMotionCallback(std::function<void(void)> cb)
231 {
232 callbacks.onNoMotion = std::move(cb);
233 }
234
240 void setOnDataReadyCallback(std::function<void(AccelerometerData)> cb)
241 {
242 callbacks.onDataReady = std::move(cb);
243 }
244
250 void setOnTiltDetectedCallback(std::function<void(void)> cb)
251 {
252 callbacks.onTiltDetected = std::move(cb);
253 }
254
261 {
262 callbacks = cbs;
263 }
264
271 {
272 return callbacks;
273 }
274
280 {
281 return callbacks;
282 }
283
293 bool enableFeature(uint16_t feature, bool enable)
294 {
295 const uint16_t motion_mask = BMA423_ANY_MOTION | BMA423_NO_MOTION;
296
297 if ((feature & (BMA423_ANY_MOTION | BMA423_NO_MOTION)) == (BMA423_ANY_MOTION | BMA423_NO_MOTION)) {
298 SENSORLIB_LOG_E("Both any-motion and no-motion are specified, only any-motion will be enabled.");
299 feature &= (~BMA423_NO_MOTION);
300 }
301
302 if (enable && (feature & motion_mask)) {
303 uint16_t motion_to_enable = feature & motion_mask;
304 if (_mon_cfg.motion_feature_enabled != 0 &&
305 _mon_cfg.motion_feature_enabled != motion_to_enable) {
306 if (bma423_feature_enable(_mon_cfg.motion_feature_enabled, 0, dev.get()) != 0) {
307 SENSORLIB_LOG_E("Failed to disable motion feature 0x%02X",
308 _mon_cfg.motion_feature_enabled);
309 return false;
310 }
311 SENSORLIB_LOG_D("Disabled previous motion feature 0x%02X",
312 _mon_cfg.motion_feature_enabled);
313 }
314 }
315
316 if (feature & BMA423_STEP_CNTR) {
317 if (bma423_step_detector_enable(enable ? BMA4_ENABLE : BMA4_DISABLE, dev.get()) != 0) {
318 SENSORLIB_LOG_E("Failed to %s step detector", enable ? "enable" : "disable");
319 return false;
320 }
321 }
322
323 if (bma423_feature_enable(feature, enable, dev.get()) != 0) {
324 SENSORLIB_LOG_E("Failed to %s feature 0x%04X",
325 enable ? "enable" : "disable", feature);
326 return false;
327 }
328
329 if (feature & motion_mask) {
330 if (enable) {
331 _mon_cfg.motion_feature_enabled = feature & motion_mask;
332 } else {
333 if ((feature & motion_mask) == _mon_cfg.motion_feature_enabled) {
334 _mon_cfg.motion_feature_enabled = 0;
335 }
336 }
337 }
338
339 return true;
340 }
341
349 bool enableDataReady(bool enable = true, InterruptPinMap pin_map = InterruptPinMap::PIN1) override
350 {
351 return enableInterrupt(pin_map, BMA4_DATA_RDY_INT, enable);
352 }
353
365 bool enableStepCounter(bool enable, uint16_t step_counter_wm = 1, bool reset_counter = false) override
366 {
367 if (enable) {
368 if (bma423_step_counter_set_watermark(step_counter_wm, dev.get()) != 0) {
369 SENSORLIB_LOG_E("Failed to set step counter watermark");
370 return false;
371 }
372 }
373 if (reset_counter) {
374 if (bma423_reset_step_counter(dev.get()) != 0) {
375 SENSORLIB_LOG_E("Failed to reset step counter");
376 return false;
377 }
378 }
379 return enableFeature(BMA423_STEP_CNTR, enable);
380 }
381
388 bool getStepCounterWatermark(uint16_t &step_counter_wm) const
389 {
390 return bma423_step_counter_get_watermark(&step_counter_wm, dev.get()) == 0;
391 }
392
402 bool enableStepDetector(bool enable, bool interrupt_enable = false,
403 InterruptPinMap pin_map = InterruptPinMap::PIN1) override
404 {
405 if (!enableInterrupt(pin_map, BMA423_STEP_CNTR_INT, interrupt_enable)) {
406 return false;
407 }
408 return enableFeature(BMA423_STEP_CNTR, enable);
409 }
410
419 bool enableTiltDetector(bool enable, bool interrupt_enable = false,
420 InterruptPinMap pin_map = InterruptPinMap::PIN1) override
421 {
422 if (!enableInterrupt(pin_map, BMA423_TILT_INT, interrupt_enable)) {
423 return false;
424 }
425 return enableFeature(BMA423_TILT, enable);
426 }
427
438 {
439 return bma423_select_platform(static_cast<uint8_t>(platform), dev.get()) == 0;
440 }
441
450 bool enableTapDetector(bool enable, bool interrupt_enable = false,
451 InterruptPinMap pin_map = InterruptPinMap::PIN1) override
452 {
453 if (!enableInterrupt(pin_map, BMA423_WAKEUP_INT, interrupt_enable)) {
454 return false;
455 }
456 return enableFeature(BMA423_WAKEUP, enable);
457 }
458
468 {
469 switch (tap) {
471 _tapType = BMA423_TapType::DOUBLE_TAP;
472 break;
474 _tapType = BMA423_TapType::SINGLE_TAP;
475 break;
476 default:
477 break;
478 }
479 return bma423_tap_selection(static_cast<uint8_t>(_tapType), dev.get()) == 0;
480 }
481
490 bool enableActivityRecognition(bool enable, bool interrupt_enable = false,
491 InterruptPinMap pin_map = InterruptPinMap::PIN1) override
492 {
493 if (!enableInterrupt(pin_map, BMA423_ACTIVITY_INT, interrupt_enable)) {
494 return false;
495 }
496 return enableFeature(BMA423_ACTIVITY, enable);
497 }
498
509 bool enableAnyMotionDetection(const MotionAxesConfig &cfg, bool enable,
510 bool interrupt_enable = false,
511 InterruptPinMap pin_map = InterruptPinMap::PIN1) override
512 {
513 uint16_t axis = 0;
514
515 if (cfg.x_axis == 0 && cfg.y_axis == 0 && cfg.z_axis == 0 && enable) {
516 SENSORLIB_LOG_E("No motion detection axis enabled");
517 return false;
518 }
519
520 if (cfg.x_axis) axis |= BMA423_X_AXIS_EN;
521 if (cfg.y_axis) axis |= BMA423_Y_AXIS_EN;
522 if (cfg.z_axis) axis |= BMA423_Z_AXIS_EN;
523
524 if (bma423_anymotion_enable_axis(axis, dev.get()) != 0) {
525 SENSORLIB_LOG_E("Failed to configure any-motion axes");
526 return false;
527 }
528
529 if (!enableInterrupt(pin_map, BMA423_ANY_NO_MOTION_INT, interrupt_enable)) {
530 return false;
531 }
532
533 if (!configMotion(true, _mon_cfg.any_motion_threshold, _mon_cfg.any_motion_duration)) {
534 return false;
535 }
536
537 return enableFeature(BMA423_ANY_MOTION, enable);
538 }
539
550 bool enableNoMotionDetection(const MotionAxesConfig &cfg, bool enable,
551 bool interrupt_enable = false,
552 InterruptPinMap pin_map = InterruptPinMap::PIN1) override
553 {
554 uint16_t axis = 0;
555
556 if (cfg.x_axis == 0 && cfg.y_axis == 0 && cfg.z_axis == 0 && enable) {
557 SENSORLIB_LOG_E("No motion detection axis enabled");
558 return false;
559 }
560
561 if (cfg.x_axis) axis |= BMA423_X_AXIS_EN;
562 if (cfg.y_axis) axis |= BMA423_Y_AXIS_EN;
563 if (cfg.z_axis) axis |= BMA423_Z_AXIS_EN;
564
565 if (bma423_anymotion_enable_axis(axis, dev.get()) != 0) {
566 SENSORLIB_LOG_E("Failed to configure no-motion axes");
567 return false;
568 }
569
570 if (!enableInterrupt(pin_map, BMA423_ANY_NO_MOTION_INT, interrupt_enable)) {
571 return false;
572 }
573
574 if (!configMotion(false, _mon_cfg.no_motion_threshold, _mon_cfg.no_motion_duration)) {
575 return false;
576 }
577
578 return enableFeature(BMA423_NO_MOTION, enable);
579 }
580
595 bool configNoMotion(uint16_t threshold, uint16_t duration) override
596 {
597 _mon_cfg.no_motion_duration = duration;
598 _mon_cfg.no_motion_threshold = threshold;
599 return true;
600 }
601
616 bool configAnyMotion(uint16_t threshold, uint16_t duration) override
617 {
618 _mon_cfg.any_motion_duration = duration;
619 _mon_cfg.any_motion_threshold = threshold;
620 return true;
621 }
622
637 bool configMotion(bool any_motion, uint16_t threshold, uint16_t duration) override
638 {
639 struct bma423_anymotion_config any_motion_cfg;
640 any_motion_cfg.threshold = threshold;
641 any_motion_cfg.duration = duration;
642 any_motion_cfg.nomotion_sel = any_motion ? 0 : 1;
643
644 if (any_motion) {
645 _mon_cfg.any_motion_threshold = threshold;
646 _mon_cfg.any_motion_duration = duration;
647 } else {
648 _mon_cfg.no_motion_threshold = threshold;
649 _mon_cfg.no_motion_duration = duration;
650 }
651
652 SENSORLIB_LOG_D("BMA423 motion config (raw): threshold=0x%04X, duration=%u, type: %s",
653 threshold, duration,
654 any_motion ? "Any-motion" : "No-motion");
655
656 return bma423_set_any_motion_config(&any_motion_cfg, dev.get()) == 0;
657 }
658
671 bool getMotionConfig(uint16_t &threshold, uint16_t &duration, bool &no_motion)
672 {
673 struct bma423_anymotion_config any_motion;
674 if (bma423_get_any_motion_config(&any_motion, dev.get()) != 0) {
675 SENSORLIB_LOG_E("Failed to read BMA423 motion configuration");
676 return false;
677 }
678 threshold = any_motion.threshold;
679 duration = any_motion.duration;
680 no_motion = any_motion.nomotion_sel;
681 return true;
682 }
683
684
691 uint32_t getStepCount()
692 {
693 uint32_t step_count = 0;
694 if (bma423_step_counter_output(&step_count, dev.get()) != 0) {
695 SENSORLIB_LOG_E("Failed to read step count");
696 return 0;
697 }
698 return step_count;
699 }
700
707 {
708 return bma423_reset_step_counter(dev.get()) == 0;
709 }
710
718 {
719 uint8_t activity_type = 0;
720 if (bma423_activity_output(&activity_type, dev.get()) != 0) {
721 SENSORLIB_LOG_E("Failed to get activity type");
723 }
724 return static_cast<ActivityType>(activity_type);
725 }
726
732 {
733 return _mon_cfg.motion_feature_enabled;
734 }
735
740 {
741 return _mon_cfg.motion_feature_enabled == BMA423_ANY_MOTION;
742 }
743
747 bool isNoMotionEnabled() const
748 {
749 return _mon_cfg.motion_feature_enabled == BMA423_NO_MOTION;
750 }
751
759 void update() override
760 {
761 if (bma4_read_int_status(&_status, dev.get()) != 0) {
762 SENSORLIB_LOG_E("Failed to read interrupt status");
763 return;
764 }
765
766 if (_status == 0) {
767 return;
768 }
769
770 if ((_status & BMA423_WAKEUP_INT) && callbacks.onTap) {
771 callbacks.onTap(_tapType == BMA423_TapType::DOUBLE_TAP ? TapType::DOUBLE_TAP : TapType::SINGLE_TAP);
772 }
773
774 if ((_status & BMA423_STEP_CNTR_INT) && callbacks.onStepDetected) {
778 }
779 }
780
781 if ((_status & BMA423_ACTIVITY_INT) && callbacks.onActivity) {
783 }
784
785 if ((_status & BMA423_ANY_NO_MOTION_INT)) {
786 if (_mon_cfg.motion_feature_enabled == BMA423_ANY_MOTION && callbacks.onAnyMotion) {
788 } else if (_mon_cfg.motion_feature_enabled == BMA423_NO_MOTION && callbacks.onNoMotion) {
790 }
791 }
792
793 if ((_status & BMA4_ACCEL_DATA_RDY_INT) && callbacks.onDataReady) {
795 if (readData(data)) {
797 }
798 }
799
800 if ((_status & BMA423_TILT_INT) && callbacks.onTiltDetected) {
802 }
803
804 _status = 0;
805 }
806
807private:
813 bool boschInitImpl() override
814 {
815 int8_t rslt = bma423_init(dev.get());
816 if ( rslt != 0 ) {
817 SENSORLIB_LOG_E("bma423_init failed with code %d", rslt);
818 return false;
819 }
820
821 dev->config_size = BMA423_CONFIG_FILE_SIZE;
822
823 rslt = bma423_write_config_file(dev.get());
824 if (rslt != 0) {
825 SENSORLIB_LOG_E("bma423_write_config_file failed with code %d", rslt);
826 return false;
827 }
828 return true;
829 }
830protected:
832 uint16_t _status;
833 MotionCfg _mon_cfg;
834 BMA423_TapType _tapType;
835};
836
837#endif
InterruptPinMap
Enumeration of interrupt pin mapping options.
@ PIN1
Interrupt pin 1.
#define SENSORLIB_LOG_E(...)
#define SENSORLIB_LOG_D(...)
Utility class for BMA423-specific conversions.
static float samples50HzToMs(uint16_t samples)
Convert duration from 50Hz samples to milliseconds.
static uint16_t msToSamples50Hz(float ms)
Convert duration from milliseconds to 50Hz samples.
static float threshold5_11ToMg(uint16_t threshold_5_11)
Converts threshold values ​​in 5.11g format to milligrams (mg)
static uint16_t mgToThreshold5_11(float threshold_mg)
Convert threshold from milli-g to 5.11g format.
void setOnStepDetectedCallback(std::function< void()> cb)
Set the callback for step detection events.
void setOnDataReadyCallback(std::function< void(AccelerometerData)> cb)
Set the callback for data ready events.
bool configNoMotion(uint16_t threshold, uint16_t duration) override
Configure no-motion detection using raw register values.
SensorBMA423()
Constructor for the SensorBMA423 class.
void setOnTapCallback(std::function< void(TapType)> cb)
Set the callback for tap events.
~SensorBMA423()=default
Destructor for the SensorBMA423 class.
bool getStepCounterWatermark(uint16_t &step_counter_wm) const
Get the current step counter watermark.
bool isNoMotionEnabled() const
Check if no-motion detection is enabled.
bool configAnyMotion(uint16_t threshold, uint16_t duration) override
Configure any-motion detection using raw register values.
void setOnActivityCallback(std::function< void(ActivityType)> cb)
Set the callback for activity events.
bool enableDataReady(bool enable=true, InterruptPinMap pin_map=InterruptPinMap::PIN1) override
Enable data ready interrupt.
bool resetStepCounter()
Reset the step counter.
bool enableNoMotionDetection(const MotionAxesConfig &cfg, bool enable, bool interrupt_enable=false, InterruptPinMap pin_map=InterruptPinMap::PIN1) override
Enable or disable no-motion detection.
bool selectTapType(TapType tap)
Select tap detection tap type.
bool enableStepCounter(bool enable, uint16_t step_counter_wm=1, bool reset_counter=false) override
Enable or disable step counter.
void setCallbacks(const EventCallbacks &cbs)
Set all callbacks at once.
void setOnNoMotionCallback(std::function< void(void)> cb)
Set the callback for no-motion events.
const EventCallbacks & getCallbacks() const
Get the current callbacks (const version)
uint8_t getEnabledMotionFeature() const
Get which motion detection feature is currently enabled.
bool selectPlatform(Platform platform)
Select the platform for the sensor.
bool enableTapDetector(bool enable, bool interrupt_enable=false, InterruptPinMap pin_map=InterruptPinMap::PIN1) override
Enable or disable tap detection.
bool getMotionConfig(uint16_t &threshold, uint16_t &duration, bool &no_motion)
Get current no-motion/any-motion detection configuration for BMA423.
bool isAnyMotionEnabled() const
Check if any-motion detection is enabled.
EventCallbacks & getCallbacks()
Get the current callbacks.
Platform
Select the platform for the sensor.
bool enableActivityRecognition(bool enable, bool interrupt_enable=false, InterruptPinMap pin_map=InterruptPinMap::PIN1) override
Enable or disable activity recognition.
bool configMotion(bool any_motion, uint16_t threshold, uint16_t duration) override
Configure motion detection parameters using raw register values.
bool enableStepDetector(bool enable, bool interrupt_enable=false, InterruptPinMap pin_map=InterruptPinMap::PIN1) override
Enable or disable step detector.
bool enableAnyMotionDetection(const MotionAxesConfig &cfg, bool enable, bool interrupt_enable=false, InterruptPinMap pin_map=InterruptPinMap::PIN1) override
Enable or disable any-motion detection.
void setOnStepCountCallback(std::function< void(uint32_t)> cb)
Set the callback for step count events.
BMA4XXCapability::Capability getCapabilities() const override
Get supported capabilities.
void update() override
Update sensor state and process interrupts.
void setOnTiltDetectedCallback(std::function< void(void)> cb)
Set the callback for tilt detection events.
ActivityType getActivityType()
Get the current activity type.
bool enableFeature(uint16_t feature, bool enable)
Enable or disable a specific feature.
bool enableTiltDetector(bool enable, bool interrupt_enable=false, InterruptPinMap pin_map=InterruptPinMap::PIN1) override
Enable or disable tilt detection.
void setOnAnyMotionCallback(std::function< void(void)> cb)
Set the any-motion callback for motion events.
uint32_t getStepCount()
Get the current step count.
bool enableInterrupt(InterruptPinMap pin_map, uint16_t interrupt_sources, bool enable)
Enable or disable specific interrupt sources on a pin.
bool readData(AccelerometerData &data) override
Get the accelerometer data.
std::unique_ptr< struct bma4_dev > dev
ActivityType
Activity detection type.
TapType
Tap detection type.
Structure representing accelerometer data.
std::function< void()> onTiltDetected
Callback for tilt detection.
std::function< void()> onStepDetected
Callback for step detection events.
std::function< void(TapType)> onTap
Callback for tap detection events.
std::function< void()> onAnyMotion
Callback for any-motion detection.
std::function< void(AccelerometerData &)> onDataReady
Callback for new accelerometer data.
std::function< void()> onNoMotion
Callback for no-motion detection.
std::function< void(ActivityType)> onActivity
Callback for activity recognition events.
std::function< void(uint32_t)> onStepCount
Callback for step count updates.
uint8_t z_axis
Enable motion detection on Z-axis (1=enabled, 0=disabled)
uint8_t y_axis
Enable motion detection on Y-axis (1=enabled, 0=disabled)
uint8_t x_axis
Enable motion detection on X-axis (1=enabled, 0=disabled)