[P120] Add ADXL345 Accelerometer plugin

This commit is contained in:
Ton Huisman
2021-11-02 21:43:33 +01:00
parent 5abee46683
commit 42b8b25c7a
3 changed files with 647 additions and 102 deletions
+196 -48
View File
@@ -3,14 +3,20 @@
#ifdef USES_P120
// #######################################################################################################
// ################################ Plugin 120: AAccelerometer - ADXL345 #################################
// ################################ Plugin 120: Accelerometer - ADXL345 ##################################
// #######################################################################################################
/**
* Plugin to support the ADXL345 Accelerometer, using the Sparkfun ADXL345 Arduino library
*/
/** Changelog:
*
* 2021-11-02, tonhuisman: Add Axis offsets for calibration
* 2021-11-01, tonhuisman: Add event processing (pseudo-interrupts), improve settings
* 2021-10-31, tonhuisman: Add Single/Double-tap and Freefall detection
* 2021-10-30, tonhuisman: Add required settings for sensor, read X/Y/Z values
* Add get2BitFromUL/set2BitToUL/get3BitFromUL/set3BitToUL support functions
* 2021-10-29, tonhuisman: Initial plugin created from template, using Sparkfun ADXL345 library
* https://github.com/sparkfun/SparkFun_ADXL345_Arduino_Library
*
@@ -26,14 +32,6 @@
# define PLUGIN_VALUENAME2_120 "Y"
# define PLUGIN_VALUENAME3_120 "Z"
// Make accessing specific parameters more readable in the code
// # define P120_I2C_OR_SPI PCONFIG(0)
# define P120_I2C_ADDR PCONFIG(1) // Kept (1) from template
// # define P120_AVERAGE_BUFFER PCONFIG(2)
// # define P120_FREQUENCY PCONFIG(3)
// # define P120_FREQUENCY_10 0 // 10x per second
// # define P120_FREQUENCY_50 1 // 50x per second
boolean Plugin_120(uint8_t function, struct EventStruct *event, String& string)
{
boolean success = false;
@@ -85,8 +83,28 @@ boolean Plugin_120(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_SET_DEFAULTS:
{
P120_I2C_ADDR = 0x53; // Default I2C Address
// P120_AVERAGE_BUFFER = 10; // Average averaging ;-)
P120_I2C_ADDR = 0x53; // Default I2C Address
P120_AVERAGE_BUFFER = 10; // Average averaging ;-)
uint32_t flags = 0ul;
set2BitToUL(flags, P120_FLAGS1_RANGE, P120_RANGE_16G); // Default to 16g range for highest resolution
bitSet(flags, P120_FLAGS1_ACTIVITY_X); // Detect activity on all axes
bitSet(flags, P120_FLAGS1_ACTIVITY_Y);
bitSet(flags, P120_FLAGS1_ACTIVITY_Z);
set8BitToUL(flags, P120_FLAGS1_ACTIVITY_TRESHOLD, P120_DEFAULT_ACTIVITY_TRESHOLD);
set8BitToUL(flags, P120_FLAGS1_INACTIVITY_TRESHOLD, P120_DEFAULT_INACTIVITY_TRESHOLD);
P120_CONFIG_FLAGS1 = flags;
flags = 0ul;
set8BitToUL(flags, P120_FLAGS2_TAP_TRESHOLD, P120_DEFAULT_TAP_TRESHOLD);
set8BitToUL(flags, P120_FLAGS2_TAP_DURATION, P120_DEFAULT_TAP_DURATION);
set8BitToUL(flags, P120_FLAGS2_DBL_TAP_LATENCY, P120_DEFAULT_DBL_TAP_LATENCY);
set8BitToUL(flags, P120_FLAGS2_DBL_TAP_WINDOW, P120_DEFAULT_DBL_TAP_WINDOW);
P120_CONFIG_FLAGS2 = flags;
flags = 0ul;
set8BitToUL(flags, P120_FLAGS3_FREEFALL_TRESHOLD, P120_DEFAULT_FREEFALL_TRESHOLD);
set8BitToUL(flags, P120_FLAGS3_FREEFALL_DURATION, P120_DEFAULT_FREEFALL_DURATION);
P120_CONFIG_FLAGS3 = flags;
// No decimals plausible, as the outputs from the sensor are of type int
for (uint8_t i = 0; i < VARS_PER_TASK; ++i) {
@@ -100,16 +118,111 @@ boolean Plugin_120(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_LOAD:
{
// addFormCheckBox(F("Read 'raw' values from Gyro"), F("p120_rawData"), P120_RAW_DATA == 1);
// Range
{
const __FlashStringHelper *rangeOptions[] = {
F("2g"),
F("4g"),
F("8g"),
F("16g (default)") };
int rangeValues[] = { P120_RANGE_2G, P120_RANGE_4G, P120_RANGE_8G, P120_RANGE_16G };
addFormSelector(F("Range"), F("p120_range"), 4, rangeOptions, rangeValues,
get2BitFromUL(P120_CONFIG_FLAGS1, P120_FLAGS1_RANGE));
}
// addFormNumericBox(F("Averaging buffer size"), F("p120_average_buf"), P120_AVERAGE_BUFFER, 1, 100);
// addUnit(F("1..100"));
// Axis selection
{
addFormCheckBox(F("X-axis activity sensing"), F("p120_activity_x"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_X) == 1);
addFormCheckBox(F("Y-axis activity sensing"), F("p120_activity_y"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Y) == 1);
addFormCheckBox(F("Z-axis activity sensing"), F("p120_activity_z"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Z) == 1);
addFormNumericBox(F("Activity treshold"), F("p120_activity_treshold"),
get8BitFromUL(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_TRESHOLD), 1, 255);
addUnit(F("1..255 * 62.5 mg"));
addFormNumericBox(F("In-activity treshold"), F("p120_inactivity_treshold"),
get8BitFromUL(P120_CONFIG_FLAGS1, P120_FLAGS1_INACTIVITY_TRESHOLD), 1, 255);
addUnit(F("1..255 * 62.5 mg"));
}
// const __FlashStringHelper *frequencyOptions[] = {
// F("10x per second"),
// F("50x per second") };
// int frequencyValues[] = { P120_FREQUENCY_10, P120_FREQUENCY_50 };
// addFormSelector(F("Measuring frequency"), F("p120_frequency"), 2, frequencyOptions, frequencyValues, P120_FREQUENCY);
// Activity logging and send events for (in)activity
{
addFormCheckBox(F("Enable (in)activity events"), F("p120_send_activity"),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_SEND_ACTIVITY) == 1);
addFormCheckBox(F("Log sensor activity (INFO)"), F("p120_log_activity"),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_LOG_ACTIVITY) == 1);
addFormCheckBox(F("Events with raw measurements"), F("p120_raw_measurement"),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_EVENT_RAW_VALUES) == 1);
}
// Tap detection
{
addFormSubHeader(F("Tap detection"));
addFormCheckBox(F("X-axis"), F("p120_tap_x"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_X) == 1);
addFormCheckBox(F("Y-axis"), F("p120_tap_y"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Y) == 1);
addFormCheckBox(F("Z-axis"), F("p120_tap_z"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Z) == 1);
addFormNote(F("Also enables taskname#Tapped event."));
addFormNumericBox(F("Tap treshold"), F("p120_tap_treshold"),
get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_TAP_TRESHOLD), 1, 255);
addUnit(F("1..255 * 62.5 mg"));
addFormNumericBox(F("Tap duration"), F("p120_tap_duration"),
get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_TAP_DURATION), 1, 255);
addUnit(F("1..255 * 625 &micro;s"));
}
// Double-tap detection
{
addFormCheckBox(F("Enable double-tap detection"), F("p120_dbl_tap"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_DBL_TAP) == 1);
addFormNote(F("Also enables taskname#DoubleTapped event."));
addFormNumericBox(F("Double-tap latency"), F("p120_dbl_tap_latency"),
get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_DBL_TAP_LATENCY), 1, 255);
addUnit(F("1..255 * 1.25 ms"));
addFormNumericBox(F("Double-tap window"), F("p120_dbl_tap_window"),
get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_DBL_TAP_WINDOW), 1, 255);
addUnit(F("1..255 * 1.25 ms"));
}
// Free-fall detection
{
addFormSubHeader(F("Free-fall detection"));
addFormCheckBox(F("Enable free-fall detection"), F("p120_free_fall"), bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_FREE_FALL) == 1);
addFormNote(F("Also enables taskname#FreeFall event."));
addFormNumericBox(F("Free-fall treshold"), F("p120_free_fall_treshold"),
get8BitFromUL(P120_CONFIG_FLAGS3, P120_FLAGS3_FREEFALL_TRESHOLD), 1, 255);
addUnit(F("1..255 * 62.5 mg"));
addFormNumericBox(F("Free-fall duration"), F("p120_free_fall_duration"),
get8BitFromUL(P120_CONFIG_FLAGS3, P120_FLAGS3_FREEFALL_DURATION), 1, 255);
addUnit(F("1..255 * 625 &micro;s"));
}
// Axis Offsets (calibration)
{
addFormSubHeader(F("Axis calibration"));
addFormNumericBox(F("X-Axis offset"), F("p120_offset_x"),
get8BitFromUL(P120_CONFIG_FLAGS4, P120_FLAGS4_OFFSET_X) - 0x80, -127, 127);
addUnit(F("-127..127"));
addFormNumericBox(F("Y-Axis offset"), F("p120_offset_y"),
get8BitFromUL(P120_CONFIG_FLAGS4, P120_FLAGS4_OFFSET_Y) - 0x80, -127, 127);
addUnit(F("-127..127"));
addFormNumericBox(F("Z-Axis offset"), F("p120_offset_z"),
get8BitFromUL(P120_CONFIG_FLAGS4, P120_FLAGS4_OFFSET_Z) - 0x80, -127, 127);
addUnit(F("-127..127"));
}
// Data retrieval options
{
addFormSubHeader(F("Data retrieval"));
addFormNumericBox(F("Averaging buffer size"), F("p120_average_buf"), P120_AVERAGE_BUFFER, 1, 100);
addUnit(F("1..100"));
const __FlashStringHelper *frequencyOptions[] = {
F("10x per second"),
F("50x per second") };
int frequencyValues[] = { P120_FREQUENCY_10, P120_FREQUENCY_50 };
addFormSelector(F("Measuring frequency"), F("p120_frequency"), 2, frequencyOptions, frequencyValues, P120_FREQUENCY);
addFormNote(F("Values X/Y/Z are updated 1x per second, Controller updates &amp; Value-events are based on 'Interval' setting."));
}
success = true;
break;
@@ -117,10 +230,45 @@ boolean Plugin_120(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_WEBFORM_SAVE:
{
P120_I2C_ADDR = getFormItemInt(F("i2c_addr"));
P120_I2C_ADDR = getFormItemInt(F("i2c_addr"));
// P120_RAW_DATA = isFormItemChecked(F("p120_rawData")) ? 1 : 0;
// P120_AVERAGE_BUFFER = getFormItemInt(F("p120_average_buf"));
// P120_FREQUENCY = getFormItemInt(F("p120_frequency"));
P120_AVERAGE_BUFFER = getFormItemInt(F("p120_average_buf"));
P120_FREQUENCY = getFormItemInt(F("p120_frequency"));
uint32_t flags = 0ul;
set2BitToUL(flags, P120_FLAGS1_RANGE, getFormItemInt(F("p120_range")));
bitWrite(flags, P120_FLAGS1_ACTIVITY_X, isFormItemChecked(F("p120_activity_x")));
bitWrite(flags, P120_FLAGS1_ACTIVITY_Y, isFormItemChecked(F("p120_activity_y")));
bitWrite(flags, P120_FLAGS1_ACTIVITY_Z, isFormItemChecked(F("p120_activity_z")));
bitWrite(flags, P120_FLAGS1_TAP_X, isFormItemChecked(F("p120_tap_x")));
bitWrite(flags, P120_FLAGS1_TAP_Y, isFormItemChecked(F("p120_tap_y")));
bitWrite(flags, P120_FLAGS1_TAP_Z, isFormItemChecked(F("p120_tap_z")));
bitWrite(flags, P120_FLAGS1_DBL_TAP, isFormItemChecked(F("p120_dbl_tap")));
bitWrite(flags, P120_FLAGS1_FREE_FALL, isFormItemChecked(F("p120_free_fall")));
bitWrite(flags, P120_FLAGS1_SEND_ACTIVITY, isFormItemChecked(F("p120_send_activity")));
bitWrite(flags, P120_FLAGS1_LOG_ACTIVITY, isFormItemChecked(F("p120_log_activity")));
bitWrite(flags, P120_FLAGS1_EVENT_RAW_VALUES, isFormItemChecked(F("p120_raw_measurement")));
set8BitToUL(flags, P120_FLAGS1_ACTIVITY_TRESHOLD, getFormItemInt(F("p120_activity_treshold")));
set8BitToUL(flags, P120_FLAGS1_INACTIVITY_TRESHOLD, getFormItemInt(F("p120_inactivity_treshold")));
P120_CONFIG_FLAGS1 = flags;
flags = 0ul;
set8BitToUL(flags, P120_FLAGS2_TAP_TRESHOLD, getFormItemInt(F("p120_tap_treshold")));
set8BitToUL(flags, P120_FLAGS2_TAP_DURATION, getFormItemInt(F("p120_tap_duration")));
set8BitToUL(flags, P120_FLAGS2_DBL_TAP_LATENCY, getFormItemInt(F("p120_dbl_tap_latency")));
set8BitToUL(flags, P120_FLAGS2_DBL_TAP_WINDOW, getFormItemInt(F("p120_dbl_tap_window")));
P120_CONFIG_FLAGS2 = flags;
flags = 0ul;
set8BitToUL(flags, P120_FLAGS3_FREEFALL_TRESHOLD, getFormItemInt(F("p120_free_fall_treshold")));
set8BitToUL(flags, P120_FLAGS3_FREEFALL_DURATION, getFormItemInt(F("p120_free_fall_duration")));
P120_CONFIG_FLAGS3 = flags;
flags = 0ul;
set8BitToUL(flags, P120_FLAGS4_OFFSET_X, getFormItemInt(F("p120_offset_x")) + 0x80);
set8BitToUL(flags, P120_FLAGS4_OFFSET_Y, getFormItemInt(F("p120_offset_y")) + 0x80);
set8BitToUL(flags, P120_FLAGS4_OFFSET_Z, getFormItemInt(F("p120_offset_z")) + 0x80);
P120_CONFIG_FLAGS4 = flags;
success = true;
break;
@@ -128,42 +276,42 @@ boolean Plugin_120(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_INIT:
{
// initPluginTaskData(event->TaskIndex, new (std::nothrow) P120_data_struct(P120_I2C_ADDR, P120_RAW_DATA, P120_AVERAGE_BUFFER));
// P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
initPluginTaskData(event->TaskIndex, new (std::nothrow) P120_data_struct(P120_I2C_ADDR, P120_AVERAGE_BUFFER));
P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
// if (nullptr != P120_data) {
// success = true;
// }
if (nullptr != P120_data) {
success = true;
}
break;
}
case PLUGIN_READ:
{
// P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
// if (nullptr != P120_data) {
// success = P120_data->initialized();
// }
if (nullptr != P120_data) {
success = P120_data->initialized();
}
break;
}
case PLUGIN_ONCE_A_SECOND:
{
// P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
// if (nullptr != P120_data) {
// int X, Y, Z;
if (nullptr != P120_data) {
int X, Y, Z;
// if (P120_data->read_data(X, Y, Z)) {
// UserVar[event->BaseVarIndex] = X;
// UserVar[event->BaseVarIndex + 1] = Y;
// UserVar[event->BaseVarIndex + 2] = Z;
if (P120_data->read_data(event, X, Y, Z)) {
UserVar[event->BaseVarIndex] = X;
UserVar[event->BaseVarIndex + 1] = Y;
UserVar[event->BaseVarIndex + 2] = Z;
// success = true;
// }
// }
success = true;
}
}
break;
}
@@ -171,14 +319,14 @@ boolean Plugin_120(uint8_t function, struct EventStruct *event, String& string)
case PLUGIN_TEN_PER_SECOND:
case PLUGIN_FIFTY_PER_SECOND:
{
// if (((function == PLUGIN_TEN_PER_SECOND) && (P120_FREQUENCY == P120_FREQUENCY_10)) ||
// ((function == PLUGIN_FIFTY_PER_SECOND) && (P120_FREQUENCY == P120_FREQUENCY_50))) {
// P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
if (((function == PLUGIN_TEN_PER_SECOND) && (P120_FREQUENCY == P120_FREQUENCY_10)) ||
((function == PLUGIN_FIFTY_PER_SECOND) && (P120_FREQUENCY == P120_FREQUENCY_50))) {
P120_data_struct *P120_data = static_cast<P120_data_struct *>(getPluginTaskData(event->TaskIndex));
// if (nullptr != P120_data) {
// success = P120_data->read_sensor();
// }
// }
if (nullptr != P120_data) {
success = P120_data->read_sensor(event);
}
}
break;
}
+357 -45
View File
@@ -2,58 +2,370 @@
#ifdef USES_P120
// **************************************************************************/
// Constructor
// **************************************************************************/
P120_data_struct::P120_data_struct(
uint8_t i2c_addr,
int threshold)
: _threshold(threshold), initialized(false)
uint8_t i2c_addr,
uint8_t aSize
)
: _i2c_addr(i2c_addr), _aSize(aSize)
{
// Call begin() immediately, or else _i2cPort in lipo object is still a nullptr
// lipo.begin();
// _threshold = constrain(_threshold, 1, 32);
if (_aSize == 0) { _aSize = 1; }
_XA.resize(_aSize, 0);
_YA.resize(_aSize, 0);
_ZA.resize(_aSize, 0);
_aUsed = 0;
_aMax = 0;
}
// bool P120_data_struct::begin()
// {
// quickStart() - Restarts the MAX1704x to allow it to re-"guess" the
// parameters that go into its SoC algorithms. Calling this in your setup()
// usually results in more accurate SoC readings.
// Output: 0 on success, positive integer on fail.
// **************************************************************************/
// Destructor
// **************************************************************************/
P120_data_struct::~P120_data_struct() {
if (initialized()) {
delete adxl345;
adxl345 = nullptr;
}
}
// FIXME TD-er: Looks like begin() and/or quickStart() may not return expected values.
// const bool success = lipo.begin() && (lipo.quickStart() == 0);
// lipo.begin();
// lipo.quickStart();
// const bool success = true;
// **************************************************************************/
// Initialize sensor and read data from ADXL345
// **************************************************************************/
bool P120_data_struct::read_sensor(struct EventStruct *event) {
# if PLUGIN_120_DEBUG
String log;
# endif // if PLUGIN_120_DEBUG
// if (success) {
// switch (_device) {
// case MAX1704X_MAX17043:
// case MAX1704X_MAX17044:
// break;
// case MAX1704X_MAX17048:
// case MAX1704X_MAX17049:
// lipo.enableSOCAlert();
// break;
// }
// lipo.setThreshold(_threshold);
// initialized = true;
// return true;
// }
// initialized = false;
// return false;
// }
if (!initialized()) {
init_sensor(event);
# if PLUGIN_120_DEBUG
// bool P120_data_struct::read(bool clearAlert)
// {
// voltage = lipo.getVoltage();
// soc = lipo.getSOC();
// changeRate = lipo.getChangeRate();
// return lipo.getAlert(clearAlert);
// }
if (loglevelActiveFor(LOG_LEVEL_DEBUG) &&
log.reserve(55)) {
log = F("ADXL345: i2caddress: 0x");
log += String(_i2cAddress, HEX);
log += F(", initialized: ");
log += String(initialized() ? F("true") : F("false"));
log += F(", ID=0x");
log += String(adxl345->getDevID(), HEX);
addLog(LOG_LEVEL_DEBUG, log);
}
# endif // if PLUGIN_120_DEBUG
}
// void P120_data_struct::clearAlert() {
// alert = false;
// lipo.clearAlert();
// }
if (initialized()) {
_x = 0; _y = 0; _z = 0;
adxl345->readAccel(&_x, &_y, &_z);
_XA[_aUsed] = _x;
_YA[_aUsed] = _y;
_ZA[_aUsed] = _z;
_aUsed++;
if ((_aMax < _aUsed) && (_aUsed < _aSize)) {
_aMax = _aUsed;
}
if (_aUsed == _aSize) {
_aUsed = 0;
}
# if PLUGIN_120_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG) &&
log.reserve(40)) {
log = F("ADXL345: X: ");
log += _x;
log += F(", Y: ");
log += _y;
log += F(", Z: ");
log += _z;
addLog(LOG_LEVEL_DEBUG, log);
}
# endif // if PLUGIN_120_DEBUG
sensor_check_interrupt(event); // Process any interrupt
return true;
}
return false;
}
// **************************************************************************/
// Average the measurements and return the results
// **************************************************************************/
bool P120_data_struct::read_data(struct EventStruct *event, int& X, int& Y, int& Z) {
X = 0;
Y = 0;
Z = 0;
if (initialized()) {
for (uint8_t n = 0; n <= _aMax; n++) {
X += _XA[n];
Y += _YA[n];
Z += _ZA[n];
}
X /= _aMax; // Average available measurements
Y /= _aMax;
Z /= _aMax;
# if PLUGIN_120_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log;
if (log.reserve(40)) {
log = F("ADXL345: averages, X: ");
log += X;
log += F(", Y: ");
log += Y;
log += F(", Z: ");
log += Z;
addLog(LOG_LEVEL_DEBUG, log);
}
}
# endif // if PLUGIN_120_DEBUG
}
return initialized();
}
// **************************************************************************/
// Initialize ADXL345
// **************************************************************************/
bool P120_data_struct::init_sensor(struct EventStruct *event) {
adxl345 = new (std::nothrow) ADXL345(_i2c_addr);
if (initialized()) {
uint8_t act = 0, freeFall = 0, singleTap = 0, doubleTap = 0;
addLog(LOG_LEVEL_INFO, F("ADXL345: Initializing sensor..."));
adxl345->powerOn();
adxl345->setRangeSetting(2 ^ (get2BitFromUL(P120_CONFIG_FLAGS1, P120_FLAGS1_RANGE) + 1)); // Range is stored in 2 bits, only 4 possible
// options
// Activity triggering
// Inactivity triggering, same axis
adxl345->setActivityXYZ(bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_X),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Y),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Z));
adxl345->setInactivityXYZ(bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_X),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Y),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Z));
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_X) ||
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Y) ||
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Z)) {
adxl345->setActivityThreshold(get8BitFromUL(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_TRESHOLD));
adxl345->setInactivityThreshold(get8BitFromUL(P120_CONFIG_FLAGS1, P120_FLAGS1_INACTIVITY_TRESHOLD));
act = 1;
}
// Axis Offsets
adxl345->setAxisOffset(get8BitFromUL(P120_CONFIG_FLAGS4, P120_FLAGS4_OFFSET_X) - 0x80,
get8BitFromUL(P120_CONFIG_FLAGS4, P120_FLAGS4_OFFSET_Y) - 0x80,
get8BitFromUL(P120_CONFIG_FLAGS4, P120_FLAGS4_OFFSET_Z) - 0x80);
// Tap triggering
adxl345->setTapDetectionOnXYZ(bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_X),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Y),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Z));
// Tap detection
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_X) ||
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Y) ||
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Z)) {
adxl345->setTapThreshold(get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_TAP_TRESHOLD));
adxl345->setTapDuration(get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_TAP_DURATION));
singleTap = 1;
// Double-tap detection
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_DBL_TAP)) {
adxl345->setDoubleTapLatency(get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_DBL_TAP_LATENCY));
adxl345->setDoubleTapWindow(get8BitFromUL(P120_CONFIG_FLAGS2, P120_FLAGS2_DBL_TAP_WINDOW));
doubleTap = 1;
} else {
adxl345->setDoubleTapLatency(0); // Off
adxl345->setDoubleTapWindow(0);
}
} else {
adxl345->setTapThreshold(0); // Off
adxl345->setTapDuration(0);
adxl345->setDoubleTapLatency(0);
adxl345->setDoubleTapWindow(0);
}
// Free-fall detection
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_FREE_FALL)) {
adxl345->setFreeFallThreshold(get8BitFromUL(P120_CONFIG_FLAGS3, P120_FLAGS3_FREEFALL_TRESHOLD));
adxl345->setFreeFallDuration(get8BitFromUL(P120_CONFIG_FLAGS3, P120_FLAGS3_FREEFALL_DURATION));
freeFall = 1;
} else {
adxl345->setFreeFallThreshold(0);
adxl345->setFreeFallDuration(0);
}
// Enable interrupts
adxl345->setImportantInterruptMapping(singleTap, doubleTap, freeFall, act, act);
adxl345->ActivityINT(act);
adxl345->InactivityINT(act);
adxl345->singleTapINT(singleTap);
adxl345->doubleTapINT(doubleTap);
adxl345->FreeFallINT(freeFall);
addLog(LOG_LEVEL_INFO, F("ADXL345: Initialization done."));
} else {
addLog(LOG_LEVEL_ERROR, F("ADXL345: Initialization of sensor failed."));
return false;
}
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log;
if (log.reserve(25)) {
log = F("ADXL345: Address: 0x");
log += String(_i2c_addr, HEX);
addLog(LOG_LEVEL_DEBUG, log);
}
}
return true;
}
/* Look for Interrupts and Triggered Action */
void P120_data_struct::sensor_check_interrupt(struct EventStruct *event) {
// getInterruptSource clears all triggered actions after returning value
// Do not call again until you need to recheck for triggered actions
uint8_t interrupts = adxl345->getInterruptSource();
String payload;
payload.reserve(30);
// Free Fall Detection
if (adxl345->triggered(interrupts, ADXL345_FREE_FALL)) {
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_LOG_ACTIVITY)) {
addLog(LOG_LEVEL_INFO, F("ADXL345: *** FREE FALL ***"));
}
payload = F("FreeFall=");
appendPayloadXYZ(event, payload, 1u, 1u, 1u); // Use all values
send_task_event(event, payload);
}
// Inactivity
if (adxl345->triggered(interrupts, ADXL345_INACTIVITY) &&
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_SEND_ACTIVITY)) {
if (!inactivityTriggered) {
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_LOG_ACTIVITY)) {
addLog(LOG_LEVEL_INFO, F("ADXL345: *** INACTIVITY ***"));
}
payload = F("Inactivity=");
appendPayloadXYZ(event, payload,
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_X),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Y),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Z));
send_task_event(event, payload);
}
inactivityTriggered = true;
activityTriggered = false;
}
// Activity
if (adxl345->triggered(interrupts, ADXL345_ACTIVITY) &&
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_SEND_ACTIVITY)) {
if (!activityTriggered) {
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_LOG_ACTIVITY)) {
addLog(LOG_LEVEL_INFO, F("ADXL345: *** ACTIVITY ***"));
}
payload = F("Activity=");
appendPayloadXYZ(event, payload,
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_X),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Y),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_ACTIVITY_Z));
send_task_event(event, payload);
}
activityTriggered = true;
inactivityTriggered = false;
}
// Double Tap Detection
// Tap Detection
if (adxl345->triggered(interrupts, ADXL345_DOUBLE_TAP) ||
(adxl345->triggered(interrupts, ADXL345_SINGLE_TAP))) {
if (adxl345->triggered(interrupts, ADXL345_SINGLE_TAP)) {
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_LOG_ACTIVITY)) {
addLog(LOG_LEVEL_INFO, F("ADXL345: *** TAP ***"));
}
payload = F("Tapped");
}
if (adxl345->triggered(interrupts, ADXL345_DOUBLE_TAP)) { // tonhuisman: Double-tap overrides single-tap event
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_LOG_ACTIVITY)) { // This is on purpose and as intended!
addLog(LOG_LEVEL_INFO, F("ADXL345: *** DOUBLE TAP ***"));
}
payload = F("DoubleTapped");
}
payload += '=';
appendPayloadXYZ(event, payload,
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_X),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Y),
bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_TAP_Z));
send_task_event(event, payload);
}
}
// *******************************************************************
// Append X, Y and Z arguments where configured
// *******************************************************************
void P120_data_struct::appendPayloadXYZ(struct EventStruct *event, String& payload,
uint8_t useX,
uint8_t useY,
uint8_t useZ) {
if (useX == 1) {
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_EVENT_RAW_VALUES)) {
payload += _x;
} else {
payload += formatUserVarNoCheck(event, 0);
}
} else {
payload += 0;
}
payload += ',';
if (useY == 1) {
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_EVENT_RAW_VALUES)) {
payload += _y;
} else {
payload += formatUserVarNoCheck(event, 1);
}
} else {
payload += 0;
}
payload += ',';
if (useZ == 1) {
if (bitRead(P120_CONFIG_FLAGS1, P120_FLAGS1_EVENT_RAW_VALUES)) {
payload += _z;
} else {
payload += formatUserVarNoCheck(event, 2);
}
} else {
payload += 0;
}
}
// *******************************************************************
// Send out an event for the current event, aith provided payload
// *******************************************************************
void P120_data_struct::send_task_event(struct EventStruct *event,
String & eventPayload) {
if (Settings.UseRules &&
!eventPayload.isEmpty()) {
String RuleEvent;
RuleEvent += getTaskDeviceName(event->TaskIndex);
RuleEvent += '#';
RuleEvent += eventPayload;
eventQueue.addMove(std::move(RuleEvent));
}
}
#endif // ifdef USES_P120
+94 -9
View File
@@ -4,28 +4,113 @@
#include "../../_Plugin_Helper.h"
#ifdef USES_P120
# include "../Globals/EventQueue.h"
# include <Wire.h> // Needed for I2C
// https://github.com/sparkfun/SparkFun_ADXL345_Arduino_Library
# include <SparkFun_ADXL345.h>
# define PLUGIN_120_DEBUG false // Set to true to enable debug out log
// Make accessing specific parameters more readable in the code
// # define P120_I2C_OR_SPI PCONFIG(0)
# define P120_I2C_ADDR PCONFIG(1) // Kept (1) from template
# define P120_AVERAGE_BUFFER PCONFIG(2)
# define P120_FREQUENCY PCONFIG(3)
# define P120_FREQUENCY_10 0 // 10x per second
# define P120_FREQUENCY_50 1 // 50x per second
// First set of configuration flags
# define P120_CONFIG_FLAGS1 PCONFIG_LONG(0)
# define P120_FLAGS1_RANGE 0 // Range setting, size 2 bits
# define P120_RANGE_2G 0
# define P120_RANGE_4G 1
# define P120_RANGE_8G 2
# define P120_RANGE_16G 3
# define P120_FLAGS1_ACTIVITY_X 2 // X-axis activity setting
# define P120_FLAGS1_ACTIVITY_Y 3 // Y-axis activity setting
# define P120_FLAGS1_ACTIVITY_Z 4 // Z-axis activity setting
# define P120_FLAGS1_TAP_X 5 // X-axis tap detection
# define P120_FLAGS1_TAP_Y 6 // Y-axis tap detection
# define P120_FLAGS1_TAP_Z 7 // Z-axis tap detection
# define P120_FLAGS1_DBL_TAP 8 // Double-tap detection
# define P120_FLAGS1_FREE_FALL 9 // Free-fall detection
# define P120_FLAGS1_SEND_ACTIVITY 10 // Send (in)activity events
# define P120_FLAGS1_LOG_ACTIVITY 11 // Log activity at INFO level
# define P120_FLAGS1_EVENT_RAW_VALUES 12 // Events use direct raw sensorvalues
# define P120_FLAGS1_ACTIVITY_TRESHOLD 16 // Activity treshold, 8 bits
# define P120_DEFAULT_ACTIVITY_TRESHOLD 75 // Default treshold: 75 * 62.5 mg = 4.6875 g
# define P120_FLAGS1_INACTIVITY_TRESHOLD 24 // Inactivity treshold, 8 bits
# define P120_DEFAULT_INACTIVITY_TRESHOLD 75 // Default treshold: 75 * 62.5 mg = 4.6875 g
// Second set of configuration flags, Tap settings
# define P120_CONFIG_FLAGS2 PCONFIG_LONG(1)
# define P120_FLAGS2_TAP_TRESHOLD 0
# define P120_DEFAULT_TAP_TRESHOLD 50 // Default treshold: 50 * 62.5 mg = 3.125 g
# define P120_FLAGS2_TAP_DURATION 8
# define P120_DEFAULT_TAP_DURATION 15 // Default duration: 15 * 625 us = .09375 sec
# define P120_FLAGS2_DBL_TAP_LATENCY 16
# define P120_DEFAULT_DBL_TAP_LATENCY 80 // Default latency: 80 * 1.25 ms = .01 sec
# define P120_FLAGS2_DBL_TAP_WINDOW 24
# define P120_DEFAULT_DBL_TAP_WINDOW 200 // Default window: 200 * 1.25 ms = .25 sec
// Third set of configuration flags, Free-fall settings
# define P120_CONFIG_FLAGS3 PCONFIG_LONG(2)
# define P120_FLAGS3_FREEFALL_TRESHOLD 0
# define P120_DEFAULT_FREEFALL_TRESHOLD 7 // Default treshold: 7 * 62.5 mg = 0.4375 g
# define P120_FLAGS3_FREEFALL_DURATION 8
# define P120_DEFAULT_FREEFALL_DURATION 30 // Default duration: 30 * 5 ms = .15 sec
// Fourth set of configuration flags, Axis Offset settings
# define P120_CONFIG_FLAGS4 PCONFIG_LONG(3)
# define P120_FLAGS4_OFFSET_X 0
# define P120_FLAGS4_OFFSET_Y 8
# define P120_FLAGS4_OFFSET_Z 16
struct P120_data_struct : public PluginTaskData_base {
public:
P120_data_struct(uint8_t i2c_addr,
int threshold);
P120_data_struct(uint8_t i2c_addr,
uint8_t aSize);
~P120_data_struct();
// bool begin();
bool read_sensor(struct EventStruct *event);
bool read_data(struct EventStruct *event,
int & X,
int & Y,
int & Z);
// // Perform read and return true when an alert has been high
// bool read(bool clearAlert);
bool initialized() {
return adxl345 != nullptr;
}
// void clearAlert();
private:
int _threshold;
bool init_sensor(struct EventStruct *event);
void sensor_check_interrupt(struct EventStruct *event);
void appendPayloadXYZ(struct EventStruct *event,
String & payload,
uint8_t useX,
uint8_t useY,
uint8_t useZ);
void send_task_event(struct EventStruct *event,
String & eventPayload);
bool initialized = false;
ADXL345 *adxl345 = nullptr;
uint8_t _i2c_addr;
uint8_t _aSize;
std::vector<int>_XA;
std::vector<int>_YA;
std::vector<int>_ZA;
uint8_t _aUsed = 0;
uint8_t _aMax = 0;
int _x = 0, _y = 0, _z = 0; // Last measured values
bool activityTriggered = false;
bool inactivityTriggered = false;
};
#endif // ifdef USES_P120
#endif // ifndef PLUGINSTRUCTS_P120_DATA_STRUCT_H