| /* |
| * 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 |
| * resarding 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 <assert.h> |
| #include <math.h> |
| |
| #include "os/mynewt.h" |
| #include "hal/hal_i2c.h" |
| #include "hal/hal_spi.h" |
| #include "hal/hal_gpio.h" |
| #include "i2cn/i2cn.h" |
| #include "sensor/sensor.h" |
| #include "sensor/accel.h" |
| #include "adxl345/adxl345.h" |
| #include "adxl345_priv.h" |
| #include "modlog/modlog.h" |
| #include "stats/stats.h" |
| #include <syscfg/syscfg.h> |
| |
| static struct hal_spi_settings spi_adxl345_settings = { |
| .data_order = HAL_SPI_MSB_FIRST, |
| .data_mode = HAL_SPI_MODE3, |
| .baudrate = 4000, |
| .word_size = HAL_SPI_WORD_SIZE_8BIT, |
| }; |
| |
| |
| /* Define the stats section and records */ |
| STATS_SECT_START(adxl345_stat_section) |
| STATS_SECT_ENTRY(read_errors) |
| STATS_SECT_ENTRY(write_errors) |
| STATS_SECT_END |
| |
| /* Define stat names for querying */ |
| STATS_NAME_START(adxl345_stat_section) |
| STATS_NAME(adxl345_stat_section, read_errors) |
| STATS_NAME(adxl345_stat_section, write_errors) |
| STATS_NAME_END(adxl345_stat_section) |
| |
| /* Global variable used to hold stats data */ |
| STATS_SECT_DECL(adxl345_stat_section) g_adxl345stats; |
| |
| #define ADXL345_LOG(lvl_, ...) \ |
| MODLOG_ ## lvl_(MYNEWT_VAL(ADXL345_LOG_MODULE), __VA_ARGS__) |
| |
| #define ADXL345_NOTIFY_MASK 0x01 |
| #define ADXL345_READ_MASK 0x02 |
| |
| #if MYNEWT_VAL(ADXL345_INT_ENABLE) |
| static void interrupt_handler(void * arg); |
| static int init_intpin(struct adxl345 * adxl345, hal_gpio_irq_handler_t handler, |
| void * arg); |
| static int enable_interrupt(struct sensor * sensor, uint8_t ints_to_enable); |
| static int disable_interrupt(struct sensor * sensor, uint8_t ints_to_disable); |
| #endif |
| |
| /* Exports for the sensor API */ |
| static int adxl345_sensor_read(struct sensor *, sensor_type_t, |
| sensor_data_func_t, void *, uint32_t); |
| static int adxl345_sensor_get_config(struct sensor *, sensor_type_t, |
| struct sensor_cfg *); |
| static int adxl345_sensor_set_trigger_thresh(struct sensor * sensor, |
| sensor_type_t sensor_type, |
| struct sensor_type_traits * stt); |
| static int adxl345_sensor_set_notification(struct sensor * sensor, |
| sensor_event_type_t sensor_event_type); |
| static int adxl345_sensor_unset_notification(struct sensor * sensor, |
| sensor_event_type_t sensor_event_type); |
| static int adxl345_sensor_handle_interrupt(struct sensor * sensor); |
| static int adxl345_sensor_clear_low_thresh(struct sensor *sensor, |
| sensor_type_t type); |
| static int adxl345_sensor_clear_high_thresh(struct sensor *sensor, |
| sensor_type_t type); |
| |
| |
| static const struct sensor_driver adxl345_sensor_driver = { |
| .sd_read = adxl345_sensor_read, |
| .sd_get_config = adxl345_sensor_get_config, |
| .sd_set_trigger_thresh = adxl345_sensor_set_trigger_thresh, |
| .sd_set_notification = adxl345_sensor_set_notification, |
| .sd_unset_notification = adxl345_sensor_unset_notification, |
| .sd_handle_interrupt = adxl345_sensor_handle_interrupt, |
| .sd_clear_low_trigger_thresh = adxl345_sensor_clear_low_thresh, |
| .sd_clear_high_trigger_thresh = adxl345_sensor_clear_high_thresh |
| }; |
| |
| /** |
| * Writes a single byte to the specified register using i2c |
| * |
| * @param The sensor interface |
| * @param The register address to write to |
| * @param The value to write |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_i2c_write8(struct sensor_itf *itf, uint8_t reg, uint8_t value) |
| { |
| int rc; |
| uint8_t payload[2] = { reg, value }; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 2, |
| .buffer = payload |
| }; |
| |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(ADXL345_I2C_RETRIES)); |
| |
| if (rc) { |
| ADXL345_LOG(ERROR, |
| "Failed to write to 0x%02X:0x%02X with value 0x%02X\n", |
| itf->si_addr, reg, value); |
| STATS_INC(g_adxl345stats, read_errors); |
| } |
| |
| return rc; |
| } |
| |
| /** |
| * Reads a single byte from the specified register using i2c |
| * |
| * @param The sensor interface |
| * @param The register address to read from |
| * @param Pointer to where the register value should be written |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_i2c_read8(struct sensor_itf *itf, uint8_t reg, uint8_t *value) |
| { |
| int rc; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 1, |
| .buffer = ® |
| }; |
| |
| /* Register write */ |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(ADXL345_I2C_RETRIES)); |
| if (rc) { |
| ADXL345_LOG(ERROR, "I2C access failed at address 0x%02X\n", |
| itf->si_addr) |
| |
| STATS_INC(g_adxl345stats, write_errors); |
| return rc; |
| } |
| |
| /* Read one byte back */ |
| data_struct.buffer = value; |
| rc = i2cn_master_read(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(ADXL345_I2C_RETRIES)); |
| |
| if (rc) { |
| ADXL345_LOG(ERROR, "Failed to read from 0x%02X:0x%02X - %02X\n", |
| itf->si_addr, reg, rc); |
| STATS_INC(g_adxl345stats, read_errors); |
| } |
| return rc; |
| } |
| |
| /** |
| * Read multiple bytes starting from specified register over i2c |
| * |
| * @param The sensor interface |
| * @param The register address start reading from |
| * @param Pointer to where the register value should be written |
| * @param Number of bytes to read |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_i2c_readlen(struct sensor_itf *itf, uint8_t reg, uint8_t *buffer, uint8_t len) |
| { |
| int rc; |
| |
| struct hal_i2c_master_data data_struct = { |
| .address = itf->si_addr, |
| .len = 1, |
| .buffer = ® |
| }; |
| |
| /* Register write */ |
| rc = i2cn_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(ADXL345_I2C_RETRIES)); |
| if (rc) { |
| ADXL345_LOG(ERROR, "I2C access failed at address 0x%02X\n", |
| itf->si_addr); |
| STATS_INC(g_adxl345stats, write_errors); |
| return rc; |
| } |
| |
| /* Read data */ |
| data_struct.len = len; |
| data_struct.buffer = buffer; |
| rc = i2cn_master_read(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 1, |
| MYNEWT_VAL(ADXL345_I2C_RETRIES)); |
| |
| if (rc) { |
| ADXL345_LOG(ERROR, "Failed to read from 0x%02X:0x%02X\n", |
| itf->si_addr, reg); |
| STATS_INC(g_adxl345stats, read_errors); |
| } |
| |
| return rc; |
| } |
| |
| /** |
| * Writes a single byte to the specified register using SPI |
| * |
| * @param The sensor interface |
| * @param The register address to write to |
| * @param The value to write |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_spi_write8(struct sensor_itf *itf, uint8_t reg, uint8_t value) |
| { |
| int rc; |
| |
| /* Select the device */ |
| hal_gpio_write(itf->si_cs_pin, 0); |
| |
| /* Send the address */ |
| rc = hal_spi_tx_val(itf->si_num, reg & ~ADXL345_SPI_READ_CMD_BIT); |
| if (rc == 0xFFFF) { |
| rc = SYS_EINVAL; |
| ADXL345_LOG(ERROR, "SPI_%u register write failed addr:0x%02X\n", |
| itf->si_num, reg); |
| STATS_INC(g_adxl345stats, write_errors); |
| goto err; |
| } |
| |
| /* Read data */ |
| rc = hal_spi_tx_val(itf->si_num, value); |
| if (rc == 0xFFFF) { |
| rc = SYS_EINVAL; |
| ADXL345_LOG(ERROR, "SPI_%u write failed addr:0x%02X\n", |
| itf->si_num, reg); |
| STATS_INC(g_adxl345stats, write_errors); |
| goto err; |
| } |
| |
| rc = 0; |
| |
| err: |
| /* De-select the device */ |
| hal_gpio_write(itf->si_cs_pin, 1); |
| |
| return rc; |
| } |
| |
| |
| /** |
| * Reads a single byte from the specified register using SPI |
| * |
| |
| * @param The register address to read from |
| * @param Pointer to where the register value should be written |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_spi_read8(struct sensor_itf *itf, uint8_t reg, uint8_t *value) |
| { |
| uint16_t retval; |
| int rc = 0; |
| |
| /* Select the device */ |
| hal_gpio_write(itf->si_cs_pin, 0); |
| |
| /* Send the address */ |
| retval = hal_spi_tx_val(itf->si_num, reg | ADXL345_SPI_READ_CMD_BIT); |
| |
| if (retval == 0xFFFF) { |
| rc = SYS_EINVAL; |
| ADXL345_LOG(ERROR, "SPI_%u register write failed addr:0x%02X\n", |
| itf->si_num, reg); |
| STATS_INC(g_adxl345stats, read_errors); |
| goto err; |
| } |
| |
| /* Read data */ |
| retval = hal_spi_tx_val(itf->si_num, 0); |
| if (retval == 0xFFFF) { |
| rc = SYS_EINVAL; |
| ADXL345_LOG(ERROR, "SPI_%u read failed addr:0x%02X\n", |
| itf->si_num, reg); |
| STATS_INC(g_adxl345stats, read_errors); |
| goto err; |
| } |
| *value = retval; |
| |
| err: |
| /* De-select the device */ |
| hal_gpio_write(itf->si_cs_pin, 1); |
| |
| return rc; |
| } |
| |
| /** |
| * Read multiple bytes starting from specified register over SPI |
| * |
| * @param The sensor interface |
| * @param The register address start reading from |
| * @param Pointer to where the register value should be written |
| * @param Number of bytes to read |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| adxl345_spi_readlen(struct sensor_itf *itf, uint8_t reg, uint8_t *buffer, |
| uint8_t len) |
| { |
| int i; |
| uint16_t retval; |
| int rc = 0; |
| |
| /* Select the device */ |
| hal_gpio_write(itf->si_cs_pin, 0); |
| |
| /* Send the address */ |
| retval = hal_spi_tx_val(itf->si_num, reg | ADXL345_SPI_READ_CMD_BIT |
| | ADXL345_SPI_MULTIBYTE_CMD_BIT); |
| |
| if (retval == 0xFFFF) { |
| rc = SYS_EINVAL; |
| ADXL345_LOG(ERROR, "SPI_%u register write failed addr:0x%02X\n", |
| itf->si_num, reg); |
| STATS_INC(g_adxl345stats, read_errors); |
| goto err; |
| } |
| |
| for (i = 0; i < len; i++) { |
| /* Read data */ |
| retval = hal_spi_tx_val(itf->si_num, 0); |
| if (retval == 0xFFFF) { |
| rc = SYS_EINVAL; |
| ADXL345_LOG(ERROR, "SPI_%u read failed addr:0x%02X\n", |
| itf->si_num, reg); |
| STATS_INC(g_adxl345stats, read_errors); |
| goto err; |
| } |
| buffer[i] = retval; |
| } |
| |
| err: |
| /* De-select the device */ |
| hal_gpio_write(itf->si_cs_pin, 1); |
| |
| return rc; |
| } |
| |
| |
| /** |
| * Write byte to ADXL345 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 |
| adxl345_write8(struct sensor_itf *itf, uint8_t reg, uint8_t value) |
| { |
| int rc; |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(ADXL345_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| if (itf->si_type == SENSOR_ITF_I2C) { |
| rc = adxl345_i2c_write8(itf, reg, value); |
| } else { |
| rc = adxl345_spi_write8(itf, reg, value); |
| } |
| |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Read byte data from ADXL345 sensor over different interfaces |
| * |
| * @param The sensor interface |
| * @param The register address to read from |
| * @param Pointer to where the register value should be written |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| adxl345_read8(struct sensor_itf *itf, uint8_t reg, uint8_t *value) |
| { |
| int rc; |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(ADXL345_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| if (itf->si_type == SENSOR_ITF_I2C) { |
| rc = adxl345_i2c_read8(itf, reg, value); |
| } else { |
| rc = adxl345_spi_read8(itf, reg, value); |
| } |
| |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Read multiple bytes starting from specified register over different interfaces |
| * |
| * @param The sensor interface |
| * @param The register address start reading from |
| * @param Pointer to where the register value should be written |
| * @param Number of bytes to read |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| adxl345_readlen(struct sensor_itf *itf, uint8_t reg, uint8_t *buffer, |
| uint8_t len) |
| { |
| int rc; |
| |
| rc = sensor_itf_lock(itf, MYNEWT_VAL(ADXL345_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| if (itf->si_type == SENSOR_ITF_I2C) { |
| rc = adxl345_i2c_readlen(itf, reg, buffer, len); |
| } else { |
| rc = adxl345_spi_readlen(itf, reg, buffer, len); |
| } |
| |
| sensor_itf_unlock(itf); |
| |
| return rc; |
| } |
| |
| /** |
| * Sets ADXL345 into new power mode |
| * |
| * @param The sensor interface |
| * @param Power mode to set |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_power_mode(struct sensor_itf *itf, enum adxl345_power_mode state) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_POWER_CTL, ®); |
| if (rc) { |
| return rc; |
| } |
| |
| reg &= 0xF3; |
| reg |= ((uint8_t)state) << 2; |
| |
| return adxl345_write8(itf, ADXL345_POWER_CTL, (uint8_t)reg); |
| } |
| |
| /** |
| * Gets power mode ADXL345 is currently in |
| * |
| * @param The sensor interface |
| * @param Pointer to store current power mode |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_power_mode(struct sensor_itf *itf, enum adxl345_power_mode *state) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_POWER_CTL, ®); |
| if (rc) { |
| return rc; |
| } |
| |
| reg &= 0xC; |
| reg >>= 2; |
| |
| *state = (enum adxl345_accel_range)reg; |
| |
| return 0; |
| } |
| |
| /** |
| * Sets whether low power mode is enabled. Low power mode acheives lower |
| * power consumption at the expense of higher noise, but is only effective |
| * at sample rates between 12.5Hz and 400Hz |
| * |
| * @param The sensor interface |
| * @param Setting to use for low power mode |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_low_power_enable(struct sensor_itf *itf, uint8_t enable) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_BW_RATE, ®); |
| if (rc) { |
| return rc; |
| } |
| |
| reg &= 0x0F; |
| if (enable) { |
| reg |= 0x10; |
| } |
| |
| return adxl345_write8(itf, ADXL345_BW_RATE, (uint8_t)reg); |
| } |
| |
| /** |
| * Gets current setting of low power mode. Low power mode acheives lower |
| * power consumption at the expense of higher noise, but is only effective |
| * at sample rates between 12.5Hz and 400Hz |
| * |
| * @param The sensor interface |
| * @param Pointer to store value |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_low_power_enable(struct sensor_itf *itf, uint8_t *enable) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_BW_RATE, ®); |
| if (rc) { |
| return rc; |
| } |
| |
| *enable = (reg & 0x10) != 0; |
| |
| return 0; |
| } |
| |
| /** |
| * Sets the accelerometer range to specified setting |
| * |
| * @param The sensor interface |
| * @param accelerometer range to set |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_accel_range(struct sensor_itf *itf, enum adxl345_accel_range range) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_DATA_FORMAT, ®); |
| if (rc) { |
| return rc; |
| } |
| |
| reg &= 0xFC; |
| reg |= (uint8_t)range; |
| |
| return adxl345_write8(itf, ADXL345_DATA_FORMAT, (uint8_t)reg); |
| } |
| |
| /** |
| * Gets the accelerometer range currently set |
| * |
| * @param The sensor interface |
| * @param Pointer to location to store accelerometer range |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_accel_range(struct sensor_itf *itf, enum adxl345_accel_range *range) |
| { |
| uint8_t reg; |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_DATA_FORMAT, ®); |
| if (rc) { |
| return rc; |
| } |
| |
| *range = (enum adxl345_accel_range)(reg & 0x3); |
| |
| return 0; |
| } |
| |
| /** |
| * Sets new offsets in ADXL345 |
| * |
| * @param The sensor interface |
| * @param X offset |
| * @param Y offset |
| * @param Z offset |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_offsets(struct sensor_itf *itf, int8_t offset_x, |
| int8_t offset_y, int8_t offset_z) |
| { |
| int rc; |
| |
| rc = adxl345_write8(itf, ADXL345_OFSX, offset_x); |
| if (rc){ |
| return rc; |
| } |
| |
| rc = adxl345_write8(itf, ADXL345_OFSY, offset_y); |
| if (rc){ |
| return rc; |
| } |
| |
| return adxl345_write8(itf, ADXL345_OFSZ, offset_z); |
| } |
| |
| /** |
| * Gets the offsets currently set |
| * |
| * @param The sensor interface |
| * @param Pointer to location to store X offset |
| * @param Pointer to location to store Y offset |
| * @param Pointer to location to store Z offset |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_offsets(struct sensor_itf *itf, int8_t *offset_x, |
| int8_t *offset_y, int8_t *offset_z) |
| { |
| |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_OFSX, (uint8_t *)offset_x); |
| if (rc){ |
| return rc; |
| } |
| |
| rc = adxl345_read8(itf, ADXL345_OFSY, (uint8_t *)offset_y); |
| if (rc){ |
| return rc; |
| } |
| |
| return adxl345_read8(itf, ADXL345_OFSZ, (uint8_t *)offset_z); |
| } |
| |
| /** |
| * Sets new tap settings in ADXL345 sensor |
| * |
| * @param The sensor interface |
| * @param Structure of new settings |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_tap_settings(struct sensor_itf *itf, struct adxl345_tap_settings settings) |
| { |
| int rc; |
| uint8_t enables = 0; |
| |
| rc = adxl345_write8(itf, ADXL345_THRESH_TAP, settings.threshold); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_write8(itf, ADXL345_DUR, settings.duration); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_write8(itf, ADXL345_LATENT, settings.latency); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_write8(itf, ADXL345_WINDOW, settings.window); |
| if (rc) { |
| return rc; |
| } |
| |
| enables |= settings.x_enable ? (1 << 2) : 0; |
| enables |= settings.y_enable ? (1 << 1) : 0; |
| enables |= settings.z_enable ? (1 << 0) : 0; |
| enables |= settings.suppress ? (1 << 3) : 0; |
| |
| return adxl345_write8(itf, ADXL345_TAP_AXES, enables); |
| } |
| |
| /** |
| * Gets the current tap settings from ADXL345 sensor |
| * |
| * @param The sensor interface |
| * @param Ponter to structure to store settings |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_tap_settings(struct sensor_itf *itf, struct adxl345_tap_settings *settings) |
| { |
| int rc; |
| uint8_t enables; |
| |
| rc = adxl345_read8(itf, ADXL345_THRESH_TAP, &(settings->threshold)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_read8(itf, ADXL345_DUR, &(settings->duration)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_read8(itf, ADXL345_LATENT, &(settings->latency)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_read8(itf, ADXL345_WINDOW, &(settings->window)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_read8(itf, ADXL345_TAP_AXES, &enables); |
| if (rc) { |
| return rc; |
| } |
| |
| settings->x_enable = (enables & (1 << 2)) != 0; |
| settings->x_enable = (enables & (1 << 1)) != 0; |
| settings->x_enable = (enables & (1 << 0)) != 0; |
| settings->suppress = (enables & (1 << 3)) != 0; |
| |
| return 0; |
| } |
| |
| /** |
| * Sets new threshold for triggering activity interrupt |
| * |
| * @param The sensor interface |
| * @param threshold value (62.5mg/LSB) |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_active_threshold(struct sensor_itf *itf, uint8_t threshold) |
| { |
| return adxl345_write8(itf, ADXL345_THRESH_ACT, threshold); |
| } |
| |
| /** |
| * Gets current threshold for triggering activity interrupt |
| * |
| * @param The sensor interface |
| * @param Pointer to store threshold value (62.5mg/LSB) |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_active_threshold(struct sensor_itf *itf, uint8_t *threshold) |
| { |
| return adxl345_read8(itf, ADXL345_THRESH_ACT, threshold); |
| } |
| |
| /** |
| * Sets new threshold and time for triggering inactivity interrupt |
| * |
| * @param The sensor interface |
| * @param threshold value (62.5mg/LSB) |
| * @param time value in seconds |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_inactive_settings(struct sensor_itf *itf, uint8_t threshold, uint8_t time) |
| { |
| int rc; |
| |
| rc = adxl345_write8(itf, ADXL345_THRESH_INACT, threshold); |
| if (rc){ |
| return rc; |
| } |
| |
| return adxl345_write8(itf, ADXL345_TIME_INACT, time); |
| } |
| |
| /** |
| * Gets current threshold and time set for triggering inactivity interrupt |
| * |
| * @param The sensor interface |
| * @param Pointer to store threshold value (62.5mg/LSB) |
| * @param Ponter to store time value in seconds |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_inactive_settings(struct sensor_itf *itf, uint8_t *threshold, uint8_t *time) |
| { |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_THRESH_INACT, threshold); |
| if (rc){ |
| return rc; |
| } |
| |
| return adxl345_read8(itf, ADXL345_TIME_INACT, time); |
| } |
| |
| /** |
| * Sets new activity/inactivity interrupt axis selections |
| * |
| * @param The sensor interface |
| * @param Structure of new configuration |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_act_inact_enables(struct sensor_itf *itf, struct adxl345_act_inact_enables cfg) |
| { |
| uint8_t reg = 0; |
| |
| reg |= cfg.inact_z ? (1 << 0) : 0; |
| reg |= cfg.inact_y ? (1 << 1) : 0; |
| reg |= cfg.inact_x ? (1 << 2) : 0; |
| reg |= cfg.inact_ac_dc ? (1 << 3) : 0; |
| reg |= cfg.act_z ? (1 << 4) : 0; |
| reg |= cfg.act_y ? (1 << 5) : 0; |
| reg |= cfg.act_x ? (1 << 6) : 0; |
| reg |= cfg.act_ac_dc ? (1 << 7) : 0; |
| |
| ADXL345_LOG(ERROR, "act_inact = 0x%x\n", reg); |
| |
| return adxl345_write8(itf, ADXL345_ACT_INACT_CTL, reg); |
| |
| } |
| |
| /** |
| * Sets new activity/inactivity interrupt axis selections |
| * |
| * @param The sensor interface |
| * @param Pointer to structure to store configuration |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_act_inact_enables(struct sensor_itf *itf, struct adxl345_act_inact_enables *cfg) |
| { |
| int rc; |
| uint8_t reg; |
| |
| rc = adxl345_read8(itf, ADXL345_ACT_INACT_CTL, ®); |
| if (rc) { |
| return rc; |
| } |
| |
| cfg->inact_z = (reg & (1 << 0)) != 0; |
| cfg->inact_y = (reg & (1 << 1)) != 0; |
| cfg->inact_x = (reg & (1 << 2)) != 0; |
| cfg->inact_ac_dc = (reg & (1 << 3)) != 0; |
| cfg->act_z = (reg & (1 << 4)) != 0; |
| cfg->act_y = (reg & (1 << 5)) != 0; |
| cfg->act_x = (reg & (1 << 6)) != 0; |
| cfg->act_ac_dc = (reg & (1 << 7)) != 0; |
| |
| return 0; |
| } |
| |
| /** |
| * Sets new threshold and time for triggering freefall interrupt |
| * |
| * @param The sensor interface |
| * @param threshold value (62.5mg/LSB) |
| * @param time value in seconds |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_freefall_settings(struct sensor_itf *itf, uint8_t threshold, uint8_t time) |
| { |
| int rc; |
| |
| rc = adxl345_write8(itf, ADXL345_THRESH_FF, threshold); |
| if (rc){ |
| return rc; |
| } |
| |
| return adxl345_write8(itf, ADXL345_TIME_FF, time); |
| } |
| |
| /** |
| * Gets current threshold and time set for triggering freefall interrupt |
| * |
| * @param The sensor interface |
| * @param Pointer to store threshold value (62.5mg/LSB) |
| * @param Ponter to store time value in seconds |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_freefall_settings(struct sensor_itf *itf, uint8_t *threshold, uint8_t *time) |
| { |
| int rc; |
| |
| rc = adxl345_read8(itf, ADXL345_THRESH_FF, threshold); |
| if (rc){ |
| return rc; |
| } |
| |
| return adxl345_read8(itf, ADXL345_TIME_FF, time); |
| } |
| |
| /** |
| * Sets new sample rate for measurements |
| * |
| * @param The sensor interface |
| * @param sample rate value |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_set_sample_rate(struct sensor_itf *itf, enum adxl345_sample_rate rate) |
| { |
| return adxl345_write8(itf, ADXL345_BW_RATE, (uint8_t) rate); |
| } |
| |
| /** |
| * Gets current sample rate settings |
| * |
| * @param The sensor interface |
| * @param Pointer to store rate value |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_get_sample_rate(struct sensor_itf *itf, enum adxl345_sample_rate *rate) |
| { |
| int rc; |
| uint8_t reg; |
| |
| rc = adxl345_read8(itf, ADXL345_BW_RATE, ®); |
| if (rc){ |
| return rc; |
| } |
| |
| *rate = (enum adxl345_sample_rate)(reg & 0xF); |
| return 0; |
| } |
| |
| /** |
| * Configures which interrupts are enabled and which interrupt pins they are |
| * mapped to. |
| * |
| * @param The sensor interface |
| * @param which interrupts are enabled |
| * @param which interrupts are mapped to which pin |
| * |
| * @return 0 on success, non-zero error on failure |
| */ |
| int |
| adxl345_setup_interrupts(struct sensor_itf *itf, uint8_t enables, uint8_t mapping) |
| { |
| int rc; |
| |
| rc = adxl345_write8(itf, ADXL345_INT_MAP, mapping); |
| if (rc) { |
| return rc; |
| } |
| |
| return adxl345_write8(itf, ADXL345_INT_ENABLE, enables); |
| } |
| |
| /** |
| * Clears interrupts (except DATA_READY, Watermark & Overrun which need data to |
| * be read to clear). Provides status as output to identify which interrupts have |
| * triggered. |
| * |
| * @param The sensor interface |
| * @param Pointer to store interrupt status |
| * |
| * @return 0 on success, non-zero error on failure |
| */ |
| int adxl345_clear_interrupts(struct sensor_itf *itf, uint8_t *int_status) |
| { |
| return adxl345_read8(itf, ADXL345_INT_SOURCE, int_status); |
| } |
| |
| /** |
| * Expects to be called back through os_dev_create(). |
| * |
| * @param The device object associated with this accelerometer |
| * @param Argument passed to OS device init, unused |
| * |
| * @return 0 on success, non-zero error on failure. |
| */ |
| int |
| adxl345_init(struct os_dev *dev, void *arg) |
| { |
| struct adxl345 *adxl; |
| struct sensor *sensor; |
| int rc; |
| |
| if (!arg || !dev) { |
| return SYS_ENODEV; |
| } |
| |
| adxl = (struct adxl345 *) dev; |
| |
| adxl->cfg.mask = SENSOR_TYPE_ALL; |
| |
| sensor = &adxl->sensor; |
| |
| /* Initialise the stats entry */ |
| rc = stats_init( |
| STATS_HDR(g_adxl345stats), |
| STATS_SIZE_INIT_PARMS(g_adxl345stats, STATS_SIZE_32), |
| STATS_NAME_INIT_PARMS(adxl345_stat_section)); |
| SYSINIT_PANIC_ASSERT(rc == 0); |
| /* Register the entry with the stats registry */ |
| rc = stats_register(dev->od_name, STATS_HDR(g_adxl345stats)); |
| SYSINIT_PANIC_ASSERT(rc == 0); |
| |
| rc = sensor_init(sensor, dev); |
| if (rc) { |
| return rc; |
| } |
| |
| /* Add the accelerometer/gyroscope driver */ |
| rc = sensor_set_driver(sensor, SENSOR_TYPE_ACCELEROMETER, |
| (struct sensor_driver *) &adxl345_sensor_driver); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = sensor_set_interface(sensor, arg); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = sensor_mgr_register(sensor); |
| if (rc) { |
| return rc; |
| } |
| |
| if (sensor->s_itf.si_type == SENSOR_ITF_SPI) { |
| rc = hal_spi_config(sensor->s_itf.si_num, &spi_adxl345_settings); |
| if (rc == EINVAL) { |
| return rc; |
| } |
| |
| rc = hal_spi_enable(sensor->s_itf.si_num); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = hal_gpio_init_out(sensor->s_itf.si_cs_pin, 1); |
| if (rc) { |
| return rc; |
| } |
| } |
| |
| #if MYNEWT_VAL(ADXL345_INT_ENABLE) |
| adxl->pdd.read_ctx.srec_sensor = sensor; |
| adxl->pdd.notify_ctx.snec_sensor = sensor; |
| |
| rc = init_intpin(adxl, interrupt_handler, sensor); |
| if (rc != 0) { |
| return rc; |
| } |
| #endif |
| |
| |
| return 0; |
| } |
| |
| /** |
| * Configure ADXL345 sensor |
| * |
| * @param Sensor device ADXL345 structure |
| * @param Sensor device ADXL345 config |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| adxl345_config(struct adxl345 *dev, struct adxl345_cfg *cfg) |
| { |
| int rc; |
| struct sensor_itf *itf; |
| |
| itf = SENSOR_GET_ITF(&(dev->sensor)); |
| |
| /* Check device id is correct */ |
| uint8_t val = 0; |
| rc = adxl345_read8(itf, ADXL345_DEVID, &val); |
| if (rc) { |
| return rc; |
| } |
| if (val != ADXL345_DEVID_VAL) { |
| return SYS_EINVAL; |
| } |
| |
| rc = adxl345_read8(itf, ADXL345_DATA_FORMAT, &val); |
| if (rc) { |
| return rc; |
| } |
| |
| /* Set accelerometer into full resolution */ |
| val |= 0x08; |
| |
| /* Set interupt pin polarity to match local pin setting */ |
| if (dev->sensor.s_itf.si_ints[dev->pdd.int_num].active) { |
| val &= ~0x20; |
| } else { |
| val |= 0x20; |
| } |
| |
| rc = adxl345_write8(itf, ADXL345_DATA_FORMAT, val); |
| if (rc) { |
| return rc; |
| } |
| |
| /* Setup range as per config */ |
| rc = adxl345_set_accel_range(itf, cfg->accel_range); |
| if (rc) { |
| return rc; |
| } |
| dev->cfg.accel_range = cfg->accel_range; |
| |
| /* setup sample rate */ |
| rc = adxl345_set_sample_rate(itf, cfg->sample_rate); |
| if (rc) { |
| return rc; |
| } |
| dev->cfg.sample_rate = cfg->sample_rate; |
| |
| /* setup data offsets */ |
| rc = adxl345_set_offsets(itf, cfg->offset_x, cfg->offset_y, cfg->offset_z); |
| if (rc) { |
| return rc; |
| } |
| dev->cfg.offset_x = cfg->offset_x; |
| dev->cfg.offset_y = cfg->offset_y; |
| dev->cfg.offset_z = cfg->offset_z; |
| |
| /* setup tap detection settings */ |
| rc = adxl345_set_tap_settings(itf, cfg->tap_cfg); |
| if (rc) { |
| return rc; |
| } |
| dev->cfg.tap_cfg = cfg->tap_cfg; |
| |
| /* setup activity detection settings */ |
| rc = adxl345_set_active_threshold(itf, 0xFF); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_set_inactive_settings(itf, 0, 0); |
| if (rc) { |
| return rc; |
| } |
| |
| /* setup freefall settings */ |
| rc = adxl345_set_freefall_settings(itf, cfg->freefall_threshold, cfg->freefall_time); |
| if (rc) { |
| return rc; |
| } |
| dev->cfg.freefall_threshold = cfg->freefall_threshold; |
| dev->cfg.freefall_time = cfg->freefall_time; |
| |
| /* setup low power mode */ |
| rc = adxl345_set_low_power_enable(itf, cfg->low_power_enable); |
| if (rc) { |
| return rc; |
| } |
| dev->cfg.low_power_enable = cfg->low_power_enable; |
| |
| /* setup default interrupt config */ |
| rc = adxl345_setup_interrupts(itf, 0, 0); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_clear_interrupts(itf, &val); |
| if (rc) { |
| return rc; |
| } |
| |
| /* Setup current power mode */ |
| rc = adxl345_set_power_mode(itf, cfg->power_mode); |
| if (rc) { |
| return rc; |
| } |
| dev->cfg.power_mode = cfg->power_mode; |
| |
| |
| rc = sensor_set_type_mask(&(dev->sensor), cfg->mask); |
| if (rc) { |
| return rc; |
| } |
| |
| dev->cfg.mask = cfg->mask; |
| |
| return 0; |
| } |
| |
| static float adxl345_convert_reg_to_ms2(int16_t val, float lsb_mg) |
| { |
| float tmp = val * lsb_mg * 0.001; /* convert to g */ |
| return tmp * STANDARD_ACCEL_GRAVITY; /* convert to ms2 */ |
| } |
| |
| static uint8_t adxl345_convert_ms2_to_reg(float ms2, float lsb_mg) |
| { |
| float tmp = (ms2 * 1000) / STANDARD_ACCEL_GRAVITY; /* convert to mg */ |
| tmp /= lsb_mg; /* convert to reg format */ |
| return (uint8_t) tmp; |
| } |
| |
| /** |
| * Reads Accelerometer data from ADXL345 sensor |
| * |
| * @param Pointer to sensor interface |
| * @param Pointer to structure to store result |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| int |
| adxl345_get_accel_data(struct sensor_itf *itf, struct sensor_accel_data *sad) |
| { |
| int rc; |
| |
| uint8_t payload[6]; |
| int16_t x,y,z; |
| |
| float lsb_mg = 4; /* lsb is always 4mg when device is set to full resolution */ |
| |
| /* Get a new accelerometer sample */ |
| rc = adxl345_readlen(itf, ADXL345_DATAX0, payload, 6); |
| if (rc) { |
| return rc; |
| } |
| |
| x = (((int16_t)payload[1]) << 8) | payload[0]; |
| y = (((int16_t)payload[3]) << 8) | payload[2]; |
| z = (((int16_t)payload[5]) << 8) | payload[4]; |
| |
| /* calculate MS*2 values to provide to data_func */ |
| sad->sad_x = adxl345_convert_reg_to_ms2(x, lsb_mg); |
| sad->sad_x_is_valid = 1; |
| sad->sad_y = adxl345_convert_reg_to_ms2(y, lsb_mg); |
| sad->sad_y_is_valid = 1; |
| sad->sad_z = adxl345_convert_reg_to_ms2(z, lsb_mg); |
| sad->sad_z_is_valid = 1; |
| |
| return 0; |
| } |
| |
| /** |
| * Read Accelerometer data from ADXL345 sensor |
| * |
| * @param Pointer to sensor structure |
| * @param Type of sensor data to read |
| * @param Pointer to function to call to output data |
| * @param Pointer to data to pass to data_func |
| * @param timeout value |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| adxl345_sensor_read(struct sensor *sensor, sensor_type_t type, |
| sensor_data_func_t data_func, void *data_arg, uint32_t timeout) |
| { |
| (void)timeout; |
| int rc; |
| |
| struct sensor_itf *itf; |
| struct sensor_accel_data sad; |
| |
| /* If the read isn't looking for accel don't do anything. */ |
| if (!(type & SENSOR_TYPE_ACCELEROMETER)) { |
| return SYS_EINVAL; |
| } |
| |
| itf = SENSOR_GET_ITF(sensor); |
| |
| rc = adxl345_get_accel_data(itf, &sad); |
| if (rc) { |
| return rc; |
| } |
| |
| /* output data using data_func */ |
| rc = data_func(sensor, data_arg, &sad, SENSOR_TYPE_ACCELEROMETER); |
| if (rc) { |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| adxl345_sensor_get_config(struct sensor *sensor, sensor_type_t type, |
| struct sensor_cfg *cfg) |
| { |
| /* If the read isn't looking for accel, don't do anything. */ |
| if (!(type & SENSOR_TYPE_ACCELEROMETER)) { |
| return SYS_EINVAL; |
| } |
| |
| cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT_TRIPLET; |
| |
| return 0; |
| } |
| |
| #if MYNEWT_VAL(ADXL345_INT_ENABLE) |
| static void |
| interrupt_handler(void * arg) |
| { |
| struct sensor *sensor = arg; |
| sensor_mgr_put_interrupt_evt(sensor); |
| } |
| |
| /** |
| * Initialises the local interrupt pin |
| * |
| * @param Pointer to device structure |
| * @param interrupt handler to setup |
| * @param Pointer to data to pass to irq |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| init_intpin(struct adxl345 * adxl345, hal_gpio_irq_handler_t handler, |
| void * arg) |
| { |
| struct adxl345_private_driver_data *pdd = &adxl345->pdd; |
| hal_gpio_irq_trig_t trig; |
| int pin = -1; |
| int rc; |
| int i; |
| |
| for (i = 0; i < MYNEWT_VAL(SENSOR_MAX_INTERRUPTS_PINS); i++){ |
| pin = adxl345->sensor.s_itf.si_ints[i].host_pin; |
| if (pin >= 0) { |
| break; |
| } |
| } |
| |
| if (pin < 0) { |
| ADXL345_LOG(ERROR, "Interrupt pin not configured\n"); |
| return SYS_EINVAL; |
| } |
| |
| pdd->int_num = i; |
| if (adxl345->sensor.s_itf.si_ints[pdd->int_num].active) { |
| trig = HAL_GPIO_TRIG_RISING; |
| } else { |
| trig = HAL_GPIO_TRIG_FALLING; |
| } |
| |
| if (adxl345->sensor.s_itf.si_ints[pdd->int_num].device_pin == 1) { |
| pdd->int_route = 0x00; |
| } else if (adxl345->sensor.s_itf.si_ints[pdd->int_num].device_pin == 2) { |
| pdd->int_route = 0xFF; |
| } else { |
| ADXL345_LOG(ERROR, "Route not configured\n"); |
| return SYS_EINVAL; |
| } |
| |
| rc = hal_gpio_irq_init(pin, |
| handler, |
| arg, |
| trig, |
| HAL_GPIO_PULL_NONE); |
| if (rc != 0) { |
| ADXL345_LOG(ERROR, "Failed to initialise interrupt pin %d\n", pin); |
| return rc; |
| } |
| |
| return 0; |
| } |
| |
| /** |
| * Enables an interrupt in ADXL345 device |
| * |
| * @param Pointer to sensor structure |
| * @param which interrupt(s) to enable |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| enable_interrupt(struct sensor * sensor, uint8_t ints_to_enable) |
| { |
| struct adxl345_private_driver_data *pdd; |
| struct adxl345 *adxl345; |
| struct sensor_itf *itf; |
| |
| if (ints_to_enable == 0) { |
| return SYS_EINVAL; |
| } |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| itf = SENSOR_GET_ITF(sensor); |
| pdd = &adxl345->pdd; |
| |
| /* if no interrupts are currently in use enable int pin */ |
| if (pdd->int_enable == 0) { |
| hal_gpio_irq_enable(adxl345->sensor.s_itf.si_ints[pdd->int_num].host_pin); |
| } |
| |
| /* update which interrupts are enabled */ |
| pdd->int_enable |= ints_to_enable; |
| |
| /* enable interrupt in device */ |
| return adxl345_setup_interrupts(itf, pdd->int_enable, pdd->int_route); |
| } |
| |
| /** |
| * Disables an interrupt in ADXL345 device |
| * |
| * @param Pointer to sensor structure |
| * @param which interrupt(s) to disable |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| disable_interrupt(struct sensor * sensor, uint8_t ints_to_disable) |
| { |
| struct adxl345_private_driver_data *pdd; |
| struct adxl345 *adxl345; |
| struct sensor_itf *itf; |
| |
| if (ints_to_disable == 0) { |
| return SYS_EINVAL; |
| } |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| itf = SENSOR_GET_ITF(sensor); |
| pdd = &adxl345->pdd; |
| |
| /* update which interrupts are enabled */ |
| pdd->int_enable &= ~ints_to_disable; |
| |
| /* if no interrupts are now in use disable int pin */ |
| if (pdd->int_enable == 0) { |
| hal_gpio_irq_disable(adxl345->sensor.s_itf.si_ints[pdd->int_num].host_pin); |
| } |
| |
| /* update interrupt setup in device */ |
| return adxl345_setup_interrupts(itf, pdd->int_enable, pdd->int_route); |
| } |
| #endif |
| |
| /** |
| * Handles and interrupt, firing correct events |
| * |
| * @param Pointer to sensor structure |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| adxl345_sensor_handle_interrupt(struct sensor * sensor) |
| { |
| #if MYNEWT_VAL(ADXL345_INT_ENABLE) |
| struct adxl345 * adxl345; |
| struct adxl345_private_driver_data *pdd; |
| struct sensor_itf *itf; |
| uint8_t int_status; |
| |
| int rc; |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| itf = SENSOR_GET_ITF(sensor); |
| |
| pdd = &adxl345->pdd; |
| |
| rc = adxl345_clear_interrupts(itf, &int_status); |
| if (rc != 0) { |
| ADXL345_LOG(ERROR, "Cound not read int status err=0x%02x\n", rc); |
| return rc; |
| } |
| |
| if (pdd->registered_mask & ADXL345_NOTIFY_MASK) { |
| if (int_status & ADXL345_INT_SINGLE_TAP_BIT) { |
| sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_SINGLE_TAP); |
| } |
| |
| if (int_status & ADXL345_INT_DOUBLE_TAP_BIT) { |
| sensor_mgr_put_notify_evt(&pdd->notify_ctx, SENSOR_EVENT_TYPE_DOUBLE_TAP); |
| } |
| } |
| |
| if ((pdd->registered_mask & ADXL345_READ_MASK) && |
| ((int_status & ADXL345_INT_ACTIVITY_BIT) || |
| (int_status & ADXL345_INT_INACTIVITY_BIT))) { |
| ADXL345_LOG(ERROR, "READ EVT 0x%02x\n", int_status); |
| sensor_mgr_put_read_evt(&pdd->read_ctx); |
| } |
| |
| return 0; |
| #else |
| return SYS_ENODEV; |
| #endif |
| } |
| |
| /** |
| * Sets up trigger thresholds and enables interrupts |
| * |
| * @param Pointer to sensor structure |
| * @param type of sensor |
| * @param threshold settings to configure |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| adxl345_sensor_set_trigger_thresh(struct sensor * sensor, |
| sensor_type_t sensor_type, |
| struct sensor_type_traits * stt) |
| { |
| #if MYNEWT_VAL(ADXL345_INT_ENABLE) |
| struct adxl345 * adxl345; |
| struct sensor_itf *itf; |
| int rc; |
| const struct sensor_accel_data * low_thresh; |
| const struct sensor_accel_data * high_thresh; |
| uint8_t ints_to_enable = 0; |
| float thresh; |
| struct adxl345_private_driver_data *pdd; |
| struct adxl345_act_inact_enables axis_enables = { 0 }; |
| |
| if (sensor_type != SENSOR_TYPE_ACCELEROMETER) { |
| return SYS_EINVAL; |
| } |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| itf = SENSOR_GET_ITF(sensor); |
| pdd = &adxl345->pdd; |
| |
| low_thresh = stt->stt_low_thresh.sad; |
| high_thresh = stt->stt_high_thresh.sad; |
| |
| if (low_thresh->sad_x_is_valid | |
| low_thresh->sad_y_is_valid | |
| low_thresh->sad_z_is_valid) { |
| thresh = INFINITY; |
| |
| if (low_thresh->sad_x_is_valid) { |
| axis_enables.inact_x = 1; |
| if (thresh > low_thresh->sad_x) { |
| thresh = low_thresh->sad_x; |
| } |
| } |
| if (low_thresh->sad_y_is_valid) { |
| axis_enables.inact_y = 1; |
| if (thresh > low_thresh->sad_y) { |
| thresh = low_thresh->sad_y; |
| } |
| } |
| if (low_thresh->sad_z_is_valid) { |
| axis_enables.inact_z = 1; |
| if (thresh > low_thresh->sad_z) { |
| thresh = low_thresh->sad_z; |
| } |
| } |
| |
| rc = adxl345_set_inactive_settings(itf, |
| adxl345_convert_ms2_to_reg(thresh, 62.5), 2); |
| |
| if (rc) { |
| return rc; |
| } |
| |
| ints_to_enable |= ADXL345_INT_INACTIVITY_BIT; |
| } |
| |
| if (high_thresh->sad_x_is_valid | |
| high_thresh->sad_y_is_valid | |
| high_thresh->sad_z_is_valid) { |
| thresh = 0.0; |
| |
| if (high_thresh->sad_x_is_valid) { |
| axis_enables.act_x = 1; |
| if (thresh < high_thresh->sad_x) { |
| thresh = high_thresh->sad_x; |
| } |
| } |
| if (high_thresh->sad_y_is_valid) { |
| axis_enables.act_y = 1; |
| if (thresh < high_thresh->sad_y) { |
| thresh = high_thresh->sad_y; |
| } |
| } |
| if (high_thresh->sad_z_is_valid) { |
| axis_enables.act_z = 1; |
| if (thresh < high_thresh->sad_z) { |
| thresh = high_thresh->sad_z; |
| } |
| } |
| |
| rc = adxl345_set_active_threshold(itf, |
| adxl345_convert_ms2_to_reg(thresh, 62.5)); |
| if (rc) { |
| return rc; |
| } |
| |
| ints_to_enable |= ADXL345_INT_ACTIVITY_BIT; |
| |
| } |
| |
| rc = enable_interrupt(sensor, ints_to_enable); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = adxl345_set_act_inact_enables(itf, axis_enables); |
| if (rc) { |
| return rc; |
| } |
| |
| pdd->read_ctx.srec_type |= sensor_type; |
| pdd->registered_mask |= ADXL345_READ_MASK; |
| |
| return 0; |
| #else |
| return SYS_ENODEV; |
| #endif |
| } |
| |
| /** |
| * Disable the low threshold interrupt |
| * |
| * @param ptr to sensor |
| * @param the Sensor type |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| adxl345_sensor_clear_low_thresh(struct sensor *sensor, |
| sensor_type_t type) |
| { |
| struct adxl345 *adxl345; |
| uint8_t ints_to_disable = ADXL345_INT_INACTIVITY_BIT; |
| |
| if (type != SENSOR_TYPE_ACCELEROMETER) { |
| return SYS_EINVAL; |
| } |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| |
| /* if neither high or low threshs are now set disable read mask */ |
| if((adxl345->pdd.int_enable & ADXL345_INT_ACTIVITY_BIT) == 0) { |
| adxl345->pdd.read_ctx.srec_type &= ~type; |
| adxl345->pdd.registered_mask &= ~ADXL345_READ_MASK; |
| } |
| |
| return disable_interrupt(sensor, ints_to_disable); |
| } |
| |
| |
| /** |
| * Disable the high threshold interrupt |
| * |
| * @param ptr to sensor |
| * @param the Sensor type |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| adxl345_sensor_clear_high_thresh(struct sensor *sensor, |
| sensor_type_t type) |
| { |
| struct adxl345 *adxl345; |
| uint8_t ints_to_disable = ADXL345_INT_ACTIVITY_BIT; |
| |
| if (type != SENSOR_TYPE_ACCELEROMETER) { |
| return SYS_EINVAL; |
| } |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| |
| /* if neither high or low threshs are now set disable read mask */ |
| if((adxl345->pdd.int_enable & ADXL345_INT_INACTIVITY_BIT) == 0) { |
| adxl345->pdd.read_ctx.srec_type &= ~type; |
| adxl345->pdd.registered_mask &= ~ADXL345_READ_MASK; |
| } |
| |
| return disable_interrupt(sensor, ints_to_disable); |
| } |
| |
| /** |
| * Enables notifications on tap or double tap events |
| * |
| * @param Pointer to sensor structure |
| * @param which event to get notifications for |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| adxl345_sensor_set_notification(struct sensor * sensor, |
| sensor_event_type_t sensor_event_type) |
| { |
| #if MYNEWT_VAL(ADXL345_INT_ENABLE) |
| struct adxl345 * adxl345; |
| uint8_t ints_to_enable = 0; |
| struct adxl345_private_driver_data *pdd; |
| int rc; |
| |
| ADXL345_LOG(ERROR, "Enabling notifications\n"); |
| |
| if ((sensor_event_type & ~(SENSOR_EVENT_TYPE_DOUBLE_TAP | |
| SENSOR_EVENT_TYPE_SINGLE_TAP)) != 0) { |
| return SYS_EINVAL; |
| } |
| |
| /*XXX for now we do not support registering for both events */ |
| if (sensor_event_type == (SENSOR_EVENT_TYPE_DOUBLE_TAP | |
| SENSOR_EVENT_TYPE_SINGLE_TAP)) { |
| return SYS_EINVAL; |
| } |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| pdd = &adxl345->pdd; |
| |
| if (pdd->registered_mask & ADXL345_NOTIFY_MASK) { |
| return SYS_EBUSY; |
| } |
| |
| /* Enable tap event*/ |
| if(sensor_event_type == SENSOR_EVENT_TYPE_DOUBLE_TAP) { |
| ints_to_enable |= ADXL345_INT_DOUBLE_TAP_BIT; |
| } |
| if(sensor_event_type == SENSOR_EVENT_TYPE_SINGLE_TAP) { |
| ints_to_enable |= ADXL345_INT_SINGLE_TAP_BIT; |
| } |
| |
| rc = enable_interrupt(sensor, ints_to_enable); |
| if (rc) { |
| return rc; |
| } |
| |
| pdd->notify_ctx.snec_evtype |= sensor_event_type; |
| pdd->registered_mask |= ADXL345_NOTIFY_MASK; |
| |
| ADXL345_LOG(ERROR, "Enabled notifications\n"); |
| |
| return 0; |
| #else |
| return SYS_ENODEV; |
| #endif |
| } |
| |
| |
| /** |
| * Disables notifications on tap or double tap events |
| * |
| * @param Pointer to sensor structure |
| * @param which event to get notifications for |
| * |
| * @return 0 on success, non-zero on failure |
| */ |
| static int |
| adxl345_sensor_unset_notification(struct sensor * sensor, |
| sensor_event_type_t sensor_event_type) |
| { |
| #if MYNEWT_VAL(ADXL345_INT_ENABLE) |
| struct adxl345 * adxl345; |
| uint8_t ints_to_disable = 0; |
| |
| if ((sensor_event_type & ~(SENSOR_EVENT_TYPE_DOUBLE_TAP | |
| SENSOR_EVENT_TYPE_SINGLE_TAP)) != 0) { |
| return SYS_EINVAL; |
| } |
| |
| /*XXX for now we do not support registering for both events */ |
| if (sensor_event_type == (SENSOR_EVENT_TYPE_DOUBLE_TAP | |
| SENSOR_EVENT_TYPE_SINGLE_TAP)) { |
| return SYS_EINVAL; |
| } |
| |
| adxl345 = (struct adxl345 *)SENSOR_GET_DEVICE(sensor); |
| |
| adxl345->pdd.notify_ctx.snec_evtype &= ~sensor_event_type; |
| adxl345->pdd.registered_mask &= ~ADXL345_NOTIFY_MASK; |
| |
| ints_to_disable |= ADXL345_INT_SINGLE_TAP_BIT; |
| ints_to_disable |= ADXL345_INT_DOUBLE_TAP_BIT; |
| |
| return disable_interrupt(sensor, ints_to_disable); |
| |
| #else |
| return SYS_ENODEV; |
| #endif |
| } |
| |
| |
| |