# SPDX-FileCopyrightText: Copyright (c) 2023 Jose D. Montoya
#
# SPDX-License-Identifier: MIT
"""
`bma220_slope`
================================================================================
BMA220 Slope Bosch Circuitpython Driver library
* Author(s): Jose D. Montoya
"""
# pylint: disable=useless-parent-delegation,no-name-in-module
from micropython import const
from adafruit_register.i2c_bit import RWBit, ROBit
from adafruit_register.i2c_bits import RWBits
from bma220.bma220 import BMA220
try:
from typing import Tuple
except ImportError:
pass
__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/jposada202020/CircuitPython_BMA220.git"
_CONF = const(0x1A)
_SLOPE_INFO = const(0x12)
_SLOPE_INFO2 = const(0x16)
_INTERRUPTS = const(0x18)
# Slope Axis Enabled Values
SLOPE_X_DISABLED = const(0b0)
SLOPE_X_ENABLED = const(0b1)
SLOPE_Y_DISABLED = const(0b0)
SLOPE_Y_ENABLED = const(0b1)
SLOPE_Z_DISABLED = const(0b0)
SLOPE_Z_ENABLED = const(0b1)
slope_axis_enabled_values = (SLOPE_X_DISABLED, SLOPE_X_ENABLED)
# Filter Values
FILTER_DISABLED = const(0b0)
FILTER_ENABLED = const(0b1)
filter_values = (FILTER_DISABLED, FILTER_ENABLED)
SLOPE_SIGN_POSITIVE = const(0b00)
SLOPE_SIGN_NEGATIVE = const(0b01)
slope_sign_values = (SLOPE_SIGN_POSITIVE, SLOPE_SIGN_NEGATIVE)
[docs]class BMA220_SLOPE(BMA220):
"""
The any-motion detection uses the slope between two successive acceleration signals to detect
changes in motion. It generates an interrupt when a preset threshold slope_th is exceeded. The
threshold can be configured between 0 and the maximum acceleration value corresponding to
the selected measurement range. The time difference between the successive acceleration
signals depends on the bandwidth of the configurable low pass filter and corresponds roughly to
1/(2*bandwidth) (Δt=1/(2*bw)).
In order to suppress failure signals, the interrupt is only generated if a certain number
:attr:`slope_duration` of consecutive slope data points is above the slope threshold
:attr:`slope_threshold`.
If the same number of data points falls below the threshold, the interrupt is reset.
The criteria for any-motion detection are fulfilled and the slope interrupt is
generated if any of the enabled channels exceeds the threshold :attr:`slope_threshold`
for :attr:`slope_threshold` consecutive times. As soon as all the enabled channels fall
or stay below this threshold for :attr:`slope_threshold` consecutive times the interrupt
is reset unless interrupt signal is latched.
The any-motion interrupt logic sends out the signals of the axis that has triggered
the interrupt (:attr:`slope_interrupt_info`) and the signal of motion
direction (:attr:`slope_sign`).
When serial interface is active, any-motion detection logic is enabled if any of
the any-motion enable register bits is set. To disable the any-motion interrupt,
clear all the axis enable bits.
In the dedicated wake-up mode (6.1), all three axes are enabled for any-motion detection
whether the individual axis enable bits are set or not.
"""
_slope_z_enabled = RWBit(_CONF, 3)
_slope_y_enabled = RWBit(_CONF, 4)
_slope_x_enabled = RWBit(_CONF, 5)
_slope_int = ROBit(_INTERRUPTS, 0)
_slope_threshold = RWBits(4, _SLOPE_INFO, 2)
_slope_duration = RWBits(2, _SLOPE_INFO, 0)
_slope_filter_enable = RWBit(_SLOPE_INFO, 6)
_slope_sign = RWBit(_SLOPE_INFO2, 0)
_slope_z_first = RWBit(_SLOPE_INFO2, 1)
_slope_y_first = RWBit(_SLOPE_INFO2, 2)
_slope_x_first = RWBit(_SLOPE_INFO2, 3)
def __init__(self, i2c_bus):
super().__init__(i2c_bus)
@property
def slope_x_enabled(self) -> str:
"""
Sensor slope_x_enabled
+-------------------------------------------+-----------------+
| Mode | Value |
+===========================================+=================+
| :py:const:`bma220_slope.SLOPE_X_DISABLED` | :py:const:`0b0` |
+-------------------------------------------+-----------------+
| :py:const:`bma220_slope.SLOPE_X_ENABLED` | :py:const:`0b1` |
+-------------------------------------------+-----------------+
"""
values = (
"SLOPE_X_DISABLED",
"SLOPE_X_ENABLED",
)
return values[self._slope_x_enabled]
@slope_x_enabled.setter
def slope_x_enabled(self, value: int) -> None:
if value not in slope_axis_enabled_values:
raise ValueError("Value must be a valid slope_x_enabled setting")
self._slope_x_enabled = value
@property
def slope_y_enabled(self) -> str:
"""
Sensor y_enabled
+-------------------------------------------+-----------------+
| Mode | Value |
+===========================================+=================+
| :py:const:`bma220_slope.SLOPE_Y_DISABLED` | :py:const:`0b0` |
+-------------------------------------------+-----------------+
| :py:const:`bma220_slope.SLOPE_Y_ENABLED` | :py:const:`0b1` |
+-------------------------------------------+-----------------+
"""
values = (
"SLOPE_Y_DISABLED",
"SLOPE_Y_ENABLED",
)
return values[self._slope_y_enabled]
@slope_y_enabled.setter
def slope_y_enabled(self, value: int) -> None:
if value not in slope_axis_enabled_values:
raise ValueError("Value must be a valid slope_y_enabled setting")
self._slope_y_enabled = value
@property
def slope_z_enabled(self) -> str:
"""
Sensor slope_z_enabled
+-------------------------------------------+-----------------+
| Mode | Value |
+===========================================+=================+
| :py:const:`bma220_slope.SLOPE_Z_DISABLED` | :py:const:`0b0` |
+-------------------------------------------+-----------------+
| :py:const:`bma220_slope.SLOPE_Z_ENABLED` | :py:const:`0b1` |
+-------------------------------------------+-----------------+
"""
values = (
"SLOPE_Z_DISABLED",
"SLOPE_Z_ENABLED",
)
return values[self._slope_z_enabled]
@slope_z_enabled.setter
def slope_z_enabled(self, value: int) -> None:
if value not in slope_axis_enabled_values:
raise ValueError("Value must be a valid slope_z_enabled setting")
self._slope_z_enabled = value
@property
def slope_threshold(self) -> int:
"""
the interrupt is only generated if a certain number :attr:`slope_duration`
of consecutive slope data points is above the slope threshold :attr:`slope_threshold`.
1 LSB threshold is 1 LSB of acc_data
"""
return self._slope_threshold
@slope_threshold.setter
def slope_threshold(self, value: int) -> None:
if value not in range(0, 16, 1):
raise ValueError("Value must be a valid slope_threshold setting")
self._slope_threshold = value
@property
def slope_interrupt(self) -> bool:
"""
Sensor slope_z_enabled
"""
return self._slope_int
@property
def slope_duration(self) -> int:
"""
the interrupt is only generated if a certain number :attr:`slope_duration`
of consecutive slope data points is above the slope threshold :attr:`slope_threshold`.
define the number of consecutive slope data points above :attr:`slope_threshold`
which are required to set the interrupt:
+-------------------------------------------+------------------+
| Mode | Value |
+===========================================+==================+
| :py:const:`bma220_slope.SLOPE_DURATION_1` | :py:const:`0b00` |
+-------------------------------------------+------------------+
| :py:const:`bma220_slope.SLOPE_DURATION_2` | :py:const:`0b01` |
+-------------------------------------------+------------------+
| :py:const:`bma220_slope.SLOPE_DURATION_3` | :py:const:`0b10` |
+-------------------------------------------+------------------+
| :py:const:`bma220_slope.SLOPE_DURATION_4` | :py:const:`0b11` |
+-------------------------------------------+------------------+
"""
values = (
"SLOPE_DURATION_1",
"SLOPE_DURATION_2",
"SLOPE_DURATION_3",
"SLOPE_DURATION_4",
)
return values[self._slope_duration]
@slope_duration.setter
def slope_duration(self, value: int) -> None:
if value not in (0, 1, 2, 3):
raise ValueError("Value must be a valid slope_duration setting")
self._slope_duration = value
@property
def slope_filter(self) -> int:
"""
Defines whether filtered or unfiltered acceleration data should be used
(evaluated)
+------------------------------------------+-----------------+
| Mode | Value |
+==========================================+=================+
| :py:const:`bma220_slope.FILTER_DISABLED` | :py:const:`0b0` |
+------------------------------------------+-----------------+
| :py:const:`bma220_slope.FILTER_ENABLED` | :py:const:`0b1` |
+------------------------------------------+-----------------+
"""
values = ("FILTER_DISABLED", "FILTER_ENABLED")
return values[self._slope_filter_enable]
@slope_filter.setter
def slope_filter(self, value: int) -> None:
if value not in (0, 1):
raise ValueError("Value must be a valid slope_filter setting")
self._slope_filter_enable = value
@property
def slope_interrupt_info(self) -> Tuple[bool, bool, bool]:
"""
Sensor slope_z_enabled
"""
return self._slope_x_first, self._slope_y_first, self._slope_z_first
@property
def slope_sign(self) -> str:
"""
Sensor slope_sign
+----------------------------------------------+------------------+
| Mode | Value |
+==============================================+==================+
| :py:const:`bma220_slope.SLOPE_SIGN_POSITIVE` | :py:const:`0b00` |
+----------------------------------------------+------------------+
| :py:const:`bma220_slope.SLOPE_SIGN_NEGATIVE` | :py:const:`0b01` |
+----------------------------------------------+------------------+
"""
values = (
"SLOPE_SIGN_POSITIVE",
"SLOPE_SIGN_NEGATIVE",
)
return values[self._slope_sign]
@slope_sign.setter
def slope_sign(self, value: int) -> None:
if value not in slope_sign_values:
raise ValueError("Value must be a valid slope_sign setting")
self._slope_sign = value