This is an automated email from the ASF dual-hosted git repository. vipulrahane pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
The following commit(s) were added to refs/heads/master by this push: new 151bb20 Lis2dh12 driver (#1520) 151bb20 is described below commit 151bb202f317409319c1ca10ca11ca32d03f866a Author: JustineKH <35044800+justin...@users.noreply.github.com> AuthorDate: Wed Nov 14 16:59:18 2018 -0800 Lis2dh12 driver (#1520) - Add notifications support and various fixes --- .../sensors/lis2dh12/include/lis2dh12/lis2dh12.h | 316 ++++- hw/drivers/sensors/lis2dh12/src/lis2dh12.c | 1472 ++++++++++++++++++-- hw/drivers/sensors/lis2dh12/src/lis2dh12_priv.h | 37 +- hw/drivers/sensors/lis2dh12/src/lis2dh12_shell.c | 387 +++++ hw/drivers/sensors/lis2dh12/syscfg.yml | 37 +- 5 files changed, 2092 insertions(+), 157 deletions(-) diff --git a/hw/drivers/sensors/lis2dh12/include/lis2dh12/lis2dh12.h b/hw/drivers/sensors/lis2dh12/include/lis2dh12/lis2dh12.h index 7e13fcb..ab4b807 100644 --- a/hw/drivers/sensors/lis2dh12/include/lis2dh12/lis2dh12.h +++ b/hw/drivers/sensors/lis2dh12/include/lis2dh12/lis2dh12.h @@ -77,18 +77,191 @@ extern "C" { #define LIS2DH12_FS_8G 0x20 #define LIS2DH12_FS_16G 0x30 +#define LIS2DH12_CLICK_SRC_IA (1 << 6) +#define LIS2DH12_CLICK_SRC_DCLICK (1 << 5) +#define LIS2DH12_CLICK_SRC_SCLICK (1 << 4) +#define LIS2DH12_CLICK_SRC_SIGN (1 << 3) +#define LIS2DH12_CLICK_SRC_Z (1 << 2) +#define LIS2DH12_CLICK_SRC_Y (1 << 1) +#define LIS2DH12_CLICK_SRC_X (1 << 0) + +#define LIS2DH12_CTRL_REG6_I2_CLICK (1 << 7) +#define LIS2DH12_CTRL_REG6_I2_IA1 (1 << 6) +#define LIS2DH12_CTRL_REG6_I2_IA2 (1 << 5) +#define LIS2DH12_CTRL_REG6_I2_BOOT (1 << 4) +#define LIS2DH12_CTRL_REG6_I2_ACT (1 << 3) +#define LIS2DH12_CTRL_REG6_INT_POLARITY (1 << 1) + +/* int1_src */ +#define LIS2DH12_INT1_IA (1 << 6) +#define LIS2DH12_INT1_ZH (1 << 5) +#define LIS2DH12_INT1_ZL (1 << 4) +#define LIS2DH12_INT1_YH (1 << 3) +#define LIS2DH12_INT1_YL (1 << 2) +#define LIS2DH12_INT1_XH (1 << 1) +#define LIS2DH12_INT1_XL (1 << 0) + +/* int2_src */ +#define LIS2DH12_INT2_IA (1 << 6) +#define LIS2DH12_INT2_ZH (1 << 5) +#define LIS2DH12_INT2_ZL (1 << 4) +#define LIS2DH12_INT2_YH (1 << 3) +#define LIS2DH12_INT2_YL (1 << 2) +#define LIS2DH12_INT2_XH (1 << 1) +#define LIS2DH12_INT2_XL (1 << 0) + +/* int_src */ +#define LIS2DH12_NOTIF_SRC_INT1_IA (LIS2DH12_INT1_IA) +#define LIS2DH12_NOTIF_SRC_INT1_ZH (LIS2DH12_INT1_ZH) +#define LIS2DH12_NOTIF_SRC_INT1_ZL (LIS2DH12_INT1_ZL) +#define LIS2DH12_NOTIF_SRC_INT1_YH (LIS2DH12_INT1_YH) +#define LIS2DH12_NOTIF_SRC_INT1_YL (LIS2DH12_INT1_YL) +#define LIS2DH12_NOTIF_SRC_INT1_XH (LIS2DH12_INT1_XH) +#define LIS2DH12_NOTIF_SRC_INT1_XL (LIS2DH12_INT1_XL) +#define LIS2DH12_NOTIF_SRC_INT2_IA (LIS2DH12_INT2_IA << 8) +#define LIS2DH12_NOTIF_SRC_INT2_ZH (LIS2DH12_INT2_ZH << 8) +#define LIS2DH12_NOTIF_SRC_INT2_ZL (LIS2DH12_INT2_ZL << 8) +#define LIS2DH12_NOTIF_SRC_INT2_YH (LIS2DH12_INT2_YH << 8) +#define LIS2DH12_NOTIF_SRC_INT2_YL (LIS2DH12_INT2_YL << 8) +#define LIS2DH12_NOTIF_SRC_INT2_XH (LIS2DH12_INT2_XH << 8) +#define LIS2DH12_NOTIF_SRC_INT2_XL (LIS2DH12_INT2_XL << 8) + +/* int1 pin config - generate either data ready or in */ +#define LIS2DH12_CTRL_REG3_I1_CLICK (1 << 7) +#define LIS2DH12_CTRL_REG3_I1_IA1 (1 << 6) +#define LIS2DH12_CTRL_REG3_I1_IA2 (1 << 5) +#define LIS2DH12_CTRL_REG3_I1_ZYXDA (1 << 4) +#define LIS2DH12_CTRL_REG3_I1_WTM (1 << 2) +#define LIS2DH12_CTRL_REG3_I1_OVERRUN (1 << 1) + +enum lis2dh12_read_mode { + LIS2DH12_READ_M_POLL = 0, + LIS2DH12_READ_M_STREAM = 1, +}; + +struct lis2dh12_notif_cfg { + sensor_event_type_t event; + uint8_t int_num; + uint16_t notif_src; + uint8_t int_cfg; +}; + +struct lis2dh12_tap_settings { + uint8_t en_xs : 1; // Interrupt on X single tap + uint8_t en_ys : 1; // Interrupt on Y single tap + uint8_t en_zs : 1; // Interrupt on Z single tap + uint8_t en_xd : 1; // Interrupt on X double tap + uint8_t en_yd : 1; // Interrupt on Y double tap + uint8_t en_zd : 1; // Interrupt on Z double tap + uint8_t hpf : 1; // High pass filter enable + + /* ths data is 7 bits, fs = +-2g */ + int8_t click_ths; + /* shock is maximum time data can be over threshold to register as tap + LSB = 1/ODR */ + int8_t time_limit; + + /* latency is time between taps in double tap, LSB = 1/ODR */ + uint8_t time_latency; + /* quiet is time after tap data is just below threshold + LSB = 1/ODR */ + uint8_t time_window; +}; + +struct lis2dh12_int_cfg { + uint8_t cfg; + uint8_t ths; + uint8_t dur; +}; + +/* Read mode configuration */ +struct lis2dh12_read_mode_cfg { + enum lis2dh12_read_mode mode; + uint8_t int_num:1; + uint8_t int_cfg; +}; + struct lis2dh12_cfg { uint8_t lc_rate; uint8_t lc_fs; + + uint8_t reference; + /* Tap config */ + struct lis2dh12_tap_settings tap; + + /* Read mode config */ + struct lis2dh12_read_mode_cfg read_mode; + + /* Notif config */ + struct lis2dh12_notif_cfg *notif_cfg; + uint8_t max_num_notif; + + struct lis2dh12_int_cfg int_cfg[2]; + + uint8_t xen : 1; + uint8_t yen : 1; + uint8_t zen : 1; + uint8_t hp_mode : 2; + uint8_t hp_cut_off : 2; + uint8_t hp_fds : 1; + uint8_t hp_click : 1; + uint8_t hp_ia1 : 1; + uint8_t hp_ia2 : 1; + uint8_t bdu : 1; + uint8_t latch_int1 : 1; + uint8_t latch_int2 : 1; + uint8_t d4d_int1 : 1; + uint8_t d4d_int2 : 1; + uint8_t int_pp_od : 1; + + /* Power mode */ + uint8_t power_mode; + + /* Fifo config */ + uint8_t fifo_mode; + uint8_t fifo_watermark; + + /* Sleep/wakeup settings */ + uint8_t act_ths; + uint8_t act_dur; + uint8_t lc_pull_up_disc; sensor_type_t lc_s_mask; }; +/* Used to track interrupt state to wake any present waiters */ +struct lis2dh12_int { + /* Synchronize access to this structure */ + os_sr_t lock; + /* Sleep waiting for an interrupt to occur */ + struct os_sem wait; + /* Is the interrupt currently active */ + bool active; + /* Is there a waiter currently sleeping */ + bool asleep; + /* Configured interrupts */ + struct sensor_int *ints; +}; + +/* Private per driver data */ +struct lis2dh12_pdd { + /* Notification event context */ + struct sensor_notify_ev_ctx notify_ctx; + /* Inetrrupt state */ + struct lis2dh12_int *interrupt; + /* Interrupt enabled on INT1 and INT2 pin (CTRL_REG3 and CTRL_REG6) */ + uint8_t int_enable[2]; + /* State of pin for sleep/wake up handling */ + uint8_t int2_pin_state; +}; + struct lis2dh12 { struct os_dev dev; struct sensor sensor; struct lis2dh12_cfg cfg; + struct lis2dh12_int intr; os_time_t last_read_time; + struct lis2dh12_pdd pdd; }; /** @@ -200,13 +373,24 @@ int lis2dh12_reset(struct sensor_itf *itf); /** + * Set reference threshold + * + * @param the sensor interface + * @param threshold + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_set_ref_thresh(struct sensor_itf *itf, uint8_t ths); + +/** * Enable interrupt 2 * * @param the sensor interface * @param events to enable int for */ int -lis2dh12_enable_int2(struct sensor_itf *itf, uint8_t *reg); +lis2dh12_enable_int2(struct sensor_itf *itf, uint8_t reg); /** * Enable interrupt 1 @@ -215,7 +399,7 @@ lis2dh12_enable_int2(struct sensor_itf *itf, uint8_t *reg); * @param events to enable int for */ int -lis2dh12_enable_int1(struct sensor_itf *itf, uint8_t *reg); +lis2dh12_enable_int1(struct sensor_itf *itf, uint8_t reg); /** * Set interrupt threshold for int 1 @@ -243,17 +427,23 @@ lis2dh12_set_int2_thresh(struct sensor_itf *itf, uint8_t ths); * Clear interrupt 1 * * @param the sensor interface + * @param src pointer to return interrupt source in + * + * @return 0 on success, non-zero on failure */ int -lis2dh12_clear_int1(struct sensor_itf *itf); +lis2dh12_clear_int1(struct sensor_itf *itf, uint8_t *src); /** * Clear interrupt 2 * * @param the sensor interface + * @param src pointer to return interrupt source in + * + * @return 0 on success, non-zero on failure */ int -lis2dh12_clear_int2(struct sensor_itf *itf); +lis2dh12_clear_int2(struct sensor_itf *itf, uint8_t *src); /** * Set interrupt pin configuration for interrupt 1 @@ -321,6 +511,124 @@ lis2dh12_disable_int2(struct sensor_itf *itf); int lis2dh12_hpf_cfg(struct sensor_itf *itf, uint8_t reg); +/** + * Set operating mode + * + * @param the sensor interface + * @param mode CTRL_REG1[3:0]:CTRL_REG4[3:0] + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_set_op_mode(struct sensor_itf *itf, uint8_t mode); + +/** + * Clear click interrupt + * + * @param the sensor interface + * @param src pointer for active interrupts + */ +int +lis2dh12_clear_click(struct sensor_itf *itf, uint8_t *src); + +/** + * Set click configuration register + * + * @param the sensor interface + * @param value to put in CLICK_CFG register + */ +int +lis2dh12_set_click_cfg(struct sensor_itf *itf, uint8_t cfg); + +/** + * Set click threshold value + * + * @param the sensor interface + * @param value click threshold value + */ +int +lis2dh12_set_click_threshold(struct sensor_itf *itf, uint8_t cfg); + +/** + * Set click time limit register + * + * This sets maximum time interval that can elapse between the start of + * the click-detection procedure and when the acceleration falls below + * thhreshold. 1 LSB = 1/ODR + * + * @param the sensor interface + * @param value to put in TIME_LIMIT register + */ +int +lis2dh12_set_click_time_limit(struct sensor_itf *itf, uint8_t limit); + +/** + * Set click time latency register + * + * This function sets time interval that starts after the first click detection + * where the click-detection procedure is disabled. This is relevant for + * double click detection only. + * + * 1 LSB = 1/ODR + * + * @param the sensor interface + * @param value to put in TIME_LATENCY register + */ +int +lis2dh12_set_click_time_latency(struct sensor_itf *itf, uint8_t latency); + +/** + * Set click time window register + * + * This function sets the maximum interval of time that can elapse after end of + * the latency interval in which click-detection procedure can start. + * This is relevant for double click detection only. + * + * 1 LSB = 1/ODR + * + * @param the sensor interface + * @param value to put in TIME_WINDOW register + */ +int +lis2dh12_set_click_time_window(struct sensor_itf *itf, uint8_t window); + +/** + * Set activity threshold + * + * @param the sensor interface + * @param threshold 0..127 threshold value for activity/sleep detection + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_set_activity_threshold(struct sensor_itf *itf, uint8_t threshold); + +/** + * Set activity duration + * + * @param the sensor interface + * @param duration Sleep-to-wake, return-to-sleep duration. + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_set_activity_duration(struct sensor_itf *itf, uint8_t duration); + +/** + * Get number of samples in FIFO + * + * @param the sensor interface + * @param Pointer to return number of samples + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_get_fifo_samples(struct sensor_itf *itf, uint8_t *samples); + +#if MYNEWT_VAL(LIS2DH12_CLI) +int lis2dh12_shell_init(void); +#endif + #ifdef __cplusplus } #endif diff --git a/hw/drivers/sensors/lis2dh12/src/lis2dh12.c b/hw/drivers/sensors/lis2dh12/src/lis2dh12.c index fcb961e..fcc272a 100644 --- a/hw/drivers/sensors/lis2dh12/src/lis2dh12.c +++ b/hw/drivers/sensors/lis2dh12/src/lis2dh12.c @@ -34,6 +34,100 @@ #include "modlog/modlog.h" #include "stats/stats.h" #include <syscfg/syscfg.h> +#include <sensor/sensor.h> +#if LIS2DH12_PRINT_INTR +#include "console/console.h" +#endif + +#ifndef LIS2DH12_PRINT_INTR +#define LIS2DH12_PRINT_INTR (0) +#endif + +/* + * Max time to wait for interrupt. + */ +#define LIS2DH12_MAX_INT_WAIT (4 * OS_TICKS_PER_SEC) + +static const struct lis2dh12_notif_cfg dflt_notif_cfg[] = { + { + .event = SENSOR_EVENT_TYPE_SINGLE_TAP, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_CLICK_SRC_SCLICK, + .int_cfg = LIS2DH12_CTRL_REG3_I1_CLICK + }, + { + .event = SENSOR_EVENT_TYPE_DOUBLE_TAP, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_CLICK_SRC_DCLICK, + .int_cfg = LIS2DH12_CTRL_REG3_I1_CLICK + }, + { + .event = SENSOR_EVENT_TYPE_SLEEP, + .int_num = 1, // Must be 1 + .notif_src = 0, // Not used host pin is read for state + .int_cfg = LIS2DH12_CTRL_REG6_I2_ACT + }, + { + .event = SENSOR_EVENT_TYPE_FREE_FALL, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT2_IA, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA2 + }, + { + .event = SENSOR_EVENT_TYPE_WAKEUP, + .int_num = 1, // Must be 1 + .notif_src = 0, // Not used host pin is read for state + .int_cfg = LIS2DH12_CTRL_REG6_I2_ACT + }, + { + .event = SENSOR_EVENT_TYPE_SLEEP_CHANGE, + .int_num = 1, // Must be 1 + .notif_src = 0, // Not used host pin is read for state + .int_cfg = LIS2DH12_CTRL_REG6_I2_ACT + }, + { + .event = SENSOR_EVENT_TYPE_ORIENT_CHANGE, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT1_IA, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA1 + }, + { + .event = SENSOR_EVENT_TYPE_ORIENT_X_L_CHANGE, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT1_XL, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA1 + }, + { + .event = SENSOR_EVENT_TYPE_ORIENT_X_H_CHANGE, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT1_XH, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA1 + }, + { + .event = SENSOR_EVENT_TYPE_ORIENT_Y_L_CHANGE, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT1_YL, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA1 + }, + { + .event = SENSOR_EVENT_TYPE_ORIENT_Y_H_CHANGE, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT1_YH, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA1 + }, + { + .event = SENSOR_EVENT_TYPE_ORIENT_Z_L_CHANGE, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT1_ZL, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA1 + }, + { + .event = SENSOR_EVENT_TYPE_ORIENT_Z_H_CHANGE, + .int_num = 0, // Should be 0, unless inactivity interrupt is not used + .notif_src = LIS2DH12_NOTIF_SRC_INT1_ZH, + .int_cfg = LIS2DH12_CTRL_REG3_I1_IA1 + } +}; static struct hal_spi_settings spi_lis2dh12_settings = { .data_order = HAL_SPI_MSB_FIRST, @@ -46,12 +140,36 @@ static struct hal_spi_settings spi_lis2dh12_settings = { STATS_SECT_START(lis2dh12_stat_section) STATS_SECT_ENTRY(write_errors) STATS_SECT_ENTRY(read_errors) +#if MYNEWT_VAL(LIS2DH12_NOTIF_STATS) + STATS_SECT_ENTRY(single_tap_notify) + STATS_SECT_ENTRY(double_tap_notify) + STATS_SECT_ENTRY(free_fall_notify) + STATS_SECT_ENTRY(sleep_notify) + STATS_SECT_ENTRY(wakeup_notify) + STATS_SECT_ENTRY(sleep_chg_notify) + STATS_SECT_ENTRY(orient_chg_notify) + STATS_SECT_ENTRY(orient_chg_x_notify) + STATS_SECT_ENTRY(orient_chg_y_notify) + STATS_SECT_ENTRY(orient_chg_z_notify) +#endif STATS_SECT_END /* Define stat names for querying */ STATS_NAME_START(lis2dh12_stat_section) STATS_NAME(lis2dh12_stat_section, write_errors) STATS_NAME(lis2dh12_stat_section, read_errors) +#if MYNEWT_VAL(LIS2DH12_NOTIF_STATS) + STATS_NAME(lis2dh12_stat_section, single_tap_notify) + STATS_NAME(lis2dh12_stat_section, double_tap_notify) + STATS_NAME(lis2dh12_stat_section, free_fall_notify) + STATS_NAME(lis2dh12_stat_section, sleep_notify) + STATS_NAME(lis2dh12_stat_section, wakeup_notify) + STATS_NAME(lis2dh12_stat_section, sleep_chg_notify) + STATS_NAME(lis2dh12_stat_section, orient_chg_notify) + STATS_NAME(lis2dh12_stat_section, orient_chg_x_notify) + STATS_NAME(lis2dh12_stat_section, orient_chg_y_notify) + STATS_NAME(lis2dh12_stat_section, orient_chg_z_notify) +#endif STATS_NAME_END(lis2dh12_stat_section) /* Global variable used to hold stats data */ @@ -65,6 +183,7 @@ static int lis2dh12_sensor_read(struct sensor *, sensor_type_t, sensor_data_func_t, void *, uint32_t); static int lis2dh12_sensor_get_config(struct sensor *, sensor_type_t, struct sensor_cfg *); +static int lis2dh12_sensor_set_config(struct sensor *, void *); static int lis2dh12_sensor_set_trigger_thresh(struct sensor *, sensor_type_t, struct sensor_type_traits *); @@ -74,13 +193,23 @@ lis2dh12_sensor_clear_low_thresh(struct sensor *, sensor_type_t); static int lis2dh12_sensor_clear_high_thresh(struct sensor *, sensor_type_t); +static int lis2dh12_sensor_set_notification(struct sensor *, + sensor_event_type_t); +static int lis2dh12_sensor_unset_notification(struct sensor *, + sensor_event_type_t); +static int lis2dh12_sensor_handle_interrupt(struct sensor *); + static const struct sensor_driver g_lis2dh12_sensor_driver = { .sd_read = lis2dh12_sensor_read, + .sd_set_config = lis2dh12_sensor_set_config, .sd_get_config = lis2dh12_sensor_get_config, /* Setting trigger threshold is optional */ .sd_set_trigger_thresh = lis2dh12_sensor_set_trigger_thresh, .sd_clear_low_trigger_thresh = lis2dh12_sensor_clear_low_thresh, - .sd_clear_high_trigger_thresh = lis2dh12_sensor_clear_high_thresh + .sd_clear_high_trigger_thresh = lis2dh12_sensor_clear_high_thresh, + .sd_set_notification = lis2dh12_sensor_set_notification, + .sd_unset_notification = lis2dh12_sensor_unset_notification, + .sd_handle_interrupt = lis2dh12_sensor_handle_interrupt }; /** @@ -98,6 +227,11 @@ lis2dh12_i2c_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer, uint8_t len) { int rc; + if (len > 1) + { + addr |= 0x80; + } + uint8_t payload[20] = { addr, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -380,6 +514,66 @@ lis2dh12_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, } /** + * Write byte to sensor over different interfaces + * + * @param The sensor interface + * @param The register address to write to + * @param The value to write + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_write8(struct sensor_itf *itf, uint8_t reg, uint8_t value) +{ + int rc; + + rc = sensor_itf_lock(itf, MYNEWT_VAL(LIS2DH12_ITF_LOCK_TMO)); + if (rc) { + return rc; + } + + if (itf->si_type == SENSOR_ITF_I2C) { + rc = lis2dh12_i2c_writelen(itf, reg, &value, 1); + } else { + rc = lis2dh12_spi_writelen(itf, reg, &value, 1); + } + + sensor_itf_unlock(itf); + + return rc; +} + +/** + * Read single register from LIS2DH12 sensor over different interfaces + * + * @param interface to use + * @param register address + * @param pinter to register data + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_read8(struct sensor_itf *itf, uint8_t addr, uint8_t *reg) +{ + int rc; + + rc = sensor_itf_lock(itf, MYNEWT_VAL(LIS2DH12_ITF_LOCK_TMO)); + if (rc) { + return rc; + } + + if (itf->si_type == SENSOR_ITF_I2C) { + rc = lis2dh12_i2c_readlen(itf, addr, reg, 1); + } else { + rc = lis2dh12_spi_readlen(itf, addr, reg, 1); + } + + sensor_itf_unlock(itf); + + return rc; +} + +/** * Reset lis2dh12 * * @param The sensor interface @@ -676,7 +870,8 @@ lis2dh12_set_fifo_mode(struct sensor_itf *itf, uint8_t mode) goto err; } - reg |= mode; + reg &= 0x3f; + reg |= mode << 6; rc = lis2dh12_writelen(itf, LIS2DH12_REG_FIFO_CTRL_REG, ®, 1); if (rc) { @@ -699,6 +894,27 @@ err: } /** + * Get Number of Samples in FIFO + * + * @param the sensor interface + * @param Pointer to return number of samples in + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_get_fifo_samples(struct sensor_itf *itf, uint8_t *samples) +{ + uint8_t reg; + int rc; + + rc = lis2dh12_read8(itf, LIS2DH12_REG_FIFO_SRC_REG, ®); + if (rc == 0) { + *samples = reg & LIS2DH12_FIFO_SRC_FSS; + } + + return rc; +} + +/** * * Get operating mode * @@ -762,32 +978,42 @@ lis2dh12_set_op_mode(struct sensor_itf *itf, uint8_t mode) int rc; uint8_t reg; - rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); + /* reset filtering block */ + rc = lis2dh12_readlen(itf, LIS2DH12_REG_REFERENCE, ®, 1); if (rc) { goto err; } - reg &= ~LIS2DH12_CTRL_REG1_LPEN; - reg |= ((mode & 0x80) >> 4); + rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); + if (rc) { + goto err; + } - rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); + /* Set HR bit */ + reg &= ~LIS2DH12_CTRL_REG4_HR; + reg |= (mode & 0x08); + + rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); if (rc) { goto err; } - rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); + /* Set LP bit */ + rc = lis2dh12_readlen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); if (rc) { goto err; } - reg &= ~LIS2DH12_CTRL_REG4_HR; - reg |= (mode & 0x08); + reg &= ~LIS2DH12_CTRL_REG1_LPEN; + reg |= ((mode & 0x80) >> 4); - rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG4, ®, 1); + rc = lis2dh12_writelen(itf, LIS2DH12_REG_CTRL_REG1, ®, 1); if (rc) { goto err; } + + os_time_delay(OS_TICKS_PER_SEC/1000 + 1); return 0; @@ -795,6 +1021,31 @@ err: return rc; } +int +lis2dh12_get_fs(struct sensor_itf *itf, uint8_t *fs) +{ + int rc; + + rc = lis2dh12_get_full_scale(itf, fs); + if (rc) { + return rc; + } + + if (*fs == LIS2DH12_FS_2G) { + *fs = 2; + } else if (*fs == LIS2DH12_FS_4G) { + *fs = 4; + } else if (*fs == LIS2DH12_FS_8G) { + *fs = 8; + } else if (*fs == LIS2DH12_FS_16G) { + *fs = 16; + } else { + return SYS_EINVAL; + } + + return 0; +} + /** * Gets a new data sample from the light sensor. * @@ -806,45 +1057,27 @@ err: * @return 0 on success, non-zero on failure */ int -lis2dh12_get_data(struct sensor_itf *itf, int16_t *x, int16_t *y, int16_t *z) +lis2dh12_get_data(struct sensor_itf *itf, uint8_t fs, int16_t *x, int16_t *y, int16_t *z) { int rc; - uint8_t payload[6] = {0}; - uint8_t fs; + uint8_t payload[6] = {0}; + uint8_t status; *x = *y = *z = 0; - rc = lis2dh12_readlen(itf, LIS2DH12_REG_OUT_X_L, payload, 1); - rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_X_H, &payload[1], 1); - rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Y_L, &payload[2], 1); - rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Y_H, &payload[3], 1); - rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Z_L, &payload[4], 1); - rc |= lis2dh12_readlen(itf, LIS2DH12_REG_OUT_Z_H, &payload[5], 1); + rc = lis2dh12_readlen(itf, LIS2DH12_REG_STATUS_REG, &status, 1); if (rc) { goto err; } - *x = payload[0] | (payload[1] << 8); - *y = payload[2] | (payload[3] << 8); - *z = payload[4] | (payload[5] << 8); - - rc = lis2dh12_get_full_scale(itf, &fs); + rc = lis2dh12_readlen(itf, LIS2DH12_REG_OUT_X_L, payload, 6); if (rc) { goto err; } - if (fs == LIS2DH12_FS_2G) { - fs = 2; - } else if (fs == LIS2DH12_FS_4G) { - fs = 4; - } else if (fs == LIS2DH12_FS_8G) { - fs = 8; - } else if (fs == LIS2DH12_FS_16G) { - fs = 16; - } else { - rc = SYS_EINVAL; - goto err; - } + *x = payload[0] | (payload[1] << 8); + *y = payload[2] | (payload[3] << 8); + *z = payload[4] | (payload[5] << 8); /* * Since full scale is +/-(fs)g, @@ -864,6 +1097,136 @@ err: return rc; } +static int +init_intpin(struct lis2dh12 *lis2dh12, int int_num, hal_gpio_irq_handler_t handler, + void *arg) +{ + hal_gpio_irq_trig_t trig; + int pin; + int rc; + + pin = lis2dh12->sensor.s_itf.si_ints[int_num].host_pin; + if (pin >= 0) { + trig = lis2dh12->sensor.s_itf.si_ints[int_num].active; + + rc = hal_gpio_irq_init(pin, + handler, + arg, + trig, + HAL_GPIO_PULL_NONE); + } + if (pin < 0) { + LIS2DH12_LOG(ERROR, "Interrupt pin not configured\n"); + return SYS_EINVAL; + } + + if (rc != 0) { + LIS2DH12_LOG(ERROR, "Failed to initialize interrupt pin %d\n", pin); + return rc; + } + + return 0; +} + +static void +init_interrupt(struct lis2dh12_int *interrupt, struct sensor_int *ints) +{ + os_error_t error; + + error = os_sem_init(&interrupt->wait, 0); + assert(error == OS_OK); + + interrupt->active = false; + interrupt->asleep = false; + interrupt->ints = ints; +} + +static void +undo_interrupt(struct lis2dh12_int *interrupt) +{ + OS_ENTER_CRITICAL(interrupt->lock); + interrupt->active = false; + interrupt->asleep = false; + OS_EXIT_CRITICAL(interrupt->lock); +} + +static int +wait_interrupt(struct lis2dh12_int *interrupt, uint8_t int_num) +{ + bool wait; + os_error_t error; + + OS_ENTER_CRITICAL(interrupt->lock); + + /* Check if we did not missed interrupt */ + if (hal_gpio_read(interrupt->ints[int_num].host_pin) == + interrupt->ints[int_num].active) { + OS_EXIT_CRITICAL(interrupt->lock); + return OS_OK; + } + + if (interrupt->active) { + interrupt->active = false; + wait = false; + } else { + interrupt->asleep = true; + wait = true; + } + OS_EXIT_CRITICAL(interrupt->lock); + + if (wait) { + error = os_sem_pend(&interrupt->wait, LIS2DH12_MAX_INT_WAIT); + if (error == OS_TIMEOUT) { + return error; + } + assert(error == OS_OK); + } + return OS_OK; +} + +static void +wake_interrupt(struct lis2dh12_int *interrupt) +{ + bool wake; + + OS_ENTER_CRITICAL(interrupt->lock); + if (interrupt->asleep) { + interrupt->asleep = false; + wake = true; + } else { + interrupt->active = true; + wake = false; + } + OS_EXIT_CRITICAL(interrupt->lock); + + if (wake) { + os_error_t error; + + error = os_sem_release(&interrupt->wait); + assert(error == OS_OK); + } +} + +/** + * IRQ handler for interrupts for high/low threshold + * + * @param arg + */ +static void +lis2dh12_int_irq_handler(void *arg) +{ + struct sensor *sensor = arg; + struct lis2dh12 *lis2dh12; + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + + if (lis2dh12->pdd.interrupt) { + wake_interrupt(lis2dh12->pdd.interrupt); + } + + sensor_mgr_put_interrupt_evt(sensor); +} + /** * Expects to be called back through os_dev_create(). * @@ -949,6 +1312,19 @@ lis2dh12_init(struct os_dev *dev, void *arg) } } + init_interrupt(&lis2dh12->intr, lis2dh12->sensor.s_itf.si_ints); + + lis2dh12->pdd.notify_ctx.snec_sensor = sensor; + lis2dh12->pdd.interrupt = NULL; + + rc = init_intpin(lis2dh12, 0, lis2dh12_int_irq_handler, sensor); + if (rc) { + return rc; + } + rc = init_intpin(lis2dh12, 1, lis2dh12_int_irq_handler, sensor); + if (rc) { + return rc; + } return 0; err: return rc; @@ -983,71 +1359,771 @@ err: return rc; } -static int -lis2dh12_sensor_read(struct sensor *sensor, sensor_type_t type, - sensor_data_func_t data_func, void *data_arg, uint32_t timeout) +/** + * Sets the interrupt push-pull/open-drain selection + * + * @param The sensor interface + * @param interrupt setting (0 = push-pull, 1 = open-drain) + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_set_int_pp_od(struct sensor_itf *itf, uint8_t mode) { - struct sensor_accel_data sad; - struct sensor_itf *itf; - int16_t x, y ,z; - float fx, fy ,fz; int rc; + uint8_t reg; - /* If the read isn't looking for accel or mag data, don't do anything. */ - if (!(type & SENSOR_TYPE_ACCELEROMETER)) { - rc = SYS_EINVAL; - goto err; + rc = lis2dh12_read8(itf, LIS2DH12_REG_CTRL_REG6, ®); + if (rc) { + return rc; } - itf = SENSOR_GET_ITF(sensor); - - x = y = z = 0; - - if (itf->si_type == SENSOR_ITF_SPI) { - - rc = hal_spi_disable(sensor->s_itf.si_num); - if (rc) { - goto err; - } + reg &= ~LIS2DH12_CTRL_REG6_INT_POLARITY; + reg |= mode ? LIS2DH12_CTRL_REG6_INT_POLARITY : 0; - rc = hal_spi_config(sensor->s_itf.si_num, &spi_lis2dh12_settings); - if (rc == EINVAL) { - /* If spi is already enabled, for nrf52, it returns -1, We should not - * fail if the spi is already enabled - */ - goto err; - } + return lis2dh12_write8(itf, LIS2DH12_REG_CTRL_REG6, reg); +} - rc = hal_spi_enable(sensor->s_itf.si_num); - if (rc) { - goto err; - } - } +/** + * Gets the interrupt push-pull/open-drain selection + * + * @param The sensor interface + * @param ptr to store setting (0 = push-pull, 1 = open-drain) + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_get_int_pp_od(struct sensor_itf *itf, uint8_t *mode) +{ + int rc; + uint8_t reg; - rc = lis2dh12_get_data(itf, &x, &y, &z); + rc = lis2dh12_read8(itf, LIS2DH12_REG_CTRL_REG6, ®); if (rc) { - goto err; + return rc; } - /* converting values from mg to ms^2 */ + *mode = (reg & LIS2DH12_CTRL_REG6_INT_POLARITY) ? 1 : 0; + + return 0; +} + +int +lis2dh12_clear_click(struct sensor_itf *itf, uint8_t *src) +{ + return lis2dh12_read8(itf, LIS2DH12_REG_CLICK_SRC, src); +} + +int +lis2dh12_set_click_cfg(struct sensor_itf *itf, uint8_t cfg) +{ + return lis2dh12_write8(itf, LIS2DH12_REG_CLICK_CFG, cfg); +} + +int +lis2dh12_set_click_threshold(struct sensor_itf *itf, uint8_t cfg) +{ + return lis2dh12_write8(itf, LIS2DH12_REG_CLICK_THS, cfg); +} + +int +lis2dh12_set_click_time_limit(struct sensor_itf *itf, uint8_t limit) +{ + return lis2dh12_write8(itf, LIS2DH12_REG_TIME_LIMIT, limit); +} + +int +lis2dh12_set_click_time_latency(struct sensor_itf *itf, uint8_t latency) +{ + return lis2dh12_write8(itf, LIS2DH12_REG_TIME_LATENCY, latency); +} + +int +lis2dh12_set_click_time_window(struct sensor_itf *itf, uint8_t window) +{ + return lis2dh12_write8(itf, LIS2DH12_REG_TIME_WINDOW, window); +} + +int +lis2dh12_set_activity_threshold(struct sensor_itf *itf, uint8_t threshold) +{ + return lis2dh12_write8(itf, LIS2DH12_REG_ACT_THS, threshold); +} + +int +lis2dh12_set_activity_duration(struct sensor_itf *itf, uint8_t duration) +{ + return lis2dh12_write8(itf, LIS2DH12_REG_ACT_DUR, duration); +} + +static int +disable_interrupt(struct sensor *sensor, uint8_t int_to_disable, uint8_t int_num) +{ + struct lis2dh12 *lis2dh12; + struct lis2dh12_pdd *pdd; + struct sensor_itf *itf; + int rc; + + if (int_to_disable == 0) { + return SYS_EINVAL; + } + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + itf = SENSOR_GET_ITF(sensor); + pdd = &lis2dh12->pdd; + + pdd->int_enable[int_num] &= ~(int_to_disable); + + /* disable GPIO int if no longer needed */ + if (!pdd->int_enable[int_num]) { + hal_gpio_irq_disable(itf->si_ints[int_num].host_pin); + } + + /* update interrupt setup in device */ + if (int_num == 0) { + rc = lis2dh12_set_int1_pin_cfg(itf, pdd->int_enable[int_num]); + } else { + rc = lis2dh12_set_int2_pin_cfg(itf, pdd->int_enable[int_num]); + } + + return rc; +} + + +static int +enable_interrupt(struct sensor *sensor, uint8_t int_to_enable, uint8_t int_num) +{ + struct lis2dh12 *lis2dh12; + struct lis2dh12_pdd *pdd; + struct sensor_itf *itf; + int rc; + + if (!int_to_enable) { + rc = SYS_EINVAL; + goto err; + } + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + itf = SENSOR_GET_ITF(sensor); + pdd = &lis2dh12->pdd; + + /* if no interrupts are currently in use enable int pin */ + if (!pdd->int_enable[int_num]) { + hal_gpio_irq_enable(itf->si_ints[int_num].host_pin); + } + + if ((pdd->int_enable[int_num] & int_to_enable) == 0) { + pdd->int_enable[int_num] |= int_to_enable; + + /* enable interrupt in device */ + if (int_num == 0) { + rc = lis2dh12_set_int1_pin_cfg(itf, pdd->int_enable[int_num]); + } else { + rc = lis2dh12_set_int2_pin_cfg(itf, pdd->int_enable[int_num]); + } + + if (rc) { + disable_interrupt(sensor, int_to_enable, int_num); + goto err; + } + } + + return 0; +err: + return rc; +} + +static int +lis2dh12_do_read(struct sensor *sensor, sensor_data_func_t data_func, + void * data_arg, uint8_t fs) +{ + struct sensor_accel_data sad; + struct sensor_itf *itf; + int16_t x, y ,z; + float fx, fy ,fz; + int rc; + + itf = SENSOR_GET_ITF(sensor); + + x = y = z = 0; + + rc = lis2dh12_get_data(itf, fs, &x, &y, &z); + if (rc) { + goto err; + } + + /* converting values from mg to ms^2 */ lis2dh12_calc_acc_ms2(x, &fx); lis2dh12_calc_acc_ms2(y, &fy); lis2dh12_calc_acc_ms2(z, &fz); - sad.sad_x = fx; - sad.sad_y = fy; - sad.sad_z = fz; + sad.sad_x = fx; + sad.sad_y = fy; + sad.sad_z = fz; + + sad.sad_x_is_valid = 1; + sad.sad_y_is_valid = 1; + sad.sad_z_is_valid = 1; + + /* Call data function */ + rc = data_func(sensor, data_arg, &sad, SENSOR_TYPE_ACCELEROMETER); + if (rc != 0) { + goto err; + } + + return 0; +err: + return rc; +} + +/** + * Do accelerometer polling reads + * + * @param The sensor ptr + * @param The sensor type + * @param The function pointer to invoke for each accelerometer reading. + * @param The opaque pointer that will be passed in to the function. + * @param If non-zero, how long the stream should run in milliseconds. + * + * @return 0 on success, non-zero on failure. + */ +int +lis2dh12_poll_read(struct sensor *sensor, sensor_type_t sensor_type, + sensor_data_func_t data_func, void *data_arg, + uint32_t timeout) +{ + struct lis2dh12 *lis2dh12; + struct lis2dh12_cfg *cfg; + struct sensor_itf *itf; + uint8_t fs; + int rc; + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + itf = SENSOR_GET_ITF(sensor); + cfg = &lis2dh12->cfg; + + /* If the read isn't looking for accel data, don't do anything. */ + if (!(sensor_type & SENSOR_TYPE_ACCELEROMETER)) { + rc = SYS_EINVAL; + goto err; + } + + if (cfg->read_mode.mode != LIS2DH12_READ_M_POLL) { + rc = SYS_EINVAL; + goto err; + } + + rc = lis2dh12_get_fs(itf, &fs); + if (rc) { + goto err; + } + + rc = lis2dh12_do_read(sensor, data_func, data_arg, fs); + if (rc) { + goto err; + } + + return 0; +err: + return rc; +} + +int +lis2dh12_stream_read(struct sensor *sensor, + sensor_type_t sensor_type, + sensor_data_func_t read_func, + void *read_arg, + uint32_t time_ms) +{ + struct lis2dh12_pdd *pdd; + struct lis2dh12 *lis2dh12; + struct sensor_itf *itf; + struct lis2dh12_cfg *cfg; + os_time_t time_ticks; + os_time_t stop_ticks = 0; + uint8_t fifo_samples; + uint8_t fs; + int rc, rc2; + + /* If the read isn't looking for accel data, don't do anything. */ + if (!(sensor_type & SENSOR_TYPE_ACCELEROMETER)) { + return SYS_EINVAL; + } + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + itf = SENSOR_GET_ITF(sensor); + pdd = &lis2dh12->pdd; + cfg = &lis2dh12->cfg; + + if (cfg->read_mode.mode != LIS2DH12_READ_M_STREAM) { + return SYS_EINVAL; + } + + undo_interrupt(&lis2dh12->intr); + + if (pdd->interrupt) { + return SYS_EBUSY; + } + + /* enable interrupt */ + pdd->interrupt = &lis2dh12->intr; + + rc = enable_interrupt(sensor, cfg->read_mode.int_cfg, + cfg->read_mode.int_num); + if (rc) { + return rc; + } + + if (time_ms != 0) { + rc = os_time_ms_to_ticks(time_ms, &time_ticks); + if (rc) { + goto err; + } + stop_ticks = os_time_get() + time_ticks; + } + + rc = lis2dh12_get_fs(itf, &fs); + if (rc) { + goto err; + } + + for (;;) { + /* force at least one read for cases when fifo is disabled */ + rc = wait_interrupt(&lis2dh12->intr, cfg->read_mode.int_num); + if (rc) { + goto err; + } + fifo_samples = 1; + + while (fifo_samples > 0) { + + /* read all data we believe is currently in fifo */ + while (fifo_samples > 0) { + rc = lis2dh12_do_read(sensor, read_func, read_arg, fs); + if (rc) { + goto err; + } + fifo_samples--; + + } + + /* check if any data is available in fifo */ + rc = lis2dh12_get_fifo_samples(itf, &fifo_samples); + if (rc) { + goto err; + } + + } + + if (time_ms != 0 && OS_TIME_TICK_GT(os_time_get(), stop_ticks)) { + break; + } + + } + +err: + /* disable interrupt */ + pdd->interrupt = NULL; + rc2 = disable_interrupt(sensor, cfg->read_mode.int_cfg, + cfg->read_mode.int_num); + if (rc) { + return rc; + } else { + return rc2; + } +} + +static int +lis2dh12_sensor_read(struct sensor *sensor, sensor_type_t type, + sensor_data_func_t data_func, void *data_arg, uint32_t timeout) +{ + int rc; + const struct lis2dh12_cfg *cfg; + struct lis2dh12 *lis2dh12; + struct sensor_itf *itf; + + /* If the read isn't looking for accel data, don't do anything. */ + if (!(type & SENSOR_TYPE_ACCELEROMETER)) { + rc = SYS_EINVAL; + goto err; + } + + itf = SENSOR_GET_ITF(sensor); + + if (itf->si_type == SENSOR_ITF_SPI) { + + rc = hal_spi_disable(sensor->s_itf.si_num); + if (rc) { + goto err; + } + + rc = hal_spi_config(sensor->s_itf.si_num, &spi_lis2dh12_settings); + if (rc == EINVAL) { + /* If spi is already enabled, for nrf52, it returns -1, We should not + * fail if the spi is already enabled + */ + goto err; + } + + rc = hal_spi_enable(sensor->s_itf.si_num); + if (rc) { + goto err; + } + } + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + cfg = &lis2dh12->cfg; + + if (cfg->read_mode.mode == LIS2DH12_READ_M_POLL) { + rc = lis2dh12_poll_read(sensor, type, data_func, data_arg, timeout); + } else { + rc = lis2dh12_stream_read(sensor, type, data_func, data_arg, timeout); + } +err: + if (rc) { + return SYS_EINVAL; /* XXX */ + } else { + return SYS_EOK; + } +} + +static struct lis2dh12_notif_cfg * +lis2dh12_find_notif_cfg_by_event(sensor_event_type_t event, + struct lis2dh12_cfg *cfg) +{ + int i; + struct lis2dh12_notif_cfg *notif_cfg = NULL; + + if (!cfg) { + goto err; + } + + for (i = 0; i < cfg->max_num_notif; i++) { + if (event == cfg->notif_cfg[i].event) { + notif_cfg = &cfg->notif_cfg[i]; + break; + } + } + + if (i == cfg->max_num_notif) { + /* here if type is set to a non valid event or more than one event + * we do not currently support registering for more than one event + * per notification + */ + goto err; + } + + return notif_cfg; +err: + return NULL; +} + +static int +lis2dh12_sensor_set_notification(struct sensor *sensor, sensor_event_type_t event) +{ + struct lis2dh12 *lis2dh12; + struct lis2dh12_pdd *pdd; + struct lis2dh12_notif_cfg *notif_cfg; + int rc; + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + pdd = &lis2dh12->pdd; + + notif_cfg = lis2dh12_find_notif_cfg_by_event(event, &lis2dh12->cfg); + if (!notif_cfg) { + rc = SYS_EINVAL; + goto err; + } + + rc = enable_interrupt(sensor, notif_cfg->int_cfg, notif_cfg->int_num); + if (rc) { + goto err; + } + + pdd->notify_ctx.snec_evtype |= event; - sad.sad_x_is_valid = 1; - sad.sad_y_is_valid = 1; - sad.sad_z_is_valid = 1; + return 0; +err: + return rc; +} - /* Call data function */ - rc = data_func(sensor, data_arg, &sad, SENSOR_TYPE_ACCELEROMETER); - if (rc != 0) { +static int +lis2dh12_sensor_set_config(struct sensor *sensor, void *cfg) +{ + struct lis2dh12 *lis2dh12; + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + + return lis2dh12_config(lis2dh12, (struct lis2dh12_cfg*)cfg); +} + +static int +lis2dh12_sensor_unset_notification(struct sensor *sensor, sensor_event_type_t event) +{ + struct lis2dh12_notif_cfg *notif_cfg; + struct lis2dh12 *lis2dh12; + int rc; + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + + notif_cfg = lis2dh12_find_notif_cfg_by_event(event, &lis2dh12->cfg); + if (!notif_cfg) { + rc = SYS_EINVAL; + goto err; + } + + lis2dh12->pdd.notify_ctx.snec_evtype &= ~event; + + rc = disable_interrupt(sensor, notif_cfg->int_cfg, notif_cfg->int_num); + +err: + return rc; +} + +static void +lis2dh12_inc_notif_stats(sensor_event_type_t event) +{ + +#if MYNEWT_VAL(LIS2DH12_NOTIF_STATS) + switch (event) { + case SENSOR_EVENT_TYPE_SLEEP: + STATS_INC(g_lis2dh12stats, sleep_notify); + break; + case SENSOR_EVENT_TYPE_SINGLE_TAP: + STATS_INC(g_lis2dh12stats, single_tap_notify); + break; + case SENSOR_EVENT_TYPE_DOUBLE_TAP: + STATS_INC(g_lis2dh12stats, double_tap_notify); + break; + case SENSOR_EVENT_TYPE_ORIENT_CHANGE: + STATS_INC(g_lis2dh12stats, orient_chg_notify); + break; + case SENSOR_EVENT_TYPE_ORIENT_X_CHANGE: + STATS_INC(g_lis2dh12stats, orient_chg_x_notify); + break; + case SENSOR_EVENT_TYPE_ORIENT_Y_CHANGE: + STATS_INC(g_lis2dh12stats, orient_chg_y_notify); + break; + case SENSOR_EVENT_TYPE_ORIENT_Z_CHANGE: + STATS_INC(g_lis2dh12stats, orient_chg_z_notify); + break; + case SENSOR_EVENT_TYPE_SLEEP_CHANGE: + STATS_INC(g_lis2dh12stats, sleep_chg_notify); + break; + case SENSOR_EVENT_TYPE_WAKEUP: + STATS_INC(g_lis2dh12stats, wakeup_notify); + break; + case SENSOR_EVENT_TYPE_FREE_FALL: + STATS_INC(g_lis2dh12stats, free_fall_notify); + break; + default: + break; + } +#endif + + return; +} + +static int +lis2dh12_notify(struct lis2dh12 *lis2dh12, uint16_t src, + sensor_event_type_t event_type) +{ + struct lis2dh12_notif_cfg *notif_cfg; + + notif_cfg = lis2dh12_find_notif_cfg_by_event(event_type, &lis2dh12->cfg); + if (!notif_cfg) { + return SYS_EINVAL; + } + + if (src & notif_cfg->notif_src) { + sensor_mgr_put_notify_evt(&lis2dh12->pdd.notify_ctx, event_type); + lis2dh12_inc_notif_stats(event_type); + } + + return 0; +} + +static int +lis2dh12_sensor_handle_interrupt(struct sensor *sensor) +{ + struct lis2dh12 *lis2dh12; + struct sensor_itf *itf; + uint8_t int_src_bytes[2]; + uint16_t int_src; + uint8_t click_src; + uint8_t int2_pin_state; + struct lis2dh12_notif_cfg *notif_cfg; + struct lis2dh12_pdd *pdd; + int rc; + + lis2dh12 = (struct lis2dh12 *)SENSOR_GET_DEVICE(sensor); + itf = SENSOR_GET_ITF(sensor); + pdd = &lis2dh12->pdd; + + rc = lis2dh12_clear_int1(itf, &int_src_bytes[0]); + if (rc) { + LIS2DH12_LOG(ERROR, "Could not read INT1_SRC (err=0x%02x)\n", rc); + goto err; + } + + /* Read pin state of interrupt 2 before clearing the int */ + int2_pin_state = hal_gpio_read(itf->si_ints[1].host_pin); + + rc = lis2dh12_clear_int2(itf, &int_src_bytes[1]); + if (rc) { + LIS2DH12_LOG(ERROR, "Could not read INT1_SRC (err=0x%02x)\n", rc); goto err; } + int_src = (int_src_bytes[1] << 8) | int_src_bytes[0]; + +#if LIS2DH12_PRINT_INTR + console_printf("INT_SRC = 0x%02X 0x%02X\n", int_src_bytes[0], + int_src_bytes[1]); + + if (int_src) { + int16_t x, y, z; + lis2dh12_get_data(itf, 16, &x, &y, &z); + console_printf("X = %-5d Y = %-5d Z = %-5d\n", x, y, z); + } +#endif + + if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_CHANGE) { + rc = lis2dh12_notify(lis2dh12, int_src, SENSOR_EVENT_TYPE_ORIENT_CHANGE); + if (rc) { + goto err; + } + } + + if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_X_L_CHANGE) { + rc = lis2dh12_notify(lis2dh12, int_src, SENSOR_EVENT_TYPE_ORIENT_X_L_CHANGE); + if (rc) { + goto err; + } + } + + if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Y_L_CHANGE) { + rc = lis2dh12_notify(lis2dh12, int_src, SENSOR_EVENT_TYPE_ORIENT_Y_L_CHANGE); + if (rc) { + goto err; + } + } + + if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Z_L_CHANGE) { + rc = lis2dh12_notify(lis2dh12, int_src, SENSOR_EVENT_TYPE_ORIENT_Z_L_CHANGE); + if (rc) { + goto err; + } + } + + if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_X_H_CHANGE) { + rc = lis2dh12_notify(lis2dh12, int_src, SENSOR_EVENT_TYPE_ORIENT_X_H_CHANGE); + if (rc) { + goto err; + } + } + + if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Y_H_CHANGE) { + rc = lis2dh12_notify(lis2dh12, int_src, SENSOR_EVENT_TYPE_ORIENT_Y_H_CHANGE); + if (rc) { + goto err; + } + } + + if (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_ORIENT_Z_H_CHANGE) { + rc = lis2dh12_notify(lis2dh12, int_src, SENSOR_EVENT_TYPE_ORIENT_Z_H_CHANGE); + if (rc) { + goto err; + } + } + + /* Check is single/double detection was requested, if not interrupt + * did not happened and there is no need to query device about it + */ + if ((pdd->notify_ctx.snec_evtype & + (SENSOR_EVENT_TYPE_DOUBLE_TAP | SENSOR_EVENT_TYPE_DOUBLE_TAP)) != 0) { + /* Read click interrupt state from device */ + rc = lis2dh12_clear_click(itf, &click_src); + if (rc) { + LIS2DH12_LOG(ERROR, "Could not read int src err=0x%02x\n", rc); + return rc; + } + + if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_SINGLE_TAP) && + (click_src & LIS2DH12_CLICK_SRC_SCLICK)) { + rc = lis2dh12_notify(lis2dh12, click_src, SENSOR_EVENT_TYPE_SINGLE_TAP); + if (rc) { + goto err; + } + return 0; + } + + if ((pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_DOUBLE_TAP) && + (click_src & LIS2DH12_CLICK_SRC_DCLICK)) { + rc = lis2dh12_notify(lis2dh12, click_src, SENSOR_EVENT_TYPE_DOUBLE_TAP); + if (rc) { + goto err; + } + return 0; + } + } + + /* Free fall */ + notif_cfg = lis2dh12_find_notif_cfg_by_event(SENSOR_EVENT_TYPE_FREE_FALL, + &lis2dh12->cfg); + if (NULL != notif_cfg && + 0 != (int_src & notif_cfg->notif_src)) { + /* Free-fall is detected */ + sensor_mgr_put_notify_evt(&lis2dh12->pdd.notify_ctx, + SENSOR_EVENT_TYPE_FREE_FALL); + lis2dh12_inc_notif_stats(SENSOR_EVENT_TYPE_FREE_FALL); + } + + /* Sleep and wake up */ + + /* Sleep/wake up notifications on */ + if (pdd->notify_ctx.snec_evtype & + (SENSOR_EVENT_TYPE_SLEEP | SENSOR_EVENT_TYPE_SLEEP_CHANGE | SENSOR_EVENT_TYPE_WAKEUP)) { + /* + * Sleep state can be routed to INT2 pin, pin is active when device stays active + * Notification will be sent only on activity pin state change. + */ + if (int2_pin_state != lis2dh12->pdd.int2_pin_state) { + lis2dh12->pdd.int2_pin_state = int2_pin_state; + + if ((!int2_pin_state) && + 0 != (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_WAKEUP)) { + /* Just become active */ + notif_cfg = lis2dh12_find_notif_cfg_by_event(SENSOR_EVENT_TYPE_WAKEUP, + &lis2dh12->cfg); + sensor_mgr_put_notify_evt(&lis2dh12->pdd.notify_ctx, + SENSOR_EVENT_TYPE_WAKEUP); + lis2dh12_inc_notif_stats(SENSOR_EVENT_TYPE_WAKEUP); + } else if (int2_pin_state && + 0 != (pdd->notify_ctx.snec_evtype & SENSOR_EVENT_TYPE_SLEEP)) { + /* Just went to sleep */ + notif_cfg = lis2dh12_find_notif_cfg_by_event(SENSOR_EVENT_TYPE_SLEEP, + &lis2dh12->cfg); + sensor_mgr_put_notify_evt(&lis2dh12->pdd.notify_ctx, + SENSOR_EVENT_TYPE_SLEEP); + lis2dh12_inc_notif_stats(SENSOR_EVENT_TYPE_SLEEP); + } else{ + notif_cfg = lis2dh12_find_notif_cfg_by_event(SENSOR_EVENT_TYPE_SLEEP_CHANGE, + &lis2dh12->cfg); + /* Sleep change interrupt must be configured for int2 */ + if ((notif_cfg && int2_pin_state && itf->si_ints[1].active == HAL_GPIO_TRIG_RISING) || + (notif_cfg && !int2_pin_state && itf->si_ints[1].active == HAL_GPIO_TRIG_FALLING) || + (notif_cfg && itf->si_ints[1].active == HAL_GPIO_TRIG_BOTH)) + { + /* Sleep change detected, either wake-up or sleep */ + sensor_mgr_put_notify_evt(&lis2dh12->pdd.notify_ctx, + SENSOR_EVENT_TYPE_SLEEP_CHANGE); + lis2dh12_inc_notif_stats(SENSOR_EVENT_TYPE_SLEEP_CHANGE); + } + } + } + } + return 0; err: return rc; @@ -1072,6 +2148,29 @@ err: } /** + * Set reference threshold + * + * @param the sensor interface + * @param threshold + * + * @return 0 on success, non-zero on failure + */ +int +lis2dh12_set_ref_thresh(struct sensor_itf *itf, uint8_t ths) +{ + int rc; + + rc = lis2dh12_writelen(itf, LIS2DH12_REG_REFERENCE, &ths, 1); + if (rc) { + goto err; + } + + return 0; +err: + return rc; +} + +/** * Set interrupt threshold for int 2 * * @param the sensor interface @@ -1124,11 +2223,9 @@ err: * @param the sensor interface */ int -lis2dh12_clear_int2(struct sensor_itf *itf) +lis2dh12_clear_int2(struct sensor_itf *itf, uint8_t *src) { - uint8_t reg; - - return lis2dh12_readlen(itf, LIS2DH12_REG_INT2_SRC, ®, 1); + return lis2dh12_readlen(itf, LIS2DH12_REG_INT2_SRC, src, 1); } /** @@ -1137,11 +2234,9 @@ lis2dh12_clear_int2(struct sensor_itf *itf) * @param the sensor interface */ int -lis2dh12_clear_int1(struct sensor_itf *itf) +lis2dh12_clear_int1(struct sensor_itf *itf, uint8_t *src) { - uint8_t reg; - - return lis2dh12_readlen(itf, LIS2DH12_REG_INT1_SRC, ®, 1); + return lis2dh12_readlen(itf, LIS2DH12_REG_INT1_SRC, src, 1); } /** @@ -1151,9 +2246,9 @@ lis2dh12_clear_int1(struct sensor_itf *itf) * @param events to enable int for */ int -lis2dh12_enable_int2(struct sensor_itf *itf, uint8_t *reg) +lis2dh12_enable_int2(struct sensor_itf *itf, uint8_t reg) { - return lis2dh12_writelen(itf, LIS2DH12_REG_INT2_CFG, reg, 1); + return lis2dh12_write8(itf, LIS2DH12_REG_INT2_CFG, reg); } /** @@ -1278,13 +2373,13 @@ lis2dh12_disable_int1(struct sensor_itf *itf) uint8_t reg; int rc; - reg = 0; - - rc = lis2dh12_clear_int1(itf); + rc = lis2dh12_clear_int1(itf, ®); if (rc) { goto err; } + reg = 0; + os_time_delay((OS_TICKS_PER_SEC * 20)/1000 + 1); rc = lis2dh12_writelen(itf, LIS2DH12_REG_INT1_CFG, ®, 1); @@ -1305,13 +2400,13 @@ lis2dh12_disable_int2(struct sensor_itf *itf) uint8_t reg; int rc; - reg = 0; - - rc = lis2dh12_clear_int2(itf); + rc = lis2dh12_clear_int2(itf, ®); if (rc) { goto err; } + reg = 0; + os_time_delay((OS_TICKS_PER_SEC * 20)/1000 + 1); rc = lis2dh12_writelen(itf, LIS2DH12_REG_INT2_CFG, ®, 1); @@ -1327,20 +2422,9 @@ err: * @param events to enable int for */ int -lis2dh12_enable_int1(struct sensor_itf *itf, uint8_t *reg) -{ - return lis2dh12_writelen(itf, LIS2DH12_REG_INT1_CFG, reg, 1); -} - -/** - * IRQ handler for interrupts for high/low threshold - * - * @param arg - */ -static void -lis2dh12_int_irq_handler(void *arg) +lis2dh12_enable_int1(struct sensor_itf *itf, uint8_t reg) { - sensor_mgr_put_read_evt(arg); + return lis2dh12_write8(itf, LIS2DH12_REG_INT1_CFG, reg); } /** @@ -1420,7 +2504,8 @@ lis2dh12_set_low_thresh(struct sensor_itf *itf, struct sensor_type_traits *stt) { int16_t acc_mg; - uint8_t reg; + uint8_t reg = 0xFF; + uint8_t int_src; int rc; rc = 0; @@ -1478,7 +2563,7 @@ lis2dh12_set_low_thresh(struct sensor_itf *itf, reg |= low_thresh.sad->sad_y_is_valid ? LIS2DH12_INT2_CFG_YLIE : 0; reg |= low_thresh.sad->sad_z_is_valid ? LIS2DH12_INT2_CFG_ZLIE : 0; - rc = lis2dh12_clear_int1(itf); + rc = lis2dh12_clear_int1(itf, &int_src); if (rc) { goto err; } @@ -1487,7 +2572,7 @@ lis2dh12_set_low_thresh(struct sensor_itf *itf, hal_gpio_irq_enable(itf->si_low_pin); - rc = lis2dh12_enable_int1(itf, ®); + rc = lis2dh12_enable_int1(itf, reg); if (rc) { goto err; } @@ -1505,7 +2590,8 @@ lis2dh12_set_high_thresh(struct sensor_itf *itf, struct sensor_type_traits *stt) { int16_t acc_mg; - uint8_t reg; + uint8_t reg = 0; + uint8_t int_src; int rc; rc = 0; @@ -1563,14 +2649,14 @@ lis2dh12_set_high_thresh(struct sensor_itf *itf, reg |= high_thresh.sad->sad_y_is_valid ? LIS2DH12_INT2_CFG_YHIE : 0; reg |= high_thresh.sad->sad_z_is_valid ? LIS2DH12_INT2_CFG_ZHIE : 0; - rc = lis2dh12_clear_int2(itf); + rc = lis2dh12_clear_int2(itf, &int_src); if (rc) { goto err; } hal_gpio_irq_enable(itf->si_high_pin); - rc = lis2dh12_enable_int2(itf, ®); + rc = lis2dh12_enable_int2(itf, reg); if (rc) { goto err; } @@ -1649,6 +2735,52 @@ err: } /** + * Set tap detection configuration + * + * @param the sensor interface + * @param the tap settings + * @return 0 on success, non-zero on failure + */ +int lis2dh12_set_tap_cfg(struct sensor_itf *itf, struct lis2dh12_tap_settings *cfg) +{ + int rc; + uint8_t reg; + + reg = cfg->en_xs ? LIS2DH12_CLICK_CFG_XS : 0; + reg |= cfg->en_ys ? LIS2DH12_CLICK_CFG_YS : 0; + reg |= cfg->en_zs ? LIS2DH12_CLICK_CFG_ZS : 0; + reg |= cfg->en_xd ? LIS2DH12_CLICK_CFG_XD : 0; + reg |= cfg->en_yd ? LIS2DH12_CLICK_CFG_YD : 0; + reg |= cfg->en_zd ? LIS2DH12_CLICK_CFG_ZD : 0; + rc = lis2dh12_set_click_cfg(itf, reg); + if (rc) { + return rc; + } + + lis2dh12_set_click_threshold(itf, cfg->click_ths); + if (rc) { + return rc; + } + + lis2dh12_set_click_time_limit(itf, cfg->time_limit); + if (rc) { + return rc; + } + + lis2dh12_set_click_time_latency(itf, cfg->time_latency); + if (rc) { + return rc; + } + + lis2dh12_set_click_time_window(itf, cfg->time_window); + if (rc) { + return rc; + } + + return 0; +} + +/** * Configure the sensor * * @param ptr to sensor driver @@ -1701,6 +2833,12 @@ lis2dh12_config(struct lis2dh12 *lis2dh12, struct lis2dh12_cfg *cfg) goto err; } + rc = lis2dh12_set_int_pp_od(itf, cfg->int_pp_od); + if (rc) { + goto err; + } + lis2dh12->cfg.int_pp_od = cfg->int_pp_od; + rc = lis2dh12_pull_up_disc(itf, cfg->lc_pull_up_disc); if (rc) { goto err; @@ -1708,7 +2846,9 @@ lis2dh12_config(struct lis2dh12 *lis2dh12, struct lis2dh12_cfg *cfg) lis2dh12->cfg.lc_pull_up_disc = cfg->lc_pull_up_disc; - rc = lis2dh12_hpf_cfg(itf, 0x00); + rc = lis2dh12_hpf_cfg(itf, (cfg->hp_mode << 6) | (cfg->hp_cut_off << 4) | + (cfg->hp_fds << 3) | (cfg->hp_click << 2) | + (cfg->hp_ia2 << 1) | cfg->hp_ia1); if (rc) { goto err; } @@ -1727,6 +2867,7 @@ lis2dh12_config(struct lis2dh12 *lis2dh12, struct lis2dh12_cfg *cfg) lis2dh12->cfg.lc_rate = cfg->lc_rate; + /*sets xen yen and xen */ rc = lis2dh12_chan_enable(itf, LIS2DH12_CTRL_REG1_XPEN | LIS2DH12_CTRL_REG1_YPEN | LIS2DH12_CTRL_REG1_ZPEN); @@ -1739,12 +2880,74 @@ lis2dh12_config(struct lis2dh12 *lis2dh12, struct lis2dh12_cfg *cfg) goto err; } - rc = lis2dh12_set_op_mode(itf, LIS2DH12_OM_HIGH_RESOLUTION); + rc = lis2dh12_set_op_mode(itf, cfg->power_mode); + if (rc) { + goto err; + } + + rc = lis2dh12_set_fifo_mode(itf, cfg->fifo_mode); + if (rc) { + goto err; + } + + rc = lis2dh12_set_ref_thresh(itf, cfg->reference); + if (rc) + { + goto err; + } + + if (cfg->int_cfg[0].ths) { + rc = lis2dh12_set_int1_thresh(itf, cfg->int_cfg[0].ths); + if (rc) { + goto err; + } + rc = lis2dh12_enable_int1(itf, cfg->int_cfg[0].cfg); + if (rc) { + goto err; + } + rc = lis2dh12_set_int1_duration(itf, cfg->int_cfg[0].dur); + if (rc) { + goto err; + } + lis2dh12->cfg.int_cfg[0] = cfg->int_cfg[0]; + } + + if (cfg->int_cfg[1].ths) { + rc = lis2dh12_set_int2_thresh(itf, cfg->int_cfg[1].ths); + if (rc) { + goto err; + } + rc = lis2dh12_enable_int2(itf, cfg->int_cfg[1].cfg); + if (rc) { + goto err; + } + rc = lis2dh12_set_int2_duration(itf, cfg->int_cfg[1].dur); + if (rc) { + goto err; + } + lis2dh12->cfg.int_cfg[0] = cfg->int_cfg[0]; + } + + if (cfg->latch_int1) { + rc = lis2dh12_latch_int1(itf); + } + if (rc) { + goto err; + } + + if (cfg->latch_int2) { + rc = lis2dh12_latch_int2(itf); + } + if (rc) { + goto err; + } + + rc = lis2dh12_set_activity_threshold(itf, cfg->act_ths); if (rc) { goto err; } - rc = lis2dh12_set_fifo_mode(itf, LIS2DH12_FIFO_M_BYPASS); + rc = lis2dh12_set_activity_duration(itf, cfg->act_dur); if (rc) { goto err; } @@ -1753,10 +2956,41 @@ lis2dh12_config(struct lis2dh12 *lis2dh12, struct lis2dh12_cfg *cfg) if (rc) { goto err; } +// lis2dh12_shell_init(); + lis2dh12->cfg.read_mode.int_cfg = cfg->read_mode.int_cfg; + lis2dh12->cfg.read_mode.int_num = cfg->read_mode.int_num; + lis2dh12->cfg.read_mode.mode = cfg->read_mode.mode; + + if (!cfg->notif_cfg) { + lis2dh12->cfg.notif_cfg = (struct lis2dh12_notif_cfg *)dflt_notif_cfg; + lis2dh12->cfg.max_num_notif = sizeof(dflt_notif_cfg)/sizeof(dflt_notif_cfg[0]); + } else { + lis2dh12->cfg.notif_cfg = cfg->notif_cfg; + lis2dh12->cfg.max_num_notif = cfg->max_num_notif; + } + + lis2dh12->cfg.read_mode.int_cfg = cfg->read_mode.int_cfg; + lis2dh12->cfg.read_mode.int_num = cfg->read_mode.int_num; + lis2dh12->cfg.read_mode.mode = cfg->read_mode.mode; + + if (!cfg->notif_cfg) { + lis2dh12->cfg.notif_cfg = (struct lis2dh12_notif_cfg *)dflt_notif_cfg; + lis2dh12->cfg.max_num_notif = sizeof(dflt_notif_cfg)/sizeof(dflt_notif_cfg[0]); + } else { + lis2dh12->cfg.notif_cfg = cfg->notif_cfg; + lis2dh12->cfg.max_num_notif = cfg->max_num_notif; + } lis2dh12->cfg.lc_s_mask = cfg->lc_s_mask; + rc = lis2dh12_set_tap_cfg(itf, &cfg->tap); + if (rc) { + goto err; + } + lis2dh12->cfg.tap = cfg->tap; + return 0; err: + return rc; } diff --git a/hw/drivers/sensors/lis2dh12/src/lis2dh12_priv.h b/hw/drivers/sensors/lis2dh12/src/lis2dh12_priv.h index d37c269..6848b15 100644 --- a/hw/drivers/sensors/lis2dh12/src/lis2dh12_priv.h +++ b/hw/drivers/sensors/lis2dh12/src/lis2dh12_priv.h @@ -61,12 +61,6 @@ extern "C" { #define LIS2DH12_CTRL_REG2_HPIA1 (1) #define LIS2DH12_REG_CTRL_REG3 0x22 -#define LIS2DH12_CTRL_REG3_I1_CLICK (1 << 7) -#define LIS2DH12_CTRL_REG3_I1_IA1 (1 << 6) -#define LIS2DH12_CTRL_REG3_I1_IA2 (1 << 5) -#define LIS2DH12_CTRL_REG3_I1_ZYXDA (1 << 4) -#define LIS2DH12_CTRL_REG3_I1_WTM (1 << 2) -#define LIS2DH12_CTRL_REG3_I1_OVERRUN (1 << 1) #define LIS2DH12_REG_CTRL_REG4 0x23 #define LIS2DH12_CTRL_REG4_BDU (1 << 7) @@ -85,12 +79,6 @@ extern "C" { #define LIS2DH12_CTRL_REG5_D4D_INT2 (1) #define LIS2DH12_REG_CTRL_REG6 0x25 -#define LIS2DH12_CTRL_REG6_I2_CLICK (1 << 7) -#define LIS2DH12_CTRL_REG6_I2_IA1 (1 << 6) -#define LIS2DH12_CTRL_REG6_I2_IA2 (1 << 5) -#define LIS2DH12_CTRL_REG6_I2_BOOT (1 << 4) -#define LIS2DH12_CTRL_REG6_I2_ACT (1 << 3) -#define LIS2DH12_CTRL_REG6_INT_POLARITY (1 << 1) #define LIS2DH12_REG_REFERENCE 0x26 @@ -133,13 +121,6 @@ extern "C" { #define LIS2DH12_INT1_CFG_XLIE (1) #define LIS2DH12_REG_INT1_SRC 0x31 -#define LIS2DH12_INT1_IA (1 << 5) -#define LIS2DH12_INT1_ZH (1 << 5) -#define LIS2DH12_INT1_ZL (1 << 4) -#define LIS2DH12_INT1_YH (1 << 3) -#define LIS2DH12_INT1_YL (1 << 2) -#define LIS2DH12_INT1_XH (1 << 1) -#define LIS2DH12_INT1_XL (1) #define LIS2DH12_REG_INT1_THS 0x32 #define LIS2DH12_INT1_THS (0x7f) @@ -157,13 +138,6 @@ extern "C" { #define LIS2DH12_INT2_CFG_XLIE (1) #define LIS2DH12_REG_INT2_SRC 0x35 -#define LIS2DH12_INT1_IA (1 << 5) -#define LIS2DH12_INT1_ZH (1 << 5) -#define LIS2DH12_INT1_ZL (1 << 4) -#define LIS2DH12_INT1_YH (1 << 3) -#define LIS2DH12_INT1_YL (1 << 2) -#define LIS2DH12_INT1_XH (1 << 1) -#define LIS2DH12_INT1_XL (1) #define LIS2DH12_REG_INT2_THS 0x36 #define LIS2DH12_INT2_THS (0x7f) @@ -179,13 +153,6 @@ extern "C" { #define LIS2DH12_CLICK_CFG_XS (1) #define LIS2DH12_REG_CLICK_SRC 0x39 -#define LIS2DH12_CLICK_SRC_IA (1 << 6) -#define LIS2DH12_CLICK_SRC_DCLICK (1 << 5) -#define LIS2DH12_CLICK_SRC_SCLICK (1 << 4) -#define LIS2DH12_CLICK_SRC_SIGN (1 << 3) -#define LIS2DH12_CLICK_SRC_Z (1 << 2) -#define LIS2DH12_CLICK_SRC_Y (1 << 1) -#define LIS2DH12_CLICK_SRC_X (1 << 0) #define LIS2DH12_REG_CLICK_THS 0x3A #define LIS2DH12_CLICK_LIR (1 << 7) @@ -209,6 +176,10 @@ extern "C" { int lis2dh12_writelen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, uint8_t len); int lis2dh12_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, uint8_t len); +int lis2dh12_write8(struct sensor_itf *itf, uint8_t reg, uint8_t value); +int lis2dh12_read8(struct sensor_itf *itf, uint8_t reg, uint8_t *value); +int lis2dh12_get_data(struct sensor_itf *itf, uint8_t fs, int16_t *x, int16_t *y, int16_t *z); +int lis2dh12_get_fs(struct sensor_itf *itf, uint8_t *fs); #ifdef __cplusplus } diff --git a/hw/drivers/sensors/lis2dh12/src/lis2dh12_shell.c b/hw/drivers/sensors/lis2dh12/src/lis2dh12_shell.c new file mode 100644 index 0000000..7b9beb7 --- /dev/null +++ b/hw/drivers/sensors/lis2dh12/src/lis2dh12_shell.c @@ -0,0 +1,387 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <string.h> +#include <errno.h> +#include "os/mynewt.h" +#include "console/console.h" +#include "sensor/accel.h" +#include "lis2dh12/lis2dh12.h" +#include "lis2dh12_priv.h" + +#if MYNEWT_VAL(LIS2DH12_CLI) && MYNEWT_VAL(SENSOR_CLI) + +#include "shell/shell.h" +#include "parse/parse.h" + +#define LIS2DH12_CLI_FIRST_REGISTER 0x07 +#define LIS2DH12_CLI_LAST_REGISTER 0x3F + +static int lis2dh12_shell_cmd(int argc, char **argv); + +static struct shell_cmd lis2dh12_shell_cmd_struct = { + .sc_cmd = "lis2dh12", + .sc_cmd_func = lis2dh12_shell_cmd +}; + +static struct sensor_itf g_sensor_itf = { + .si_type = MYNEWT_VAL(LIS2DH12_SHELL_ITF_TYPE), + .si_num = MYNEWT_VAL(LIS2DH12_SHELL_ITF_NUM), + .si_cs_pin = MYNEWT_VAL(LIS2DH12_SHELL_CSPIN), + .si_addr = MYNEWT_VAL(LIS2DH12_SHELL_ITF_ADDR) +}; + +static int +lis2dh12_shell_err_too_many_args(char *cmd_name) +{ + console_printf("Error: too many arguments for command \"%s\"\n", + cmd_name); + return EINVAL; +} + +static int +lis2dh12_shell_err_too_few_args(char *cmd_name) +{ + console_printf("Error: too few arguments for command \"%s\"\n", + cmd_name); + return EINVAL; +} + +static int +lis2dh12_shell_err_unknown_arg(char *cmd_name) +{ + console_printf("Error: unknown argument \"%s\"\n", + cmd_name); + return EINVAL; +} + +static int +lis2dh12_shell_err_invalid_arg(char *cmd_name) +{ + console_printf("Error: invalid argument \"%s\"\n", + cmd_name); + return EINVAL; +} + +static int +lis2dh12_shell_help(void) +{ + console_printf("%s cmd [flags...]\n", lis2dh12_shell_cmd_struct.sc_cmd); + console_printf("cmd:\n"); + console_printf("\tr [n_samples]\n"); + console_printf("\tchipid\n"); + console_printf("\tdump\n"); + console_printf("\tpeek [reg]\n"); + console_printf("\tpoke [reg value]\n"); + console_printf("\ttest\n"); + + return 0; +} + +static int +lis2dh12_shell_cmd_read_chipid(int argc, char **argv) +{ + int rc; + uint8_t chipid; + + rc = lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_WHO_AM_I, &chipid); + if (rc) { + goto err; + } + + console_printf("CHIP_ID:0x%02X\n", chipid); + + return 0; +err: + return rc; +} + +static int +lis2dh12_shell_cmd_read(int argc, char **argv) +{ + uint16_t samples = 1; + uint16_t val; + int rc; + char tmpstr[13]; + int16_t x,y,z; + float fx,fy,fz; + uint8_t fs; + + if (argc > 3) { + return lis2dh12_shell_err_too_many_args(argv[1]); + } + + /* Check if more than one sample requested */ + if (argc == 3) { + val = parse_ll_bounds(argv[2], 1, UINT16_MAX, &rc); + if (rc) { + return lis2dh12_shell_err_invalid_arg(argv[2]); + } + samples = val; + } + + while (samples--) { + + rc = lis2dh12_get_fs(&g_sensor_itf, &fs); + if (rc) { + return rc; + } + + rc = lis2dh12_get_data(&g_sensor_itf, fs,&x, &y, &z); + if (rc) { + console_printf("Read failed: %d\n", rc); + return rc; + } + + lis2dh12_calc_acc_ms2(x, &fx); + lis2dh12_calc_acc_ms2(y, &fy); + lis2dh12_calc_acc_ms2(z, &fz); + + console_printf("x:%s ", sensor_ftostr(fx, tmpstr, 13)); + console_printf("y:%s ", sensor_ftostr(fy, tmpstr, 13)); + console_printf("z:%s\n", sensor_ftostr(fz, tmpstr, 13)); + } + + return 0; +} + +static int +lis2dh12_shell_cmd_dump(int argc, char **argv) +{ + uint8_t val; + + if (argc > 2) { + return lis2dh12_shell_err_too_many_args(argv[1]); + } + + /* Dump all the register values for debug purposes */ + val = 0; + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_TEMP_L, &val)); + console_printf("0x%02X (OUT_TEMP_L): 0x%02X\n", LIS2DH12_REG_OUT_TEMP_L, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_TEMP_H, &val)); + console_printf("0x%02X (OUT_TEMP_H): 0x%02X\n", LIS2DH12_REG_OUT_TEMP_H, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_WHO_AM_I, &val)); + console_printf("0x%02X (WHO_AM_I): 0x%02X\n", LIS2DH12_REG_WHO_AM_I, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CTRL_REG0, &val)); + console_printf("0x%02X (CTRL0): 0x%02X\n", LIS2DH12_REG_CTRL_REG0, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_TEMP_CFG, &val)); + console_printf("0x%02X (TEMP_CFG): 0x%02X\n", LIS2DH12_REG_TEMP_CFG, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CTRL_REG1, &val)); + console_printf("0x%02X (CTRL1): 0x%02X\n", LIS2DH12_REG_CTRL_REG1, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CTRL_REG2, &val)); + console_printf("0x%02X (CTRL2): 0x%02X\n", LIS2DH12_REG_CTRL_REG2, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CTRL_REG3, &val)); + console_printf("0x%02X (CTRL3): 0x%02X\n", LIS2DH12_REG_CTRL_REG3, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CTRL_REG4, &val)); + console_printf("0x%02X (CTRL4): 0x%02X\n", LIS2DH12_REG_CTRL_REG4, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CTRL_REG5, &val)); + console_printf("0x%02X (CTRL5): 0x%02X\n", LIS2DH12_REG_CTRL_REG5, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CTRL_REG6, &val)); + console_printf("0x%02X (CTRL6): 0x%02X\n", LIS2DH12_REG_CTRL_REG6, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_REFERENCE, &val)); + console_printf("0x%02X (REFERENCE): 0x%02X\n", LIS2DH12_REG_REFERENCE, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_STATUS_REG, &val)); + console_printf("0x%02X (STATUS): 0x%02X\n", LIS2DH12_REG_STATUS_REG, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_X_L, &val)); + console_printf("0x%02X (OUT_X_L): 0x%02X\n", LIS2DH12_REG_OUT_X_L, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_X_H, &val)); + console_printf("0x%02X (OUT_X_H): 0x%02X\n", LIS2DH12_REG_OUT_X_H, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_Y_L, &val)); + console_printf("0x%02X (OUT_Y_L): 0x%02X\n", LIS2DH12_REG_OUT_Y_L, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_Y_H, &val)); + console_printf("0x%02X (OUT_Y_H): 0x%02X\n", LIS2DH12_REG_OUT_Y_H, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_Z_L, &val)); + console_printf("0x%02X (OUT_Z_L): 0x%02X\n", LIS2DH12_REG_OUT_Z_L, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_OUT_Z_H, &val)); + console_printf("0x%02X (OUT_Z_H): 0x%02X\n", LIS2DH12_REG_OUT_Z_H, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_FIFO_CTRL_REG, &val)); + console_printf("0x%02X (FIFO_CTRL): 0x%02X\n", LIS2DH12_REG_FIFO_CTRL_REG, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_FIFO_SRC_REG, &val)); + console_printf("0x%02X (FIFO_SRC): 0x%02X\n", LIS2DH12_REG_FIFO_SRC_REG, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT1_CFG, &val)); + console_printf("0x%02X (INT1_CFG): 0x%02X\n", LIS2DH12_REG_INT1_CFG, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT1_SRC, &val)); + console_printf("0x%02X (INT1_SRC): 0x%02X\n", LIS2DH12_REG_INT1_SRC, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT1_THS, &val)); + console_printf("0x%02X (INT1_THS): 0x%02X\n", LIS2DH12_REG_INT1_THS, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT1_DURATION, &val)); + console_printf("0x%02X (INT1_DURATION): 0x%02X\n", LIS2DH12_REG_INT1_DURATION, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT2_CFG, &val)); + console_printf("0x%02X (INT2_CFG): 0x%02X\n", LIS2DH12_REG_INT2_CFG, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT2_SRC, &val)); + console_printf("0x%02X (INT2_SRC): 0x%02X\n", LIS2DH12_REG_INT2_SRC, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT2_THS, &val)); + console_printf("0x%02X (INT2_THS): 0x%02X\n", LIS2DH12_REG_INT2_THS, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_INT2_DURATION, &val)); + console_printf("0x%02X (INT2_DURATION): 0x%02X\n", LIS2DH12_REG_INT2_DURATION, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CLICK_CFG, &val)); + console_printf("0x%02X (CLICK_CFG): 0x%02X\n", LIS2DH12_REG_CLICK_CFG, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CLICK_SRC, &val)); + console_printf("0x%02X (CLICK_SRC): 0x%02X\n", LIS2DH12_REG_CLICK_SRC, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_CLICK_THS, &val)); + console_printf("0x%02X (CLICK_THS): 0x%02X\n", LIS2DH12_REG_CLICK_THS, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_TIME_LIMIT, &val)); + console_printf("0x%02X (TIME_LIMIT): 0x%02X\n", LIS2DH12_REG_TIME_LIMIT, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_TIME_LATENCY, &val)); + console_printf("0x%02X (TIME_LATENCY): 0x%02X\n", LIS2DH12_REG_TIME_LATENCY, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_TIME_WINDOW, &val)); + console_printf("0x%02X (TIME_WINDOW): 0x%02X\n", LIS2DH12_REG_TIME_WINDOW, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_ACT_THS, &val)); + console_printf("0x%02X (ACT_THS): 0x%02X\n", LIS2DH12_REG_ACT_THS, val); + assert(0 == lis2dh12_read8(&g_sensor_itf, LIS2DH12_REG_ACT_DUR, &val)); + console_printf("0x%02X (ACT_DUR): 0x%02X\n", LIS2DH12_REG_ACT_DUR, val); + + return 0; +} + +static int +lis2dh12_shell_cmd_peek(int argc, char **argv) +{ + int rc; + uint8_t value; + uint8_t reg; + + if (argc > 3) { + return lis2dh12_shell_err_too_many_args(argv[1]); + } else if (argc < 3) { + return lis2dh12_shell_err_too_few_args(argv[1]); + } + + reg = parse_ll_bounds(argv[2], LIS2DH12_CLI_FIRST_REGISTER, LIS2DH12_CLI_LAST_REGISTER, &rc); + if (rc != 0) { + return lis2dh12_shell_err_invalid_arg(argv[2]); + } + + rc = lis2dh12_read8(&g_sensor_itf, reg, &value); + if (rc) { + console_printf("peek failed %d\n", rc); + }else{ + console_printf("reg 0x%02X(%d) = 0x%02X\n", reg, reg, value); + } + + return 0; +} + +static int +lis2dh12_shell_cmd_poke(int argc, char **argv) +{ + int rc; + uint8_t reg; + uint8_t value; + + if (argc > 4) { + return lis2dh12_shell_err_too_many_args(argv[1]); + } else if (argc < 4) { + return lis2dh12_shell_err_too_few_args(argv[1]); + } + + reg = parse_ll_bounds(argv[2], LIS2DH12_CLI_FIRST_REGISTER, LIS2DH12_CLI_LAST_REGISTER, &rc); + if (rc != 0) { + return lis2dh12_shell_err_invalid_arg(argv[2]); + } + + value = parse_ll_bounds(argv[3], 0, 255, &rc); + if (rc != 0) { + return lis2dh12_shell_err_invalid_arg(argv[3]); + } + + rc = lis2dh12_write8(&g_sensor_itf, reg, value); + if (rc) { + console_printf("poke failed %d\n", rc); + }else{ + console_printf("wrote: 0x%02X(%d) to 0x%02X\n", value, value, reg); + } + + return 0; +} + +static int +lis2dh12_shell_cmd_test(int argc, char **argv) +{ + int rc; + int result = 0; + + rc = 0; //lis2dh12_run_self_test(&g_sensor_itf, &result); + if (rc) { + goto err; + } + + if (result) { + console_printf("SELF TEST: FAILED\n"); + } else { + console_printf("SELF TEST: PASSED\n"); + } + + return 0; +err: + return rc; +} + +static int +lis2dh12_shell_cmd(int argc, char **argv) +{ + if (argc == 1) { + return lis2dh12_shell_help(); + } + + /* Read command (get a new data sample) */ + if (argc > 1 && strcmp(argv[1], "r") == 0) { + return lis2dh12_shell_cmd_read(argc, argv); + } + + /* Chip ID */ + if (argc > 1 && strcmp(argv[1], "chipid") == 0) { + return lis2dh12_shell_cmd_read_chipid(argc, argv); + } + + /* Dump */ + if (argc > 1 && strcmp(argv[1], "dump") == 0) { + return lis2dh12_shell_cmd_dump(argc, argv); + } + + /* Peek */ + if (argc > 1 && strcmp(argv[1], "peek") == 0) { + return lis2dh12_shell_cmd_peek(argc, argv); + } + + /* Poke */ + if (argc > 1 && strcmp(argv[1], "poke") == 0) { + return lis2dh12_shell_cmd_poke(argc, argv); + } + + /* Test */ + if (argc > 1 && strcmp(argv[1], "test") == 0) { + return lis2dh12_shell_cmd_test(argc, argv); + } + + return lis2dh12_shell_err_unknown_arg(argv[1]); +} + +int +lis2dh12_shell_init(void) +{ + int rc; + + rc = shell_cmd_register(&lis2dh12_shell_cmd_struct); + SYSINIT_PANIC_ASSERT(rc == 0); + + return rc; +} + +#endif diff --git a/hw/drivers/sensors/lis2dh12/syscfg.yml b/hw/drivers/sensors/lis2dh12/syscfg.yml index 9cdc2be..72cd520 100644 --- a/hw/drivers/sensors/lis2dh12/syscfg.yml +++ b/hw/drivers/sensors/lis2dh12/syscfg.yml @@ -33,4 +33,39 @@ syscfg.defs: description: > Number of OS ticks to wait for each I2C transaction to complete. value: 3 - \ No newline at end of file + LIS2DH12_SHELL_ITF_NUM: + description: 'Shell interface number for the LIS2DH12' + value: 0 + LIS2DH12_SHELL_ITF_TYPE: + description: 'Shell interface type for the LIS2DH12' + value: 1 + LIS2DH12_SHELL_CSPIN: + description: 'CS pin for LIS2DH12' + value : -1 + LIS2DH12_SHELL_ITF_ADDR: + description: 'Slave address for LIS2DH12' + value : 0x19 + LIS2DH12_CLI: + description: 'Enable shell support for the LIS2DH12' + value: 0 + LIS2DH12_NOTIF_STATS: + description: 'Enable notification stats' + value: 1 + LIS2DH12_INT1_PIN_HOST: + description: 'Interrupt pin number on host device connected to INT1 on device' + value: 25 + LIS2DH12_INT1_PIN_DEVICE: + description: 'Interrupt pin number 1 or 2 on accelerometer device' + value: 1 + LIS2DH12_INT1_CFG_ACTIVE: + description: 'Set 0 for active-low, 1 for active-high' + value: 0 + LIS2DH12_INT2_PIN_HOST: + description: 'Interrupt pin number on host device connected to INT1 on device' + value: 31 + LIS2DH12_INT2_PIN_DEVICE: + description: 'Interrupt pin number 1 or 2 on accelerometer device' + value: 2 + LIS2DH12_INT2_CFG_ACTIVE: + description: 'Set 0 for active-low, 1 for active-high' + value: 0