Commit 723f747b authored by Florian Hars's avatar Florian Hars
Browse files

support more bhi160 sensors

parent 1eef5c51
Pipeline #4337 passed with stages
in 1 minute and 51 seconds
......@@ -34,11 +34,11 @@ clockwise around their respective axis.
utime.sleep(0.25)
Orientation
-----------
.. autoclass:: bhi160.BHI160Orientation
:members:
:inherited-members:
.. autoclass:: bhi160.BHI160
.. autoclass:: bhi160.BHI160Vector
.. autoclass:: bhi160.BHI160Quaternion
Accelerometer
-------------
......@@ -46,6 +46,14 @@ Accelerometer
:members:
:inherited-members:
.. autoclass:: bhi160.BHI160Gravity
:members:
:inherited-members:
.. autoclass:: bhi160.BHI160LinearAcceleration
:members:
:inherited-members:
Gyroscope
---------
.. autoclass:: bhi160.BHI160Gyroscope
......@@ -55,5 +63,25 @@ Gyroscope
Magnetometer
------------
.. autoclass:: bhi160.BHI160Magnetometer
:members:
:inherited-members:
Orientation
-----------
.. autoclass:: bhi160.BHI160Orientation
:members:
:inherited-members:
Rotation
--------
.. autoclass:: bhi160.BHI160Rotation
:members:
:inherited-members:
.. autoclass:: bhi160.BHI160GameRotation
:members:
:inherited-members:
.. autoclass:: bhi160.BHI160GeomagneticRotation
:members:
:inherited-members:
......@@ -186,26 +186,37 @@ API(API_INTERRUPT_DISABLE, int epic_interrupt_disable(api_int_id_t int_id));
/* clang-format off */
/** Reset Handler */
#define EPIC_INT_RESET 0
#define EPIC_INT_RESET 0
/** ``^C`` interrupt. See :c:func:`epic_isr_ctrl_c` for details. */
#define EPIC_INT_CTRL_C 1
#define EPIC_INT_CTRL_C 1
/** UART Receive interrupt. See :c:func:`epic_isr_uart_rx`. */
#define EPIC_INT_UART_RX 2
#define EPIC_INT_UART_RX 2
/** RTC Alarm interrupt. See :c:func:`epic_isr_rtc_alarm`. */
#define EPIC_INT_RTC_ALARM 3
#define EPIC_INT_RTC_ALARM 3
/** BHI160 Accelerometer. See :c:func:`epic_isr_bhi160_accelerometer`. */
#define EPIC_INT_BHI160_ACCELEROMETER 4
#define EPIC_INT_BHI160_ACCELEROMETER 4
/** BHI160 Orientation Sensor. See :c:func:`epic_isr_bhi160_orientation`. */
#define EPIC_INT_BHI160_ORIENTATION 5
#define EPIC_INT_BHI160_ORIENTATION 5
/** BHI160 Gyroscope. See :c:func:`epic_isr_bhi160_gyroscope`. */
#define EPIC_INT_BHI160_GYROSCOPE 6
#define EPIC_INT_BHI160_GYROSCOPE 6
/** MAX30001 ECG. See :c:func:`epic_isr_max30001_ecg`. */
#define EPIC_INT_MAX30001_ECG 7
#define EPIC_INT_MAX30001_ECG 7
/** BHI160 Magnetometer. See :c:func:`epic_isr_bhi160_magnetometer`. */
#define EPIC_INT_BHI160_MAGNETOMETER 8
#define EPIC_INT_BHI160_MAGNETOMETER 8
/** BHI160 step counter. See :c:func:`epic_isr_bhi160_step_counter`. */
#define EPIC_INT_BHI160_STEP_COUNTER 9
/** BHI160 rotation. See :c:func:`epic_isr_bhi160_rotation_vecor`. */
#define EPIC_INT_BHI160_ROTATION_VECTOR 10
/** BHI160 game rotation. See :c:func:`epic_isr_bhi160_game_rotation_vector`. */
#define EPIC_INT_BHI160_GAME_ROTATION_VECTOR 11
/** BHI160 geomagnetic rotation. See :c:func:`epic_isr_bhi160_geomagnetic_rotation_vector`. */
#define EPIC_INT_BHI160_GEOMAGNETIC_ROTATION_VECTOR 12
/** BHI160 Gravity. See :c:func:`epic_isr_bhi160_gravity`. */
#define EPIC_INT_BHI160_GRAVITY 13
/** BHI160 Linear Acceleration. See :c:func:`epic_isr_bhi160_linear_acceleration`. */
#define EPIC_INT_BHI160_LINEAR_ACCELERATION 14
/* Number of defined interrupts. */
#define EPIC_INT_NUM 9
#define EPIC_INT_NUM 15
/* clang-format on */
/*
......@@ -1049,38 +1060,82 @@ enum bhi160_sensor_type {
* Accelerometer
*
* - Data type: :c:type:`bhi160_data_vector`
* - Dynamic range: g's (1x Earth Gravity, ~9.81m*s^-2)
* - Default dynamic range: g's (1x Earth Gravity, ~9.81m*s^-2)
*/
BHI160_ACCELEROMETER = 0,
/**
* Magnetometer
*
* - Data type: :c:type:`bhi160_data_vector`
* - Dynamic range: -1000 to 1000 microtesla
* - Default dynamic range: -1000 to 1000 microtesla
*/
BHI160_MAGNETOMETER = 1,
/** Orientation */
/** Orientation
*
* - Data type: :c:type:`bhi160_data_vector`
* - Unit: Degrees
* - Scale factor: 360° / 2^{15}
*/
BHI160_ORIENTATION = 2,
/** Gyroscope */
/** Gyroscope
*
* - Data type: :c:type:`bhi160_data_vector`
* - Default dynamic range: 2000°/s
*/
BHI160_GYROSCOPE = 3,
/** Gravity (**Unimplemented**) */
/**
* Gravity
*
* - Data type: :c:type:`bhi160_data_vector`
* - Default dynamic range: g's (1x Earth Gravity, ~9.81m*s^-2)
*/
BHI160_GRAVITY = 4,
/** Linear acceleration (**Unimplemented**) */
/** Linear acceleration
*
* - Data type: :c:type:`bhi160_data_vector`
* - Default dynamic range: g's (1x Earth Gravity, ~9.81m*s^-2)
*/
BHI160_LINEAR_ACCELERATION = 5,
/** Rotation vector (**Unimplemented**) */
/** Rotation vector
*
* - Data type: :c:type:`bhi160_data_quaternion`
* - Unit: unitless / accuracy in radians
* - Scale factor: 2^{-14}
*/
BHI160_ROTATION_VECTOR = 6,
/** Uncalibrated magnetometer (**Unimplemented**) */
BHI160_UNCALIBRATED_MAGNETOMETER = 7,
/** Game rotation vector (whatever that is supposed to be) */
/** Game rotation vector
*
* - Data type: :c:type:`bhi160_data_quaternion`
* - Unit: unitless / accuracy in radians
* - Scale factor: 2^{-14}
*/
BHI160_GAME_ROTATION_VECTOR = 8,
/** Uncalibrated gyroscrope (**Unimplemented**) */
BHI160_UNCALIBRATED_GYROSCOPE = 9,
/** Geomagnetic rotation vector (**Unimplemented**) */
/** Geomagnetic rotation vector
*
* - Data type: :c:type:`bhi160_data_quaternion`
* - Unit: unitless / accuracy in radians
* - Scale factor: 2^{-14}
*/
BHI160_GEOMAGNETIC_ROTATION_VECTOR = 10,
/** Step counter
*
* - Data type: :c:type:`bhi160_data_abs_scalar`
* - Unit: unitless
* - Scale factor: 1
*/
BHI160_STEP_COUNTER = 11,
/** Number of sensors, must alwys be last */
BHI160_SENSOR_NUMBER
};
enum bhi160_data_type {
BHI160_DATA_TYPE_VECTOR
BHI160_DATA_TYPE_VECTOR,
BHI160_DATA_TYPE_QUATERNION,
BHI160_DATA_TYPE_ABS_SCALAR
};
/**
......@@ -1088,13 +1143,28 @@ enum bhi160_data_type {
* ------------------------
*/
/**
* Quaternion Data.
* See the individual sensor's documentation for details.
*/
struct bhi160_data_quaternion {
/** X */
int16_t x;
/** Y */
int16_t y;
/** Z */
int16_t z;
/** W */
int16_t w;
/** Estimated Accuracy */
int16_t accuracy;
};
/**
* Vector Data. The scaling of these values is dependent on the chosen dynamic
* range. See the individual sensor's documentation for details.
*/
struct bhi160_data_vector {
enum bhi160_data_type data_type;
/** X */
int16_t x;
/** Y */
......@@ -1105,6 +1175,14 @@ struct bhi160_data_vector {
uint8_t status;
};
/**
* Absolute Scalar Data.
*/
struct bhi160_data_abs_scalar {
/** Value */
uint16_t value;
};
/**
* BHI160 API
* ----------
......@@ -1208,11 +1286,59 @@ API_ISR(EPIC_INT_BHI160_ORIENTATION, epic_isr_bhi160_orientation);
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_GYROSCOPE`
*
* :c:func:`epic_isr_bhi160_orientation` is called whenever the BHI160
* :c:func:`epic_isr_bhi160_gyroscope` is called whenever the BHI160
* gyroscrope has new data available.
*/
API_ISR(EPIC_INT_BHI160_GYROSCOPE, epic_isr_bhi160_gyroscope);
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_ROTATION_VECTOR`
*
* :c:func:`epic_isr_bhi160_rotation_vector` is called whenever the BHI160
* rotation vecor has new data available.
*/
API_ISR(EPIC_INT_BHI160_ROTATION_VECTOR, epic_isr_bhi160_rotation_vector);
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_GRAVITY`
*
* :c:func:`epic_isr_bhi160_gravity` is called whenever the BHI160
* gravity sensor has new data available.
*/
API_ISR(EPIC_INT_BHI160_GRAVITY, epic_isr_bhi160_gravity);
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_LINEAR_ACCELERATION`
*
* :c:func:`epic_isr_bhi160_linear_acceleration` is called whenever the BHI160
* linear acceleration sensor has new data available.
*/
API_ISR(EPIC_INT_BHI160_LINEAR_ACCELERATION, epic_isr_bhi160_linear_acceleration);
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_GAME_ROTATION_VECTOR`
*
* :c:func:`epic_isr_bhi160_game_rotation_vector` is called whenever the BHI160
* game rotation vecor has new data available.
*/
API_ISR(EPIC_INT_BHI160_GAME_ROTATION_VECTOR, epic_isr_bhi160_game_rotation_vector);
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_GEOMAGNETIC_ROTATION_VECTOR`
*
* :c:func:`epic_isr_bhi160_geomagnetic_rotation_vector` is called whenever the BHI160
* geomagnetic rotation vecor has new data available.
*/
API_ISR(EPIC_INT_BHI160_GEOMAGNETIC_ROTATION_VECTOR, epic_isr_bhi160_geomagnetic_rotation_vector);
/**
* **Interrupt Service Routine** for :c:data:`EPIC_INT_BHI160_STEP_COUNTER`
*
* :c:func:`epic_isr_bhi160_step_counter` is called whenever the BHI160
* step counter has new data available.
*/
API_ISR(EPIC_INT_BHI160_STEP_COUNTER, epic_isr_bhi160_step_counter);
/**
* Vibration Motor
......
......@@ -61,10 +61,10 @@ static StaticSemaphore_t bhi160_mutex_data;
static SemaphoreHandle_t bhi160_mutex = NULL;
/* Streams */
static struct stream_info bhi160_streams[10];
static struct stream_info bhi160_streams[BHI160_SENSOR_NUMBER];
/* Active */
static bool bhi160_sensor_active[10] = { 0 };
static bool bhi160_sensor_active[BHI160_SENSOR_NUMBER] = { 0 };
/* -- Utilities -------------------------------------------------------- {{{ */
/*
......@@ -74,11 +74,19 @@ static bool bhi160_sensor_active[10] = { 0 };
static size_t bhi160_lookup_data_size(enum bhi160_sensor_type type)
{
switch (type) {
case BHI160_ROTATION_VECTOR:
case BHI160_GAME_ROTATION_VECTOR:
case BHI160_GEOMAGNETIC_ROTATION_VECTOR:
return sizeof(struct bhi160_data_quaternion);
case BHI160_ACCELEROMETER:
case BHI160_MAGNETOMETER:
case BHI160_ORIENTATION:
case BHI160_GYROSCOPE:
case BHI160_GRAVITY:
case BHI160_LINEAR_ACCELERATION:
return sizeof(struct bhi160_data_vector);
case BHI160_STEP_COUNTER:
return sizeof(struct bhi160_data_abs_scalar);
default:
return 0;
}
......@@ -98,6 +106,18 @@ static bhy_virtual_sensor_t bhi160_lookup_vs_id(enum bhi160_sensor_type type)
return VS_ID_ORIENTATION;
case BHI160_GYROSCOPE:
return VS_ID_GYROSCOPE;
case BHI160_GRAVITY:
return VS_ID_GRAVITY;
case BHI160_LINEAR_ACCELERATION:
return VS_ID_LINEAR_ACCELERATION;
case BHI160_ROTATION_VECTOR:
return VS_ID_ROTATION_VECTOR;
case BHI160_GAME_ROTATION_VECTOR:
return VS_ID_GAME_ROTATION_VECTOR;
case BHI160_GEOMAGNETIC_ROTATION_VECTOR:
return VS_ID_GEOMAGNETIC_ROTATION_VECTOR;
case BHI160_STEP_COUNTER:
return VS_ID_STEP_COUNTER;
default:
return -1;
}
......@@ -117,6 +137,18 @@ static int bhi160_lookup_sd(enum bhi160_sensor_type type)
return SD_BHI160_ORIENTATION;
case BHI160_GYROSCOPE:
return SD_BHI160_GYROSCOPE;
case BHI160_GRAVITY:
return SD_BHI160_GRAVITY;
case BHI160_LINEAR_ACCELERATION:
return SD_BHI160_LINEAR_ACCELERATION;
case BHI160_ROTATION_VECTOR:
return SD_BHI160_ROTATION_VECTOR;
case BHI160_GAME_ROTATION_VECTOR:
return SD_BHI160_GAME_ROTATION_VECTOR;
case BHI160_GEOMAGNETIC_ROTATION_VECTOR:
return SD_BHI160_GEOMAGNETIC_ROTATION_VECTOR;
case BHI160_STEP_COUNTER:
return SD_BHI160_STEP_COUNTER;
default:
return -1;
}
......@@ -238,14 +270,144 @@ void epic_bhi160_disable_all_sensors()
/* -- Driver ----------------------------------------------------------- {{{ */
/*
* Handle a single packet from the FIFO. For most sensors this means pushing
* the sample into its sample queue.
* Handle a single packet containing a quaternion value.
*/
static void
bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
static void bhi160_handle_quaternion_packet(bhy_data_generic_t *sensor_data)
{
uint8_t sensor_id = sensor_data->data_quaternion.sensor_id;
enum bhi160_sensor_type sensor_type = 0;
int epic_int = 0;
bool wakeup = false;
switch (sensor_id) {
case VS_ID_ROTATION_VECTOR_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_ROTATION_VECTOR:
sensor_type = BHI160_ROTATION_VECTOR;
epic_int = EPIC_INT_BHI160_ROTATION_VECTOR;
break;
case VS_ID_GAME_ROTATION_VECTOR_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_GAME_ROTATION_VECTOR:
sensor_type = BHI160_GAME_ROTATION_VECTOR;
epic_int = EPIC_INT_BHI160_GAME_ROTATION_VECTOR;
break;
case VS_ID_GEOMAGNETIC_ROTATION_VECTOR_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_GEOMAGNETIC_ROTATION_VECTOR:
sensor_type = BHI160_GEOMAGNETIC_ROTATION_VECTOR;
epic_int = EPIC_INT_BHI160_GEOMAGNETIC_ROTATION_VECTOR;
break;
default:
return;
}
assert(bhi160_streams[sensor_type].item_size ==
sizeof(struct bhi160_data_quaternion));
if (bhi160_streams[sensor_type].queue == NULL) {
return;
}
struct bhi160_data_quaternion data_buffer;
data_buffer.x = sensor_data->data_quaternion.x;
data_buffer.y = sensor_data->data_quaternion.y;
data_buffer.z = sensor_data->data_quaternion.z;
data_buffer.w = sensor_data->data_quaternion.w;
data_buffer.accuracy = sensor_data->data_quaternion.estimated_accuracy;
/* Discard overflow. See discussion in !316. */
xQueueSend(bhi160_streams[sensor_type].queue, &data_buffer, 0);
if (wakeup) {
api_interrupt_trigger(epic_int);
}
}
/*
* Handle a single packet containing a vector value.
*/
static void bhi160_handle_vector_packet(bhy_data_generic_t *sensor_data)
{
uint8_t sensor_id = sensor_data->data_vector.sensor_id;
struct bhi160_data_vector data_vector;
enum bhi160_sensor_type sensor_type = 0;
int epic_int = 0;
bool wakeup = false;
switch (sensor_id) {
case VS_ID_ACCELEROMETER_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_ACCELEROMETER:
sensor_type = BHI160_ACCELEROMETER;
epic_int = EPIC_INT_BHI160_ACCELEROMETER;
break;
case VS_ID_MAGNETOMETER_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_MAGNETOMETER:
sensor_type = BHI160_MAGNETOMETER;
epic_int = EPIC_INT_BHI160_MAGNETOMETER;
break;
case VS_ID_ORIENTATION_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_ORIENTATION:
sensor_type = BHI160_ORIENTATION;
epic_int = EPIC_INT_BHI160_ORIENTATION;
break;
case VS_ID_GYROSCOPE_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_GYROSCOPE:
sensor_type = BHI160_GYROSCOPE;
epic_int = EPIC_INT_BHI160_GYROSCOPE;
break;
case VS_ID_GRAVITY_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_GRAVITY:
sensor_type = BHI160_GRAVITY;
epic_int = EPIC_INT_BHI160_GRAVITY;
break;
case VS_ID_LINEAR_ACCELERATION_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_LINEAR_ACCELERATION:
sensor_type = BHI160_LINEAR_ACCELERATION;
epic_int = EPIC_INT_BHI160_LINEAR_ACCELERATION;
break;
default:
return;
}
assert(bhi160_streams[sensor_type].item_size ==
sizeof(struct bhi160_data_vector));
if (bhi160_streams[sensor_type].queue == NULL) {
return;
}
struct bhi160_data_vector data_buffer;
data_buffer.x = sensor_data->data_vector.x;
data_buffer.y = sensor_data->data_vector.y;
data_buffer.z = sensor_data->data_vector.z;
data_buffer.status = sensor_data->data_vector.status;
/* Discard overflow. See discussion in !316. */
xQueueSend(bhi160_streams[sensor_type].queue, &data_buffer, 0);
if (wakeup) {
api_interrupt_trigger(epic_int);
}
}
/*
* Handle a single packet containing an absolute scalar value.
*/
static void bhi160_handle_u16_packet(bhy_data_generic_t *sensor_data)
{
uint8_t sensor_id = sensor_data->data_scalar_u16.sensor_id;
/*
* Timestamp of the next samples, counting at 32 kHz.
* Currently unused.
......@@ -260,72 +422,58 @@ bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
wakeup = true;
/* fall through */
case VS_ID_TIMESTAMP_MSW:
assert(data_type == BHY_DATA_TYPE_SCALAR_U16);
timestamp = sensor_data->data_scalar_u16.data << 16;
break;
case VS_ID_TIMESTAMP_LSW_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_TIMESTAMP_LSW:
assert(data_type == BHY_DATA_TYPE_SCALAR_U16);
timestamp = (timestamp & 0xFFFF0000) |
sensor_data->data_scalar_u16.data;
break;
case VS_ID_ACCELEROMETER_WAKEUP:
case VS_ID_MAGNETOMETER_WAKEUP:
case VS_ID_ORIENTATION_WAKEUP:
case VS_ID_GYROSCOPE_WAKEUP:
case VS_ID_STEP_COUNTER_WAKEUP:
wakeup = true;
/* fall through */
case VS_ID_ACCELEROMETER:
case VS_ID_MAGNETOMETER:
case VS_ID_ORIENTATION:
case VS_ID_GYROSCOPE:
switch (sensor_id) {
case VS_ID_ACCELEROMETER_WAKEUP:
case VS_ID_ACCELEROMETER:
sensor_type = BHI160_ACCELEROMETER;
epic_int = EPIC_INT_BHI160_ACCELEROMETER;
break;
case VS_ID_MAGNETOMETER_WAKEUP:
case VS_ID_MAGNETOMETER:
sensor_type = BHI160_MAGNETOMETER;
epic_int = EPIC_INT_BHI160_MAGNETOMETER;
break;
case VS_ID_ORIENTATION_WAKEUP:
case VS_ID_ORIENTATION:
sensor_type = BHI160_ORIENTATION;
epic_int = EPIC_INT_BHI160_ORIENTATION;
break;
case VS_ID_GYROSCOPE_WAKEUP:
case VS_ID_GYROSCOPE:
sensor_type = BHI160_GYROSCOPE;
epic_int = EPIC_INT_BHI160_GYROSCOPE;
break;
}
assert(data_type == BHY_DATA_TYPE_VECTOR);
case VS_ID_STEP_COUNTER: {
sensor_type = BHI160_STEP_COUNTER;
epic_int = EPIC_INT_BHI160_STEP_COUNTER;
if (bhi160_streams[sensor_type].queue == NULL) {
break;
}
data_vector.data_type = BHI160_DATA_TYPE_VECTOR;
data_vector.x = sensor_data->data_vector.x;
data_vector.y = sensor_data->data_vector.y;
data_vector.z = sensor_data->data_vector.z;
data_vector.status = sensor_data->data_vector.status;
assert(bhi160_streams[sensor_type].item_size ==
sizeof(struct bhi160_data_abs_scalar));
struct bhi160_data_abs_scalar data_buffer;
data_buffer.value = sensor_data->data_scalar_u16.data;
/* Discard overflow. See discussion in !316. */
if (xQueueSend(
bhi160_streams[sensor_type].queue,
&data_vector,
0) != pdTRUE) {
LOG_WARN("bhi160", "queue full for %d", sensor_type);
}
xQueueSend(bhi160_streams[sensor_type].queue, &data_buffer, 0);
if (wakeup) {
api_interrupt_trigger(epic_int);
}
break;
}
default:
break;
}
}
/*
* Handle a single packet from the FIFO. For most sensors this means pushing
* the sample into its sample queue.
*/
static void
bhi160_handle_packet(bhy_data_type_t data_type, bhy_data_generic_t *sensor_data)
{
switch (data_type) {
case BHY_DATA_TYPE_QUATERNION:
bhi160_handle_quaternion_packet(sensor_data);
break;
case BHY_DATA_TYPE_VECTOR:
bhi160_handle_vector_packet(sensor_data);
break;
case BHY_DATA_TYPE_SCALAR_U16:
bhi160_handle_u16_packet(sensor_data);
break;
default:
break;
}
......
......@@ -31,6 +31,12 @@ enum stream_descriptor {
SD_BHI160_MAGNETOMETER,
SD_BHI160_ORIENTATION,
SD_BHI160_GYROSCOPE,
SD_BHI160_GRAVITY,