nanohub: isl29034: fix build error when DEBUG not defined
am: 3fac23e689
Change-Id: Id4dc90f12aa03176fc411964054f7cfe7737354a
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..1e0d8c8
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,3 @@
+subdirs = [
+ "lib",
+]
diff --git a/contexthubhal/Android.mk b/contexthubhal/Android.mk
index 1600e1b..be27d47 100644
--- a/contexthubhal/Android.mk
+++ b/contexthubhal/Android.mk
@@ -14,7 +14,10 @@
# Include target-specific files.
LOCAL_SRC_FILES += nanohubhal_default.cpp
-LOCAL_STATIC_LIBRARIES += libnanohub_common
+LOCAL_HEADER_LIBRARIES := \
+ libhardware_headers \
+ libnanohub_common_headers \
+ libutils_headers
LOCAL_MODULE := context_hub.default
LOCAL_MODULE_TAGS := optional
diff --git a/contexthubhal/nanohubhal.cpp b/contexthubhal/nanohubhal.cpp
index fa3c5f8..21b6374 100644
--- a/contexthubhal/nanohubhal.cpp
+++ b/contexthubhal/nanohubhal.cpp
@@ -26,8 +26,8 @@
#include <hardware/context_hub.h>
#include <hardware/hardware.h>
-#include <utils/Log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <nanohub/nanohub.h>
@@ -139,8 +139,11 @@
discard_inotify_evt(pfd);
while (access(NANOHUB_LOCK_FILE, F_OK) == 0) {
ALOGW("Nanohub is locked; blocking read thread");
- int ret = poll(&pfd, 1, 5000);
- if (ret > 0) {
+ int ret = TEMP_FAILURE_RETRY(poll(&pfd, 1, 5000));
+ if (ret < 0) {
+ ALOGE("poll returned with an error: %s", strerror(errno));
+ break;
+ } else if (ret > 0) {
discard_inotify_evt(pfd);
}
}
@@ -226,10 +229,12 @@
setDebugFlags(property_get_int32("persist.nanohub.debug", 0));
while (1) {
- int ret = poll(myFds, numPollFds, -1);
- if (ret <= 0) {
- ALOGD("poll returned with an error: %s", strerror(errno));
+ int ret = TEMP_FAILURE_RETRY(poll(myFds, numPollFds, -1));
+ if (ret == 0)
continue;
+ else if (ret < 0) {
+ ALOGE("poll returned with an error: %s", strerror(errno));
+ break;
}
if (hasInotify) {
diff --git a/contexthubhal/nanohubhal_default.cpp b/contexthubhal/nanohubhal_default.cpp
index 2645c61..fb5231e 100644
--- a/contexthubhal/nanohubhal_default.cpp
+++ b/contexthubhal/nanohubhal_default.cpp
@@ -18,7 +18,7 @@
#include <hardware/context_hub.h>
#include "nanohub_perdevice.h"
#include "nanohubhal.h"
-#include <utils/Log.h>
+#include <log/log.h>
namespace android {
diff --git a/contexthubhal/system_comms.cpp b/contexthubhal/system_comms.cpp
index c4e9b62..4a67a66 100644
--- a/contexthubhal/system_comms.cpp
+++ b/contexthubhal/system_comms.cpp
@@ -24,7 +24,7 @@
#include <vector>
-#include <utils/Log.h>
+#include <log/log.h>
#include <endian.h>
diff --git a/contexthubhal/test/main.cpp b/contexthubhal/test/main.cpp
index fe21e99..f8399ce 100644
--- a/contexthubhal/test/main.cpp
+++ b/contexthubhal/test/main.cpp
@@ -16,8 +16,8 @@
#include <signal.h>
#include <unistd.h>
+#include <log/log.h>
#include <sys/endian.h>
-#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/context_hub.h>
diff --git a/firmware/app/chre/common/chre_app.c b/firmware/app/chre/common/chre_app.c
index aae23cf..55bbdf2 100644
--- a/firmware/app/chre/common/chre_app.c
+++ b/firmware/app/chre/common/chre_app.c
@@ -176,7 +176,7 @@
return;
si = eOsSensorFind(SENSOR_TYPE(evt), 0, &sensorHandle);
- if (si) {
+ if (si && eOsSensorGetReqRate(sensorHandle)) {
switch (si->numAxis) {
case NUM_AXIS_EMBEDDED:
processEmbeddedData(eventData, sensorHandle, SENSOR_TYPE(evt));
diff --git a/firmware/lib/builtins/Android.mk b/firmware/lib/builtins/Android.mk
index aa8663c..b43bdb2 100644
--- a/firmware/lib/builtins/Android.mk
+++ b/firmware/lib/builtins/Android.mk
@@ -31,6 +31,10 @@
umoddi3.c \
aeabi_f2d.c \
aeabi_llsl.c \
+ aeabi_llsr.c \
+ aeabi_ul2f.c \
+ aeabi_l2f.c \
+ aeabi_f2ulz.c \
LOCAL_C_INCLUDES = $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDE_DIRS := \
diff --git a/firmware/lib/builtins/aeabi_f2ulz.c b/firmware/lib/builtins/aeabi_f2ulz.c
new file mode 100644
index 0000000..a6413a7
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_f2ulz.c
@@ -0,0 +1,27 @@
+/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+du_int __aeabi_f2ulz(float a);
+
+/* Support for systems that have hardware floating-point; can set the invalid
+ * flag as a side-effect of computation.
+ */
+
+du_int
+__aeabi_f2ulz(float a)
+{
+ if (a <= 0.0f) return 0;
+ float da = a;
+ su_int high = da / 4294967296.f; /* da / 0x1p32f; */
+ su_int low = da - (float)high * 4294967296.f; /* high * 0x1p32f; */
+ return ((du_int)high << 32) | low;
+}
diff --git a/firmware/lib/builtins/aeabi_l2f.c b/firmware/lib/builtins/aeabi_l2f.c
new file mode 100644
index 0000000..63d832f
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_l2f.c
@@ -0,0 +1,80 @@
+/*===-- floatdisf.c - Implement __floatdisf -------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ *===----------------------------------------------------------------------===
+ *
+ * This file implements __floatdisf for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a float, rounding toward even.*/
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * di_int is a 64 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+float __aeabi_l2f(di_int a);
+
+float
+__aeabi_l2f(di_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N-1);
+ a = (a ^ s) - s;
+ int sd = N - __builtin_clzll(a); /* number of significant digits */
+ int e = sd - 1; /* exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = ((du_int)a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((du_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((su_int)s & 0x80000000) | /* sign */
+ ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
diff --git a/firmware/lib/builtins/aeabi_llsr.c b/firmware/lib/builtins/aeabi_llsr.c
new file mode 100644
index 0000000..2f0ba6b
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_llsr.c
@@ -0,0 +1,43 @@
+/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __lshrdi3 for the compiler_rt library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_lib.h"
+
+/* Returns: logical a >> b */
+
+/* Precondition: 0 <= b < bits_in_dword */
+
+di_int __aeabi_llsr(di_int a, si_int b);
+
+di_int
+__aeabi_llsr(di_int a, si_int b)
+{
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+ udwords input;
+ udwords result;
+ input.all = a;
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
+ {
+ result.s.high = 0;
+ result.s.low = input.s.high >> (b - bits_in_word);
+ }
+ else /* 0 <= b < bits_in_word */
+ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
+ }
+ return result.all;
+}
diff --git a/firmware/lib/builtins/aeabi_ul2f.c b/firmware/lib/builtins/aeabi_ul2f.c
new file mode 100644
index 0000000..80734db
--- /dev/null
+++ b/firmware/lib/builtins/aeabi_ul2f.c
@@ -0,0 +1,77 @@
+/*===-- floatundisf.c - Implement __floatundisf ---------------------------===
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements __floatundisf for the compiler_rt library.
+ *
+ *===----------------------------------------------------------------------===
+ */
+
+/* Returns: convert a to a float, rounding toward even. */
+
+/* Assumption: float is a IEEE 32 bit floating point type
+ * du_int is a 64 bit integral type
+ */
+
+/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+
+#include "int_lib.h"
+
+float __aeabi_ul2f(du_int a);
+
+float
+__aeabi_ul2f(du_int a)
+{
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int sd = N - __builtin_clzll(a); /* number of significant digits */
+ int e = sd - 1; /* 8 exponent */
+ if (sd > FLT_MANT_DIG)
+ {
+ /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ * 12345678901234567890123456
+ * 1 = msb 1 bit
+ * P = bit FLT_MANT_DIG-1 bits to the right of 1
+ * Q = bit FLT_MANT_DIG bits to the right of 1
+ * R = "or" of all bits to the right of Q
+ */
+ switch (sd)
+ {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (FLT_MANT_DIG+2))) |
+ ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
+ };
+ /* finish: */
+ a |= (a & 4) != 0; /* Or P into R */
+ ++a; /* round - this step may add a significant bit */
+ a >>= 2; /* dump Q and R */
+ /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
+ if (a & ((du_int)1 << FLT_MANT_DIG))
+ {
+ a >>= 1;
+ ++e;
+ }
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ else
+ {
+ a <<= (FLT_MANT_DIG - sd);
+ /* a is now rounded to FLT_MANT_DIG bits */
+ }
+ float_bits fb;
+ fb.u = ((e + 127) << 23) | /* exponent */
+ ((su_int)a & 0x007FFFFF); /* mantissa */
+ return fb.f;
+}
diff --git a/firmware/lib/builtins/int_lib.h b/firmware/lib/builtins/int_lib.h
index 3d968a8..fddef7f 100644
--- a/firmware/lib/builtins/int_lib.h
+++ b/firmware/lib/builtins/int_lib.h
@@ -16,7 +16,8 @@
#ifndef INT_LIB_H
#define INT_LIB_H
-#define CHAR_BIT 8
+#define FLT_MANT_DIG __FLT_MANT_DIG__
+#define CHAR_BIT 8
typedef unsigned su_int;
typedef int si_int;
@@ -44,6 +45,12 @@
} s;
} udwords;
+typedef union
+{
+ su_int u;
+ float f;
+} float_bits;
+
/* Assumption: Signed integral is 2's complement. */
/* Assumption: Right shift of signed negative is arithmetic shift. */
diff --git a/firmware/lib/lib.mk b/firmware/lib/lib.mk
index 41d84ee..b26fc9f 100644
--- a/firmware/lib/lib.mk
+++ b/firmware/lib/lib.mk
@@ -84,4 +84,8 @@
SRCS += $(BUILTINS_PATH)/umoddi3.c
SRCS += $(BUILTINS_PATH)/aeabi_f2d.c
SRCS += $(BUILTINS_PATH)/aeabi_llsl.c
+SRCS += $(BUILTINS_PATH)/aeabi_llsr.c
+SRCS += $(BUILTINS_PATH)/aeabi_ul2f.c
+SRCS += $(BUILTINS_PATH)/aeabi_l2f.c
+SRCS += $(BUILTINS_PATH)/aeabi_f2ulz.c
CFLAGS += -I$(BUILTINS_PATH)
diff --git a/firmware/os/algos/calibration/accelerometer/accel_cal.c b/firmware/os/algos/calibration/accelerometer/accel_cal.c
index 0a6d96d..c700253 100644
--- a/firmware/os/algos/calibration/accelerometer/accel_cal.c
+++ b/firmware/os/algos/calibration/accelerometer/accel_cal.c
@@ -180,6 +180,7 @@
acc->x_bias = acc->y_bias = acc->z_bias = 0;
acc->x_bias_new = acc->y_bias_new = acc->z_bias_new = 0;
+ acc->average_temperature_celsius = 0;
#ifdef IMU_TEMP_DBG_ENABLED
acc->temp_time_nanos = 0;
@@ -422,7 +423,11 @@
float evmin = (eigenvals.x < eigenvals.y) ? eigenvals.x : eigenvals.y;
evmin = (eigenvals.z < evmin) ? eigenvals.z : evmin;
- float evmag = sqrtf(eigenvals.x + eigenvals.y + eigenvals.z);
+ float eigenvals_sum = eigenvals.x + eigenvals.y + eigenvals.z;
+
+ // Testing for negative number.
+ float evmag = (eigenvals_sum > 0) ? sqrtf(eigenvals_sum) : 0;
+
// Passing when evmin/evmax> EIGEN_RATIO.
int eigen_pass = (evmin > evmax * EIGEN_RATIO) && (evmag > EIGEN_MAG);
@@ -526,10 +531,11 @@
// Eigen Ratio Test.
if (accEigenTest(&acc->ac1[temp_gate].akf,
&acc->ac1[temp_gate].agd)) {
- // Storing the new offsets.
+ // Storing the new offsets and average temperature.
acc->x_bias_new = bias.x * KSCALE2;
acc->y_bias_new = bias.y * KSCALE2;
acc->z_bias_new = bias.z * KSCALE2;
+ acc->average_temperature_celsius = acc->ac1[temp_gate].agd.mean_t;
}
#ifdef ACCEL_CAL_DBG_ENABLED
//// Debug ///////
diff --git a/firmware/os/algos/calibration/accelerometer/accel_cal.h b/firmware/os/algos/calibration/accelerometer/accel_cal.h
index e76abcd..1cfef61 100644
--- a/firmware/os/algos/calibration/accelerometer/accel_cal.h
+++ b/firmware/os/algos/calibration/accelerometer/accel_cal.h
@@ -139,6 +139,9 @@
// to store a new offset, which gets updated during a power down event.
float x_bias_new, y_bias_new, z_bias_new;
+ // Average temperature of the bias update.
+ float average_temperature_celsius;
+
// Offset values that get subtracted from live data
float x_bias, y_bias, z_bias;
diff --git a/firmware/os/algos/calibration/gyroscope/gyro_cal.c b/firmware/os/algos/calibration/gyroscope/gyro_cal.c
index d6a69f3..3179b0e 100644
--- a/firmware/os/algos/calibration/gyroscope/gyro_cal.c
+++ b/firmware/os/algos/calibration/gyroscope/gyro_cal.c
@@ -21,7 +21,7 @@
#include <string.h>
#include "calibration/util/cal_log.h"
-#include "common/math/vec.h"
+#include "common/math/macros.h"
/////// DEFINITIONS AND MACROS ///////////////////////////////////////
@@ -29,28 +29,19 @@
// of the given sensor).
#define MAX_GYRO_BIAS (0.2f) // [rad/sec]
-// Converts units of radians to milli-degrees.
-#define RAD_TO_MILLI_DEGREES (float)(1e3f * 180.0f / NANO_PI)
-
// Watchdog timeout value (5 seconds). Monitors dropouts in sensor data and
// resets when exceeded.
-#define GYRO_WATCHDOG_TIMEOUT_NANOS (5000000000)
+#define GYRO_WATCHDOG_TIMEOUT_NANOS (SEC_TO_NANOS(5))
#ifdef GYRO_CAL_DBG_ENABLED
// The time value used to throttle debug messaging.
-#define GYROCAL_WAIT_TIME_NANOS (100000000)
-
-// Unit conversion: nanoseconds to seconds.
-#define NANOS_TO_SEC (1.0e-9f)
+#define GYROCAL_WAIT_TIME_NANOS (MSEC_TO_NANOS(100))
// A debug version label to help with tracking results.
#define GYROCAL_DEBUG_VERSION_STRING "[July 05, 2017]"
// Debug log tag string used to identify debug report output data.
#define GYROCAL_REPORT_TAG "[GYRO_CAL:REPORT]"
-
-// Debug log tag string used to identify debug tuning output data.
-#define GYROCAL_TUNE_TAG "[GYRO_CAL:TUNE]"
#endif // GYRO_CAL_DBG_ENABLED
/////// FORWARD DECLARATIONS /////////////////////////////////////////
@@ -113,7 +104,7 @@
};
/*
- * Updates running calculation of the gyro's mean sampling rate.
+ * Updates the running calculation of the gyro's mean sampling rate.
*
* Behavior:
* 1) If 'debug_mean_sampling_rate_hz' pointer is not NULL then the local
@@ -123,11 +114,13 @@
* 3) Otherwise, the local estimate of the mean sampling rates is updated.
*
* INPUTS:
- * debug_mean_sampling_rate_hz: Pointer to the mean sampling rate to update.
+ * sample_rate_estimator: Pointer to the estimator data structure.
+ * debug_mean_sampling_rate_hz: Pointer to the mean sampling rate to update.
* timestamp_nanos: Time stamp (nanoseconds).
* reset_stats: Flag that signals a reset of the sampling rate estimate.
*/
-static void gyroSamplingRateUpdate(float* debug_mean_sampling_rate_hz,
+static void gyroSamplingRateUpdate(struct SampleRateData* sample_rate_estimator,
+ float* debug_mean_sampling_rate_hz,
uint64_t timestamp_nanos, bool reset_stats);
// Updates the information used for debug printouts.
@@ -146,17 +139,11 @@
uint32_t hi = v >> 32, lo = v;
if (!hi) //this is very fast for cases where we fit into a uint32_t
- return(float)lo;
+ return (float)lo;
else {
return ((float)hi) * 4294967296.0f + (float)lo;
}
}
-
-#ifdef GYRO_CAL_DBG_TUNE_ENABLED
-// Prints debug information useful for tuning the GyroCal parameters.
-static void gyroCalTuneDebugPrint(const struct GyroCal* gyro_cal,
- uint64_t timestamp_nanos);
-#endif // GYRO_CAL_DBG_TUNE_ENABLED
#endif // GYRO_CAL_DBG_ENABLED
/////// FUNCTION DEFINITIONS /////////////////////////////////////////
@@ -235,7 +222,8 @@
}
// Ensures that the gyro sampling rate estimate is reset.
- gyroSamplingRateUpdate(NULL, 0, /*reset_stats=*/true);
+ gyroSamplingRateUpdate(&gyro_cal->sample_rate_estimator, NULL, 0,
+ /*reset_stats=*/true);
#endif // GYRO_CAL_DBG_ENABLED
}
@@ -264,10 +252,10 @@
#ifdef GYRO_CAL_DBG_ENABLED
CAL_DEBUG_LOG("[GYRO_CAL:SET BIAS]",
- "Gyro Bias Calibration [mDPS]: %s%d.%03d, %s%d.%03d, %s%d.%03d",
- CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MILLI_DEGREES, 3),
- CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MILLI_DEGREES, 3),
- CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MILLI_DEGREES, 3));
+ "Gyro Bias Calibration [mDPS]: " CAL_FORMAT_3DIGITS_TRIPLET,
+ CAL_ENCODE_FLOAT(gyro_cal->bias_x * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_y * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(gyro_cal->bias_z * RAD_TO_MDEG, 3));
#endif // GYRO_CAL_DBG_ENABLED
}
@@ -310,7 +298,8 @@
#ifdef GYRO_CAL_DBG_ENABLED
// Update the gyro sampling rate estimate.
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/false);
+ gyroSamplingRateUpdate(&gyro_cal->sample_rate_estimator, NULL,
+ sample_time_nanos, /*reset_stats=*/false);
#endif // GYRO_CAL_DBG_ENABLED
// Pass gyro data to stillness detector
@@ -453,7 +442,8 @@
#ifdef GYRO_CAL_DBG_ENABLED
// Resets the sampling rate estimate.
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/true);
+ gyroSamplingRateUpdate(&gyro_cal->sample_rate_estimator, NULL,
+ sample_time_nanos, /*reset_stats=*/true);
#endif // GYRO_CAL_DBG_ENABLED
// Update stillness flag. Force the start of a new stillness period.
@@ -496,7 +486,8 @@
#ifdef GYRO_CAL_DBG_ENABLED
// Resets the sampling rate estimate.
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/true);
+ gyroSamplingRateUpdate(&gyro_cal->sample_rate_estimator, NULL,
+ sample_time_nanos, /*reset_stats=*/true);
#endif // GYRO_CAL_DBG_ENABLED
// Update stillness flag.
@@ -517,20 +508,18 @@
gyro_cal->gyro_stillness_detect.prev_mean_z < MAX_GYRO_BIAS &&
gyro_cal->gyro_stillness_detect.prev_mean_z > -MAX_GYRO_BIAS)) {
#ifdef GYRO_CAL_DBG_ENABLED
- CAL_DEBUG_LOG("[GYRO_CAL:REJECT]",
- "Offset|Temp|Time [mDPS|C|nsec]: %s%d.%03d, %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d, %llu",
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.prev_mean_x *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.prev_mean_y *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.prev_mean_z *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->temperature_mean_celsius, 3),
- (unsigned long long int)calibration_time_nanos);
+ CAL_DEBUG_LOG(
+ "[GYRO_CAL:REJECT]",
+ "Offset|Temp|Time [mDPS|C|nsec]: " CAL_FORMAT_3DIGITS_TRIPLET
+ ", " CAL_FORMAT_3DIGITS ", %llu",
+ CAL_ENCODE_FLOAT(
+ gyro_cal->gyro_stillness_detect.prev_mean_x * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(
+ gyro_cal->gyro_stillness_detect.prev_mean_y * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(
+ gyro_cal->gyro_stillness_detect.prev_mean_z * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(gyro_cal->temperature_mean_celsius, 3),
+ (unsigned long long int)calibration_time_nanos);
#endif // GYRO_CAL_DBG_ENABLED
// Outside of range. Ignore, reset, and continue.
@@ -620,7 +609,8 @@
#ifdef GYRO_CAL_DBG_ENABLED
// Resets the sampling rate estimate.
- gyroSamplingRateUpdate(NULL, sample_time_nanos, /*reset_stats=*/true);
+ gyroSamplingRateUpdate(&gyro_cal->sample_rate_estimator, NULL,
+ sample_time_nanos, /*reset_stats=*/true);
#endif // GYRO_CAL_DBG_ENABLED
// Resets the stillness window end-time.
@@ -661,10 +651,8 @@
gyro_cal->temperature_mean_tracker.mean_accumulator = 0.0f;
// Initializes the min/max temperatures values.
- gyro_cal->temperature_mean_tracker.temperature_min_max_celsius[0] =
- FLT_MAX;
- gyro_cal->temperature_mean_tracker.temperature_min_max_celsius[1] =
- -FLT_MAX;
+ gyro_cal->temperature_mean_tracker.temperature_min_celsius = FLT_MAX;
+ gyro_cal->temperature_mean_tracker.temperature_max_celsius = -FLT_MAX;
break;
case DO_UPDATE_DATA:
@@ -676,14 +664,14 @@
// Tracks the min, max, and latest temperature values.
gyro_cal->temperature_mean_tracker.latest_temperature_celsius =
temperature_celsius;
- if (gyro_cal->temperature_mean_tracker.temperature_min_max_celsius[0] >
+ if (gyro_cal->temperature_mean_tracker.temperature_min_celsius >
temperature_celsius) {
- gyro_cal->temperature_mean_tracker.temperature_min_max_celsius[0] =
+ gyro_cal->temperature_mean_tracker.temperature_min_celsius =
temperature_celsius;
}
- if (gyro_cal->temperature_mean_tracker.temperature_min_max_celsius[1] <
+ if (gyro_cal->temperature_mean_tracker.temperature_max_celsius <
temperature_celsius) {
- gyro_cal->temperature_mean_tracker.temperature_min_max_celsius[1] =
+ gyro_cal->temperature_mean_tracker.temperature_max_celsius =
temperature_celsius;
}
break;
@@ -709,9 +697,10 @@
// Records the min/max and mean temperature values for debug purposes.
gyro_cal->debug_gyro_cal.temperature_mean_celsius =
gyro_cal->temperature_mean_celsius;
- memcpy(gyro_cal->debug_gyro_cal.temperature_min_max_celsius,
- gyro_cal->temperature_mean_tracker.temperature_min_max_celsius,
- 2 * sizeof(float));
+ gyro_cal->debug_gyro_cal.temperature_min_celsius =
+ gyro_cal->temperature_mean_tracker.temperature_min_celsius;
+ gyro_cal->debug_gyro_cal.temperature_max_celsius =
+ gyro_cal->temperature_mean_tracker.temperature_max_celsius;
#endif
break;
@@ -719,9 +708,8 @@
// Determines if the min/max delta exceeded the set limit.
if (gyro_cal->temperature_mean_tracker.num_points > 0) {
min_max_temp_exceeded =
- (gyro_cal->temperature_mean_tracker.temperature_min_max_celsius[1] -
- gyro_cal->temperature_mean_tracker
- .temperature_min_max_celsius[0]) >
+ (gyro_cal->temperature_mean_tracker.temperature_max_celsius -
+ gyro_cal->temperature_mean_tracker.temperature_min_celsius) >
gyro_cal->temperature_delta_limit_celsius;
#ifdef GYRO_CAL_DBG_ENABLED
@@ -743,41 +731,50 @@
bool gyroStillMeanTracker(struct GyroCal* gyro_cal,
enum GyroCalTrackerCommand do_this) {
- static float gyro_winmean_min[3] = {0.0f, 0.0f, 0.0f};
- static float gyro_winmean_max[3] = {0.0f, 0.0f, 0.0f};
bool mean_not_stable = false;
- size_t i;
switch (do_this) {
case DO_RESET:
// Resets the min/max window mean values to a default value.
- for (i = 0; i < 3; i++) {
- gyro_winmean_min[i] = FLT_MAX;
- gyro_winmean_max[i] = -FLT_MAX;
+ for (size_t i = 0; i < 3; i++) {
+ gyro_cal->window_mean_tracker.gyro_winmean_min[i] = FLT_MAX;
+ gyro_cal->window_mean_tracker.gyro_winmean_max[i] = -FLT_MAX;
}
break;
case DO_UPDATE_DATA:
// Computes the min/max window mean values.
- if (gyro_winmean_min[0] > gyro_cal->gyro_stillness_detect.win_mean_x) {
- gyro_winmean_min[0] = gyro_cal->gyro_stillness_detect.win_mean_x;
+ if (gyro_cal->window_mean_tracker.gyro_winmean_min[0] >
+ gyro_cal->gyro_stillness_detect.win_mean_x) {
+ gyro_cal->window_mean_tracker.gyro_winmean_min[0] =
+ gyro_cal->gyro_stillness_detect.win_mean_x;
}
- if (gyro_winmean_max[0] < gyro_cal->gyro_stillness_detect.win_mean_x) {
- gyro_winmean_max[0] = gyro_cal->gyro_stillness_detect.win_mean_x;
+ if (gyro_cal->window_mean_tracker.gyro_winmean_max[0] <
+ gyro_cal->gyro_stillness_detect.win_mean_x) {
+ gyro_cal->window_mean_tracker.gyro_winmean_max[0] =
+ gyro_cal->gyro_stillness_detect.win_mean_x;
}
- if (gyro_winmean_min[1] > gyro_cal->gyro_stillness_detect.win_mean_y) {
- gyro_winmean_min[1] = gyro_cal->gyro_stillness_detect.win_mean_y;
+ if (gyro_cal->window_mean_tracker.gyro_winmean_min[1] >
+ gyro_cal->gyro_stillness_detect.win_mean_y) {
+ gyro_cal->window_mean_tracker.gyro_winmean_min[1] =
+ gyro_cal->gyro_stillness_detect.win_mean_y;
}
- if (gyro_winmean_max[1] < gyro_cal->gyro_stillness_detect.win_mean_y) {
- gyro_winmean_max[1] = gyro_cal->gyro_stillness_detect.win_mean_y;
+ if (gyro_cal->window_mean_tracker.gyro_winmean_max[1] <
+ gyro_cal->gyro_stillness_detect.win_mean_y) {
+ gyro_cal->window_mean_tracker.gyro_winmean_max[1] =
+ gyro_cal->gyro_stillness_detect.win_mean_y;
}
- if (gyro_winmean_min[2] > gyro_cal->gyro_stillness_detect.win_mean_z) {
- gyro_winmean_min[2] = gyro_cal->gyro_stillness_detect.win_mean_z;
+ if (gyro_cal->window_mean_tracker.gyro_winmean_min[2] >
+ gyro_cal->gyro_stillness_detect.win_mean_z) {
+ gyro_cal->window_mean_tracker.gyro_winmean_min[2] =
+ gyro_cal->gyro_stillness_detect.win_mean_z;
}
- if (gyro_winmean_max[2] < gyro_cal->gyro_stillness_detect.win_mean_z) {
- gyro_winmean_max[2] = gyro_cal->gyro_stillness_detect.win_mean_z;
+ if (gyro_cal->window_mean_tracker.gyro_winmean_max[2] <
+ gyro_cal->gyro_stillness_detect.win_mean_z) {
+ gyro_cal->window_mean_tracker.gyro_winmean_max[2] =
+ gyro_cal->gyro_stillness_detect.win_mean_z;
}
break;
@@ -785,34 +782,45 @@
// Store the most recent "stillness" mean data to the GyroCal data
// structure. This functionality allows previous results to be recalled
// when the device suddenly becomes "not still".
- memcpy(gyro_cal->gyro_winmean_min, gyro_winmean_min, 3 * sizeof(float));
- memcpy(gyro_cal->gyro_winmean_max, gyro_winmean_max, 3 * sizeof(float));
- break;
+ memcpy(gyro_cal->gyro_winmean_min,
+ gyro_cal->window_mean_tracker.gyro_winmean_min,
+ sizeof(gyro_cal->window_mean_tracker.gyro_winmean_min));
+ memcpy(gyro_cal->gyro_winmean_max,
+ gyro_cal->window_mean_tracker.gyro_winmean_max,
+ sizeof(gyro_cal->window_mean_tracker.gyro_winmean_max));
+ break;
case DO_EVALUATE:
// Performs the stability check and returns the 'true' if the difference
// between min/max window mean value is outside the stable range.
- for (i = 0; i < 3; i++) {
- mean_not_stable |= (gyro_winmean_max[i] - gyro_winmean_min[i]) >
+ for (size_t i = 0; i < 3; i++) {
+ mean_not_stable |= (gyro_cal->window_mean_tracker.gyro_winmean_max[i] -
+ gyro_cal->window_mean_tracker.gyro_winmean_min[i]) >
gyro_cal->stillness_mean_delta_limit;
}
#ifdef GYRO_CAL_DBG_ENABLED
if (mean_not_stable) {
CAL_DEBUG_LOG(
"[GYRO_CAL:MEAN_STABILITY_GATE]",
- "Variation Limit|Delta [mDPS]: %s%d.%03d | %s%d.%03d, %s%d.%03d, "
- "%s%d.%03d",
+ "Variation Limit|Delta [mDPS]: " CAL_FORMAT_3DIGITS
+ " | " CAL_FORMAT_3DIGITS_TRIPLET,
+ CAL_ENCODE_FLOAT(gyro_cal->stillness_mean_delta_limit * RAD_TO_MDEG,
+ 3),
CAL_ENCODE_FLOAT(
- gyro_cal->stillness_mean_delta_limit * RAD_TO_MILLI_DEGREES, 3),
- CAL_ENCODE_FLOAT((gyro_winmean_max[0] - gyro_winmean_min[0]) *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT((gyro_winmean_max[1] - gyro_winmean_min[1]) *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT((gyro_winmean_max[2] - gyro_winmean_min[2]) *
- RAD_TO_MILLI_DEGREES,
- 3));
+ (gyro_cal->window_mean_tracker.gyro_winmean_max[0] -
+ gyro_cal->window_mean_tracker.gyro_winmean_min[0]) *
+ RAD_TO_MDEG,
+ 3),
+ CAL_ENCODE_FLOAT(
+ (gyro_cal->window_mean_tracker.gyro_winmean_max[1] -
+ gyro_cal->window_mean_tracker.gyro_winmean_min[1]) *
+ RAD_TO_MDEG,
+ 3),
+ CAL_ENCODE_FLOAT(
+ (gyro_cal->window_mean_tracker.gyro_winmean_max[2] -
+ gyro_cal->window_mean_tracker.gyro_winmean_min[2]) *
+ RAD_TO_MDEG,
+ 3));
}
#endif // GYRO_CAL_DBG_ENABLED
break;
@@ -825,21 +833,19 @@
}
#ifdef GYRO_CAL_DBG_ENABLED
-void gyroSamplingRateUpdate(float* debug_mean_sampling_rate_hz,
+void gyroSamplingRateUpdate(struct SampleRateData* sample_rate_estimator,
+ float* debug_mean_sampling_rate_hz,
uint64_t timestamp_nanos, bool reset_stats) {
- // This is used for local calculations of average sampling rate.
- static uint64_t last_timestamp_nanos = 0;
- static uint64_t time_delta_accumulator = 0;
- static size_t num_samples = 0;
-
// If 'debug_mean_sampling_rate_hz' is not NULL then this function just reads
// out the estimate of the sampling rate.
if (debug_mean_sampling_rate_hz) {
- if (num_samples > 1 && time_delta_accumulator > 0) {
+ if (sample_rate_estimator->num_samples > 1 &&
+ sample_rate_estimator->time_delta_accumulator > 0) {
// Computes the final mean calculation.
*debug_mean_sampling_rate_hz =
- num_samples /
- (floatFromUint64(time_delta_accumulator) * NANOS_TO_SEC);
+ sample_rate_estimator->num_samples /
+ (floatFromUint64(sample_rate_estimator->time_delta_accumulator) *
+ NANOS_TO_SEC);
} else {
// Not enough samples to compute a valid sample rate estimate. Indicate
// this with a -1 value.
@@ -850,26 +856,28 @@
// Resets the sampling rate mean estimator data.
if (reset_stats) {
- last_timestamp_nanos = 0;
- time_delta_accumulator = 0;
- num_samples = 0;
+ sample_rate_estimator->last_timestamp_nanos = 0;
+ sample_rate_estimator->time_delta_accumulator = 0;
+ sample_rate_estimator->num_samples = 0;
return;
}
// Skip adding this data to the accumulator if:
// 1. A bad timestamp was received (i.e., time not monotonic).
// 2. 'last_timestamp_nanos' is zero.
- if (timestamp_nanos <= last_timestamp_nanos || last_timestamp_nanos == 0) {
- last_timestamp_nanos = timestamp_nanos;
+ if (timestamp_nanos <= sample_rate_estimator->last_timestamp_nanos ||
+ sample_rate_estimator->last_timestamp_nanos == 0) {
+ sample_rate_estimator->last_timestamp_nanos = timestamp_nanos;
return;
}
// Increments the number of samples.
- num_samples++;
+ sample_rate_estimator->num_samples++;
// Accumulate the time steps.
- time_delta_accumulator += timestamp_nanos - last_timestamp_nanos;
- last_timestamp_nanos = timestamp_nanos;
+ sample_rate_estimator->time_delta_accumulator +=
+ timestamp_nanos - sample_rate_estimator->last_timestamp_nanos;
+ sample_rate_estimator->last_timestamp_nanos = timestamp_nanos;
}
void gyroCalUpdateDebug(struct GyroCal* gyro_cal) {
@@ -905,14 +913,15 @@
gyro_cal->debug_gyro_cal.calibration[2] = gyro_cal->bias_z;
// Records the mean gyroscope sampling rate.
- gyroSamplingRateUpdate(&gyro_cal->debug_gyro_cal.mean_sampling_rate_hz, 0,
+ gyroSamplingRateUpdate(&gyro_cal->sample_rate_estimator,
+ &gyro_cal->debug_gyro_cal.mean_sampling_rate_hz, 0,
/*reset_stats=*/true);
// Records the min/max gyroscope window stillness mean values.
memcpy(gyro_cal->debug_gyro_cal.gyro_winmean_min, gyro_cal->gyro_winmean_min,
- 3 * sizeof(float));
+ sizeof(gyro_cal->gyro_winmean_min));
memcpy(gyro_cal->debug_gyro_cal.gyro_winmean_max, gyro_cal->gyro_winmean_max,
- 3 * sizeof(float));
+ sizeof(gyro_cal->gyro_winmean_max));
// Records the previous stillness window means.
gyro_cal->debug_gyro_cal.accel_mean[0] =
@@ -971,23 +980,21 @@
float mag_data;
switch (print_data) {
case OFFSET:
- CAL_DEBUG_LOG(debug_tag,
- "Cal#|Offset|Temp|Time [mDPS|C|nsec]: %lu, %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d, %s%d.%03d, %llu",
- (unsigned long int)gyro_cal->debug_calibration_count,
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.calibration[0] *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.calibration[1] *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.calibration[2] *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->debug_gyro_cal.temperature_mean_celsius, 3),
- (unsigned long long int)
- gyro_cal->debug_gyro_cal.end_still_time_nanos);
+ CAL_DEBUG_LOG(
+ debug_tag,
+ "Cal#|Offset|Temp|Time [mDPS|C|nsec]: "
+ "%lu, " CAL_FORMAT_3DIGITS_TRIPLET ", " CAL_FORMAT_3DIGITS ", %llu",
+ (unsigned long int)gyro_cal->debug_calibration_count,
+ CAL_ENCODE_FLOAT(
+ gyro_cal->debug_gyro_cal.calibration[0] * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(
+ gyro_cal->debug_gyro_cal.calibration[1] * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(
+ gyro_cal->debug_gyro_cal.calibration[2] * RAD_TO_MDEG, 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.temperature_mean_celsius,
+ 3),
+ (unsigned long long int)
+ gyro_cal->debug_gyro_cal.end_still_time_nanos);
break;
case STILLNESS_DATA:
@@ -996,8 +1003,8 @@
: -1.0f; // Signals that magnetometer was not used.
CAL_DEBUG_LOG(
debug_tag,
- "Cal#|Stillness|Confidence [nsec]: %lu, %llu, %s%d.%03d, %s%d.%03d, "
- "%s%d.%03d",
+ "Cal#|Stillness|Confidence [nsec]: %lu, "
+ "%llu, " CAL_FORMAT_3DIGITS_TRIPLET,
(unsigned long int)gyro_cal->debug_calibration_count,
(unsigned long long int)(gyro_cal->debug_gyro_cal
.end_still_time_nanos -
@@ -1011,91 +1018,90 @@
case SAMPLE_RATE_AND_TEMPERATURE:
CAL_DEBUG_LOG(
debug_tag,
- "Cal#|Mean|Min|Max|Delta|Sample Rate [C|Hz]: %lu, %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d, %s%d.%04d, %s%d.%03d",
+ "Cal#|Mean|Min|Max|Delta|Sample Rate [C|Hz]: "
+ "%lu, " CAL_FORMAT_3DIGITS_TRIPLET ", " CAL_FORMAT_3DIGITS
+ ", " CAL_FORMAT_3DIGITS,
(unsigned long int)gyro_cal->debug_calibration_count,
CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.temperature_mean_celsius,
3),
- CAL_ENCODE_FLOAT(
- gyro_cal->debug_gyro_cal.temperature_min_max_celsius[0], 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->debug_gyro_cal.temperature_min_max_celsius[1], 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->debug_gyro_cal.temperature_min_max_celsius[1] -
- gyro_cal->debug_gyro_cal.temperature_min_max_celsius[0],
- 4),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.temperature_min_celsius, 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.temperature_max_celsius, 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.temperature_max_celsius -
+ gyro_cal->debug_gyro_cal.temperature_min_celsius,
+ 3),
CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mean_sampling_rate_hz, 3));
break;
case GYRO_MINMAX_STILLNESS_MEAN:
CAL_DEBUG_LOG(
debug_tag,
- "Cal#|Gyro Peak Stillness Variation [mDPS]: %lu, %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d",
+ "Cal#|Gyro Peak Stillness Variation [mDPS]: "
+ "%lu, " CAL_FORMAT_3DIGITS_TRIPLET,
(unsigned long int)gyro_cal->debug_calibration_count,
CAL_ENCODE_FLOAT((gyro_cal->debug_gyro_cal.gyro_winmean_max[0] -
gyro_cal->debug_gyro_cal.gyro_winmean_min[0]) *
- RAD_TO_MILLI_DEGREES,
+ RAD_TO_MDEG,
3),
CAL_ENCODE_FLOAT((gyro_cal->debug_gyro_cal.gyro_winmean_max[1] -
gyro_cal->debug_gyro_cal.gyro_winmean_min[1]) *
- RAD_TO_MILLI_DEGREES,
+ RAD_TO_MDEG,
3),
CAL_ENCODE_FLOAT((gyro_cal->debug_gyro_cal.gyro_winmean_max[2] -
gyro_cal->debug_gyro_cal.gyro_winmean_min[2]) *
- RAD_TO_MILLI_DEGREES,
+ RAD_TO_MDEG,
3));
break;
case ACCEL_STATS:
- CAL_DEBUG_LOG(
- debug_tag,
- "Cal#|Accel Mean|Var [m/sec^2|(m/sec^2)^2]: %lu, "
- "%s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%06d, %s%d.%06d, %s%d.%06d",
- (unsigned long int)gyro_cal->debug_calibration_count,
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_mean[0], 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_mean[1], 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_mean[2], 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_var[0], 6),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_var[1], 6),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_var[2], 6));
+ CAL_DEBUG_LOG(debug_tag,
+ "Cal#|Accel Mean|Var [m/sec^2|(m/sec^2)^2]: "
+ "%lu, " CAL_FORMAT_3DIGITS_TRIPLET
+ ", " CAL_FORMAT_6DIGITS_TRIPLET,
+ (unsigned long int)gyro_cal->debug_calibration_count,
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_mean[0], 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_mean[1], 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_mean[2], 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_var[0], 6),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_var[1], 6),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.accel_var[2], 6));
break;
case GYRO_STATS:
CAL_DEBUG_LOG(
debug_tag,
- "Cal#|Gyro Mean|Var [mDPS|mDPS^2]: %lu, %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d",
+ "Cal#|Gyro Mean|Var [mDPS|mDPS^2]: %lu, " CAL_FORMAT_3DIGITS_TRIPLET
+ ", " CAL_FORMAT_3DIGITS_TRIPLET,
(unsigned long int)gyro_cal->debug_calibration_count,
- CAL_ENCODE_FLOAT(
- gyro_cal->debug_gyro_cal.gyro_mean[0] * RAD_TO_MILLI_DEGREES, 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->debug_gyro_cal.gyro_mean[1] * RAD_TO_MILLI_DEGREES, 3),
- CAL_ENCODE_FLOAT(
- gyro_cal->debug_gyro_cal.gyro_mean[2] * RAD_TO_MILLI_DEGREES, 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.gyro_var[0] *
- RAD_TO_MILLI_DEGREES * RAD_TO_MILLI_DEGREES,
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.gyro_mean[0] * RAD_TO_MDEG,
3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.gyro_var[1] *
- RAD_TO_MILLI_DEGREES * RAD_TO_MILLI_DEGREES,
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.gyro_mean[1] * RAD_TO_MDEG,
3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.gyro_var[2] *
- RAD_TO_MILLI_DEGREES * RAD_TO_MILLI_DEGREES,
- 3));
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.gyro_mean[2] * RAD_TO_MDEG,
+ 3),
+ CAL_ENCODE_FLOAT(
+ gyro_cal->debug_gyro_cal.gyro_var[0] * RAD_TO_MDEG * RAD_TO_MDEG,
+ 3),
+ CAL_ENCODE_FLOAT(
+ gyro_cal->debug_gyro_cal.gyro_var[1] * RAD_TO_MDEG * RAD_TO_MDEG,
+ 3),
+ CAL_ENCODE_FLOAT(
+ gyro_cal->debug_gyro_cal.gyro_var[2] * RAD_TO_MDEG * RAD_TO_MDEG,
+ 3));
break;
case MAG_STATS:
if (gyro_cal->debug_gyro_cal.using_mag_sensor) {
- CAL_DEBUG_LOG(debug_tag,
- "Cal#|Mag Mean|Var [uT|uT^2]: %lu, %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d, %s%d.%06d, %s%d.%06d, %s%d.%06d",
- (unsigned long int)gyro_cal->debug_calibration_count,
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_mean[0], 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_mean[1], 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_mean[2], 3),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_var[0], 6),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_var[1], 6),
- CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_var[2], 6));
+ CAL_DEBUG_LOG(
+ debug_tag,
+ "Cal#|Mag Mean|Var [uT|uT^2]: %lu, " CAL_FORMAT_3DIGITS_TRIPLET
+ ", " CAL_FORMAT_6DIGITS_TRIPLET,
+ (unsigned long int)gyro_cal->debug_calibration_count,
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_mean[0], 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_mean[1], 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_mean[2], 3),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_var[0], 6),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_var[1], 6),
+ CAL_ENCODE_FLOAT(gyro_cal->debug_gyro_cal.mag_var[2], 6));
} else {
CAL_DEBUG_LOG(debug_tag,
"Cal#|Mag Mean|Var [uT|uT^2]: %lu, 0, 0, 0, -1.0, -1.0, "
@@ -1104,73 +1110,12 @@
}
break;
-#ifdef GYRO_CAL_DBG_TUNE_ENABLED
- case ACCEL_STATS_TUNING:
- CAL_DEBUG_LOG(
- debug_tag,
- "Accel Mean|Var [m/sec^2|(m/sec^2)^2]: %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d, %s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.prev_mean_x, 3),
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.prev_mean_y, 3),
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.prev_mean_z, 3),
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_x, 6),
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_y, 6),
- CAL_ENCODE_FLOAT(gyro_cal->accel_stillness_detect.win_var_z, 6));
- break;
-
- case GYRO_STATS_TUNING:
- CAL_DEBUG_LOG(
- debug_tag,
- "Gyro Mean|Var [mDPS|mDPS^2]: %s%d.%03d, %s%d.%03d, %s%d.%03d, "
- "%s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.prev_mean_x *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.prev_mean_y *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.prev_mean_z *
- RAD_TO_MILLI_DEGREES,
- 3),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_x *
- RAD_TO_MILLI_DEGREES * RAD_TO_MILLI_DEGREES,
- 6),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_y *
- RAD_TO_MILLI_DEGREES * RAD_TO_MILLI_DEGREES,
- 6),
- CAL_ENCODE_FLOAT(gyro_cal->gyro_stillness_detect.win_var_z *
- RAD_TO_MILLI_DEGREES * RAD_TO_MILLI_DEGREES,
- 6));
- break;
-
- case MAG_STATS_TUNING:
- if (gyro_cal->using_mag_sensor) {
- CAL_DEBUG_LOG(
- debug_tag,
- "Mag Mean|Var [uT|uT^2]: %s%d.%03d, %s%d.%03d, %s%d.%03d, "
- "%s%d.%06d, %s%d.%06d, %s%d.%06d",
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.prev_mean_x, 3),
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.prev_mean_y, 3),
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.prev_mean_z, 3),
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_x, 6),
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_y, 6),
- CAL_ENCODE_FLOAT(gyro_cal->mag_stillness_detect.win_var_z, 6));
- } else {
- CAL_DEBUG_LOG(GYROCAL_TUNE_TAG,
- "Mag Mean|Var [uT|uT^2]: 0, 0, 0, -1.0, -1.0, -1.0");
- }
- break;
-#endif // GYRO_CAL_DBG_TUNE_ENABLED
-
default:
break;
}
}
void gyroCalDebugPrint(struct GyroCal* gyro_cal, uint64_t timestamp_nanos) {
- static enum GyroCalDebugState next_state = GYRO_IDLE;
- static uint64_t wait_timer_nanos = 0;
-
// This is a state machine that controls the reporting out of debug data.
switch (gyro_cal->debug_state) {
case GYRO_IDLE:
@@ -1188,144 +1133,70 @@
case GYRO_WAIT_STATE:
// This helps throttle the print statements.
- if (NANO_TIMER_CHECK_T1_GEQUAL_T2_PLUS_DELTA(
- timestamp_nanos, wait_timer_nanos, GYROCAL_WAIT_TIME_NANOS)) {
- gyro_cal->debug_state = next_state;
+ if (NANO_TIMER_CHECK_T1_GEQUAL_T2_PLUS_DELTA(timestamp_nanos,
+ gyro_cal->wait_timer_nanos,
+ GYROCAL_WAIT_TIME_NANOS)) {
+ gyro_cal->debug_state = gyro_cal->next_state;
}
break;
case GYRO_PRINT_OFFSET:
gyroCalDebugPrintData(gyro_cal, GYROCAL_REPORT_TAG, OFFSET);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_STILLNESS_DATA; // Sets the next state.
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->next_state = GYRO_PRINT_STILLNESS_DATA; // Sets the next state.
gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
break;
case GYRO_PRINT_STILLNESS_DATA:
gyroCalDebugPrintData(gyro_cal, GYROCAL_REPORT_TAG, STILLNESS_DATA);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_SAMPLE_RATE_AND_TEMPERATURE; // Sets next state.
- gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->next_state =
+ GYRO_PRINT_SAMPLE_RATE_AND_TEMPERATURE; // Sets next state.
+ gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
break;
case GYRO_PRINT_SAMPLE_RATE_AND_TEMPERATURE:
gyroCalDebugPrintData(gyro_cal, GYROCAL_REPORT_TAG,
SAMPLE_RATE_AND_TEMPERATURE);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_GYRO_MINMAX_STILLNESS_MEAN; // Sets next state.
- gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->next_state =
+ GYRO_PRINT_GYRO_MINMAX_STILLNESS_MEAN; // Sets next state.
+ gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
break;
case GYRO_PRINT_GYRO_MINMAX_STILLNESS_MEAN:
gyroCalDebugPrintData(gyro_cal, GYROCAL_REPORT_TAG,
GYRO_MINMAX_STILLNESS_MEAN);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_ACCEL_STATS; // Sets the next state.
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->next_state = GYRO_PRINT_ACCEL_STATS; // Sets the next state.
gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
break;
case GYRO_PRINT_ACCEL_STATS:
gyroCalDebugPrintData(gyro_cal, GYROCAL_REPORT_TAG, ACCEL_STATS);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_GYRO_STATS; // Sets the next state.
- gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->next_state = GYRO_PRINT_GYRO_STATS; // Sets the next state.
+ gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
break;
case GYRO_PRINT_GYRO_STATS:
gyroCalDebugPrintData(gyro_cal, GYROCAL_REPORT_TAG, GYRO_STATS);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_MAG_STATS; // Sets the next state.
- gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->next_state = GYRO_PRINT_MAG_STATS; // Sets the next state.
+ gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
break;
case GYRO_PRINT_MAG_STATS:
gyroCalDebugPrintData(gyro_cal, GYROCAL_REPORT_TAG, MAG_STATS);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_IDLE; // Sets the next state.
- gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->next_state = GYRO_IDLE; // Sets the next state.
+ gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
break;
default:
// Sends this state machine to its idle state.
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- gyro_cal->debug_state = GYRO_WAIT_STATE; // First, go to wait state.
- }
-
-#ifdef GYRO_CAL_DBG_TUNE_ENABLED
- if (gyro_cal->debug_state == GYRO_IDLE) {
- // This check keeps the tuning printout from interleaving with the above
- // debug print data.
- gyroCalTuneDebugPrint(gyro_cal, timestamp_nanos);
- }
-#endif // GYRO_CAL_DBG_TUNE_ENABLED
-}
-
-#ifdef GYRO_CAL_DBG_TUNE_ENABLED
-void gyroCalTuneDebugPrint(const struct GyroCal* gyro_cal,
- uint64_t timestamp_nanos) {
- static enum GyroCalDebugState debug_state = GYRO_IDLE;
- static enum GyroCalDebugState next_state = GYRO_IDLE;
- static uint64_t wait_timer_nanos = 0;
-
- // Output sensor variance levels to assist with tuning thresholds.
- // i. Within the first 300 seconds of boot: output interval = 5
- // seconds.
- // ii. Thereafter: output interval is 60 seconds.
- bool condition_i = ((timestamp_nanos <= 300000000000) &&
- NANO_TIMER_CHECK_T1_GEQUAL_T2_PLUS_DELTA(
- timestamp_nanos, wait_timer_nanos, 5000000000));
- bool condition_ii = NANO_TIMER_CHECK_T1_GEQUAL_T2_PLUS_DELTA(
- timestamp_nanos, wait_timer_nanos, 60000000000);
-
- // This is a state machine that controls the reporting out of tuning data.
- switch (debug_state) {
- case GYRO_IDLE:
- // Wait for a trigger and start the data tuning printout sequence.
- if (condition_i || condition_ii) {
- CAL_DEBUG_LOG(GYROCAL_TUNE_TAG, "Temp [C]: %s%d.%03d",
- CAL_ENCODE_FLOAT(gyro_cal->temperature_mean_celsius, 3));
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_ACCEL_STATS; // Sets the next state.
- debug_state = GYRO_WAIT_STATE; // First, go to wait state.
- } else {
- debug_state = GYRO_IDLE;
- }
- break;
-
- case GYRO_WAIT_STATE:
- // This helps throttle the print statements.
- if (NANO_TIMER_CHECK_T1_GEQUAL_T2_PLUS_DELTA(
- timestamp_nanos, wait_timer_nanos, GYROCAL_WAIT_TIME_NANOS)) {
- debug_state = next_state;
- }
- break;
-
- case GYRO_PRINT_ACCEL_STATS:
- gyroCalDebugPrintData(gyro_cal, GYROCAL_TUNE_TAG, ACCEL_STATS_TUNING);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_GYRO_STATS; // Sets the next state.
- debug_state = GYRO_WAIT_STATE; // First, go to wait state.
- break;
-
- case GYRO_PRINT_GYRO_STATS:
- gyroCalDebugPrintData(gyro_cal, GYROCAL_TUNE_TAG, GYRO_STATS_TUNING);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_PRINT_MAG_STATS; // Sets the next state.
- debug_state = GYRO_WAIT_STATE; // First, go to wait state.
- break;
-
- case GYRO_PRINT_MAG_STATS:
- gyroCalDebugPrintData(gyro_cal, GYROCAL_TUNE_TAG, MAG_STATS_TUNING);
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- next_state = GYRO_IDLE; // Sets the next state.
- debug_state = GYRO_WAIT_STATE; // First, go to wait state.
- break;
-
- default:
- // Sends this state machine to its idle state.
- wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
- debug_state = GYRO_IDLE;
+ gyro_cal->wait_timer_nanos = timestamp_nanos; // Starts the wait timer.
+ gyro_cal->debug_state = GYRO_IDLE; // Go to idle state.
}
}
-#endif // GYRO_CAL_DBG_TUNE_ENABLED
#endif // GYRO_CAL_DBG_ENABLED
diff --git a/firmware/os/algos/calibration/gyroscope/gyro_cal.h b/firmware/os/algos/calibration/gyroscope/gyro_cal.h
index cd96676..5e7d5ee 100644
--- a/firmware/os/algos/calibration/gyroscope/gyro_cal.h
+++ b/firmware/os/algos/calibration/gyroscope/gyro_cal.h
@@ -35,7 +35,6 @@
* - Temperature [Celsius]
*
* #define GYRO_CAL_DBG_ENABLED to enable debug printout statements.
- * #define GYRO_CAL_DBG_TUNE_ENABLED to periodically printout sensor variance
* data to assist in tuning the GyroCal parameters.
*/
@@ -80,15 +79,30 @@
float mag_var[3];
float gyro_winmean_min[3];
float gyro_winmean_max[3];
- float temperature_min_max_celsius[2]; // 0=min; 1=max
+ float temperature_min_celsius;
+ float temperature_max_celsius;
float temperature_mean_celsius;
bool using_mag_sensor;
};
+
+// Data structure for sample rate estimation.
+struct SampleRateData {
+ uint64_t last_timestamp_nanos;
+ uint64_t time_delta_accumulator;
+ size_t num_samples;
+};
#endif // GYRO_CAL_DBG_ENABLED
+// Data structure for tracking min/max window mean during device stillness.
+struct MinMaxWindowMeanData {
+ float gyro_winmean_min[3];
+ float gyro_winmean_max[3];
+};
+
// Data structure for tracking temperature data during device stillness.
struct TemperatureMeanData {
- float temperature_min_max_celsius[2];
+ float temperature_min_celsius;
+ float temperature_max_celsius;
float latest_temperature_celsius;
float mean_accumulator;
size_t num_points;
@@ -103,6 +117,9 @@
// Data for tracking temperature mean during periods of device stillness.
struct TemperatureMeanData temperature_mean_tracker;
+ // Data for tracking gyro mean during periods of device stillness.
+ struct MinMaxWindowMeanData window_mean_tracker;
+
// Aggregated sensor stillness threshold required for gyro bias calibration.
float stillness_threshold;
@@ -166,6 +183,11 @@
// Debug info.
struct DebugGyroCal debug_gyro_cal; // Debug data structure.
enum GyroCalDebugState debug_state; // Debug printout state machine.
+ enum GyroCalDebugState next_state; // Debug state machine next state.
+ uint64_t wait_timer_nanos; // Debug message throttle timer.
+
+ struct SampleRateData sample_rate_estimator; // Debug sample rate estimator.
+
size_t debug_calibration_count; // Total number of cals performed.
size_t debug_watchdog_count; // Total number of watchdog timeouts.
bool debug_print_trigger; // Flag used to trigger data printout.
diff --git a/firmware/os/algos/calibration/magnetometer/mag_cal.c b/firmware/os/algos/calibration/magnetometer/mag_cal.c
index 1fb7630..7f8e563 100644
--- a/firmware/os/algos/calibration/magnetometer/mag_cal.c
+++ b/firmware/os/algos/calibration/magnetometer/mag_cal.c
@@ -71,7 +71,10 @@
float evmin = (eigenvals.x < eigenvals.y) ? eigenvals.x : eigenvals.y;
evmin = (eigenvals.z < evmin) ? eigenvals.z : evmin;
- float evmag = sqrtf(eigenvals.x + eigenvals.y + eigenvals.z);
+ float eigenvals_sum = eigenvals.x + eigenvals.y + eigenvals.z;
+
+ // Testing for negative number.
+ float evmag = (eigenvals_sum > 0) ? sqrtf(eigenvals_sum) : 0;
int eigen_pass = (evmin * MAX_EIGEN_RATIO > evmax) &&
(evmag > MIN_EIGEN_MAG) && (evmag < MAX_EIGEN_MAG);
@@ -119,7 +122,8 @@
initVec3(&v, out.x, out.y, out.z);
vec3ScalarMul(&v, -0.5f);
- float r = sqrtf(vec3Dot(&v, &v) - out.w);
+ float r_square = vec3Dot(&v, &v) - out.w;
+ float r = (r_square > 0) ? sqrtf(r_square) : 0;
initVec3(bias, v.x, v.y, v.z);
*radius = r;
diff --git a/firmware/os/algos/calibration/over_temp/over_temp_cal.c b/firmware/os/algos/calibration/over_temp/over_temp_cal.c
index 254dd7b..d92f1da 100644
--- a/firmware/os/algos/calibration/over_temp/over_temp_cal.c
+++ b/firmware/os/algos/calibration/over_temp/over_temp_cal.c
@@ -22,7 +22,7 @@
#include <string.h>
#include "calibration/util/cal_log.h"
-#include "common/math/vec.h"
+#include "common/math/macros.h"
#include "util/nano_assert.h"
/////// DEFINITIONS AND MACROS ////////////////////////////////////////////////
@@ -32,9 +32,17 @@
// Defines the default weighting function for the linear model fit routine.
// Weighting = 10.0; for offsets newer than 5 minutes.
-#define OTC_WEIGHT_DEFINITION_0 0, 300000000000, 10.0f
+static const struct OverTempCalWeightPt kOtcDefaultWeight0 = {
+ .offset_age_nanos = MIN_TO_NANOS(5),
+ .weight = 10.0f,
+};
+
// Weighting = 0.1; for offsets newer than 15 minutes.
-#define OTC_WEIGHT_DEFINITION_1 1, 900000000000, 0.1f
+static const struct OverTempCalWeightPt kOtcDefaultWeight1 = {
+ .offset_age_nanos = MIN_TO_NANOS(15),
+ .weight = 0.1f,
+};
+
// The default weighting used for all older offsets.
#define OTC_MIN_WEIGHT_VALUE (0.04f)
@@ -42,11 +50,11 @@
// A debug version label to help with tracking results.
#define OTC_DEBUG_VERSION_STRING "[July 05, 2017]"
-// The time value used to throttle debug messaging (100msec).
-#define OTC_WAIT_TIME_NANOS (100000000)
+// The time interval used to throttle debug messaging (100msec).
+#define OTC_WAIT_TIME_NANOS (SEC_TO_NANOS(0.1))
-// The time value used to throttle temperture print messaging (1 second).
-#define OTC_PRINT_TEMP_NANOS (1000000000)
+// The time interval used to throttle temperture print messaging (1 second).
+#define OTC_PRINT_TEMP_NANOS (SEC_TO_NANOS(1))
// Sensor axis label definition with index correspondence: 0=X, 1=Y, 2=Z.
static const char kDebugAxisLabel[3] = "XYZ";
@@ -166,80 +174,25 @@
size_t axis_index, float temperature_celsius);
// Sets the OTC model parameters to an "initialized" state.
-static void resetOtcLinearModel(struct OverTempCal *over_temp_cal) {
- ASSERT_NOT_NULL(over_temp_cal);
-
- // Sets the temperature sensitivity model parameters to
- // OTC_INITIAL_SENSITIVITY to indicate that the model is in an "initial"
- // state.
- over_temp_cal->temp_sensitivity[0] = OTC_INITIAL_SENSITIVITY;
- over_temp_cal->temp_sensitivity[1] = OTC_INITIAL_SENSITIVITY;
- over_temp_cal->temp_sensitivity[2] = OTC_INITIAL_SENSITIVITY;
- memset(over_temp_cal->sensor_intercept, 0, 3 * sizeof(float));
-}
+static void resetOtcLinearModel(struct OverTempCal *over_temp_cal);
// Checks that the input temperature value is within the valid range. If outside
// of range, then 'temperature_celsius' is coerced to within the limits.
-static bool checkAndEnforceTemperatureRange(float *temperature_celsius) {
- if (*temperature_celsius > OTC_TEMP_MAX_CELSIUS) {
- *temperature_celsius = OTC_TEMP_MAX_CELSIUS;
- return false;
- }
- if (*temperature_celsius < OTC_TEMP_MIN_CELSIUS) {
- *temperature_celsius = OTC_TEMP_MIN_CELSIUS;
- return false;
- }
- return true;
-}
+static bool checkAndEnforceTemperatureRange(float *temperature_celsius);
// Returns "true" if the candidate linear model parameters are within the valid
// range, and not all zeros.
static bool isValidOtcLinearModel(const struct OverTempCal *over_temp_cal,
- float temp_sensitivity, float sensor_intercept) {
- ASSERT_NOT_NULL(over_temp_cal);
-
- return NANO_ABS(temp_sensitivity) < over_temp_cal->temp_sensitivity_limit &&
- NANO_ABS(sensor_intercept) < over_temp_cal->sensor_intercept_limit &&
- NANO_ABS(temp_sensitivity) > OTC_MODELDATA_NEAR_ZERO_TOL &&
- NANO_ABS(sensor_intercept) > OTC_MODELDATA_NEAR_ZERO_TOL;
-}
+ float temp_sensitivity, float sensor_intercept);
// Returns "true" if 'offset' and 'offset_temp_celsius' is valid.
-static bool isValidOtcOffset(const float *offset, float offset_temp_celsius) {
- ASSERT_NOT_NULL(offset);
-
- // Simple check to ensure that:
- // 1. All of the input data is non "zero".
- // 2. The offset temperature is within the valid range.
- if (NANO_ABS(offset[0]) < OTC_MODELDATA_NEAR_ZERO_TOL &&
- NANO_ABS(offset[1]) < OTC_MODELDATA_NEAR_ZERO_TOL &&
- NANO_ABS(offset[2]) < OTC_MODELDATA_NEAR_ZERO_TOL &&
- NANO_ABS(offset_temp_celsius) < OTC_MODELDATA_NEAR_ZERO_TOL) {
- return false;
- }
-
- // Only returns the "check" result. Don't care about coercion.
- return checkAndEnforceTemperatureRange(&offset_temp_celsius);
-}
+static bool isValidOtcOffset(const float *offset, float offset_temp_celsius);
// Returns the least-squares weight based on the age of a particular offset
// estimate.
static float evaluateWeightingFunction(const struct OverTempCal *over_temp_cal,
uint64_t offset_timestamp_nanos,
- uint64_t current_timestamp_nanos) {
- ASSERT_NOT_NULL(over_temp_cal);
- size_t i;
- for (i = 0; i < OTC_NUM_WEIGHT_LEVELS; i++) {
- if (current_timestamp_nanos <=
- offset_timestamp_nanos +
- over_temp_cal->weighting_function[i].offset_age_nanos) {
- return over_temp_cal->weighting_function[i].weight;
- }
- }
-
- // Returning the default weight for all older offsets.
- return OTC_MIN_WEIGHT_VALUE;
-}
+ uint64_t current_timestamp_nanos);
// Updates 'compensated_offset' using the linear OTC model.
static void compensateWithLinearModel(struct OverTempCal *over_temp_cal,
@@ -292,14 +245,7 @@
// new_debug_tag = "INIT]"
// Output: "[OVER_TEMP_CAL:INIT]"
static void createDebugTag(struct OverTempCal *over_temp_cal,
- const char *new_debug_tag) {
- over_temp_cal->otc_debug_tag[0] = '[';
- memcpy(over_temp_cal->otc_debug_tag + 1, over_temp_cal->otc_sensor_tag,
- strlen(over_temp_cal->otc_sensor_tag));
- memcpy(
- over_temp_cal->otc_debug_tag + strlen(over_temp_cal->otc_sensor_tag) + 1,
- new_debug_tag, strlen(new_debug_tag) + 1);
-}
+ const char *new_debug_tag);
#endif // OVERTEMPCAL_DBG_ENABLED
/////// FUNCTION DEFINITIONS //////////////////////////////////////////////////
@@ -342,13 +288,13 @@
OTC_TEMP_INVALID_CELSIUS;
// Defines the default weighting function for the linear model fit routine.
- overTempSetWeightingFunction(over_temp_cal, OTC_WEIGHT_DEFINITION_0);
- overTempSetWeightingFunction(over_temp_cal, OTC_WEIGHT_DEFINITION_1);
+ overTempSetWeightingFunction(over_temp_cal, 0, &kOtcDefaultWeight0);
+ overTempSetWeightingFunction(over_temp_cal, 1, &kOtcDefaultWeight1);
#ifdef OVERTEMPCAL_DBG_ENABLED
// Sets the default sensor descriptors for debugging.
overTempCalDebugDescriptors(over_temp_cal, "OVER_TEMP_CAL", "mDPS",
- 1e3f * 180.0f / NANO_PI);
+ RAD_TO_MDEG);
createDebugTag(over_temp_cal, ":INIT]");
if (over_temp_cal->over_temp_enable) {
@@ -376,8 +322,7 @@
// Sets the model parameters if they are within the acceptable limits.
// Includes a check to reject input model parameters that may have been passed
// in as all zeros.
- size_t i;
- for (i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (isValidOtcLinearModel(over_temp_cal, temp_sensitivity[i],
sensor_intercept[i])) {
over_temp_cal->temp_sensitivity[i] = temp_sensitivity[i];
@@ -394,7 +339,8 @@
// Checks that the new offset data is valid.
if (isValidOtcOffset(offset, offset_temp_celsius)) {
// Sets the initial over-temp calibration estimate.
- memcpy(over_temp_cal->model_data[0].offset, offset, 3 * sizeof(float));
+ memcpy(over_temp_cal->model_data[0].offset, offset,
+ sizeof(over_temp_cal->model_data[0].offset));
over_temp_cal->model_data[0].offset_temp_celsius = offset_temp_celsius;
over_temp_cal->model_data[0].timestamp_nanos = timestamp_nanos;
over_temp_cal->num_model_pts = 1;
@@ -412,7 +358,8 @@
// If the new offset is valid, then it will be used as the current compensated
// offset, otherwise the current value will be kept.
if (isValidOtcOffset(offset, offset_temp_celsius)) {
- memcpy(over_temp_cal->compensated_offset.offset, offset, 3 * sizeof(float));
+ memcpy(over_temp_cal->compensated_offset.offset, offset,
+ sizeof(over_temp_cal->compensated_offset.offset));
over_temp_cal->compensated_offset.offset_temp_celsius = offset_temp_celsius;
over_temp_cal->compensated_offset.timestamp_nanos = timestamp_nanos;
}
@@ -430,7 +377,8 @@
createDebugTag(over_temp_cal, ":SET MODEL]");
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
- "Offset|Temp [%s|C]: %s%d.%03d, %s%d.%03d, %s%d.%03d | %s%d.%03d",
+ "Offset|Temp [%s|C]: " CAL_FORMAT_3DIGITS_TRIPLET
+ " | " CAL_FORMAT_3DIGITS,
over_temp_cal->otc_unit_tag,
CAL_ENCODE_FLOAT(offset[0] * over_temp_cal->otc_unit_conversion, 3),
CAL_ENCODE_FLOAT(offset[1] * over_temp_cal->otc_unit_conversion, 3),
@@ -439,8 +387,8 @@
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
- "Sensitivity|Intercept [%s/C|%s]: %s%d.%03d, %s%d.%03d, %s%d.%03d | "
- "%s%d.%03d, %s%d.%03d, %s%d.%03d",
+ "Sensitivity|Intercept [%s/C|%s]: " CAL_FORMAT_3DIGITS_TRIPLET
+ " | " CAL_FORMAT_3DIGITS_TRIPLET,
over_temp_cal->otc_unit_tag, over_temp_cal->otc_unit_tag,
CAL_ENCODE_FLOAT(temp_sensitivity[0] * over_temp_cal->otc_unit_conversion,
3),
@@ -475,8 +423,10 @@
ASSERT_NOT_NULL(sensor_intercept);
// Gets the latest over-temp calibration model data.
- memcpy(temp_sensitivity, over_temp_cal->temp_sensitivity, 3 * sizeof(float));
- memcpy(sensor_intercept, over_temp_cal->sensor_intercept, 3 * sizeof(float));
+ memcpy(temp_sensitivity, over_temp_cal->temp_sensitivity,
+ sizeof(over_temp_cal->temp_sensitivity));
+ memcpy(sensor_intercept, over_temp_cal->sensor_intercept,
+ sizeof(over_temp_cal->sensor_intercept));
*timestamp_nanos = over_temp_cal->last_model_update_nanos;
// Gets the latest temperature compensated offset estimate.
@@ -491,9 +441,8 @@
// Load only "good" data from the input 'model_data'.
over_temp_cal->num_model_pts = NANO_MIN(data_length, OTC_MODEL_SIZE);
- size_t i;
size_t valid_data_count = 0;
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
+ for (size_t i = 0; i < over_temp_cal->num_model_pts; i++) {
if (isValidOtcOffset(model_data[i].offset,
model_data[i].offset_temp_celsius)) {
memcpy(&over_temp_cal->model_data[i], &model_data[i],
@@ -553,7 +502,7 @@
float *compensated_offset_temperature_celsius,
float *compensated_offset) {
memcpy(compensated_offset, over_temp_cal->compensated_offset.offset,
- 3 * sizeof(float));
+ sizeof(over_temp_cal->compensated_offset.offset));
*compensated_offset_temperature_celsius =
over_temp_cal->compensated_offset.offset_temp_celsius;
}
@@ -638,7 +587,7 @@
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
"Offset|Temperature|Time [%s|C|nsec]: "
- "%s%d.%03d, %s%d.%03d, %s%d.%03d, %s%d.%03d, %llu",
+ CAL_FORMAT_3DIGITS_TRIPLET ", " CAL_FORMAT_3DIGITS ", %llu",
over_temp_cal->otc_unit_tag,
CAL_ENCODE_FLOAT(offset[0] * over_temp_cal->otc_unit_conversion, 3),
CAL_ENCODE_FLOAT(offset[1] * over_temp_cal->otc_unit_conversion, 3),
@@ -674,8 +623,7 @@
// Check condition:
// temp_lo_check <= model_data[i].offset_temp_celsius < temp_hi_check
bool replaced_one = false;
- size_t i = 0;
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
+ for (size_t i = 0; i < over_temp_cal->num_model_pts; i++) {
if (over_temp_cal->model_data[i].offset_temp_celsius < temp_hi_check &&
over_temp_cal->model_data[i].offset_temp_celsius >= temp_lo_check) {
// NOTE - The pointer to the new model data point is set here; the offset
@@ -688,7 +636,7 @@
// NOTE - The pointer to the new model data point is set here; the offset
// data is set below in the call to 'setLatestEstimate'.
- if (!replaced_one && over_temp_cal->num_model_pts < OTC_MODEL_SIZE) {
+ if (!replaced_one) {
if (over_temp_cal->num_model_pts < OTC_MODEL_SIZE) {
// 3) If nothing was replaced, and the 'model_data' buffer is not full
// then add the estimate data to the array.
@@ -699,7 +647,7 @@
// 4) Otherwise (nothing was replaced and buffer is full), replace the
// oldest data with the incoming one.
over_temp_cal->latest_offset = &over_temp_cal->model_data[0];
- for (i = 1; i < over_temp_cal->num_model_pts; i++) {
+ for (size_t i = 1; i < over_temp_cal->num_model_pts; i++) {
if (over_temp_cal->latest_offset->timestamp_nanos <
over_temp_cal->model_data[i].timestamp_nanos) {
over_temp_cal->latest_offset = &over_temp_cal->model_data[i];
@@ -757,7 +705,7 @@
// Prints out temperature and the current timestamp.
createDebugTag(over_temp_cal, ":TEMP]");
CAL_DEBUG_LOG(over_temp_cal->otc_debug_tag,
- "Temperature|Time [C|nsec] = %s%d.%03d, %llu",
+ "Temperature|Time [C|nsec] = " CAL_FORMAT_3DIGITS ", %llu",
CAL_ENCODE_FLOAT(temperature_celsius, 3),
(unsigned long long int)timestamp_nanos);
}
@@ -805,13 +753,11 @@
ASSERT_NOT_NULL(sensor_intercept);
ASSERT_NOT_NULL(max_error);
- size_t i;
- size_t j;
float max_error_test;
memset(max_error, 0, 3 * sizeof(float));
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
- for (j = 0; j < 3; j++) {
+ for (size_t i = 0; i < over_temp_cal->num_model_pts; i++) {
+ for (size_t j = 0; j < 3; j++) {
max_error_test =
NANO_ABS(over_temp_cal->model_data[i].offset[j] -
(temp_sensitivity[j] *
@@ -824,16 +770,13 @@
}
}
-// TODO: Refactor to implement a compliance check on the storage of
+// TODO(davejacobs): Refactor to implement a compliance check on the storage of
// 'offset_age_nanos' to ensure a monotonically increasing order with index.
-void overTempSetWeightingFunction(struct OverTempCal *over_temp_cal,
- size_t index,
- uint64_t offset_age_nanos,
- float weight) {
+void overTempSetWeightingFunction(
+ struct OverTempCal *over_temp_cal, size_t index,
+ const struct OverTempCalWeightPt *new_otc_weight) {
if (index < OTC_NUM_WEIGHT_LEVELS) {
- over_temp_cal->weighting_function[index].offset_age_nanos =
- offset_age_nanos;
- over_temp_cal->weighting_function[index].weight = weight;
+ over_temp_cal->weighting_function[index] = *new_otc_weight;
}
}
@@ -847,10 +790,9 @@
// Defaults to using the current compensated offset value.
float compensated_offset[3];
memcpy(compensated_offset, over_temp_cal->compensated_offset.offset,
- 3 * sizeof(float));
+ sizeof(over_temp_cal->compensated_offset.offset));
- size_t index;
- for (index = 0; index < 3; index++) {
+ for (size_t index = 0; index < 3; index++) {
if (over_temp_cal->temp_sensitivity[index] < OTC_INITIAL_SENSITIVITY) {
// If a valid axis model is defined then the default compensation will
// use the linear model:
@@ -875,8 +817,7 @@
// Adds a delta term to the 'compensated_offset' using the temperature
// difference defined by 'delta_temp_celsius'.
- size_t index;
- for (index = 0; index < 3; index++) {
+ for (size_t index = 0; index < 3; index++) {
if (over_temp_cal->temp_sensitivity[index] < OTC_INITIAL_SENSITIVITY) {
// If a valid axis model is defined, then use the linear model to assist
// with computing an extrapolated compensation term.
@@ -894,7 +835,7 @@
// Uses the most recent offset estimate for offset compensation.
float compensated_offset[3];
- memcpy(compensated_offset, estimate->offset, 3 * sizeof(float));
+ memcpy(compensated_offset, estimate->offset, sizeof(compensated_offset));
// Checks that the offset temperature is valid.
if (estimate->offset_temp_celsius > OTC_TEMP_INVALID_CELSIUS) {
@@ -922,12 +863,11 @@
// The default compensated offset is the nearest-temperature offset vector.
float compensated_offset[3];
memcpy(compensated_offset, over_temp_cal->nearest_offset->offset,
- 3 * sizeof(float));
+ sizeof(compensated_offset));
const float compensated_offset_temperature_celsius =
over_temp_cal->nearest_offset->offset_temp_celsius;
- size_t index;
- for (index = 0; index < 3; index++) {
+ for (size_t index = 0; index < 3; index++) {
if (over_temp_cal->temp_sensitivity[index] < OTC_INITIAL_SENSITIVITY) {
// If a valid axis model is defined, then use the linear model to assist
// with computing an extrapolated compensation term.
@@ -1099,9 +1039,8 @@
// If the 'compensated_offset' value has changed significantly, then set
// 'new_overtemp_offset_available' true.
- size_t i;
bool new_overtemp_offset_available = false;
- for (i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (NANO_ABS(over_temp_cal->compensated_offset.offset[i] -
compensated_offset[i]) >=
over_temp_cal->significant_offset_change) {
@@ -1115,7 +1054,7 @@
// vector and timestamp are updated.
if (new_overtemp_offset_available) {
memcpy(over_temp_cal->compensated_offset.offset, compensated_offset,
- 3 * sizeof(float));
+ sizeof(over_temp_cal->compensated_offset.offset));
over_temp_cal->compensated_offset.timestamp_nanos = timestamp_nanos;
over_temp_cal->compensated_offset.offset_temp_celsius = temperature_celsius;
}
@@ -1128,7 +1067,8 @@
if (over_temp_cal->latest_offset) {
// Sets the latest over-temp calibration estimate.
- memcpy(over_temp_cal->latest_offset->offset, offset, 3 * sizeof(float));
+ memcpy(over_temp_cal->latest_offset->offset, offset,
+ sizeof(over_temp_cal->latest_offset->offset));
over_temp_cal->latest_offset->offset_temp_celsius = offset_temp_celsius;
over_temp_cal->latest_offset->timestamp_nanos = timestamp_nanos;
}
@@ -1178,9 +1118,8 @@
// set. Otherwise, a lockout condition could occur where the entire model
// data set would need to be replaced in order to bring the model fit error
// below the error limit and allow a successful model update.
- size_t i;
bool updated_one = false;
- for (i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (isValidOtcLinearModel(over_temp_cal, temp_sensitivity[i],
sensor_intercept[i])) {
over_temp_cal->temp_sensitivity[i] = temp_sensitivity[i];
@@ -1191,7 +1130,8 @@
createDebugTag(over_temp_cal, ":REJECT]");
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
- "%c-Axis Parameters|Time [%s/C|%s|nsec]: %s%d.%03d, %s%d.%03d, %llu",
+ "%c-Axis Parameters|Time [%s/C|%s|nsec]: " CAL_FORMAT_3DIGITS
+ ", " CAL_FORMAT_3DIGITS ", %llu",
kDebugAxisLabel[i], over_temp_cal->otc_unit_tag,
over_temp_cal->otc_unit_tag,
CAL_ENCODE_FLOAT(
@@ -1227,11 +1167,10 @@
// Performs a brute force search for the estimate nearest
// 'temperature_celsius'.
- size_t i = 0;
float dtemp_new = 0.0f;
float dtemp_old = FLT_MAX;
over_temp_cal->nearest_offset = &over_temp_cal->model_data[0];
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
+ for (size_t i = 0; i < over_temp_cal->num_model_pts; i++) {
dtemp_new = NANO_ABS(over_temp_cal->model_data[i].offset_temp_celsius -
temperature_celsius);
if (dtemp_new < dtemp_old) {
@@ -1245,9 +1184,8 @@
uint64_t timestamp_nanos) {
ASSERT_NOT_NULL(over_temp_cal);
- size_t i;
bool removed_one = false;
- for (i = 0; i < over_temp_cal->num_model_pts; i++) {
+ for (size_t i = 0; i < over_temp_cal->num_model_pts; i++) {
if (timestamp_nanos > over_temp_cal->model_data[i].timestamp_nanos &&
timestamp_nanos > over_temp_cal->age_limit_nanos +
over_temp_cal->model_data[i].timestamp_nanos) {
@@ -1285,8 +1223,8 @@
createDebugTag(over_temp_cal, ":REMOVE]");
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
- "Offset|Temp|Time [%s|C|nsec]: %s%d.%03d, %s%d.%03d, %s%d.%03d, "
- "%s%d.%03d, %llu",
+ "Offset|Temp|Time [%s|C|nsec]: " CAL_FORMAT_3DIGITS_TRIPLET
+ ", " CAL_FORMAT_3DIGITS ", %llu",
over_temp_cal->otc_unit_tag,
CAL_ENCODE_FLOAT(over_temp_cal->model_data[model_index].offset[0] *
over_temp_cal->otc_unit_conversion,
@@ -1304,8 +1242,7 @@
#endif // OVERTEMPCAL_DBG_ENABLED
// Remove the model data at 'model_index'.
- size_t i;
- for (i = model_index; i < over_temp_cal->num_model_pts - 1; i++) {
+ for (size_t i = model_index; i < over_temp_cal->num_model_pts - 1; i++) {
memcpy(&over_temp_cal->model_data[i], &over_temp_cal->model_data[i + 1],
sizeof(struct OverTempCalDataPt));
}
@@ -1328,8 +1265,7 @@
// complete (i.e., x, y, z values are all provided). Therefore, the jumpstart
// data produced here requires that the model parameters have all been fully
// defined and are all within the valid range.
- size_t i;
- for (i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (!isValidOtcLinearModel(over_temp_cal,
over_temp_cal->temp_sensitivity[i],
over_temp_cal->sensor_intercept[i])) {
@@ -1348,9 +1284,8 @@
float offset_temp_celsius =
(start_bin_num + 0.5f) * over_temp_cal->delta_temp_per_bin;
- size_t j;
- for (i = 0; i < over_temp_cal->min_num_model_pts; i++) {
- for (j = 0; j < 3; j++) {
+ for (size_t i = 0; i < over_temp_cal->min_num_model_pts; i++) {
+ for (size_t j = 0; j < 3; j++) {
over_temp_cal->model_data[i].offset[j] =
over_temp_cal->temp_sensitivity[j] * offset_temp_celsius +
over_temp_cal->sensor_intercept[j];
@@ -1391,8 +1326,7 @@
// First pass computes the weighted mean values.
const size_t n = over_temp_cal->num_model_pts;
- size_t i = 0;
- for (i = 0; i < n; ++i) {
+ for (size_t i = 0; i < n; ++i) {
weight = evaluateWeightingFunction(
over_temp_cal, over_temp_cal->model_data[i].timestamp_nanos,
timestamp_nanos);
@@ -1407,7 +1341,7 @@
// Second pass computes the mean corrected second moment values.
ASSERT(sw > 0.0f);
const float inv_sw = 1.0f / sw;
- for (i = 0; i < n; ++i) {
+ for (size_t i = 0; i < n; ++i) {
weight = evaluateWeightingFunction(
over_temp_cal, over_temp_cal->model_data[i].timestamp_nanos,
timestamp_nanos);
@@ -1453,9 +1387,87 @@
return false;
}
+void resetOtcLinearModel(struct OverTempCal *over_temp_cal) {
+ ASSERT_NOT_NULL(over_temp_cal);
+
+ // Sets the temperature sensitivity model parameters to
+ // OTC_INITIAL_SENSITIVITY to indicate that the model is in an "initial"
+ // state.
+ over_temp_cal->temp_sensitivity[0] = OTC_INITIAL_SENSITIVITY;
+ over_temp_cal->temp_sensitivity[1] = OTC_INITIAL_SENSITIVITY;
+ over_temp_cal->temp_sensitivity[2] = OTC_INITIAL_SENSITIVITY;
+ memset(over_temp_cal->sensor_intercept, 0,
+ sizeof(over_temp_cal->sensor_intercept));
+}
+
+bool checkAndEnforceTemperatureRange(float *temperature_celsius) {
+ if (*temperature_celsius > OTC_TEMP_MAX_CELSIUS) {
+ *temperature_celsius = OTC_TEMP_MAX_CELSIUS;
+ return false;
+ }
+ if (*temperature_celsius < OTC_TEMP_MIN_CELSIUS) {
+ *temperature_celsius = OTC_TEMP_MIN_CELSIUS;
+ return false;
+ }
+ return true;
+}
+
+bool isValidOtcLinearModel(const struct OverTempCal *over_temp_cal,
+ float temp_sensitivity, float sensor_intercept) {
+ ASSERT_NOT_NULL(over_temp_cal);
+
+ return NANO_ABS(temp_sensitivity) < over_temp_cal->temp_sensitivity_limit &&
+ NANO_ABS(sensor_intercept) < over_temp_cal->sensor_intercept_limit &&
+ NANO_ABS(temp_sensitivity) > OTC_MODELDATA_NEAR_ZERO_TOL &&
+ NANO_ABS(sensor_intercept) > OTC_MODELDATA_NEAR_ZERO_TOL;
+}
+
+bool isValidOtcOffset(const float *offset, float offset_temp_celsius) {
+ ASSERT_NOT_NULL(offset);
+
+ // Simple check to ensure that:
+ // 1. All of the input data is non "zero".
+ // 2. The offset temperature is within the valid range.
+ if (NANO_ABS(offset[0]) < OTC_MODELDATA_NEAR_ZERO_TOL &&
+ NANO_ABS(offset[1]) < OTC_MODELDATA_NEAR_ZERO_TOL &&
+ NANO_ABS(offset[2]) < OTC_MODELDATA_NEAR_ZERO_TOL &&
+ NANO_ABS(offset_temp_celsius) < OTC_MODELDATA_NEAR_ZERO_TOL) {
+ return false;
+ }
+
+ // Only returns the "check" result. Don't care about coercion.
+ return checkAndEnforceTemperatureRange(&offset_temp_celsius);
+}
+
+float evaluateWeightingFunction(const struct OverTempCal *over_temp_cal,
+ uint64_t offset_timestamp_nanos,
+ uint64_t current_timestamp_nanos) {
+ ASSERT_NOT_NULL(over_temp_cal);
+ for (size_t i = 0; i < OTC_NUM_WEIGHT_LEVELS; i++) {
+ if (current_timestamp_nanos <=
+ offset_timestamp_nanos +
+ over_temp_cal->weighting_function[i].offset_age_nanos) {
+ return over_temp_cal->weighting_function[i].weight;
+ }
+ }
+
+ // Returning the default weight for all older offsets.
+ return OTC_MIN_WEIGHT_VALUE;
+}
+
/////// DEBUG FUNCTION DEFINITIONS ////////////////////////////////////////////
#ifdef OVERTEMPCAL_DBG_ENABLED
+void createDebugTag(struct OverTempCal *over_temp_cal,
+ const char *new_debug_tag) {
+ over_temp_cal->otc_debug_tag[0] = '[';
+ memcpy(over_temp_cal->otc_debug_tag + 1, over_temp_cal->otc_sensor_tag,
+ strlen(over_temp_cal->otc_sensor_tag));
+ memcpy(
+ over_temp_cal->otc_debug_tag + strlen(over_temp_cal->otc_sensor_tag) + 1,
+ new_debug_tag, strlen(new_debug_tag) + 1);
+}
+
void updateDebugData(struct OverTempCal* over_temp_cal) {
ASSERT_NOT_NULL(over_temp_cal);
@@ -1473,8 +1485,7 @@
memset(&over_temp_cal->debug_overtempcal, 0, sizeof(struct DebugOverTempCal));
// Copies over the relevant data.
- size_t i;
- for (i = 0; i < 3; i++) {
+ for (size_t i = 0; i < 3; i++) {
if (isValidOtcLinearModel(over_temp_cal, over_temp_cal->temp_sensitivity[i],
over_temp_cal->sensor_intercept[i])) {
over_temp_cal->debug_overtempcal.temp_sensitivity[i] =
@@ -1543,8 +1554,8 @@
// Prints out the latest offset estimate (input data).
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
- "Cal#|Offset|Temp|Time [%s|C|nsec]: %lu, %s%d.%03d, "
- "%s%d.%03d, %s%d.%03d, %s%d.%03d, %llu",
+ "Cal#|Offset|Temp|Time [%s|C|nsec]: %lu, " CAL_FORMAT_3DIGITS_TRIPLET
+ ", " CAL_FORMAT_3DIGITS ", %llu",
over_temp_cal->otc_unit_tag,
(unsigned long int)over_temp_cal->debug_num_estimates,
CAL_ENCODE_FLOAT(
@@ -1576,7 +1587,7 @@
// Prints out the model parameters.
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
- "Cal#|Sensitivity [%s/C]: %lu, %s%d.%03d, %s%d.%03d, %s%d.%03d",
+ "Cal#|Sensitivity [%s/C]: %lu, " CAL_FORMAT_3DIGITS_TRIPLET,
over_temp_cal->otc_unit_tag,
(unsigned long int)over_temp_cal->debug_num_estimates,
CAL_ENCODE_FLOAT(
@@ -1593,7 +1604,7 @@
3));
CAL_DEBUG_LOG(over_temp_cal->otc_debug_tag,
- "Cal#|Intercept [%s]: %lu, %s%d.%03d, %s%d.%03d, %s%d.%03d",
+ "Cal#|Intercept [%s]: %lu, " CAL_FORMAT_3DIGITS_TRIPLET,
over_temp_cal->otc_unit_tag,
(unsigned long int)over_temp_cal->debug_num_estimates,
CAL_ENCODE_FLOAT(
@@ -1620,7 +1631,7 @@
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
"Cal#|#Updates|#ModelPts|Model Error [%s]: %lu, "
- "%lu, %lu, %s%d.%03d, %s%d.%03d, %s%d.%03d",
+ "%lu, %lu, " CAL_FORMAT_3DIGITS_TRIPLET,
over_temp_cal->otc_unit_tag,
(unsigned long int)over_temp_cal->debug_num_estimates,
(unsigned long int)over_temp_cal->debug_num_model_updates,
@@ -1647,8 +1658,8 @@
if (over_temp_cal->model_counter < over_temp_cal->num_model_pts) {
CAL_DEBUG_LOG(
over_temp_cal->otc_debug_tag,
- " Model[%lu] [%s|C|nsec] = %s%d.%03d, %s%d.%03d, %s%d.%03d, "
- "%s%d.%03d, %llu",
+ " Model[%lu] [%s|C|nsec] = " CAL_FORMAT_3DIGITS_TRIPLET
+ ", " CAL_FORMAT_3DIGITS ", %llu",
(unsigned long int)over_temp_cal->model_counter,
over_temp_cal->otc_unit_tag,
CAL_ENCODE_FLOAT(
diff --git a/firmware/os/algos/calibration/over_temp/over_temp_cal.h b/firmware/os/algos/calibration/over_temp/over_temp_cal.h
index 81b2173..8a404d3 100644
--- a/firmware/os/algos/calibration/over_temp/over_temp_cal.h
+++ b/firmware/os/algos/calibration/over_temp/over_temp_cal.h
@@ -130,17 +130,26 @@
#define OTC_NUM_WEIGHT_LEVELS (2)
// Rate-limits the check of old data to every 2 hours.
-#define OTC_STALE_CHECK_TIME_NANOS (7200000000000)
+#define OTC_STALE_CHECK_TIME_NANOS (HRS_TO_NANOS(2))
// Time duration in which to enforce using the last offset estimate for
// compensation (30 seconds).
-#define OTC_USE_RECENT_OFFSET_TIME_NANOS (30000000000)
+#define OTC_USE_RECENT_OFFSET_TIME_NANOS (SEC_TO_NANOS(30))
// The age at which an offset estimate is considered stale (30 minutes).
-#define OTC_OFFSET_IS_STALE_NANOS (1800000000000)
+#define OTC_OFFSET_IS_STALE_NANOS (MIN_TO_NANOS(30))
// The refresh interval for the OTC model (30 seconds).
-#define OTC_REFRESH_MODEL_NANOS (30000000000)
+#define OTC_REFRESH_MODEL_NANOS (SEC_TO_NANOS(30))
+
+// Defines a weighting function value for the linear model fit routine.
+struct OverTempCalWeightPt {
+ // The age limit below which an offset will use this weight value.
+ uint64_t offset_age_nanos;
+
+ // The weighting applied (>0).
+ float weight;
+};
// Over-temperature sensor offset estimate structure.
struct OverTempCalDataPt {
@@ -150,15 +159,6 @@
float offset[3];
};
-// Weighting data used to improve the quality of the linear model fit.
-struct OverTempCalWeightPt {
- // Offset age below which this weight applies.
- uint64_t offset_age_nanos;
-
- // Weighting value for offset estimates more recent than 'offset_age_nanos'.
- float weight;
-};
-
#ifdef OVERTEMPCAL_DBG_ENABLED
// Debug printout state enumeration.
enum OverTempCalDebugState {
@@ -532,14 +532,13 @@
* INPUTS:
* over_temp_cal: Over-temp data structure.
* index: Weighting function index.
- * offset_age_nanos: The age limit below which an offset will use this weight
- * value.
- * weight: The weighting applied (>0).
+ * new_otc_weight: Pointer to the settings for the new non-zero weighting
+ * value and corresponding age limit below which an offset
+ * will use the weight.
*/
-void overTempSetWeightingFunction(struct OverTempCal *over_temp_cal,
- size_t index,
- uint64_t offset_age_nanos,
- float weight);
+void overTempSetWeightingFunction(
+ struct OverTempCal *over_temp_cal, size_t index,
+ const struct OverTempCalWeightPt *new_otc_weight);
#ifdef OVERTEMPCAL_DBG_ENABLED
// This debug printout function assumes the input sensor data is a gyroscope
diff --git a/firmware/os/algos/calibration/util/cal_log.h b/firmware/os/algos/calibration/util/cal_log.h
index f2e711f..1bd80fd 100644
--- a/firmware/os/algos/calibration/util/cal_log.h
+++ b/firmware/os/algos/calibration/util/cal_log.h
@@ -54,6 +54,13 @@
((x < 0) ? "-" : ""), \
(int)CAL_FLOOR(fabsf(x)), (int)((fabsf(x) - CAL_FLOOR(fabsf(x))) * powf(10, num_digits)) // NOLINT
+// Helper definitions for CAL_ENCODE_FLOAT to specify the print format with
+// desired significant digits.
+#define CAL_FORMAT_3DIGITS "%s%d.%03d"
+#define CAL_FORMAT_6DIGITS "%s%d.%06d"
+#define CAL_FORMAT_3DIGITS_TRIPLET "%s%d.%03d, %s%d.%03d, %s%d.%03d"
+#define CAL_FORMAT_6DIGITS_TRIPLET "%s%d.%06d, %s%d.%06d, %s%d.%06d"
+
#ifdef __cplusplus
}
#endif
diff --git a/firmware/os/algos/common/math/levenberg_marquardt.c b/firmware/os/algos/common/math/levenberg_marquardt.c
index 9c179ac..66e423f 100644
--- a/firmware/os/algos/common/math/levenberg_marquardt.c
+++ b/firmware/os/algos/common/math/levenberg_marquardt.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <string.h>
+#include "common/math/macros.h"
#include "common/math/mat.h"
#include "common/math/vec.h"
diff --git a/firmware/os/algos/common/math/macros.h b/firmware/os/algos/common/math/macros.h
new file mode 100644
index 0000000..5c06e24
--- /dev/null
+++ b/firmware/os/algos/common/math/macros.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file contains helper macros and definitions.
+
+#ifndef LOCATION_LBS_CONTEXTHUB_NANOAPPS_COMMON_MATH_MACROS_H_
+#define LOCATION_LBS_CONTEXTHUB_NANOAPPS_COMMON_MATH_MACROS_H_
+
+// Mathematical constants.
+#define NANO_PI (3.14159265359f)
+
+// Common math operations.
+#define NANO_ABS(x) ((x) > 0 ? (x) : -(x))
+#define NANO_MAX(a, b) ((a) > (b)) ? (a) : (b)
+#define NANO_MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+// Timestamp conversion macros.
+#ifdef __cplusplus
+#define MSEC_TO_NANOS(x) (static_cast<uint64_t>(x) * 1000000)
+#else
+#define MSEC_TO_NANOS(x) ((uint64_t)(x) * 1000000) // NOLINT
+#endif
+
+#define SEC_TO_NANOS(x) MSEC_TO_NANOS(x * 1000)
+#define MIN_TO_NANOS(x) SEC_TO_NANOS(x * 60)
+#define HRS_TO_NANOS(x) MIN_TO_NANOS(x * 60)
+#define DAYS_TO_NANOS(x) HRS_TO_NANOS(x * 24)
+
+// Unit conversion: nanoseconds to seconds.
+#define NANOS_TO_SEC (1.0e-9f)
+
+// Unit conversion: milli-degrees to radians.
+#define MDEG_TO_RAD (NANO_PI / 180.0e3f)
+
+// Unit conversion: radians to milli-degrees.
+#define RAD_TO_MDEG (180.0e3f / NANO_PI)
+
+// Time check helper macro that returns true if:
+// i. 't1' is equal to or exceeds 't2' plus 't_delta'.
+// ii. Or, a negative timestamp delta occurred since,
+// 't1' should always >= 't2'. This prevents potential lockout conditions
+// if the timer count 't1' rolls over or an erroneously large
+// timestamp is passed through.
+#define NANO_TIMER_CHECK_T1_GEQUAL_T2_PLUS_DELTA(t1, t2, t_delta) \
+ (((t1) >= (t2) + (t_delta)) || ((t1) < (t2)))
+
+#endif // LOCATION_LBS_CONTEXTHUB_NANOAPPS_COMMON_MATH_MACROS_H_
diff --git a/firmware/os/algos/common/math/vec.c b/firmware/os/algos/common/math/vec.c
index b55ea8e..bb9f929 100644
--- a/firmware/os/algos/common/math/vec.c
+++ b/firmware/os/algos/common/math/vec.c
@@ -15,6 +15,7 @@
*/
#include "common/math/vec.h"
+#include "common/math/macros.h"
void findOrthogonalVector(float inX, float inY, float inZ, float *outX,
float *outY, float *outZ) {
diff --git a/firmware/os/algos/common/math/vec.h b/firmware/os/algos/common/math/vec.h
index 49f197c..0a4c8b3 100644
--- a/firmware/os/algos/common/math/vec.h
+++ b/firmware/os/algos/common/math/vec.h
@@ -53,23 +53,6 @@
float x, y, z, w;
};
-#define NANO_PI (3.14159265359f)
-
-#define NANO_ABS(x) ((x) > 0 ? (x) : -(x))
-
-#define NANO_MAX(a, b) ((a) > (b)) ? (a) : (b)
-
-#define NANO_MIN(a, b) ((a) < (b)) ? (a) : (b)
-
-// Time check helper macro that returns true if:
-// i. 't1' is equal to or exceeds 't2' plus 't_delta'.
-// ii. Or, a negative timestamp delta occurred since,
-// 't1' should always >= 't2'. This prevents potential lockout conditions
-// if the timer count 't1' rolls over or an erroneously large
-// timestamp is passed through.
-#define NANO_TIMER_CHECK_T1_GEQUAL_T2_PLUS_DELTA(t1, t2, t_delta) \
- (((t1) >= (t2) + (t_delta)) || ((t1) < (t2)))
-
// 3-DIMENSIONAL VECTOR MATH ///////////////////////////////////////////
static inline void initVec3(struct Vec3 *v, float x, float y, float z) {
ASSERT_NOT_NULL(v);
diff --git a/firmware/os/core/nanohubCommand.c b/firmware/os/core/nanohubCommand.c
index 439f3dc..79d8804 100644
--- a/firmware/os/core/nanohubCommand.c
+++ b/firmware/os/core/nanohubCommand.c
@@ -1078,7 +1078,7 @@
uint64_t appId;
uint32_t appVer, appSize;
- if (osAppInfoByIndex(le32toh(req->idx), &appId, &appVer, &appSize)) {
+ if (osExtAppInfoByIndex(le32toh(req->idx), &appId, &appVer, &appSize)) {
resp = heapAlloc(sizeof(*resp));
if (resp) {
resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
diff --git a/firmware/os/core/nanohub_chre.c b/firmware/os/core/nanohub_chre.c
index 6dd32d6..b8e6825 100644
--- a/firmware/os/core/nanohub_chre.c
+++ b/firmware/os/core/nanohub_chre.c
@@ -102,7 +102,7 @@
{
uint64_t *timeNanos = va_arg(args, uint64_t *);
if (timeNanos)
- *timeNanos = timGetTime();
+ *timeNanos = sensorGetTime();
}
static inline uint32_t osChreTimerSet(uint64_t duration, const void* cookie, bool oneShot)
diff --git a/firmware/os/core/osApi.c b/firmware/os/core/osApi.c
index 1716f09..8361d9a 100644
--- a/firmware/os/core/osApi.c
+++ b/firmware/os/core/osApi.c
@@ -178,7 +178,7 @@
*retValP = sensorTriggerOndemand(0, sensorHandle);
}
-static void osExpApiSensorGetRate(uintptr_t *retValP, va_list args)
+static void osExpApiSensorGetCurRate(uintptr_t *retValP, va_list args)
{
uint32_t sensorHandle = va_arg(args, uint32_t);
@@ -191,6 +191,13 @@
*timeNanos = sensorGetTime();
}
+static void osExpApiSensorGetReqRate(uintptr_t *retValP, va_list args)
+{
+ uint32_t sensorHandle = va_arg(args, uint32_t);
+
+ *retValP = sensorGetReqRate(sensorHandle);
+}
+
static void osExpApiTimGetTime(uintptr_t *retValP, va_list args)
{
uint64_t *timeNanos = va_arg(args, uint64_t *);
@@ -482,9 +489,9 @@
static const struct SyscallTable osMainEvtqTable = {
.numEntries = SYSCALL_OS_MAIN_EVTQ_LAST,
.entry = {
- [SYSCALL_OS_MAIN_EVTQ_SUBCRIBE] = { .func = osExpApiEvtqSubscribe, },
- [SYSCALL_OS_MAIN_EVTQ_UNSUBCRIBE] = { .func = osExpApiEvtqUnsubscribe, },
- [SYSCALL_OS_MAIN_EVTQ_ENQUEUE] = { .func = osExpApiEvtqEnqueue, },
+ [SYSCALL_OS_MAIN_EVTQ_SUBCRIBE] = { .func = osExpApiEvtqSubscribe, },
+ [SYSCALL_OS_MAIN_EVTQ_UNSUBCRIBE] = { .func = osExpApiEvtqUnsubscribe, },
+ [SYSCALL_OS_MAIN_EVTQ_ENQUEUE] = { .func = osExpApiEvtqEnqueue, },
[SYSCALL_OS_MAIN_EVTQ_ENQUEUE_PRIVATE] = { .func = osExpApiEvtqEnqueuePrivate, },
[SYSCALL_OS_MAIN_EVTQ_RETAIN_EVT] = { .func = osExpApiEvtqRetainEvt, },
[SYSCALL_OS_MAIN_EVTQ_FREE_RETAINED] = { .func = osExpApiEvtqFreeRetained, },
@@ -501,17 +508,18 @@
static const struct SyscallTable osMainSensorsTable = {
.numEntries = SYSCALL_OS_MAIN_SENSOR_LAST,
.entry = {
- [SYSCALL_OS_MAIN_SENSOR_SIGNAL] = { .func = osExpApiSensorSignal, },
- [SYSCALL_OS_MAIN_SENSOR_REG] = { .func = osExpApiSensorReg, },
- [SYSCALL_OS_MAIN_SENSOR_UNREG] = { .func = osExpApiSensorUnreg, },
+ [SYSCALL_OS_MAIN_SENSOR_SIGNAL] = { .func = osExpApiSensorSignal, },
+ [SYSCALL_OS_MAIN_SENSOR_REG] = { .func = osExpApiSensorReg, },
+ [SYSCALL_OS_MAIN_SENSOR_UNREG] = { .func = osExpApiSensorUnreg, },
[SYSCALL_OS_MAIN_SENSOR_REG_INIT_COMP] = { .func = osExpApiSensorRegInitComp },
- [SYSCALL_OS_MAIN_SENSOR_FIND] = { .func = osExpApiSensorFind, },
- [SYSCALL_OS_MAIN_SENSOR_REQUEST] = { .func = osExpApiSensorReq, },
- [SYSCALL_OS_MAIN_SENSOR_RATE_CHG] = { .func = osExpApiSensorRateChg, },
- [SYSCALL_OS_MAIN_SENSOR_RELEASE] = { .func = osExpApiSensorRel, },
- [SYSCALL_OS_MAIN_SENSOR_TRIGGER] = { .func = osExpApiSensorTrigger, },
- [SYSCALL_OS_MAIN_SENSOR_GET_RATE] = { .func = osExpApiSensorGetRate, },
- [SYSCALL_OS_MAIN_SENSOR_GET_TIME] = { .func = osExpApiSensorGetTime, },
+ [SYSCALL_OS_MAIN_SENSOR_FIND] = { .func = osExpApiSensorFind, },
+ [SYSCALL_OS_MAIN_SENSOR_REQUEST] = { .func = osExpApiSensorReq, },
+ [SYSCALL_OS_MAIN_SENSOR_RATE_CHG] = { .func = osExpApiSensorRateChg, },
+ [SYSCALL_OS_MAIN_SENSOR_RELEASE] = { .func = osExpApiSensorRel, },
+ [SYSCALL_OS_MAIN_SENSOR_TRIGGER] = { .func = osExpApiSensorTrigger, },
+ [SYSCALL_OS_MAIN_SENSOR_GET_CUR_RATE] = { .func = osExpApiSensorGetCurRate, },
+ [SYSCALL_OS_MAIN_SENSOR_GET_TIME] = { .func = osExpApiSensorGetTime, },
+ [SYSCALL_OS_MAIN_SENSOR_GET_REQ_RATE] = { .func = osExpApiSensorGetReqRate, },
},
};
@@ -519,9 +527,9 @@
static const struct SyscallTable osMainTimerTable = {
.numEntries = SYSCALL_OS_MAIN_TIME_LAST,
.entry = {
- [SYSCALL_OS_MAIN_TIME_GET_TIME] = { .func = osExpApiTimGetTime, },
- [SYSCALL_OS_MAIN_TIME_SET_TIMER] = { .func = osExpApiTimSetTimer, },
- [SYSCALL_OS_MAIN_TIME_CANCEL_TIMER] = { .func = osExpApiTimCancelTimer, },
+ [SYSCALL_OS_MAIN_TIME_GET_TIME] = { .func = osExpApiTimGetTime, },
+ [SYSCALL_OS_MAIN_TIME_SET_TIMER] = { .func = osExpApiTimSetTimer, },
+ [SYSCALL_OS_MAIN_TIME_CANCEL_TIMER] = { .func = osExpApiTimCancelTimer, },
},
};
@@ -529,17 +537,17 @@
.numEntries = SYSCALL_OS_MAIN_HEAP_LAST,
.entry = {
[SYSCALL_OS_MAIN_HEAP_ALLOC] = { .func = osExpApiHeapAlloc },
- [SYSCALL_OS_MAIN_HEAP_FREE] = { .func = osExpApiHeapFree },
+ [SYSCALL_OS_MAIN_HEAP_FREE] = { .func = osExpApiHeapFree },
},
};
static const struct SyscallTable osMainSlabTable = {
.numEntries = SYSCALL_OS_MAIN_SLAB_LAST,
.entry = {
- [SYSCALL_OS_MAIN_SLAB_NEW] = { .func = osExpApiSlabNew },
+ [SYSCALL_OS_MAIN_SLAB_NEW] = { .func = osExpApiSlabNew },
[SYSCALL_OS_MAIN_SLAB_DESTROY] = { .func = osExpApiSlabDestroy },
- [SYSCALL_OS_MAIN_SLAB_ALLOC] = { .func = osExpApiSlabAlloc },
- [SYSCALL_OS_MAIN_SLAB_FREE] = { .func = osExpApiSlabFree },
+ [SYSCALL_OS_MAIN_SLAB_ALLOC] = { .func = osExpApiSlabAlloc },
+ [SYSCALL_OS_MAIN_SLAB_FREE] = { .func = osExpApiSlabFree },
},
};
diff --git a/firmware/os/core/sensors.c b/firmware/os/core/sensors.c
index 877e0a2..b8caec5 100644
--- a/firmware/os/core/sensors.c
+++ b/firmware/os/core/sensors.c
@@ -526,6 +526,7 @@
if (s && s->currentRate != SENSOR_RATE_OFF && s->currentRate < SENSOR_RATE_POWERING_ON) {
s->currentRate = evt->value1;
s->currentLatency = evt->value2;
+ sensorReconfig(s, sensorCalcHwRate(s, 0, 0), sensorCalcHwLatency(s));
osEnqueueEvtOrFree(sensorGetMyCfgEventType(s->si->sensorType), evt, sensorInternalEvtFreeF);
} else {
slabAllocatorFree(mInternalEvents, evt);
diff --git a/firmware/os/core/seos.c b/firmware/os/core/seos.c
index f220dc3..52ccf7a 100644
--- a/firmware/os/core/seos.c
+++ b/firmware/os/core/seos.c
@@ -1360,6 +1360,28 @@
return false;
}
+bool osExtAppInfoByIndex(uint32_t appIdx, uint64_t *appId, uint32_t *appVer, uint32_t *appSize)
+{
+ struct Task *task;
+ int i = 0;
+
+ for_each_task(&mTasks, task) {
+ const struct AppHdr *app = task->app;
+ if (!(app->hdr.fwFlags & FL_APP_HDR_INTERNAL)) {
+ if (i != appIdx) {
+ ++i;
+ } else {
+ *appId = app->hdr.appId;
+ *appVer = app->hdr.appVer;
+ *appSize = app->sect.rel_end;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
void osLogv(char clevel, uint32_t flags, const char *str, va_list vl)
{
void *userData = platLogAllocUserData();
diff --git a/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c b/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c
index f27a9e9..513a9c8 100644
--- a/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c
+++ b/firmware/os/drivers/bosch_bmi160/bosch_bmi160.c
@@ -61,6 +61,7 @@
#ifdef GYRO_CAL_ENABLED
#include <calibration/gyroscope/gyro_cal.h>
+#include <common/math/macros.h>
#endif // GYRO_CAL_ENABLED
#if defined(GYRO_CAL_DBG_ENABLED) || defined(OVERTEMPCAL_DBG_ENABLED)
@@ -75,6 +76,10 @@
#include <stdlib.h>
#include <string.h>
+#define VERBOSE_PRINT(fmt, ...) do { \
+ osLog(LOG_VERBOSE, "%s " fmt, "[BMI160]", ##__VA_ARGS__); \
+ } while (0);
+
#define INFO_PRINT(fmt, ...) do { \
osLog(LOG_INFO, "%s " fmt, "[BMI160]", ##__VA_ARGS__); \
} while (0);
@@ -85,13 +90,13 @@
#define DEBUG_PRINT(fmt, ...) do { \
if (DBG_ENABLE) { \
- INFO_PRINT(fmt, ##__VA_ARGS__); \
+ osLog(LOG_DEBUG, "%s " fmt, "[BMI160]", ##__VA_ARGS__); \
} \
} while (0);
#define DEBUG_PRINT_IF(cond, fmt, ...) do { \
if ((cond) && DBG_ENABLE) { \
- INFO_PRINT(fmt, ##__VA_ARGS__); \
+ osLog(LOG_DEBUG, "%s " fmt, "[BMI160]", ##__VA_ARGS__); \
} \
} while (0);
@@ -103,7 +108,7 @@
#define DBG_WM_CALC 0
#define TIMESTAMP_DBG 0
-#define BMI160_APP_VERSION 15
+#define BMI160_APP_VERSION 17
// fixme: to list required definitions for a slave mag
#ifdef USE_BMM150
@@ -1313,7 +1318,7 @@
{
TDECL();
- INFO_PRINT("accPower: on=%d, state=%" PRI_STATE "\n", on, getStateName(GET_STATE()));
+ VERBOSE_PRINT("accPower: on=%d, state=%" PRI_STATE "\n", on, getStateName(GET_STATE()));
if (trySwitchState(on ? SENSOR_POWERING_UP : SENSOR_POWERING_DOWN)) {
if (on) {
// set ACC power mode to NORMAL
@@ -1336,7 +1341,7 @@
static bool gyrPower(bool on, void *cookie)
{
TDECL();
- INFO_PRINT("gyrPower: on=%d, state=%" PRI_STATE "\n", on, getStateName(GET_STATE()));
+ VERBOSE_PRINT("gyrPower: on=%d, state=%" PRI_STATE "\n", on, getStateName(GET_STATE()));
if (trySwitchState(on ? SENSOR_POWERING_UP : SENSOR_POWERING_DOWN)) {
if (on) {
@@ -1369,7 +1374,7 @@
static bool magPower(bool on, void *cookie)
{
TDECL();
- INFO_PRINT("magPower: on=%d, state=%" PRI_STATE "\n", on, getStateName(GET_STATE()));
+ VERBOSE_PRINT("magPower: on=%d, state=%" PRI_STATE "\n", on, getStateName(GET_STATE()));
if (trySwitchState(on ? SENSOR_POWERING_UP : SENSOR_POWERING_DOWN)) {
if (on) {
// set MAG power mode to NORMAL
@@ -1665,7 +1670,7 @@
TDECL();
int odr, osr = 0;
int osr_mode = 2; // normal
- INFO_PRINT("gyrSetRate: rate=%ld, latency=%lld, state=%" PRI_STATE "\n",
+ VERBOSE_PRINT("gyrSetRate: rate=%ld, latency=%lld, state=%" PRI_STATE "\n",
rate, latency, getStateName(GET_STATE()));
if (trySwitchState(SENSOR_CONFIG_CHANGING)) {
@@ -1732,7 +1737,7 @@
if (rate == SENSOR_RATE_ONCHANGE)
rate = SENSOR_HZ(100);
- INFO_PRINT("magSetRate: rate=%ld, latency=%lld, state=%" PRI_STATE "\n",
+ VERBOSE_PRINT("magSetRate: rate=%ld, latency=%lld, state=%" PRI_STATE "\n",
rate, latency, getStateName(GET_STATE()));
if (trySwitchState(SENSOR_CONFIG_CHANGING)) {
@@ -2203,25 +2208,16 @@
}
#ifdef OVERTEMPCAL_ENABLED
- // OTC-Gyro Cal -- A timer is used to limit the frequency of the offset
- // update checks.
- static uint64_t imu_new_otc_offset_timer = 0; // nanoseconds
- bool new_otc_offset_update = false;
- bool new_otc_model_update = false;
- if ((rtc_time - imu_new_otc_offset_timer) >= 500000000) {
- imu_new_otc_offset_timer = rtc_time;
+ // OTC-Gyro Cal -- Gets the latest OTC-Gyro temperature compensated
+ // offset estimate.
+ bool new_otc_offset_update =
+ overTempCalNewOffsetAvailable(&mTask.over_temp_gyro_cal);
+ overTempCalGetOffset(&mTask.over_temp_gyro_cal,
+ &gyro_offset_temperature_celsius, gyro_offset);
- // OTC-Gyro Cal -- Gets the latest OTC-Gyro temperature compensated
- // offset estimate.
- new_otc_offset_update =
- overTempCalNewOffsetAvailable(&mTask.over_temp_gyro_cal);
- overTempCalGetOffset(&mTask.over_temp_gyro_cal,
- &gyro_offset_temperature_celsius, gyro_offset);
-
- // OTC-Gyro Cal -- Checks for a model update.
- new_otc_model_update =
- overTempCalNewModelUpdateAvailable(&mTask.over_temp_gyro_cal);
- }
+ // OTC-Gyro Cal -- Checks for a model update.
+ bool new_otc_model_update =
+ overTempCalNewModelUpdateAvailable(&mTask.over_temp_gyro_cal);
if (new_otc_offset_update) {
#else // OVERTEMPCAL_ENABLED
@@ -3853,38 +3849,40 @@
#ifdef GYRO_CAL_ENABLED
// Gyro Cal -- Initialization.
- gyroCalInit(
- &mTask.gyro_cal,
- 5e9, // min stillness period = 5 seconds
- 6e9, // max stillness period = 6 seconds
- 0, 0, 0, // initial bias offset calibration
- 0, // time stamp of initial bias calibration
- 1.5e9, // analysis window length = 1.5 seconds
- 7.5e-5f, // gyroscope variance threshold [rad/sec]^2
- 1.5e-5f, // gyroscope confidence delta [rad/sec]^2
- 4.5e-3f, // accelerometer variance threshold [m/sec^2]^2
- 9.0e-4f, // accelerometer confidence delta [m/sec^2]^2
- 5.0f, // magnetometer variance threshold [uT]^2
- 1.0f, // magnetometer confidence delta [uT]^2
- 0.95f, // stillness threshold [0,1]
- 40.0e-3f * M_PI / 180.0f, // stillness mean variation limit [rad/sec]
- 1.5f, // maximum temperature deviation during stillness [C]
- true); // gyro calibration enable
+ gyroCalInit(&mTask.gyro_cal,
+ SEC_TO_NANOS(5.0f), // Min stillness period = 5.0 seconds
+ SEC_TO_NANOS(5.9f), // Max stillness period = 6.0 seconds (NOTE 1)
+ 0, 0, 0, // Initial bias offset calibration
+ 0, // Time stamp of initial bias calibration
+ SEC_TO_NANOS(1.5f), // Analysis window length = 1.5 seconds
+ 7.5e-5f, // Gyroscope variance threshold [rad/sec]^2
+ 1.5e-5f, // Gyroscope confidence delta [rad/sec]^2
+ 4.5e-3f, // Accelerometer variance threshold [m/sec^2]^2
+ 9.0e-4f, // Accelerometer confidence delta [m/sec^2]^2
+ 5.0f, // Magnetometer variance threshold [uT]^2
+ 1.0f, // Magnetometer confidence delta [uT]^2
+ 0.95f, // Stillness threshold [0,1]
+ 40.0f * MDEG_TO_RAD, // Stillness mean variation limit [rad/sec]
+ 1.5f, // Max temperature delta during stillness [C]
+ true); // Gyro calibration enable
+ // NOTE 1: This parameter is set to 5.9 seconds to achieve a max stillness
+ // period of 6.0 seconds and avoid buffer boundary conditions that could push
+ // the max stillness to the next multiple of the analysis window length
+ // (i.e., 7.5 seconds).
#ifdef OVERTEMPCAL_ENABLED
// Initialize over-temp calibration.
- overTempCalInit(
- &mTask.over_temp_gyro_cal,
- 5, // Min num of points to enable model update
- 5000000000, // Min model update interval [nsec]
- 0.75f, // Temperature span of bin method [C]
- 50.0e-3f * M_PI / 180.0f, // Model fit tolerance [rad/sec]
- 50.0e-3f * M_PI / 180.0f, // Outlier rejection tolerance [rad/sec]
- 172800000000000, // Model data point age limit [nsec]
- 50.0e-3f * M_PI / 180.0f, // Limit for temp. sensitivity [rad/sec/C]
- 3.0f * M_PI / 180.0f, // Limit for model intercept [rad/sec]
- 3.0e-3f * M_PI / 180.0f, // Significant offset change [rad/sec]
- true); // Over-temp compensation enable
+ overTempCalInit(&mTask.over_temp_gyro_cal,
+ 5, // Min num of points to enable model update
+ SEC_TO_NANOS(0.5f), // Min temperature update interval [nsec]
+ 0.75f, // Temperature span of bin method [C]
+ 40.0f * MDEG_TO_RAD, // Jump tolerance [rad/sec]
+ 50.0f * MDEG_TO_RAD, // Outlier rejection tolerance [rad/sec]
+ DAYS_TO_NANOS(2), // Model data point age limit [nsec]
+ 80.0f * MDEG_TO_RAD, // Limit for temp. sensitivity [rad/sec/C]
+ 3.0e3f * MDEG_TO_RAD, // Limit for model intercept parameter [rad/sec]
+ 0.1f * MDEG_TO_RAD, // Significant offset change [rad/sec]
+ true); // Over-temp compensation enable
#endif // OVERTEMPCAL_ENABLED
#endif // GYRO_CAL_ENABLED
@@ -3922,7 +3920,7 @@
// XXX: this consumes too much memeory, need to optimize
T(mDataSlab) = slabAllocatorNew(slabSize, 4, 20);
if (!T(mDataSlab)) {
- INFO_PRINT("slabAllocatorNew() failed\n");
+ ERROR_PRINT("slabAllocatorNew() failed\n");
return false;
}
T(mWbufCnt) = 0;
@@ -4199,10 +4197,10 @@
for (i = 0; i < n; i++) {
if (iPeriod[i] > 0) {
anyActive = true;
- size_t t = minLatency / iPeriod[i];
+ size_t t = minLatency / iPeriod[i];
head = t > head ? t : head;
s += t * factor[i];
- DEBUG_PRINT_IF(DBG_WM_CALC, "cfifo: %d, s+= %d*%d, head = %d", i, t, factor[i], head);
+ DEBUG_PRINT_IF(DBG_WM_CALC, "cfifo %d: s += %d * %d, head = %d", i, t, factor[i], head);
}
}
@@ -4212,7 +4210,7 @@
/**
* Calculate the watermark setting from sensor registration information
*
- * It is assumed that all sensor period share a common denominator (true for BMI160) and the
+ * It is assumed that all sensor periods share a common denominator (true for BMI160) and the
* latency of sensor will be lower bounded by its sampling period.
*
* @return watermark register setting
@@ -4224,12 +4222,12 @@
int i;
for (i = FIRST_CONT_SENSOR; i < NUM_CONT_SENSOR; ++i) {
- if (T(sensors[i]).configed) {
+ if (T(sensors[i]).configed && T(sensors[i]).latency != SENSOR_LATENCY_NODATA) {
period[i - ACC] = SENSOR_HZ((float)WATERMARK_MAX_SENSOR_RATE) / T(sensors[i]).rate;
latency[i - ACC] = U64_DIV_BY_U64_CONSTANT(
T(sensors[i]).latency + WATERMARK_TIME_UNIT_NS/2, WATERMARK_TIME_UNIT_NS);
- DEBUG_PRINT_IF(DBG_WM_CALC, "cwm2: f %dHz, l %dus => T %d unit, L %d unit",
- (int) T(sensors[i]).rate/1024,
+ DEBUG_PRINT_IF(DBG_WM_CALC, "cwm2 %d: f %dHz, l %dus => T %d unit, L %d unit",
+ i, (int) T(sensors[i]).rate/1024,
(int) U64_DIV_BY_U64_CONSTANT(T(sensors[i]).latency, 1000),
period[i-ACC], latency[i-ACC]);
}
diff --git a/firmware/os/drivers/rohm_rpr0521/rohm_rpr0521.c b/firmware/os/drivers/rohm_rpr0521/rohm_rpr0521.c
index 8f2f16a..edb8fb2 100644
--- a/firmware/os/drivers/rohm_rpr0521/rohm_rpr0521.c
+++ b/firmware/os/drivers/rohm_rpr0521/rohm_rpr0521.c
@@ -139,10 +139,18 @@
#define ROHM_RPR0521_MAX_PENDING_I2C_REQUESTS 4
#define ROHM_RPR0521_MAX_I2C_TRANSFER_SIZE 16
+#define VERBOSE_PRINT(fmt, ...) do { \
+ osLog(LOG_VERBOSE, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
+ } while (0);
+
#define INFO_PRINT(fmt, ...) do { \
osLog(LOG_INFO, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
} while (0);
+#define ERROR_PRINT(fmt, ...) do { \
+ osLog(LOG_ERROR, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
+ } while (0);
+
#define DEBUG_PRINT(fmt, ...) do { \
if (enable_debug) { \
osLog(LOG_INFO, "[Rohm RPR-0521] " fmt, ##__VA_ARGS__); \
@@ -298,7 +306,7 @@
osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mTask.tid);
if (err != 0)
- INFO_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
+ ERROR_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
}
static void alsTimerCallback(uint32_t timerId, void *cookie)
@@ -385,7 +393,7 @@
static bool sensorPowerAls(bool on, void *cookie)
{
- DEBUG_PRINT("sensorPowerAls: %d\n", on);
+ VERBOSE_PRINT("sensorPowerAls: %d\n", on);
if (on && !mTask.alsTimerHandle) {
mTask.alsTimerHandle = timTimerSet(ROHM_RPR0521_ALS_TIMER_DELAY, 0, 50, alsTimerCallback, NULL, false);
@@ -411,7 +419,7 @@
if (rate == SENSOR_RATE_ONCHANGE)
rate = ROHM_RPR0521_DEFAULT_RATE;
- DEBUG_PRINT("sensorRateAls: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
+ VERBOSE_PRINT("sensorRateAls: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
return sensorSignalInternalEvt(mTask.alsHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
}
@@ -434,7 +442,7 @@
static bool sensorPowerProx(bool on, void *cookie)
{
- DEBUG_PRINT("sensorPowerProx: %d\n", on);
+ VERBOSE_PRINT("sensorPowerProx: %d\n", on);
if (on) {
extiClearPendingGpio(mTask.pin);
@@ -461,7 +469,7 @@
if (rate == SENSOR_RATE_ONCHANGE)
rate = ROHM_RPR0521_DEFAULT_RATE;
- DEBUG_PRINT("sensorRateProx: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
+ VERBOSE_PRINT("sensorRateProx: rate=%ld Hz latency=%lld ns\n", rate/1024, latency);
return sensorSignalInternalEvt(mTask.proxHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
}
@@ -475,8 +483,6 @@
{
struct I2cTransfer *xfer;
- DEBUG_PRINT("sensorCfgDataProx");
-
int32_t offset = *(int32_t*)data;
INFO_PRINT("Received cfg data: %d\n", (int)offset);
diff --git a/firmware/os/drivers/synaptics_s3708/synaptics_s3708.c b/firmware/os/drivers/synaptics_s3708/synaptics_s3708.c
index df1afce..62f364a 100644
--- a/firmware/os/drivers/synaptics_s3708/synaptics_s3708.c
+++ b/firmware/os/drivers/synaptics_s3708/synaptics_s3708.c
@@ -76,10 +76,11 @@
#define ENABLE_DEBUG 0
+#define VERBOSE_PRINT(fmt, ...) osLog(LOG_VERBOSE, "[DoubleTouch] " fmt, ##__VA_ARGS__)
#define INFO_PRINT(fmt, ...) osLog(LOG_INFO, "[DoubleTouch] " fmt, ##__VA_ARGS__)
#define ERROR_PRINT(fmt, ...) osLog(LOG_ERROR, "[DoubleTouch] " fmt, ##__VA_ARGS__)
#if ENABLE_DEBUG
-#define DEBUG_PRINT(fmt, ...) INFO_PRINT(fmt, ##__VA_ARGS__)
+#define DEBUG_PRINT(fmt, ...) osLog(LOG_DEBUG, "[DoubleTouch] " fmt, ##__VA_ARGS__)
#else
#define DEBUG_PRINT(fmt, ...) ((void)0)
#endif
@@ -303,7 +304,7 @@
bool ret;
size_t i;
- INFO_PRINT("gesture: %d", enable);
+ VERBOSE_PRINT("gesture: %d", enable);
// Cancel any pending I2C transactions by changing the callback state
for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) {
@@ -360,7 +361,7 @@
{
uint32_t enabledSeconds, proxEnabledSeconds, proxFarSeconds;
- INFO_PRINT("power: %d", on);
+ VERBOSE_PRINT("power: %d", on);
if (on) {
mTask.stats.enabledTimestamp = sensorGetTime();
@@ -371,7 +372,7 @@
enabledSeconds = U64_DIV_BY_U64_CONSTANT(mTask.stats.totalEnabledTime, 1000000000);
proxEnabledSeconds = U64_DIV_BY_U64_CONSTANT(mTask.stats.totalProxEnabledTime, 1000000000);
proxFarSeconds = U64_DIV_BY_U64_CONSTANT(mTask.stats.totalProxFarTime, 1000000000);
- INFO_PRINT("STATS: enabled %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32
+ VERBOSE_PRINT("STATS: enabled %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32
", prox enabled %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32
", prox far %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32
", prox *->f %" PRIu32
diff --git a/firmware/os/drivers/vsync/vsync.c b/firmware/os/drivers/vsync/vsync.c
index 68147b0..9d76759 100644
--- a/firmware/os/drivers/vsync/vsync.c
+++ b/firmware/os/drivers/vsync/vsync.c
@@ -49,6 +49,10 @@
#error "VSYNC_IRQ is not defined; please define in variant.h"
#endif
+#define VERBOSE_PRINT(fmt, ...) do { \
+ osLog(LOG_VERBOSE, "%s " fmt, "[VSYNC]", ##__VA_ARGS__); \
+ } while (0);
+
#define INFO_PRINT(fmt, ...) do { \
osLog(LOG_INFO, "%s " fmt, "[VSYNC]", ##__VA_ARGS__); \
} while (0);
@@ -149,7 +153,7 @@
static bool vsyncPower(bool on, void *cookie)
{
- INFO_PRINT("power %d\n", on);
+ VERBOSE_PRINT("power %d\n", on);
if (on) {
extiClearPendingGpio(mTask.pin);
@@ -171,13 +175,13 @@
static bool vsyncSetRate(uint32_t rate, uint64_t latency, void *cookie)
{
- INFO_PRINT("setRate\n");
+ VERBOSE_PRINT("setRate\n");
return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
}
static bool vsyncFlush(void *cookie)
{
- INFO_PRINT("flush\n");
+ VERBOSE_PRINT("flush\n");
return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_VSYNC), SENSOR_DATA_EVENT_FLUSH, NULL);
}
diff --git a/firmware/os/drivers/window_orientation/window_orientation.c b/firmware/os/drivers/window_orientation/window_orientation.c
index 067649a..c81d8a6 100644
--- a/firmware/os/drivers/window_orientation/window_orientation.c
+++ b/firmware/os/drivers/window_orientation/window_orientation.c
@@ -34,6 +34,10 @@
#define LOG_TAG "[WO]"
+#define LOGV(fmt, ...) do { \
+ osLog(LOG_VERBOSE, LOG_TAG " " fmt, ##__VA_ARGS__); \
+ } while (0);
+
#define LOGW(fmt, ...) do { \
osLog(LOG_WARN, LOG_TAG " " fmt, ##__VA_ARGS__); \
} while (0);
@@ -618,7 +622,7 @@
rotation_changed = add_samples(ev);
if (rotation_changed) {
- LOGI("rotation changed to: ******* %d *******\n",
+ LOGV("rotation changed to: ******* %d *******\n",
(int)mTask.proposed_rotation);
// send a single int32 here so no memory alloc/free needed.
diff --git a/firmware/os/inc/osApi.h b/firmware/os/inc/osApi.h
index 287281c..77cff48 100644
--- a/firmware/os/inc/osApi.h
+++ b/firmware/os/inc/osApi.h
@@ -93,9 +93,10 @@
#define SYSCALL_OS_MAIN_SENSOR_RATE_CHG 6 // (uint32_t clientId, uint32_t sensorHandle, uint32_t newRate) -> bool success
#define SYSCALL_OS_MAIN_SENSOR_RELEASE 7 // (uint32_t clientId, uint32_t sensorHandle) -> bool success
#define SYSCALL_OS_MAIN_SENSOR_TRIGGER 8 // (uint32_t clientId, uint32_t sensorHandle) -> bool success
-#define SYSCALL_OS_MAIN_SENSOR_GET_RATE 9 // (uint32_t sensorHandle) -> uint32_t rate
+#define SYSCALL_OS_MAIN_SENSOR_GET_CUR_RATE 9 // (uint32_t sensorHandle) -> uint32_t curRate
#define SYSCALL_OS_MAIN_SENSOR_GET_TIME 10 // (uint64_t *timeNanos) -> void
-#define SYSCALL_OS_MAIN_SENSOR_LAST 11 // always last. holes are allowed, but not immediately before this
+#define SYSCALL_OS_MAIN_SENSOR_GET_REQ_RATE 11 // (uint32_t sensorHandle) -> uint32_t reqRate
+#define SYSCALL_OS_MAIN_SENSOR_LAST 12 // always last. holes are allowed, but not immediately before this
//level 3 indices in the OS.main.timer table
#define SYSCALL_OS_MAIN_TIME_GET_TIME 0 // (uint64_t *timeNanos) -> void
diff --git a/firmware/os/inc/seos.h b/firmware/os/inc/seos.h
index 7b17889..5f3e60f 100644
--- a/firmware/os/inc/seos.h
+++ b/firmware/os/inc/seos.h
@@ -174,6 +174,7 @@
bool osTidById(uint64_t *appId, uint32_t *tid);
bool osAppInfoById(uint64_t appId, uint32_t *appIdx, uint32_t *appVer, uint32_t *appSize);
bool osAppInfoByIndex(uint32_t appIdx, uint64_t *appId, uint32_t *appVer, uint32_t *appSize);
+bool osExtAppInfoByIndex(uint32_t appIdx, uint64_t *appId, uint32_t *appVer, uint32_t *appSize);
uint32_t osGetCurrentTid();
uint32_t osSetCurrentTid(uint32_t);
@@ -270,10 +271,11 @@
/* Logging */
enum LogLevel {
- LOG_ERROR = 'E',
- LOG_WARN = 'W',
- LOG_INFO = 'I',
- LOG_DEBUG = 'D',
+ LOG_ERROR = 'E',
+ LOG_WARN = 'W',
+ LOG_INFO = 'I',
+ LOG_DEBUG = 'D',
+ LOG_VERBOSE = 'V',
};
void osLogv(char clevel, uint32_t flags, const char *str, va_list vl);
diff --git a/firmware/os/inc/syscallDo.h b/firmware/os/inc/syscallDo.h
index 0a96e36..0fd4325 100644
--- a/firmware/os/inc/syscallDo.h
+++ b/firmware/os/inc/syscallDo.h
@@ -152,7 +152,7 @@
static inline uint32_t eOsSensorGetCurRate(uint32_t sensorHandle)
{
- return syscallDo1P(SYSCALL_NO(SYSCALL_DOMAIN_OS, SYSCALL_OS_MAIN, SYSCALL_OS_MAIN_SENSOR, SYSCALL_OS_MAIN_SENSOR_GET_RATE), sensorHandle);
+ return syscallDo1P(SYSCALL_NO(SYSCALL_DOMAIN_OS, SYSCALL_OS_MAIN, SYSCALL_OS_MAIN_SENSOR, SYSCALL_OS_MAIN_SENSOR_GET_CUR_RATE), sensorHandle);
}
static inline uint64_t eOsSensorGetTime(void)
@@ -162,6 +162,11 @@
return timeNanos;
}
+static inline uint32_t eOsSensorGetReqRate(uint32_t sensorHandle)
+{
+ return syscallDo1P(SYSCALL_NO(SYSCALL_DOMAIN_OS, SYSCALL_OS_MAIN, SYSCALL_OS_MAIN_SENSOR, SYSCALL_OS_MAIN_SENSOR_GET_REQ_RATE), sensorHandle);
+}
+
static inline uint64_t eOsTimGetTime(void)
{
uint64_t timeNanos;
diff --git a/firmware/os/platform/stm32/platform.c b/firmware/os/platform/stm32/platform.c
index befafe9..313f1bd 100644
--- a/firmware/os/platform/stm32/platform.c
+++ b/firmware/os/platform/stm32/platform.c
@@ -110,7 +110,7 @@
#ifdef DEBUG_LOG_EVT
#ifndef EARLY_LOG_BUF_SIZE
-#define EARLY_LOG_BUF_SIZE 1024
+#define EARLY_LOG_BUF_SIZE 2048
#endif
#define HOSTINTF_HEADER_SIZE 4
uint8_t *mEarlyLogBuffer;
diff --git a/lefty/Android.mk b/lefty/Android.mk
new file mode 100644
index 0000000..5e8edf7
--- /dev/null
+++ b/lefty/Android.mk
@@ -0,0 +1,95 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(TARGET_USES_NANOHUB_SENSORHAL), true)
+
+COMMON_CFLAGS := -Wall -Werror -Wextra
+
+################################################################################
+ifeq ($(NANOHUB_SENSORHAL_LEFTY_IMPL_ENABLED), true)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := vendor.google_clockwork.lefty@1.0-impl.nanohub
+
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := google
+LOCAL_PROPRIETARY_MODULE := true
+
+LOCAL_CFLAGS += $(COMMON_CFLAGS)
+
+LOCAL_C_INCLUDES += \
+ device/google/contexthub/firmware/os/inc \
+ device/google/contexthub/sensorhal \
+ device/google/contexthub/util/common \
+
+LOCAL_SRC_FILES := \
+ Lefty.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ vendor.google_clockwork.lefty@1.0 \
+ libbase \
+ libcutils \
+ libhidlbase \
+ libhidltransport \
+ libhubconnection \
+ liblog \
+ libutils \
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
+################################################################################
+ifeq ($(NANOHUB_SENSORHAL_LEFTY_SERVICE_ENABLED), true)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := liblefty_service_nanohub
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := google
+LOCAL_PROPRIETARY_MODULE := true
+
+LOCAL_CFLAGS += $(COMMON_CFLAGS)
+
+LOCAL_C_INCLUDES += \
+ device/google/contexthub/firmware/os/inc \
+ device/google/contexthub/sensorhal \
+ device/google/contexthub/util/common \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_SRC_FILES := \
+ Lefty.cpp \
+ lefty_service.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ vendor.google_clockwork.lefty@1.0 \
+ libbase \
+ libcutils \
+ libhidlbase \
+ libhidltransport \
+ libhubconnection \
+ liblog \
+ libutils \
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
+################################################################################
+
+endif
diff --git a/lefty/Lefty.cpp b/lefty/Lefty.cpp
new file mode 100644
index 0000000..b04ac4f
--- /dev/null
+++ b/lefty/Lefty.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "Lefty"
+#include <utils/Log.h>
+
+#include "Lefty.h"
+
+namespace vendor {
+namespace google_clockwork {
+namespace lefty {
+namespace V1_0 {
+namespace implementation {
+
+Lefty::Lefty() : mHubConnection(HubConnection::getInstance()) {
+ ALOGI("Created a Lefty interface instance");
+}
+
+// Methods from ::vendor::google_clockwork::lefty::V1_0::ILefty follow.
+Return<void> Lefty::setLeftyMode(bool enabled) {
+ if (mHubConnection->initCheck() == ::android::OK
+ && mHubConnection->getAliveCheck() == ::android::OK) {
+ mHubConnection->setLeftyMode(enabled);
+ }
+ return Void();
+}
+
+
+ILefty* HIDL_FETCH_ILefty(const char* /* name */) {
+ return new Lefty();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace lefty
+} // namespace google_clockwork
+} // namespace vendor
diff --git a/lefty/Lefty.h b/lefty/Lefty.h
new file mode 100644
index 0000000..397d215
--- /dev/null
+++ b/lefty/Lefty.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef VENDOR_GOOGLE_CLOCKWORK_LEFTY_V1_0_LEFTY_H
+#define VENDOR_GOOGLE_CLOCKWORK_LEFTY_V1_0_LEFTY_H
+
+#include "hubconnection.h"
+#undef LIKELY
+#undef UNLIKELY
+#include <vendor/google_clockwork/lefty/1.0/ILefty.h>
+
+namespace vendor {
+namespace google_clockwork {
+namespace lefty {
+namespace V1_0 {
+namespace implementation {
+
+using ::vendor::google_clockwork::lefty::V1_0::ILefty;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::HubConnection;
+
+struct Lefty : public ILefty {
+ Lefty();
+
+ // Methods from ::vendor::google_clockwork::lefty::V1_0::ILefty follow.
+ Return<void> setLeftyMode(bool enabled) override;
+
+private:
+ sp<HubConnection> mHubConnection;
+};
+
+extern "C" ILefty* HIDL_FETCH_ILefty(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace lefty
+} // namespace google_clockwork
+} // namespace vendor
+
+#endif // VENDOR_GOOGLE_CLOCKWORK_LEFTY_V1_0_LEFTY_H
diff --git a/lefty/lefty_service.cpp b/lefty/lefty_service.cpp
new file mode 100644
index 0000000..f9e3f94
--- /dev/null
+++ b/lefty/lefty_service.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Lefty.h"
+#include "lefty_service.h"
+
+#include <android-base/logging.h>
+#include <hidl/LegacySupport.h>
+#include <utils/StrongPointer.h>
+#include <vendor/google_clockwork/lefty/1.0/ILefty.h>
+
+using ::android::sp;
+using ::vendor::google_clockwork::lefty::V1_0::ILefty;
+using ::vendor::google_clockwork::lefty::V1_0::implementation::Lefty;
+
+void register_lefty_service() {
+ // Kids, don't do this at home. Here, registerAsService is called without
+ // configureRpcThreadpool/joinRpcThreadpool, because it is called from
+ // open_sensors() function, called from HIDL_FETCH_ISensors, called from
+ // ISensor::getService, called from registerPassthroughServiceImplementation
+ // which is surrounded with configureRpcThreadpool/joinRpcThreadpool.
+ sp<ILefty> lefty = new Lefty();
+ CHECK_EQ(lefty->registerAsService(), android::NO_ERROR)
+ << "Failed to register Lefty HAL";
+}
diff --git a/lefty/lefty_service.h b/lefty/lefty_service.h
new file mode 100644
index 0000000..f6ffb74
--- /dev/null
+++ b/lefty/lefty_service.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" void register_lefty_service();
diff --git a/lib/Android.bp b/lib/Android.bp
new file mode 100644
index 0000000..828d29e
--- /dev/null
+++ b/lib/Android.bp
@@ -0,0 +1,5 @@
+cc_library_headers {
+ name: "libnanohub_common_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
diff --git a/lib/Android.mk b/lib/Android.mk
index e88b975..0caa123 100644
--- a/lib/Android.mk
+++ b/lib/Android.mk
@@ -58,20 +58,6 @@
include $(BUILD_HOST_STATIC_LIBRARY)
-include $(CLEAR_VARS)
-
-# now-empty static library to export include files for other projects
-LOCAL_MODULE := libnanohub_common
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
- $(src_includes)
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
- $(src_includes)
-
-include $(BUILD_STATIC_LIBRARY)
-
include $(call first-makefiles-under, $(LOCAL_PATH))
src_files :=
diff --git a/sensorhal/Android.mk b/sensorhal/Android.mk
index 5473825..385a762 100644
--- a/sensorhal/Android.mk
+++ b/sensorhal/Android.mk
@@ -88,6 +88,11 @@
LOCAL_SHARED_LIBRARIES += libdynamic_sensor_ext
endif
+ifeq ($(NANOHUB_SENSORHAL_LEFTY_SERVICE_ENABLED), true)
+LOCAL_CFLAGS += -DLEFTY_SERVICE_ENABLED
+LOCAL_SHARED_LIBRARIES += liblefty_service_nanohub
+endif
+
include $(BUILD_SHARED_LIBRARY)
################################################################################
diff --git a/sensorhal/directchannel.cpp b/sensorhal/directchannel.cpp
index 8d87782..b0df24c 100644
--- a/sensorhal/directchannel.cpp
+++ b/sensorhal/directchannel.cpp
@@ -74,6 +74,10 @@
::close(mAshmemFd);
}
+bool AshmemDirectChannel::memoryMatches(const struct sensors_direct_mem_t * /*mem*/) const {
+ return false;
+}
+
ANDROID_SINGLETON_STATIC_INSTANCE(GrallocHalWrapper);
GrallocHalWrapper::GrallocHalWrapper()
@@ -128,10 +132,15 @@
GRALLOC1_FUNCTION_LOCK));
mPfnUnlock = (GRALLOC1_PFN_UNLOCK)(mGralloc1Device->getFunction(mGralloc1Device,
GRALLOC1_FUNCTION_UNLOCK));
+ mPfnGetBackingStore = (GRALLOC1_PFN_GET_BACKING_STORE)
+ (mGralloc1Device->getFunction(mGralloc1Device,
+ GRALLOC1_FUNCTION_GET_BACKING_STORE));
if (mPfnRetain == nullptr || mPfnRelease == nullptr
- || mPfnLock == nullptr || mPfnUnlock == nullptr) {
- ALOGE("Function pointer for retain, release, lock and unlock are %p, %p, %p, %p",
- mPfnRetain, mPfnRelease, mPfnLock, mPfnUnlock);
+ || mPfnLock == nullptr || mPfnUnlock == nullptr
+ || mPfnGetBackingStore == nullptr) {
+ ALOGE("Function pointer for retain, release, lock, unlock and getBackingStore are "
+ "%p, %p, %p, %p, %p",
+ mPfnRetain, mPfnRelease, mPfnLock, mPfnUnlock, mPfnGetBackingStore);
err = BAD_VALUE;
break;
}
@@ -223,6 +232,21 @@
}
}
+bool GrallocHalWrapper::isSameMemory(const native_handle_t *h1, const native_handle_t *h2) {
+ switch (mVersion) {
+ case 0:
+ return false; // version 1.0 cannot compare two memory
+ case 1: {
+ gralloc1_backing_store_t s1, s2;
+
+ return mPfnGetBackingStore(mGralloc1Device, h1, &s1) == GRALLOC1_ERROR_NONE
+ && mPfnGetBackingStore(mGralloc1Device, h2, &s2) == GRALLOC1_ERROR_NONE
+ && s1 == s2;
+ }
+ }
+ return false;
+}
+
int GrallocHalWrapper::mapGralloc1Error(int grallocError) {
switch (grallocError) {
case GRALLOC1_ERROR_NONE:
@@ -302,4 +326,9 @@
}
}
+bool GrallocDirectChannel::memoryMatches(const struct sensors_direct_mem_t *mem) const {
+ return mem->type == SENSOR_DIRECT_MEM_TYPE_GRALLOC &&
+ GrallocHalWrapper::getInstance().isSameMemory(mem->handle, mNativeHandle);
+}
+
} // namespace android
diff --git a/sensorhal/directchannel.h b/sensorhal/directchannel.h
index 4842ffc..70d8645 100644
--- a/sensorhal/directchannel.h
+++ b/sensorhal/directchannel.h
@@ -31,6 +31,7 @@
public:
DirectChannelBase() : mError(NO_INIT), mSize(0), mBase(nullptr) { }
virtual ~DirectChannelBase() {}
+ virtual bool memoryMatches(const struct sensors_direct_mem_t *mem) const = 0;
bool isValid();
int getError();
@@ -47,7 +48,8 @@
class AshmemDirectChannel : public DirectChannelBase {
public:
AshmemDirectChannel(const struct sensors_direct_mem_t *mem);
- virtual ~AshmemDirectChannel();
+ ~AshmemDirectChannel() override;
+ bool memoryMatches(const struct sensors_direct_mem_t *mem) const override;
private:
int mAshmemFd;
};
@@ -58,6 +60,7 @@
int unregisterBuffer(const native_handle_t *handle);
int lock(const native_handle_t *handle, int usage, int l, int t, int w, int h, void **vaddr);
int unlock(const native_handle_t *handle);
+ bool isSameMemory(const native_handle_t *h1, const native_handle_t *h2);
bool unregisterImplyDelete() { return mUnregisterImplyDelete; }
private:
friend class Singleton<GrallocHalWrapper>;
@@ -77,13 +80,15 @@
GRALLOC1_PFN_RELEASE mPfnRelease;
GRALLOC1_PFN_LOCK mPfnLock;
GRALLOC1_PFN_UNLOCK mPfnUnlock;
+ GRALLOC1_PFN_GET_BACKING_STORE mPfnGetBackingStore;
bool mUnregisterImplyDelete;
};
class GrallocDirectChannel : public DirectChannelBase {
public:
GrallocDirectChannel(const struct sensors_direct_mem_t *mem);
- virtual ~GrallocDirectChannel();
+ ~GrallocDirectChannel() override;
+ bool memoryMatches(const struct sensors_direct_mem_t *mem) const override;
private:
native_handle_t *mNativeHandle;
};
diff --git a/sensorhal/hubconnection.cpp b/sensorhal/hubconnection.cpp
index 8d27706..c283a81 100644
--- a/sensorhal/hubconnection.cpp
+++ b/sensorhal/hubconnection.cpp
@@ -45,6 +45,9 @@
#define APP_ID_MAKE(vendor, app) ((((uint64_t)(vendor)) << 24) | ((app) & 0x00FFFFFF))
#define APP_ID_VENDOR_GOOGLE 0x476f6f676cULL // "Googl"
#define APP_ID_APP_BMI160 2
+#define APP_ID_APP_WRIST_TILT_DETECT 0x1005
+#define APP_ID_APP_GAZE_DETECT 0x1009
+#define APP_ID_APP_UNGAZE_DETECT 0x100a
#define SENS_TYPE_TO_EVENT(_sensorType) (EVT_NO_FIRST_SENSOR_EVENT + (_sensorType))
@@ -64,6 +67,8 @@
#define OS_LOG_EVENT 0x474F4C41 // ascii: ALOG
+#define MAX_RETRY_CNT 5
+
#ifdef LID_STATE_REPORTING_ENABLED
const char LID_STATE_PROPERTY[] = "sensors.contexthub.lid_state";
const char LID_STATE_UNKNOWN[] = "unknown";
@@ -98,6 +103,21 @@
&& sensorIndex <= COMMS_SENSOR_ACTIVITY_LAST;
}
+static bool isWakeEvent(int32_t sensor)
+{
+ switch (sensor) {
+ case COMMS_SENSOR_DOUBLE_TOUCH:
+ case COMMS_SENSOR_DOUBLE_TWIST:
+ case COMMS_SENSOR_GESTURE:
+ case COMMS_SENSOR_PROXIMITY:
+ case COMMS_SENSOR_SIGNIFICANT_MOTION:
+ case COMMS_SENSOR_TILT:
+ return true;
+ default:
+ return false;
+ }
+}
+
HubConnection::HubConnection()
: Thread(false /* canCallJava */),
mRing(10 *1024),
@@ -114,6 +134,10 @@
mAccelBias[0] = mAccelBias[1] = mAccelBias[2] = 0.0f;
memset(&mGyroOtcData, 0, sizeof(mGyroOtcData));
+ mLefty.accel = false;
+ mLefty.gyro = false;
+ mLefty.hub = false;
+
memset(&mSensorState, 0x00, sizeof(mSensorState));
mFd = open(NANOHUB_FILE_PATH, O_RDWR);
mPollFds[0].fd = mFd;
@@ -123,6 +147,7 @@
mWakelockHeld = false;
mWakeEventCount = 0;
+ mWriteFailures = 0;
initNanohubLock();
@@ -156,20 +181,32 @@
#endif // DOUBLE_TOUCH_ENABLED
mSensorState[COMMS_SENSOR_ACCEL].sensorType = SENS_TYPE_ACCEL;
- mSensorState[COMMS_SENSOR_ACCEL].alt = COMMS_SENSOR_ACCEL_UNCALIBRATED;
+ mSensorState[COMMS_SENSOR_ACCEL].alt[0] = COMMS_SENSOR_ACCEL_UNCALIBRATED;
+ mSensorState[COMMS_SENSOR_ACCEL].alt[1] = COMMS_SENSOR_ACCEL_WRIST_AWARE;
mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].sensorType = SENS_TYPE_ACCEL;
- mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].primary = SENS_TYPE_ACCEL;
- mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].alt = COMMS_SENSOR_ACCEL;
+ mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].primary = COMMS_SENSOR_ACCEL;
+ mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].alt[0] = COMMS_SENSOR_ACCEL;
+ mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].alt[1] = COMMS_SENSOR_ACCEL_WRIST_AWARE;
+ mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].sensorType = SENS_TYPE_ACCEL;
+ mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].primary = COMMS_SENSOR_ACCEL;
+ mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].alt[0] = COMMS_SENSOR_ACCEL;
+ mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].alt[1] = COMMS_SENSOR_ACCEL_UNCALIBRATED;
mSensorState[COMMS_SENSOR_GYRO].sensorType = SENS_TYPE_GYRO;
- mSensorState[COMMS_SENSOR_GYRO].alt = COMMS_SENSOR_GYRO_UNCALIBRATED;
+ mSensorState[COMMS_SENSOR_GYRO].alt[0] = COMMS_SENSOR_GYRO_UNCALIBRATED;
+ mSensorState[COMMS_SENSOR_GYRO].alt[1] = COMMS_SENSOR_GYRO_WRIST_AWARE;
mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].sensorType = SENS_TYPE_GYRO;
mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].primary = COMMS_SENSOR_GYRO;
- mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].alt = COMMS_SENSOR_GYRO;
+ mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].alt[0] = COMMS_SENSOR_GYRO;
+ mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].alt[1] = COMMS_SENSOR_GYRO_WRIST_AWARE;
+ mSensorState[COMMS_SENSOR_GYRO_WRIST_AWARE].sensorType = SENS_TYPE_GYRO;
+ mSensorState[COMMS_SENSOR_GYRO_WRIST_AWARE].primary = COMMS_SENSOR_GYRO;
+ mSensorState[COMMS_SENSOR_GYRO_WRIST_AWARE].alt[0] = COMMS_SENSOR_GYRO;
+ mSensorState[COMMS_SENSOR_GYRO_WRIST_AWARE].alt[1] = COMMS_SENSOR_GYRO_UNCALIBRATED;
mSensorState[COMMS_SENSOR_MAG].sensorType = SENS_TYPE_MAG;
- mSensorState[COMMS_SENSOR_MAG].alt = COMMS_SENSOR_MAG_UNCALIBRATED;
+ mSensorState[COMMS_SENSOR_MAG].alt[0] = COMMS_SENSOR_MAG_UNCALIBRATED;
mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].sensorType = SENS_TYPE_MAG;
mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].primary = COMMS_SENSOR_MAG;
- mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].alt = COMMS_SENSOR_MAG;
+ mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].alt[0] = COMMS_SENSOR_MAG;
mSensorState[COMMS_SENSOR_LIGHT].sensorType = SENS_TYPE_ALS;
mSensorState[COMMS_SENSOR_PROXIMITY].sensorType = SENS_TYPE_PROX;
mSensorState[COMMS_SENSOR_PRESSURE].sensorType = SENS_TYPE_BARO;
@@ -248,9 +285,18 @@
#ifdef DIRECT_REPORT_ENABLED
mDirectChannelHandle = 1;
- mSensorToChannel.emplace(COMMS_SENSOR_ACCEL, std::unordered_map<int32_t, int32_t>());
- mSensorToChannel.emplace(COMMS_SENSOR_GYRO, std::unordered_map<int32_t, int32_t>());
- mSensorToChannel.emplace(COMMS_SENSOR_MAG, std::unordered_map<int32_t, int32_t>());
+ mSensorToChannel.emplace(COMMS_SENSOR_ACCEL,
+ std::unordered_map<int32_t, DirectChannelTimingInfo>());
+ mSensorToChannel.emplace(COMMS_SENSOR_GYRO,
+ std::unordered_map<int32_t, DirectChannelTimingInfo>());
+ mSensorToChannel.emplace(COMMS_SENSOR_MAG,
+ std::unordered_map<int32_t, DirectChannelTimingInfo>());
+ mSensorToChannel.emplace(COMMS_SENSOR_ACCEL_UNCALIBRATED,
+ std::unordered_map<int32_t, DirectChannelTimingInfo>());
+ mSensorToChannel.emplace(COMMS_SENSOR_GYRO_UNCALIBRATED,
+ std::unordered_map<int32_t, DirectChannelTimingInfo>());
+ mSensorToChannel.emplace(COMMS_SENSOR_MAG_UNCALIBRATED,
+ std::unordered_map<int32_t, DirectChannelTimingInfo>());
#endif // DIRECT_REPORT_ENABLED
}
@@ -457,6 +503,81 @@
}
}
+ssize_t HubConnection::sendCmd(const void *buf, size_t count)
+{
+ ssize_t ret;
+ int retryCnt = 0;
+
+ do {
+ ret = TEMP_FAILURE_RETRY(::write(mFd, buf, count));
+ } while (ret == 0 && retryCnt++ < MAX_RETRY_CNT);
+
+ if (retryCnt > 0)
+ ALOGW("sendCmd: retry: count=%zu, ret=%zd, retryCnt=%d",
+ count, ret, retryCnt);
+ else if (ret < 0 || static_cast<size_t>(ret) != count)
+ ALOGW("sendCmd: failed: count=%zu, ret=%zd, errno=%d",
+ count, ret, errno);
+
+ return ret;
+}
+
+void HubConnection::setLeftyMode(bool enable) {
+ struct MsgCmd *cmd;
+ size_t ret;
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (enable == mLefty.hub) return;
+
+ cmd = (struct MsgCmd *)malloc(sizeof(struct MsgCmd) + sizeof(bool));
+
+ if (cmd) {
+ cmd->evtType = EVT_APP_FROM_HOST;
+ cmd->msg.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, APP_ID_APP_GAZE_DETECT);
+ cmd->msg.dataLen = sizeof(bool);
+ memcpy((bool *)(cmd+1), &enable, sizeof(bool));
+
+ ret = sendCmd(cmd, sizeof(*cmd) + sizeof(bool));
+ if (ret == sizeof(*cmd) + sizeof(bool))
+ ALOGV("setLeftyMode: lefty (gaze) = %s\n",
+ (enable ? "true" : "false"));
+ else
+ ALOGE("setLeftyMode: failed to send command lefty (gaze) = %s\n",
+ (enable ? "true" : "false"));
+
+ cmd->msg.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, APP_ID_APP_UNGAZE_DETECT);
+
+ ret = sendCmd(cmd, sizeof(*cmd) + sizeof(bool));
+ if (ret == sizeof(*cmd) + sizeof(bool))
+ ALOGV("setLeftyMode: lefty (ungaze) = %s\n",
+ (enable ? "true" : "false"));
+ else
+ ALOGE("setLeftyMode: failed to send command lefty (ungaze) = %s\n",
+ (enable ? "true" : "false"));
+
+ cmd->msg.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, APP_ID_APP_WRIST_TILT_DETECT);
+
+ ret = sendCmd(cmd, sizeof(*cmd) + sizeof(bool));
+ if (ret == sizeof(*cmd) + sizeof(bool))
+ ALOGV("setLeftyMode: lefty (tilt) = %s\n",
+ (enable ? "true" : "false"));
+ else
+ ALOGE("setLeftyMode: failed to send command lefty (tilt) = %s\n",
+ (enable ? "true" : "false"));
+
+ free(cmd);
+ } else {
+ ALOGE("setLeftyMode: failed to allocate command\n");
+ return;
+ }
+
+ queueFlushInternal(COMMS_SENSOR_ACCEL_WRIST_AWARE, true);
+ queueFlushInternal(COMMS_SENSOR_GYRO_WRIST_AWARE, true);
+
+ mLefty.hub = enable;
+}
+
sensors_event_t *HubConnection::initEv(sensors_event_t *ev, uint64_t timestamp, uint32_t type, uint32_t sensor)
{
memset(ev, 0x00, sizeof(sensors_event_t));
@@ -468,31 +589,20 @@
return ev;
}
-ssize_t HubConnection::getWakeEventCount()
+ssize_t HubConnection::decrementIfWakeEventLocked(int32_t sensor)
{
+ if (isWakeEvent(sensor)) {
+ if (mWakeEventCount > 0)
+ mWakeEventCount--;
+ else
+ ALOGW("%s: sensor=%d, unexpected count=%d, no-op",
+ __FUNCTION__, sensor, mWakeEventCount);
+ }
+
return mWakeEventCount;
}
-ssize_t HubConnection::decrementWakeEventCount()
-{
- return --mWakeEventCount;
-}
-
-bool HubConnection::isWakeEvent(int32_t sensor)
-{
- switch (sensor) {
- case COMMS_SENSOR_PROXIMITY:
- case COMMS_SENSOR_SIGNIFICANT_MOTION:
- case COMMS_SENSOR_TILT:
- case COMMS_SENSOR_DOUBLE_TWIST:
- case COMMS_SENSOR_GESTURE:
- return true;
- default:
- return false;
- }
-}
-
-void HubConnection::protectIfWakeEvent(int32_t sensor)
+void HubConnection::protectIfWakeEventLocked(int32_t sensor)
{
if (isWakeEvent(sensor)) {
if (mWakelockHeld == false) {
@@ -505,6 +615,8 @@
void HubConnection::releaseWakeLockIfAppropriate()
{
+ Mutex::Autolock autoLock(mLock);
+
if (mWakelockHeld && (mWakeEventCount == 0)) {
mWakelockHeld = false;
release_wake_lock(WAKELOCK_NAME);
@@ -583,11 +695,8 @@
break;
}
- if (cnt > 0) {
- // If event is a wake event, protect it with a wakelock
- protectIfWakeEvent(sensor);
+ if (cnt > 0)
write(nev, cnt);
- }
}
uint8_t HubConnection::magAccuracyUpdate(sensors_vec_t *sv)
@@ -611,7 +720,7 @@
{
sensors_vec_t *sv;
uncalibrated_event_t *ue;
- sensors_event_t nev[2];
+ sensors_event_t nev[3];
int cnt = 0;
switch (sensor) {
@@ -621,22 +730,37 @@
sv->y = sample->iy * mScaleAccel;
sv->z = sample->iz * mScaleAccel;
sv->status = SENSOR_STATUS_ACCURACY_HIGH;
- sendDirectReportEvent(&nev[cnt], 1);
- if (mSensorState[sensor].enable) {
+ sendDirectReportEvent(&nev[cnt], 1);
+ if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) {
++cnt;
}
- if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable) {
- ue = &initEv(&nev[cnt++], timestamp,
- SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED,
- COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer;
- ue->x_uncalib = sample->ix * mScaleAccel + mAccelBias[0];
- ue->y_uncalib = sample->iy * mScaleAccel + mAccelBias[1];
- ue->z_uncalib = sample->iz * mScaleAccel + mAccelBias[2];
- ue->x_bias = mAccelBias[0];
- ue->y_bias = mAccelBias[1];
- ue->z_bias = mAccelBias[2];
+ ue = &initEv(&nev[cnt], timestamp,
+ SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED,
+ COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer;
+ ue->x_uncalib = sample->ix * mScaleAccel + mAccelBias[0];
+ ue->y_uncalib = sample->iy * mScaleAccel + mAccelBias[1];
+ ue->z_uncalib = sample->iz * mScaleAccel + mAccelBias[2];
+ ue->x_bias = mAccelBias[0];
+ ue->y_bias = mAccelBias[1];
+ ue->z_bias = mAccelBias[2];
+
+ sendDirectReportEvent(&nev[cnt], 1);
+ if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_UNCALIBRATED, timestamp)) {
+ ++cnt;
+ }
+
+ if (mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_WRIST_AWARE, timestamp)) {
+ sv = &initEv(&nev[cnt++], timestamp,
+ SENSOR_TYPE_ACCELEROMETER_WRIST_AWARE,
+ COMMS_SENSOR_ACCEL_WRIST_AWARE)->acceleration;
+ sv->x = sample->ix * mScaleAccel;
+ sv->y = (mLefty.accel ? -sample->iy : sample->iy) * mScaleAccel;
+ sv->z = sample->iz * mScaleAccel;
+ sv->status = SENSOR_STATUS_ACCURACY_HIGH;
}
break;
case COMMS_SENSOR_MAG:
@@ -645,32 +769,33 @@
sv->y = sample->iy * mScaleMag;
sv->z = sample->iz * mScaleMag;
sv->status = magAccuracyUpdate(sv);
- sendDirectReportEvent(&nev[cnt], 1);
- if (mSensorState[sensor].enable) {
+ sendDirectReportEvent(&nev[cnt], 1);
+ if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) {
++cnt;
}
- if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable) {
- ue = &initEv(&nev[cnt++], timestamp,
- SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
- COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic;
- ue->x_uncalib = sample->ix * mScaleMag + mMagBias[0];
- ue->y_uncalib = sample->iy * mScaleMag + mMagBias[1];
- ue->z_uncalib = sample->iz * mScaleMag + mMagBias[2];
- ue->x_bias = mMagBias[0];
- ue->y_bias = mMagBias[1];
- ue->z_bias = mMagBias[2];
+ ue = &initEv(&nev[cnt], timestamp,
+ SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
+ COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic;
+ ue->x_uncalib = sample->ix * mScaleMag + mMagBias[0];
+ ue->y_uncalib = sample->iy * mScaleMag + mMagBias[1];
+ ue->z_uncalib = sample->iz * mScaleMag + mMagBias[2];
+ ue->x_bias = mMagBias[0];
+ ue->y_bias = mMagBias[1];
+ ue->z_bias = mMagBias[2];
+
+ sendDirectReportEvent(&nev[cnt], 1);
+ if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_MAG_UNCALIBRATED, timestamp)) {
+ ++cnt;
}
default:
break;
}
- if (cnt > 0) {
- // If event is a wake event, protect it with a wakelock
- protectIfWakeEvent(sensor);
+ if (cnt > 0)
write(nev, cnt);
- }
}
void HubConnection::processSample(uint64_t timestamp, uint32_t type, uint32_t sensor, struct ThreeAxisSample *sample, bool highAccuracy)
@@ -678,7 +803,7 @@
sensors_vec_t *sv;
uncalibrated_event_t *ue;
sensors_event_t *ev;
- sensors_event_t nev[2];
+ sensors_event_t nev[3];
static const float heading_accuracy = M_PI / 6.0f;
float w;
int cnt = 0;
@@ -690,22 +815,38 @@
sv->y = sample->y;
sv->z = sample->z;
sv->status = SENSOR_STATUS_ACCURACY_HIGH;
- sendDirectReportEvent(&nev[cnt], 1);
- if (mSensorState[sensor].enable) {
+ sendDirectReportEvent(&nev[cnt], 1);
+ if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) {
++cnt;
}
- if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable) {
- ue = &initEv(&nev[cnt++], timestamp,
- SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED,
- COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer;
- ue->x_uncalib = sample->x + mAccelBias[0];
- ue->y_uncalib = sample->y + mAccelBias[1];
- ue->z_uncalib = sample->z + mAccelBias[2];
- ue->x_bias = mAccelBias[0];
- ue->y_bias = mAccelBias[1];
- ue->z_bias = mAccelBias[2];
+ ue = &initEv(&nev[cnt], timestamp,
+ SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED,
+ COMMS_SENSOR_ACCEL_UNCALIBRATED)->uncalibrated_accelerometer;
+ ue->x_uncalib = sample->x + mAccelBias[0];
+ ue->y_uncalib = sample->y + mAccelBias[1];
+ ue->z_uncalib = sample->z + mAccelBias[2];
+ ue->x_bias = mAccelBias[0];
+ ue->y_bias = mAccelBias[1];
+ ue->z_bias = mAccelBias[2];
+
+ sendDirectReportEvent(&nev[cnt], 1);
+ if (mSensorState[COMMS_SENSOR_ACCEL_UNCALIBRATED].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_UNCALIBRATED, timestamp)) {
+ ++cnt;
+ }
+
+ if (mSensorState[COMMS_SENSOR_ACCEL_WRIST_AWARE].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_ACCEL_WRIST_AWARE, timestamp)) {
+ sv = &initEv(&nev[cnt], timestamp,
+ SENSOR_TYPE_ACCELEROMETER_WRIST_AWARE,
+ COMMS_SENSOR_ACCEL_WRIST_AWARE)->acceleration;
+ sv->x = sample->x;
+ sv->y = (mLefty.accel ? -sample->y : sample->y);
+ sv->z = sample->z;
+ sv->status = SENSOR_STATUS_ACCURACY_HIGH;
+ ++cnt;
}
break;
case COMMS_SENSOR_GYRO:
@@ -714,22 +855,38 @@
sv->y = sample->y;
sv->z = sample->z;
sv->status = SENSOR_STATUS_ACCURACY_HIGH;
- sendDirectReportEvent(&nev[cnt], 1);
- if (mSensorState[sensor].enable) {
+ sendDirectReportEvent(&nev[cnt], 1);
+ if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) {
++cnt;
}
- if (mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].enable) {
- ue = &initEv(&nev[cnt++], timestamp,
- SENSOR_TYPE_GYROSCOPE_UNCALIBRATED,
- COMMS_SENSOR_GYRO_UNCALIBRATED)->uncalibrated_gyro;
- ue->x_uncalib = sample->x + mGyroBias[0];
- ue->y_uncalib = sample->y + mGyroBias[1];
- ue->z_uncalib = sample->z + mGyroBias[2];
- ue->x_bias = mGyroBias[0];
- ue->y_bias = mGyroBias[1];
- ue->z_bias = mGyroBias[2];
+ ue = &initEv(&nev[cnt], timestamp,
+ SENSOR_TYPE_GYROSCOPE_UNCALIBRATED,
+ COMMS_SENSOR_GYRO_UNCALIBRATED)->uncalibrated_gyro;
+ ue->x_uncalib = sample->x + mGyroBias[0];
+ ue->y_uncalib = sample->y + mGyroBias[1];
+ ue->z_uncalib = sample->z + mGyroBias[2];
+ ue->x_bias = mGyroBias[0];
+ ue->y_bias = mGyroBias[1];
+ ue->z_bias = mGyroBias[2];
+ sendDirectReportEvent(&nev[cnt], 1);
+
+ if (mSensorState[COMMS_SENSOR_GYRO_UNCALIBRATED].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_GYRO_UNCALIBRATED, timestamp)) {
+ ++cnt;
+ }
+
+ if (mSensorState[COMMS_SENSOR_GYRO_WRIST_AWARE].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_GYRO_WRIST_AWARE, timestamp)) {
+ sv = &initEv(&nev[cnt], timestamp,
+ SENSOR_TYPE_GYROSCOPE_WRIST_AWARE,
+ COMMS_SENSOR_GYRO_WRIST_AWARE)->gyro;
+ sv->x = (mLefty.gyro ? -sample->x : sample->x);
+ sv->y = sample->y;
+ sv->z = (mLefty.gyro ? -sample->z : sample->z);
+ sv->status = SENSOR_STATUS_ACCURACY_HIGH;
+ ++cnt;
}
break;
case COMMS_SENSOR_ACCEL_BIAS:
@@ -752,20 +909,24 @@
sv->status = magAccuracyUpdate(sv);
sendDirectReportEvent(&nev[cnt], 1);
- if (mSensorState[sensor].enable) {
+ if (mSensorState[sensor].enable && isSampleIntervalSatisfied(sensor, timestamp)) {
++cnt;
}
- if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable) {
- ue = &initEv(&nev[cnt++], timestamp,
- SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
- COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic;
- ue->x_uncalib = sample->x + mMagBias[0];
- ue->y_uncalib = sample->y + mMagBias[1];
- ue->z_uncalib = sample->z + mMagBias[2];
- ue->x_bias = mMagBias[0];
- ue->y_bias = mMagBias[1];
- ue->z_bias = mMagBias[2];
+ ue = &initEv(&nev[cnt], timestamp,
+ SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
+ COMMS_SENSOR_MAG_UNCALIBRATED)->uncalibrated_magnetic;
+ ue->x_uncalib = sample->x + mMagBias[0];
+ ue->y_uncalib = sample->y + mMagBias[1];
+ ue->z_uncalib = sample->z + mMagBias[2];
+ ue->x_bias = mMagBias[0];
+ ue->y_bias = mMagBias[1];
+ ue->z_bias = mMagBias[2];
+ sendDirectReportEvent(&nev[cnt], 1);
+
+ if (mSensorState[COMMS_SENSOR_MAG_UNCALIBRATED].enable
+ && isSampleIntervalSatisfied(COMMS_SENSOR_MAG_UNCALIBRATED, timestamp)) {
+ ++cnt;
}
break;
case COMMS_SENSOR_MAG_BIAS:
@@ -821,11 +982,8 @@
break;
}
- if (cnt > 0) {
- // If event is a wake event, protect it with a wakelock
- protectIfWakeEvent(sensor);
+ if (cnt > 0)
write(nev, cnt);
- }
}
void HubConnection::discardInotifyEvent() {
@@ -870,7 +1028,7 @@
cmd.sensorType, i, mSensorState[i].enable, frequency_q10_to_period_ns(mSensorState[i].rate),
mSensorState[i].latency);
- int ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
+ int ret = sendCmd(&cmd, sizeof(cmd));
if (ret != sizeof(cmd)) {
ALOGW("failed to send config command to restore sensor %d\n", cmd.sensorType);
}
@@ -879,7 +1037,7 @@
for (auto iter = mFlushesPending[i].cbegin(); iter != mFlushesPending[i].cend(); ++iter) {
for (int j = 0; j < iter->count; j++) {
- int ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
+ int ret = sendCmd(&cmd, sizeof(cmd));
if (ret != sizeof(cmd)) {
ALOGW("failed to send flush command to sensor %d\n", cmd.sensorType);
}
@@ -915,6 +1073,9 @@
case 'D':
ALOGD("osLog: %s", &buf[5]);
break;
+ case 'V':
+ ALOGV("osLog: %s", &buf[5]);
+ break;
default:
break;
}
@@ -1261,13 +1422,18 @@
ev.sensor = 0;
ev.meta_data.what = META_DATA_FLUSH_COMPLETE;
ev.meta_data.sensor = flush.handle;
- --flush.count;
- if (flush.count == 0) {
+ if (flush.internal) {
+ if (flush.handle == COMMS_SENSOR_ACCEL_WRIST_AWARE)
+ mLefty.accel = !mLefty.accel;
+ else if (flush.handle == COMMS_SENSOR_GYRO_WRIST_AWARE)
+ mLefty.gyro = !mLefty.gyro;
+ } else
+ write(&ev, 1);
+
+ if (--flush.count == 0)
mFlushesPending[primary].pop_front();
- }
- write(&ev, 1);
ALOGV("flushing %d", ev.meta_data.sensor);
}
}
@@ -1456,10 +1622,6 @@
return false;
}
-ssize_t HubConnection::read(sensors_event_t *ev, size_t size) {
- return mRing.read(ev, size);
-}
-
void HubConnection::setActivityCallback(ActivityEventHandler *eventHandler)
{
Mutex::Autolock autoLock(mLock);
@@ -1468,31 +1630,28 @@
void HubConnection::initConfigCmd(struct ConfigCmd *cmd, int handle)
{
- uint8_t alt = mSensorState[handle].alt;
-
memset(cmd, 0x00, sizeof(*cmd));
cmd->evtType = EVT_NO_SENSOR_CONFIG_EVENT;
cmd->sensorType = mSensorState[handle].sensorType;
+ cmd->cmd = mSensorState[handle].enable ? CONFIG_CMD_ENABLE : CONFIG_CMD_DISABLE;
+ cmd->rate = mSensorState[handle].rate;
+ cmd->latency = mSensorState[handle].latency;
- if (alt && mSensorState[alt].enable && mSensorState[handle].enable) {
+ for (int i=0; i<MAX_ALTERNATES; ++i) {
+ uint8_t alt = mSensorState[handle].alt[i];
+
+ if (alt == COMMS_SENSOR_INVALID) continue;
+ if (!mSensorState[alt].enable) continue;
+
cmd->cmd = CONFIG_CMD_ENABLE;
- if (mSensorState[alt].rate > mSensorState[handle].rate)
+
+ if (mSensorState[alt].rate > cmd->rate) {
cmd->rate = mSensorState[alt].rate;
- else
- cmd->rate = mSensorState[handle].rate;
- if (mSensorState[alt].latency < mSensorState[handle].latency)
+ }
+ if (mSensorState[alt].latency < cmd->latency) {
cmd->latency = mSensorState[alt].latency;
- else
- cmd->latency = mSensorState[handle].latency;
- } else if (alt && mSensorState[alt].enable) {
- cmd->cmd = mSensorState[alt].enable ? CONFIG_CMD_ENABLE : CONFIG_CMD_DISABLE;
- cmd->rate = mSensorState[alt].rate;
- cmd->latency = mSensorState[alt].latency;
- } else { /* !alt || !mSensorState[alt].enable */
- cmd->cmd = mSensorState[handle].enable ? CONFIG_CMD_ENABLE : CONFIG_CMD_DISABLE;
- cmd->rate = mSensorState[handle].rate;
- cmd->latency = mSensorState[handle].latency;
+ }
}
// will be a nop if direct report mode is not enabled
@@ -1511,10 +1670,12 @@
initConfigCmd(&cmd, handle);
- ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
- if (ret == sizeof(cmd))
+ ret = sendCmd(&cmd, sizeof(cmd));
+ if (ret == sizeof(cmd)) {
+ updateSampleRate(handle, enable ? CONFIG_CMD_ENABLE : CONFIG_CMD_DISABLE);
ALOGV("queueActivate: sensor=%d, handle=%d, enable=%d",
cmd.sensorType, handle, enable);
+ }
else
ALOGW("queueActivate: failed to send command: sensor=%d, handle=%d, enable=%d",
cmd.sensorType, handle, enable);
@@ -1539,7 +1700,7 @@
initConfigCmd(&cmd, handle);
- ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
+ ret = sendCmd(&cmd, sizeof(cmd));
if (ret == sizeof(cmd))
ALOGV("queueSetDelay: sensor=%d, handle=%d, period=%" PRId64,
cmd.sensorType, handle, sampling_period_ns);
@@ -1571,13 +1732,15 @@
initConfigCmd(&cmd, handle);
- ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
- if (ret == sizeof(cmd))
+ ret = sendCmd(&cmd, sizeof(cmd));
+ if (ret == sizeof(cmd)) {
+ updateSampleRate(handle, CONFIG_CMD_ENABLE); // batch uses CONFIG_CMD_ENABLE command
ALOGV("queueBatch: sensor=%d, handle=%d, period=%" PRId64 ", latency=%" PRId64,
cmd.sensorType, handle, sampling_period_ns, max_report_latency_ns);
- else
+ } else {
ALOGW("queueBatch: failed to send command: sensor=%d, handle=%d, period=%" PRId64 ", latency=%" PRId64,
cmd.sensorType, handle, sampling_period_ns, max_report_latency_ns);
+ }
} else {
ALOGV("queueBatch: unhandled handle=%d, period=%" PRId64 ", latency=%" PRId64,
handle, sampling_period_ns, max_report_latency_ns);
@@ -1586,12 +1749,16 @@
void HubConnection::queueFlush(int handle)
{
+ Mutex::Autolock autoLock(mLock);
+ queueFlushInternal(handle, false);
+}
+
+void HubConnection::queueFlushInternal(int handle, bool internal)
+{
struct ConfigCmd cmd;
uint32_t primary;
int ret;
- Mutex::Autolock autoLock(mLock);
-
if (isValidHandle(handle)) {
// If no primary sensor type is specified,
// then 'handle' is the primary sensor type.
@@ -1600,16 +1767,18 @@
std::list<Flush>& flushList = mFlushesPending[primary];
- if (!flushList.empty() && flushList.back().handle == handle) {
+ if (!flushList.empty() &&
+ flushList.back().internal == internal &&
+ flushList.back().handle == handle) {
++flushList.back().count;
} else {
- flushList.push_back((struct Flush){handle, 1});
+ flushList.push_back((struct Flush){handle, 1, internal});
}
initConfigCmd(&cmd, handle);
cmd.cmd = CONFIG_CMD_FLUSH;
- ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
+ ret = sendCmd(&cmd, sizeof(cmd));
if (ret == sizeof(cmd)) {
ALOGV("queueFlush: sensor=%d, handle=%d",
cmd.sensorType, handle);
@@ -1632,7 +1801,7 @@
memcpy(cmd->data, data, length);
cmd->cmd = CONFIG_CMD_CFG_DATA;
- ret = TEMP_FAILURE_RETRY(::write(mFd, cmd, sizeof(*cmd) + length));
+ ret = sendCmd(cmd, sizeof(*cmd) + length);
if (ret == sizeof(*cmd) + length)
ALOGV("queueData: sensor=%d, length=%zu",
cmd->sensorType, length);
@@ -1702,8 +1871,44 @@
}
}
+ssize_t HubConnection::read(sensors_event_t *ev, size_t size) {
+ ssize_t n = mRing.read(ev, size);
+
+ Mutex::Autolock autoLock(mLock);
+
+ // We log the first failure in write, so only log 2+ errors
+ if (mWriteFailures > 1) {
+ ALOGW("%s: mRing.write failed %d times",
+ __FUNCTION__, mWriteFailures);
+ mWriteFailures = 0;
+ }
+
+ for (ssize_t i = 0; i < n; i++)
+ decrementIfWakeEventLocked(ev[i].sensor);
+
+ return n;
+}
+
+
ssize_t HubConnection::write(const sensors_event_t *ev, size_t n) {
- return mRing.write(ev, n);
+ ssize_t ret = 0;
+
+ Mutex::Autolock autoLock(mLock);
+
+ for (size_t i=0; i<n; i++) {
+ if (mRing.write(&ev[i], 1) == 1) {
+ ret++;
+ // If event is a wake event, protect it with a wakelock
+ protectIfWakeEventLocked(ev[i].sensor);
+ } else {
+ if (mWriteFailures++ == 0)
+ ALOGW("%s: mRing.write failed @ %zu/%zu",
+ __FUNCTION__, i, n);
+ break;
+ }
+ }
+
+ return ret;
}
#ifdef USB_MAG_BIAS_REPORTING_ENABLED
@@ -1718,7 +1923,7 @@
cmd->msg.dataLen = sizeof(float);
memcpy((float *)(cmd+1), &mUsbMagBias, sizeof(float));
- ret = TEMP_FAILURE_RETRY(::write(mFd, cmd, sizeof(*cmd) + sizeof(float)));
+ ret = sendCmd(cmd, sizeof(*cmd) + sizeof(float));
if (ret == sizeof(*cmd) + sizeof(float))
ALOGV("queueUsbMagBias: bias=%f\n", mUsbMagBias);
else
@@ -1820,7 +2025,14 @@
auto i = mSensorToChannel.find(nev->sensor);
if (i != mSensorToChannel.end()) {
for (auto &j : i->second) {
- mDirectChannel[j.first]->write(nev);
+ if ((uint64_t)nev->timestamp > j.second.lastTimestamp
+ && intervalLargeEnough(
+ nev->timestamp - j.second.lastTimestamp,
+ rateLevelToDeviceSamplingPeriodNs(
+ nev->sensor, j.second.rateLevel))) {
+ mDirectChannel[j.first]->write(nev);
+ j.second.lastTimestamp = nev->timestamp;
+ }
}
}
++nev;
@@ -1830,35 +2042,31 @@
}
void HubConnection::mergeDirectReportRequest(struct ConfigCmd *cmd, int handle) {
+ int maxRateLevel = SENSOR_DIRECT_RATE_STOP;
+
auto j = mSensorToChannel.find(handle);
if (j != mSensorToChannel.end()) {
- bool enable = false;
- rate_q10_t rate;
-
- if (!j->second.empty()) {
- int maxRateLevel = SENSOR_DIRECT_RATE_STOP;
+ for (auto &i : j->second) {
+ maxRateLevel = std::max(i.second.rateLevel, maxRateLevel);
+ }
+ }
+ for (auto handle : mSensorState[handle].alt) {
+ auto j = mSensorToChannel.find(handle);
+ if (j != mSensorToChannel.end()) {
for (auto &i : j->second) {
- maxRateLevel = (i.second) > maxRateLevel ? i.second : maxRateLevel;
- }
- switch(maxRateLevel) {
- case SENSOR_DIRECT_RATE_NORMAL:
- enable = true;
- rate = period_ns_to_frequency_q10(20000000ull); // NORMAL = 50Hz
- break;
- case SENSOR_DIRECT_RATE_FAST:
- enable = true;
- rate = period_ns_to_frequency_q10(5000000ull); // FAST = 200Hz
- break;
- default:
- break;
+ maxRateLevel = std::max(i.second.rateLevel, maxRateLevel);
}
}
+ }
- if (enable) {
- cmd->rate = (rate > cmd->rate || cmd->cmd == CONFIG_CMD_DISABLE) ? rate : cmd->rate;
- cmd->latency = 0;
- cmd->cmd = CONFIG_CMD_ENABLE;
- }
+ uint64_t period = rateLevelToDeviceSamplingPeriodNs(handle, maxRateLevel);
+ if (period != INT64_MAX) {
+ rate_q10_t rate;
+ rate = period_ns_to_frequency_q10(period);
+
+ cmd->rate = (rate > cmd->rate || cmd->cmd == CONFIG_CMD_DISABLE) ? rate : cmd->rate;
+ cmd->latency = 0;
+ cmd->cmd = CONFIG_CMD_ENABLE;
}
}
@@ -1866,6 +2074,13 @@
std::unique_ptr<DirectChannelBase> ch;
int ret = NO_MEMORY;
+ Mutex::Autolock autoLock(mDirectChannelLock);
+ for (const auto& c : mDirectChannel) {
+ if (c.second->memoryMatches(mem)) {
+ // cannot reusing same memory
+ return BAD_VALUE;
+ }
+ }
switch(mem->type) {
case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
ch = std::make_unique<AshmemDirectChannel>(mem);
@@ -1879,7 +2094,6 @@
if (ch) {
if (ch->isValid()) {
- Mutex::Autolock autoLock(mDirectChannelLock);
ret = mDirectChannelHandle++;
mDirectChannel.insert(std::make_pair(ret, std::move(ch)));
} else {
@@ -1941,7 +2155,7 @@
struct ConfigCmd cmd;
initConfigCmd(&cmd, sensor_handle);
- int result = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
+ int result = sendCmd(&cmd, sizeof(cmd));
ret = ret && (result == sizeof(cmd));
}
return ret ? NO_ERROR : BAD_VALUE;
@@ -1975,14 +2189,14 @@
j->second.erase(channel_handle);
if (rate_level != SENSOR_DIRECT_RATE_STOP) {
- j->second.insert(std::make_pair(channel_handle, rate_level));
+ j->second.insert(std::make_pair(channel_handle, (DirectChannelTimingInfo){0, rate_level}));
}
Mutex::Autolock autoLock2(mLock);
struct ConfigCmd cmd;
initConfigCmd(&cmd, sensor_handle);
- int ret = TEMP_FAILURE_RETRY(::write(mFd, &cmd, sizeof(cmd)));
+ int ret = sendCmd(&cmd, sizeof(cmd));
if (rate_level == SENSOR_DIRECT_RATE_STOP) {
ret = NO_ERROR;
@@ -1995,6 +2209,80 @@
bool HubConnection::isDirectReportSupported() const {
return true;
}
+
+void HubConnection::updateSampleRate(int handle, int reason) {
+ bool affected = mSensorToChannel.find(handle) != mSensorToChannel.end();
+ for (size_t i = 0; i < MAX_ALTERNATES && !affected; ++i) {
+ if (mSensorState[handle].alt[i] != COMMS_SENSOR_INVALID) {
+ affected |=
+ mSensorToChannel.find(mSensorState[handle].alt[i]) != mSensorToChannel.end();
+ }
+ }
+ if (!affected) {
+ return;
+ }
+
+ switch (reason) {
+ case CONFIG_CMD_ENABLE: {
+ constexpr uint64_t PERIOD_800HZ = 1250000;
+ uint64_t period_multiplier =
+ (frequency_q10_to_period_ns(mSensorState[handle].rate) + PERIOD_800HZ / 2)
+ / PERIOD_800HZ;
+ uint64_t desiredTSample = PERIOD_800HZ;
+ while (period_multiplier /= 2) {
+ desiredTSample *= 2;
+ }
+ mSensorState[handle].desiredTSample = desiredTSample;
+ ALOGV("DesiredTSample for handle 0x%x set to %" PRIu64, handle, desiredTSample);
+ break;
+ }
+ case CONFIG_CMD_DISABLE:
+ mSensorState[handle].desiredTSample = INT64_MAX;
+ ALOGV("DesiredTSample 0x%x set to disable", handle);
+ break;
+ default:
+ ALOGW("%s: unexpected reason = %d, no-op", __FUNCTION__, reason);
+ break;
+ }
+}
+
+bool HubConnection::isSampleIntervalSatisfied(int handle, uint64_t timestamp) {
+ if (mSensorToChannel.find(handle) == mSensorToChannel.end()) {
+ return true;
+ }
+
+ if (mSensorState[handle].lastTimestamp >= timestamp
+ || mSensorState[handle].desiredTSample == INT64_MAX) {
+ return false;
+ } else if (intervalLargeEnough(timestamp - mSensorState[handle].lastTimestamp,
+ mSensorState[handle].desiredTSample)) {
+ mSensorState[handle].lastTimestamp = timestamp;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+uint64_t HubConnection::rateLevelToDeviceSamplingPeriodNs(int handle, int rateLevel) const {
+ if (mSensorToChannel.find(handle) == mSensorToChannel.end()) {
+ return INT64_MAX;
+ }
+
+ switch (rateLevel) {
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ // No sensor support VERY_FAST, fall through
+ case SENSOR_DIRECT_RATE_FAST:
+ if (handle != COMMS_SENSOR_MAG && handle != COMMS_SENSOR_MAG_UNCALIBRATED) {
+ return 2500*1000; // 400Hz
+ }
+ // fall through
+ case SENSOR_DIRECT_RATE_NORMAL:
+ return 20*1000*1000; // 50 Hz
+ // fall through
+ default:
+ return INT64_MAX;
+ }
+}
#else // DIRECT_REPORT_ENABLED
// nop functions if feature is turned off
int HubConnection::addDirectChannel(const struct sensors_direct_mem_t *) {
@@ -2018,6 +2306,13 @@
bool HubConnection::isDirectReportSupported() const {
return false;
}
+
+void HubConnection::updateSampleRate(int, int) {
+}
+
+bool HubConnection::isSampleIntervalSatisfied(int, uint64_t) {
+ return true;
+}
#endif // DIRECT_REPORT_ENABLED
} // namespace android
diff --git a/sensorhal/hubconnection.h b/sensorhal/hubconnection.h
index 4ad4b40..558ece3 100644
--- a/sensorhal/hubconnection.h
+++ b/sensorhal/hubconnection.h
@@ -47,6 +47,8 @@
#define GYRO_SW_BIAS_TAG "gyro_sw"
#define MAG_BIAS_TAG "mag"
+#define MAX_ALTERNATES 2
+
namespace android {
struct HubConnection : public Thread {
@@ -74,10 +76,7 @@
void setOperationParameter(const additional_info_event_t &info);
- bool isWakeEvent(int32_t sensor);
void releaseWakeLockIfAppropriate();
- ssize_t getWakeEventCount();
- ssize_t decrementWakeEventCount();
//TODO: factor out event ring buffer functionality into a separate class
ssize_t read(sensors_event_t *ev, size_t size);
@@ -92,6 +91,8 @@
mScaleMag = scaleMag;
}
+ void setLeftyMode(bool enable);
+
protected:
HubConnection();
virtual ~HubConnection();
@@ -104,7 +105,8 @@
bool mWakelockHeld;
int32_t mWakeEventCount;
- void protectIfWakeEvent(int32_t sensor);
+ void protectIfWakeEventLocked(int32_t sensor);
+ ssize_t decrementIfWakeEventLocked(int32_t sensor);
static inline uint64_t period_ns_to_frequency_q10(nsecs_t period_ns) {
return 1024000000000ULL / period_ns;
@@ -147,18 +149,31 @@
struct HostHubRawPacket msg;
} __attribute__((packed));
+ struct LeftyState
+ {
+ bool accel; // Process wrist-aware accel samples as lefty mode
+ bool gyro; // Process wrist-aware gyro samples as lefty mode
+ bool hub; // Sensor hub is currently operating in lefty mode
+ };
+
struct Flush
{
int handle;
uint8_t count;
+
+ // Used to synchronize the transition in and out of
+ // lefty mode between nanohub and the AP.
+ bool internal;
};
struct SensorState {
uint64_t latency;
+ uint64_t lastTimestamp;
+ uint64_t desiredTSample;
rate_q10_t rate;
uint8_t sensorType;
uint8_t primary;
- uint8_t alt;
+ uint8_t alt[MAX_ALTERNATES];
bool enable;
};
@@ -224,6 +239,7 @@
Mutex mLock;
RingBuffer mRing;
+ int32_t mWriteFailures;
ActivityEventHandler *mActivityEventHandler;
@@ -236,6 +252,8 @@
float mScaleAccel, mScaleMag;
+ LeftyState mLefty;
+
SensorState mSensorState[NUM_COMMS_SENSORS_PLUS_1];
std::list<struct Flush> mFlushesPending[NUM_COMMS_SENSORS_PLUS_1];
@@ -262,8 +280,11 @@
&& mSensorState[handle].sensorType;
}
+ ssize_t sendCmd(const void *buf, size_t count);
void initConfigCmd(struct ConfigCmd *cmd, int handle);
+ void queueFlushInternal(int handle, bool internal);
+
void queueDataInternal(int handle, void *data, size_t length);
void discardInotifyEvent();
@@ -304,12 +325,24 @@
private:
void sendDirectReportEvent(const sensors_event_t *nev, size_t n);
void mergeDirectReportRequest(struct ConfigCmd *cmd, int handle);
+ bool isSampleIntervalSatisfied(int handle, uint64_t timestamp);
+ void updateSampleRate(int handle, int reason);
#ifdef DIRECT_REPORT_ENABLED
int stopAllDirectReportOnChannel(
int channel_handle, std::vector<int32_t> *unstoppedSensors);
+ uint64_t rateLevelToDeviceSamplingPeriodNs(int handle, int rateLevel) const;
+ inline static bool intervalLargeEnough(uint64_t actual, uint64_t desired) {
+ return (actual + (actual >> 4)) >= desired; // >= 94.11% of desired
+ }
+
+ struct DirectChannelTimingInfo{
+ uint64_t lastTimestamp;
+ int rateLevel;
+ };
Mutex mDirectChannelLock;
- //sensor_handle=>(channel_handle, rate_level)
- std::unordered_map<int32_t, std::unordered_map<int32_t, int32_t> > mSensorToChannel;
+ //sensor_handle=>(channel_handle => DirectChannelTimingInfo)
+ std::unordered_map<int32_t,
+ std::unordered_map<int32_t, DirectChannelTimingInfo> > mSensorToChannel;
//channel_handle=>ptr of Channel obj
std::unordered_map<int32_t, std::unique_ptr<DirectChannelBase>> mDirectChannel;
int32_t mDirectChannelHandle;
diff --git a/sensorhal/hubdefs.h b/sensorhal/hubdefs.h
index 9664e2b..f63cc42 100644
--- a/sensorhal/hubdefs.h
+++ b/sensorhal/hubdefs.h
@@ -84,6 +84,8 @@
COMMS_SENSOR_UNGAZE = 46,
COMMS_SENSOR_ACCEL_UNCALIBRATED = 47,
COMMS_SENSOR_HUMIDITY = 48,
+ COMMS_SENSOR_ACCEL_WRIST_AWARE = 49,
+ COMMS_SENSOR_GYRO_WRIST_AWARE = 50,
COMMS_SENSOR_AMBIENT_TEMPERATURE = 51,
NUM_COMMS_SENSORS_PLUS_1,
@@ -118,6 +120,8 @@
SENSOR_TYPE_DOUBLE_TOUCH = SENSOR_TYPE_DEVICE_PRIVATE_BASE + 4,
SENSOR_TYPE_GAZE = SENSOR_TYPE_DEVICE_PRIVATE_BASE + 5,
SENSOR_TYPE_UNGAZE = SENSOR_TYPE_DEVICE_PRIVATE_BASE + 6,
+ SENSOR_TYPE_ACCELEROMETER_WRIST_AWARE=SENSOR_TYPE_DEVICE_PRIVATE_BASE + 7,
+ SENSOR_TYPE_GYROSCOPE_WRIST_AWARE = SENSOR_TYPE_DEVICE_PRIVATE_BASE + 8,
};
} // namespace android
diff --git a/sensorhal/sensors.cpp b/sensorhal/sensors.cpp
index 65b881c..234f7da 100644
--- a/sensorhal/sensors.cpp
+++ b/sensorhal/sensors.cpp
@@ -35,6 +35,10 @@
#include <SensorEventCallback.h>
#endif
+#ifdef LEFTY_SERVICE_ENABLED
+#include "lefty_service.h"
+#endif
+
using namespace android;
////////////////////////////////////////////////////////////////////////////////
@@ -101,28 +105,7 @@
// Release wakelock if held and no more events in ring buffer
mHubConnection->releaseWakeLockIfAppropriate();
- ssize_t n = mHubConnection->read(data, count);
-
- if (n < 0) {
- return -1;
- }
-
- // If we have wake events in the queue, determine how many we're sending
- // up this round and decrement that count now so that when we get called back,
- // we'll have an accurate count of how many wake events are STILL in the HAL queue
- // to be able to determine whether we can release our wakelock if held.
- if (mHubConnection->getWakeEventCount() != 0) {
- for (ssize_t i = 0; i < n; i++) {
- if (mHubConnection->isWakeEvent(data[i].sensor)) {
- ssize_t count = mHubConnection->decrementWakeEventCount();
- if (count == 0) {
- break;
- }
- }
- }
- }
-
- return n;
+ return mHubConnection->read(data, count);
}
int SensorContext::batch(
@@ -407,6 +390,9 @@
gHubAlive = ctx->getHubAlive();
*dev = &ctx->device.common;
+#ifdef LEFTY_SERVICE_ENABLED
+ register_lefty_service();
+#endif
return 0;
}
diff --git a/util/common/ring.cpp b/util/common/ring.cpp
index 26d44d6..245f3d0 100644
--- a/util/common/ring.cpp
+++ b/util/common/ring.cpp
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
+#include <atomic>
namespace android {
@@ -120,8 +121,18 @@
}
while(size--) {
- mData[mWritePos] = *(ev++);
+ // part before reserved0 field
+ memcpy(&mData[mWritePos], ev, offsetof(sensors_event_t, reserved0));
+ // part after reserved0 field
+ memcpy(reinterpret_cast<char *>(&mData[mWritePos]) + offsetof(sensors_event_t, timestamp),
+ reinterpret_cast<const char *>(ev) + offsetof(sensors_event_t, timestamp),
+ sizeof(sensors_event_t) - offsetof(sensors_event_t, timestamp));
+ // barrier before writing the atomic counter
+ std::atomic_thread_fence(std::memory_order_release);
mData[mWritePos].reserved0 = mCounter++;
+ // barrier after writing the atomic counter
+ std::atomic_thread_fence(std::memory_order_release);
+ ++ev;
if (++mWritePos >= mSize) {
mWritePos = 0;
diff --git a/util/nanoapp_cmd/nanoapp_cmd.c b/util/nanoapp_cmd/nanoapp_cmd.c
index 28456d6..5692181 100644
--- a/util/nanoapp_cmd/nanoapp_cmd.c
+++ b/util/nanoapp_cmd/nanoapp_cmd.c
@@ -484,7 +484,7 @@
LOGE("Download failed after %d retries; erasing all apps "
"before final attempt", i);
eraseSharedArea();
- uninstallCnt = 0;
+ parseConfigAppInfo(&installCnt, &uninstallCnt);
}
removeApps(uninstallCnt);
downloadApps(installCnt);