diff --git a/hal/inc/exrtc_hal.h b/hal/inc/exrtc_hal.h index c8bb49050d..045cc73c4a 100644 --- a/hal/inc/exrtc_hal.h +++ b/hal/inc/exrtc_hal.h @@ -23,10 +23,24 @@ #if HAL_PLATFORM_EXTERNAL_RTC #include "rtc_hal.h" +#include "i2c_hal.h" #include "system_tick_hal.h" #include #include +#define HAL_EXRTC_CONFIG_VERSION 1 + +typedef struct hal_exrtc_config_t { + uint16_t version; + uint16_t size; + uint8_t wdi_pin; + uint8_t int_pin; + hal_i2c_interface_t i2c_if; + uint8_t i2c_addr; + int8_t osc_cal_xt; + uint8_t reserved[7]; +} hal_exrtc_config_t; + #ifdef __cplusplus extern "C" { #endif @@ -34,7 +48,7 @@ extern "C" { typedef hal_rtc_alarm_handler hal_exrtc_alarm_handler; typedef hal_rtc_alarm_flags hal_exrtc_alarm_flags; -int hal_exrtc_init(void* reserved); +int hal_exrtc_init(const hal_exrtc_config_t* config, void* reserved); int hal_exrtc_set_time(const struct timeval* tv, void* reserved); int hal_exrtc_get_time(struct timeval* tv, void* reserved); int hal_exrtc_set_alarm(const struct timeval* tv, uint32_t flags, hal_exrtc_alarm_handler handler, void* context, void* reserved); diff --git a/hal/inc/hal_dynalib.h b/hal/inc/hal_dynalib.h index e4d0a3e86c..766b4b47f5 100644 --- a/hal/inc/hal_dynalib.h +++ b/hal/inc/hal_dynalib.h @@ -36,9 +36,9 @@ #include "rtc_hal.h" #include "interrupts_hal.h" -#if PLATFORM_ID == PLATFORM_TRACKER +#if HAL_PLATFORM_EXTERNAL_RTC #include "exrtc_hal.h" -#endif // PLATFORM_ID == PLATFORM_TRACKER +#endif // HAL_PLATFORM_EXTERNAL_RTC #endif @@ -99,15 +99,23 @@ DYNALIB_FN(BASE_IDX + 22, hal, hal_timer_micros, uint64_t(void*)) DYNALIB_FN(BASE_IDX + 23, hal, hal_rtc_get_time, int(struct timeval*, void*)) DYNALIB_FN(BASE_IDX + 24, hal, hal_rtc_set_time, int(const struct timeval*, void*)) -#if PLATFORM_ID == PLATFORM_TRACKER +#if HAL_PLATFORM_EXTERNAL_RTC DYNALIB_FN(BASE_IDX + 25, hal, hal_exrtc_enable_watchdog, int(system_tick_t, void*)) DYNALIB_FN(BASE_IDX + 26, hal, hal_exrtc_feed_watchdog, int(void*)) DYNALIB_FN(BASE_IDX + 27, hal, hal_exrtc_disable_watchdog, int(void*)) DYNALIB_FN(BASE_IDX + 28, hal, hal_exrtc_get_watchdog_limits, void(system_tick_t*, system_tick_t*, void*)) -#define BASE_IDX2 (BASE_IDX + 29) +DYNALIB_FN(BASE_IDX + 29, hal, hal_exrtc_init, int(const hal_exrtc_config_t*, void*)) +DYNALIB_FN(BASE_IDX + 30, hal, hal_exrtc_set_time, int(const struct timeval*, void*)) +DYNALIB_FN(BASE_IDX + 31, hal, hal_exrtc_get_time, int(struct timeval*, void*)) +DYNALIB_FN(BASE_IDX + 32, hal, hal_exrtc_set_alarm, int(const struct timeval*, uint32_t, hal_exrtc_alarm_handler, void*, void*)) +DYNALIB_FN(BASE_IDX + 33, hal, hal_exrtc_cancel_alarm, int(void*)) +DYNALIB_FN(BASE_IDX + 34, hal, hal_exrtc_time_is_valid, bool(void*)) +DYNALIB_FN(BASE_IDX + 35, hal, hal_exrtc_sleep_timer, int(system_tick_t, void*)) +DYNALIB_FN(BASE_IDX + 36, hal, hal_exrtc_calibrate_xt, int(int, void*)) +#define BASE_IDX2 (BASE_IDX + 37) #else #define BASE_IDX2 (BASE_IDX + 25) -#endif // PLATFORM_ID == PLATFORM_TRACKER +#endif // HAL_PLATFORM_EXTERNAL_RTC DYNALIB_END(hal) diff --git a/hal/inc/hal_platform.h b/hal/inc/hal_platform.h index 049afd5ccc..52c8129325 100644 --- a/hal/inc/hal_platform.h +++ b/hal/inc/hal_platform.h @@ -399,17 +399,9 @@ #define HAL_PLATFORM_EXTERNAL_RTC (0) #endif // HAL_PLATFORM_EXTERNAL_RTC -#if HAL_PLATFORM_EXTERNAL_RTC -# ifndef HAL_PLATFORM_EXTERNAL_RTC_I2C -# error "HAL_PLATFORM_EXTERNAL_RTC_I2C is not defined" -# endif /* HAL_PLATFORM_EXTERNAL_RTC_I2C */ -# ifndef HAL_PLATFORM_EXTERNAL_RTC_I2C_ADDR -# error "HAL_PLATFORM_EXTERNAL_RTC_I2C_ADDR is not defined" -# endif /* HAL_PLATFORM_EXTERNAL_RTC_I2C_ADDR */ -# ifndef HAL_PLATFORM_EXTERNAL_RTC_CAL_XT -# define HAL_PLATFORM_EXTERNAL_RTC_CAL_XT (0) -# endif /* HAL_PLATFORM_EXTERNAL_RTC_CAL_XT */ -#endif /* HAL_PLATFORM_EXTERNAL_RTC */ +#ifndef HAL_PLATFORM_EXTERNAL_RTC_OPTIONAL +#define HAL_PLATFORM_EXTERNAL_RTC_OPTIONAL (0) +#endif // HAL_PLATFORM_EXTERNAL_RTC_OPTIONAL #ifndef HAL_PLATFORM_FILE_MAXIMUM_FD #define HAL_PLATFORM_FILE_MAXIMUM_FD (65535) diff --git a/hal/src/tracker/am18x5.cpp b/hal/shared/am18x5.cpp similarity index 75% rename from hal/src/tracker/am18x5.cpp rename to hal/shared/am18x5.cpp index 153f492f0d..974f521ff9 100644 --- a/hal/src/tracker/am18x5.cpp +++ b/hal/shared/am18x5.cpp @@ -52,15 +52,15 @@ int timevalToCalendar(const struct timeval* tv, struct tm* calendar) { Am18x5::Am18x5() : initialized_(false), - address_(HAL_PLATFORM_EXTERNAL_RTC_I2C_ADDR), - wire_(HAL_PLATFORM_EXTERNAL_RTC_I2C), + detected_(false), alarmYear_(0), alarmHandler_(nullptr), alarmHandlerContext_(nullptr), exRtcWorkerThread_(nullptr), exRtcWorkerSemaphore_(nullptr), exRtcWorkerThreadExit_(false) { - begin(); + config_.version = HAL_EXRTC_CONFIG_VERSION; + config_.size = sizeof(hal_exrtc_config_t); } Am18x5::~Am18x5() { @@ -72,20 +72,37 @@ Am18x5& Am18x5::getInstance() { return am18x5; } -int Am18x5::begin() { +void Am18x5::dumpRegisters() const { + uint8_t buff[16] = {0}; + for (uint8_t i = 0; i < 16; ++i) { + readRegister(static_cast(i + 0x0F), &buff[i]); + } + LOG(TRACE, "AM18x5 Registers:"); + for (uint8_t i = 0; i < 16; ++i) { + LOG(TRACE, "Reg %02X: %02X", i + 0x0F, buff[i]); + } +} + +int Am18x5::begin(const hal_exrtc_config_t* config) { CHECK_FALSE(initialized_, SYSTEM_ERROR_NONE); - - if (!hal_i2c_is_enabled(wire_, nullptr)) { - CHECK(hal_i2c_init(wire_, nullptr)); - hal_i2c_begin(wire_, I2C_MODE_MASTER, 0x00, nullptr); + CHECK_TRUE(config, SYSTEM_ERROR_INVALID_ARGUMENT); + memcpy(&config_, config, std::min(config->size, config_.size)); + + if (!hal_i2c_is_enabled(config_.i2c_if, nullptr)) { + CHECK(hal_i2c_init(config_.i2c_if, nullptr)); + hal_i2c_begin(config_.i2c_if, I2C_MODE_MASTER, 0x00, nullptr); // Make sure to reset the I2C bus to avoid potentially corrupting the AM18x5 configuration if // we start communication with it during an ongoing write transaction (which may happen e.g. after a hard reset) - hal_i2c_reset(wire_, 0, nullptr); + hal_i2c_reset(config_.i2c_if, 0, nullptr); } // NOTE: acquire lock only after initializing the I2C peripheral, as this will actually call into // hal_i2c_lock/hal_i2c_unlock, which do not function unless hal_i2c_init is called. - Am18x5Lock lock(); + Am18x5Lock lock; + + uint16_t partNumber = 0; + CHECK(getPartNumber(&partNumber, true)); + CHECK_TRUE(partNumber == PART_NUMBER, SYSTEM_ERROR_NOT_FOUND); if (os_semaphore_create(&exRtcWorkerSemaphore_, 1, 0)) { exRtcWorkerSemaphore_ = nullptr; @@ -99,25 +116,32 @@ int Am18x5::begin() { return SYSTEM_ERROR_INTERNAL; } - hal_gpio_mode(RTC_WDI, OUTPUT); - hal_gpio_write(RTC_WDI, 1); + if (config_.wdi_pin != PIN_INVALID) { + hal_gpio_mode(config_.wdi_pin, OUTPUT); + hal_gpio_write(config_.wdi_pin, 1); + } - hal_gpio_mode(RTC_INT, INPUT_PULLUP); - hal_interrupt_extra_configuration_t extra = {}; - extra.version = HAL_INTERRUPT_EXTRA_CONFIGURATION_VERSION_1; - CHECK(hal_interrupt_attach(RTC_INT, exRtcInterruptHandler, this, FALLING, &extra)); + if (config_.int_pin != PIN_INVALID) { + hal_gpio_mode(config_.int_pin, INPUT_PULLUP); + hal_interrupt_extra_configuration_t extra = {}; + extra.version = HAL_INTERRUPT_EXTRA_CONFIGURATION_VERSION_1; + CHECK(hal_interrupt_attach(config_.int_pin, exRtcInterruptHandler, this, FALLING, &extra)); + } initialized_ = true; - uint16_t partNumber = 0; - CHECK(getPartNumber(&partNumber)); - CHECK_TRUE(partNumber == PART_NUMBER, SYSTEM_ERROR_INTERNAL); - // Automatically switch to internal RC oscillator when using VBAT as the power supply. // CHECK(enableAutoSwitchOnBattery(true)); + // Select the external crystal oscillator as the default oscillator. + CHECK(selectOscillator(Am18x5Oscillator::EXTERNAL_CRYSTAL)); + + // But fallback to RC oscillator if the external oscillator fails + CHECK(writeRegister(Am18x5Register::CONFIG_KEY, CONFIG_KEY_OSC_CONTROL)); + CHECK(writeRegister(Am18x5Register::OSC_CONTROL, 1, false, true, OSC_CONTROL_FOS_MASK, OSC_CONTROL_FOS_SHIFT)); + // Digital calibration to improve accuracy. - xtOscillatorDigitalCalibration(HAL_PLATFORM_EXTERNAL_RTC_CAL_XT); + xtOscillatorDigitalCalibration(config_.osc_cal_xt); // Automatically clear interrupt flags after reading the the status register. CHECK(writeRegister(Am18x5Register::CONTROL1, 1, false, true, CONTROL1_ARST_MASK, CONTROL1_ARST_SHIFT)); @@ -126,7 +150,7 @@ int Am18x5::begin() { } int Am18x5::end() { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_NONE); exRtcWorkerThreadExit_ = true; @@ -142,16 +166,18 @@ int Am18x5::end() { } int Am18x5::lock() { - return hal_i2c_lock(wire_, nullptr); + return hal_i2c_lock(config_.i2c_if, nullptr); } int Am18x5::unlock() { - return hal_i2c_unlock(wire_, nullptr); + return hal_i2c_unlock(config_.i2c_if, nullptr); } -int Am18x5::getPartNumber(uint16_t* id) const { - Am18x5Lock lock(); - CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); +int Am18x5::getPartNumber(uint16_t* id, bool detect) const { + Am18x5Lock lock; + if (!detect) { + CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); + } uint8_t val = 0x00; CHECK(readRegister(Am18x5Register::ID0, &val)); *id = ((uint16_t)val) << 8; @@ -164,7 +190,7 @@ int Am18x5::setTime(const struct timeval* tv) const { struct tm calendar; CHECK(timevalToCalendar(tv, &calendar)); - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t buff[8] = {0}; buff[0] = CHECK(decToBcd(tv->tv_usec / MICROS_IN_HUNDREDTH)); @@ -182,7 +208,7 @@ int Am18x5::setTime(const struct timeval* tv) const { int Am18x5::getTime(struct timeval* tv) const { CHECK_TRUE(tv, SYSTEM_ERROR_INVALID_ARGUMENT); - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t buff[8] = {0}; CHECK(readContinuousRegisters(Am18x5Register::HUNDREDTHS, buff, sizeof(buff))); @@ -208,7 +234,7 @@ int Am18x5::setAlarm(const struct timeval* tv) { struct tm calendar; CHECK(timevalToCalendar(tv, &calendar)); - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t buff[7] = {0}; buff[0] = CHECK(decToBcd(tv->tv_usec / MICROS_IN_HUNDREDTH)); @@ -225,7 +251,7 @@ int Am18x5::setAlarm(const struct timeval* tv) { } int Am18x5::enableAlarm(bool enable, Am18x5::AlarmHandler handler, void* context) { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); alarmHandler_ = handler; alarmHandlerContext_ = context; @@ -260,7 +286,7 @@ int Am18x5::getAlarm(struct timeval* tv) const { } int Am18x5::enableWatchdog(uint8_t value, Am18x5WatchdogFrequency frequency) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); CHECK_TRUE(value < 32, SYSTEM_ERROR_INVALID_ARGUMENT); uint8_t regValue = WDT_REGISTER_WDS_MASK; @@ -270,36 +296,58 @@ int Am18x5::enableWatchdog(uint8_t value, Am18x5WatchdogFrequency frequency) con } int Am18x5::disableWatchdog() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::WDT, 0, false, true, WDT_REGISTER_BMB_MASK, WDT_REGISTER_BMB_SHIFT); } int Am18x5::feedWatchdog() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); - if (hal_gpio_read(RTC_WDI) == 1) { - hal_gpio_write(RTC_WDI, 0); + CHECK_TRUE(config_.wdi_pin != PIN_INVALID, SYSTEM_ERROR_INVALID_STATE); + + if (hal_gpio_read(config_.wdi_pin) == 1) { + hal_gpio_write(config_.wdi_pin, 0); } else { - hal_gpio_write(RTC_WDI, 1); + hal_gpio_write(config_.wdi_pin, 1); } return SYSTEM_ERROR_NONE; } +int Am18x5::setPsw(bool val) const { + Am18x5Lock lock; + CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); + CHECK(writeRegister(Am18x5Register::OSC_STATUS, 0, false, true, OSC_STATUS_LKO2_MASK, OSC_STATUS_LKO2_SHIFT)); + CHECK(writeRegister(Am18x5Register::CONTROL1, val, false, true, CONTROL1_OUTB_MASK, CONTROL1_OUTB_SHIFT)); + LOG(TRACE, "PSW set to %d", val); + return SYSTEM_ERROR_NONE; +} + int Am18x5::sleep(uint8_t ticks, Am18x5TimerFrequency frequency) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); - // Enable to access the BATMODE_IO and OUTPUT_CTRL registers - CHECK(writeRegister(Am18x5Register::CONFIG_KEY, 0x9D)); + // CONFIG_KEY_PRIMARY enables access to BATMODE_IO and OUTPUT_CTRL registers + CHECK(writeRegister(Am18x5Register::CONFIG_KEY, CONFIG_KEY_PRIMARY)); // Configure RTC pins to minimize power leakage CHECK(writeRegister(Am18x5Register::BATMODE_IO, 0x00)); - CHECK(writeRegister(Am18x5Register::OUTPUT_CTRL, 0x30)); + // CONFIG_KEY resets on each write, redo for OUTPUT_CTRL + CHECK(writeRegister(Am18x5Register::CONFIG_KEY, CONFIG_KEY_PRIMARY)); + CHECK(writeRegister(Am18x5Register::OUTPUT_CTRL, 0x20/*0x30*/)); // EXDS bit should be 0 inorder to use EXTI pin as the wakeup source // Stop the count down timer just in case CHECK(writeRegister(Am18x5Register::TIMER_CONTROL, 0, false, true, TIMER_CONTROL_TE_MASK, TIMER_CONTROL_TE_SHIFT)); // Set PSW/nIRQ2 to be working in SLEEP mode CHECK(writeRegister(Am18x5Register::CONTROL2, 6, false, true, CONTROL2_OUT2S_MASK, CONTROL2_OUT2S_SHIFT)); + + CHECK(writeRegister(Am18x5Register::CONFIG_KEY, CONFIG_KEY_OSC_CONTROL)); + CHECK(writeRegister(Am18x5Register::OSC_CONTROL, 1, false, true, OSC_CONTROL_PWGT_MASK, OSC_CONTROL_PWGT_SHIFT)); + + // Read status to clear the interrupt flags + uint8_t status = 0x00; + CHECK(readRegister(Am18x5Register::STATUS, &status)); + // Enable count down timer interrupt - CHECK(writeRegister(Am18x5Register::INT_MASK, 1, false, true, INTERRUPT_TIE_MASK, INTERRUPT_TIE_SHIFT)); + // CHECK(writeRegister(Am18x5Register::INT_MASK, 1, false, true, INTERRUPT_TIE_MASK, INTERRUPT_TIE_SHIFT)); // And the EX1E bit should be enabled to use EXTI pin as the wakeup source + CHECK(writeRegister(Am18x5Register::INT_MASK, 0xE9)); // Set count down timer's current value CHECK(writeRegister(Am18x5Register::TIMER, ticks)); // Configure and start the count down timer @@ -310,18 +358,22 @@ int Am18x5::sleep(uint8_t ticks, Am18x5TimerFrequency frequency) const { newValue &= ~TIMER_CONTROL_TFS_MASK; newValue |= static_cast(frequency); // Set the count down timer frequency CHECK(writeRegister(Am18x5Register::TIMER_CONTROL, newValue)); + + // Rising edge on EXTI pin will wake up the device + // CHECK(writeRegister(Am18x5Register::SLEEP_CONTROL, 0, false, true, SLEEP_CONTROL_EX1P_MASK, SLEEP_CONTROL_EX1P_SHIFT)); + // Transfer to SLEEP state without any delay return writeRegister(Am18x5Register::SLEEP_CONTROL, 1, false, true, SLEEP_CONTROL_SLP_MASK, SLEEP_CONTROL_SLP_SHIFT); } int Am18x5::setHundredths(uint8_t hundredths) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::HUNDREDTHS, hundredths, true); } int Am18x5::getHundredths() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t hundredths = 0; CHECK(readRegister(Am18x5Register::HUNDREDTHS, &hundredths, true)); @@ -329,14 +381,14 @@ int Am18x5::getHundredths() const { } int Am18x5::setSeconds(uint8_t seconds) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(seconds <= 59, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::SECONDS, seconds, true, false, SECONDS_MASK); } int Am18x5::getSeconds() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t seconds = 0; CHECK(readRegister(Am18x5Register::SECONDS, &seconds, true, SECONDS_MASK)); @@ -344,14 +396,14 @@ int Am18x5::getSeconds() const { } int Am18x5::setMinutes(uint8_t minutes) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(minutes <= 59, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::MINUTES, minutes, true, false, MINUTES_MASK); } int Am18x5::getMinutes() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t minutes = 0; CHECK(readRegister(Am18x5Register::MINUTES, &minutes, true, MINUTES_MASK)); @@ -359,7 +411,7 @@ int Am18x5::getMinutes() const { } int Am18x5::setHours(uint8_t hours, HourFormat format) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); if (format == HourFormat::HOUR24) { CHECK_TRUE(hours <= 23, SYSTEM_ERROR_INVALID_ARGUMENT); @@ -372,12 +424,12 @@ int Am18x5::setHours(uint8_t hours, HourFormat format) const { if (format == HourFormat::HOUR12_PM) { hours |= HOURS_AM_PM_MASK; } - return writeRegister(Am18x5Register::HOURS_ALARM, hours, false, false); + return writeRegister(Am18x5Register::HOURS, hours, false, false); } } int Am18x5::getHours(HourFormat* format) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(format, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t control1 = 0x00; @@ -397,14 +449,14 @@ int Am18x5::getHours(HourFormat* format) const { } int Am18x5::setDate(uint8_t date) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(date > 0 && date <= 31, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::DATE, date, true, false, DATE_MASK); } int Am18x5::getDate() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t date = 0; CHECK(readRegister(Am18x5Register::DATE, &date, true, DATE_MASK)); @@ -412,14 +464,14 @@ int Am18x5::getDate() const { } int Am18x5::setMonths(uint8_t months) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(months > 0 && months <= 12, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::MONTHS, months, true, false, MONTHS_MASK); } int Am18x5::getMonths() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t months = 0; CHECK(readRegister(Am18x5Register::MONTHS, &months, true, MONTHS_MASK)); @@ -427,13 +479,13 @@ int Am18x5::getMonths() const { } int Am18x5::setYears(uint8_t years) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::YEARS, years, true, false); } int Am18x5::getYears() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t years = 0; CHECK(readRegister(Am18x5Register::YEARS, &years, true)); @@ -441,14 +493,14 @@ int Am18x5::getYears() const { } int Am18x5::setWeekday(uint8_t weekday) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(weekday > 0 && weekday <= 7, SYSTEM_ERROR_INVALID_ARGUMENT); CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); return writeRegister(Am18x5Register::WEEKDAY, weekday, true, false, WEEKDAY_MASK); } int Am18x5::getWeekday() const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t weekday = 0; CHECK(readRegister(Am18x5Register::WEEKDAY, &weekday, true, WEEKDAY_MASK)); @@ -456,7 +508,7 @@ int Am18x5::getWeekday() const { } int Am18x5::xtOscillatorDigitalCalibration(int adjVal) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); uint8_t xtcal, cmdx; int offsetx; @@ -498,8 +550,9 @@ int Am18x5::xtOscillatorDigitalCalibration(int adjVal) const { } int Am18x5::selectOscillator(Am18x5Oscillator oscillator) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); + CHECK(writeRegister(Am18x5Register::CONFIG_KEY, CONFIG_KEY_OSC_CONTROL)); uint8_t val = 0; if (oscillator == Am18x5Oscillator::INTERNAL_RC) { val = 1; @@ -508,13 +561,14 @@ int Am18x5::selectOscillator(Am18x5Oscillator oscillator) const { } int Am18x5::enableAutoSwitchOnBattery(bool enable) const { - Am18x5Lock lock(); + Am18x5Lock lock; CHECK_TRUE(initialized_, SYSTEM_ERROR_INVALID_STATE); + CHECK(writeRegister(Am18x5Register::CONFIG_KEY, CONFIG_KEY_OSC_CONTROL)); return writeRegister(Am18x5Register::OSC_CONTROL, enable, false, true, OSC_CONTROL_AOS_MASK, OSC_CONTROL_AOS_SHIFT); } int Am18x5::writeRegister(const Am18x5Register reg, uint8_t val, bool bcd, bool rw, uint8_t mask, uint8_t shift) const { - Am18x5Lock lock(); + Am18x5Lock lock; uint8_t currValue = 0x00; if (rw) { CHECK(readRegister(reg, &currValue)); @@ -524,33 +578,33 @@ int Am18x5::writeRegister(const Am18x5Register reg, uint8_t val, bool bcd, bool CHECK(val = decToBcd(val)); } currValue |= (val << shift); - hal_i2c_begin_transmission(wire_, address_, nullptr); - hal_i2c_write(wire_, static_cast(reg), nullptr); - hal_i2c_write(wire_, currValue, nullptr); - hal_i2c_end_transmission(wire_, true, nullptr); + hal_i2c_begin_transmission(config_.i2c_if, config_.i2c_addr, nullptr); + hal_i2c_write(config_.i2c_if, static_cast(reg), nullptr); + hal_i2c_write(config_.i2c_if, currValue, nullptr); + hal_i2c_end_transmission(config_.i2c_if, true, nullptr); return SYSTEM_ERROR_NONE; } int Am18x5::writeContinuousRegisters(const Am18x5Register start_reg, const uint8_t* buff, size_t len) const { - Am18x5Lock lock(); - hal_i2c_begin_transmission(wire_, address_, nullptr); - hal_i2c_write(wire_, static_cast(start_reg), nullptr); + Am18x5Lock lock; + hal_i2c_begin_transmission(config_.i2c_if, config_.i2c_addr, nullptr); + hal_i2c_write(config_.i2c_if, static_cast(start_reg), nullptr); for (size_t i = 0; i < len; i++) { - hal_i2c_write(wire_, buff[i], nullptr); + hal_i2c_write(config_.i2c_if, buff[i], nullptr); } - hal_i2c_end_transmission(wire_, true, nullptr); + hal_i2c_end_transmission(config_.i2c_if, true, nullptr); return len; } int Am18x5::readRegister(const Am18x5Register reg, uint8_t* const val, bool bcd, uint8_t mask, uint8_t shift) const { - Am18x5Lock lock(); - hal_i2c_begin_transmission(wire_, address_, nullptr); - hal_i2c_write(wire_, static_cast(reg), nullptr); - hal_i2c_end_transmission(wire_, false, nullptr); - if (hal_i2c_request(wire_, address_, 1, true, nullptr) == 0) { + Am18x5Lock lock; + hal_i2c_begin_transmission(config_.i2c_if, config_.i2c_addr, nullptr); + hal_i2c_write(config_.i2c_if, static_cast(reg), nullptr); + hal_i2c_end_transmission(config_.i2c_if, false, nullptr); + if (hal_i2c_request(config_.i2c_if, config_.i2c_addr, 1, true, nullptr) == 0) { return SYSTEM_ERROR_INTERNAL; } - *val = hal_i2c_read(wire_, nullptr); + *val = hal_i2c_read(config_.i2c_if, nullptr); *val &= mask; *val >>= shift; if (bcd) { @@ -560,20 +614,20 @@ int Am18x5::readRegister(const Am18x5Register reg, uint8_t* const val, bool bcd, } int Am18x5::readContinuousRegisters(const Am18x5Register start_reg, uint8_t* buff, size_t len) const { - Am18x5Lock lock(); - hal_i2c_begin_transmission(wire_, address_, nullptr); - hal_i2c_write(wire_, static_cast(start_reg), nullptr); - hal_i2c_end_transmission(wire_, false, nullptr); - if (hal_i2c_request(wire_, address_, len, true, nullptr) == 0) { + Am18x5Lock lock; + hal_i2c_begin_transmission(config_.i2c_if, config_.i2c_addr, nullptr); + hal_i2c_write(config_.i2c_if, static_cast(start_reg), nullptr); + hal_i2c_end_transmission(config_.i2c_if, false, nullptr); + if (hal_i2c_request(config_.i2c_if, config_.i2c_addr, len, true, nullptr) == 0) { return SYSTEM_ERROR_INTERNAL; } - int32_t size = hal_i2c_available(wire_, nullptr); + int32_t size = hal_i2c_available(config_.i2c_if, nullptr); if (size <= 0) { return size; } size = std::min((size_t)size, len); for (int32_t i = 0; i < size; i++) { - buff[i] = hal_i2c_read(wire_, nullptr); + buff[i] = hal_i2c_read(config_.i2c_if, nullptr); } return size; } @@ -590,7 +644,7 @@ os_thread_return_t Am18x5::exRtcInterruptHandleThread(void* param) { while(!instance->exRtcWorkerThreadExit_) { os_semaphore_take(instance->exRtcWorkerSemaphore_, CONCURRENT_WAIT_FOREVER, false); { - Am18x5Lock lock(); + Am18x5Lock lock; uint8_t alm = 0; if (instance->readRegister(Am18x5Register::STATUS, &alm, false, STATUS_ALM_MASK) != SYSTEM_ERROR_NONE) { diff --git a/hal/src/tracker/am18x5.h b/hal/shared/am18x5.h similarity index 96% rename from hal/src/tracker/am18x5.h rename to hal/shared/am18x5.h index 80147966bd..376eadb5de 100644 --- a/hal/src/tracker/am18x5.h +++ b/hal/shared/am18x5.h @@ -26,6 +26,7 @@ #include "static_recursive_mutex.h" #include "concurrent_hal.h" #include "i2c_hal.h" +#include "exrtc_hal.h" namespace particle { @@ -127,7 +128,7 @@ class Am18x5 { public: typedef void (*AlarmHandler)(void* context); - int begin(); + int begin(const hal_exrtc_config_t* config); int end(); int sync(); @@ -146,7 +147,7 @@ class Am18x5 { // If multiple wakeup sources are configured, sleep mode exits on one wakeup source satisfied. int sleep(uint8_t ticks, Am18x5TimerFrequency frequency) const; - int getPartNumber(uint16_t* id) const; + int getPartNumber(uint16_t* id, bool detect = false) const; /* * The XT oscillator calibration value is determined by the following process: @@ -176,6 +177,9 @@ class Am18x5 { Am18x5(); ~Am18x5(); + void dumpRegisters() const; + int setPsw(bool val) const; // This is dangerous, make it private for now! + int setHundredths(uint8_t hundredths) const; int setSeconds(uint8_t seconds) const; int setMinutes(uint8_t minutes) const; @@ -206,14 +210,14 @@ class Am18x5 { static constexpr uint16_t PART_NUMBER = 0x1805; bool initialized_; - uint8_t address_; - hal_i2c_interface_t wire_; + bool detected_; uint8_t alarmYear_; AlarmHandler alarmHandler_; void* alarmHandlerContext_; os_thread_t exRtcWorkerThread_; os_queue_t exRtcWorkerSemaphore_; bool exRtcWorkerThreadExit_; + hal_exrtc_config_t config_; }; // class Am18x5 diff --git a/hal/src/tracker/am18x5_defines.h b/hal/shared/am18x5_defines.h similarity index 93% rename from hal/src/tracker/am18x5_defines.h rename to hal/shared/am18x5_defines.h index ac5a02c213..9504137c82 100644 --- a/hal/src/tracker/am18x5_defines.h +++ b/hal/shared/am18x5_defines.h @@ -54,9 +54,11 @@ // Control 1 Bits Mask #define CONTROL1_STOP_MASK 0x80 +#define CONTROL1_STOP_SHIFT (7) #define CONTROL1_1224_MASK 0x40 #define CONTROL1_1224_SHIFT (6) #define CONTROL1_OUTB_MASK 0x20 +#define CONTROL1_OUTB_SHIFT (5) #define CONTROL1_OUT_MASK 0x10 #define CONTROL1_RSP_MASK 0x08 #define CONTROL1_ARST_MASK 0x04 @@ -97,6 +99,7 @@ #define SLEEP_CONTROL_SLRES_MASK 0x40 // When 1, assert nRST low when the Power Control SM is in the SLEEP state. #define SLEEP_CONTROL_EX2P_MASK 0x20 // When 1, the external interrupt XT2 will trigger on a rising edge of the WDI pin. #define SLEEP_CONTROL_EX1P_MASK 0x10 // When 1, the external interrupt XT1 will trigger on a rising edge of the EXTI pin. +#define SLEEP_CONTROL_EX1P_SHIFT (4) #define SLEEP_CONTROL_SLST_MASK 0x08 // Set when the AM18X5 enters Sleep Mode #define SLEEP_CONTROL_SLTO_MASK 0x07 // The number of 7.8 ms periods after SLP is set until the Power Control SM goes into the SLEEP state. @@ -125,7 +128,9 @@ #define OSC_CONTROL_AOS_MASK 0x10 #define OSC_CONTROL_AOS_SHIFT (4) #define OSC_CONTROL_FOS_MASK 0x08 +#define OSC_CONTROL_FOS_SHIFT (3) #define OSC_CONTROL_PWGT_MASK 0x04 +#define OSC_CONTROL_PWGT_SHIFT (2) #define OSC_CONTROL_OFIE_MASK 0x02 #define OSC_CONTROL_ACIE_MASK 0x01 @@ -133,6 +138,7 @@ #define OSC_STATUS_XTCAL_MASK 0xC0 #define OSC_STATUS_XTCAL_SHIFT (6) #define OSC_STATUS_LKO2_MASK 0x20 +#define OSC_STATUS_LKO2_SHIFT (5) #define OSC_STATUS_OMODE_MASK 0x10 #define OSC_STATUS_OF_MASK 0x02 #define OSC_STATUS_ACF_MASK 0x01 @@ -163,6 +169,11 @@ #define OUTPUT_CTRL_O3EN_MASK 0x02 #define OUTPUT_CTRL_O1EN_MASK 0x01 +// Configuration Keys +#define CONFIG_KEY_SOFTWARE_RESET 0x3C +#define CONFIG_KEY_PRIMARY 0x9D +#define CONFIG_KEY_OSC_CONTROL 0xA1 + #endif // HAL_PLATFORM_EXTERNAL_RTC #endif // AM18X5_DEFINES_H \ No newline at end of file diff --git a/hal/src/nRF52840/exrtc_hal.cpp b/hal/shared/exrtc_hal.cpp similarity index 97% rename from hal/src/nRF52840/exrtc_hal.cpp rename to hal/shared/exrtc_hal.cpp index 7d35333b12..0fd74c15a7 100644 --- a/hal/src/nRF52840/exrtc_hal.cpp +++ b/hal/shared/exrtc_hal.cpp @@ -33,9 +33,8 @@ const auto UNIX_TIME_201801010000 = 1514764800; // 2018/01/01 00:00:00 } // anonymous -int hal_exrtc_init(void* reserved) { - (void)Am18x5::getInstance(); - return 0; +int hal_exrtc_init(const hal_exrtc_config_t* config, void* reserved) { + return Am18x5::getInstance().begin(config); } int hal_exrtc_set_time(const struct timeval* tv, void* reserved) { diff --git a/hal/src/msom/hal_platform_config.h b/hal/src/msom/hal_platform_config.h index 5b7f20605b..6db846c5ba 100644 --- a/hal/src/msom/hal_platform_config.h +++ b/hal/src/msom/hal_platform_config.h @@ -22,6 +22,8 @@ #define HAL_PLATFORM_FUELGAUGE_MAX17043 (1) #define HAL_PLATFORM_FUELGAUGE_MAX17043_I2C (HAL_I2C_INTERFACE1) +#define HAL_PLATFORM_EXTERNAL_RTC (1) + #define HAL_PLATFORM_POWER_MANAGEMENT (1) #define HAL_PLATFORM_POWER_MANAGEMENT_OPTIONAL (1) diff --git a/hal/src/nRF52840/rtc_hal.cpp b/hal/src/nRF52840/rtc_hal.cpp index a07bc6c0d3..519c769ce1 100644 --- a/hal/src/nRF52840/rtc_hal.cpp +++ b/hal/src/nRF52840/rtc_hal.cpp @@ -70,7 +70,16 @@ uint64_t usUnixtimeFromTimeval(const struct timeval* tv) { void hal_rtc_init(void) { #if HAL_PLATFORM_EXTERNAL_RTC - hal_exrtc_init(nullptr); + hal_exrtc_config_t config = { + .version = HAL_EXRTC_CONFIG_VERSION, + .size = sizeof(hal_exrtc_config_t), + .wdi_pin = RTC_WDI, + .int_pin = RTC_INT, + .i2c_if = HAL_PLATFORM_EXTERNAL_RTC_I2C, + .i2c_addr = HAL_PLATFORM_EXTERNAL_RTC_I2C_ADDR, + .osc_cal_xt = HAL_PLATFORM_EXTERNAL_RTC_CAL_XT, + }; + hal_exrtc_init(&config, nullptr); struct timeval tv = {}; if (!hal_exrtc_get_time(&tv, nullptr)) { hal_rtc_set_time(&tv, nullptr); diff --git a/hal/src/rtl872x/exrtc_hal.cpp b/hal/src/rtl872x/exrtc_hal.cpp deleted file mode 100644 index 7d35333b12..0000000000 --- a/hal/src/rtl872x/exrtc_hal.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2020 Particle Industries, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#include "exrtc_hal.h" - -#if HAL_PLATFORM_EXTERNAL_RTC - -// #define LOG_CHECKED_ERRORS 1 - -#include "check.h" -#include "system_error.h" -#include "am18x5.h" - -using namespace particle; - -namespace { - -const auto UNIX_TIME_201801010000 = 1514764800; // 2018/01/01 00:00:00 - -} // anonymous - -int hal_exrtc_init(void* reserved) { - (void)Am18x5::getInstance(); - return 0; -} - -int hal_exrtc_set_time(const struct timeval* tv, void* reserved) { - return Am18x5::getInstance().setTime(tv); -} - -int hal_exrtc_get_time(struct timeval* tv, void* reserved) { - return Am18x5::getInstance().getTime(tv); -} - -int hal_exrtc_set_alarm(const struct timeval* tv, uint32_t flags, hal_exrtc_alarm_handler handler, void* context, void* reserved) { - CHECK_TRUE(tv, SYSTEM_ERROR_INVALID_ARGUMENT); - struct timeval alarm = *tv; - if (flags & HAL_RTC_ALARM_FLAG_IN) { - struct timeval now; - CHECK(hal_exrtc_get_time(&now, nullptr)); - timeradd(&now, tv, &alarm); - } - CHECK(Am18x5::getInstance().setAlarm(&alarm)); - CHECK(Am18x5::getInstance().enableAlarm(true, handler, context)); - - int res = CHECK(Am18x5::getInstance().getAlarm(&alarm)); - struct timeval now; - CHECK(hal_exrtc_get_time(&now, nullptr)); - // If alarm time is in the past and it hasn't fired - if (timercmp(&alarm, &now, <) && res == 0) { - return SYSTEM_ERROR_TIMEOUT; - } - return 0; -} - -int hal_exrtc_cancel_alarm(void* reserved) { - return Am18x5::getInstance().enableAlarm(false, nullptr, nullptr); -} - -bool hal_exrtc_time_is_valid(void* reserved) { - struct timeval tv; - if (!hal_exrtc_get_time(&tv, nullptr)) { - return tv.tv_sec > UNIX_TIME_201801010000; - } - return false; -} - -int hal_exrtc_enable_watchdog(system_tick_t ms, void* reserved) { - uint8_t value; // Maximum 31. - Am18x5WatchdogFrequency frequency; - if (ms < 1937) { // 31 * 1000 / 16 - frequency = Am18x5WatchdogFrequency::HZ_16; - value = ms * 16 / 1000; - } else if (ms <= 7750) { - frequency = Am18x5WatchdogFrequency::HZ_4; - value = ms * 4 / 1000; - } else if (ms <= 31000) { - frequency = Am18x5WatchdogFrequency::HZ_1; - value = ms / 1000; - } else if (ms <= 124000) { - frequency = Am18x5WatchdogFrequency::HZ_1_4; - value = ms / 4 / 1000; - } else { - return SYSTEM_ERROR_INVALID_ARGUMENT; - } - CHECK_TRUE(value > 0, SYSTEM_ERROR_INVALID_ARGUMENT); - return Am18x5::getInstance().enableWatchdog(value, frequency); -} - -int hal_exrtc_disable_watchdog(void* reserved) { - return Am18x5::getInstance().disableWatchdog(); -} - -int hal_exrtc_feed_watchdog(void* reserved) { - return Am18x5::getInstance().feedWatchdog(); -} - -int hal_exrtc_sleep_timer(system_tick_t ms, void* reserved) { - uint8_t ticks; - Am18x5TimerFrequency frequency; - if (ms <= 3984) { // 255 * 1000 / 64 - frequency = Am18x5TimerFrequency::HZ_64; - ticks = ms * 64 / 1000; - } else if (ms <= 255000) { - frequency = Am18x5TimerFrequency::HZ_1; - ticks = ms / 1000; - } else if (ms <= 15300000) { - frequency = Am18x5TimerFrequency::HZ_1_60; - ticks = ms / 60 / 1000; - } else { - // TODO: use alarm or watchdog as the wakeup source - return SYSTEM_ERROR_NOT_SUPPORTED; - } - CHECK_TRUE(ticks > 0, SYSTEM_ERROR_INVALID_ARGUMENT); - return Am18x5::getInstance().sleep(ticks, frequency); -} - -int hal_exrtc_calibrate_xt(int adjValue, void* reserved) { - return Am18x5::getInstance().xtOscillatorDigitalCalibration(adjValue); -} - -void hal_exrtc_get_watchdog_limits(system_tick_t* low, system_tick_t* high, void* reserved) { - if (low) { - *low = 63; // round(Am18x5WatchdogFrequency::HZ_16 * 1) - } - if (high) { - *high = 124000; // // round(Am18x5WatchdogFrequency::HZ_1_4 * 31) - } -} - -#endif // HAL_PLATFORM_EXTERNAL_RTC diff --git a/hal/src/rtl872x/rtc_hal.cpp b/hal/src/rtl872x/rtc_hal.cpp index e9021bc73d..7e02aa8632 100644 --- a/hal/src/rtl872x/rtc_hal.cpp +++ b/hal/src/rtl872x/rtc_hal.cpp @@ -29,11 +29,6 @@ extern "C" { #include "rtl8721d.h" } -#if HAL_PLATFORM_EXTERNAL_RTC -#include "exrtc_hal.h" -#endif - - namespace { const time_t UNIX_TIME_20180101000000 = 1514764800UL; // 2018/01/01 00:00:00 @@ -41,42 +36,6 @@ const time_t UNIX_TIME_20000101000000 = 946684800UL; // 2000/01/01 00:00:00 const int CFG_RTC_PRIORITY = 5; -#if HAL_PLATFORM_EXTERNAL_RTC -class ExternalRtc { -public: - ExternalRtc() = default; - ~ExternalRtc() = default; - - int init() { - return hal_exrtc_init(nullptr); - } - - int deinit() { - return SYSTEM_ERROR_NONE; - } - - int getTime(struct timeval* tv) { - return hal_exrtc_get_time(tv, nullptr); - } - - int setTime(const struct timeval* tv) { - return hal_exrtc_set_time(tv, nullptr); - } - - int setAlarm(const struct timeval* tv, uint32_t flags, hal_rtc_alarm_handler handler, void* context) { - return hal_exrtc_set_alarm(tv, flags, handler, context, nullptr); - } - - int cancelAlarm() { - return hal_exrtc_cancel_alarm(nullptr); - } - - bool isTimeValid() { - return hal_exrtc_time_is_valid(nullptr); - } -}; -#endif - class RealtekRtc { public: RealtekRtc() : @@ -328,11 +287,7 @@ class RealtekRtc { retained_system struct tm RealtekRtc::timeInfo_ = {}; -#if HAL_PLATFORM_EXTERNAL_RTC -ExternalRtc rtcInstance; -#else RealtekRtc rtcInstance; -#endif } // anonymous diff --git a/user/tests/app/ctub_plus_power_test/blank.cpp b/user/tests/app/ctub_plus_power_test/blank.cpp new file mode 100644 index 0000000000..70bed4ae3b --- /dev/null +++ b/user/tests/app/ctub_plus_power_test/blank.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2019 Particle Industries, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "application.h" +#include "bma400.h" +#include "exrtc_hal.h" + +SYSTEM_MODE(MANUAL); +SerialLogHandler l(115200, LOG_LEVEL_ALL); + +constexpr uint16_t DEFAULT_INPUT_CURRENT_LIMIT = 900; // 900mA +constexpr uint16_t DEFAULT_INPUT_VOLTAGE_LIMIT = 3880; // 3.88V +constexpr uint16_t DEFAULT_CHARGE_CURRENT = 896; // 896mA +constexpr uint16_t DEFAULT_TERMINATION_VOLTAGE = 4112; // 4.112V +constexpr uint8_t DEFAULT_SOC_18_BIT_PRECISION = 18; // 18 is default, but may be 18 or 19 when a custom model is loaded + +STARTUP( + SystemPowerConfiguration config = {}; + config.powerSourceMinVoltage(DEFAULT_INPUT_VOLTAGE_LIMIT) + .powerSourceMaxCurrent(DEFAULT_INPUT_CURRENT_LIMIT) + .batteryChargeCurrent(DEFAULT_CHARGE_CURRENT) + .batteryChargeVoltage(DEFAULT_TERMINATION_VOLTAGE) + .socBitPrecision(DEFAULT_SOC_18_BIT_PRECISION) + .auxiliaryPowerControlPin(PIN_INVALID) // No aux power control pin + .interruptPin(LOW_BAT_UC) // Use the default: LOW_BAT_UC + .feature(SystemPowerFeature::PMIC_DETECTION); + System.setPowerConfiguration(config); // Set the power configuration +); + +BMA400_INTF_RET_TYPE bmaReadFn(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, void *intf_ptr) { + uint8_t addr = *((uint8_t*)intf_ptr); + hal_i2c_begin_transmission(HAL_I2C_INTERFACE1, addr, nullptr); + hal_i2c_write(HAL_I2C_INTERFACE1, static_cast(reg_addr), nullptr); + hal_i2c_end_transmission(HAL_I2C_INTERFACE1, false, nullptr); + if (hal_i2c_request(HAL_I2C_INTERFACE1, addr, length, true, nullptr) != length) { + return BMA400_E_COM_FAIL; + } + for (uint32_t i = 0; i < length; ++i) { + reg_data[i] = hal_i2c_read(HAL_I2C_INTERFACE1, nullptr); + } + return BMA400_OK; +} + +BMA400_INTF_RET_TYPE bmaWriteFn(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, void *intf_ptr) { + uint8_t addr = *((uint8_t*)intf_ptr); + hal_i2c_begin_transmission(HAL_I2C_INTERFACE1, addr, nullptr); + hal_i2c_write(HAL_I2C_INTERFACE1, static_cast(reg_addr), nullptr); + for (size_t i = 0; i < length; i++) { + hal_i2c_write(HAL_I2C_INTERFACE1, reg_data[i], nullptr); + } + hal_i2c_end_transmission(HAL_I2C_INTERFACE1, true, nullptr); + return BMA400_OK; +} + +void bmaDelayUsFn(uint32_t period, void *intf_ptr) { + delayMicroseconds(period); // Use the delay function to wait for the specified period +} + +/* executes once at startup */ +void setup() { + delay(5000); // Wait for the system to stabilize + + // Power manager should have initialized the I2C interface + // Wire.begin(); + + uint8_t bmaAddr = 0x14; + bma400_dev dev = {}; + dev.intf = BMA400_I2C_INTF; // Use I2C interface + dev.intf_ptr = &bmaAddr; + dev.read = bmaReadFn; // Set the read function + dev.write = bmaWriteFn; // Set the write function + dev.delay_us = bmaDelayUsFn; // Set the delay function + if (bma400_init(&dev)) { + Log.error("BMA400 initialization failed"); + } else { + Log.info("BMA400 initialized successfully: %02X", dev.chip_id); + int8_t ret = bma400_set_power_mode(BMA400_MODE_NORMAL, &dev); // Set the power mode to normal + if (ret != BMA400_OK) { + Log.error("Failed to set BMA400 power mode: %d", ret); + } else { + Log.info("BMA400 power mode set to normal"); + bma400_sensor_conf conf = {}; + conf.type = BMA400_GEN1_INT; + conf.param.gen_int.gen_int_thres = 200; // 8mg per LSB. 0 - 255 + conf.param.gen_int.gen_int_dur = 1; + conf.param.gen_int.axes_sel = 0x07; // Enable all axes + conf.param.gen_int.data_src = BMA400_DATA_SRC_ACC_FILT1; + conf.param.gen_int.criterion_sel = BMA400_ACTIVITY_INT; // Activity interrupt + conf.param.gen_int.evaluate_axes = BMA400_ANY_AXES_INT; + conf.param.gen_int.ref_update = BMA400_UPDATE_EVERY_TIME; // Update reference values every time + conf.param.gen_int.hysteresis = BMA400_HYST_24_MG; + conf.param.gen_int.int_thres_ref_x = 100; // No reference threshold for x + conf.param.gen_int.int_thres_ref_y = 100; // No reference threshold for y + conf.param.gen_int.int_thres_ref_z = 100; // No reference threshold for z + conf.param.gen_int.int_chan = BMA400_INT_CHANNEL_1; // Map to interrupt channel 1 + ret = bma400_set_sensor_conf(&conf, 1, &dev); + if (ret != BMA400_OK) { + Log.error("Failed to set BMA400 sensor configuration: %d", ret); + } else { + Log.info("BMA400 sensor configuration set successfully"); + bma400_device_conf devConfig = {}; + devConfig.type = BMA400_INT_PIN_CONF; + devConfig.param.int_conf.int_chan = BMA400_INT_CHANNEL_1; // Map to interrupt channel 1 + devConfig.param.int_conf.pin_conf = BMA400_INT_PUSH_PULL_ACTIVE_0; + ret = bma400_set_device_conf(&devConfig, 1, &dev); + if (ret != BMA400_OK) { + Log.error("Failed to configure BMA400 interrupt: %d", ret); + } else { + Log.info("BMA400 interrupt configured successfully"); + bma400_int_enable enable = {}; + enable.type = BMA400_GEN1_INT_EN; + enable.conf = BMA400_ENABLE; // Enable the generic interrupt 1 + ret = bma400_enable_interrupt(&enable, 1, &dev); + if (ret != BMA400_OK) { + Log.error("Failed to enable BMA400 interrupt: %d", ret); + } else { + Log.info("BMA400 interrupt enabled"); + } + } + } + } + } + + hal_exrtc_config_t config = { + .version = HAL_EXRTC_CONFIG_VERSION, + .size = sizeof(hal_exrtc_config_t), + .wdi_pin = D7, + .int_pin = A7, + .i2c_if = HAL_I2C_INTERFACE1, + .i2c_addr = 0x69, + .osc_cal_xt = -45, + }; + hal_exrtc_init(&config, nullptr); + + struct timeval tv = {}; + hal_exrtc_get_time(&tv, nullptr); + Log.info("Current time: %ld", tv.tv_sec); + + tv.tv_sec = 1753916506; + Log.info("Set time: %ld", tv.tv_sec); + hal_exrtc_set_time(&tv, nullptr); + + delay(1000); + hal_exrtc_sleep_timer(30 * 1000, nullptr); + + // hal_exrtc_enable_watchdog(5000, nullptr); // Enable watchdog with 5 seconds timeout +} + +/* executes continuously after setup() runs */ +void loop() { + // hal_exrtc_feed_watchdog(nullptr); // Feed the watchdog to prevent reset + + delay(1000); // Sleep for 1 second + struct timeval tv = {}; + hal_exrtc_get_time(&tv, nullptr); + Log.info("Current time: %ld", tv.tv_sec); +} diff --git a/user/tests/app/ctub_plus_power_test/bma400.c b/user/tests/app/ctub_plus_power_test/bma400.c new file mode 100644 index 0000000000..71d7588aca --- /dev/null +++ b/user/tests/app/ctub_plus_power_test/bma400.c @@ -0,0 +1,3550 @@ +/** +* Copyright (c) 2024 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bma400.c +* @date 2024-05-10 +* @version v1.5.10 +* +*/ + +#include "bma400.h" + +/* + * @brief Accel self test diff xyz data structure + */ +struct bma400_selftest_delta_limit +{ + /* Accel X data */ + int32_t x; + + /* Accel Y data */ + int32_t y; + + /* Accel Z data */ + int32_t z; +}; + +/************************************************************************************/ +/*********************** Static function declarations *******************************/ +/************************************************************************************/ + +/* + * @brief This internal API is used to validate the device pointer for + * null conditions. + * + * @param[in] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t null_ptr_check(const struct bma400_dev *dev); + +/* + * @brief This internal API is used to set sensor configurations + * + * @param[in] data : Data to be mapped with interrupt + * @param[in] conf : Sensor configurations to be set + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_sensor_conf(uint8_t *data, const struct bma400_sensor_conf *conf, struct bma400_dev *dev); + +/* + * @brief This internal API is used to get sensor configurations + * + * @param[in] data : Data to be mapped with interrupt + * @param[in] conf : Sensor configurations to be set + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_sensor_conf(const uint8_t *data, struct bma400_sensor_conf *conf, struct bma400_dev *dev); + +/* + * @brief This internal API is used to set the accel configurations in sensor + * + * @param[in] accel_conf : Structure instance with accel configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_accel_conf(const struct bma400_acc_conf *accel_conf, struct bma400_dev *dev); + +/* + * @brief This API reads accel data along with sensor time + * + * @param[in] data_sel : Variable to select the data to be read + * @param[in,out] accel : Structure instance to store the accel data + * @param[in] dev : Structure instance of bma400_dev + * + * Assignable values for data_sel: + * - BMA400_DATA_ONLY + * - BMA400_DATA_SENSOR_TIME + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_accel_data(uint8_t data_sel, struct bma400_sensor_data *accel, struct bma400_dev *dev); + +/* + * @brief This API enables the auto-wakeup feature + * of the sensor using a timeout value + * + * @param[in] wakeup_conf : Structure instance of wakeup configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_autowakeup_timeout(const struct bma400_auto_wakeup_conf *wakeup_conf, struct bma400_dev *dev); + +/* + * @brief This API enables the auto-wakeup feature of the sensor + * + * @param[in] conf : Configuration value to enable/disable + * auto-wakeup interrupt + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_auto_wakeup(uint8_t conf, struct bma400_dev *dev); + +/* + * @brief This API sets the parameters for auto-wakeup feature + * of the sensor + * + * @param[in] wakeup_conf : Structure instance of wakeup configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_autowakeup_interrupt(const struct bma400_wakeup_conf *wakeup_conf, struct bma400_dev *dev); + +/* + * @brief This API sets the sensor to enter low power mode + * automatically based on the configurations + * + * @param[in] auto_lp_conf : Structure instance of auto-low power settings + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_auto_low_power(const struct bma400_auto_lp_conf *auto_lp_conf, struct bma400_dev *dev); + +/* + * @brief This API sets the tap setting parameters + * + * @param[in] tap_set : Structure instance of tap configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_tap_conf(const struct bma400_tap_conf *tap_set, struct bma400_dev *dev); + +/* + * @brief This API sets the parameters for activity change detection + * + * @param[in] act_ch_set : Structure instance of activity change + * configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_activity_change_conf(const struct bma400_act_ch_conf *act_ch_set, struct bma400_dev *dev); + +/* + * @brief This API sets the parameters for generic interrupt1 configuration + * + * @param[in] gen_int_set : Structure instance of generic interrupt + * configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_gen1_int(const struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev); + +/* + * @brief This API sets the parameters for generic interrupt2 configuration + * + * @param[in] gen_int_set : Structure instance of generic interrupt + * configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_gen2_int(const struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev); + +/* + * @brief This API sets the parameters for orientation interrupt + * + * @param[in] orient_conf : Structure instance of orient interrupt + * configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_orient_int(const struct bma400_orient_int_conf *orient_conf, struct bma400_dev *dev); + +/* + * @brief This internal API is used to get the accel configurations in sensor + * + * @param[in,out] accel_conf : Structure instance of basic + * accelerometer configuration + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_accel_conf(struct bma400_acc_conf *accel_conf, struct bma400_dev *dev); + +/* + * @brief This API gets the set sensor settings for auto-wakeup timeout feature + * + * @param[in,out] wakeup_conf : Structure instance of wake-up configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_autowakeup_timeout(struct bma400_auto_wakeup_conf *wakeup_conf, struct bma400_dev *dev); + +/* + * @brief This API gets the set sensor settings for + * auto-wakeup interrupt feature + * + * @param[in,out] wakeup_conf : Structure instance of wake-up configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_autowakeup_interrupt(struct bma400_wakeup_conf *wakeup_conf, struct bma400_dev *dev); + +/* + * @brief This API gets the sensor to get the auto-low + * power mode configuration settings + * + * @param[in,out] auto_lp_conf : Structure instance of low power + * configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_auto_low_power(struct bma400_auto_lp_conf *auto_lp_conf, struct bma400_dev *dev); + +/* + * @brief This API sets the tap setting parameters + * + * @param[in,out] tap_set : Structure instance of tap configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_tap_conf(struct bma400_tap_conf *tap_set, struct bma400_dev *dev); + +/* + * @brief This API gets the parameters for activity change detection + * + * @param[in,out] act_ch_set : Structure instance of activity + * change configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_activity_change_conf(struct bma400_act_ch_conf *act_ch_set, struct bma400_dev *dev); + +/* + * @brief This API gets the generic interrupt1 configuration + * + * @param[in,out] gen_int_set : Structure instance of generic + * interrupt configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_gen1_int(struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev); + +/* + * @brief This API gets the generic interrupt2 configuration + * + * @param[in,out] gen_int_set : Structure instance of generic + * interrupt configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_gen2_int(struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev); + +/* + * @brief This API gets the parameters for orientation interrupt + * + * @param[in,out] orient_conf : Structure instance of orient + * interrupt configurations + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_orient_int(struct bma400_orient_int_conf *orient_conf, struct bma400_dev *dev); + +/* + * @brief This API sets the selected interrupt to be mapped to + * the hardware interrupt pin of the sensor + * + * @param[in,out] data_array : Data array of interrupt pin configurations + * @param[in] int_enable : Interrupt selected for pin mapping + * @param[in] int_map : Interrupt channel to be mapped + * + * @return Nothing + */ +static void map_int_pin(uint8_t *data_array, uint8_t int_enable, enum bma400_int_chan int_map); + +/* + * @brief This API checks whether the interrupt is mapped to the INT pin1 + * or INT pin2 of the sensor + * + * @param[in] int_1_map : Variable to denote whether the interrupt is + * mapped to INT1 pin or not + * @param[in] int_2_map : Variable to denote whether the interrupt is + * mapped to INT2 pin or not + * @param[in,out] int_map : Interrupt channel which is mapped + * INT1/INT2/NONE/BOTH + * + * @return Nothing + */ +static void check_mapped_interrupts(uint8_t int_1_map, uint8_t int_2_map, enum bma400_int_chan *int_map); + +/* + * @brief This API gets the selected interrupt and its mapping to + * the hardware interrupt pin of the sensor + * + * @param[in,out] data_array : Data array of interrupt pin configurations + * @param[in] int_enable : Interrupt selected for pin mapping + * @param[out] int_map : Interrupt channel which is mapped + * + * @return Nothing + */ +static void get_int_pin_map(const uint8_t *data_array, uint8_t int_enable, enum bma400_int_chan *int_map); + +/* + * @brief This API is used to set the interrupt pin configurations + * + * @param[in] int_conf : Interrupt pin configuration + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_int_pin_conf(struct bma400_int_pin_conf int_conf, struct bma400_dev *dev); + +/* + * @brief This API is used to set the interrupt pin configurations + * + * @param[in,out] int_conf : Interrupt pin configuration + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_int_pin_conf(struct bma400_int_pin_conf *int_conf, struct bma400_dev *dev); + +/* + * @brief This API is used to set the FIFO configurations + * + * @param[in,out] fifo_conf : Structure instance containing the FIFO + * configuration set in the sensor + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t set_fifo_conf(const struct bma400_fifo_conf *fifo_conf, struct bma400_dev *dev); + +/* + * @brief This API is used to get the FIFO configurations + * + * @param[in,out] fifo_conf : Structure instance containing the FIFO + * configuration set in the sensor + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t get_fifo_conf(struct bma400_fifo_conf *fifo_conf, struct bma400_dev *dev); + +/* + * @brief This API is used to get the number of bytes filled in FIFO + * + * @param[in,out] fifo_byte_cnt : Number of bytes in the FIFO buffer + * actually filled by the sensor + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t get_fifo_length(uint16_t *fifo_byte_cnt, struct bma400_dev *dev); + +/* + * @brief This API is used to read the FIFO of BMA400 + * + * @param[in,out] fifo : Pointer to the fifo structure. + * + * @param[in] dev : Structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t read_fifo(struct bma400_fifo_data *fifo, struct bma400_dev *dev); + +/* + * @brief This API is used to unpack the accelerometer frames from the FIFO + * + * @param[in,out] fifo : Pointer to the fifo structure. + * @param[in,out] accel_data : Structure instance to store the accel data + * @param[in,out] frame_count : Number of frames requested by user as input + * Number of frames actually parsed as output + * @param[in] dev : Structure instance of bma400_dev + * + * @return Nothing + */ +static void unpack_accel_frame(struct bma400_fifo_data *fifo, + struct bma400_fifo_sensor_data *accel_data, + uint16_t *frame_count, + const struct bma400_dev *dev); + +/* + * @brief This API is used to check for a frame availability in FIFO + * + * @param[in,out] fifo : Pointer to the fifo structure. + * @param[in,out] frame_available : Variable to denote availability of a frame + * @param[in] accel_width : Variable to denote 12/8 bit accel data + * @param[in] data_en : Data enabled in FIFO + * @param[in,out] data_index : Index of the currently parsed FIFO data + * + * @return Nothing + */ +static void check_frame_available(const struct bma400_fifo_data *fifo, + uint8_t *frame_available, + uint8_t accel_width, + uint8_t data_en, + uint16_t *data_index); + +/* + * @brief This API is used to unpack the accelerometer xyz data from the FIFO + * and store it in the user defined buffer + * + * @param[in,out] fifo : Pointer to the fifo structure. + * @param[in,out] accel_data : Structure instance to store the accel data + * @param[in,out] data_index : Index of the currently parsed FIFO data + * @param[in] accel_width : Variable to denote 12/8 bit accel data + * @param[in] frame_header : Variable to get the data enabled + * + * @return Nothing + */ +static void unpack_accel(const struct bma400_fifo_data *fifo, + struct bma400_fifo_sensor_data *accel_data, + uint16_t *data_index, + uint8_t accel_width, + uint8_t frame_header); + +/* + * @brief This API is used to parse and store the sensor time from the + * FIFO data in the structure instance dev + * + * @param[in,out] fifo : Pointer to the fifo structure. + * @param[in,out] data_index : Index of the FIFO data which has sensor time + * + * @return Nothing + */ +static void unpack_sensortime_frame(struct bma400_fifo_data *fifo, uint16_t *data_index); + +/* + * @brief This API validates the self test results + * + * @param[in] accel_pos : Structure pointer to store accel data + * for positive excitation + * @param[in] accel_neg : Structure pointer to store accel data + * for negative excitation + * + *@param[in] dev : structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +static int8_t validate_accel_self_test(const struct bma400_sensor_data *accel_pos, + const struct bma400_sensor_data *accel_neg); + +/* + * @brief This API performs self test with positive excitation + * + * @param[in] accel_pos : Structure pointer to store accel data + * for positive excitation + * @param[in] dev : structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval -ve value -> Error + */ +static int8_t positive_excited_accel(struct bma400_sensor_data *accel_pos, struct bma400_dev *dev); + +/* + * @brief This API performs self test with negative excitation + * + * @param[in] accel_neg : Structure pointer to store accel data + * for negative excitation + * @param[in] dev : structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval -ve value -> Error + */ +static int8_t negative_excited_accel(struct bma400_sensor_data *accel_neg, struct bma400_dev *dev); + +/* + * @brief This API performs the pre-requisites needed to perform the self test + * + * @param[in] dev : structure instance of bma400_dev + * + * @return Result of API execution status + * @retval zero -> Success + * @retval -ve value -> Error + */ +static int8_t enable_self_test(struct bma400_dev *dev); + +/************************************************************************************/ +/*********************** User function definitions **********************************/ +/************************************************************************************/ + +int8_t bma400_init(struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t chip_id = 0; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if (rslt == BMA400_OK) + { + /* Initial power-up time */ + dev->delay_us(5000, dev->intf_ptr); + + /* Assigning dummy byte value */ + if (dev->intf == BMA400_SPI_INTF) + { + /* Dummy Byte availability */ + dev->dummy_byte = 1; + + /* Dummy read of Chip-ID in SPI mode */ + rslt = bma400_get_regs(BMA400_REG_CHIP_ID, &chip_id, 1, dev); + } + else + { + dev->dummy_byte = 0; + } + + if (rslt == BMA400_OK) + { + /* Chip ID of the sensor is read */ + rslt = bma400_get_regs(BMA400_REG_CHIP_ID, &chip_id, 1, dev); + + /* Proceed if everything is fine until now */ + if (rslt == BMA400_OK) + { + /* Check for chip id validity */ + if (chip_id == BMA400_CHIP_ID) + { + /* Store the chip ID in dev structure */ + dev->chip_id = chip_id; + } + else + { + rslt = BMA400_E_DEV_NOT_FOUND; + } + } + } + } + + return rslt; +} + +int8_t bma400_set_regs(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t count; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (reg_data != NULL)) + { + /* Write the data to the reg_addr */ + + /* SPI write requires to set The MSB of reg_addr as 0 + * but in default the MSB is always 0 + */ + if (len == 1) + { + dev->intf_rslt = dev->write(reg_addr, reg_data, len, dev->intf_ptr); + if (dev->intf_rslt != BMA400_INTF_RET_SUCCESS) + { + /* Failure case */ + rslt = BMA400_E_COM_FAIL; + } + } + + /* Burst write is not allowed thus we split burst case write + * into single byte writes Thus user can write multiple bytes + * with ease + */ + if (len > 1) + { + for (count = 0; (count < len) && (rslt == BMA400_OK); count++) + { + dev->intf_rslt = dev->write(reg_addr, ®_data[count], 1, dev->intf_ptr); + reg_addr++; + if (dev->intf_rslt != BMA400_INTF_RET_SUCCESS) + { + /* Failure case */ + rslt = BMA400_E_COM_FAIL; + } + } + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bma400_dev *dev) +{ + int8_t rslt; + uint16_t index; + uint8_t temp_buff[BMA400_MAX_LEN]; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (reg_data != NULL)) + { + if (dev->intf != BMA400_I2C_INTF) + { + /* If interface selected is SPI */ + reg_addr = reg_addr | BMA400_SPI_RD_MASK; + } + + /* Read the data from the reg_addr */ + dev->intf_rslt = dev->read(reg_addr, temp_buff, (len + dev->dummy_byte), dev->intf_ptr); + if (dev->intf_rslt == BMA400_INTF_RET_SUCCESS) + { + for (index = 0; index < len; index++) + { + /* Parse the data read and store in "reg_data" + * buffer so that the dummy byte is removed + * and user will get only valid data + */ + reg_data[index] = temp_buff[index + dev->dummy_byte]; + } + } + else + { + /* Failure case */ + rslt = BMA400_E_COM_FAIL; + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_soft_reset(struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data = BMA400_SOFT_RESET_CMD; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMA400_OK) + { + /* Reset the device */ + rslt = bma400_set_regs(BMA400_REG_COMMAND, &data, 1, dev); + dev->delay_us(BMA400_DELAY_US_SOFT_RESET, dev->intf_ptr); + if ((rslt == BMA400_OK) && (dev->intf == BMA400_SPI_INTF)) + { + /* Dummy read of 0x7F register to enable SPI Interface + * if SPI is used + */ + rslt = bma400_get_regs(0x7F, &data, 1, dev); + } + } + + return rslt; +} + +int8_t bma400_set_power_mode(uint8_t power_mode, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data = 0; + + rslt = null_ptr_check(dev); + if (rslt == BMA400_OK) + { + rslt = bma400_get_regs(BMA400_REG_ACCEL_CONFIG_0, ®_data, 1, dev); + } + + if (rslt == BMA400_OK) + { + reg_data = BMA400_SET_BITS_POS_0(reg_data, BMA400_POWER_MODE, power_mode); + + /* Set the power mode of sensor */ + rslt = bma400_set_regs(BMA400_REG_ACCEL_CONFIG_0, ®_data, 1, dev); + if (power_mode == BMA400_MODE_LOW_POWER) + { + /* A delay of 1/ODR is required to switch power modes + * Low power mode has 25Hz frequency and hence it needs + * 40ms delay to enter low power mode + */ + dev->delay_us(40000, dev->intf_ptr); + } + else + { + dev->delay_us(10000, dev->intf_ptr); /* TBC */ + } + } + + return rslt; +} + +int8_t bma400_get_power_mode(uint8_t *power_mode, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (power_mode != NULL)) + { + rslt = bma400_get_regs(BMA400_REG_STATUS, ®_data, 1, dev); + *power_mode = BMA400_GET_BITS(reg_data, BMA400_POWER_MODE_STATUS); + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_accel_data(uint8_t data_sel, struct bma400_sensor_data *accel, struct bma400_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (accel != NULL)) + { + /* Read and store the accel data */ + rslt = get_accel_data(data_sel, accel, dev); + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_set_sensor_conf(const struct bma400_sensor_conf *conf, uint16_t n_sett, struct bma400_dev *dev) +{ + int8_t rslt; + uint16_t idx = 0; + uint8_t data_array[3] = { 0 }; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (conf != NULL)) + { + /* Read the interrupt pin mapping configurations */ + rslt = bma400_get_regs(BMA400_REG_INT_MAP, data_array, 3, dev); + if (rslt == BMA400_OK) + { + for (idx = 0; (idx < n_sett) && (rslt == BMA400_OK); idx++) + { + rslt = set_sensor_conf(data_array, conf + idx, dev); + } + + if (rslt == BMA400_OK) + { + /* Set the interrupt pin mapping configurations */ + rslt = bma400_set_regs(BMA400_REG_INT_MAP, data_array, 3, dev); + } + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_sensor_conf(struct bma400_sensor_conf *conf, uint16_t n_sett, struct bma400_dev *dev) +{ + int8_t rslt; + uint16_t idx; + uint8_t data_array[3] = { 0 }; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + if ((rslt == BMA400_OK) && (conf != NULL)) + { + /* Read the interrupt pin mapping configurations */ + rslt = bma400_get_regs(BMA400_REG_INT_MAP, data_array, 3, dev); + + for (idx = 0; (idx < n_sett) && (rslt == BMA400_OK); idx++) + { + rslt = get_sensor_conf(data_array, conf + idx, dev); + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_set_device_conf(const struct bma400_device_conf *conf, uint8_t n_sett, struct bma400_dev *dev) +{ + int8_t rslt; + uint16_t idx; + uint8_t data_array[3] = { 0 }; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + if ((rslt == BMA400_OK) && (conf != NULL)) + { + + /* Read the interrupt pin mapping configurations */ + rslt = bma400_get_regs(BMA400_REG_INT_MAP, data_array, 3, dev); + + for (idx = 0; (idx < n_sett) && (rslt == BMA400_OK); idx++) + { + switch (conf[idx].type) + { + case BMA400_AUTOWAKEUP_TIMEOUT: + rslt = set_autowakeup_timeout(&conf[idx].param.auto_wakeup, dev); + break; + case BMA400_AUTOWAKEUP_INT: + rslt = set_autowakeup_interrupt(&conf[idx].param.wakeup, dev); + if (rslt == BMA400_OK) + { + /* Interrupt pin mapping */ + map_int_pin(data_array, BMA400_WAKEUP_INT_MAP, conf[idx].param.wakeup.int_chan); + } + + break; + case BMA400_AUTO_LOW_POWER: + rslt = set_auto_low_power(&conf[idx].param.auto_lp, dev); + break; + case BMA400_INT_PIN_CONF: + rslt = set_int_pin_conf(conf[idx].param.int_conf, dev); + break; + case BMA400_INT_OVERRUN_CONF: + + /* Interrupt pin mapping */ + map_int_pin(data_array, BMA400_INT_OVERRUN_MAP, conf[idx].param.overrun_int.int_chan); + break; + case BMA400_FIFO_CONF: + rslt = set_fifo_conf(&conf[idx].param.fifo_conf, dev); + if (rslt == BMA400_OK) + { + /* Interrupt pin mapping */ + map_int_pin(data_array, BMA400_FIFO_WM_INT_MAP, conf[idx].param.fifo_conf.fifo_wm_channel); + map_int_pin(data_array, BMA400_FIFO_FULL_INT_MAP, conf[idx].param.fifo_conf.fifo_full_channel); + } + + break; + default: + rslt = BMA400_E_INVALID_CONFIG; + } + } + + if (rslt == BMA400_OK) + { + /* Set the interrupt pin mapping configurations */ + rslt = bma400_set_regs(BMA400_REG_INT_MAP, data_array, 3, dev); + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_device_conf(struct bma400_device_conf *conf, uint8_t n_sett, struct bma400_dev *dev) +{ + int8_t rslt; + uint16_t idx = 0; + uint8_t data_array[3] = { 0 }; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (conf != NULL)) + { + /* Read the interrupt pin mapping configurations */ + rslt = bma400_get_regs(BMA400_REG_INT_MAP, data_array, 3, dev); + + for (idx = 0; (idx < n_sett) && (rslt == BMA400_OK); idx++) + { + switch (conf[idx].type) + { + case BMA400_AUTOWAKEUP_TIMEOUT: + rslt = get_autowakeup_timeout(&conf[idx].param.auto_wakeup, dev); + break; + case BMA400_AUTOWAKEUP_INT: + rslt = get_autowakeup_interrupt(&conf[idx].param.wakeup, dev); + if (rslt == BMA400_OK) + { + /* Get the INT pin mapping */ + get_int_pin_map(data_array, BMA400_WAKEUP_INT_MAP, &conf[idx].param.wakeup.int_chan); + } + + break; + case BMA400_AUTO_LOW_POWER: + rslt = get_auto_low_power(&conf[idx].param.auto_lp, dev); + break; + case BMA400_INT_PIN_CONF: + rslt = get_int_pin_conf(&conf[idx].param.int_conf, dev); + break; + case BMA400_INT_OVERRUN_CONF: + get_int_pin_map(data_array, BMA400_INT_OVERRUN_MAP, &conf[idx].param.overrun_int.int_chan); + break; + case BMA400_FIFO_CONF: + rslt = get_fifo_conf(&conf[idx].param.fifo_conf, dev); + if (rslt == BMA400_OK) + { + get_int_pin_map(data_array, + BMA400_FIFO_FULL_INT_MAP, + &conf[idx].param.fifo_conf.fifo_full_channel); + get_int_pin_map(data_array, BMA400_FIFO_WM_INT_MAP, &conf[idx].param.fifo_conf.fifo_wm_channel); + } + + break; + } + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_interrupt_status(uint16_t *int_status, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data[3]; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (int_status != NULL)) + { + /* Read the interrupt status registers */ + rslt = bma400_get_regs(BMA400_REG_INT_STAT0, reg_data, 3, dev); + reg_data[1] = BMA400_SET_BITS(reg_data[1], BMA400_INT_STATUS, reg_data[2]); + + /* Concatenate the interrupt status to the output */ + *int_status = ((uint16_t)reg_data[1] << 8) | reg_data[0]; + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_set_step_counter_param(const uint8_t *sccr_conf, struct bma400_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (sccr_conf != NULL)) + { + /* Set the step counter parameters in the sensor */ + rslt = bma400_set_regs(0x59, sccr_conf, 24, dev); + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_steps_counted(uint32_t *step_count, uint8_t *activity_data, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[4]; + + uint32_t step_count_0 = 0; + uint32_t step_count_1 = 0; + uint32_t step_count_2 = 0; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (step_count != NULL) && (activity_data != NULL)) + { + rslt = bma400_get_regs(BMA400_REG_STEP_CNT_0, data_array, 4, dev); + + step_count_0 = (uint32_t)data_array[0]; + step_count_1 = (uint32_t)data_array[1] << 8; + step_count_2 = (uint32_t)data_array[2] << 16; + *step_count = step_count_0 | step_count_1 | step_count_2; + + *activity_data = data_array[3]; + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_temperature_data(int16_t *temperature_data, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + /* Check for null pointer in the device structure*/ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (temperature_data != NULL)) + { + rslt = bma400_get_regs(BMA400_REG_TEMP_DATA, ®_data, 1, dev); + + /* Temperature data calculations */ + *temperature_data = (int16_t)(((int8_t)reg_data) * 5) + 230; + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_interrupts_enabled(struct bma400_int_enable *int_select, uint8_t n_sett, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t idx = 0; + uint8_t reg_data[2]; + uint8_t wkup_int; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (int_select != NULL)) + { + rslt = bma400_get_regs(BMA400_REG_INT_CONF_0, reg_data, 2, dev); + if (rslt == BMA400_OK) + { + for (idx = 0; idx < n_sett; idx++) + { + /* Read the enable/disable of interrupts + * based on user selection + */ + switch (int_select[idx].type) + { + case BMA400_DRDY_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[0], BMA400_EN_DRDY); + break; + case BMA400_FIFO_WM_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[0], BMA400_EN_FIFO_WM); + break; + case BMA400_FIFO_FULL_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[0], BMA400_EN_FIFO_FULL); + break; + case BMA400_GEN2_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[0], BMA400_EN_GEN2); + break; + case BMA400_GEN1_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[0], BMA400_EN_GEN1); + break; + case BMA400_ORIENT_CHANGE_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[0], BMA400_EN_ORIENT_CH); + break; + case BMA400_LATCH_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[1], BMA400_EN_LATCH); + break; + case BMA400_ACTIVITY_CHANGE_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[1], BMA400_EN_ACTCH); + break; + case BMA400_DOUBLE_TAP_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[1], BMA400_EN_D_TAP); + break; + case BMA400_SINGLE_TAP_INT_EN: + int_select[idx].conf = BMA400_GET_BITS(reg_data[1], BMA400_EN_S_TAP); + break; + case BMA400_STEP_COUNTER_INT_EN: + int_select[idx].conf = BMA400_GET_BITS_POS_0(reg_data[1], BMA400_EN_STEP_INT); + break; + case BMA400_AUTO_WAKEUP_EN: + rslt = bma400_get_regs(BMA400_REG_AUTOWAKEUP_1, &wkup_int, 1, dev); + if (rslt == BMA400_OK) + { + /* Auto-Wakeup int status */ + int_select[idx].conf = BMA400_GET_BITS(wkup_int, BMA400_WAKEUP_INTERRUPT); + } + + break; + default: + rslt = BMA400_E_INVALID_CONFIG; + break; + } + } + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_enable_interrupt(const struct bma400_int_enable *int_select, uint8_t n_sett, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t conf, idx = 0; + uint8_t reg_data[2]; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (int_select != NULL)) + { + rslt = bma400_get_regs(BMA400_REG_INT_CONF_0, reg_data, 2, dev); + if (rslt == BMA400_OK) + { + for (idx = 0; idx < n_sett; idx++) + { + conf = int_select[idx].conf; + + /* Enable the interrupt based on user selection */ + switch (int_select[idx].type) + { + case BMA400_DRDY_INT_EN: + reg_data[0] = BMA400_SET_BITS(reg_data[0], BMA400_EN_DRDY, conf); + break; + case BMA400_FIFO_WM_INT_EN: + reg_data[0] = BMA400_SET_BITS(reg_data[0], BMA400_EN_FIFO_WM, conf); + break; + case BMA400_FIFO_FULL_INT_EN: + reg_data[0] = BMA400_SET_BITS(reg_data[0], BMA400_EN_FIFO_FULL, conf); + break; + case BMA400_GEN2_INT_EN: + reg_data[0] = BMA400_SET_BITS(reg_data[0], BMA400_EN_GEN2, conf); + break; + case BMA400_GEN1_INT_EN: + reg_data[0] = BMA400_SET_BITS(reg_data[0], BMA400_EN_GEN1, conf); + break; + case BMA400_ORIENT_CHANGE_INT_EN: + reg_data[0] = BMA400_SET_BITS(reg_data[0], BMA400_EN_ORIENT_CH, conf); + break; + case BMA400_LATCH_INT_EN: + reg_data[1] = BMA400_SET_BITS(reg_data[1], BMA400_EN_LATCH, conf); + break; + case BMA400_ACTIVITY_CHANGE_INT_EN: + reg_data[1] = BMA400_SET_BITS(reg_data[1], BMA400_EN_ACTCH, conf); + break; + case BMA400_DOUBLE_TAP_INT_EN: + reg_data[1] = BMA400_SET_BITS(reg_data[1], BMA400_EN_D_TAP, conf); + break; + case BMA400_SINGLE_TAP_INT_EN: + reg_data[1] = BMA400_SET_BITS(reg_data[1], BMA400_EN_S_TAP, conf); + break; + case BMA400_STEP_COUNTER_INT_EN: + reg_data[1] = BMA400_SET_BITS_POS_0(reg_data[1], BMA400_EN_STEP_INT, conf); + break; + case BMA400_AUTO_WAKEUP_EN: + rslt = set_auto_wakeup(conf, dev); + break; + default: + rslt = BMA400_E_INVALID_CONFIG; + break; + } + } + + if (rslt == BMA400_OK) + { + /* Set the configurations in the sensor */ + rslt = bma400_set_regs(BMA400_REG_INT_CONF_0, reg_data, 2, dev); + } + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_get_fifo_data(struct bma400_fifo_data *fifo, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data; + uint16_t fifo_byte_cnt = 0; + uint16_t user_fifo_len = 0; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (fifo != NULL)) + { + /* Resetting the FIFO data byte index */ + fifo->accel_byte_start_idx = 0; + + /* Reading the FIFO length */ + rslt = get_fifo_length(&fifo_byte_cnt, dev); + if (rslt == BMA400_OK) + { + /* Get the FIFO configurations + * from the sensor */ + rslt = bma400_get_regs(BMA400_REG_FIFO_CONFIG_0, &data, 1, dev); + if (rslt == BMA400_OK) + { + /* Get the data from FIFO_CONFIG0 register */ + fifo->fifo_8_bit_en = BMA400_GET_BITS(data, BMA400_FIFO_8_BIT_EN); + fifo->fifo_data_enable = BMA400_GET_BITS(data, BMA400_FIFO_AXES_EN); + fifo->fifo_time_enable = BMA400_GET_BITS(data, BMA400_FIFO_TIME_EN); + fifo->fifo_sensor_time = 0; + user_fifo_len = fifo->length; + if (fifo->length > fifo_byte_cnt) + { + /* Handling case where user requests + * more data than available in FIFO + */ + fifo->length = fifo_byte_cnt; + } + + /* Reading extra bytes as per the macro + * "BMA400_FIFO_BYTES_OVERREAD" + * when FIFO time is enabled + */ + if ((fifo->fifo_time_enable == BMA400_ENABLE) && + (fifo_byte_cnt + BMA400_FIFO_BYTES_OVERREAD <= user_fifo_len)) + { + /* Handling sensor time availability*/ + fifo->length = fifo->length + BMA400_FIFO_BYTES_OVERREAD; + } + + /* Read the FIFO data */ + rslt = read_fifo(fifo, dev); + } + } + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_extract_accel(struct bma400_fifo_data *fifo, + struct bma400_fifo_sensor_data *accel_data, + uint16_t *frame_count, + const struct bma400_dev *dev) +{ + int8_t rslt; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if ((rslt == BMA400_OK) && (fifo != NULL) && (accel_data != NULL) && (frame_count != NULL)) + { + /* Parse the FIFO data */ + unpack_accel_frame(fifo, accel_data, frame_count, dev); + } + else + { + rslt = BMA400_E_NULL_PTR; + } + + return rslt; +} + +int8_t bma400_set_fifo_flush(struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data = BMA400_FIFO_FLUSH_CMD; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if (rslt == BMA400_OK) + { + /* FIFO flush command is set */ + rslt = bma400_set_regs(BMA400_REG_COMMAND, &data, 1, dev); + } + + return rslt; +} + +int8_t bma400_perform_self_test(struct bma400_dev *dev) +{ + int8_t rslt; + int8_t self_test_rslt = 0; + struct bma400_sensor_data accel_pos, accel_neg; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if (rslt == BMA400_OK) + { + /* pre-requisites for self test*/ + rslt = enable_self_test(dev); + if (rslt == BMA400_OK) + { + rslt = positive_excited_accel(&accel_pos, dev); + if (rslt == BMA400_OK) + { + rslt = negative_excited_accel(&accel_neg, dev); + if (rslt == BMA400_OK) + { + /* Validate the self test result */ + rslt = validate_accel_self_test(&accel_pos, &accel_neg); + } + } + } + } + + /* Check to ensure bus error does not occur */ + if (rslt <= BMA400_OK) + { + /* Store the status of self test result */ + self_test_rslt = rslt; + + /* Perform soft reset */ + rslt = bma400_soft_reset(dev); + } + + /* Check to ensure bus operations are success */ + if (rslt == BMA400_OK) + { + /* Restore self_test_rslt as return value */ + rslt = self_test_rslt; + } + + return rslt; +} + +/************************************************************************************/ +/*********************** Static function definitions **********************************/ +/************************************************************************************/ + +static int8_t null_ptr_check(const struct bma400_dev *dev) +{ + int8_t rslt; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->intf_ptr == NULL)) + { + /* Device structure pointer is not valid */ + rslt = BMA400_E_NULL_PTR; + } + else + { + /* Device structure is fine */ + rslt = BMA400_OK; + } + + return rslt; +} + +static int8_t set_sensor_conf(uint8_t *data, const struct bma400_sensor_conf *conf, struct bma400_dev *dev) +{ + int8_t rslt = BMA400_E_INVALID_CONFIG; + uint8_t int_enable = 0; + enum bma400_int_chan int_map = BMA400_UNMAP_INT_PIN; + + if (BMA400_ACCEL == conf->type) + { + /* Setting Accel configurations */ + rslt = set_accel_conf(&conf->param.accel, dev); + int_enable = BMA400_DATA_READY_INT_MAP; + int_map = conf->param.accel.int_chan; + } + + if (BMA400_TAP_INT == conf->type) + { + /* Setting tap configurations */ + rslt = set_tap_conf(&conf->param.tap, dev); + int_enable = BMA400_TAP_INT_MAP; + int_map = conf->param.tap.int_chan; + } + + if (BMA400_ACTIVITY_CHANGE_INT == conf->type) + { + /* Setting activity change configurations */ + rslt = set_activity_change_conf(&conf->param.act_ch, dev); + int_enable = BMA400_ACT_CH_INT_MAP; + int_map = conf->param.act_ch.int_chan; + } + + if (BMA400_GEN1_INT == conf->type) + { + /* Setting generic int 1 configurations */ + rslt = set_gen1_int(&conf->param.gen_int, dev); + int_enable = BMA400_GEN1_INT_MAP; + int_map = conf->param.gen_int.int_chan; + } + + if (BMA400_GEN2_INT == conf->type) + { + /* Setting generic int 2 configurations */ + rslt = set_gen2_int(&conf->param.gen_int, dev); + int_enable = BMA400_GEN2_INT_MAP; + int_map = conf->param.gen_int.int_chan; + } + + if (BMA400_ORIENT_CHANGE_INT == conf->type) + { + /* Setting orient int configurations */ + rslt = set_orient_int(&conf->param.orient, dev); + int_enable = BMA400_ORIENT_CH_INT_MAP; + int_map = conf->param.orient.int_chan; + } + + if (BMA400_STEP_COUNTER_INT == conf->type) + { + rslt = BMA400_OK; + int_enable = BMA400_STEP_INT_MAP; + int_map = conf->param.step_cnt.int_chan; + } + + if (rslt == BMA400_OK) + { + /* Int pin mapping settings */ + map_int_pin(data, int_enable, int_map); + } + + return rslt; +} + +static int8_t get_sensor_conf(const uint8_t *data, struct bma400_sensor_conf *conf, struct bma400_dev *dev) +{ + int8_t rslt = BMA400_E_INVALID_CONFIG; + uint8_t int_enable = 0; + enum bma400_int_chan int_map = BMA400_UNMAP_INT_PIN; + + if (BMA400_ACCEL == conf->type) + { + /* Get Accel configurations */ + rslt = get_accel_conf(&conf->param.accel, dev); + int_enable = BMA400_DATA_READY_INT_MAP; + int_map = conf->param.accel.int_chan; + } + + if (BMA400_TAP_INT == conf->type) + { + /* Get tap configurations */ + rslt = get_tap_conf(&conf->param.tap, dev); + int_enable = BMA400_TAP_INT_MAP; + int_map = conf->param.tap.int_chan; + } + + if (BMA400_ACTIVITY_CHANGE_INT == conf->type) + { + /* Get activity change configurations */ + rslt = get_activity_change_conf(&conf->param.act_ch, dev); + int_enable = BMA400_ACT_CH_INT_MAP; + int_map = conf->param.act_ch.int_chan; + } + + if (BMA400_GEN1_INT == conf->type) + { + /* Get generic int 1 configurations */ + rslt = get_gen1_int(&conf->param.gen_int, dev); + int_enable = BMA400_GEN1_INT_MAP; + int_map = conf->param.gen_int.int_chan; + } + + if (BMA400_GEN2_INT == conf->type) + { + /* Get generic int 2 configurations */ + rslt = get_gen2_int(&conf->param.gen_int, dev); + int_enable = BMA400_GEN2_INT_MAP; + int_map = conf->param.gen_int.int_chan; + } + + if (BMA400_ORIENT_CHANGE_INT == conf->type) + { + /* Get orient int configurations */ + rslt = get_orient_int(&conf->param.orient, dev); + int_enable = BMA400_ORIENT_CH_INT_MAP; + int_map = conf->param.orient.int_chan; + } + + if (BMA400_STEP_COUNTER_INT == conf->type) + { + rslt = BMA400_OK; + int_enable = BMA400_STEP_INT_MAP; + int_map = conf->param.step_cnt.int_chan; + } + + if (rslt == BMA400_OK) + { + /* Int pin mapping settings */ + get_int_pin_map(data, int_enable, &int_map); + } + + return rslt; +} + +static int8_t set_accel_conf(const struct bma400_acc_conf *accel_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[3] = { 0, 0, 0xE0 }; + + /* Update the accel configurations from the user structure + * accel_conf + */ + rslt = bma400_get_regs(BMA400_REG_ACCEL_CONFIG_0, data_array, 3, dev); + if (rslt == BMA400_OK) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_FILT_1_BW, accel_conf->filt1_bw); + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_OSR_LP, accel_conf->osr_lp); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_ACCEL_RANGE, accel_conf->range); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_OSR, accel_conf->osr); + data_array[1] = BMA400_SET_BITS_POS_0(data_array[1], BMA400_ACCEL_ODR, accel_conf->odr); + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_DATA_FILTER, accel_conf->data_src); + + /* Set the accel configurations in the sensor */ + rslt = bma400_set_regs(BMA400_REG_ACCEL_CONFIG_0, data_array, 3, dev); + } + + return rslt; +} + +static int8_t get_accel_conf(struct bma400_acc_conf *accel_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[3]; + + rslt = bma400_get_regs(BMA400_REG_ACCEL_CONFIG_0, data_array, 3, dev); + if (rslt == BMA400_OK) + { + accel_conf->filt1_bw = BMA400_GET_BITS(data_array[0], BMA400_FILT_1_BW); + accel_conf->osr_lp = BMA400_GET_BITS(data_array[0], BMA400_OSR_LP); + accel_conf->range = BMA400_GET_BITS(data_array[1], BMA400_ACCEL_RANGE); + accel_conf->osr = BMA400_GET_BITS(data_array[1], BMA400_OSR); + accel_conf->odr = BMA400_GET_BITS_POS_0(data_array[1], BMA400_ACCEL_ODR); + accel_conf->data_src = BMA400_GET_BITS(data_array[2], BMA400_DATA_FILTER); + } + + return rslt; +} + +static int8_t get_accel_data(uint8_t data_sel, struct bma400_sensor_data *accel, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[9] = { 0 }; + uint16_t lsb; + uint8_t msb; + uint8_t time_0; + uint16_t time_1; + uint32_t time_2; + + if (data_sel == BMA400_DATA_ONLY) + { + /* Read the sensor data registers only */ + rslt = bma400_get_regs(BMA400_REG_ACCEL_DATA, data_array, 6, dev); + } + else if (data_sel == BMA400_DATA_SENSOR_TIME) + { + /* Read the sensor data along with sensor time */ + rslt = bma400_get_regs(BMA400_REG_ACCEL_DATA, data_array, 9, dev); + } + else + { + /* Invalid use of "data_sel" */ + rslt = BMA400_E_INVALID_CONFIG; + } + + if (rslt == BMA400_OK) + { + lsb = data_array[0]; + msb = data_array[1]; + + /* accel X axis data */ + accel->x = (int16_t)(((uint16_t)msb * 256) + lsb); + if (accel->x > 2047) + { + /* Computing accel data negative value */ + accel->x = accel->x - 4096; + } + + lsb = data_array[2]; + msb = data_array[3]; + + /* accel Y axis data */ + accel->y = (int16_t)(((uint16_t)msb * 256) | lsb); + if (accel->y > 2047) + { + /* Computing accel data negative value */ + accel->y = accel->y - 4096; + } + + lsb = data_array[4]; + msb = data_array[5]; + + /* accel Z axis data */ + accel->z = (int16_t)(((uint16_t)msb * 256) | lsb); + if (accel->z > 2047) + { + /* Computing accel data negative value */ + accel->z = accel->z - 4096; + } + + if (data_sel == BMA400_DATA_ONLY) + { + /* Update sensortime as 0 */ + accel->sensortime = 0; + } + + if (data_sel == BMA400_DATA_SENSOR_TIME) + { + /* Sensor-time data*/ + time_0 = data_array[6]; + time_1 = ((uint16_t)data_array[7] << 8); + time_2 = ((uint32_t)data_array[8] << 16); + accel->sensortime = (uint32_t)(time_2 + time_1 + time_0); + } + } + + return rslt; +} + +static int8_t set_autowakeup_timeout(const struct bma400_auto_wakeup_conf *wakeup_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[2]; + uint8_t lsb; + uint8_t msb; + + rslt = bma400_get_regs(BMA400_REG_AUTOWAKEUP_1, &data_array[1], 1, dev); + if (rslt == BMA400_OK) + { + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_WAKEUP_TIMEOUT, wakeup_conf->wakeup_timeout); + + /* LSB of timeout threshold */ + lsb = BMA400_GET_BITS_POS_0(wakeup_conf->timeout_thres, BMA400_WAKEUP_THRES_LSB); + + /* MSB of timeout threshold */ + msb = BMA400_GET_BITS(wakeup_conf->timeout_thres, BMA400_WAKEUP_THRES_MSB); + + /* Set the value in the data_array */ + data_array[0] = msb; + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_WAKEUP_TIMEOUT_THRES, lsb); + rslt = bma400_set_regs(BMA400_REG_AUTOWAKEUP_0, data_array, 2, dev); + } + + return rslt; +} + +static int8_t get_autowakeup_timeout(struct bma400_auto_wakeup_conf *wakeup_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[2]; + uint8_t lsb; + uint8_t msb; + + rslt = bma400_get_regs(BMA400_REG_AUTOWAKEUP_0, data_array, 2, dev); + if (rslt == BMA400_OK) + { + wakeup_conf->wakeup_timeout = BMA400_GET_BITS(data_array[1], BMA400_WAKEUP_TIMEOUT); + msb = data_array[0]; + lsb = BMA400_GET_BITS(data_array[1], BMA400_WAKEUP_TIMEOUT_THRES); + + /* Store the timeout value in the wakeup structure */ + wakeup_conf->timeout_thres = msb << 4 | lsb; + } + + return rslt; +} + +static int8_t set_auto_wakeup(uint8_t conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + rslt = bma400_get_regs(BMA400_REG_AUTOWAKEUP_1, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + reg_data = BMA400_SET_BITS(reg_data, BMA400_WAKEUP_INTERRUPT, conf); + + /* Enabling the Auto wakeup interrupt */ + rslt = bma400_set_regs(BMA400_REG_AUTOWAKEUP_1, ®_data, 1, dev); + } + + return rslt; +} + +static int8_t set_autowakeup_interrupt(const struct bma400_wakeup_conf *wakeup_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[5] = { 0 }; + + /* Set the wakeup reference update */ + data_array[0] = BMA400_SET_BITS_POS_0(data_array[0], BMA400_WKUP_REF_UPDATE, wakeup_conf->wakeup_ref_update); + + /* Set the number of samples for interrupt condition evaluation */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_SAMPLE_COUNT, wakeup_conf->sample_count); + + /* Enable low power wake-up interrupt for X,Y,Z axes*/ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_WAKEUP_EN_AXES, wakeup_conf->wakeup_axes_en); + + /* Set interrupt threshold configuration */ + data_array[1] = wakeup_conf->int_wkup_threshold; + + /* Set the reference acceleration x-axis for the wake-up interrupt */ + data_array[2] = wakeup_conf->int_wkup_ref_x; + + /* Set the reference acceleration y-axis for the wake-up interrupt */ + data_array[3] = wakeup_conf->int_wkup_ref_y; + + /* Set the reference acceleration z-axis for the wake-up interrupt */ + data_array[4] = wakeup_conf->int_wkup_ref_z; + + /* Set the wakeup interrupt configurations in the sensor */ + rslt = bma400_set_regs(BMA400_REG_WAKEUP_INT_CONF_0, data_array, 5, dev); + + return rslt; +} + +static int8_t get_autowakeup_interrupt(struct bma400_wakeup_conf *wakeup_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[5]; + + rslt = bma400_get_regs(BMA400_REG_WAKEUP_INT_CONF_0, data_array, 5, dev); + if (rslt == BMA400_OK) + { + /* get the wakeup reference update */ + wakeup_conf->wakeup_ref_update = BMA400_GET_BITS_POS_0(data_array[0], BMA400_WKUP_REF_UPDATE); + + /* Get the number of samples for interrupt condition evaluation */ + wakeup_conf->sample_count = BMA400_GET_BITS(data_array[0], BMA400_SAMPLE_COUNT); + + /* Get the axes enabled */ + wakeup_conf->wakeup_axes_en = BMA400_GET_BITS(data_array[0], BMA400_WAKEUP_EN_AXES); + + /* Get interrupt threshold configuration */ + wakeup_conf->int_wkup_threshold = data_array[1]; + + /* Get the reference acceleration x-axis for the wake-up interrupt */ + wakeup_conf->int_wkup_ref_x = data_array[2]; + + /* Get the reference acceleration y-axis for the wake-up interrupt */ + wakeup_conf->int_wkup_ref_y = data_array[3]; + + /* Get the reference acceleration z-axis for the wake-up interrupt */ + wakeup_conf->int_wkup_ref_z = data_array[4]; + } + + return rslt; +} + +static int8_t set_auto_low_power(const struct bma400_auto_lp_conf *auto_lp_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + uint8_t timeout_msb; + uint8_t timeout_lsb; + + rslt = bma400_get_regs(BMA400_REG_AUTO_LOW_POW_1, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + reg_data = BMA400_SET_BITS_POS_0(reg_data, BMA400_AUTO_LOW_POW, auto_lp_conf->auto_low_power_trigger); + + /* If auto Low power timeout threshold is enabled */ + if (auto_lp_conf->auto_low_power_trigger & 0x0C) + { + rslt = bma400_get_regs(BMA400_REG_AUTO_LOW_POW_0, &timeout_msb, 1, dev); + if (rslt == BMA400_OK) + { + /* Compute the timeout threshold MSB value */ + timeout_msb = BMA400_GET_BITS(auto_lp_conf->auto_lp_timeout_threshold, BMA400_AUTO_LP_THRES); + + /* Compute the timeout threshold LSB value */ + timeout_lsb = BMA400_GET_BITS_POS_0(auto_lp_conf->auto_lp_timeout_threshold, BMA400_AUTO_LP_THRES_LSB); + reg_data = BMA400_SET_BITS(reg_data, BMA400_AUTO_LP_TIMEOUT_LSB, timeout_lsb); + + /* Set the timeout threshold MSB value */ + rslt = bma400_set_regs(BMA400_REG_AUTO_LOW_POW_0, &timeout_msb, 1, dev); + } + } + + if (rslt == BMA400_OK) + { + /* Set the Auto low power configurations */ + rslt = bma400_set_regs(BMA400_REG_AUTO_LOW_POW_1, ®_data, 1, dev); + } + } + + return rslt; +} + +static int8_t get_auto_low_power(struct bma400_auto_lp_conf *auto_lp_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[2]; + uint8_t timeout_msb; + uint8_t timeout_lsb; + + rslt = bma400_get_regs(BMA400_REG_AUTO_LOW_POW_0, data_array, 2, dev); + if (rslt == BMA400_OK) + { + /* Get the auto low power trigger */ + auto_lp_conf->auto_low_power_trigger = BMA400_GET_BITS_POS_0(data_array[1], BMA400_AUTO_LOW_POW); + timeout_msb = data_array[0]; + timeout_lsb = BMA400_GET_BITS(data_array[1], BMA400_AUTO_LP_TIMEOUT_LSB); + + /* Get the auto low power timeout threshold */ + auto_lp_conf->auto_lp_timeout_threshold = timeout_msb << 4 | timeout_lsb; + } + + return rslt; +} + +static int8_t set_tap_conf(const struct bma400_tap_conf *tap_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data[2] = { 0, 0 }; + + rslt = bma400_get_regs(BMA400_REG_TAP_CONFIG, reg_data, 2, dev); + if (rslt == BMA400_OK) + { + /* Set the axis to sense for tap */ + reg_data[0] = BMA400_SET_BITS(reg_data[0], BMA400_TAP_AXES_EN, tap_set->axes_sel); + + /* Set the threshold for tap sensing */ + reg_data[0] = BMA400_SET_BITS_POS_0(reg_data[0], BMA400_TAP_SENSITIVITY, tap_set->sensitivity); + + /* Set the Quiet_dt setting */ + reg_data[1] = BMA400_SET_BITS(reg_data[1], BMA400_TAP_QUIET_DT, tap_set->quiet_dt); + + /* Set the Quiet setting */ + reg_data[1] = BMA400_SET_BITS(reg_data[1], BMA400_TAP_QUIET, tap_set->quiet); + + /* Set the tics_th setting */ + reg_data[1] = BMA400_SET_BITS_POS_0(reg_data[1], BMA400_TAP_TICS_TH, tap_set->tics_th); + + /* Set the TAP configuration in the sensor*/ + rslt = bma400_set_regs(BMA400_REG_TAP_CONFIG, reg_data, 2, dev); + } + + return rslt; +} + +static int8_t get_tap_conf(struct bma400_tap_conf *tap_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data[2]; + + rslt = bma400_get_regs(BMA400_REG_TAP_CONFIG, reg_data, 2, dev); + if (rslt == BMA400_OK) + { + /* Get the axis enabled for tap sensing */ + tap_set->axes_sel = BMA400_GET_BITS(reg_data[0], BMA400_TAP_AXES_EN); + + /* Get the threshold for tap sensing */ + tap_set->sensitivity = BMA400_GET_BITS_POS_0(reg_data[0], BMA400_TAP_SENSITIVITY); + + /* Get the Quiet_dt setting */ + tap_set->quiet_dt = BMA400_GET_BITS(reg_data[1], BMA400_TAP_QUIET_DT); + + /* Get the Quiet setting */ + tap_set->quiet = BMA400_GET_BITS(reg_data[1], BMA400_TAP_QUIET); + + /* Get the tics_th setting */ + tap_set->tics_th = BMA400_GET_BITS_POS_0(reg_data[1], BMA400_TAP_TICS_TH); + } + + return rslt; +} + +static int8_t set_activity_change_conf(const struct bma400_act_ch_conf *act_ch_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[2] = { 0 }; + + /* Set the activity change threshold */ + data_array[0] = act_ch_set->act_ch_thres; + + /* Set the axis to sense for activity change */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_ACT_CH_AXES_EN, act_ch_set->axes_sel); + + /* Set the data source for activity change */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_ACT_CH_DATA_SRC, act_ch_set->data_source); + + /* Set the Number of sample points(NPTS) + * for sensing activity change + */ + data_array[1] = BMA400_SET_BITS_POS_0(data_array[1], BMA400_ACT_CH_NPTS, act_ch_set->act_ch_ntps); + + /* Set the Activity change configuration in the sensor*/ + rslt = bma400_set_regs(BMA400_REG_ACT_CH_CONFIG_0, data_array, 2, dev); + + return rslt; +} + +static int8_t get_activity_change_conf(struct bma400_act_ch_conf *act_ch_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[2]; + + rslt = bma400_get_regs(BMA400_REG_ACT_CH_CONFIG_0, data_array, 2, dev); + if (rslt == BMA400_OK) + { + /* Get the activity change threshold */ + act_ch_set->act_ch_thres = data_array[0]; + + /* Get the axis enabled for activity change detection */ + act_ch_set->axes_sel = BMA400_GET_BITS(data_array[1], BMA400_ACT_CH_AXES_EN); + + /* Get the data source for activity change */ + act_ch_set->data_source = BMA400_GET_BITS(data_array[1], BMA400_ACT_CH_DATA_SRC); + + /* Get the Number of sample points(NPTS) + * for sensing activity change + */ + act_ch_set->act_ch_ntps = BMA400_GET_BITS_POS_0(data_array[1], BMA400_ACT_CH_NPTS); + } + + return rslt; +} + +static int8_t set_gen1_int(const struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[11] = { 0 }; + + /* Set the axes to sense for interrupt */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_AXES_EN, gen_int_set->axes_sel); + + /* Set the data source for interrupt */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_DATA_SRC, gen_int_set->data_src); + + /* Set the reference update mode */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_REFU, gen_int_set->ref_update); + + /* Set the hysteresis for interrupt calculation */ + data_array[0] = BMA400_SET_BITS_POS_0(data_array[0], BMA400_INT_HYST, gen_int_set->hysteresis); + + /* Set the criterion to generate interrupt on either + * ACTIVITY OR INACTIVITY + */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_GEN_INT_CRITERION, gen_int_set->criterion_sel); + + /* Set the interrupt axes logic (AND/OR) for the + * enabled axes to generate interrupt + */ + data_array[1] = BMA400_SET_BITS_POS_0(data_array[1], BMA400_GEN_INT_COMB, gen_int_set->evaluate_axes); + + /* Set the interrupt threshold */ + data_array[2] = gen_int_set->gen_int_thres; + + /* Set the MSB of gen int dur */ + data_array[3] = BMA400_GET_MSB(gen_int_set->gen_int_dur); + + /* Set the LSB of gen int dur */ + data_array[4] = BMA400_GET_LSB(gen_int_set->gen_int_dur); + + /* Handling case of manual reference update */ + if (gen_int_set->ref_update == BMA400_UPDATE_MANUAL) + { + /* Set the LSB of reference x threshold */ + data_array[5] = BMA400_GET_LSB(gen_int_set->int_thres_ref_x); + + /* Set the MSB of reference x threshold */ + data_array[6] = BMA400_GET_MSB(gen_int_set->int_thres_ref_x); + + /* Set the LSB of reference y threshold */ + data_array[7] = BMA400_GET_LSB(gen_int_set->int_thres_ref_y); + + /* Set the MSB of reference y threshold */ + data_array[8] = BMA400_GET_MSB(gen_int_set->int_thres_ref_y); + + /* Set the LSB of reference z threshold */ + data_array[9] = BMA400_GET_LSB(gen_int_set->int_thres_ref_z); + + /* Set the MSB of reference z threshold */ + data_array[10] = BMA400_GET_MSB(gen_int_set->int_thres_ref_z); + + /* Set the GEN1 INT configuration in the sensor */ + rslt = bma400_set_regs(BMA400_REG_GEN1_INT_CONFIG, data_array, 11, dev); + } + else + { + /* Set the GEN1 INT configuration in the sensor */ + rslt = bma400_set_regs(BMA400_REG_GEN1_INT_CONFIG, data_array, 5, dev); + } + + return rslt; +} + +static int8_t get_gen1_int(struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[11]; + + rslt = bma400_get_regs(BMA400_REG_GEN1_INT_CONFIG, data_array, 11, dev); + if (rslt == BMA400_OK) + { + /* Get the axes to sense for interrupt */ + gen_int_set->axes_sel = BMA400_GET_BITS(data_array[0], BMA400_INT_AXES_EN); + + /* Get the data source for interrupt */ + gen_int_set->data_src = BMA400_GET_BITS(data_array[0], BMA400_INT_DATA_SRC); + + /* Get the reference update mode */ + gen_int_set->ref_update = BMA400_GET_BITS(data_array[0], BMA400_INT_REFU); + + /* Get the hysteresis for interrupt calculation */ + gen_int_set->hysteresis = BMA400_GET_BITS_POS_0(data_array[0], BMA400_INT_HYST); + + /* Get the interrupt axes logic (AND/OR) to generate interrupt */ + gen_int_set->evaluate_axes = BMA400_GET_BITS_POS_0(data_array[1], BMA400_GEN_INT_COMB); + + /* Get the criterion to generate interrupt ACTIVITY/INACTIVITY */ + gen_int_set->criterion_sel = BMA400_GET_BITS(data_array[1], BMA400_GEN_INT_CRITERION); + + /* Get the interrupt threshold */ + gen_int_set->gen_int_thres = data_array[2]; + + /* Get the interrupt duration */ + gen_int_set->gen_int_dur = ((uint16_t)data_array[3] << 8) | data_array[4]; + + /* Get the interrupt threshold */ + data_array[6] = data_array[6] & 0x0F; + gen_int_set->int_thres_ref_x = ((uint16_t)data_array[6] << 8) | data_array[5]; + data_array[8] = data_array[8] & 0x0F; + gen_int_set->int_thres_ref_y = ((uint16_t)data_array[8] << 8) | data_array[7]; + data_array[10] = data_array[10] & 0x0F; + gen_int_set->int_thres_ref_z = ((uint16_t)data_array[10] << 8) | data_array[9]; + } + + return rslt; +} + +static int8_t set_gen2_int(const struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[11] = { 0 }; + + /* Set the axes to sense for interrupt */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_AXES_EN, gen_int_set->axes_sel); + + /* Set the data source for interrupt */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_DATA_SRC, gen_int_set->data_src); + + /* Set the reference update mode */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_REFU, gen_int_set->ref_update); + + /* Set the hysteresis for interrupt calculation */ + data_array[0] = BMA400_SET_BITS_POS_0(data_array[0], BMA400_INT_HYST, gen_int_set->hysteresis); + + /* Set the criterion to generate interrupt on either + * ACTIVITY OR INACTIVITY + */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_GEN_INT_CRITERION, gen_int_set->criterion_sel); + + /* Set the interrupt axes logic (AND/OR) for the + * enabled axes to generate interrupt + */ + data_array[1] = BMA400_SET_BITS_POS_0(data_array[1], BMA400_GEN_INT_COMB, gen_int_set->evaluate_axes); + + /* Set the interrupt threshold */ + data_array[2] = gen_int_set->gen_int_thres; + + /* Set the MSB of gen int dur */ + data_array[3] = BMA400_GET_MSB(gen_int_set->gen_int_dur); + + /* Set the LSB of gen int dur */ + data_array[4] = BMA400_GET_LSB(gen_int_set->gen_int_dur); + + /* Handling case of manual reference update */ + if (gen_int_set->ref_update == BMA400_UPDATE_MANUAL) + { + /* Set the LSB of reference x threshold */ + data_array[5] = BMA400_GET_LSB(gen_int_set->int_thres_ref_x); + + /* Set the MSB of reference x threshold */ + data_array[6] = BMA400_GET_MSB(gen_int_set->int_thres_ref_x); + + /* Set the LSB of reference y threshold */ + data_array[7] = BMA400_GET_LSB(gen_int_set->int_thres_ref_y); + + /* Set the MSB of reference y threshold */ + data_array[8] = BMA400_GET_MSB(gen_int_set->int_thres_ref_y); + + /* Set the LSB of reference z threshold */ + data_array[9] = BMA400_GET_LSB(gen_int_set->int_thres_ref_z); + + /* Set the MSB of reference z threshold */ + data_array[10] = BMA400_GET_MSB(gen_int_set->int_thres_ref_z); + + /* Set the GEN2 INT configuration in the sensor */ + rslt = bma400_set_regs(BMA400_REG_GEN2_INT_CONFIG, data_array, 11, dev); + } + else + { + /* Set the GEN2 INT configuration in the sensor */ + rslt = bma400_set_regs(BMA400_REG_GEN2_INT_CONFIG, data_array, 5, dev); + } + + return rslt; +} + +static int8_t get_gen2_int(struct bma400_gen_int_conf *gen_int_set, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[11]; + + rslt = bma400_get_regs(BMA400_REG_GEN2_INT_CONFIG, data_array, 11, dev); + if (rslt == BMA400_OK) + { + /* Get the axes to sense for interrupt */ + gen_int_set->axes_sel = BMA400_GET_BITS(data_array[0], BMA400_INT_AXES_EN); + + /* Get the data source for interrupt */ + gen_int_set->data_src = BMA400_GET_BITS(data_array[0], BMA400_INT_DATA_SRC); + + /* Get the reference update mode */ + gen_int_set->ref_update = BMA400_GET_BITS(data_array[0], BMA400_INT_REFU); + + /* Get the hysteresis for interrupt calculation */ + gen_int_set->hysteresis = BMA400_GET_BITS_POS_0(data_array[0], BMA400_INT_HYST); + + /* Get the interrupt axes logic (AND/OR) to generate interrupt */ + gen_int_set->evaluate_axes = BMA400_GET_BITS_POS_0(data_array[1], BMA400_GEN_INT_COMB); + + /* Get the criterion to generate interrupt ACTIVITY/INACTIVITY */ + gen_int_set->criterion_sel = BMA400_GET_BITS(data_array[1], BMA400_GEN_INT_CRITERION); + + /* Get the interrupt threshold */ + gen_int_set->gen_int_thres = data_array[2]; + + /* Get the interrupt duration */ + gen_int_set->gen_int_dur = ((uint16_t)data_array[3] << 8) | data_array[4]; + + /* Get the interrupt threshold */ + data_array[6] = data_array[6] & 0x0F; + gen_int_set->int_thres_ref_x = ((uint16_t)data_array[6] << 8) | data_array[5]; + data_array[8] = data_array[8] & 0x0F; + gen_int_set->int_thres_ref_y = ((uint16_t)data_array[8] << 8) | data_array[7]; + data_array[10] = data_array[10] & 0x0F; + gen_int_set->int_thres_ref_z = ((uint16_t)data_array[10] << 8) | data_array[9]; + } + + return rslt; +} + +static int8_t set_orient_int(const struct bma400_orient_int_conf *orient_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[10] = { 0 }; + + /* Set the axes to sense for interrupt */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_AXES_EN, orient_conf->axes_sel); + + /* Set the data source for interrupt */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_DATA_SRC, orient_conf->data_src); + + /* Set the reference update mode */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_INT_REFU, orient_conf->ref_update); + + /* Set the threshold for interrupt calculation */ + data_array[1] = orient_conf->orient_thres; + + /* Set the stability threshold */ + data_array[2] = orient_conf->stability_thres; + + /* Set the interrupt duration */ + data_array[3] = orient_conf->orient_int_dur; + + /* Handling case of manual reference update */ + if (orient_conf->ref_update == BMA400_UPDATE_MANUAL) + { + /* Set the LSB of reference x threshold */ + data_array[4] = BMA400_GET_LSB(orient_conf->orient_ref_x); + + /* Set the MSB of reference x threshold */ + data_array[5] = BMA400_GET_MSB(orient_conf->orient_ref_x); + + /* Set the MSB of reference x threshold */ + data_array[6] = BMA400_GET_LSB(orient_conf->orient_ref_y); + + /* Set the LSB of reference y threshold */ + data_array[7] = BMA400_GET_MSB(orient_conf->orient_ref_y); + + /* Set the MSB of reference y threshold */ + data_array[8] = BMA400_GET_LSB(orient_conf->orient_ref_z); + + /* Set the LSB of reference z threshold */ + data_array[9] = BMA400_GET_MSB(orient_conf->orient_ref_z); + + /* Set the orient configurations in the sensor */ + rslt = bma400_set_regs(BMA400_REG_ORIENTCH_INT_CONFIG, data_array, 10, dev); + } + else + { + /* Set the orient configurations in the sensor excluding + * reference values of x,y,z + */ + rslt = bma400_set_regs(BMA400_REG_ORIENTCH_INT_CONFIG, data_array, 4, dev); + } + + return rslt; +} + +static int8_t get_orient_int(struct bma400_orient_int_conf *orient_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[10]; + + rslt = bma400_get_regs(BMA400_REG_ORIENTCH_INT_CONFIG, data_array, 10, dev); + if (rslt == BMA400_OK) + { + /* Get the axes to sense for interrupt */ + orient_conf->axes_sel = BMA400_GET_BITS(data_array[0], BMA400_INT_AXES_EN); + + /* Get the data source for interrupt */ + orient_conf->data_src = BMA400_GET_BITS(data_array[0], BMA400_INT_DATA_SRC); + + /* Get the reference update mode */ + orient_conf->ref_update = BMA400_GET_BITS(data_array[0], BMA400_INT_REFU); + + /* Get the threshold for interrupt calculation */ + orient_conf->orient_thres = data_array[1]; + + /* Get the stability threshold */ + orient_conf->stability_thres = data_array[2]; + + /* Get the interrupt duration */ + orient_conf->orient_int_dur = data_array[3]; + + /* Get the interrupt reference values */ + data_array[5] = data_array[5] & 0x0F; + orient_conf->orient_ref_x = ((uint16_t)data_array[5] << 8) | data_array[4]; + data_array[5] = data_array[7] & 0x0F; + orient_conf->orient_ref_y = ((uint16_t)data_array[7] << 8) | data_array[6]; + data_array[5] = data_array[9] & 0x0F; + orient_conf->orient_ref_z = ((uint16_t)data_array[9] << 8) | data_array[8]; + } + + return rslt; +} + +static void map_int_pin(uint8_t *data_array, uint8_t int_enable, enum bma400_int_chan int_map) +{ + switch (int_enable) + { + case BMA400_DATA_READY_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1*/ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_DRDY, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2*/ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_DRDY, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_DRDY); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_DRDY); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_DRDY, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_DRDY, BMA400_ENABLE); + } + + break; + case BMA400_FIFO_WM_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1*/ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_FIFO_WM, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2*/ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_FIFO_WM, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_FIFO_WM); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_FIFO_WM); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_FIFO_WM, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_FIFO_WM, BMA400_ENABLE); + } + + break; + case BMA400_FIFO_FULL_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_FIFO_FULL, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_FIFO_FULL, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_FIFO_FULL); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_FIFO_FULL); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_FIFO_FULL, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_FIFO_FULL, BMA400_ENABLE); + } + + break; + case BMA400_INT_OVERRUN_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_INT_OVERRUN, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_INT_OVERRUN, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_INT_OVERRUN); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_INT_OVERRUN); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_INT_OVERRUN, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_INT_OVERRUN, BMA400_ENABLE); + } + + break; + case BMA400_GEN2_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_GEN2, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_GEN2, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_GEN2); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_GEN2); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_GEN2, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_GEN2, BMA400_ENABLE); + } + + break; + case BMA400_GEN1_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_GEN1, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_GEN1, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_GEN1); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_GEN1); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_GEN1, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_GEN1, BMA400_ENABLE); + } + + break; + case BMA400_ORIENT_CH_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_ORIENT_CH, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_ORIENT_CH, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_ORIENT_CH); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_ORIENT_CH); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS(data_array[0], BMA400_EN_ORIENT_CH, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS(data_array[1], BMA400_EN_ORIENT_CH, BMA400_ENABLE); + } + + break; + case BMA400_WAKEUP_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[0] = BMA400_SET_BITS_POS_0(data_array[0], BMA400_EN_WAKEUP_INT, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[1] = BMA400_SET_BITS_POS_0(data_array[1], BMA400_EN_WAKEUP_INT, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[0] = BMA400_SET_BIT_VAL_0(data_array[0], BMA400_EN_WAKEUP_INT); + data_array[1] = BMA400_SET_BIT_VAL_0(data_array[1], BMA400_EN_WAKEUP_INT); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[0] = BMA400_SET_BITS_POS_0(data_array[0], BMA400_EN_WAKEUP_INT, BMA400_ENABLE); + data_array[1] = BMA400_SET_BITS_POS_0(data_array[1], BMA400_EN_WAKEUP_INT, BMA400_ENABLE); + } + + break; + case BMA400_ACT_CH_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_ACTCH_MAP_INT1, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_ACTCH_MAP_INT2, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[2] = BMA400_SET_BIT_VAL_0(data_array[2], BMA400_ACTCH_MAP_INT1); + data_array[2] = BMA400_SET_BIT_VAL_0(data_array[2], BMA400_ACTCH_MAP_INT2); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_ACTCH_MAP_INT1, BMA400_ENABLE); + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_ACTCH_MAP_INT2, BMA400_ENABLE); + } + + break; + case BMA400_TAP_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_TAP_MAP_INT1, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_TAP_MAP_INT2, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[2] = BMA400_SET_BIT_VAL_0(data_array[2], BMA400_TAP_MAP_INT1); + data_array[2] = BMA400_SET_BIT_VAL_0(data_array[2], BMA400_TAP_MAP_INT2); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_TAP_MAP_INT1, BMA400_ENABLE); + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_TAP_MAP_INT2, BMA400_ENABLE); + } + + break; + case BMA400_STEP_INT_MAP: + if (int_map == BMA400_INT_CHANNEL_1) + { + /* Mapping interrupt to INT pin 1 */ + data_array[2] = BMA400_SET_BITS_POS_0(data_array[2], BMA400_EN_STEP_INT, BMA400_ENABLE); + } + + if (int_map == BMA400_INT_CHANNEL_2) + { + /* Mapping interrupt to INT pin 2 */ + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_STEP_MAP_INT2, BMA400_ENABLE); + } + + if (int_map == BMA400_UNMAP_INT_PIN) + { + data_array[2] = BMA400_SET_BIT_VAL_0(data_array[2], BMA400_EN_STEP_INT); + data_array[2] = BMA400_SET_BIT_VAL_0(data_array[2], BMA400_STEP_MAP_INT2); + } + + if (int_map == BMA400_MAP_BOTH_INT_PINS) + { + data_array[2] = BMA400_SET_BITS_POS_0(data_array[2], BMA400_EN_STEP_INT, BMA400_ENABLE); + data_array[2] = BMA400_SET_BITS(data_array[2], BMA400_STEP_MAP_INT2, BMA400_ENABLE); + } + + break; + default: + break; + } +} + +static void check_mapped_interrupts(uint8_t int_1_map, uint8_t int_2_map, enum bma400_int_chan *int_map) +{ + if ((int_1_map == BMA400_ENABLE) && (int_2_map == BMA400_DISABLE)) + { + /* INT 1 mapped INT 2 not mapped */ + *int_map = BMA400_INT_CHANNEL_1; + } + + if ((int_1_map == BMA400_DISABLE) && (int_2_map == BMA400_ENABLE)) + { + /* INT 1 not mapped INT 2 mapped */ + *int_map = BMA400_INT_CHANNEL_2; + } + + if ((int_1_map == BMA400_ENABLE) && (int_2_map == BMA400_ENABLE)) + { + /* INT 1 ,INT 2 both mapped */ + *int_map = BMA400_MAP_BOTH_INT_PINS; + } + + if ((int_1_map == BMA400_DISABLE) && (int_2_map == BMA400_DISABLE)) + { + /* INT 1 ,INT 2 not mapped */ + *int_map = BMA400_UNMAP_INT_PIN; + } +} + +static void get_int_pin_map(const uint8_t *data_array, uint8_t int_enable, enum bma400_int_chan *int_map) +{ + uint8_t int_1_map; + uint8_t int_2_map; + + switch (int_enable) + { + case BMA400_DATA_READY_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[0], BMA400_EN_DRDY); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[1], BMA400_EN_DRDY); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_FIFO_WM_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[0], BMA400_EN_FIFO_WM); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[1], BMA400_EN_FIFO_WM); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_FIFO_FULL_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[0], BMA400_EN_FIFO_FULL); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[1], BMA400_EN_FIFO_FULL); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_GEN2_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[0], BMA400_EN_GEN2); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[1], BMA400_EN_GEN2); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_GEN1_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[0], BMA400_EN_GEN1); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[1], BMA400_EN_GEN1); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_ORIENT_CH_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[0], BMA400_EN_ORIENT_CH); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[1], BMA400_EN_ORIENT_CH); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_WAKEUP_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS_POS_0(data_array[0], BMA400_EN_WAKEUP_INT); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS_POS_0(data_array[1], BMA400_EN_WAKEUP_INT); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_ACT_CH_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[2], BMA400_ACTCH_MAP_INT1); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[2], BMA400_ACTCH_MAP_INT2); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_TAP_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[2], BMA400_TAP_MAP_INT1); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[2], BMA400_TAP_MAP_INT2); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_STEP_INT_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS_POS_0(data_array[2], BMA400_EN_STEP_INT); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[2], BMA400_STEP_MAP_INT2); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + case BMA400_INT_OVERRUN_MAP: + + /* Interrupt 1 pin mapping status */ + int_1_map = BMA400_GET_BITS(data_array[0], BMA400_EN_INT_OVERRUN); + + /* Interrupt 2 pin mapping status */ + int_2_map = BMA400_GET_BITS(data_array[1], BMA400_EN_INT_OVERRUN); + + /* Check the mapped interrupt pins */ + check_mapped_interrupts(int_1_map, int_2_map, int_map); + break; + default: + break; + } +} + +static int8_t set_int_pin_conf(struct bma400_int_pin_conf int_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + rslt = bma400_get_regs(BMA400_REG_INT_12_IO_CTRL, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + if (int_conf.int_chan == BMA400_INT_CHANNEL_1) + { + /* Setting interrupt pin configurations */ + reg_data = BMA400_SET_BITS(reg_data, BMA400_INT_PIN1_CONF, int_conf.pin_conf); + } + + if (int_conf.int_chan == BMA400_INT_CHANNEL_2) + { + /* Setting interrupt pin configurations */ + reg_data = BMA400_SET_BITS(reg_data, BMA400_INT_PIN2_CONF, int_conf.pin_conf); + } + + /* Set the configurations in the sensor */ + rslt = bma400_set_regs(BMA400_REG_INT_12_IO_CTRL, ®_data, 1, dev); + } + + return rslt; +} + +static int8_t get_int_pin_conf(struct bma400_int_pin_conf *int_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + + rslt = bma400_get_regs(BMA400_REG_INT_12_IO_CTRL, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + if (int_conf->int_chan == BMA400_INT_CHANNEL_1) + { + /* reading Interrupt pin configurations */ + int_conf->pin_conf = BMA400_GET_BITS(reg_data, BMA400_INT_PIN1_CONF); + } + + if (int_conf->int_chan == BMA400_INT_CHANNEL_2) + { + /* Setting interrupt pin configurations */ + int_conf->pin_conf = BMA400_GET_BITS(reg_data, BMA400_INT_PIN2_CONF); + } + } + + return rslt; +} + +static int8_t get_fifo_conf(struct bma400_fifo_conf *fifo_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[3]; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if (rslt == BMA400_OK) + { + /* Get the FIFO configurations and water-mark + * values from the sensor + */ + rslt = bma400_get_regs(BMA400_REG_FIFO_CONFIG_0, data_array, 3, dev); + if (rslt == BMA400_OK) + { + /* Get the data of FIFO_CONFIG0 register */ + fifo_conf->conf_regs = data_array[0]; + + /* Get the MSB of FIFO water-mark */ + data_array[2] = BMA400_GET_BITS_POS_0(data_array[2], BMA400_FIFO_BYTES_CNT); + + /* FIFO water-mark value is stored */ + fifo_conf->fifo_watermark = ((uint16_t)data_array[2] << 8) | ((uint16_t)data_array[1]); + } + } + + return rslt; +} + +static int8_t set_fifo_conf(const struct bma400_fifo_conf *fifo_conf, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[3]; + uint8_t sens_data[3]; + + /* Check for null pointer in the device structure */ + rslt = null_ptr_check(dev); + + /* Proceed if null check is fine */ + if (rslt == BMA400_OK) + { + /* Get the FIFO configurations and water-mark + * values from the sensor + */ + rslt = bma400_get_regs(BMA400_REG_FIFO_CONFIG_0, sens_data, 3, dev); + if (rslt == BMA400_OK) + { + /* FIFO configurations */ + data_array[0] = fifo_conf->conf_regs; + if (fifo_conf->conf_status == BMA400_DISABLE) + { + /* Disable the selected interrupt status */ + data_array[0] = sens_data[0] & (~data_array[0]); + } + + /* FIFO water-mark values */ + data_array[1] = BMA400_GET_LSB(fifo_conf->fifo_watermark); + data_array[2] = BMA400_GET_MSB(fifo_conf->fifo_watermark); + data_array[2] = BMA400_GET_BITS_POS_0(data_array[2], BMA400_FIFO_BYTES_CNT); + if ((data_array[1] == sens_data[1]) && (data_array[2] == sens_data[2])) + { + /* Set the FIFO configurations in the + * sensor excluding the watermark value + */ + rslt = bma400_set_regs(BMA400_REG_FIFO_CONFIG_0, data_array, 1, dev); + } + else + { + /* Set the FIFO configurations in the sensor*/ + rslt = bma400_set_regs(BMA400_REG_FIFO_CONFIG_0, data_array, 3, dev); + } + } + } + + return rslt; +} + +static int8_t get_fifo_length(uint16_t *fifo_byte_cnt, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t data_array[2] = { 0 }; + + rslt = bma400_get_regs(BMA400_REG_FIFO_LENGTH, data_array, 2, dev); + if (rslt == BMA400_OK) + { + data_array[1] = BMA400_GET_BITS_POS_0(data_array[1], BMA400_FIFO_BYTES_CNT); + + /* Available data in FIFO is stored in fifo_byte_cnt*/ + *fifo_byte_cnt = ((uint16_t)data_array[1] << 8) | ((uint16_t)data_array[0]); + } + + return rslt; +} + +static int8_t read_fifo(struct bma400_fifo_data *fifo, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data; + uint8_t fifo_addr = BMA400_REG_FIFO_DATA; + + if (dev->intf == BMA400_SPI_INTF) + { + /* SPI mask is added */ + fifo_addr = fifo_addr | BMA400_SPI_RD_MASK; + } + + /* This update will take care of dummy byte necessity based on interface selection */ + fifo->length += dev->dummy_byte; + + /* Read the FIFO enable bit */ + rslt = bma400_get_regs(BMA400_REG_FIFO_READ_EN, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + /* FIFO read disable bit */ + if (reg_data == 0) + { + /* Read FIFO Buffer since FIFO read is enabled */ + dev->intf_rslt = dev->read(fifo_addr, fifo->data, (uint32_t)fifo->length, dev->intf_ptr); + if (dev->intf_rslt != BMA400_INTF_RET_SUCCESS) + { + rslt = BMA400_E_COM_FAIL; + } + } + else + { + /* Enable FIFO reading */ + reg_data = 0; + rslt = bma400_set_regs(BMA400_REG_FIFO_READ_EN, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + /* Delay to enable the FIFO */ + dev->delay_us(1000, dev->intf_ptr); + + /* Read FIFO Buffer since FIFO read is enabled*/ + dev->intf_rslt = dev->read(fifo_addr, fifo->data, (uint32_t)fifo->length, dev->intf_ptr); + + if (dev->intf_rslt == BMA400_OK) + { + /* Disable FIFO reading */ + reg_data = 1; + rslt = bma400_set_regs(BMA400_REG_FIFO_READ_EN, ®_data, 1, dev); + } + } + } + } + + return rslt; +} + +static void unpack_accel_frame(struct bma400_fifo_data *fifo, + struct bma400_fifo_sensor_data *accel_data, + uint16_t *frame_count, + const struct bma400_dev *dev) +{ + /* Frame header information is stored */ + uint8_t frame_header = 0; + + /* Accel data width is stored */ + uint8_t accel_width; + + /* Data index of the parsed byte from FIFO */ + uint16_t data_index; + + /* Number of accel frames parsed */ + uint16_t accel_index = 0; + + /* Variable to check frame availability */ + uint8_t frame_available = BMA400_ENABLE; + + /* Check if this is the first iteration of data unpacking + * if yes, then consider dummy byte on SPI + */ + if (fifo->accel_byte_start_idx == 0) + { + /* Dummy byte included */ + fifo->accel_byte_start_idx = dev->dummy_byte; + } + + for (data_index = fifo->accel_byte_start_idx; data_index < fifo->length;) + { + /*Header byte is stored in the variable frame_header*/ + frame_header = fifo->data[data_index]; + + /* Store the Accel 8 bit or 12 bit mode */ + accel_width = BMA400_GET_BITS(frame_header, BMA400_FIFO_8_BIT_EN); + + /* Exclude the 8/12 bit mode data from frame header */ + frame_header = frame_header & BMA400_AWIDTH_MASK; + + /*Index is moved to next byte where the data is starting*/ + data_index++; + switch (frame_header) + { + case BMA400_FIFO_XYZ_ENABLE: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_XYZ_ENABLE, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Extract and store accel xyz data */ + unpack_accel(fifo, &accel_data[accel_index], &data_index, accel_width, frame_header); + accel_index++; + } + + break; + case BMA400_FIFO_X_ENABLE: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_X_ENABLE, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Extract and store accel x data */ + unpack_accel(fifo, &accel_data[accel_index], &data_index, accel_width, frame_header); + accel_index++; + } + + break; + case BMA400_FIFO_Y_ENABLE: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_Y_ENABLE, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Extract and store accel y data */ + unpack_accel(fifo, &accel_data[accel_index], &data_index, accel_width, frame_header); + accel_index++; + } + + break; + case BMA400_FIFO_Z_ENABLE: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_Z_ENABLE, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Extract and store accel z data */ + unpack_accel(fifo, &accel_data[accel_index], &data_index, accel_width, frame_header); + accel_index++; + } + + break; + case BMA400_FIFO_XY_ENABLE: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_XY_ENABLE, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Extract and store accel xy data */ + unpack_accel(fifo, &accel_data[accel_index], &data_index, accel_width, frame_header); + accel_index++; + } + + break; + case BMA400_FIFO_YZ_ENABLE: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_YZ_ENABLE, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Extract and store accel yz data */ + unpack_accel(fifo, &accel_data[accel_index], &data_index, accel_width, frame_header); + accel_index++; + } + + break; + case BMA400_FIFO_XZ_ENABLE: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_YZ_ENABLE, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Extract and store accel xz data */ + unpack_accel(fifo, &accel_data[accel_index], &data_index, accel_width, frame_header); + accel_index++; + } + + break; + case BMA400_FIFO_SENSOR_TIME: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_SENSOR_TIME, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Unpack and store the sensor time data */ + unpack_sensortime_frame(fifo, &data_index); + } + + break; + case BMA400_FIFO_EMPTY_FRAME: + + /* Update the data index as complete */ + data_index = fifo->length; + break; + case BMA400_FIFO_CONTROL_FRAME: + check_frame_available(fifo, &frame_available, accel_width, BMA400_FIFO_CONTROL_FRAME, &data_index); + if (frame_available != BMA400_DISABLE) + { + /* Store the configuration change data from FIFO */ + fifo->conf_change = fifo->data[data_index++]; + } + + break; + default: + + /* Update the data index as complete */ + data_index = fifo->length; + break; + } + if (*frame_count == accel_index) + { + /* Frames read completely*/ + break; + } + } + + /* Update the data index */ + fifo->accel_byte_start_idx = data_index; + + /* Update number of accel frame index */ + *frame_count = accel_index; +} + +static void check_frame_available(const struct bma400_fifo_data *fifo, + uint8_t *frame_available, + uint8_t accel_width, + uint8_t data_en, + uint16_t *data_index) +{ + switch (data_en) + { + case BMA400_FIFO_XYZ_ENABLE: + + /* Handling case of 12 bit/ 8 bit data available in FIFO */ + if (accel_width == BMA400_12_BIT_FIFO_DATA) + { + if ((*data_index + 6) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + } + else if ((*data_index + 3) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + + break; + case BMA400_FIFO_X_ENABLE: + case BMA400_FIFO_Y_ENABLE: + case BMA400_FIFO_Z_ENABLE: + + /* Handling case of 12 bit/ 8 bit data available in FIFO */ + if (accel_width == BMA400_12_BIT_FIFO_DATA) + { + if ((*data_index + 2) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + } + else if ((*data_index + 1) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + + break; + case BMA400_FIFO_XY_ENABLE: + case BMA400_FIFO_YZ_ENABLE: + case BMA400_FIFO_XZ_ENABLE: + + /* Handling case of 12 bit/ 8 bit data available in FIFO */ + if (accel_width == BMA400_12_BIT_FIFO_DATA) + { + if ((*data_index + 4) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + } + else if ((*data_index + 2) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + + break; + case BMA400_FIFO_SENSOR_TIME: + if ((*data_index + 3) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + + break; + case BMA400_FIFO_CONTROL_FRAME: + if ((*data_index + 1) > fifo->length) + { + /* Partial frame available */ + *data_index = fifo->length; + *frame_available = BMA400_DISABLE; + } + + break; + default: + break; + } +} + +static void unpack_accel(const struct bma400_fifo_data *fifo, + struct bma400_fifo_sensor_data *accel_data, + uint16_t *data_index, + uint8_t accel_width, + uint8_t frame_header) +{ + uint8_t data_lsb; + uint8_t data_msb; + + /* Header information of enabled axes */ + frame_header = frame_header & BMA400_FIFO_DATA_EN_MASK; + if (accel_width == BMA400_12_BIT_FIFO_DATA) + { + if (frame_header & BMA400_FIFO_X_ENABLE) + { + /* Accel x data */ + data_lsb = fifo->data[(*data_index)++]; + data_msb = fifo->data[(*data_index)++]; + accel_data->x = (int16_t)(((uint16_t)(data_msb << 4)) | data_lsb); + if (accel_data->x > 2047) + { + /* Computing accel x data negative value */ + accel_data->x = accel_data->x - 4096; + } + } + else + { + /* Accel x not available */ + accel_data->x = 0; + } + + if (frame_header & BMA400_FIFO_Y_ENABLE) + { + /* Accel y data */ + data_lsb = fifo->data[(*data_index)++]; + data_msb = fifo->data[(*data_index)++]; + accel_data->y = (int16_t)(((uint16_t)(data_msb << 4)) | data_lsb); + if (accel_data->y > 2047) + { + /* Computing accel y data negative value */ + accel_data->y = accel_data->y - 4096; + } + } + else + { + /* Accel y not available */ + accel_data->y = 0; + } + + if (frame_header & BMA400_FIFO_Z_ENABLE) + { + /* Accel z data */ + data_lsb = fifo->data[(*data_index)++]; + data_msb = fifo->data[(*data_index)++]; + accel_data->z = (int16_t)(((uint16_t)(data_msb << 4)) | data_lsb); + if (accel_data->z > 2047) + { + /* Computing accel z data negative value */ + accel_data->z = accel_data->z - 4096; + } + } + else + { + /* Accel z not available */ + accel_data->z = 0; + } + } + else + { + if (frame_header & BMA400_FIFO_X_ENABLE) + { + /* Accel x data */ + data_msb = fifo->data[(*data_index)++]; + accel_data->x = (int16_t)((uint16_t)(data_msb << 4)); + if (accel_data->x > 2047) + { + /* Computing accel x data negative value */ + accel_data->x = accel_data->x - 4096; + } + } + else + { + /* Accel x not available */ + accel_data->x = 0; + } + + if (frame_header & BMA400_FIFO_Y_ENABLE) + { + /* Accel y data */ + data_msb = fifo->data[(*data_index)++]; + accel_data->y = (int16_t)((uint16_t)(data_msb << 4)); + if (accel_data->y > 2047) + { + /* Computing accel y data negative value */ + accel_data->y = accel_data->y - 4096; + } + } + else + { + /* Accel y not available */ + accel_data->y = 0; + } + + if (frame_header & BMA400_FIFO_Z_ENABLE) + { + /* Accel z data */ + data_msb = fifo->data[(*data_index)++]; + accel_data->z = (int16_t)((uint16_t)(data_msb << 4)); + if (accel_data->z > 2047) + { + /* Computing accel z data negative value */ + accel_data->z = accel_data->z - 4096; + } + } + else + { + /* Accel z not available */ + accel_data->z = 0; + } + } +} + +static void unpack_sensortime_frame(struct bma400_fifo_data *fifo, uint16_t *data_index) +{ + uint32_t time_msb; + uint16_t time_lsb; + uint8_t time_xlsb; + + time_msb = fifo->data[(*data_index) + 2] << 16; + time_lsb = fifo->data[(*data_index) + 1] << 8; + time_xlsb = fifo->data[(*data_index)]; + + /* Sensor time */ + fifo->fifo_sensor_time = (uint32_t)(time_msb | time_lsb | time_xlsb); + *data_index = (*data_index) + 3; +} + +static int8_t validate_accel_self_test(const struct bma400_sensor_data *accel_pos, + const struct bma400_sensor_data *accel_neg) +{ + + int8_t rslt; + + /* Structure for difference of accel values */ + struct bma400_selftest_delta_limit accel_data_diff = { 0, 0, 0 }; + + /* accel x difference value */ + accel_data_diff.x = (accel_pos->x - accel_neg->x); + + /* accel y difference value */ + accel_data_diff.y = (accel_pos->y - accel_neg->y); + + /* accel z difference value */ + accel_data_diff.z = (accel_pos->z - accel_neg->z); + + /* Validate the results of self test */ + if (((accel_data_diff.x) > BMA400_ST_ACC_X_AXIS_SIGNAL_DIFF) && + ((accel_data_diff.y) > BMA400_ST_ACC_Y_AXIS_SIGNAL_DIFF) && + ((accel_data_diff.z) > BMA400_ST_ACC_Z_AXIS_SIGNAL_DIFF)) + { + /* Self test pass condition */ + rslt = BMA400_OK; + } + else + { + /* Self test failed */ + rslt = BMA400_W_SELF_TEST_FAIL; + } + + return rslt; +} + +static int8_t positive_excited_accel(struct bma400_sensor_data *accel_pos, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data = BMA400_SELF_TEST_ENABLE_POSITIVE; + + /* Enable positive excitation for all 3 axes */ + rslt = bma400_set_regs(BMA400_REG_SELF_TEST, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + /* Read accel data after 50ms delay */ + dev->delay_us(BMA400_DELAY_US_SELF_TEST_DATA_READ, dev->intf_ptr); + rslt = bma400_get_accel_data(BMA400_DATA_ONLY, accel_pos, dev); + } + + return rslt; +} + +static int8_t negative_excited_accel(struct bma400_sensor_data *accel_neg, struct bma400_dev *dev) +{ + int8_t rslt; + uint8_t reg_data = BMA400_SELF_TEST_ENABLE_NEGATIVE; + + /* Enable negative excitation for all 3 axes */ + rslt = bma400_set_regs(BMA400_REG_SELF_TEST, ®_data, 1, dev); + if (rslt == BMA400_OK) + { + /* Read accel data after 50ms delay */ + dev->delay_us(BMA400_DELAY_US_SELF_TEST_DATA_READ, dev->intf_ptr); + rslt = bma400_get_accel_data(BMA400_DATA_ONLY, accel_neg, dev); + if (rslt == BMA400_OK) + { + /* Disable self test */ + reg_data = BMA400_SELF_TEST_DISABLE; + rslt = bma400_set_regs(BMA400_REG_SELF_TEST, ®_data, 1, dev); + } + } + + return rslt; +} + +static int8_t enable_self_test(struct bma400_dev *dev) +{ + int8_t rslt; + + /* Accelerometer setting structure */ + struct bma400_sensor_conf accel_setting; + + /* Select the type of configuration to be modified */ + accel_setting.type = BMA400_ACCEL; + + /* Get the accel configurations which are set in the sensor */ + rslt = bma400_get_sensor_conf(&accel_setting, 1, dev); + if (rslt == BMA400_OK) + { + /* Modify to the desired configurations */ + accel_setting.param.accel.odr = BMA400_ODR_100HZ; + + accel_setting.param.accel.range = BMA400_RANGE_4G; + accel_setting.param.accel.osr = BMA400_ACCEL_OSR_SETTING_3; + accel_setting.param.accel.data_src = BMA400_DATA_SRC_ACCEL_FILT_1; + + /* Set the desired configurations in the sensor */ + rslt = bma400_set_sensor_conf(&accel_setting, 1, dev); + if (rslt == BMA400_OK) + { + /* self test enabling delay */ + dev->delay_us(BMA400_DELAY_US_SELF_TEST, dev->intf_ptr); + } + + if (rslt == BMA400_OK) + { + rslt = bma400_set_power_mode(BMA400_MODE_NORMAL, dev); + } + } + + return rslt; +} diff --git a/user/tests/app/ctub_plus_power_test/bma400.h b/user/tests/app/ctub_plus_power_test/bma400.h new file mode 100644 index 0000000000..4d488a3e0c --- /dev/null +++ b/user/tests/app/ctub_plus_power_test/bma400.h @@ -0,0 +1,666 @@ +/** +* Copyright (c) 2024 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bma400.h +* @date 2024-05-10 +* @version v1.5.10 +* +*/ + +/*! + * @defgroup bma400 BMA400 + * @brief Product Overview + * and Sensor API Source Code + */ + +#ifndef BMA400_H__ +#define BMA400_H__ + +/* CPP guard */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "bma400_defs.h" + +/** + * \ingroup bma400 + * \defgroup bma400ApiInit Initialization + * @brief Initialize the sensor and device structure + */ + +/*! + * \ingroup bma400ApiInit + * \page bma400_api_bma400_init bma400_init + * \code + * int8_t bma400_init(struct bma400_dev *dev); + * \endcode + * @details This API reads the chip-id of the sensor which is the first step to + * verify the sensor and also it configures the read mechanism of SPI and + * I2C interface. As this API is the entry point, call this API before using other APIs. + * + * @param[in,out] dev : Structure instance of bma400_dev + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_init(struct bma400_dev *dev); + +/** + * \ingroup bma400 + * \defgroup bma400ApiData Data read out + * @brief Read our data from the sensor + */ + +/*! + * \ingroup bma400ApiData + * \page bma400_api_bma400_get_accel_data bma400_get_accel_data + * \code + * int8_t bma400_get_accel_data(uint8_t data_sel, struct bma400_sensor_data *accel, + * const struct bma400_dev *dev); + * \endcode + * @details This API is used to get the accelerometer data along with the sensor-time. + * + * @param[in] data_sel : Variable to select sensor data only + * or data along with sensortime + * @param[in,out] accel : Structure instance to store data + * @param[in] dev : Structure instance of bma400_dev + * + * Assignable macros for "data_sel" : + * @code + * - BMA400_DATA_ONLY + * - BMA400_DATA_SENSOR_TIME + * @endcode + * + * @note The accelerometer data value is in LSB, based on the range selected. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_accel_data(uint8_t data_sel, struct bma400_sensor_data *accel, struct bma400_dev *dev); + +/** + * \ingroup bma400 + * \defgroup bma400ApiConfig Configuration + * @brief Configuration API of sensor + */ + +/*! + * \ingroup bma400ApiConfig + * \page bma400_api_bma400_set_power_mode bma400_set_power_mode + * \code + * int8_t bma400_set_power_mode(uint8_t power_mode, const struct bma400_dev *dev); + * \endcode + * @details This API is used to set the power mode of the sensor. + * + * @param[in] power_mode : Macro to select power mode of the sensor. + * @param[in] dev : Structure instance of bma400_dev. + * + * Possible value for power_mode : + * @code + * BMA400_NORMAL_MODE + * BMA400_SLEEP_MODE + * BMA400_LOW_POWER_MODE + * @endcode + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_set_power_mode(uint8_t power_mode, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiConfig + * \page bma400_api_bma400_get_power_mode bma400_get_power_mode + * \code + * int8_t bma400_get_power_mode(uint8_t *power_mode, const struct bma400_dev *dev); + * \endcode + * @details This API is used to get the power mode of the sensor. + * @param[out] power_mode : power mode of the sensor. + * @param[in] dev : Structure instance of bma400_dev. + * + * * Possible value for power_mode : + * @code + * BMA400_NORMAL_MODE + * BMA400_SLEEP_MODE + * BMA400_LOW_POWER_MODE + * @endcode + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_power_mode(uint8_t *power_mode, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiConfig + * \page bma400_api_bma400_set_sensor_conf bma400_set_sensor_conf + * \code + * int8_t bma400_set_sensor_conf(const struct bma400_sensor_conf *conf, uint16_t n_sett, + * const struct bma400_dev *dev); + * \endcode + * @details This API is used to define sensor settings such as: + * - Accelerometer configuration (Like ODR,OSR,range...) + * - Tap configuration + * - Activity change configuration + * - Gen1/Gen2 configuration + * - Orientation change configuration + * - Step counter configuration + * + * @param[in] conf : Structure instance of the configuration structure + * @param[in] n_sett : Number of settings to be set + * @param[in] dev : Structure instance of bma400_dev + * + * @note Before calling this API, fill in the value of the required configurations in the conf structure + * (Examples are mentioned in the readme.md). + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_set_sensor_conf(const struct bma400_sensor_conf *conf, uint16_t n_sett, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiConfig + * \page bma400_api_bma400_get_sensor_conf bma400_get_sensor_conf + * \code + * int8_t bma400_get_sensor_conf(struct bma400_sensor_conf *conf, uint16_t n_sett, const struct bma400_dev *dev); + * \endcode + * @details This API is used to get the sensor settings like sensor + * configurations and interrupt configurations and store + * them in the corresponding structure instance. + * + * @param[in] conf : Structure instance of the configuration structure + * @param[in] n_sett : Number of settings to be obtained + * @param[in] dev : Structure instance of bma400_dev. + * + * @note Once the API is called, the settings structure will be updated in the settings structure. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_sensor_conf(struct bma400_sensor_conf *conf, uint16_t n_sett, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiConfig + * \page bma400_api_bma400_set_device_conf bma400_set_device_conf + * \code + * int8_t bma400_set_device_conf(const struct bma400_device_conf *conf, uint8_t n_sett, + * const struct bma400_dev *dev); + * \endcode + * @details This API is used to set the device specific settings like: + * - BMA400_AUTOWAKEUP_TIMEOUT + * - BMA400_AUTOWAKEUP_INT + * - BMA400_AUTO_LOW_POWER + * - BMA400_INT_PIN_CONF + * - BMA400_INT_OVERRUN_CONF + * - BMA400_FIFO_CONF + * + * @param[in] conf : Structure instance of the configuration structure. + * @param[in] n_sett : Number of settings to be set + * @param[in] dev : Structure instance of bma400_dev. + * + * @note Before calling this API, fill in the value of the required configurations in the + * conf structure(refer Examples). + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_set_device_conf(const struct bma400_device_conf *conf, uint8_t n_sett, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiConfig + * \page bma400_api_bma400_get_device_conf bma400_get_device_conf + * \code + * int8_t bma400_get_device_conf(struct bma400_device_conf *conf, uint8_t n_sett, const struct bma400_dev *dev); + * \endcode + * @details This API is used to get the device specific settings and store + * them in the corresponding structure instance. + * + * @param[in] conf : Structure instance of the configuration structure + * @param[in] n_sett : Number of settings to be obtained + * @param[in] dev : Structure instance of bma400_dev. + * + * @note Once the API is called, the settings structure will be updated + * in the settings structure. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_device_conf(struct bma400_device_conf *conf, uint8_t n_sett, struct bma400_dev *dev); + +/** + * \ingroup bma400 + * \defgroup bma400ApiFifo FIFO + * @brief Access and extract FIFO accelerometer data + */ + +/*! + * \ingroup bma400ApiFifo + * \page bma400_api_bma400_set_fifo_flush bma400_set_fifo_flush + * \code + * int8_t bma400_set_fifo_flush(const struct bma400_dev *dev); + * \endcode + * @details This API writes the fifo_flush command into command register. + * This action clears all data in the FIFO. + * + * @param[in] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_set_fifo_flush(struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiFifo + * \page bma400_api_bma400_get_fifo_data bma400_get_fifo_data + * \code + * int8_t bma400_get_fifo_data(struct bma400_fifo_data *fifo, const struct bma400_dev *dev); + * \endcode + * @details This API reads the FIFO data from the sensor. + * + * @note User has to allocate the FIFO buffer along with + * corresponding FIFO read length from his side before calling this API + * as mentioned in the readme.md + * + * @note User must specify the number of bytes to read from the FIFO in + * fifo->length , It will be updated by the number of bytes actually + * read from FIFO after calling this API + * + * @param[in,out] fifo : Pointer to the FIFO structure. + * + * @param[in,out] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_fifo_data(struct bma400_fifo_data *fifo, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiFifo + * \page bma400_api_bma400_extract_accel bma400_extract_accel + * \code + * int8_t bma400_extract_accel(struct bma400_fifo_data *fifo, struct bma400_fifo_sensor_data *accel_data, + * uint16_t *frame_count, const struct bma400_dev *dev); + * \endcode + * @details This API parses and extracts the accelerometer frames, FIFO time + * and control frames from FIFO data read by the "bma400_get_fifo_data" API + * and stores it in the "accel_data" structure instance. + * + * @note The bma400_extract_accel API should be called only after + * reading the FIFO data by calling the bma400_get_fifo_data() API + * Please refer the readme.md for usage. + * + * @param[in,out] fifo : Pointer to the FIFO structure. + * + * @param[out] accel_data : Structure instance of bma400_fifo_sensor_data where + * the accelerometer data from FIFO is extracted + * and stored after calling this API + * + * @param[in,out] frame_count : Number of valid accelerometer frames requested + * by user is given as input and it is updated by + * the actual frames parsed from the FIFO + * + * @param[in] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_extract_accel(struct bma400_fifo_data *fifo, + struct bma400_fifo_sensor_data *accel_data, + uint16_t *frame_count, + const struct bma400_dev *dev); + +/** + * \ingroup bma400 + * \defgroup bma400ApiInterrupt Interrupt + * @brief Interrupt API + */ + +/*! + * \ingroup bma400ApiInterrupt + * \page bma400_api_bma400_get_interrupt_status bma400_get_interrupt_status + * \code + * int8_t bma400_get_interrupt_status(uint16_t *int_status, const struct bma400_dev *dev); + * \endcode + * @details This API is used to check if the interrupts are asserted and return the status. + * + * @param[in] int_status : Interrupt status of sensor + * @param[in] dev : Structure instance of bma400_dev. + * + * @note Interrupt status of the sensor determines which all interrupts are asserted at any instant of time. + * @code + * BMA400_WAKEUP_INT_ASSERTED + * BMA400_ORIENT_CH_INT_ASSERTED + * BMA400_GEN1_INT_ASSERTED + * BMA400_GEN2_INT_ASSERTED + * BMA400_FIFO_FULL_INT_ASSERTED + * BMA400_FIFO_WM_INT_ASSERTED + * BMA400_DRDY_INT_ASSERTED + * BMA400_INT_OVERRUN_ASSERTED + * BMA400_STEP_INT_ASSERTED + * BMA400_S_TAP_INT_ASSERTED + * BMA400_D_TAP_INT_ASSERTED + * BMA400_ACT_CH_X_ASSERTED + * BMA400_ACT_CH_Y_ASSERTED + * BMA400_ACT_CH_Z_ASSERTED + *@endcode + * @note Call the API and then use the above macros to check whether the interrupt is asserted or not. + *@code + * if (int_status & BMA400_FIFO_FULL_INT_ASSERTED) { + * printf("\n FIFO FULL INT ASSERTED"); + * } + *@endcode + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_interrupt_status(uint16_t *int_status, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiInterrupt + * \page bma400_api_bma400_get_interrupts_enabled bma400_get_interrupts_enabled + * \code + * int8_t bma400_get_interrupts_enabled(struct bma400_int_enable *int_select, uint8_t n_sett, + * const struct bma400_dev *dev); + * \endcode + * @details This API is used to get the enable/disable status of the various interrupts. + * + * @param[in] int_select : Structure to select specific interrupts + * @param[in] n_sett : Number of interrupt settings enabled / disabled + * @param[in] dev : Structure instance of bma400_dev. + * + * @note Select the needed interrupt type for which the status of it whether + * it is enabled/disabled is to be known in the int_select->int_sel, and the + * output is stored in int_select->conf either as BMA400_ENABLE/BMA400_DISABLE + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_interrupts_enabled(struct bma400_int_enable *int_select, uint8_t n_sett, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiInterrupt + * \page bma400_api_bma400_enable_interrupt bma400_enable_interrupt + * \code + * int8_t bma400_enable_interrupt(const struct bma400_int_enable *int_select, uint8_t n_sett, + * const struct bma400_dev *dev); + * \endcode + * @details This API is used to enable the various interrupts. + * + * @param[in] int_select : Structure to enable specific interrupts + * @param[in] n_sett : Number of interrupt settings enabled / disabled + * @param[in] dev : Structure instance of bma400_dev. + * + * @note Multiple interrupt can be enabled/disabled by + * @code + * struct interrupt_enable int_select[2]; + * + * int_select[0].int_sel = BMA400_FIFO_FULL_INT_EN; + * int_select[0].conf = BMA400_ENABLE; + * + * int_select[1].int_sel = BMA400_FIFO_WM_INT_EN; + * int_select[1].conf = BMA400_ENABLE; + * + * rslt = bma400_enable_interrupt(&int_select, 2, dev); + *@endcode + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_enable_interrupt(const struct bma400_int_enable *int_select, uint8_t n_sett, struct bma400_dev *dev); + +/** + * \ingroup bma400 + * \defgroup bma400ApiRegister Registers + * @brief Generic API for accessing sensor registers + */ + +/*! + * \ingroup bma400ApiRegister + * \page bma400_api_bma400_set_regs bma400_set_regs + * \code + * int8_t bma400_set_regs(uint8_t reg_addr, uint8_t *reg_data, uint8_t len, const struct bma400_dev *dev); + * \endcode + * @details This API writes the given data to the register address of the sensor. + * + * @param[in] reg_addr : Register address from where the data to be written. + * @param[in] reg_data : Pointer to data buffer which is to be written + * in the reg_addr of sensor. + * @param[in] len : No of bytes of data to write.. + * @param[in] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_set_regs(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiRegister + * \page bma400_api_bma400_get_regs bma400_get_regs + * \code + * int8_t bma400_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint8_t len, const struct bma400_dev *dev); + * \endcode + * @details This API reads the data from the given register address of sensor. + * + * @param[in] reg_addr : Register address from where the data to be read + * @param[out] reg_data : Pointer to data buffer to store the read data. + * @param[in] len : No of bytes of data to be read. + * @param[in] dev : Structure instance of bma400_dev. + * + * @note Auto increment applies to most of the registers, with the + * exception of a few registers that trap the address. For e.g., + * Register address - 0x14(BMA400_FIFO_DATA_ADDR) + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, struct bma400_dev *dev); + +/** + * \ingroup bma400 + * \defgroup bma400ApiSystem System + * @brief API that performs system-level operations + */ + +/*! + * \ingroup bma400ApiSystem + * \page bma400_api_bma400_soft_reset bma400_soft_reset + * \code + * int8_t bma400_soft_reset(const struct bma400_dev *dev); + * \endcode + * @details This API soft-resets the sensor where all the registers are reset to their default values except 0x4B. + * + * @param[in] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_soft_reset(struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiSystem + * \page bma400_api_bma400_perform_self_test bma400_perform_self_test + * \code + * int8_t bma400_perform_self_test(const struct bma400_dev *dev); + * \endcode + * @details This API performs a self test of the accelerometer in BMA400. + * + * @param[in] dev : Structure instance of bma400_dev. + * + * @note The return value of this API is the result of self test. + * A self test does not soft reset of the sensor. Hence, the user can + * define the required settings after performing the self test. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_perform_self_test(struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiSystem + * \page bma400_api_bma400_get_temperature_data bma400_get_temperature_data + * \code + * int8_t bma400_get_temperature_data(int16_t *temperature_data, const struct bma400_dev *dev); + * \endcode + * @details This API is used to get the raw temperature data output. + * + * @note Temperature data output must be divided by a factor of 10 + * Consider temperature_data = 195 , + * Then the actual temperature is 19.5 degree Celsius. + * + * @param[in,out] temperature_data : Temperature data + * @param[in] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_temperature_data(int16_t *temperature_data, struct bma400_dev *dev); + +/** + * \ingroup bma400 + * \defgroup bma400ApiSc Step counter + * @brief Step counter feature + */ + +/*! + * \ingroup bma400ApiSc + * \page bma400_api_bma400_set_step_counter_param bma400_set_step_counter_param + * \code + * int8_t bma400_set_step_counter_param(uint8_t *sccr_conf, const struct bma400_dev *dev); + * \endcode + * @details This API is used to set the step counter's configuration parameters from the registers 0x59 to 0x70. + * + *@verbatim + *---------------------------------------------------------------------- + * Register name Address wrist(default) non-wrist + *---------------------------------------------------------------------- + * STEP_COUNTER_CONFIG0 0x59 1 1 + * STEP_COUNTER_CONFIG1 0x5A 45 50 + * STEP_COUNTER_CONFIG2 0x5B 123 120 + * STEP_COUNTER_CONFIG3 0x5C 212 230 + * STEP_COUNTER_CONFIG4 0x5D 68 135 + * STEP_COUNTER_CONFIG5 0x5E 1 0 + * STEP_COUNTER_CONFIG6 0x5F 59 132 + * STEP_COUNTER_CONFIG7 0x60 122 108 + * STEP_COUNTER_CONFIG8 0x61 219 156 + * STEP_COUNTER_CONFIG9 0x62 123 117 + * STEP_COUNTER_CONFIG10 0x63 63 100 + * STEP_COUNTER_CONFIG11 0x64 108 126 + * STEP_COUNTER_CONFIG12 0x65 205 170 + * STEP_COUNTER_CONFIG13 0x66 39 12 + * STEP_COUNTER_CONFIG14 0x67 25 12 + * STEP_COUNTER_CONFIG15 0x68 150 74 + * STEP_COUNTER_CONFIG16 0x69 160 160 + * STEP_COUNTER_CONFIG17 0x6A 195 0 + * STEP_COUNTER_CONFIG18 0x6B 14 0 + * STEP_COUNTER_CONFIG19 0x6C 12 12 + * STEP_COUNTER_CONFIG20 0x6D 60 60 + * STEP_COUNTER_CONFIG21 0x6E 240 240 + * STEP_COUNTER_CONFIG22 0x6F 0 1 + * STEP_COUNTER_CONFIG23 0x70 247 0 + *------------------------------------------------------------------------ + *@endverbatim + * + * @param[in] sccr_conf : sc config parameter + * @param[in] dev : Structure instance of bma400_dev. + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_set_step_counter_param(const uint8_t *sccr_conf, struct bma400_dev *dev); + +/*! + * \ingroup bma400ApiSc + * \page bma400_api_bma400_get_steps_counted bma400_get_steps_counted + * \code + * int8_t bma400_get_steps_counted(uint32_t *step_count, uint8_t *activity_data, const struct bma400_dev *dev); + * \endcode + * @details This API is used to get the step counter output in form of number of steps in the step_count value. + * + * @param[out] step_count : Number of step counts + * @param[out] activity_data : Activity data WALK/STILL/RUN + * @param[in] dev : Structure instance of bma400_dev. + * + * activity_data | Status + * -----------------|------------------ + * 0x00 | BMA400_STILL_ACT + * 0x01 | BMA400_WALK_ACT + * 0x02 | BMA400_RUN_ACT + * + * @return Result of API execution status. + * @retval zero -> Success + * @retval +ve value -> Warning + * @retval -ve value -> Error + */ +int8_t bma400_get_steps_counted(uint32_t *step_count, uint8_t *activity_data, struct bma400_dev *dev); + +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* BMA400_H__ */ diff --git a/user/tests/app/ctub_plus_power_test/bma400_defs.h b/user/tests/app/ctub_plus_power_test/bma400_defs.h new file mode 100644 index 0000000000..671261fe7c --- /dev/null +++ b/user/tests/app/ctub_plus_power_test/bma400_defs.h @@ -0,0 +1,1441 @@ +/** +* Copyright (c) 2024 Bosch Sensortec GmbH. All rights reserved. +* +* BSD-3-Clause +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* 3. Neither the name of the copyright holder nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* @file bma400_defs.h +* @date 2024-05-10 +* @version v1.5.10 +* +*/ + +/*! @cond DOXYGEN_BMA400_DEFS_H_ */ + +#ifndef BMA400_DEFS_H_ +#define BMA400_DEFS_H_ + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#endif + +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) S8_C(x) +#define UINT8_C(x) U8_C(x) +#endif + +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) S16_C(x) +#define UINT16_C(x) U16_C(x) +#endif + +#if !defined(INT32_C) && !defined(UINT32_C) +#define INT32_C(x) S32_C(x) +#define UINT32_C(x) U32_C(x) +#endif + +#if !defined(INT64_C) && !defined(UINT64_C) +#define INT64_C(x) S64_C(x) +#define UINT64_C(x) U64_C(x) +#endif + +/* C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *) 0) +#endif +#endif + +#ifndef TRUE +#define TRUE UINT8_C(1) +#endif + +#ifndef FALSE +#define FALSE UINT8_C(0) +#endif + +/*! + * BMA400_INTF_RET_TYPE is the read/write interface return type which can be overwritten by the build system. + * The default is set to int8_t. + */ +#ifndef BMA400_INTF_RET_TYPE +#define BMA400_INTF_RET_TYPE int8_t +#endif + +/*! + * BMA400_INTF_RET_SUCCESS is the success return value read/write interface return type which can be + * overwritten by the build system. The default is set to 0. + */ +#ifndef BMA400_INTF_RET_SUCCESS +#define BMA400_INTF_RET_SUCCESS INT8_C(0) +#endif + +/* API success code */ +#define BMA400_OK INT8_C(0) + +/* API error codes */ +#define BMA400_E_NULL_PTR INT8_C(-1) +#define BMA400_E_COM_FAIL INT8_C(-2) +#define BMA400_E_DEV_NOT_FOUND INT8_C(-3) +#define BMA400_E_INVALID_CONFIG INT8_C(-4) + +/* API warning codes */ +#define BMA400_W_SELF_TEST_FAIL INT8_C(1) + +/* CHIP ID VALUE */ +#define BMA400_CHIP_ID UINT8_C(0x90) + +/* BMA400 I2C address macros */ +#define BMA400_I2C_ADDRESS_SDO_LOW UINT8_C(0x14) +#define BMA400_I2C_ADDRESS_SDO_HIGH UINT8_C(0x15) + +/* Maximum read length */ +#define BMA400_MAX_LEN UINT8_C(128) + +/* Power mode configurations */ +#define BMA400_MODE_NORMAL UINT8_C(0x02) +#define BMA400_MODE_SLEEP UINT8_C(0x00) +#define BMA400_MODE_LOW_POWER UINT8_C(0x01) + +/* Enable / Disable macros */ +#define BMA400_DISABLE UINT8_C(0) +#define BMA400_ENABLE UINT8_C(1) + +/* Data/sensortime selection macros */ +#define BMA400_DATA_ONLY UINT8_C(0x00) +#define BMA400_DATA_SENSOR_TIME UINT8_C(0x01) + +/* ODR configurations */ +#define BMA400_ODR_12_5HZ UINT8_C(0x05) +#define BMA400_ODR_25HZ UINT8_C(0x06) +#define BMA400_ODR_50HZ UINT8_C(0x07) +#define BMA400_ODR_100HZ UINT8_C(0x08) +#define BMA400_ODR_200HZ UINT8_C(0x09) +#define BMA400_ODR_400HZ UINT8_C(0x0A) +#define BMA400_ODR_800HZ UINT8_C(0x0B) + +/* Accel Range configuration */ +#define BMA400_RANGE_2G UINT8_C(0x00) +#define BMA400_RANGE_4G UINT8_C(0x01) +#define BMA400_RANGE_8G UINT8_C(0x02) +#define BMA400_RANGE_16G UINT8_C(0x03) + +/* Accel Axes selection settings for + * DATA SAMPLING, WAKEUP, ORIENTATION CHANGE, + * GEN1, GEN2 , ACTIVITY CHANGE + */ +#define BMA400_AXIS_X_EN UINT8_C(0x01) +#define BMA400_AXIS_Y_EN UINT8_C(0x02) +#define BMA400_AXIS_Z_EN UINT8_C(0x04) +#define BMA400_AXIS_XYZ_EN UINT8_C(0x07) + +/* Accel filter(data_src_reg) selection settings */ +#define BMA400_DATA_SRC_ACCEL_FILT_1 UINT8_C(0x00) +#define BMA400_DATA_SRC_ACCEL_FILT_2 UINT8_C(0x01) +#define BMA400_DATA_SRC_ACCEL_FILT_LP UINT8_C(0x02) + +/* Accel OSR (OSR,OSR_LP) settings */ +#define BMA400_ACCEL_OSR_SETTING_0 UINT8_C(0x00) +#define BMA400_ACCEL_OSR_SETTING_1 UINT8_C(0x01) +#define BMA400_ACCEL_OSR_SETTING_2 UINT8_C(0x02) +#define BMA400_ACCEL_OSR_SETTING_3 UINT8_C(0x03) + +/* Accel filt1_bw settings */ +/* Accel filt1_bw = 0.48 * ODR */ +#define BMA400_ACCEL_FILT1_BW_0 UINT8_C(0x00) + +/* Accel filt1_bw = 0.24 * ODR */ +#define BMA400_ACCEL_FILT1_BW_1 UINT8_C(0x01) + +/* Auto wake-up timeout value of 10.24s */ +#define BMA400_TIMEOUT_MAX_AUTO_WAKEUP UINT16_C(0x0FFF) + +/* Auto low power timeout value of 10.24s */ +#define BMA400_TIMEOUT_MAX_AUTO_LP UINT16_C(0x0FFF) + +/* Reference Update macros */ +#define BMA400_UPDATE_MANUAL UINT8_C(0x00) +#define BMA400_UPDATE_ONE_TIME UINT8_C(0x01) +#define BMA400_UPDATE_EVERY_TIME UINT8_C(0x02) +#define BMA400_UPDATE_LP_EVERY_TIME UINT8_C(0x03) + +/* Reference Update macros for orient interrupts */ +#define BMA400_ORIENT_REFU_ACC_FILT_2 UINT8_C(0x01) +#define BMA400_ORIENT_REFU_ACC_FILT_LP UINT8_C(0x02) + +/* Number of samples needed for Auto-wakeup interrupt evaluation */ +#define BMA400_SAMPLE_COUNT_1 UINT8_C(0x00) +#define BMA400_SAMPLE_COUNT_2 UINT8_C(0x01) +#define BMA400_SAMPLE_COUNT_3 UINT8_C(0x02) +#define BMA400_SAMPLE_COUNT_4 UINT8_C(0x03) +#define BMA400_SAMPLE_COUNT_5 UINT8_C(0x04) +#define BMA400_SAMPLE_COUNT_6 UINT8_C(0x05) +#define BMA400_SAMPLE_COUNT_7 UINT8_C(0x06) +#define BMA400_SAMPLE_COUNT_8 UINT8_C(0x07) + +/* Auto low power configurations */ +/* Auto low power timeout disabled */ +#define BMA400_AUTO_LP_TIMEOUT_DISABLE UINT8_C(0x00) + +/* Auto low power entered on drdy interrupt */ +#define BMA400_AUTO_LP_DRDY_TRIGGER UINT8_C(0x01) + +/* Auto low power entered on GEN1 interrupt */ +#define BMA400_AUTO_LP_GEN1_TRIGGER UINT8_C(0x02) + +/* Auto low power entered on timeout of threshold value */ +#define BMA400_AUTO_LP_TIMEOUT_EN UINT8_C(0x04) + +/* Auto low power entered on timeout of threshold value + * but reset on activity detection + */ +#define BMA400_AUTO_LP_TIME_RESET_EN UINT8_C(0x08) + +/* TAP INTERRUPT CONFIG MACROS */ +/* Axes select for TAP interrupt */ +#define BMA400_TAP_X_AXIS_EN UINT8_C(0x02) +#define BMA400_TAP_Y_AXIS_EN UINT8_C(0x01) +#define BMA400_TAP_Z_AXIS_EN UINT8_C(0x00) + +/* TAP tics_th setting */ + +/* Maximum time between upper and lower peak of a tap, in data samples + * this time depends on the mechanics of the device tapped onto + * default = 12 samples + */ + +/* Configures 6 data samples for high-low tap signal change time */ +#define BMA400_TICS_TH_6_DATA_SAMPLES UINT8_C(0x00) + +/* Configures 9 data samples for high-low tap signal change time */ +#define BMA400_TICS_TH_9_DATA_SAMPLES UINT8_C(0x01) + +/* Configures 12 data samples for high-low tap signal change time */ +#define BMA400_TICS_TH_12_DATA_SAMPLES UINT8_C(0x02) + +/* Configures 18 data samples for high-low tap signal change time */ +#define BMA400_TICS_TH_18_DATA_SAMPLES UINT8_C(0x03) + +/* TAP Sensitivity setting */ +/* It modifies the threshold for minimum TAP amplitude */ +/* BMA400_TAP_SENSITIVITY_0 correspond to highest sensitivity */ +#define BMA400_TAP_SENSITIVITY_0 UINT8_C(0x00) +#define BMA400_TAP_SENSITIVITY_1 UINT8_C(0x01) +#define BMA400_TAP_SENSITIVITY_2 UINT8_C(0x02) +#define BMA400_TAP_SENSITIVITY_3 UINT8_C(0x03) +#define BMA400_TAP_SENSITIVITY_4 UINT8_C(0x04) +#define BMA400_TAP_SENSITIVITY_5 UINT8_C(0x05) +#define BMA400_TAP_SENSITIVITY_6 UINT8_C(0x06) + +/* BMA400_TAP_SENSITIVITY_7 correspond to lowest sensitivity */ +#define BMA400_TAP_SENSITIVITY_7 UINT8_C(0x07) + +/* BMA400 TAP - quiet settings */ + +/* Quiet refers to minimum quiet time before and after double tap, + * in the data samples This time also defines the longest time interval + * between two taps so that they are considered as double tap + */ + +/* Configures 60 data samples quiet time between single or double taps */ +#define BMA400_QUIET_60_DATA_SAMPLES UINT8_C(0x00) + +/* Configures 80 data samples quiet time between single or double taps */ +#define BMA400_QUIET_80_DATA_SAMPLES UINT8_C(0x01) + +/* Configures 100 data samples quiet time between single or double taps */ +#define BMA400_QUIET_100_DATA_SAMPLES UINT8_C(0x02) + +/* Configures 120 data samples quiet time between single or double taps */ +#define BMA400_QUIET_120_DATA_SAMPLES UINT8_C(0x03) + +/* BMA400 TAP - quiet_dt settings */ + +/* quiet_dt refers to Minimum time between the two taps of a + * double tap, in data samples + */ + +/* Configures 4 data samples minimum time between double taps */ +#define BMA400_QUIET_DT_4_DATA_SAMPLES UINT8_C(0x00) + +/* Configures 8 data samples minimum time between double taps */ +#define BMA400_QUIET_DT_8_DATA_SAMPLES UINT8_C(0x01) + +/* Configures 12 data samples minimum time between double taps */ +#define BMA400_QUIET_DT_12_DATA_SAMPLES UINT8_C(0x02) + +/* Configures 16 data samples minimum time between double taps */ +#define BMA400_QUIET_DT_16_DATA_SAMPLES UINT8_C(0x03) + +/* ACTIVITY CHANGE CONFIG MACROS */ +/* Data source for activity change detection */ +#define BMA400_DATA_SRC_ACC_FILT1 UINT8_C(0x00) +#define BMA400_DATA_SRC_ACC_FILT2 UINT8_C(0x01) + +/* Number of samples to evaluate for activity change detection */ +#define BMA400_ACT_CH_SAMPLE_CNT_32 UINT8_C(0x00) +#define BMA400_ACT_CH_SAMPLE_CNT_64 UINT8_C(0x01) +#define BMA400_ACT_CH_SAMPLE_CNT_128 UINT8_C(0x02) +#define BMA400_ACT_CH_SAMPLE_CNT_256 UINT8_C(0x03) +#define BMA400_ACT_CH_SAMPLE_CNT_512 UINT8_C(0x04) + +/* Interrupt pin configuration macros */ +#define BMA400_INT_PUSH_PULL_ACTIVE_0 UINT8_C(0x00) +#define BMA400_INT_PUSH_PULL_ACTIVE_1 UINT8_C(0x01) +#define BMA400_INT_OPEN_DRIVE_ACTIVE_0 UINT8_C(0x02) +#define BMA400_INT_OPEN_DRIVE_ACTIVE_1 UINT8_C(0x03) + +/* Interrupt Assertion status macros */ +#define BMA400_ASSERTED_WAKEUP_INT UINT16_C(0x0001) +#define BMA400_ASSERTED_ORIENT_CH UINT16_C(0x0002) +#define BMA400_ASSERTED_GEN1_INT UINT16_C(0x0004) +#define BMA400_ASSERTED_GEN2_INT UINT16_C(0x0008) +#define BMA400_ASSERTED_INT_OVERRUN UINT16_C(0x0010) +#define BMA400_ASSERTED_FIFO_FULL_INT UINT16_C(0x0020) +#define BMA400_ASSERTED_FIFO_WM_INT UINT16_C(0x0040) +#define BMA400_ASSERTED_DRDY_INT UINT16_C(0x0080) +#define BMA400_ASSERTED_STEP_INT UINT16_C(0x0300) +#define BMA400_ASSERTED_S_TAP_INT UINT16_C(0x0400) +#define BMA400_ASSERTED_D_TAP_INT UINT16_C(0x0800) +#define BMA400_ASSERTED_ACT_CH_X UINT16_C(0x2000) +#define BMA400_ASSERTED_ACT_CH_Y UINT16_C(0x4000) +#define BMA400_ASSERTED_ACT_CH_Z UINT16_C(0x8000) + +/* Generic interrupt criterion_sel configuration macros */ +#define BMA400_ACTIVITY_INT UINT8_C(0x01) +#define BMA400_INACTIVITY_INT UINT8_C(0x00) + +/* Generic interrupt axes evaluation logic configuration macros */ +#define BMA400_ALL_AXES_INT UINT8_C(0x01) +#define BMA400_ANY_AXES_INT UINT8_C(0x00) + +/* Generic interrupt hysteresis configuration macros */ +#define BMA400_HYST_0_MG UINT8_C(0x00) +#define BMA400_HYST_24_MG UINT8_C(0x01) +#define BMA400_HYST_48_MG UINT8_C(0x02) +#define BMA400_HYST_96_MG UINT8_C(0x03) + +/* BMA400 Register Address */ +#define BMA400_REG_CHIP_ID UINT8_C(0x00) +#define BMA400_REG_STATUS UINT8_C(0x03) +#define BMA400_REG_ACCEL_DATA UINT8_C(0x04) +#define BMA400_REG_INT_STAT0 UINT8_C(0x0E) +#define BMA400_REG_TEMP_DATA UINT8_C(0x11) +#define BMA400_REG_FIFO_LENGTH UINT8_C(0x12) +#define BMA400_REG_FIFO_DATA UINT8_C(0x14) +#define BMA400_REG_STEP_CNT_0 UINT8_C(0x15) +#define BMA400_REG_ACCEL_CONFIG_0 UINT8_C(0x19) +#define BMA400_REG_ACCEL_CONFIG_1 UINT8_C(0x1A) +#define BMA400_REG_ACCEL_CONFIG_2 UINT8_C(0x1B) +#define BMA400_REG_INT_CONF_0 UINT8_C(0x1F) +#define BMA400_REG_INT_12_IO_CTRL UINT8_C(0x24) +#define BMA400_REG_INT_MAP UINT8_C(0x21) +#define BMA400_REG_FIFO_CONFIG_0 UINT8_C(0x26) +#define BMA400_REG_FIFO_READ_EN UINT8_C(0x29) +#define BMA400_REG_AUTO_LOW_POW_0 UINT8_C(0x2A) +#define BMA400_REG_AUTO_LOW_POW_1 UINT8_C(0x2B) +#define BMA400_REG_AUTOWAKEUP_0 UINT8_C(0x2C) +#define BMA400_REG_AUTOWAKEUP_1 UINT8_C(0x2D) +#define BMA400_REG_WAKEUP_INT_CONF_0 UINT8_C(0x2F) +#define BMA400_REG_ORIENTCH_INT_CONFIG UINT8_C(0x35) +#define BMA400_REG_GEN1_INT_CONFIG UINT8_C(0x3F) +#define BMA400_REG_GEN2_INT_CONFIG UINT8_C(0x4A) +#define BMA400_REG_ACT_CH_CONFIG_0 UINT8_C(0x55) +#define BMA400_REG_TAP_CONFIG UINT8_C(0x57) +#define BMA400_REG_SELF_TEST UINT8_C(0x7D) +#define BMA400_REG_COMMAND UINT8_C(0x7E) + +/* BMA400 Command register */ +#define BMA400_SOFT_RESET_CMD UINT8_C(0xB6) +#define BMA400_FIFO_FLUSH_CMD UINT8_C(0xB0) + +/* BMA400 Delay definitions */ +#define BMA400_DELAY_US_SOFT_RESET UINT8_C(5000) +#define BMA400_DELAY_US_SELF_TEST UINT8_C(7000) +#define BMA400_DELAY_US_SELF_TEST_DATA_READ UINT8_C(50000) + +/* Interface selection macro */ +#define BMA400_SPI_WR_MASK UINT8_C(0x7F) +#define BMA400_SPI_RD_MASK UINT8_C(0x80) + +/* UTILITY MACROS */ +#define BMA400_SET_LOW_BYTE UINT16_C(0x00FF) +#define BMA400_SET_HIGH_BYTE UINT16_C(0xFF00) + +/* Interrupt mapping selection */ +#define BMA400_DATA_READY_INT_MAP UINT8_C(0x01) +#define BMA400_FIFO_WM_INT_MAP UINT8_C(0x02) +#define BMA400_FIFO_FULL_INT_MAP UINT8_C(0x03) +#define BMA400_GEN2_INT_MAP UINT8_C(0x04) +#define BMA400_GEN1_INT_MAP UINT8_C(0x05) +#define BMA400_ORIENT_CH_INT_MAP UINT8_C(0x06) +#define BMA400_WAKEUP_INT_MAP UINT8_C(0x07) +#define BMA400_ACT_CH_INT_MAP UINT8_C(0x08) +#define BMA400_TAP_INT_MAP UINT8_C(0x09) +#define BMA400_STEP_INT_MAP UINT8_C(0x0A) +#define BMA400_INT_OVERRUN_MAP UINT8_C(0x0B) + +/* BMA400 FIFO configurations */ +#define BMA400_FIFO_AUTO_FLUSH UINT8_C(0x01) +#define BMA400_FIFO_STOP_ON_FULL UINT8_C(0x02) +#define BMA400_FIFO_TIME_EN UINT8_C(0x04) +#define BMA400_FIFO_DATA_SRC UINT8_C(0x08) +#define BMA400_FIFO_8_BIT_EN UINT8_C(0x10) +#define BMA400_FIFO_X_EN UINT8_C(0x20) +#define BMA400_FIFO_Y_EN UINT8_C(0x40) +#define BMA400_FIFO_Z_EN UINT8_C(0x80) + +/* BMA400 FIFO data configurations */ +#define BMA400_FIFO_EN_X UINT8_C(0x01) +#define BMA400_FIFO_EN_Y UINT8_C(0x02) +#define BMA400_FIFO_EN_Z UINT8_C(0x04) +#define BMA400_FIFO_EN_XY UINT8_C(0x03) +#define BMA400_FIFO_EN_YZ UINT8_C(0x06) +#define BMA400_FIFO_EN_XZ UINT8_C(0x05) +#define BMA400_FIFO_EN_XYZ UINT8_C(0x07) + +/* BMA400 Self test configurations */ +#define BMA400_SELF_TEST_DISABLE UINT8_C(0x00) +#define BMA400_SELF_TEST_ENABLE_POSITIVE UINT8_C(0x07) +#define BMA400_SELF_TEST_ENABLE_NEGATIVE UINT8_C(0x0F) + +/* BMA400 FIFO data masks */ +#define BMA400_FIFO_HEADER_MASK UINT8_C(0x3E) +#define BMA400_FIFO_BYTES_OVERREAD UINT8_C(100) +#define BMA400_AWIDTH_MASK UINT8_C(0xEF) +#define BMA400_FIFO_DATA_EN_MASK UINT8_C(0x0E) + +/* BMA400 Step status field - Activity status */ +#define BMA400_STILL_ACT UINT8_C(0x00) +#define BMA400_WALK_ACT UINT8_C(0x01) +#define BMA400_RUN_ACT UINT8_C(0x02) + +/* It is inserted when FIFO_CONFIG0.fifo_data_src + * is changed during the FIFO read + */ +#define BMA400_FIFO_CONF0_CHANGE UINT8_C(0x01) + +/* It is inserted when ACC_CONFIG0.filt1_bw + * is changed during the FIFO read + */ +#define BMA400_ACCEL_CONF0_CHANGE UINT8_C(0x02) + +/* It is inserted when ACC_CONFIG1.acc_range + * acc_odr or osr is changed during the FIFO read + */ +#define BMA400_ACCEL_CONF1_CHANGE UINT8_C(0x04) + +/* Accel width setting either 12/8 bit mode */ +#define BMA400_12_BIT_FIFO_DATA UINT8_C(0x01) +#define BMA400_8_BIT_FIFO_DATA UINT8_C(0x00) + +/* BMA400 FIFO header configurations */ +#define BMA400_FIFO_SENSOR_TIME UINT8_C(0xA0) +#define BMA400_FIFO_EMPTY_FRAME UINT8_C(0x80) +#define BMA400_FIFO_CONTROL_FRAME UINT8_C(0x48) +#define BMA400_FIFO_XYZ_ENABLE UINT8_C(0x8E) +#define BMA400_FIFO_X_ENABLE UINT8_C(0x82) +#define BMA400_FIFO_Y_ENABLE UINT8_C(0x84) +#define BMA400_FIFO_Z_ENABLE UINT8_C(0x88) +#define BMA400_FIFO_XY_ENABLE UINT8_C(0x86) +#define BMA400_FIFO_YZ_ENABLE UINT8_C(0x8C) +#define BMA400_FIFO_XZ_ENABLE UINT8_C(0x8A) + +/* BMA400 bit mask definitions */ +#define BMA400_POWER_MODE_STATUS_MSK UINT8_C(0x06) +#define BMA400_POWER_MODE_STATUS_POS UINT8_C(1) + +#define BMA400_POWER_MODE_MSK UINT8_C(0x03) + +#define BMA400_ACCEL_ODR_MSK UINT8_C(0x0F) + +#define BMA400_ACCEL_RANGE_MSK UINT8_C(0xC0) +#define BMA400_ACCEL_RANGE_POS UINT8_C(6) + +#define BMA400_DATA_FILTER_MSK UINT8_C(0x0C) +#define BMA400_DATA_FILTER_POS UINT8_C(2) + +#define BMA400_OSR_MSK UINT8_C(0x30) +#define BMA400_OSR_POS UINT8_C(4) + +#define BMA400_OSR_LP_MSK UINT8_C(0x60) +#define BMA400_OSR_LP_POS UINT8_C(5) + +#define BMA400_FILT_1_BW_MSK UINT8_C(0x80) +#define BMA400_FILT_1_BW_POS UINT8_C(7) + +#define BMA400_WAKEUP_TIMEOUT_MSK UINT8_C(0x04) +#define BMA400_WAKEUP_TIMEOUT_POS UINT8_C(2) + +#define BMA400_WAKEUP_THRES_LSB_MSK UINT16_C(0x000F) + +#define BMA400_WAKEUP_THRES_MSB_MSK UINT16_C(0x0FF0) +#define BMA400_WAKEUP_THRES_MSB_POS UINT8_C(4) + +#define BMA400_WAKEUP_TIMEOUT_THRES_MSK UINT8_C(0xF0) +#define BMA400_WAKEUP_TIMEOUT_THRES_POS UINT8_C(4) + +#define BMA400_WAKEUP_INTERRUPT_MSK UINT8_C(0x02) +#define BMA400_WAKEUP_INTERRUPT_POS UINT8_C(1) + +#define BMA400_AUTO_LOW_POW_MSK UINT8_C(0x0F) + +#define BMA400_AUTO_LP_THRES_MSK UINT16_C(0x0FF0) +#define BMA400_AUTO_LP_THRES_POS UINT8_C(4) + +#define BMA400_AUTO_LP_THRES_LSB_MSK UINT16_C(0x000F) + +#define BMA400_WKUP_REF_UPDATE_MSK UINT8_C(0x03) + +#define BMA400_AUTO_LP_TIMEOUT_LSB_MSK UINT8_C(0xF0) +#define BMA400_AUTO_LP_TIMEOUT_LSB_POS UINT8_C(4) + +#define BMA400_SAMPLE_COUNT_MSK UINT8_C(0x1C) +#define BMA400_SAMPLE_COUNT_POS UINT8_C(2) + +#define BMA400_WAKEUP_EN_AXES_MSK UINT8_C(0xE0) +#define BMA400_WAKEUP_EN_AXES_POS UINT8_C(5) + +#define BMA400_TAP_AXES_EN_MSK UINT8_C(0x18) +#define BMA400_TAP_AXES_EN_POS UINT8_C(3) + +#define BMA400_TAP_QUIET_DT_MSK UINT8_C(0x30) +#define BMA400_TAP_QUIET_DT_POS UINT8_C(4) + +#define BMA400_TAP_QUIET_MSK UINT8_C(0x0C) +#define BMA400_TAP_QUIET_POS UINT8_C(2) + +#define BMA400_TAP_TICS_TH_MSK UINT8_C(0x03) + +#define BMA400_TAP_SENSITIVITY_MSK UINT8_C(0X07) + +#define BMA400_ACT_CH_AXES_EN_MSK UINT8_C(0xE0) +#define BMA400_ACT_CH_AXES_EN_POS UINT8_C(5) + +#define BMA400_ACT_CH_DATA_SRC_MSK UINT8_C(0x10) +#define BMA400_ACT_CH_DATA_SRC_POS UINT8_C(4) + +#define BMA400_ACT_CH_NPTS_MSK UINT8_C(0x0F) + +#define BMA400_INT_AXES_EN_MSK UINT8_C(0xE0) +#define BMA400_INT_AXES_EN_POS UINT8_C(5) + +#define BMA400_INT_DATA_SRC_MSK UINT8_C(0x10) +#define BMA400_INT_DATA_SRC_POS UINT8_C(4) + +#define BMA400_INT_REFU_MSK UINT8_C(0x0C) +#define BMA400_INT_REFU_POS UINT8_C(2) + +#define BMA400_INT_HYST_MSK UINT8_C(0x03) + +#define BMA400_GEN_INT_COMB_MSK UINT8_C(0x01) + +#define BMA400_GEN_INT_CRITERION_MSK UINT8_C(0x02) +#define BMA400_GEN_INT_CRITERION_POS UINT8_C(0x01) + +#define BMA400_INT_PIN1_CONF_MSK UINT8_C(0x06) +#define BMA400_INT_PIN1_CONF_POS UINT8_C(1) + +#define BMA400_INT_PIN2_CONF_MSK UINT8_C(0x60) +#define BMA400_INT_PIN2_CONF_POS UINT8_C(5) + +#define BMA400_INT_STATUS_MSK UINT8_C(0xE0) +#define BMA400_INT_STATUS_POS UINT8_C(5) + +#define BMA400_EN_DRDY_MSK UINT8_C(0x80) +#define BMA400_EN_DRDY_POS UINT8_C(7) + +#define BMA400_EN_FIFO_WM_MSK UINT8_C(0x40) +#define BMA400_EN_FIFO_WM_POS UINT8_C(6) + +#define BMA400_EN_FIFO_FULL_MSK UINT8_C(0x20) +#define BMA400_EN_FIFO_FULL_POS UINT8_C(5) + +#define BMA400_EN_INT_OVERRUN_MSK UINT8_C(0x10) +#define BMA400_EN_INT_OVERRUN_POS UINT8_C(4) + +#define BMA400_EN_GEN2_MSK UINT8_C(0x08) +#define BMA400_EN_GEN2_POS UINT8_C(3) + +#define BMA400_EN_GEN1_MSK UINT8_C(0x04) +#define BMA400_EN_GEN1_POS UINT8_C(2) + +#define BMA400_EN_ORIENT_CH_MSK UINT8_C(0x02) +#define BMA400_EN_ORIENT_CH_POS UINT8_C(1) + +#define BMA400_EN_LATCH_MSK UINT8_C(0x80) +#define BMA400_EN_LATCH_POS UINT8_C(7) + +#define BMA400_EN_ACTCH_MSK UINT8_C(0x10) +#define BMA400_EN_ACTCH_POS UINT8_C(4) + +#define BMA400_EN_D_TAP_MSK UINT8_C(0x08) +#define BMA400_EN_D_TAP_POS UINT8_C(3) + +#define BMA400_EN_S_TAP_MSK UINT8_C(0x04) +#define BMA400_EN_S_TAP_POS UINT8_C(2) + +#define BMA400_EN_STEP_INT_MSK UINT8_C(0x01) + +#define BMA400_STEP_MAP_INT2_MSK UINT8_C(0x10) +#define BMA400_STEP_MAP_INT2_POS UINT8_C(4) + +#define BMA400_EN_WAKEUP_INT_MSK UINT8_C(0x01) + +#define BMA400_TAP_MAP_INT1_MSK UINT8_C(0x04) +#define BMA400_TAP_MAP_INT1_POS UINT8_C(2) + +#define BMA400_TAP_MAP_INT2_MSK UINT8_C(0x40) +#define BMA400_TAP_MAP_INT2_POS UINT8_C(6) + +#define BMA400_ACTCH_MAP_INT1_MSK UINT8_C(0x08) +#define BMA400_ACTCH_MAP_INT1_POS UINT8_C(3) + +#define BMA400_ACTCH_MAP_INT2_MSK UINT8_C(0x80) +#define BMA400_ACTCH_MAP_INT2_POS UINT8_C(7) + +#define BMA400_FIFO_BYTES_CNT_MSK UINT8_C(0x07) + +#define BMA400_FIFO_TIME_EN_MSK UINT8_C(0x04) +#define BMA400_FIFO_TIME_EN_POS UINT8_C(2) + +#define BMA400_FIFO_AXES_EN_MSK UINT8_C(0xE0) +#define BMA400_FIFO_AXES_EN_POS UINT8_C(5) + +#define BMA400_FIFO_8_BIT_EN_MSK UINT8_C(0x10) +#define BMA400_FIFO_8_BIT_EN_POS UINT8_C(4) + +/* Macro to SET and GET BITS of a register */ +#define BMA400_SET_BITS(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | \ + ((data << bitname##_POS) & bitname##_MSK)) + +#define BMA400_GET_BITS(reg_data, bitname) ((reg_data & (bitname##_MSK)) >> \ + (bitname##_POS)) + +#define BMA400_SET_BITS_POS_0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MSK)) | \ + (data & bitname##_MSK)) + +#define BMA400_GET_BITS_POS_0(reg_data, bitname) (reg_data & (bitname##_MSK)) + +#define BMA400_SET_BIT_VAL_0(reg_data, bitname) (reg_data & ~(bitname##_MSK)) + +#define BMA400_GET_LSB(var) (uint8_t)(var & BMA400_SET_LOW_BYTE) +#define BMA400_GET_MSB(var) (uint8_t)((var & BMA400_SET_HIGH_BYTE) >> 8) + +/* Macros used for Self test */ + +/* + * Derivation of values obtained by : + * Signal_Diff = ( (LSB/g value based on Accel Range) * (Minimum difference signal value) ) / 1000 + */ + +/* Self-test: Resulting minimum difference signal for BMA400 with Range 4G */ + +#define BMA400_ST_ACC_X_AXIS_SIGNAL_DIFF UINT16_C(768) +#define BMA400_ST_ACC_Y_AXIS_SIGNAL_DIFF UINT16_C(614) +#define BMA400_ST_ACC_Z_AXIS_SIGNAL_DIFF UINT16_C(128) + +/* + * Interface selection enums + */ +enum bma400_intf { + /* SPI interface */ + BMA400_SPI_INTF, + /* I2C interface */ + BMA400_I2C_INTF +}; + +/********************************************************* */ +/*! Function Pointers */ +/********************************************************* */ + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific read functions of the user + * + * @param[in] reg_addr : 8bit register address of the sensor + * @param[out] reg_data : Data from the specified address + * @param[in] length : Length of the reg_data array + * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related callbacks + * @retval 0 for Success + * @retval Non-zero for Failure + */ +typedef BMA400_INTF_RET_TYPE (*bma400_read_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, + void *intf_ptr); + +/*! + * @brief Bus communication function pointer which should be mapped to + * the platform specific write functions of the user + * + * @param[in] reg_addr : 8bit register address of the sensor + * @param[out] reg_data : Data to the specified address + * @param[in] length : Length of the reg_data array + * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related callbacks + * @retval 0 for Success + * @retval Non-zero for Failure + * + */ +typedef BMA400_INTF_RET_TYPE (*bma400_write_fptr_t)(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, + void *intf_ptr); + +/*! + * @brief Delay function pointer which should be mapped to + * delay function of the user + * + * @param period - The time period in microseconds + * @param[in,out] intf_ptr : Void pointer that can enable the linking of descriptors + * for interface related callbacks + */ +typedef void (*bma400_delay_us_fptr_t)(uint32_t period, void *intf_ptr); + +/* + * Sensor selection enums + */ +enum bma400_sensor { + BMA400_ACCEL, + BMA400_TAP_INT, + BMA400_ACTIVITY_CHANGE_INT, + BMA400_GEN1_INT, + BMA400_GEN2_INT, + BMA400_ORIENT_CHANGE_INT, + BMA400_STEP_COUNTER_INT +}; + +/* + * Interrupt channel selection enums + */ +enum bma400_int_chan { + BMA400_UNMAP_INT_PIN, + BMA400_INT_CHANNEL_1, + BMA400_INT_CHANNEL_2, + BMA400_MAP_BOTH_INT_PINS +}; + +/* + * Interrupt pin hardware configurations + */ +struct bma400_int_pin_conf +{ + /* Interrupt channel selection enums */ + enum bma400_int_chan int_chan; + + /* Interrupt pin configuration + * Assignable Macros : + * - BMA400_INT_PUSH_PULL_ACTIVE_0 + * - BMA400_INT_PUSH_PULL_ACTIVE_1 + * - BMA400_INT_OPEN_DRIVE_ACTIVE_0 + * - BMA400_INT_OPEN_DRIVE_ACTIVE_1 + */ + uint8_t pin_conf; +}; + +/* + * Accel basic configuration + */ +struct bma400_acc_conf +{ + /* Output data rate + * Assignable macros : + * - BMA400_ODR_12_5HZ - BMA400_ODR_25HZ - BMA400_ODR_50HZ + * - BMA400_ODR_100HZ - BMA400_ODR_200HZ - BMA400_ODR_400HZ + * - BMA400_ODR_800HZ + */ + uint8_t odr; + + /* Range of sensor + * Assignable macros : + * - BMA400_2G_RANGE - BMA400_8G_RANGE + * - BMA400_4G_RANGE - BMA400_16G_RANGE + */ + uint8_t range; + + /* Filter setting for data source + * Assignable Macros : + * - BMA400_DATA_SRC_ACCEL_FILT_1 + * - BMA400_DATA_SRC_ACCEL_FILT_2 + * - BMA400_DATA_SRC_ACCEL_FILT_LP + */ + uint8_t data_src; + + /* Assignable Macros for osr and osr_lp: + * - BMA400_ACCEL_OSR_SETTING_0 - BMA400_ACCEL_OSR_SETTING_2 + * - BMA400_ACCEL_OSR_SETTING_1 - BMA400_ACCEL_OSR_SETTING_3 + */ + + /* OSR setting for data source */ + uint8_t osr; + + /* OSR setting for low power mode */ + uint8_t osr_lp; + + /* Filter 1 Bandwidth + * Assignable macros : + * - BMA400_ACCEL_FILT1_BW_0 + * - BMA400_ACCEL_FILT1_BW_1 + */ + uint8_t filt1_bw; + + /* Interrupt channel to be mapped */ + enum bma400_int_chan int_chan; +}; + +/* + * Tap interrupt configurations + */ +struct bma400_tap_conf +{ + /* Axes enabled to sense tap setting + * Assignable macros : + * - BMA400_X_AXIS_EN_TAP + * - BMA400_Y_AXIS_EN_TAP + * - BMA400_Z_AXIS_EN_TAP + */ + uint8_t axes_sel; + + /* TAP sensitivity settings modifies the threshold + * for minimum TAP amplitude + * Assignable macros : + * - BMA400_TAP_SENSITIVITY_0 - BMA400_TAP_SENSITIVITY_4 + * - BMA400_TAP_SENSITIVITY_1 - BMA400_TAP_SENSITIVITY_5 + * - BMA400_TAP_SENSITIVITY_2 - BMA400_TAP_SENSITIVITY_6 + * - BMA400_TAP_SENSITIVITY_3 - BMA400_TAP_SENSITIVITY_7 + * + * @note : + * - BMA400_TAP_SENSITIVITY_0 correspond to highest sensitivity + * - BMA400_TAP_SENSITIVITY_7 correspond to lowest sensitivity + */ + uint8_t sensitivity; + + /* TAP tics_th setting is the maximum time between upper and lower + * peak of a tap, in data samples, This time depends on the + * mechanics of the device tapped onto default = 12 samples + * Assignable macros : + * - BMA400_TICS_TH_6_DATA_SAMPLES + * - BMA400_TICS_TH_9_DATA_SAMPLES + * - BMA400_TICS_TH_12_DATA_SAMPLES + * - BMA400_TICS_TH_18_DATA_SAMPLES + */ + uint8_t tics_th; + + /* BMA400 TAP - quiet settings to configure minimum quiet time + * before and after double tap, in the data samples. + * This time also defines the longest time interval between two + * taps so that they are considered as double tap + * Assignable macros : + * - BMA400_QUIET_60_DATA_SAMPLES + * - BMA400_QUIET_80_DATA_SAMPLES + * - BMA400_QUIET_100_DATA_SAMPLES + * - BMA400_QUIET_120_DATA_SAMPLES + */ + uint8_t quiet; + + /* BMA400 TAP - quiet_dt settings + * quiet_dt refers to Minimum time between the two taps of a + * double tap, in data samples + * Assignable macros : + * - BMA400_QUIET_DT_4_DATA_SAMPLES + * - BMA400_QUIET_DT_8_DATA_SAMPLES + * - BMA400_QUIET_DT_12_DATA_SAMPLES + * - BMA400_QUIET_DT_16_DATA_SAMPLES + */ + uint8_t quiet_dt; + + /* Interrupt channel to be mapped */ + enum bma400_int_chan int_chan; +}; + +/* + * Activity change interrupt configurations + */ +struct bma400_act_ch_conf +{ + /* Threshold for activity change (8 mg/LSB) */ + uint8_t act_ch_thres; + + /* Axes enabled to sense activity change + * Assignable macros : + * - BMA400_X_AXIS_EN + * - BMA400_Y_AXIS_EN + * - BMA400_Z_AXIS_EN + * - BMA400_XYZ_AXIS_EN + */ + uint8_t axes_sel; + + /* Data Source for activity change + * Assignable macros : + * - BMA400_DATA_SRC_ACC_FILT1 + * - BMA400_DATA_SRC_ACC_FILT2 + */ + uint8_t data_source; + + /* Sample count for sensing act_ch + * Assignable macros : + * - BMA400_ACT_CH_SAMPLE_CNT_32 + * - BMA400_ACT_CH_SAMPLE_CNT_64 + * - BMA400_ACT_CH_SAMPLE_CNT_128 + * - BMA400_ACT_CH_SAMPLE_CNT_256 + * - BMA400_ACT_CH_SAMPLE_CNT_512 + */ + uint8_t act_ch_ntps; + + /* Interrupt channel to be mapped */ + enum bma400_int_chan int_chan; +}; + +/* + * Generic interrupt configurations + */ +struct bma400_gen_int_conf +{ + /* Threshold for the gen1 interrupt (1 LSB = 8mg) + * if gen_int_thres = 10, then threshold = 10 * 8 = 80mg + */ + uint8_t gen_int_thres; + + /* Duration for which the condition has to persist until + * interrupt can be triggered + * duration is measured in data samples of selected data source + */ + uint16_t gen_int_dur; + + /* Enable axes to sense for the gen1 interrupt + * Assignable macros : + * - BMA400_X_AXIS_EN + * - BMA400_Y_AXIS_EN + * - BMA400_Z_AXIS_EN + * - BMA400_XYZ_AXIS_EN + */ + uint8_t axes_sel; + + /* Data source to sense for the gen1 interrupt + * Assignable macros : + * - BMA400_DATA_SRC_ACC_FILT1 + * - BMA400_DATA_SRC_ACC_FILT2 + */ + uint8_t data_src; + + /* Activity/Inactivity selection macros + * Assignable macros : + * - BMA400_ACTIVITY_INT + * - BMA400_INACTIVITY_INT + */ + uint8_t criterion_sel; + + /* Axes selection logic macros + * Assignable macros : + * - BMA400_ALL_AXES_INT + * - BMA400_ANY_AXES_INT + */ + uint8_t evaluate_axes; + + /* Reference x,y,z values updates + * Assignable macros : + * - BMA400_MANUAL_UPDATE + * - BMA400_ONE_TIME_UPDATE + * - BMA400_EVERY_TIME_UPDATE + * - BMA400_LP_EVERY_TIME_UPDATE + */ + uint8_t ref_update; + + /* Hysteresis value + * Higher the hysteresis value, Lower the value of noise + * Assignable macros : + * - BMA400_HYST_0_MG + * - BMA400_HYST_24_MG + * - BMA400_HYST_48_MG + * - BMA400_HYST_96_MG + */ + uint8_t hysteresis; + + /* Threshold value for x axes */ + uint16_t int_thres_ref_x; + + /* Threshold value for y axes */ + uint16_t int_thres_ref_y; + + /* Threshold value for z axes */ + uint16_t int_thres_ref_z; + + /* Interrupt channel to be mapped */ + enum bma400_int_chan int_chan; +}; + +/* + * Orient interrupt configurations + */ +struct bma400_orient_int_conf +{ + /* Enable axes to sense for the gen1 interrupt + * Assignable macros : + * - BMA400_X_AXIS_EN + * - BMA400_Y_AXIS_EN + * - BMA400_Z_AXIS_EN + * - BMA400_XYZ_AXIS_EN + */ + uint8_t axes_sel; + + /* Data source to sense for the gen1 interrupt + * Assignable macros : + * - BMA400_DATA_SRC_ACC_FILT1 + * - BMA400_DATA_SRC_ACC_FILT2 + */ + uint8_t data_src; + + /* Reference x,y,z values updates + * Assignable macros : + * - BMA400_MANUAL_UPDATE + * - BMA400_ORIENT_REFU_ACC_FILT_2 + * - BMA400_ORIENT_REFU_ACC_FILT_LP + */ + uint8_t ref_update; + + /* Threshold for the orient interrupt (1 LSB = 8mg) + * if orient_thres = 10, then threshold = 10 * 8 = 80mg + */ + uint8_t orient_thres; + + /* Threshold to check for stability (1 LSB = 8mg) + * if stability_thres = 10, then threshold = 10 * 8 = 80mg + */ + uint8_t stability_thres; + + /* orient_int_dur duration in which orient interrupt + * should occur, It is 8bit value configurable at 10ms/LSB. + */ + uint8_t orient_int_dur; + + /* Reference value for x axes */ + uint16_t orient_ref_x; + + /* Reference value for y axes */ + uint16_t orient_ref_y; + + /* Reference value for z axes */ + uint16_t orient_ref_z; + + /* Interrupt channel to be mapped */ + enum bma400_int_chan int_chan; +}; + +/* Step counter configurations */ +struct bma400_step_int_conf +{ + /* Interrupt channel to be mapped */ + enum bma400_int_chan int_chan; +}; + +/* + * Union of sensor Configurations + */ +union bma400_set_param +{ + /* Accel configurations */ + struct bma400_acc_conf accel; + + /* TAP configurations */ + struct bma400_tap_conf tap; + + /* Activity change configurations */ + struct bma400_act_ch_conf act_ch; + + /* Generic interrupt configurations */ + struct bma400_gen_int_conf gen_int; + + /* Orient configurations */ + struct bma400_orient_int_conf orient; + + /* Step counter configurations */ + struct bma400_step_int_conf step_cnt; +}; + +/* + * Sensor selection and their configurations + */ +struct bma400_sensor_conf +{ + /* Sensor selection */ + enum bma400_sensor type; + + /* Sensor configuration */ + union bma400_set_param param; +}; + +/* + * enum to select device settings + */ +enum bma400_device { + BMA400_AUTOWAKEUP_TIMEOUT, + BMA400_AUTOWAKEUP_INT, + BMA400_AUTO_LOW_POWER, + BMA400_INT_PIN_CONF, + BMA400_INT_OVERRUN_CONF, + BMA400_FIFO_CONF +}; + +/* + * BMA400 auto-wakeup configurations + */ +struct bma400_auto_wakeup_conf +{ + /* Enable auto wake-up by using timeout threshold + * Assignable Macros : + * - BMA400_ENABLE - BMA400_DISABLE + */ + uint8_t wakeup_timeout; + + /* Timeout threshold after which auto wake-up occurs + * It is 12bit value configurable at 2.5ms/LSB + * Maximum timeout is 10.24s (4096 * 2.5) for + * which the assignable macro is : + * - BMA400_AUTO_WAKEUP_TIMEOUT_MAX + */ + uint16_t timeout_thres; +}; + +/* + * BMA400 wakeup configurations + */ +struct bma400_wakeup_conf +{ + /* Wakeup reference update + * Assignable macros: + * - BMA400_MANUAL_UPDATE + * - BMA400_ONE_TIME_UPDATE + * - BMA400_EVERY_TIME_UPDATE + */ + uint8_t wakeup_ref_update; + + /* Number of samples for interrupt condition evaluation + * Assignable Macros : + * - BMA400_SAMPLE_COUNT_1 - BMA400_SAMPLE_COUNT_5 + * - BMA400_SAMPLE_COUNT_2 - BMA400_SAMPLE_COUNT_6 + * - BMA400_SAMPLE_COUNT_3 - BMA400_SAMPLE_COUNT_7 + * - BMA400_SAMPLE_COUNT_4 - BMA400_SAMPLE_COUNT_8 + */ + uint8_t sample_count; + + /* Enable low power wake-up interrupt for X(BIT 0), Y(BIT 1), Z(BIT 2) + * axes 0 - not active; 1 - active + * Assignable macros : + * - BMA400_X_AXIS_EN + * - BMA400_Y_AXIS_EN + * - BMA400_Z_AXIS_EN + * - BMA400_XYZ_AXIS_EN + */ + uint8_t wakeup_axes_en; + + /* Interrupt threshold configuration */ + uint8_t int_wkup_threshold; + + /* Reference acceleration x-axis for the wake-up interrupt */ + uint8_t int_wkup_ref_x; + + /* Reference acceleration y-axis for the wake-up interrupt */ + uint8_t int_wkup_ref_y; + + /* Reference acceleration z-axis for the wake-up interrupt */ + uint8_t int_wkup_ref_z; + + /* Interrupt channel to be mapped */ + enum bma400_int_chan int_chan; +}; + +/* + * BMA400 auto-low power configurations + */ +struct bma400_auto_lp_conf +{ + /* Enable auto low power mode using data ready interrupt / + * Genric interrupt1 / timeout counter value + * Assignable macros : + * - BMA400_AUTO_LP_DRDY_TRIGGER + * - BMA400_AUTO_LP_GEN1_TRIGGER + * - BMA400_AUTO_LP_TIMEOUT_EN + * - BMA400_AUTO_LP_TIME_RESET_EN + * - BMA400_AUTO_LP_TIMEOUT_DISABLE + */ + uint8_t auto_low_power_trigger; + + /* Timeout threshold after which auto wake-up occurs + * It is 12bit value configurable at 2.5ms/LSB + * Maximum timeout is 10.24s (4096 * 2.5) for + * which the assignable macro is : + * - BMA400_AUTO_LP_TIMEOUT_MAX + */ + uint16_t auto_lp_timeout_threshold; +}; + +/* + * FIFO configurations + */ +struct bma400_fifo_conf +{ + /* Select FIFO configurations to enable/disable + * Assignable Macros : + * - BMA400_FIFO_AUTO_FLUSH + * - BMA400_FIFO_STOP_ON_FULL + * - BMA400_FIFO_TIME_EN + * - BMA400_FIFO_DATA_SRC + * - BMA400_FIFO_8_BIT_EN + * - BMA400_FIFO_X_EN + * - BMA400_FIFO_Y_EN + * - BMA400_FIFO_Z_EN + */ + uint8_t conf_regs; + + /* Enable/ disable selected FIFO configurations + * Assignable Macros : + * - BMA400_ENABLE + * - BMA400_DISABLE + */ + uint8_t conf_status; + + /* Value to set the water-mark */ + uint16_t fifo_watermark; + + /* Interrupt pin mapping for FIFO full interrupt */ + enum bma400_int_chan fifo_full_channel; + + /* Interrupt pin mapping for FIFO water-mark interrupt */ + enum bma400_int_chan fifo_wm_channel; +}; + +/* + * Interrupt overrun configurations + */ +struct bma400_int_overrun +{ + /* Interrupt pin mapping for interrupt overrun */ + enum bma400_int_chan int_chan; +}; + +/* + * Union of device configuration parameters + */ +union bma400_device_params +{ + /* Auto wakeup configurations */ + struct bma400_auto_wakeup_conf auto_wakeup; + + /* Wakeup interrupt configurations */ + struct bma400_wakeup_conf wakeup; + + /* Auto Low power configurations */ + struct bma400_auto_lp_conf auto_lp; + + /* Interrupt pin configurations */ + struct bma400_int_pin_conf int_conf; + + /* FIFO configuration */ + struct bma400_fifo_conf fifo_conf; + + /* Interrupt overrun configuration */ + struct bma400_int_overrun overrun_int; +}; + +/* + * BMA400 device configuration + */ +struct bma400_device_conf +{ + /* Device feature selection */ + enum bma400_device type; + + /* Device feature configuration */ + union bma400_device_params param; +}; + +/* + * BMA400 sensor data + */ +struct bma400_sensor_data +{ + /* X-axis sensor data */ + int16_t x; + + /* Y-axis sensor data */ + int16_t y; + + /* Z-axis sensor data */ + int16_t z; + + /* sensor time */ + uint32_t sensortime; +}; + +/* + * BMA400 sensor data for FIFO + */ +struct bma400_fifo_sensor_data +{ + /* X-axis sensor data */ + int16_t x; + + /* Y-axis sensor data */ + int16_t y; + + /* Z-axis sensor data */ + int16_t z; +}; + +/* + * BMA400 interrupt selection + */ +enum bma400_int_type { + /* DRDY interrupt */ + BMA400_DRDY_INT_EN, + /* FIFO watermark interrupt */ + BMA400_FIFO_WM_INT_EN, + /* FIFO full interrupt */ + BMA400_FIFO_FULL_INT_EN, + /* Generic interrupt 2 */ + BMA400_GEN2_INT_EN, + /* Generic interrupt 1 */ + BMA400_GEN1_INT_EN, + /* Orient change interrupt */ + BMA400_ORIENT_CHANGE_INT_EN, + /* Latch interrupt */ + BMA400_LATCH_INT_EN, + /* Activity change interrupt */ + BMA400_ACTIVITY_CHANGE_INT_EN, + /* Double tap interrupt */ + BMA400_DOUBLE_TAP_INT_EN, + /* Single tap interrupt */ + BMA400_SINGLE_TAP_INT_EN, + /* Step interrupt */ + BMA400_STEP_COUNTER_INT_EN, + /* Auto wakeup interrupt */ + BMA400_AUTO_WAKEUP_EN +}; + +/* + * Interrupt enable/disable configurations + */ +struct bma400_int_enable +{ + /* Enum to choose the interrupt to be enabled */ + enum bma400_int_type type; + + /* Enable/ disable selected interrupts + * Assignable Macros : + * - BMA400_ENABLE + * - BMA400_DISABLE + */ + uint8_t conf; +}; +struct bma400_fifo_data +{ + /* Data buffer of user defined length is to be mapped here */ + uint8_t *data; + + /* While calling the API "bma400_get_fifo_data" , length stores + * number of bytes in FIFO to be read (specified by user as input) + * and after execution of the API ,number of FIFO data bytes + * available is provided as an output to user + */ + uint16_t length; + + /* FIFO time enable */ + uint8_t fifo_time_enable; + + /* FIFO 8bit mode enable */ + uint8_t fifo_8_bit_en; + + /* Streaming of the Accelerometer data for selected x,y,z axes + * - BMA400_FIFO_X_EN + * - BMA400_FIFO_Y_EN + * - BMA400_FIFO_Z_EN + */ + uint8_t fifo_data_enable; + + /* Will be equal to length when no more frames are there to parse */ + uint16_t accel_byte_start_idx; + + /* It stores the value of configuration changes + * in sensor during FIFO read + */ + uint8_t conf_change; + + /* Value of FIFO sensor time time */ + uint32_t fifo_sensor_time; +}; + +/* + * bma400 device structure + */ +struct bma400_dev +{ + /* Chip Id */ + uint8_t chip_id; + + /* SPI/I2C Interface selection */ + enum bma400_intf intf; + + /*! + * The interface pointer is used to enable the user + * to link their interface descriptors for reference during the + * implementation of the read and write interfaces to the + * hardware. + */ + void *intf_ptr; + + /* Decide SPI or I2C read mechanism */ + uint8_t dummy_byte; + + /* Bus read function pointer */ + bma400_read_fptr_t read; + + /* Bus write function pointer */ + bma400_write_fptr_t write; + + /* delay(in us) function pointer */ + bma400_delay_us_fptr_t delay_us; + + /* Resolution for FOC */ + uint8_t resolution; + + /* User set read/write length */ + uint16_t read_write_len; + + /*! To store interface pointer error */ + BMA400_INTF_RET_TYPE intf_rslt; +}; + +#endif /* BMA400_DEFS_H_ */ +/*! @endcond */