/*
****************************************************************************
* Copyright (C) 2015 - 2016 Bosch Sensortec GmbH
*
* File :bma4.c
*
* Date: 12 Oct 2017
*
* Revision: 2.1.9 $
*
* Usage: Sensor Driver for BMA4 family of sensors
*
****************************************************************************
* Disclaimer
*
* Common:
* Bosch Sensortec products are developed for the consumer goods industry.
* They may only be used within the parameters of the respective valid
* product data sheet.  Bosch Sensortec products are provided with the
* express understanding that there is no warranty of fitness for a
* particular purpose.They are not fit for use in life-sustaining,
* safety or security sensitive systems or any system or device
* that may lead to bodily harm or property damage if the system
* or device malfunctions. In addition,Bosch Sensortec products are
* not fit for use in products which interact with motor vehicle systems.
* The resale and or use of products are at the purchasers own risk and
* his own responsibility. The examination of fitness for the intended use
* is the sole responsibility of the Purchaser.
*
* The purchaser shall indemnify Bosch Sensortec from all third party
* claims, including any claims for incidental, or consequential damages,
* arising from any product use not covered by the parameters of
* the respective valid product data sheet or not approved by
* Bosch Sensortec and reimburse Bosch Sensortec for all costs in
* connection with such claims.
*
* The purchaser must monitor the market for the purchased products,
* particularly with regard to product safety and inform Bosch Sensortec
* without delay of all security relevant incidents.
*
* Engineering Samples are marked with an asterisk (*) or (e).
* Samples may vary from the valid technical specifications of the product
* series. They are therefore not intended or fit for resale to third
* parties or for use in end products. Their sole purpose is internal
* client testing. The testing of an engineering sample may in no way
* replace the testing of a product series. Bosch Sensortec assumes
* no liability for the use of engineering samples.
* By accepting the engineering samples, the Purchaser agrees to indemnify
* Bosch Sensortec from all claims arising from the use of engineering
* samples.
*
* Special:
* This software module (hereinafter called "Software") and any information
* on application-sheets (hereinafter called "Information") is provided
* free of charge for the sole purpose to support your application work.
* The Software and Information is subject to the following
* terms and conditions:
*
* The Software is specifically designed for the exclusive use for
* Bosch Sensortec products by personnel who have special experience
* and training. Do not use this Software if you do not have the
* proper experience or training.
*
* This Software package is provided `` as is `` and without any expressed
* or implied warranties,including without limitation, the implied warranties
* of merchantability and fitness for a particular purpose.
*
* Bosch Sensortec and their representatives and agents deny any liability
* for the functional impairment
* of this Software in terms of fitness, performance and safety.
* Bosch Sensortec and their representatives and agents shall not be liable
* for any direct or indirect damages or injury, except as
* otherwise stipulated in mandatory applicable law.
*
* The Information provided is believed to be accurate and reliable.
* Bosch Sensortec assumes no responsibility for the consequences of use
* of such Information nor for any infringement of patents or
* other rights of third parties which may result from its use.
* No license is granted by implication or otherwise under any patent or
* patent rights of Bosch. Specifications mentioned in the Information are
* subject to change without notice.
**************************************************************************/
/*! \file bma4.c
    \brief Sensor Driver for BMA4 family of sensors */
/***************************************************************************/
/**\name        Header files
****************************************************************************/
#include "bma4.h"

/***************************************************************************/
/**\name    Static Data Buffer
****************************************************************************/
/* Local array to store the values read from the register
 * using read_regs API  */
static uint8_t temp_buff[BMA4_MAX_BUFFER_SIZE] = {0};

/***************************************************************************/
/**\name        Local structures
****************************************************************************/
/*!
 * @brief Accel difference value of axis.
 */
struct data_with_sign {
  /*! Difference value */
  int16_t val;
  /*! Indicates negative value if set */
  uint8_t is_negative;
};

/*!
 * @brief Accel data deviation from ideal value
 */
struct offset_delta {
  /*! Accel x axis */
  struct data_with_sign x;
  /*! Accel y axis */
  struct data_with_sign y;
  /*! Accel z axis */
  struct data_with_sign z;
};

/*!
 * @brief Accel offset xyz structure
 */
struct accel_offset {
  /*! Accel offset X  data */
  uint8_t x;
  /*! Accel offset Y  data */
  uint8_t y;
  /*! Accel offset Z  data */
  uint8_t z;
};

/*!
 * @brief Accel self test diff xyz data structure
 */
struct selftest_delta_limit {
  /*! Accel X  data */
  int32_t x;
  /*! Accel Y  data */
  int32_t y;
  /*! Accel Z  data */
  int32_t z;
};

/*!
 * @brief Structure to store temp data values
 */
struct accel_temp {
  /*! Accel X temp data */
  int32_t x;
  /*! Accel Y temp data */
  int32_t y;
  /*! Accel Z temp data */
  int32_t z;
};

/***************************************************************************/
/*! Static Function Declarations
****************************************************************************/

/*!
 *  @brief This API validates the bandwidth and perfmode
 *  value set by the user.
 *
 *  param bandwidth[in] : bandwidth value set by the user.
 *  param perf_mode[in] : perf_mode value set by the user.
 */
static uint16_t validate_bandwidth_perfmode(uint8_t bandwidth,
                                            uint8_t perf_mode);

/*!
 *  @brief @brief This API validates the ODR value set by the user.
 *
 *  param bandwidth[in] : odr for accelerometer
 */
static uint16_t validate_odr(uint8_t odr);

/*!
 *  @brief This API is used to reset the FIFO related configurations
 *  in the fifo_frame structure.
 *
 *  @param dev[in,out]  : Structure instance of bma4_dev
 *
 */
static void reset_fifo_data_structure(const struct bma4_dev *dev);

/*!
 *  @brief This API computes the number of bytes of accel FIFO data
 *  which is to be parsed in header-less mode
 *
 *  @param[out] start_idx   : The start index for parsing data
 *  @param[out] len         : Number of bytes to be parsed
 *  @param[in]  acc_count   : Number of accelerometer frames to be read
 *  @param[in]  dev         : Structure instance of bma4_dev.
 *
 */
static void get_accel_len_to_parse(uint16_t *start_idx, uint16_t *len,
                                   const uint16_t *acc_count,
                                   const struct bma4_dev *dev);

/*!
 *  @brief This API checks the fifo read data as empty frame, if it
 *  is empty frame then moves the index to last byte.
 *
 *  @param[in,out] data_index   : The index of the current data to
 *                                be parsed from fifo data
 *  @param[in]  dev             : Structure instance of bma4_dev.
 */
static void check_empty_fifo(uint16_t *data_index, const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse the accelerometer data from the
 *  FIFO data in header mode.
 *
 *  @param[in,out] accel_data   : Structure instance of bma4_accel where
 *                                the accelerometer data in FIFO is stored.
 *  @param[in,out] accel_length : Number of accelerometer frames
 *                                (x,y,z axes data)
 *  @param[in,out] dev          : Structure instance of bma4_dev.
 *
 */
static void extract_accel_header_mode(struct bma4_accel *accel_data,
                                      uint16_t *accel_length,
                                      const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse the accelerometer data from the
 *  FIFO data in both header mode and header-less mode.
 *  It update the idx value which is used to store the index of
 *  the current data byte which is parsed.
 *
 *  @param[in,out] acc       : Structure instance of bma4_accel.
 *  @param[in,out] idx       : Index value of number of bytes parsed
 *  @param[in,out] acc_idx   : Index value of accelerometer data
 *                             (x,y,z axes) frame to be parsed
 *  @param[in] frm           : It consists of either fifo_data_enable
 *                             parameter (Accel and/or mag data enabled in FIFO)
 *                             in header-less mode or frame header data
 *                             in header mode
 *  @param[in]  dev          : Structure instance of bma4_dev.
 *
 */
static void unpack_acc_frm(struct bma4_accel *acc, uint16_t *idx,
                           uint16_t *acc_idx, uint8_t frm,
                           const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse the accelerometer data from the
 *  FIFO data and store it in the instance of the structure bma4_accel.
 *
 *  @param[out] accel_data        : Structure instance of bma4_accel where
 *                                  the parsed accel data bytes are stored.
 *  @param[in] data_start_index   : Index value of the accel data bytes
 *                                  which is to be parsed from the fifo data.
 *  @param[in] dev                :  Structure instance of bma4_dev.
 *
 */
static void unpack_accel_data(struct bma4_accel *accel_data,
                              uint16_t data_start_index,
                              const struct bma4_dev *dev);
/*!
 *  @brief This API computes the number of bytes of Mag FIFO data which is
 *  to be parsed in header-less mode
 *
 *  @param[out] start_idx   : The start index for parsing data
 *  @param[out] len         : Number of bytes to be parsed
 *  @param[in]  mag_count   : Number of magnetometer frames to be read
 *  @param[in]  dev         : Structure instance of bma4_dev.
 *
 */
static void get_mag_len_to_parse(uint16_t *start_idx, uint16_t *len,
                                 const uint16_t *mag_count,
                                 const struct bma4_dev *dev);
/*!
 *  @brief This API is used to parse the magnetometer data from the
 *  FIFO data in header mode.
 *
 *  @param[in,out] data     : Structure instance of bma4_mag_xyzr where
 *                            the magnetometer data in FIFO is extracted
 *                            and stored.
 *  @param[in,out] len      : Number of magnetometer frames
 *                           (x,y,z,r data)
 *  @param[in,out] dev      : Structure instance of bma4_dev.
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t extract_mag_header_mode(struct bma4_mag *data, uint16_t *len,
                                        const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse the magnetometer data from the
 *  FIFO data in both header mode and header-less mode and update the
 *  idx value which is used to store the index of the current
 *  data byte which is parsed.
 *
 *  @param data     : Structure instance of bma4_mag_xyzr.
 *  @param idx      : Index value of number of bytes parsed
 *  @param mag_idx  : Index value magnetometer data frame (x,y,z,r)
 *                    to be parsed
 *  @param frm      : It consists of either the fifo_data_enable parameter
 *                    (Accel and/or mag data enabled in FIFO) in
 *                    header-less mode and frame header data in header mode
 *  @param dev      : Structure instance of bma4_dev.
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t unpack_mag_frm(struct bma4_mag *data, uint16_t *idx,
                               uint16_t *mag_idx, uint8_t frm,
                               const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse the auxiliary magnetometer data from
 *  the FIFO data and store it in the instance of the structure mag_data.
 *
 *  @param mag_data         : Structure instance of bma4_mag_xyzr where the
 *                            parsed magnetometer data bytes are stored.
 *  @param start_idx        : Index value of the magnetometer data bytes
 *                            which is to be parsed from the FIFO data
 *  @param dev              : Structure instance of bma4_dev.
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t unpack_mag_data(struct bma4_mag *mag_data, uint16_t start_idx,
                                const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse and store the sensor time from the
 *  FIFO data in the structure instance dev.
 *
 *  @param[in,out] data_index : Index of the FIFO data which
 *                              has the sensor time.
 *  @param[in,out] dev        : Structure instance of bma4_dev.
 *
 */
static void unpack_sensortime_frame(uint16_t *data_index,
                                    const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse and store the skipped_frame_count from
 *  the FIFO data in the structure instance dev.
 *
 *  @param[in,out] data_index       : Index of the FIFO data which
 *                                    has the skipped frame count.
 *  @param[in,out] dev              : Structure instance of bma4_dev.
 *
 */
static void unpack_skipped_frame(uint16_t *data_index,
                                 const struct bma4_dev *dev);

/*!
 *  @brief This API is used to parse and store the dropped_frame_count from
 *  the FIFO data in the structure instance dev.
 *
 *  @param[in,out] data_index       : Index of the FIFO data which
 *                                    has the dropped frame data.
 *  @param[in,out] dev              : Structure instance of bma4_dev.
 *
 */
static void unpack_dropped_frame(uint16_t *data_index,
                                 const struct bma4_dev *dev);

/*!
 *  @brief This API is used to move the data index ahead of the
 *  current_frame_length parameter when unnecessary FIFO data appears while
 *  extracting the user specified data.
 *
 *  @param[in,out] data_index       : Index of the FIFO data which
 *                                    is to be moved ahead of the
 *                                    current_frame_length
 *  @param[in] current_frame_length : Number of bytes in a particular frame
 *  @param[in] dev                  : Structure instance of bma4_dev.
 *
 */
static void move_next_frame(uint16_t *data_index, uint8_t current_frame_length,
                            const struct bma4_dev *dev);

/*!
 *  @brief This API writes the config stream data in memory using burst mode
 *
 *  @param[in] stream_data : Pointer to store data of 32 bytes
 *  @param[in] index : Represents value in multiple of 32 bytes
 *  @param[in] dev : Structure instance of bma4_dev.
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 */
static uint16_t stream_transfer_write(const uint8_t *stream_data,
                                      uint16_t index, struct bma4_dev *dev);

/*!
 *  @brief This API enables or disables the Accel Self test feature in the
 *  sensor.
 *
 *  @param[in] accel_selftest_enable : Variable used to enable or disable
 *  the Accel self test feature
 *  Value   |  Description
 *  --------|---------------
 *  0x00    | BMA4_DISABLE
 *  0x01    | BMA4_ENABLE
 *
 *  @param[in] dev : Structure instance of bma4_dev
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t set_accel_selftest_enable(uint8_t accel_selftest_axis,
                                          struct bma4_dev *dev);

/*!
 *  @brief This API selects the sign of Accel self-test excitation
 *
 *  @param[in] accel_selftest_sign: Variable used to select the Accel
 *  self test sign
 *  Value   |  Description
 *  --------|--------------------------
 *  0x00    | BMA4_DISABLE (negative)
 *  0x01    | BMA4_ENABLE (positive)
 *
 *  @param[in] dev : Structure instance of bma4_dev
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t set_accel_selftest_sign(uint8_t accel_selftest_sign,
                                        struct bma4_dev *dev);

/*!
 *  @brief This API sets the Accel self test amplitude in the sensor.
 *
 *  @param[in] accel_selftest_amp : Variable used to specify the Accel self
 *  test amplitude
 *  Value   |  Description
 *  --------|------------------------------------
 *  0x00    | BMA4_SELFTEST_AMP_LOW
 *  0x01    | BMA4_SELFTEST_AMP_HIGH
 *
 *  @param[in] dev : structure instance of bma4_dev
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t set_accel_selftest_amp(uint8_t accel_selftest_amp,
                                       struct bma4_dev *dev);

/*!
 *  @brief This function enables and configures the Accel which is needed
 *  for Self test operation.
 *
 *  @param[in] dev : Structure instance of bma4_dev
 *
 *  @return results of self test
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t set_accel_selftest_config(struct bma4_dev *dev);

/*!
 *  @brief This API validates the Accel g value provided as input by the
 *  user for Accel offset compensation.
 *
 *  @param[in] gvalue : Pointer variable used to specify the g value
 *  set by the user for Accel offset compensation.
 *
 *  @note The g-values to be passed to the parameter should be
 *  multiples of 1000000.
 *
 *  @return results of the status of user input validation
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t validate_user_input(const int32_t *gvalue);
/*!
 *  @brief This API converts the range value into corresponding integer
 *  value.
 *
 *  @param[in] range_in : input range value.
 *  @param[out] range_out : pointer to store the integer value of range.
 *
 *  @return results of the status of user input validation
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static void map_range(uint8_t range_in, uint8_t *range_out);

/*!
 *  @brief This API normalise the data with offset.
 *
 *  @param[out] compensated_data : pointer to store the compensated data.
 *  @param[in] offset_data : pointer of offset.
 *
 *  @return results of the status of user input validation
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static void normalise_offset(const struct offset_delta *compensated_data,
                             struct accel_offset *offset_data);

/*!
 *  @brief This API normalise the data with offset.
 *
 *  @param[in] res : resolution of the sensor.
 *  @param[in] range : G-range of the accel.
 *  @param[in] delta : pointer of offset_delta.
 *  @param[out] data : pointer to store accel_offset data.
 *
 *  @return results of the status of user input validation
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static void scale_offset(uint8_t res, uint8_t range,
                         const struct offset_delta *delta,
                         struct accel_offset *data);

/*!
 *  @brief This API compensate the accel data against gravity.
 *
 *  @param[in] lsb_per_g : lsb value pre 1g.
 *  @param[in] g_val : G reference value of all axis.
 *  @param[in] data : pointer of accel_offset data.
 *  @param[out] comp_data : pointer to store compensated data.
 *
 *  @note The g-values to be passed to the parameter should be
 *  multiples of 1000000.
 *
 *  @return results of the status of user input validation
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static void comp_for_grvty(uint16_t lsb_per_g, const int32_t g_val[3],
                           const struct bma4_accel *data,
                           struct offset_delta *comp_data);
/*!
 *  @brief This function validates the Accel Self test data and decides the
 *  result of Self test operation.
 *
 *  @param[in] accel_data_diff : Pointer to structure variable which holds
 *  the Accel data difference of Self test operation
 *  @param[in] dev : Structure instance of bma4_dev
 *
 *  @return results of self test operation
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t
validate_selftest(const struct selftest_delta_limit *accel_data_diff,
                  const struct bma4_dev *dev);

/*!
 *  @brief This function configure the Accel for FOC.
 *
 *  @param[in] acc_conf : accel config structure instance
 *  @param[in] acc_en : enables the accel
 *  @param[in] pwr_mode : set the power mode
 *  @param[in] dev : Structure instance of bma4_dev
 *
 *  @return results of self test operation
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 *
 */
static uint16_t foc_config(struct bma4_accel_config *acc_conf, uint8_t *acc_en,
                           uint8_t *pwr_mode, struct bma4_dev *dev);

/*!
 *  @brief This API converts lsb value of axes to mg for self-test
 *
 *  @param[in] accel_data_diff : Pointer variable used to pass accel difference
 *  values in g
 *  @param[out] accel_data_diff_mg : Pointer variable used to store accel
 *  difference values in mg
 *  @param[out] dev : Structure instance of bma4_dev
 *
 *  @return None *
 */
static void convert_lsb_g(const struct selftest_delta_limit *accel_data_diff,
                          struct selftest_delta_limit *accel_data_diff_mg,
                          const struct bma4_dev *dev);

/*!
 *  @brief This API sets the feature config. data start address in the sensor.
 *
 *  @param[in] dev  : Structure instance of bma4_dev.
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 */
static uint16_t set_feature_config_start_addr(struct bma4_dev *dev);

/*!
 *  @brief This API increments the feature config. data address according to the
 * user provided read/write length in the dev structure.
 *
 *  @param[in] dev  : Structure instance of bma4_dev.
 *
 *  @return Result of API execution status
 *  @retval 0 -> Success
 *  @retval Any non zero value -> Fail
 */
static uint16_t increment_feature_config_addr(const struct bma4_dev *dev);

/*!
 *  @brief This API reads the 8-bit data from the given register
 *  in the sensor.
 */
static uint16_t read_regs(uint8_t addr, uint8_t *data, uint8_t len,
                          const struct bma4_dev *dev);

/*!
 *  @brief This API writes the 8-bit data to the given register
 *  in the sensor.
 */
static uint16_t write_regs(uint8_t addr, uint8_t *data, uint8_t len,
                           const struct bma4_dev *dev);

/*!
 *  @brief This API sets the feature config. data start address in the sensor.
 */
static uint16_t get_feature_config_start_addr(struct bma4_dev *dev);

/*!
 * @brief This API is used to calculate the power of given
 * base value.
 *
 * @param[in] base : value of base
 * @param[in] resolution : resolution of the sensor
 *
 * @return : return the value of base^resolution
 */

static int32_t power(int16_t base, uint8_t resolution);

/*!
 * @brief This API performs roundoff on given value
 *
 * @param[in] value : Value which is need to be rounded off
 *
 * @return : None
 */
static int8_t roundoff(int32_t value);

/*!
 * @brief This API finds the bit position of 3.9mg according to given range
 * and resolution.
 *
 * @param[in] range : range of the accel.
 * @param[in] res : resolution of the accel.
 *
 * @return : bit position of 3.9mg
 */
static int8_t get_bit_pos_3_9mg(uint8_t range, uint8_t res);

/*!
 * @brief This API finds the the null error of the device pointer structure
 *
 * @param[in] dev : Structure instance of bma4_dev.
 *
 * @return Null error
 */
static uint16_t bma4_null_pointer_check(const struct bma4_dev *dev);

/*!
 * @brief This internal API brings up the secondary interface to access
 *          auxiliary sensor
 *
 * @param[in] dev : Structure instance of bma4_dev.
 *
 * @return Result of API execution status
 *
 * @retval 0 if success, else fail
 */
static uint16_t bma4_set_aux_interface_config(struct bma4_dev *dev);

/*!
 * @brief This internal API reads the data from the auxiliary sensor
 * depending on burst length configured
 *
 * @param[in] dev  : Structure instance of bma4_dev.
 * @param[out] aux_data  : Pointer variable to store data read
 * @param[in] aux_reg_addr  : Variable to pass address from where
 *                            data is to be read
 *
 * @return Result of API execution status
 *
 * @retval 0 if success, else fail
 */
static uint16_t bma4_extract_aux_data(uint8_t aux_reg_addr, uint8_t *aux_data,
                                      uint16_t len, struct bma4_dev *dev);

/*!
 * @brief This internal API maps the actual burst read length with user length
 * set.
 *
 * @param[in] dev  : Structure instance of bma4_dev.
 * @param[out] len  : Pointer variable to store mapped length
 *
 * @return Result of API execution status
 *
 * @retval 0 if success, else fail
 */
static uint16_t bma4_map_read_len(uint8_t *len, const struct bma4_dev *dev);

/***************************************************************************/
/**\name        Extern Declarations
****************************************************************************/

/***************************************************************************/
/**\name        Globals
****************************************************************************/

/***************************************************************************/
/**\name        Function definitions
****************************************************************************/
/*!
 *  @brief This API is the entry point.
 *  Call this API before using all other APIs.
 *  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.
 */
uint16_t bma4_init(struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;
  /* Check the bma4 structure as NULL */
  if ((dev == NULL) || (dev->bus_read == NULL) || (dev->bus_write == NULL)) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (dev->interface == BMA4_SPI_INTERFACE)
      dev->dummy_byte = 1;
    else
      dev->dummy_byte = 0;

    rslt |= bma4_read_regs(BMA4_CHIP_ID_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      /* Assign Chip Id */
      dev->chip_id = data;
    }
  }

  return rslt;
}

/*!
 *  @brief This API is used to write the binary configuration in the sensor
 */
uint16_t bma4_write_config_file(struct bma4_dev *dev) {
  uint16_t rslt;
  /* Config loading disable*/
  uint8_t config_load          = 0;
  uint16_t index               = 0;
  uint8_t config_stream_status = 0;

  /* Disable advanced power save */
  rslt = bma4_set_advance_power_save(BMA4_DISABLE, dev);
  /* Wait for sensor time synchronization. Refer the data-sheet for
  more information*/
  dev->delay(1);

  if (rslt == BMA4_OK) {
    /* Disable config loading*/
    rslt |= bma4_write_regs(BMA4_INIT_CTRL_ADDR, &config_load, 1, dev);
    /* Write the config stream */
    for (index = 0; index < BMA4_CONFIG_STREAM_SIZE;
         index += dev->read_write_len)
      rslt |= stream_transfer_write((dev->config_file_ptr + index), index, dev);

    /* Enable config loading and FIFO mode */
    config_load = 0x01;
    rslt |= bma4_write_regs(BMA4_INIT_CTRL_ADDR, &config_load, 1, dev);
    /* Wait till ASIC is initialized. Refer the data-sheet for
    more information*/
    dev->delay(150);
    /* Read the status of config stream operation */
    rslt |= bma4_read_regs(BMA4_INTERNAL_STAT, &config_stream_status, 1, dev);

    if (config_stream_status != BMA4_ASIC_INITIALIZED) {
      rslt |= BMA4_E_CONFIG_STREAM_ERROR;
    } else {
      /* Enable advanced power save */
      rslt |= bma4_set_advance_power_save(BMA4_ENABLE, dev);
      rslt |= get_feature_config_start_addr(dev);
    }
  }
  return rslt;
}

/*!
 *  @brief This API checks whether the write operation requested is for feature
 *  config or register write and accordingly writes the data in the sensor.
 */
uint16_t bma4_write_regs(uint8_t addr, uint8_t *data, uint8_t len,
                         struct bma4_dev *dev) {
  uint8_t i;
  uint8_t loop_count;
  uint8_t overflow;
  uint8_t index;
  uint16_t rslt        = BMA4_OK;
  uint8_t adv_pwr_save = 0;

  /* Check the dev structure as NULL*/
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (addr == BMA4_FEATURE_CONFIG_ADDR) {
      /* Disable APS if enabled before writing the feature config register */
      rslt = bma4_get_advance_power_save(&adv_pwr_save, dev);
      if (adv_pwr_save == BMA4_ENABLE) {
        rslt |= bma4_set_advance_power_save(BMA4_DISABLE, dev);
        /* Wait for sensor time synchronization. Refer the data-sheet for
        more information*/
        dev->delay(1);
      }

      if (((len % 2) == 0) && (len <= dev->feature_len) && (rslt == BMA4_OK)) {
        if (dev->read_write_len < len) {
          /* Calculate the no of writes to be performed according
          to the read/write length */
          loop_count = len / dev->read_write_len;
          overflow   = len % dev->read_write_len;
          index      = 0;
          rslt       = set_feature_config_start_addr(dev);
          for (i = 0; i < loop_count; i++) {
            rslt |= write_regs(BMA4_FEATURE_CONFIG_ADDR, data + index,
                               dev->read_write_len, dev);
            rslt |= increment_feature_config_addr(dev);
            index = index + dev->read_write_len;
          }
          if (overflow)
            rslt |= write_regs(BMA4_FEATURE_CONFIG_ADDR, data + index, overflow,
                               dev);
          rslt |= set_feature_config_start_addr(dev);
        } else {
          rslt = write_regs(BMA4_FEATURE_CONFIG_ADDR, data, len, dev);
        }
      } else {
        rslt = BMA4_E_RD_WR_LENGTH_INVALID;
      }

      if (rslt == BMA4_OK) {
        /* Enable APS once write feature config register is done */
        rslt = bma4_get_advance_power_save(&adv_pwr_save, dev);
        if (adv_pwr_save == BMA4_DISABLE) {
          rslt |= bma4_set_advance_power_save(BMA4_ENABLE, dev);
          /* Wait for sensor time synchronization. Refer the data-sheet for
          more information*/
          dev->delay(1);
        }
      }

    } else {
      rslt = write_regs(addr, data, len, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API writes the 8-bit data to the given register
 *  in the sensor.
 */
static uint16_t write_regs(uint8_t addr, uint8_t *data, uint8_t len,
                           const struct bma4_dev *dev) {
  uint16_t rslt = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (dev->interface == BMA4_SPI_INTERFACE)
      addr = addr & BMA4_SPI_WR_MASK;
    /* write data in the register*/
    rslt |= dev->bus_write(dev->dev_addr, addr, data, len);
  }
  return rslt;
}

/*!
 *  @brief This API sets the feature config. data start address in the sensor.
 */
static uint16_t get_feature_config_start_addr(struct bma4_dev *dev) {
  uint16_t rslt;
  uint8_t asic_lsb;
  uint8_t asic_msb;

  rslt = read_regs(BMA4_RESERVED_REG_5B_ADDR, &asic_lsb, 1, dev);
  rslt |= read_regs(BMA4_RESERVED_REG_5C_ADDR, &asic_msb, 1, dev);

  /* Store asic info in dev structure */
  dev->asic_data.asic_lsb = asic_lsb & 0x0F;
  dev->asic_data.asic_msb = asic_msb;

  return rslt;
}

/*!
 *  @brief This API sets the feature config. data start address in the sensor.
 */
static uint16_t set_feature_config_start_addr(struct bma4_dev *dev) {
  uint16_t rslt;

  rslt =
      write_regs(BMA4_RESERVED_REG_5B_ADDR, &dev->asic_data.asic_lsb, 1, dev);
  rslt |=
      write_regs(BMA4_RESERVED_REG_5C_ADDR, &dev->asic_data.asic_msb, 1, dev);

  return rslt;
}

/*!
 *  @brief This API increments the feature config. data address according to the
 * user provided read/write length in the dev structure.
 */
static uint16_t increment_feature_config_addr(const struct bma4_dev *dev) {
  uint16_t rslt;
  uint16_t asic_addr;
  uint8_t asic_lsb;
  uint8_t asic_msb;

  /* Read the asic address from the sensor */
  rslt = read_regs(BMA4_RESERVED_REG_5B_ADDR, &asic_lsb, 1, dev);
  rslt |= read_regs(BMA4_RESERVED_REG_5C_ADDR, &asic_msb, 1, dev);
  /* Get the asic address */
  asic_addr = (asic_msb << 4) | (asic_lsb & 0x0F);
  /* Sum the asic address with read/write length after converting from
  byte to word */
  asic_addr = asic_addr + (dev->read_write_len / 2);
  /* Split the asic address */
  asic_lsb = asic_addr & 0x0F;
  asic_msb = (uint8_t)(asic_addr >> 4);
  /* Write the asic address in the sensor */
  rslt |= write_regs(BMA4_RESERVED_REG_5B_ADDR, &asic_lsb, 1, dev);
  rslt |= write_regs(BMA4_RESERVED_REG_5C_ADDR, &asic_msb, 1, dev);

  return rslt;
}

/*!
 *  @brief This API checks whether the read operation requested is for feature
 *  or register read and accordingly reads the data from the sensor.
 */
uint16_t bma4_read_regs(uint8_t addr, uint8_t *data, uint8_t len,
                        struct bma4_dev *dev) {
  uint8_t i;
  uint8_t loop_count;
  uint8_t overflow;
  uint8_t index;
  uint16_t rslt        = BMA4_OK;
  uint8_t adv_pwr_save = 0;

  /* Check the dev structure as NULL*/
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (addr == BMA4_FEATURE_CONFIG_ADDR) {
      /* Disable APS if enabled before reading the feature config register */
      rslt = bma4_get_advance_power_save(&adv_pwr_save, dev);
      if (adv_pwr_save == BMA4_ENABLE) {
        rslt |= bma4_set_advance_power_save(BMA4_DISABLE, dev);
        /* Wait for sensor time synchronization. Refer the data-sheet for
        more information*/
        dev->delay(1);
      }

      if (((len % 2) == 0) && (len <= dev->feature_len) && (rslt == BMA4_OK)) {
        if (dev->read_write_len < len) {
          /* Calculate the no of writes to be performed according
          to the read/write length */
          loop_count = len / dev->read_write_len;
          overflow   = len % dev->read_write_len;
          index      = 0;
          rslt       = set_feature_config_start_addr(dev);
          for (i = 0; i < loop_count; i++) {
            rslt |= read_regs(BMA4_FEATURE_CONFIG_ADDR, data + index,
                              dev->read_write_len, dev);
            rslt |= increment_feature_config_addr(dev);
            index = index + dev->read_write_len;
          }
          if (overflow)
            rslt |= read_regs(BMA4_FEATURE_CONFIG_ADDR, data + index, overflow,
                              dev);
          rslt |= set_feature_config_start_addr(dev);
        } else {
          rslt = read_regs(BMA4_FEATURE_CONFIG_ADDR, data, len, dev);
        }
      } else {
        rslt = BMA4_E_RD_WR_LENGTH_INVALID;
      }
      if (rslt == BMA4_OK) {
        /* Enable APS once read feature config register is done */
        rslt = bma4_get_advance_power_save(&adv_pwr_save, dev);
        if (adv_pwr_save == BMA4_DISABLE) {
          rslt |= bma4_set_advance_power_save(BMA4_ENABLE, dev);
          /* Wait for sensor time synchronization. Refer the data-sheet for
          more information*/
          dev->delay(1);
        }
      }
    } else {
      rslt = read_regs(addr, data, len, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the 8-bit data from the given register
 *  in the sensor.
 */
static uint16_t read_regs(uint8_t addr, uint8_t *data, uint8_t len,
                          const struct bma4_dev *dev) {
  /* variable used to return the status of communication result*/
  uint16_t rslt     = 0;
  uint16_t temp_len = len + dev->dummy_byte;
  uint16_t i;

  if (dev->interface == BMA4_SPI_INTERFACE) {
    /* SPI mask added */
    addr = addr | BMA4_SPI_RD_MASK;
  }

  if (temp_len > BMA4_MAX_BUFFER_SIZE) {
    /* Buffer size is not sufficient */
    rslt |= BMA4_E_OUT_OF_RANGE;
  }

  if (rslt == BMA4_OK) {
    /* Read the data from the register */
    rslt |= dev->bus_read(dev->dev_addr, addr, temp_buff, temp_len);

    for (i = 0; i < len; i++) {
      /* Parsing and storing the valid data */
      data[i] = temp_buff[i + dev->dummy_byte];
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the error status from the sensor.
 */
uint16_t bma4_get_error_status(struct bma4_err_reg *err_reg,
                               struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read the error codes*/
    rslt |= bma4_read_regs(BMA4_ERROR_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      /* Fatal error*/
      err_reg->fatal_err = BMA4_GET_BITS_POS_0(data, BMA4_FATAL_ERR);
      /* Cmd error*/
      err_reg->cmd_err = BMA4_GET_BITSLICE(data, BMA4_CMD_ERR);
      /* User error*/
      err_reg->err_code = BMA4_GET_BITSLICE(data, BMA4_ERR_CODE);
      /* FIFO error*/
      err_reg->fifo_err = BMA4_GET_BITSLICE(data, BMA4_FIFO_ERR);
      /* Mag data ready error*/
      err_reg->aux_err = BMA4_GET_BITSLICE(data, BMA4_AUX_ERR);
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the sensor status from the sensor.
 */
uint16_t bma4_get_status(uint8_t *status, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read the error codes*/
    rslt |= bma4_read_regs(BMA4_STATUS_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *status = data;
  }

  return rslt;
}

/*!
 *  @brief This API reads the Accel data for x,y and z axis from the sensor.
 *  The data units is in LSB format.
 */
uint16_t bma4_read_accel_xyz(struct bma4_accel *accel, struct bma4_dev *dev) {
  uint16_t rslt                        = 0;
  uint16_t lsb                         = 0;
  uint16_t msb                         = 0;
  uint8_t data[BMA4_ACCEL_DATA_LENGTH] = {0};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_DATA_8_ADDR, data, BMA4_ACCEL_DATA_LENGTH, dev);

    if (rslt == BMA4_OK) {
      msb = data[1];
      lsb = data[0];
      /* Accel data x axis */
      accel->x = (int16_t)((msb << 8) | lsb);

      msb = data[3];
      lsb = data[2];
      /* Accel data y axis */
      accel->y = (int16_t)((msb << 8) | lsb);

      msb = data[5];
      lsb = data[4];
      /* Accel data z axis */
      accel->z = (int16_t)((msb << 8) | lsb);

      if (dev->resolution == BMA4_12_BIT_RESOLUTION) {
        accel->x = (accel->x / 0x10);
        accel->y = (accel->y / 0x10);
        accel->z = (accel->z / 0x10);
      } else if (dev->resolution == BMA4_14_BIT_RESOLUTION) {
        accel->x = (accel->x / 0x04);
        accel->y = (accel->y / 0x04);
        accel->z = (accel->z / 0x04);
      }
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the sensor time of Sensor time gets updated
 *  with every update of data register or FIFO.
 */
uint16_t bma4_get_sensor_time(uint32_t *sensor_time, struct bma4_dev *dev) {
  uint16_t rslt                         = 0;
  uint8_t data[BMA4_SENSOR_TIME_LENGTH] = {0};
  uint8_t msb                           = 0;
  uint8_t xlsb                          = 0;
  uint8_t lsb                           = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_SENSORTIME_0_ADDR, data,
                           BMA4_SENSOR_TIME_LENGTH, dev);

    if (rslt == BMA4_OK) {
      msb          = data[BMA4_SENSOR_TIME_MSB_BYTE];
      xlsb         = data[BMA4_SENSOR_TIME_XLSB_BYTE];
      lsb          = data[BMA4_SENSOR_TIME_LSB_BYTE];
      *sensor_time = (uint32_t)((msb << 16) | (xlsb << 8) | lsb);
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the chip temperature of sensor.
 *
 *  @note Using a scaling factor of 1000, to obtain integer values, which
 *  at the user end, are used to get accurate temperature value .
 *  BMA4_FAHREN_SCALED = 1.8 * 1000, BMA4_KELVIN_SCALED = 273.15 * 1000
 */
uint16_t bma4_get_temperature(int32_t *temp, uint8_t temp_unit,
                              struct bma4_dev *dev) {
  uint16_t rslt                     = 0;
  uint8_t data[BMA4_TEMP_DATA_SIZE] = {0};
  int32_t temp_raw_scaled           = 0;

  /* Check for Null pointer error */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read temperature value from the register */
    rslt |=
        bma4_read_regs(BMA4_TEMPERATURE_ADDR, data, BMA4_TEMP_DATA_SIZE, dev);

    if (rslt == BMA4_OK)
      temp_raw_scaled = (int32_t)data[BMA4_TEMP_BYTE] * BMA4_SCALE_TEMP;

    /* '0' value read from the register corresponds to 23 degree C */
    (*temp) = temp_raw_scaled + (BMA4_OFFSET_TEMP * BMA4_SCALE_TEMP);

    switch (temp_unit) {
    case BMA4_DEG:
      break;

    case BMA4_FAHREN:
      /* Temperature in degree Fahrenheit */
      (*temp) = (((*temp) / BMA4_SCALE_TEMP) * BMA4_FAHREN_SCALED) +
                (32 * BMA4_SCALE_TEMP);
      break;

    case BMA4_KELVIN:
      /* Temperature in degree Kelvin */
      (*temp) = (*temp) + BMA4_KELVIN_SCALED;
      break;

    default:
      break;
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the Output data rate, Bandwidth, perf_mode
 *  and Range of accel.
 */
uint16_t bma4_get_accel_config(struct bma4_accel_config *accel,
                               struct bma4_dev *dev) {
  uint16_t rslt   = 0;
  uint8_t data[2] = {0};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_ACCEL_CONFIG_ADDR, data,
                           BMA4_ACCEL_CONFIG_LENGTH, dev);

    if (rslt == BMA4_OK) {
      /* To get the ODR */
      accel->odr = BMA4_GET_BITS_POS_0(data[0], BMA4_ACCEL_ODR);
      /* To get the bandwidth */
      accel->bandwidth = BMA4_GET_BITSLICE(data[0], BMA4_ACCEL_BW);
      /* To get the under sampling mode */
      accel->perf_mode = BMA4_GET_BITSLICE(data[0], BMA4_ACCEL_PERFMODE);
      /* Read the Accel range */
      accel->range = BMA4_GET_BITS_POS_0(data[1], BMA4_ACCEL_RANGE);
    }
  }

  return rslt;
}

/*!
 *  @brief This API sets the output_data_rate, bandwidth, perf_mode
 *  and range of Accel.
 */
uint16_t bma4_set_accel_config(const struct bma4_accel_config *accel,
                               struct bma4_dev *dev) {
  uint16_t rslt                = 0;
  uint8_t accel_config_data[2] = {0, 0};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* check whether the bandwidth and perfmode
        settings are valid */
    rslt = validate_bandwidth_perfmode(accel->bandwidth, accel->perf_mode);

    if (rslt == BMA4_OK) {
      /* check ODR is valid */
      rslt |= validate_odr(accel->odr);

      if (rslt == BMA4_OK) {
        accel_config_data[0] = accel->odr & BMA4_ACCEL_ODR_MSK;
        accel_config_data[0] |=
            (uint8_t)(accel->bandwidth << BMA4_ACCEL_BW_POS);
        accel_config_data[0] |=
            (uint8_t)(accel->perf_mode << BMA4_ACCEL_PERFMODE_POS);
        accel_config_data[1] = accel->range & BMA4_ACCEL_RANGE_MSK;

        /* Burst write is not possible in
        suspend mode hence individual write is
        used with delay of 1 ms */
        rslt |= bma4_write_regs(BMA4_ACCEL_CONFIG_ADDR, &accel_config_data[0],
                                1, dev);
        dev->delay(BMA4_GEN_READ_WRITE_DELAY);
        rslt |= bma4_write_regs((BMA4_ACCEL_CONFIG_ADDR + 1),
                                &accel_config_data[1], 1, dev);
      }
    }
  }

  return rslt;
}

/*!
 *  @brief This API validates the bandwidth and perf_mode
 *  value set by the user.
 */
static uint16_t validate_bandwidth_perfmode(uint8_t bandwidth,
                                            uint8_t perf_mode) {
  uint16_t rslt = BMA4_OK;

  if (perf_mode == BMA4_CONTINUOUS_MODE) {
    if (bandwidth > BMA4_ACCEL_NORMAL_AVG4) {
      /* Invalid bandwidth error for continuous mode */
      rslt = BMA4_E_OUT_OF_RANGE;
    }
  } else if (perf_mode == BMA4_CIC_AVG_MODE) {
    if (bandwidth > BMA4_ACCEL_RES_AVG128) {
      /* Invalid bandwidth error for CIC avg. mode */
      rslt = BMA4_E_OUT_OF_RANGE;
    }
  } else {
    rslt = BMA4_E_OUT_OF_RANGE;
  }

  return rslt;
}

/*!
 *  @brief This API validates the ODR value set by the user.
 */
static uint16_t validate_odr(uint8_t odr) {
  uint16_t rslt = BMA4_OK;

  if ((odr < BMA4_OUTPUT_DATA_RATE_0_78HZ) ||
      (odr > BMA4_OUTPUT_DATA_RATE_1600HZ)) {
    /* If odr is not valid return error */
    rslt = BMA4_E_OUT_OF_RANGE;
  }

  return rslt;
}

/*!
 *  @brief This API sets the advance power save mode in the sensor.
 */
uint16_t bma4_set_advance_power_save(uint8_t adv_pwr_save,
                                     struct bma4_dev *dev) {
  uint16_t rslt = BMA4_OK;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CONF_ADDR, &data, 1, dev);
    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITS_POS_0(data, BMA4_ADVANCE_POWER_SAVE, adv_pwr_save);
      rslt |= bma4_write_regs(BMA4_POWER_CONF_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the status of advance power save mode
 *  from the sensor.
 */
uint16_t bma4_get_advance_power_save(uint8_t *adv_pwr_save,
                                     struct bma4_dev *dev) {
  uint16_t rslt = BMA4_OK;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CONF_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *adv_pwr_save = BMA4_GET_BITS_POS_0(data, BMA4_ADVANCE_POWER_SAVE);
  }

  return rslt;
}

/*!
 *  @brief This API sets the FIFO self wake up functionality in the sensor.
 */
uint16_t bma4_set_fifo_self_wakeup(uint8_t fifo_self_wakeup,
                                   struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CONF_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITSLICE(data, BMA4_FIFO_SELF_WAKE_UP, fifo_self_wakeup);
      rslt |= bma4_write_regs(BMA4_POWER_CONF_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API gets the status of FIFO self wake up functionality from
 *  the sensor.
 */
uint16_t bma4_get_fifo_self_wakeup(uint8_t *fifo_self_wake_up,
                                   struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CONF_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *fifo_self_wake_up = BMA4_GET_BITSLICE(data, BMA4_FIFO_SELF_WAKE_UP);
  }

  return rslt;
}

/*!
 *  @brief This API enables or disables the Accel in the sensor.
 */
uint16_t bma4_set_accel_enable(uint8_t accel_en, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CTRL_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITSLICE(data, BMA4_ACCEL_ENABLE, accel_en);
      rslt |= bma4_write_regs(BMA4_POWER_CTRL_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API checks whether Accel is enabled or not in the sensor.
 */
uint16_t bma4_get_accel_enable(uint8_t *accel_en, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CTRL_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *accel_en = BMA4_GET_BITSLICE(data, BMA4_ACCEL_ENABLE);
  }

  return rslt;
}

/*!
 *  @brief This API is used to enable or disable auxiliary Mag
 *  in the sensor.
 */
uint16_t bma4_set_mag_enable(uint8_t mag_en, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CTRL_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITS_POS_0(data, BMA4_MAG_ENABLE, mag_en);
      rslt |= bma4_write_regs(BMA4_POWER_CTRL_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API is used to check whether the auxiliary Mag is enabled
 *  or not in the sensor.
 */
uint16_t bma4_get_mag_enable(uint8_t *mag_en, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_POWER_CTRL_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *mag_en = BMA4_GET_BITS_POS_0(data, BMA4_MAG_ENABLE);
  }

  return rslt;
}

/*!
 *  @brief This API reads the SPI interface mode which is set for primary
 *  interface.
 */
uint16_t bma4_get_spi_interface(uint8_t *spi, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read SPI mode */
    rslt |= bma4_read_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *spi = BMA4_GET_BITS_POS_0(data, BMA4_CONFIG_SPI3);
  }

  return rslt;
}

/*!
 *  @brief This API configures the SPI interface Mode for primary interface
 */
uint16_t bma4_set_spi_interface(uint8_t spi, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (spi <= BMA4_MAX_VALUE_SPI3) {
      /* Write SPI mode */
      rslt |= bma4_read_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);

      if (rslt == BMA4_OK) {
        data = BMA4_SET_BITS_POS_0(data, BMA4_CONFIG_SPI3, spi);
        rslt |= bma4_write_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);
      }
    } else {
      rslt |= BMA4_E_OUT_OF_RANGE;
    }
  }

  return rslt;
}

/*!
 *  @brief This API writes the available sensor specific commands
 *  to the sensor.
 */
uint16_t bma4_set_command_register(uint8_t command_reg, struct bma4_dev *dev) {
  uint16_t rslt = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Write command register */
    rslt |= bma4_write_regs(BMA4_CMD_ADDR, &command_reg, 1, dev);
  }

  return rslt;
}

/*!
 * @brief This API sets the I2C device address of auxiliary sensor
 */
uint16_t bma4_set_i2c_device_addr(struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data = 0, dev_id = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Write the auxiliary I2C device address */
    rslt |= bma4_read_regs(BMA4_AUX_DEV_ID_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      dev_id = BMA4_SET_BITSLICE(data, BMA4_I2C_DEVICE_ADDR,
                                 dev->aux_config.aux_dev_addr);
      rslt |= bma4_write_regs(BMA4_AUX_DEV_ID_ADDR, &dev_id, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API sets the register access on MAG_IF[2], MAG_IF[3],
 *  MAG_IF[4] in the sensor. This implies that the DATA registers are
 *  not updated with Mag values automatically.
 */
uint16_t bma4_set_mag_manual_enable(uint8_t mag_manual, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;
  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Write the Mag manual*/
    rslt |= bma4_read_regs(BMA4_AUX_IF_CONF_ADDR, &data, 1, dev);
    dev->delay(BMA4_GEN_READ_WRITE_DELAY);

    if (rslt == BMA4_OK) {
      /* Set the bit of Mag manual enable */
      data = BMA4_SET_BITSLICE(data, BMA4_MAG_MANUAL_ENABLE, mag_manual);
      rslt |= bma4_write_regs(BMA4_AUX_IF_CONF_ADDR, &data, 1, dev);

      if (rslt == BMA4_OK)
        dev->aux_config.manual_enable = (uint8_t)mag_manual;
    } else {
      /*dev->mag_manual_enable = 0;*/
      dev->aux_config.manual_enable = 0;
    }
  }

  return rslt;
}

/*!
 *  @brief This API checks whether the Mag access is done manually or
 *  automatically in the sensor.
 *  If the Mag access is done through manual mode then Mag data registers
 *  in sensor are not updated automatically.
 */
uint16_t bma4_get_mag_manual_enable(uint8_t *mag_manual, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read Mag manual */
    rslt |= bma4_read_regs(BMA4_AUX_IF_CONF_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *mag_manual = BMA4_GET_BITSLICE(data, BMA4_MAG_MANUAL_ENABLE);
  }

  return rslt;
}

/*!
 *  @brief This API sets the I2C interface configuration(if) mode
 *  for auxiliary Mag.
 */
uint16_t bma4_set_aux_if_mode(uint8_t if_mode, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITSLICE(data, BMA4_IF_CONFIG_IF_MODE, if_mode);
      rslt |= bma4_write_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API gets the address of the register of Aux Mag sensor
 *  where the data to be read.
 */
uint16_t bma4_get_mag_read_addr(uint8_t *mag_read_addr, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_AUX_RD_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *mag_read_addr = BMA4_GET_BITS_POS_0(data, BMA4_READ_ADDR);
  }

  return rslt;
}

/*!
 *  @brief This API sets the address of the register of Aux Mag sensor
 *  where the data to be read.
 */
uint16_t bma4_set_mag_read_addr(uint8_t mag_read_addr, struct bma4_dev *dev) {
  uint16_t rslt = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Write the Mag read address*/
    rslt |= bma4_write_regs(BMA4_AUX_RD_ADDR, &mag_read_addr, 1, dev);
  }

  return rslt;
}

/*!
 *  @brief This API gets the Aux Mag write address from the sensor.
 *  Mag write address is where the Mag data will be written.
 */
uint16_t bma4_get_mag_write_addr(uint8_t *mag_write_addr,
                                 struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_AUX_WR_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *mag_write_addr = BMA4_GET_BITS_POS_0(data, BMA4_WRITE_ADDR);
  }

  return rslt;
}

/*!
 *  @brief This API sets the Aux Mag write address in the sensor.
 *  Mag write address is where the Mag data will be written.
 */
uint16_t bma4_set_mag_write_addr(uint8_t mag_write_addr, struct bma4_dev *dev) {
  uint16_t rslt = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL)
    rslt |= BMA4_E_NULL_PTR;
  else
    rslt |= bma4_write_regs(BMA4_AUX_WR_ADDR, &mag_write_addr, 1, dev);

  return rslt;
}

/*!
 *  @brief This API reads the data from the sensor which is written to the
 *  Mag.
 */
uint16_t bma4_get_mag_write_data(uint8_t *mag_write_data,
                                 struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_AUX_WR_DATA_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *mag_write_data = BMA4_GET_BITS_POS_0(data, BMA4_WRITE_DATA);
  }

  return rslt;
}

/*!
 *  @brief This API sets the data in the sensor which in turn will
 *  be written to Mag.
 */
uint16_t bma4_set_mag_write_data(uint8_t mag_write_data, struct bma4_dev *dev) {
  uint16_t rslt = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL)
    rslt |= BMA4_E_NULL_PTR;
  else
    rslt |= bma4_write_regs(BMA4_AUX_WR_DATA_ADDR, &mag_write_data, 1, dev);

  return rslt;
}

/*!
 *  @brief This API reads the x,y,z and r axis data from the auxiliary
 *  Mag BMM150/AKM9916 sensor.
 */
uint16_t bma4_read_mag_xyzr(struct bma4_mag_xyzr *mag, struct bma4_dev *dev) {
  uint16_t rslt                           = 0;
  uint16_t msb                            = 0;
  uint16_t lsb                            = 0;
  uint8_t data[BMA4_MAG_XYZR_DATA_LENGTH] = {0};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |=
        bma4_read_regs(BMA4_DATA_0_ADDR, data, BMA4_MAG_XYZR_DATA_LENGTH, dev);

    if (rslt == BMA4_OK) {
      /* Data X */
      /* X-axis LSB value shifting */
      lsb = BMA4_GET_BITSLICE(data[BMA4_MAG_X_LSB_BYTE], BMA4_DATA_MAG_X_LSB);
      msb = data[BMA4_MAG_X_MSB_BYTE];
      mag->x = (int16_t)((msb << 8) | lsb);
      mag->x = (mag->x / 0x08);

      /* Data Y */
      /* Y-axis LSB value shifting */
      lsb = BMA4_GET_BITSLICE(data[BMA4_MAG_Y_LSB_BYTE], BMA4_DATA_MAG_Y_LSB);
      msb = data[BMA4_MAG_Y_MSB_BYTE];
      mag->y = (int16_t)((msb << 8) | lsb);
      mag->y = (mag->y / 0x08);

      /* Data Z */
      /* Z-axis LSB value shifting */
      lsb = BMA4_GET_BITSLICE(data[BMA4_MAG_Z_LSB_BYTE], BMA4_DATA_MAG_Z_LSB);
      msb = data[BMA4_MAG_Z_MSB_BYTE];
      mag->z = (int16_t)((msb << 8) | lsb);
      mag->z = (mag->z / 0x02);

      /* RHall */
      /* R-axis LSB value shifting */
      lsb = BMA4_GET_BITSLICE(data[BMA4_MAG_R_LSB_BYTE], BMA4_DATA_MAG_R_LSB);
      msb = data[BMA4_MAG_R_MSB_BYTE];
      mag->r = (int16_t)((msb << 8) | lsb);
      mag->r = (mag->r / 0x04);
    }
  }

  return rslt;
}

/*!
 *  @brief This API sets the burst data length (1,2,6,8 byte) of auxiliary
 *  Mag sensor.
 */
uint16_t bma4_set_mag_burst(uint8_t mag_burst, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Write auxiliary burst mode length*/
    rslt |= bma4_read_regs(BMA4_AUX_IF_CONF_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITS_POS_0(data, BMA4_MAG_BURST, mag_burst);
      rslt |= bma4_write_regs(BMA4_AUX_IF_CONF_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the burst data length of Mag set in the sensor.
 */
uint16_t bma4_get_mag_burst(uint8_t *mag_burst, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Write Mag burst mode length*/
    rslt |= bma4_read_regs(BMA4_AUX_IF_CONF_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *mag_burst = BMA4_GET_BITS_POS_0(data, BMA4_MAG_BURST);
  }

  return rslt;
}

/*!
 *  @brief This API reads the FIFO data of Accel and/or Mag sensor
 */
uint16_t bma4_read_fifo_data(struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;
  uint8_t addr  = BMA4_FIFO_DATA_ADDR;
  /* check the bma4 structure as NULL*/
  if (dev == NULL || dev->fifo == NULL || dev->fifo->data == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    reset_fifo_data_structure(dev);
    /* read FIFO data*/
    if (dev->interface == BMA4_SPI_INTERFACE)
      addr = addr | BMA4_SPI_RD_MASK;

    rslt |=
        dev->bus_read(dev->dev_addr, addr, dev->fifo->data, dev->fifo->length);
    /* read fifo frame content configuration*/
    rslt |= bma4_read_regs(BMA4_FIFO_CONFIG_1_ADDR, &data, 1, dev);
    /* filter fifo header enabled status */
    dev->fifo->fifo_header_enable = data & BMA4_FIFO_HEADER;
    /* filter accel/mag data enabled status */
    dev->fifo->fifo_data_enable = data & BMA4_FIFO_M_A_ENABLE;
  }

  return rslt;
}

/*!
 *  @brief This API parses and extracts the accelerometer frames from
 *  FIFO data read by the "bma4_read_fifo_data" API and stores it in the
 *  "accel_data" structure instance.
 */
uint16_t bma4_extract_accel(struct bma4_accel *accel_data,
                            uint16_t *accel_length,
                            const struct bma4_dev *dev) {
  uint16_t rslt             = 0;
  uint16_t data_index       = 0;
  uint16_t accel_index      = 0;
  uint16_t data_read_length = 0;

  if (dev == NULL || dev->fifo == NULL || dev->fifo->data == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Parsing the FIFO data in header-less mode */
    if (dev->fifo->fifo_header_enable == 0) {
      get_accel_len_to_parse(&data_index, &data_read_length, accel_length, dev);

      for (; data_index < data_read_length;) {
        unpack_acc_frm(accel_data, &data_index, &accel_index,
                       dev->fifo->fifo_data_enable, dev);
        /*Check for the availability of next
        two bytes of FIFO data */
        check_empty_fifo(&data_index, dev);
      }
      /* update number of accel data read*/
      *accel_length = accel_index;
      /*update the accel byte index*/
      dev->fifo->accel_byte_start_idx = data_index;
    } else {
      /* Parsing the FIFO data in header mode */
      extract_accel_header_mode(accel_data, accel_length, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API parses and extracts the magnetometer frames from
 *  FIFO data read by the "bma4_read_fifo_data" API and stores it in the
 *  "mag_data" structure instance parameter of this API
 */
uint16_t bma4_extract_mag(struct bma4_mag *mag_data, uint16_t *mag_length,
                          const struct bma4_dev *dev) {
  uint16_t rslt             = 0;
  uint16_t data_index       = 0;
  uint16_t mag_index        = 0;
  uint16_t data_read_length = 0;

  if (dev == NULL || dev->fifo == NULL || dev->fifo->data == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Parsing the FIFO data in header-less mode */
    if (dev->fifo->fifo_header_enable == 0) {
      get_mag_len_to_parse(&data_index, &data_read_length, mag_length, dev);
      for (; data_index < data_read_length;) {
        rslt |= unpack_mag_frm(mag_data, &data_index, &mag_index,
                               dev->fifo->fifo_data_enable, dev);
        /*Check for the availability of next
        two bytes of FIFO data */
        check_empty_fifo(&data_index, dev);
      }
      /* update number of Aux. sensor data read*/
      *mag_length = mag_index;
      /*update the Aux. sensor frame index*/
      dev->fifo->mag_byte_start_idx = data_index;
    } else {
      /* Parsing the FIFO data in header mode */
      rslt |= extract_mag_header_mode(mag_data, mag_length, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the FIFO water mark level which is set
 *  in the sensor.
 */
uint16_t bma4_get_fifo_wm(uint16_t *fifo_wm, struct bma4_dev *dev) {
  uint16_t rslt   = 0;
  uint8_t data[2] = {0, 0};

  /* Check the bma4  structure as NULL*/
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read the FIFO water mark level*/
    rslt |=
        bma4_read_regs(BMA4_FIFO_WTM_0_ADDR, data, BMA4_FIFO_WM_LENGTH, dev);

    if (BMA4_OK == rslt)
      *fifo_wm = (data[1] << 8) | (data[0]);
  }

  return rslt;
}

/*!
 *  @brief This API sets the FIFO watermark level in the sensor.
 */
uint16_t bma4_set_fifo_wm(uint16_t fifo_wm, struct bma4_dev *dev) {
  uint16_t rslt   = 0;
  uint8_t data[2] = {0, 0};

  /* Check the bma4  structure as NULL*/
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {

    data[0] = BMA4_GET_LSB(fifo_wm);
    data[1] = BMA4_GET_MSB(fifo_wm);
    /* consecutive write is not possible in suspend mode hence
         separate write is used with delay of 1 ms*/
    /* Write the fifo watermark level*/
    rslt |= bma4_write_regs(BMA4_FIFO_WTM_0_ADDR, &data[0], 1, dev);
    dev->delay(BMA4_GEN_READ_WRITE_DELAY);
    rslt |= bma4_write_regs((BMA4_FIFO_WTM_0_ADDR + 1), &data[1], 1, dev);
  }

  return rslt;
}

/*!
 *  @brief This API checks whether the Accel FIFO data is set for filtered
 *  or unfiltered mode.
 */
uint16_t bma4_get_accel_fifo_filter_data(uint8_t *accel_fifo_filter,
                                         struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read the Accel FIFO filter data */
    rslt |= bma4_read_regs(BMA4_FIFO_DOWN_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *accel_fifo_filter = BMA4_GET_BITSLICE(data, BMA4_FIFO_FILTER_ACCEL);
  }

  return rslt;
}

/*!
 *  @brief This API sets the condition of Accel FIFO data either to
 *  filtered or unfiltered mode.
 */
uint16_t bma4_set_accel_fifo_filter_data(uint8_t accel_fifo_filter,
                                         struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (accel_fifo_filter <= BMA4_MAX_VALUE_FIFO_FILTER) {
      rslt |= bma4_read_regs(BMA4_FIFO_DOWN_ADDR, &data, 1, dev);

      if (rslt == BMA4_OK) {
        /* Write Accel FIFO filter data */
        data =
            BMA4_SET_BITSLICE(data, BMA4_FIFO_FILTER_ACCEL, accel_fifo_filter);
        rslt |= bma4_write_regs(BMA4_FIFO_DOWN_ADDR, &data, 1, dev);
      }
    } else {
      rslt |= BMA4_E_OUT_OF_RANGE;
    }
  }
  return rslt;
}

/*!
 *  @brief This API reads the down sampling rates which is configured
 *  for Accel FIFO data.
 */
uint16_t bma4_get_fifo_down_accel(uint8_t *fifo_down, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read the Accel FIFO down data */
    rslt |= bma4_read_regs(BMA4_FIFO_DOWN_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *fifo_down = BMA4_GET_BITSLICE(data, BMA4_FIFO_DOWN_ACCEL);
  }

  return rslt;
}

/*!
 *  @brief This API sets the down-sampling rates for Accel FIFO.
 */
uint16_t bma4_set_fifo_down_accel(uint8_t fifo_down, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Write the Accel FIFO down data */
    rslt |= bma4_read_regs(BMA4_FIFO_DOWN_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITSLICE(data, BMA4_FIFO_DOWN_ACCEL, fifo_down);
      rslt |= bma4_write_regs(BMA4_FIFO_DOWN_ADDR, &data, 1, dev);
    }
  }
  return rslt;
}

/*!
 *  @brief This API reads the length of FIFO data available in the sensor
 *  in the units of bytes.
 */
uint16_t bma4_get_fifo_length(uint16_t *fifo_length, struct bma4_dev *dev) {
  uint16_t rslt                       = 0;
  uint8_t index                       = 0;
  uint8_t data[BMA4_FIFO_DATA_LENGTH] = {0, 0};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read FIFO length*/
    rslt |= bma4_read_regs(BMA4_FIFO_LENGTH_0_ADDR, data, BMA4_FIFO_DATA_LENGTH,
                           dev);

    if (rslt == BMA4_OK) {
      index = BMA4_FIFO_LENGTH_MSB_BYTE;
      data[index] =
          BMA4_GET_BITS_POS_0(data[index], BMA4_FIFO_BYTE_COUNTER_MSB);
      *fifo_length = ((data[index] << 8) | data[index - 1]);
    }
  }

  return rslt;
}

/*!
 *  @brief This API aligns and compensates the Mag data of BMM150/AKM9916
 *  sensor.
 */
uint16_t
bma4_second_if_mag_compensate_xyz(struct bma4_mag_fifo_data mag_fifo_data,
                                  uint8_t mag_second_if,
                                  struct bma4_mag *compensated_mag_data) {
  uint16_t rslt = 0;
#ifdef BMM150
  int16_t mag_x  = 0;
  int16_t mag_y  = 0;
  int16_t mag_z  = 0;
  uint16_t mag_r = 0;
#endif

  switch (mag_second_if) {
#ifdef BMM150
  case BMA4_SEC_IF_BMM150:
    /* X data*/
    mag_x =
        (int16_t)((mag_fifo_data.mag_x_msb << 8) | (mag_fifo_data.mag_x_lsb));
    mag_x = (int16_t)(mag_x / 0x08);

    /* Y data*/
    mag_y =
        (int16_t)((mag_fifo_data.mag_y_msb << 8) | (mag_fifo_data.mag_y_lsb));
    mag_y = (int16_t)(mag_y / 0x08);

    /* Z data*/
    mag_z =
        (int16_t)((mag_fifo_data.mag_z_msb << 8) | (mag_fifo_data.mag_z_lsb));
    mag_z = (int16_t)(mag_z / 0x02);

    /* R data*/
    mag_r = (uint16_t)((mag_fifo_data.mag_r_y2_msb << 8) |
                       (mag_fifo_data.mag_r_y2_lsb));
    mag_r = (uint16_t)(mag_r >> 2);

    /* Compensated Mag x data */
    compensated_mag_data->x = bma4_bmm150_mag_compensate_X(mag_x, mag_r);

    /* Compensated Mag y data */
    compensated_mag_data->y = bma4_bmm150_mag_compensate_Y(mag_y, mag_r);

    /* Compensated Mag z data */
    compensated_mag_data->z = bma4_bmm150_mag_compensate_Z(mag_z, mag_r);
    break;
#endif

#ifdef AKM9916

  case BMA4_SEC_IF_AKM09916:
    /* Compensated X data */
    compensated_mag_data->x =
        (int16_t)((mag_fifo_data.mag_x_msb << 8) | (mag_fifo_data.mag_x_lsb));
    /* Compensated Y data*/
    compensated_mag_data->y =
        (int16_t)((mag_fifo_data.mag_y_msb << 8) | (mag_fifo_data.mag_y_lsb));
    /* Compensated Z data*/
    compensated_mag_data->z =
        (int16_t)((mag_fifo_data.mag_z_msb << 8) | (mag_fifo_data.mag_z_lsb));
    break;

#endif
  default:
    rslt |= BMA4_E_OUT_OF_RANGE;
    break;
  }
  return rslt;
}

/*!
 *  @brief This API reads Mag. x,y and z axis data from either BMM150 or
 *  AKM9916 sensor
 */
uint16_t bma4_read_mag_xyz(struct bma4_mag *mag, uint8_t sensor_select,
                           struct bma4_dev *dev) {
  uint16_t rslt = 0;

#if defined(AKM9916) || defined(BMM150)
  uint8_t index;
  uint16_t msb                           = 0;
  uint16_t lsb                           = 0;
  uint8_t data[BMA4_MAG_XYZ_DATA_LENGTH] = {0};
#endif

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    switch (sensor_select) {

#if defined(BMM150)

    case BMA4_SEC_IF_BMM150:
      rslt |=
          bma4_read_regs(BMA4_DATA_0_ADDR, data, BMA4_MAG_XYZ_DATA_LENGTH, dev);

      if (rslt == BMA4_OK) {
        index = BMA4_MAG_X_LSB_BYTE;
        /*X-axis LSB value shifting*/
        data[index] = BMA4_GET_BITSLICE(data[index], BMA4_DATA_MAG_X_LSB);
        /* Data X */
        msb    = data[index + 1];
        lsb    = data[index];
        mag->x = (int16_t)((msb << 8) | lsb);
        mag->x = (mag->x / 0x08);

        /* Data Y */
        /*Y-axis LSB value shifting*/
        data[index + 2] =
            BMA4_GET_BITSLICE(data[index + 2], BMA4_DATA_MAG_Y_LSB);
        msb    = data[index + 3];
        lsb    = data[index + 2];
        mag->y = (int16_t)((msb << 8) | lsb);
        mag->y = (mag->y / 0x08);

        /* Data Z */
        /*Z-axis LSB value shifting*/
        data[index + 4] =
            BMA4_GET_BITSLICE(data[index + 4], BMA4_DATA_MAG_Z_LSB);
        msb    = data[index + 5];
        lsb    = data[index + 4];
        mag->z = (int16_t)((msb << 8) | lsb);
        mag->z = (mag->z / 0x02);
      }
      break;
#endif

#if defined(AKM9916)
    case BMA4_SEC_IF_AKM09916:

      if (AKM9916_SENSOR == dev->aux_sensor) {
        rslt |= bma4_read_regs(BMA4_DATA_0_ADDR, data, BMA4_MAG_XYZ_DATA_LENGTH,
                               dev);

        if (rslt == BMA4_OK) {
          index = BMA4_MAG_X_LSB_BYTE;
          /* Data X */
          msb    = data[index + 1];
          lsb    = data[index];
          mag->x = (int16_t)((msb << 8) | lsb);

          /* Data Y */
          msb    = data[index + 3];
          lsb    = data[index + 2];
          mag->y = (int32_t)((msb << 8) | lsb);

          /* Data Z */
          msb    = data[index + 5];
          lsb    = data[index + 4];
          mag->z = (int16_t)((msb << 8) | lsb);
        }
      }
      break;
#endif

    default:
      rslt |= BMA4_E_OUT_OF_RANGE;
      break;
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the auxiliary I2C interface configuration which
 *  is set in the sensor.
 */
uint16_t bma4_get_if_mode(uint8_t *if_mode, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read auxiliary interface configuration */
    rslt |= bma4_read_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *if_mode = BMA4_GET_BITSLICE(data, BMA4_IF_CONFIG_IF_MODE);
  }

  return rslt;
}

/*!
 *  @brief This API sets the auxiliary interface configuration in the
 *  sensor.
 */
uint16_t bma4_set_if_mode(uint8_t if_mode, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (if_mode <= BMA4_MAX_IF_MODE) {
      /* Write the interface configuration mode */
      rslt |= bma4_read_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);
      if (rslt == BMA4_OK) {
        data = BMA4_SET_BITSLICE(data, BMA4_IF_CONFIG_IF_MODE, if_mode);
        rslt |= bma4_write_regs(BMA4_IF_CONFIG_ADDR, &data, 1, dev);
      }
    } else {
      rslt |= BMA4_E_OUT_OF_RANGE;
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the data ready status of Accel from the sensor.
 */
uint16_t bma4_get_accel_data_rdy(uint8_t *data_rdy, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /*Reads the status of Accel data ready*/
    rslt |= bma4_read_regs(BMA4_STATUS_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *data_rdy = BMA4_GET_BITSLICE(data, BMA4_STAT_DATA_RDY_ACCEL);
  }

  return rslt;
}

/*!
 *  @brief This API reads the data ready status of Mag from the sensor.
 *  The status get reset when Mag data register is read.
 */
uint16_t bma4_get_mag_data_rdy(uint8_t *data_rdy, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /*Reads the status of Accel data ready*/
    rslt |= bma4_read_regs(BMA4_STATUS_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK)
      *data_rdy = BMA4_GET_BITSLICE(data, BMA4_STAT_DATA_RDY_MAG);
  }

  return rslt;
}

/*!
 *  @brief This API reads the ASIC status from the sensor.
 *  The status information is mentioned in the below table.
 */
uint16_t bma4_get_asic_status(struct bma4_asic_status *asic_status,
                              struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read the Mag I2C device address*/
    rslt |= bma4_read_regs(BMA4_INTERNAL_ERROR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      asic_status->sleep                  = (data & 0x01);
      asic_status->irq_ovrn               = ((data & 0x02) >> 0x01);
      asic_status->wc_event               = ((data & 0x04) >> 0x02);
      asic_status->stream_transfer_active = ((data & 0x08) >> 0x03);
    }
  }

  return rslt;
}

/*!
 *  @brief This API enables the offset compensation for filtered and
 *  unfiltered  Accel data.
 */
uint16_t bma4_set_offset_comp(uint8_t offset_en, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_NV_CONFIG_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      /* Write Accel FIFO filter data */
      data = BMA4_SET_BITSLICE(data, BMA4_NV_ACCEL_OFFSET, offset_en);
      rslt |= bma4_write_regs(BMA4_NV_CONFIG_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API gets the status of Accel offset compensation
 */
uint16_t bma4_get_offset_comp(uint8_t *offset_en, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_NV_CONFIG_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      /* Write Accel FIFO filter data */
      *offset_en = BMA4_GET_BITSLICE(data, BMA4_NV_ACCEL_OFFSET);
    }
  }

  return rslt;
}

/*!
 *  @brief This API performs Fast Offset Compensation for Accel.
 *
 *  @note The g-values to be passed to the parameter should be
 *  multiples of 1000000.
 */
uint16_t bma4_perform_accel_foc(const int32_t accel_g_value[3],
                                struct bma4_dev *dev) {
  uint16_t rslt                     = 0;
  struct bma4_accel accel_value[10] = {{0}};
  struct accel_offset offset        = {0};
  struct offset_delta delta         = {{0, 0}, {0, 0}, {0, 0}};
  struct bma4_accel_config acc_conf = {0};
  uint8_t accel_en                  = 0;
  uint8_t adv_pwr_save              = 0;
  uint8_t range                     = 0;
  uint16_t lsb_per_g                = 0;
  struct accel_temp temp            = {0};
  struct bma4_accel avg             = {0};
  struct bma4_accel accel_data      = {0};
  uint8_t i                         = 0;

  /* used to validate user input */
  rslt |= validate_user_input(accel_g_value);

  if (BMA4_OK == rslt) {
    /* Configure accel config, accel enable and
    advance power save for FOC */
    rslt |= foc_config(&acc_conf, &accel_en, &adv_pwr_save, dev);

    /*TO DO: Check for data ready status before
    reading accel values*/

    if (BMA4_OK == rslt) {
      /* Giving a delay of 20ms before reading accel data
      since odr is configured as 50Hz */
      for (i = 0; i < 10; i++) {
        dev->delay(20);
        rslt |= bma4_read_accel_xyz(&accel_value[i], dev);
        temp.x = temp.x + (int32_t)accel_value[i].x;
        temp.y = temp.y + (int32_t)accel_value[i].y;
        temp.z = temp.z + (int32_t)accel_value[i].z;
      }

      /* Take average of x, y and z data for lesser noise */
      avg.x = (int16_t)(temp.x / 10);
      avg.y = (int16_t)(temp.y / 10);
      avg.z = (int16_t)(temp.z / 10);

      /* Copy average value in another structure */
      accel_data = avg;

      if (BMA4_OK == rslt) {
        /* Get the exact range value */
        map_range(acc_conf.range, &range);
        /* Get LSB per bit given the range and resolution */
        lsb_per_g = (uint16_t)(power(2, dev->resolution) / (2 * range));
        /* Compensate accel data against gravity */
        comp_for_grvty(lsb_per_g, accel_g_value, &accel_data, &delta);
        /* scale according to offset register resolution*/
        scale_offset(dev->resolution, range, &delta, &offset);
        /* normalise the data with offset*/
        normalise_offset(&delta, &offset);

        /* offset values are written in the offset register */
        rslt |=
            bma4_write_regs(BMA4_OFFSET_0_ADDR, (uint8_t *)&offset.x, 1, dev);
        rslt |=
            bma4_write_regs(BMA4_OFFSET_1_ADDR, (uint8_t *)&offset.y, 1, dev);
        rslt |=
            bma4_write_regs(BMA4_OFFSET_2_ADDR, (uint8_t *)&offset.z, 1, dev);

        /* Enable offset compensation */
        rslt |= bma4_set_offset_comp(BMA4_ENABLE, dev);

        /* Set accel config, accel enable and advance power save */
        rslt |= bma4_set_accel_config(&acc_conf, dev);
        rslt |= bma4_set_accel_enable(accel_en, dev);
        rslt |= bma4_set_advance_power_save(adv_pwr_save, dev);
      } else {
        rslt |= BMA4_E_FOC_FAIL;
      }
    }
  }
  return rslt;
}

/*!
 *  @brief This API checks whether the self test functionality of the sensor
 *  is working or not.
 *  The following parameter of struct bma4_dev, should have the valid value
 * before performing the Self test,
 *  1.  Variant and 2. Resolution
 */
uint16_t bma4_perform_accel_selftest(uint8_t *result, struct bma4_dev *dev) {
  uint16_t rslt              = 0;
  struct bma4_accel positive = {0};
  struct bma4_accel negative = {0};
  /*! Structure for difference of accel values in g*/
  struct selftest_delta_limit accel_data_diff = {0};
  /*! Structure for difference of accel values in mg*/
  struct selftest_delta_limit accel_data_diff_mg = {0};

  *result = BMA4_SELFTEST_FAIL;

  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {

    rslt = set_accel_selftest_config(dev);
    dev->delay(20);
    rslt |= bma4_selftest_config(BMA4_ENABLE, dev);

    if (rslt == BMA4_OK) {
      dev->delay(100);
      rslt = bma4_read_accel_xyz(&positive, dev);
      rslt |= bma4_selftest_config(BMA4_DISABLE, dev);

      if (rslt == BMA4_OK) {
        dev->delay(100);
        rslt = bma4_read_accel_xyz(&negative, dev);

        accel_data_diff.x = ABS(positive.x) + ABS(negative.x);
        accel_data_diff.y = ABS(positive.y) + ABS(negative.y);
        accel_data_diff.z = ABS(positive.z) + ABS(negative.z);

        /*! Converting LSB of the differences of accel values to mg*/
        convert_lsb_g(&accel_data_diff, &accel_data_diff_mg, dev);
        /*! Validating self test for accel values in mg*/
        rslt |= validate_selftest(&accel_data_diff_mg, dev);

        if (rslt == BMA4_OK)
          *result = BMA4_SELFTEST_PASS;

        /* Triggers a soft reset */
        rslt |= bma4_set_command_register(0xB6, dev);
        dev->delay(200);
      }
    }
  }

  return rslt;
}

/*!
 *  @brief This API performs the steps needed for Self test operation
 *  before reading the Accel Self test data.
 */
uint16_t bma4_selftest_config(uint8_t sign, struct bma4_dev *dev) {
  uint16_t rslt = 0;

  rslt |= set_accel_selftest_enable(BMA4_ENABLE, dev);
  rslt |= set_accel_selftest_sign(sign, dev);

  /* Set self test amplitude based on variant */
  switch (dev->variant) {
  case BMA42X_VARIANT:
    /* Set self test amplitude to high for BMA42x */
    rslt |= set_accel_selftest_amp(BMA4_ENABLE, dev);
    break;

  case BMA45X_VARIANT:
    /* Set self test amplitude to low for BMA45x */
    rslt |= set_accel_selftest_amp(BMA4_DISABLE, dev);
    break;

  default:
    rslt = BMA4_E_INVALID_SENSOR;
    break;
  }

  return rslt;
}

/*!
 *  @brief API sets the interrupt to either interrupt1 or
 *  interrupt2 pin in the sensor.
 */
uint16_t bma4_map_interrupt(uint8_t int_line, uint16_t int_map, uint8_t enable,
                            struct bma4_dev *dev) {
  uint16_t rslt    = 0;
  uint8_t data[3]  = {0, 0, 0};
  uint8_t index[2] = {BMA4_INT_MAP_1_ADDR, BMA4_INT_MAP_2_ADDR};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {

    rslt |= bma4_read_regs(BMA4_INT_MAP_1_ADDR, data, 3, dev);

    if (enable == TRUE) {
      /* Feature interrupt mapping */
      data[int_line] |= (uint8_t)(int_map & (0x00FF));
      /* Hardware interrupt mapping */
      if (int_line == BMA4_INTR2_MAP)
        data[2] |= (uint8_t)((int_map & (0xFF00)) >> 4);
      else
        data[2] |= (uint8_t)((int_map & (0xFF00)) >> 8);

      rslt |= bma4_write_regs(index[int_line], &data[int_line], 1, dev);
      rslt |= bma4_write_regs(BMA4_INT_MAP_DATA_ADDR, &data[2], 1, dev);

    } else {
      /* Feature interrupt un-mapping */
      data[int_line] &= (~(uint8_t)(int_map & (0x00FF)));
      /* Hardware interrupt un-mapping */
      if (int_line == BMA4_INTR2_MAP)
        data[2] &= (~(uint8_t)((int_map & (0xFF00)) >> 4));
      else
        data[2] &= (~(uint8_t)((int_map & (0xFF00)) >> 8));

      rslt |= bma4_write_regs(index[int_line], &data[int_line], 1, dev);
      rslt |= bma4_write_regs(BMA4_INT_MAP_DATA_ADDR, &data[2], 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API sets the interrupt mode in the sensor.
 */
uint16_t bma4_set_interrupt_mode(uint8_t mode, struct bma4_dev *dev) {
  uint16_t rslt = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {

    if (mode == BMA4_NON_LATCH_MODE || mode == BMA4_LATCH_MODE)
      rslt |= bma4_write_regs(BMA4_INTR_LATCH_ADDR, &mode, 1, dev);
    else
      rslt |= BMA4_E_OUT_OF_RANGE;
  }

  return rslt;
}

/*!
 *  @brief This API gets the interrupt mode which is set in the sensor.
 */
uint16_t bma4_get_interrupt_mode(uint8_t *mode, struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_INTR_LATCH_ADDR, &data, 1, dev);
    *mode = data;
  }

  return rslt;
}

/*!
 *  @brief This API sets the auxiliary Mag(BMM150 or AKM9916) output data
 *  rate and offset.
 */
uint16_t bma4_set_aux_mag_config(const struct bma4_aux_mag_config *aux_mag,
                                 struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if ((aux_mag->odr >= BMA4_OUTPUT_DATA_RATE_0_78HZ) &&
        (aux_mag->odr <= BMA4_OUTPUT_DATA_RATE_1600HZ) &&
        ((aux_mag->offset & BMA4_MAG_CONFIG_OFFSET_MSK) == 0x00)) {
      data = (uint8_t)(aux_mag->odr |
                       ((aux_mag->offset << BMA4_MAG_CONFIG_OFFSET_POS)));
      rslt |= bma4_write_regs(BMA4_AUX_CONFIG_ADDR, &data, 1, dev);
    } else {
      rslt |= BMA4_E_OUT_OF_RANGE;
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the auxiliary Mag(BMM150 or AKM9916) output data
 *  rate and offset.
 */
uint16_t bma4_get_aux_mag_config(struct bma4_aux_mag_config *aux_mag,
                                 struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_AUX_CONFIG_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      aux_mag->odr    = (data & 0x0F);
      aux_mag->offset = (data & BMA4_MAG_CONFIG_OFFSET_MSK) >> 4;
    }
  }

  return rslt;
}

/*! @brief This API sets the FIFO configuration in the sensor.
 */
uint16_t bma4_set_fifo_config(uint8_t config, uint8_t enable,
                              struct bma4_dev *dev) {
  uint16_t rslt         = 0;
  uint8_t data[2]       = {0, 0};
  uint8_t fifo_config_0 = config & BMA4_FIFO_CONFIG_0_MASK;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_FIFO_CONFIG_0_ADDR, data,
                           BMA4_FIFO_CONFIG_LENGTH, dev);

    if (rslt == BMA4_OK) {

      if (fifo_config_0 > 0) {

        if (enable == TRUE)
          data[0] = data[0] | fifo_config_0;
        else
          data[0] = data[0] & (~fifo_config_0);
      }

      if (enable == TRUE)
        data[1] = data[1] | (config & BMA4_FIFO_CONFIG_1_MASK);
      else
        data[1] = data[1] & (~(config & BMA4_FIFO_CONFIG_1_MASK));

      /* Burst write is not possible in suspend mode hence
      separate write is used with delay of 1 ms*/
      rslt |= bma4_write_regs(BMA4_FIFO_CONFIG_0_ADDR, &data[0], 1, dev);
      dev->delay(BMA4_GEN_READ_WRITE_DELAY);
      rslt |= bma4_write_regs((BMA4_FIFO_CONFIG_0_ADDR + 1), &data[1], 1, dev);
    }
  }

  return rslt;
}

/*! @brief This API reads the FIFO configuration from the sensor.
 */
uint16_t bma4_get_fifo_config(uint8_t *fifo_config, struct bma4_dev *dev) {
  uint16_t rslt   = 0;
  uint8_t data[2] = {0, 0};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_FIFO_CONFIG_0_ADDR, data,
                           BMA4_FIFO_CONFIG_LENGTH, dev);

    if (rslt == BMA4_OK)
      *fifo_config =
          ((uint8_t)((data[0] & BMA4_FIFO_CONFIG_0_MASK) | (data[1])));
  }

  return rslt;
}

/*! @brief This function sets the electrical behaviour of interrupt pin1 or
 *  pin2 in the sensor.
 */
uint16_t
bma4_set_int_pin_config(const struct bma4_int_pin_config *int_pin_config,
                        uint8_t int_line, struct bma4_dev *dev) {
  uint16_t rslt                      = 0;
  uint8_t interrupt_address_array[2] = {BMA4_INT1_IO_CTRL_ADDR,
                                        BMA4_INT2_IO_CTRL_ADDR};
  uint8_t data                       = 0;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (int_line <= 1) {
      data = ((uint8_t)(
          (int_pin_config->edge_ctrl & BMA4_INT_EDGE_CTRL_MASK) |
          ((int_pin_config->lvl << 1) & BMA4_INT_LEVEL_MASK) |
          ((int_pin_config->od << 2) & BMA4_INT_OPEN_DRAIN_MASK) |
          ((int_pin_config->output_en << 3) & BMA4_INT_OUTPUT_EN_MASK) |
          ((int_pin_config->input_en << 4) & BMA4_INT_INPUT_EN_MASK)));

      rslt |= bma4_write_regs(interrupt_address_array[int_line], &data, 1, dev);
    } else {
      rslt |= BMA4_E_INT_LINE_INVALID;
    }
  }

  return rslt;
}

/*! @brief This API reads the electrical behavior of interrupt pin1 or pin2
 *  from the sensor.
 */
uint16_t bma4_get_int_pin_config(struct bma4_int_pin_config *int_pin_config,
                                 uint8_t int_line, struct bma4_dev *dev) {
  uint16_t rslt                      = 0;
  uint8_t interrupt_address_array[2] = {BMA4_INT1_IO_CTRL_ADDR,
                                        BMA4_INT2_IO_CTRL_ADDR};
  uint8_t data                       = 0;

  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    if (int_line <= 1) {
      rslt |= bma4_read_regs(interrupt_address_array[int_line], &data, 1, dev);
      /* Assign interrupt configurations to the
      structure members*/
      if (rslt == BMA4_OK) {
        int_pin_config->edge_ctrl = data & BMA4_INT_EDGE_CTRL_MASK;
        int_pin_config->lvl =
            ((data & BMA4_INT_LEVEL_MASK) >> BMA4_INT_LEVEL_POS);
        int_pin_config->od =
            ((data & BMA4_INT_OPEN_DRAIN_MASK) >> BMA4_INT_OPEN_DRAIN_POS);
        int_pin_config->output_en =
            ((data & BMA4_INT_OUTPUT_EN_MASK) >> BMA4_INT_OUTPUT_EN_POS);
        int_pin_config->input_en =
            ((data & BMA4_INT_INPUT_EN_MASK) >> BMA4_INT_INPUT_EN_POS);
      }
    } else {
      rslt |= BMA4_E_INT_LINE_INVALID;
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the Feature and Hardware interrupt status from the
 * sensor.
 */
uint16_t bma4_read_int_status(uint16_t *int_status, struct bma4_dev *dev) {
  uint16_t rslt   = 0;
  uint8_t data[2] = {0};

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    rslt |= bma4_read_regs(BMA4_INT_STAT_0_ADDR, data, 2, dev);

    if (rslt == BMA4_OK) {
      *int_status                  = data[0];
      *((uint8_t *)int_status + 1) = data[1];
    }
  }

  return rslt;
}

/*!
 *  @brief This API reads the Feature interrupt status from the sensor.
 */
uint16_t bma4_read_int_status_0(uint8_t *int_status_0, struct bma4_dev *dev) {
  uint16_t rslt = BMA4_OK;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    /* Null pointer check */
    rslt = BMA4_E_NULL_PTR;
  } else {
    rslt = bma4_read_regs(BMA4_INT_STAT_0_ADDR, int_status_0, 1, dev);
  }

  return rslt;
}

/*!
 *  @brief This API reads the Hardware interrupt status from the sensor.
 */
uint16_t bma4_read_int_status_1(uint8_t *int_status_1, struct bma4_dev *dev) {
  uint16_t rslt = BMA4_OK;

  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    /* Null pointer check */
    rslt = BMA4_E_NULL_PTR;
  } else {
    rslt = bma4_read_regs(BMA4_INT_STAT_1_ADDR, int_status_1, 1, dev);
  }

  return rslt;
}

/*!
 * @brief This API initializes the auxiliary interface to access
 * auxiliary sensor
 */
uint16_t bma4_aux_interface_init(struct bma4_dev *dev) {
  /* Variable to return error codes */
  uint16_t rslt = BMA4_OK;

  /* Check for Null pointer error */
  rslt |= bma4_null_pointer_check(dev);
  if (rslt == BMA4_OK) {
    /* Set the auxiliary sensor configuration */
    rslt = bma4_set_aux_interface_config(dev);
    if (rslt != BMA4_OK)
      rslt = BMA4_E_AUX_CONFIG_FAIL;
  }

  return rslt;
}

/*!
 * @brief This API reads the data from the auxiliary sensor
 */
uint16_t bma4_aux_read(uint8_t aux_reg_addr, uint8_t *aux_data, uint16_t len,
                       struct bma4_dev *dev) {
  /* Variable to return error codes */
  uint16_t rslt = BMA4_OK;

  /* Check for Null pointer error */
  rslt |= bma4_null_pointer_check(dev);
  if (rslt == BMA4_OK) {
    /* Read the data from the data register in terms of
    user defined length  */
    rslt = bma4_extract_aux_data(aux_reg_addr, aux_data, len, dev);
  }

  return rslt;
}

/*!
 * @brief This API writes the data into the auxiliary sensor
 */
uint16_t bma4_aux_write(uint8_t aux_reg_addr, uint8_t *aux_data, uint16_t len,
                        struct bma4_dev *dev) {

  uint16_t rslt = BMA4_OK;

  /* Check for Null pointer error */
  rslt |= bma4_null_pointer_check(dev);
  if (rslt == BMA4_OK) {
    /* Write data in terms of user defined length  */
    if (len > 0) {
      while (len--) {
        /* First set data to write */
        rslt = bma4_write_regs(BMA4_AUX_WR_DATA_ADDR, aux_data, 1, dev);
        dev->delay(BMA4_AUX_COM_DELAY);
        if (rslt == BMA4_OK) {
          /* Then set address to write */
          rslt = bma4_write_regs(BMA4_AUX_WR_ADDR, &aux_reg_addr, 1, dev);
          dev->delay(BMA4_AUX_COM_DELAY);

          /* Increment data array and register address until
           *  user-defined length is greater than 0 */
          if ((rslt == BMA4_OK) && (len > 0)) {
            aux_data++;
            aux_reg_addr++;
          }
        } else {
          rslt = BMA4_E_FAIL;
        }
      }
    } else {
      rslt = BMA4_E_RD_WR_LENGTH_INVALID;
    }
  }

  return rslt;
}

/*****************************************************************************/
/* Static function definition */
/*!
 *  @brief This API converts lsb value of axes to mg for self-test *
 */
static void convert_lsb_g(const struct selftest_delta_limit *accel_data_diff,
                          struct selftest_delta_limit *accel_data_diff_mg,
                          const struct bma4_dev *dev) {
  uint32_t lsb_per_g;
  /*! Range considered for self-test is 8g */
  uint8_t range = 8;

  /*! lsb_per_g for the respective resolution and 8g range*/
  lsb_per_g = (uint32_t)(power(2, dev->resolution) / (2 * range));
  /*! accel x value in mg */
  accel_data_diff_mg->x = (accel_data_diff->x / (int32_t)lsb_per_g) * 1000;
  /*! accel y value in mg */
  accel_data_diff_mg->y = (accel_data_diff->y / (int32_t)lsb_per_g) * 1000;
  /*! accel z value in mg */
  accel_data_diff_mg->z = (accel_data_diff->z / (int32_t)lsb_per_g) * 1000;
}

/*!
 *  @brief This API writes the config stream data in memory using burst mode
 *  @note index value should be even number.
 */
static uint16_t stream_transfer_write(const uint8_t *stream_data,
                                      uint16_t index, struct bma4_dev *dev) {
  uint16_t rslt    = 0;
  uint8_t asic_msb = (uint8_t)((index / 2) >> 4);
  uint8_t asic_lsb = ((index / 2) & 0x0F);

  rslt |= bma4_write_regs(BMA4_RESERVED_REG_5B_ADDR, &asic_lsb, 1, dev);

  if (rslt == BMA4_OK) {
    rslt |= bma4_write_regs(BMA4_RESERVED_REG_5C_ADDR, &asic_msb, 1, dev);

    if (rslt == BMA4_OK)
      rslt |= write_regs(BMA4_FEATURE_CONFIG_ADDR, (uint8_t *)stream_data,
                         dev->read_write_len, dev);
  }

  return rslt;
}

/*!
 *  @brief This API enables or disables the Accel Self test feature in the
 *  sensor.
 */
static uint16_t set_accel_selftest_enable(uint8_t accel_selftest_enable,
                                          struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;
  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {
    /* Read the self test register */
    rslt |= bma4_read_regs(BMA4_ACC_SELF_TEST_ADDR, &data, 1, dev);

    if (rslt == BMA4_OK) {
      data = BMA4_SET_BITS_POS_0(data, BMA4_ACCEL_SELFTEST_ENABLE,
                                 accel_selftest_enable);
      rslt |= bma4_write_regs(BMA4_ACC_SELF_TEST_ADDR, &data, 1, dev);
    }
  }

  return rslt;
}

/*!
 *  @brief This API selects the sign of Accel self-test excitation.
 */
static uint16_t set_accel_selftest_sign(uint8_t accel_selftest_sign,
                                        struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;
  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {

    if (accel_selftest_sign <= BMA4_MAX_VALUE_SELFTEST_SIGN) {
      /* Read the Accel self test sign*/
      rslt |= bma4_read_regs(BMA4_ACC_SELF_TEST_ADDR, &data, 1, dev);

      if (rslt == BMA4_OK) {
        data = BMA4_SET_BITSLICE(data, BMA4_ACCEL_SELFTEST_SIGN,
                                 accel_selftest_sign);
        rslt |= bma4_write_regs(BMA4_ACC_SELF_TEST_ADDR, &data, 1, dev);
      }
    } else {
      rslt = BMA4_E_OUT_OF_RANGE;
    }
  }

  return rslt;
}

/*!
 *  @brief This API sets the Accel self test amplitude in the sensor.
 */
static uint16_t set_accel_selftest_amp(uint8_t accel_selftest_amp,
                                       struct bma4_dev *dev) {
  uint16_t rslt = 0;
  uint8_t data  = 0;
  /* Check the bma4 structure as NULL */
  if (dev == NULL) {
    rslt |= BMA4_E_NULL_PTR;
  } else {

    if (accel_selftest_amp <= BMA4_MAX_VALUE_SELFTEST_AMP) {
      /* Write  self test amplitude*/
      rslt |= bma4_read_regs(BMA4_ACC_SELF_TEST_ADDR, &data, 1, dev);

      if (rslt == BMA4_OK) {
        data = BMA4_SET_BITSLICE(data, BMA4_SELFTEST_AMP, accel_selftest_amp);

        rslt |= bma4_write_regs(BMA4_ACC_SELF_TEST_ADDR, &data, 1, dev);
      }
    } else {
      rslt |= BMA4_E_OUT_OF_RANGE;
    }
  }

  return rslt;
}

/*!
 *  @brief This function enables and configures the Accel which is needed
 *  for Self test operation.
 */
static uint16_t set_accel_selftest_config(struct bma4_dev *dev) {
  uint16_t rslt                  = 0;
  struct bma4_accel_config accel = {0};

  accel.odr       = BMA4_OUTPUT_DATA_RATE_1600HZ;
  accel.bandwidth = BMA4_ACCEL_NORMAL_AVG4;
  accel.perf_mode = BMA4_ENABLE;
  accel.range     = BMA4_ACCEL_RANGE_8G;

  rslt |= bma4_set_accel_enable(BMA4_ENABLE, dev);
  dev->delay(1);
  rslt |= bma4_set_accel_config(&accel, dev);

  return rslt;
}

/*!
 *  @brief This API validates the Accel g value provided as input by the
 *  user for Accel offset compensation.
 *
 *  @note The g-values to be passed to the parameter should be
 *  multiples of 1000000.
 */
static uint16_t validate_user_input(const int32_t *gvalue)

{
  uint8_t index    = 0;
  int32_t min_gval = (int32_t)(-1.0 * BMA4XY_MULTIPLIER);
  int32_t max_gval = (int32_t)(1.0 * BMA4XY_MULTIPLIER);

  while (index < 3) {
    if (gvalue[index] >= min_gval && gvalue[index] <= max_gval)
      index++;
    else
      return BMA4_E_OUT_OF_RANGE;
  }

  return BMA4_OK;
}

/*!
 *  @brief This API normalise the data with offset
 */
static void normalise_offset(const struct offset_delta *compensated_data,
                             struct accel_offset *offset_data) {
  /* for handling negative offset */
  /* employing twos's Complement method*/
  if (compensated_data->x.is_negative == TRUE) {
    offset_data->x = ~offset_data->x;
    offset_data->x += 1;
  }

  if (compensated_data->y.is_negative == TRUE) {
    offset_data->y = ~offset_data->y;
    offset_data->y += 1;
  }

  if (compensated_data->z.is_negative == TRUE) {
    offset_data->z = ~offset_data->z;
    offset_data->z += 1;
  }

  offset_data->x = (uint8_t)((offset_data->x) * (-1));
  offset_data->y = (uint8_t)((offset_data->y) * (-1));
  offset_data->z = (uint8_t)((offset_data->z) * (-1));
}

/*!
 *  @brief This API normalize the data with offset.
 */
static void scale_offset(uint8_t res, uint8_t range,
                         const struct offset_delta *delta,
                         struct accel_offset *data) {
  int8_t bit_pos_3_9mg, bit_pos_3_9mg_nextbit;
  uint8_t round_off = 0;

  /* Find the bit position of 3.9mg */
  bit_pos_3_9mg = get_bit_pos_3_9mg(range, res);

  /* Data register resolution less than or equal to  3.9 mg */
  if (bit_pos_3_9mg > 0) {
    /* Round off, consider if the next bit is high */
    bit_pos_3_9mg_nextbit = bit_pos_3_9mg - 1;
    round_off = (uint8_t)(1 * power(2, ((uint8_t)bit_pos_3_9mg_nextbit)));
    /* scale according to offset register resolution*/
    data->x = (uint8_t)((delta->x.val + round_off) /
                        power(2, ((uint8_t)bit_pos_3_9mg)));
    data->y = (uint8_t)((delta->y.val + round_off) /
                        power(2, ((uint8_t)bit_pos_3_9mg)));
    data->z = (uint8_t)((delta->z.val + round_off) /
                        power(2, ((uint8_t)bit_pos_3_9mg)));
  } else if (bit_pos_3_9mg < 0) {
    bit_pos_3_9mg = (int8_t)(bit_pos_3_9mg * -1);
    data->x = (uint8_t)(delta->x.val * power(2, ((uint8_t)bit_pos_3_9mg)));
    data->y = (uint8_t)(delta->y.val * power(2, ((uint8_t)bit_pos_3_9mg)));
    data->z = (uint8_t)(delta->z.val * power(2, ((uint8_t)bit_pos_3_9mg)));
  } else {
    /* Scale according to offset register resolution */
    data->x = (uint8_t)(delta->x.val);
    data->y = (uint8_t)(delta->y.val);
    data->z = (uint8_t)(delta->z.val);
  }
}

/*!
 *  @brief This API compensate the accel data against gravity.
 *
 *  @note The g-values to be passed to the parameter should be
 *  multiples of 1000000.
 */
static void comp_for_grvty(uint16_t lsb_per_g, const int32_t g_val[3],
                           const struct bma4_accel *data,
                           struct offset_delta *comp_data) {
  int64_t accel_value_lsb[3] = {0};
  uint8_t index;

  for (index = 0; index < 3; index++) {
    /* convert g to lsb */
    accel_value_lsb[index] = ((int64_t)(lsb_per_g) * (int64_t)(g_val[index]));
  }

  /*  Dividing the accel value in LSB by 1000000 to get
  compensated data back in g-value */
  comp_data->x.val = (int16_t)(
      data->x -
      (int16_t)((accel_value_lsb[BMA4_X_AXIS] / (int64_t)BMA4XY_MULTIPLIER)));
  comp_data->y.val = (int16_t)(
      data->y -
      (int16_t)((accel_value_lsb[BMA4_Y_AXIS] / (int64_t)BMA4XY_MULTIPLIER)));
  comp_data->z.val = (int16_t)(
      data->z -
      (int16_t)((accel_value_lsb[BMA4_Z_AXIS] / (int64_t)BMA4XY_MULTIPLIER)));

  if (comp_data->x.val < 0) {
    comp_data->x.val         = ABS(comp_data->x.val);
    comp_data->x.is_negative = 1;
  }

  if (comp_data->y.val < 0) {
    comp_data->y.val         = ABS(comp_data->y.val);
    comp_data->y.is_negative = 1;
  }

  if (comp_data->z.val < 0) {
    comp_data->z.val         = ABS(comp_data->z.val);
    comp_data->z.is_negative = 1;
  }
}

/*!
 *  @brief This API converts the range value into corresponding
 *  integer value.
 */
static void map_range(uint8_t range_in, uint8_t *range_out) {
  switch (range_in) {
  case BMA4_ACCEL_RANGE_2G:
    *range_out = 2;
    break;
  case BMA4_ACCEL_RANGE_4G:
    *range_out = 4;
    break;
  case BMA4_ACCEL_RANGE_8G:
    *range_out = 8;
    break;
  case BMA4_ACCEL_RANGE_16G:
    *range_out = 16;
    break;
  default:
    break;
  }
}

/*!
 *  @brief This API is used to reset the FIFO related configurations
 *  in the fifo_frame structure.
 *
 */
static void reset_fifo_data_structure(const struct bma4_dev *dev) {
  /*Prepare for next FIFO read by resetting FIFO's
  internal data structures*/
  dev->fifo->accel_byte_start_idx      = 0;
  dev->fifo->mag_byte_start_idx        = 0;
  dev->fifo->sc_frame_byte_start_idx   = 0;
  dev->fifo->sensor_time               = 0;
  dev->fifo->skipped_frame_count       = 0;
  dev->fifo->accel_dropped_frame_count = 0;
  dev->fifo->mag_dropped_frame_count   = 0;
}

/*!
 *  @brief This API computes the number of bytes of accel FIFO data
 *  which is to be parsed in header-less mode
 */
static void get_accel_len_to_parse(uint16_t *start_idx, uint16_t *len,
                                   const uint16_t *acc_count,
                                   const struct bma4_dev *dev) {
  uint8_t dummy_byte_spi = 0;

  /*Check if this is the first iteration of data unpacking
   if yes, then consider dummy byte on SPI*/
  if (dev->fifo->accel_byte_start_idx == 0)
    dummy_byte_spi = dev->dummy_byte;

  /*Data start index*/
  *start_idx = dev->fifo->accel_byte_start_idx + dummy_byte_spi;

  if (dev->fifo->fifo_data_enable == BMA4_FIFO_A_ENABLE) {
    /*Len has the number of bytes to loop for */
    *len = (uint16_t)(((*acc_count) * BMA4_FIFO_A_LENGTH) + dummy_byte_spi);
  } else if (dev->fifo->fifo_data_enable == BMA4_FIFO_M_A_ENABLE) {
    /*Len has the number of bytes to loop for */
    *len = (uint16_t)(((*acc_count) * BMA4_FIFO_MA_LENGTH) + dummy_byte_spi);
  } else {
    /*Only aux. sensor or no sensor is enabled in FIFO,
    so there will be no accel data.
    Update the data index as complete*/
    *start_idx = dev->fifo->length;
  }
  if ((*len) > dev->fifo->length) {
    /*Handling the case where more data is requested
    than available*/
    *len = dev->fifo->length;
  }
}

/*!
 *  @brief This API checks the fifo read data as empty frame, if it
 *  is empty frame then moves the index to last byte.
 */
static void check_empty_fifo(uint16_t *data_index, const struct bma4_dev *dev) {
  if ((*data_index + 2) < dev->fifo->length) {
    /* Check if FIFO is empty */
    if ((dev->fifo->data[*data_index] == FIFO_MSB_CONFIG_CHECK) &&
        (dev->fifo->data[*data_index + 1] == FIFO_LSB_CONFIG_CHECK)) {
      /*Update the data index as complete*/
      *data_index = dev->fifo->length;
    }
  }
}

/*!
 *  @brief This API is used to parse the accelerometer data from the
 *  FIFO data in header mode.
 *
 */
static void extract_accel_header_mode(struct bma4_accel *accel_data,
                                      uint16_t *accel_length,
                                      const struct bma4_dev *dev) {
  uint8_t frame_header = 0;
  uint16_t data_index;
  uint16_t accel_index   = 0;
  uint16_t frame_to_read = *accel_length;
  /*Check if this is the first iteration of data unpacking
   if yes, then consider dummy byte on SPI*/
  if (dev->fifo->accel_byte_start_idx == 0)
    dev->fifo->accel_byte_start_idx = dev->dummy_byte;

  for (data_index = dev->fifo->accel_byte_start_idx;
       data_index < dev->fifo->length;) {
    /*Header byte is stored in the variable frame_header*/
    frame_header = dev->fifo->data[data_index];
    /*Get the frame details from header*/
    frame_header = frame_header & BMA4_FIFO_TAG_INTR_MASK;
    /*Index is moved to next byte where the data is starting*/
    data_index++;

    switch (frame_header) {
    /* Accel frame */
    case FIFO_HEAD_A:
    case FIFO_HEAD_M_A:
      unpack_acc_frm(accel_data, &data_index, &accel_index, frame_header, dev);
      break;
    /* Aux. sensor frame */
    case FIFO_HEAD_M:
      move_next_frame(&data_index, BMA4_FIFO_M_LENGTH, dev);
      break;
    /* Sensor time frame */
    case FIFO_HEAD_SENSOR_TIME:
      unpack_sensortime_frame(&data_index, dev);
      break;
    /* Skip frame */
    case FIFO_HEAD_SKIP_FRAME:
      unpack_skipped_frame(&data_index, dev);
      break;
    /* Input config frame */
    case FIFO_HEAD_INPUT_CONFIG:
      move_next_frame(&data_index, 1, dev);
      break;
    /* Sample drop frame */
    case FIFO_HEAD_SAMPLE_DROP:
      unpack_dropped_frame(&data_index, dev);
      break;
    /* Over read FIFO data */
    case FIFO_HEAD_OVER_READ_MSB:
      /* Update the data index as complete*/
      data_index = dev->fifo->length;
      break;
    default:
      break;
    }
    if (frame_to_read == accel_index) {
      /*Number of frames to read completed*/
      break;
    }
  }

  /*Update number of accel data read*/
  *accel_length = accel_index;
  /*Update the accel frame index*/
  dev->fifo->accel_byte_start_idx = data_index;
}

/*!
 *  @brief This API is used to parse the accelerometer data from the
 *  FIFO data in both header mode and header-less mode.
 *  It update the idx value which is used to store the index of
 *  the current data byte which is parsed.
 */
static void unpack_acc_frm(struct bma4_accel *acc, uint16_t *idx,
                           uint16_t *acc_idx, uint8_t frm,
                           const struct bma4_dev *dev) {
  switch (frm) {
  case FIFO_HEAD_A:
  case BMA4_FIFO_A_ENABLE:
    /*Partial read, then skip the data*/
    if ((*idx + BMA4_FIFO_A_LENGTH) > dev->fifo->length) {
      /*Update the data index as complete*/
      *idx = dev->fifo->length;
      break;
    }
    /*Unpack the data array into the structure instance "acc" */
    unpack_accel_data(&acc[*acc_idx], *idx, dev);
    /*Move the data index*/
    *idx = *idx + BMA4_FIFO_A_LENGTH;
    (*acc_idx)++;
    break;
  case FIFO_HEAD_M_A:
  case BMA4_FIFO_M_A_ENABLE:
    /*Partial read, then skip the data*/
    if ((*idx + BMA4_FIFO_MA_LENGTH) > dev->fifo->length) {
      /*Update the data index as complete*/
      *idx = dev->fifo->length;
      break;
    }
    /*Unpack the data array into structure instance "acc"*/
    unpack_accel_data(&acc[*acc_idx], *idx + BMA4_MA_FIFO_A_X_LSB, dev);
    /*Move the data index*/
    *idx = *idx + BMA4_FIFO_MA_LENGTH;
    (*acc_idx)++;
    break;
  /* Aux. sensor frame */
  case FIFO_HEAD_M:
  case BMA4_FIFO_M_ENABLE:
    (*idx) = (*idx) + BMA4_FIFO_M_LENGTH;
    break;
  default:
    break;
  }
}

/*!
 *  @brief This API is used to parse the accelerometer data from the
 *  FIFO data and store it in the instance of the structure bma4_accel.
 */
static void unpack_accel_data(struct bma4_accel *accel_data,
                              uint16_t data_start_index,
                              const struct bma4_dev *dev) {
  uint16_t data_lsb;
  uint16_t data_msb;

  /* Accel raw x data */
  data_lsb      = dev->fifo->data[data_start_index++];
  data_msb      = dev->fifo->data[data_start_index++];
  accel_data->x = (int16_t)((data_msb << 8) | data_lsb);

  /* Accel raw y data */
  data_lsb      = dev->fifo->data[data_start_index++];
  data_msb      = dev->fifo->data[data_start_index++];
  accel_data->y = (int16_t)((data_msb << 8) | data_lsb);

  /* Accel raw z data */
  data_lsb      = dev->fifo->data[data_start_index++];
  data_msb      = dev->fifo->data[data_start_index++];
  accel_data->z = (int16_t)((data_msb << 8) | data_lsb);

  if (dev->resolution == BMA4_12_BIT_RESOLUTION) {
    accel_data->x = (accel_data->x / 0x10);
    accel_data->y = (accel_data->y / 0x10);
    accel_data->z = (accel_data->z / 0x10);
  } else if (dev->resolution == BMA4_14_BIT_RESOLUTION) {
    accel_data->x = (accel_data->x / 0x04);
    accel_data->y = (accel_data->y / 0x04);
    accel_data->z = (accel_data->z / 0x04);
  }
}

/*!
 *  @brief This API computes the number of bytes of Mag FIFO data which is
 *  to be parsed in header-less mode
 *
 */
static void get_mag_len_to_parse(uint16_t *start_idx, uint16_t *len,
                                 const uint16_t *mag_count,
                                 const struct bma4_dev *dev) {
  uint8_t dummy_byte_spi = 0;

  /*Check if this is the first iteration of data unpacking
   if yes, then consider dummy byte on SPI*/
  if (dev->fifo->mag_byte_start_idx == 0)
    dummy_byte_spi = dev->dummy_byte;

  /*Data start index*/
  *start_idx = dev->fifo->mag_byte_start_idx + dummy_byte_spi;

  if (dev->fifo->fifo_data_enable == BMA4_FIFO_M_ENABLE) {
    /*Len has the number of bytes to loop for */
    *len = (uint16_t)(((*mag_count) * BMA4_FIFO_M_LENGTH) + dummy_byte_spi);
  } else if (dev->fifo->fifo_data_enable == BMA4_FIFO_M_A_ENABLE) {
    /*Len has the number of bytes to loop for */
    *len = (uint16_t)(((*mag_count) * BMA4_FIFO_MA_LENGTH) + dummy_byte_spi);
  } else {
    /*Only accel sensor or no sensor is enabled in FIFO,
    so there will be no mag data.
    Update the data index as complete*/
    *start_idx = dev->fifo->length;
  }

  /*Handling the case where more data is requested than available*/
  if ((*len) > dev->fifo->length) {
    /*Len is equal to the FIFO length*/
    *len = dev->fifo->length;
  }
}

/*!
 *  @brief This API is used to parse the magnetometer data from the
 *  FIFO data in header mode.
 *
 */
static uint16_t extract_mag_header_mode(struct bma4_mag *data, uint16_t *len,
                                        const struct bma4_dev *dev) {
  uint16_t rslt        = 0;
  uint8_t frame_header = 0;
  uint16_t data_index;
  uint16_t mag_index     = 0;
  uint16_t frame_to_read = *len;

  /*Check if this is the first iteration of data unpacking
   if yes, then consider dummy byte on SPI*/
  if (dev->fifo->mag_byte_start_idx == 0)
    dev->fifo->mag_byte_start_idx = dev->dummy_byte;

  for (data_index = dev->fifo->mag_byte_start_idx;
       data_index < dev->fifo->length;) {
    /*Header byte is stored in the variable frame_header*/
    frame_header = dev->fifo->data[data_index];
    /*Get the frame details from header*/
    frame_header = frame_header & BMA4_FIFO_TAG_INTR_MASK;
    /*Index is moved to next byte where the data is starting*/
    data_index++;

    switch (frame_header) {
    /* Aux. sensor frame */
    case FIFO_HEAD_M:
    case FIFO_HEAD_M_A:
      rslt |= unpack_mag_frm(data, &data_index, &mag_index, frame_header, dev);
      break;
    /* Aux. sensor frame */
    case FIFO_HEAD_A:
      move_next_frame(&data_index, BMA4_FIFO_A_LENGTH, dev);
      break;
    /* Sensor time frame */
    case FIFO_HEAD_SENSOR_TIME:
      unpack_sensortime_frame(&data_index, dev);
      break;
    /* Skip frame */
    case FIFO_HEAD_SKIP_FRAME:
      unpack_skipped_frame(&data_index, dev);
      break;
    /* Input config frame */
    case FIFO_HEAD_INPUT_CONFIG:
      move_next_frame(&data_index, 1, dev);
      break;
    /* Sample drop frame */
    case FIFO_HEAD_SAMPLE_DROP:
      unpack_dropped_frame(&data_index, dev);
      break;
    case FIFO_HEAD_OVER_READ_MSB:
      /*Update the data index as complete*/
      data_index = dev->fifo->length;
      break;
    default:
      break;
    }
    if (frame_to_read == mag_index) {
      /*Number of frames to read completed*/
      break;
    }
  }
  /*update number of Aux. sensor data read*/
  *len = mag_index;
  /*update the Aux. sensor frame index*/
  dev->fifo->mag_byte_start_idx = data_index;
  return rslt;
}

/*!
 *  @brief This API is used to parse the magnetometer data from the
 *  FIFO data in both header mode and header-less mode and update the
 *  data_index value which is used to store the index of the current
 *  data byte which is parsed.
 *
 */
static uint16_t unpack_mag_frm(struct bma4_mag *data, uint16_t *idx,
                               uint16_t *mag_idx, uint8_t frm,
                               const struct bma4_dev *dev) {
  uint16_t rslt = 0;

  switch (frm) {
  case FIFO_HEAD_M:
  case BMA4_FIFO_M_ENABLE:
    /*partial read, then skip the data*/
    if ((*idx + BMA4_FIFO_M_LENGTH) > dev->fifo->length) {
      /*update the data index as complete*/
      *idx = dev->fifo->length;
      break;
    }

    /*unpack the data array into Aux. sensor data structure*/
    rslt |= unpack_mag_data(&data[*mag_idx], *idx, dev);
    /*move the data index*/
    *idx = *idx + BMA4_FIFO_M_LENGTH;
    (*mag_idx)++;
    break;
  case FIFO_HEAD_M_A:
  case BMA4_FIFO_M_A_ENABLE:
    /*partial read, then skip the data*/
    if ((*idx + BMA4_FIFO_MA_LENGTH) > dev->fifo->length) {
      /*update the data index as complete*/
      *idx = dev->fifo->length;
      break;
    }

    /*unpack the data array into Aux. sensor data structure*/
    rslt |= unpack_mag_data(&data[*mag_idx], *idx, dev);
    /*move the data index to next frame*/
    *idx = *idx + BMA4_FIFO_MA_LENGTH;
    (*mag_idx)++;
    break;
  /* aux. sensor frame */
  case FIFO_HEAD_A:
  case BMA4_FIFO_A_ENABLE:
    (*idx) = (*idx) + BMA4_FIFO_A_LENGTH;
    break;
  default:
    break;
  }

  return rslt;
}

/*!
 *  @brief This API is used to parse the auxiliary magnetometer data from
 *  the FIFO data and store it in the instance of the structure mag_data.
 *
 */
static uint16_t unpack_mag_data(struct bma4_mag *mag_data, uint16_t start_idx,
                                const struct bma4_dev *dev) {
  uint16_t rslt = 0;
  struct bma4_mag_fifo_data mag_fifo_data;

  /* Aux. mag sensor raw x data */
  mag_fifo_data.mag_x_lsb = dev->fifo->data[start_idx++];
  mag_fifo_data.mag_x_msb = dev->fifo->data[start_idx++];

  /* Aux. mag sensor raw y data */
  mag_fifo_data.mag_y_lsb = dev->fifo->data[start_idx++];
  mag_fifo_data.mag_y_msb = dev->fifo->data[start_idx++];

  /* Aux. mag sensor raw z data */
  mag_fifo_data.mag_z_lsb = dev->fifo->data[start_idx++];
  mag_fifo_data.mag_z_msb = dev->fifo->data[start_idx++];

  /* Aux. mag sensor raw r data */
  mag_fifo_data.mag_r_y2_lsb = dev->fifo->data[start_idx++];
  mag_fifo_data.mag_r_y2_msb = dev->fifo->data[start_idx++];

  /*Compensated FIFO data output*/
  rslt |= bma4_second_if_mag_compensate_xyz(mag_fifo_data, dev->aux_sensor,
                                            mag_data);

  return rslt;
}

/*!
 *  @brief This API is used to parse and store the sensor time from the
 *  FIFO data in the structure instance dev.
 *
 */
static void unpack_sensortime_frame(uint16_t *data_index,
                                    const struct bma4_dev *dev) {
  uint32_t sensor_time_byte3 = 0;
  uint16_t sensor_time_byte2 = 0;
  uint8_t sensor_time_byte1  = 0;

  /*Partial read, then move the data index to last data*/
  if ((*data_index + BMA4_SENSOR_TIME_LENGTH) > dev->fifo->length) {
    /*Update the data index as complete*/
    *data_index = dev->fifo->length;
  } else {
    sensor_time_byte3 =
        dev->fifo->data[(*data_index) + BMA4_SENSOR_TIME_MSB_BYTE] << 16;
    sensor_time_byte2 =
        dev->fifo->data[(*data_index) + BMA4_SENSOR_TIME_XLSB_BYTE] << 8;
    sensor_time_byte1 = dev->fifo->data[(*data_index)];
    /* Sensor time */
    dev->fifo->sensor_time =
        (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1);
    *data_index = (*data_index) + BMA4_SENSOR_TIME_LENGTH;
  }
}

/*!
 *  @brief This API is used to parse and store the skipped_frame_count from
 *  the FIFO data in the structure instance dev.
 */
static void unpack_skipped_frame(uint16_t *data_index,
                                 const struct bma4_dev *dev) {
  /*Partial read, then move the data index to last data*/
  if (*data_index >= dev->fifo->length) {
    /*Update the data index as complete*/
    *data_index = dev->fifo->length;
  } else {
    dev->fifo->skipped_frame_count = dev->fifo->data[*data_index];
    /*Move the data index*/
    *data_index = (*data_index) + 1;
  }
}

/*!
 *  @brief This API is used to parse and store the dropped_frame_count from
 *  the FIFO data in the structure instance dev.
 */
static void unpack_dropped_frame(uint16_t *data_index,
                                 const struct bma4_dev *dev) {
  uint8_t dropped_frame = 0;
  /*Partial read, then move the data index to last data*/
  if (*data_index >= dev->fifo->length) {
    /*Update the data index as complete*/
    *data_index = dev->fifo->length;
  } else {
    /*Extract accel and mag dropped frame count*/
    dropped_frame = dev->fifo->data[*data_index] & ACCEL_AUX_FIFO_DROP;
    /*Move the data index and update the dropped frame count*/
    switch (dropped_frame) {
    case ACCEL_FIFO_DROP:
      *data_index = (*data_index) + BMA4_FIFO_A_LENGTH;
      dev->fifo->accel_dropped_frame_count =
          dev->fifo->accel_dropped_frame_count + 1;
      break;
    case AUX_FIFO_DROP:
      *data_index = (*data_index) + BMA4_FIFO_M_LENGTH;
      dev->fifo->mag_dropped_frame_count =
          dev->fifo->mag_dropped_frame_count + 1;
      break;
    case ACCEL_AUX_FIFO_DROP:
      *data_index = (*data_index) + BMA4_FIFO_MA_LENGTH;
      dev->fifo->accel_dropped_frame_count =
          dev->fifo->accel_dropped_frame_count + 1;
      dev->fifo->mag_dropped_frame_count =
          dev->fifo->mag_dropped_frame_count + 1;
      break;
    default:
      break;
    }
  }
}

/*!
 *  @brief This API is used to move the data index ahead of the
 *  current_frame_length parameter when unnecessary FIFO data appears while
 *  extracting the user specified data.
 */
static void move_next_frame(uint16_t *data_index, uint8_t current_frame_length,
                            const struct bma4_dev *dev) {
  /*Partial read, then move the data index to last data*/
  if ((*data_index + current_frame_length) > dev->fifo->length) {
    /*Update the data index as complete*/
    *data_index = dev->fifo->length;
  } else {
    /*Move the data index to next frame*/
    *data_index = *data_index + current_frame_length;
  }
}

/*!
 *  @brief This function validates the Accel Self test data and decides the
 *  result of Self test operation.
 */
static uint16_t
validate_selftest(const struct selftest_delta_limit *accel_data_diff,
                  const struct bma4_dev *dev) {
  uint16_t rslt = 0;

  /* Set self test amplitude based on variant */
  switch (dev->variant) {
  case BMA42X_VARIANT:
    /* Validating accel data by comparing with minimum value of the axes in mg
     */
    /* For BMA42x - > x axis limit 400mg, y axis limit 800mg and z axis limit
     * 400mg */
    if ((accel_data_diff->x > BMA42X_ST_ACC_X_AXIS_SIGNAL_DIFF) &&
        (accel_data_diff->y > BMA42X_ST_ACC_Y_AXIS_SIGNAL_DIFF) &&
        (accel_data_diff->z > BMA42X_ST_ACC_Z_AXIS_SIGNAL_DIFF)) {
      rslt = BMA4_OK;
    } else {
      rslt = BMA4_E_SELF_TEST_FAIL;
    }
    break;

  case BMA45X_VARIANT:
    /* Validating accel data by comparing with minimum value of the axes in mg
     */
    /* For BMA45x - > x axis limit 1800mg, y axis limit 1800mg and z axis limit
     * 1800mg */
    if ((accel_data_diff->x > BMA45X_ST_ACC_X_AXIS_SIGNAL_DIFF) &&
        (accel_data_diff->y > BMA45X_ST_ACC_Y_AXIS_SIGNAL_DIFF) &&
        (accel_data_diff->z > BMA45X_ST_ACC_Z_AXIS_SIGNAL_DIFF)) {
      rslt = BMA4_OK;
    } else {
      rslt = BMA4_E_SELF_TEST_FAIL;
    }
    break;

  default:
    rslt = BMA4_E_INVALID_SENSOR;
    break;
  }

  return rslt;
}

/*!
 *  @brief This function configure the Accel for FOC.
 */
static uint16_t foc_config(struct bma4_accel_config *acc_conf, uint8_t *acc_en,
                           uint8_t *pwr_mode, struct bma4_dev *dev) {
  uint16_t rslt     = 0;
  uint8_t accel_cnf = BMA4_ACCEL_CONFIG_FOC;

  /* for saving Accel configuration,
   Accel enable status, advance power save*/
  rslt |= bma4_get_accel_config(acc_conf, dev);
  rslt |= bma4_get_accel_enable(acc_en, dev);
  rslt |= bma4_get_advance_power_save(pwr_mode, dev);

  /* Disabling offset compensation that is in place*/
  rslt |= bma4_set_offset_comp(BMA4_DISABLE, dev);

  if (rslt == BMA4_OK) {
    /* Set Accel config to 50Hz, continuous filter mode,
    no under sampling */
    rslt |= bma4_write_regs(BMA4_ACCEL_CONFIG_ADDR, &accel_cnf, 1, dev);

    if (rslt == BMA4_OK) {
      /* Switch Accel to normal mode and
      advance power save to zero*/
      rslt |= bma4_set_accel_enable(BMA4_ENABLE, dev);
      rslt |= bma4_set_advance_power_save(BMA4_DISABLE, dev);
    }
  }

  return rslt;
}

/*!
 * @brief This API is used to calculate the power of 2
 */
static int32_t power(int16_t base, uint8_t resolution) {
  uint8_t i = 1;
  /* Initialize variable to store the power of 2 value */
  int32_t value = 1;

  for (; i <= resolution; i++)
    value = (int32_t)(value * base);

  return value;
}

/*!
 * @brief This API performs the roundoff on given value
 */
static int8_t roundoff(int32_t value) {
  /* Variable to return the round off value */
  int8_t ret = 0;

  /* Since the value passed is scaled in multiples of 100,
  the return value is divided by 100 to get the round off value */
  if (value < 0)
    ret = (int8_t)(((value)-50) / 100);
  else
    ret = (int8_t)(((value) + 50) / 100);

  return ret;
}

/*!
 * @brief This API finds the bit position of 3.9mg according to given range
 * and resolution.
 */
static int8_t get_bit_pos_3_9mg(uint8_t range, uint8_t res) {
  /* Variable to store the bit position of 3.9mg */
  int8_t bit_pos_3_9mg = 0;
  /* Variable to store the value to be rounded off */
  int32_t value = 0;
  /* Variable to store the LSB per bit in micros */
  int32_t ug_per_bit;
  /* Variable to store the rounded off value */
  int8_t round_off_int;
  /* Variable to store the bit count */
  uint8_t bit_count = 0;
  /* Variable to store the signed range value */
  int32_t range_value;

  /* Scaling range with a multiplier to get integer value of ug_per_bit */
  range_value = (int32_t)(2 * range * BMA4XY_MULTIPLIER);

  /* Get the G-per bit resolution*/
  ug_per_bit = (int32_t)(range_value / power(2, res));

  /* Compare for -ve & +ve bit position w.r.t 3900micro-g or as reference
   * Note: Value scaled in 100s to get accurate integer value */
  if (ug_per_bit > 3900)
    value = (int32_t)(ug_per_bit * 100 / 3900);
  else
    value = (int32_t)(3900 * 100 / ug_per_bit);

  /* Round off the value */
  round_off_int = (int8_t)(roundoff(value));

  /* Find the bit position of 3.9mg*/
  while (round_off_int != 1) {
    round_off_int = (round_off_int / 0x02);
    bit_count++;
  }

  /* Check for +ve and -ve bit position of 3.9 mg */
  if (ug_per_bit > 3900)
    bit_pos_3_9mg = (int8_t)(bit_count * (-1));
  else
    bit_pos_3_9mg = (int8_t)bit_count;

  return bit_pos_3_9mg;
}
/*!
 * @brief This internal API brings up the secondary interface to access
 *          auxiliary sensor *
 */
static uint16_t bma4_set_aux_interface_config(struct bma4_dev *dev) {
  /* Variable to return error codes */
  uint16_t rslt = BMA4_OK;

  /* Check for null pointer error */
  rslt |= bma4_null_pointer_check(dev);

  if (rslt == BMA4_OK) {
    /* Enable the auxiliary sensor */
    rslt |= bma4_set_mag_enable(0x01, dev);
    dev->delay(BMA4_AUX_COM_DELAY);

    /* Disable advance power save */
    rslt |= bma4_set_advance_power_save(0x00, dev);
    dev->delay(BMA4_AUX_COM_DELAY);

    /* Set the I2C device address of auxiliary device */
    rslt |= bma4_set_i2c_device_addr(dev);
    dev->delay(BMA4_AUX_COM_DELAY);

    /* Set auxiliary interface to manual mode */
    rslt |= bma4_set_mag_manual_enable(dev->aux_config.manual_enable, dev);
    dev->delay(BMA4_AUX_COM_DELAY);

    /* Set the number of bytes for burst read */
    rslt |= bma4_set_mag_burst(dev->aux_config.burst_read_length, dev);
    dev->delay(BMA4_AUX_COM_DELAY);

    /* Switch on the the auxiliary interface mode */
    rslt |= bma4_set_if_mode(dev->aux_config.if_mode, dev);
    dev->delay(BMA4_AUX_COM_DELAY);
  }

  return rslt;
}

/*!
 * @brief This internal API reads the data from the auxiliary sensor
 *        depending on burst length configured
 */
static uint16_t bma4_extract_aux_data(uint8_t aux_reg_addr, uint8_t *aux_data,
                                      uint16_t len, struct bma4_dev *dev) {
  /* Variable to return error codes */
  uint16_t rslt = BMA4_OK;
  /* Pointer variable to read data from the register */
  uint8_t data[15] = {0};
  /* Variable to define length counts */
  uint8_t len_count = 0;
  /* Variable to define burst read length */
  uint8_t burst_len = 0;
  /* Variable to define read length */
  uint8_t read_length = 0;
  /* Variable to define the number of burst reads */
  uint8_t burst_count;
  /* Variable to define address of the data register*/
  uint8_t aux_read_addr = BMA4_DATA_0_ADDR;

  /* Extract burst read length in a variable */
  rslt |= bma4_map_read_len(&burst_len, dev);

  for (burst_count = 0; burst_count < len; burst_count += burst_len) {
    /* Set the address whose data is to be read */
    rslt |= bma4_set_mag_read_addr(aux_reg_addr, dev);
    dev->delay(BMA4_AUX_COM_DELAY);

    if (rslt == BMA4_OK) {
      /* If user defined length is valid */
      if (len > 0) {
        /* Read the data from the data register */
        rslt |= bma4_read_regs(aux_read_addr, data, (uint8_t)burst_len, dev);
        dev->delay(BMA4_AUX_COM_DELAY);

        if (rslt == BMA4_OK) {
          /* If defined user length or remaining length after a burst
          read  is less than burst length */
          if ((len - burst_count) < burst_len) {
            /* Read length is equal to burst_length or
               remaining length*/
            read_length = (uint8_t)(len - burst_count);
          } else {
            /* Read length is equal to burst_length */
            read_length = burst_len;
          }

          /* Copy the read data in terms of given read length */
          for (len_count = 0; len_count < read_length; len_count++)
            aux_data[burst_count + len_count] = data[len_count];

          /* Increment the register address by burst read length */
          aux_reg_addr += burst_len;
        } else {
          rslt = BMA4_E_RD_WR_LENGTH_INVALID;
        }
      } else {
        rslt = BMA4_E_FAIL;
      }
    } else {
      rslt = BMA4_E_FAIL;
    }
  }

  return rslt;
}

/*!
 * @brief This internal API maps the actual burst read length with user
            length set.
 */
static uint16_t bma4_map_read_len(uint8_t *len, const struct bma4_dev *dev) {
  /* Variable to return error codes */
  uint16_t rslt = BMA4_OK;

  switch (dev->aux_config.burst_read_length) {

  case BMA4_AUX_READ_LEN_0:
    *len = 1;
    break;
  case BMA4_AUX_READ_LEN_1:
    *len = 2;
    break;
  case BMA4_AUX_READ_LEN_2:
    *len = 6;
    break;
  case BMA4_AUX_READ_LEN_3:
    *len = 8;
    break;
  default:
    rslt = BMA4_E_OUT_OF_RANGE;
    break;
  }

  return rslt;
}

/*!
 * @brief This internal API checks null pointer error
 */
static uint16_t bma4_null_pointer_check(const struct bma4_dev *dev) {
  uint16_t rslt = BMA4_OK;

  if ((dev == NULL) || (dev->bus_read == NULL) || (dev->bus_write == NULL))
    rslt |= BMA4_E_NULL_PTR;
  else
    rslt = BMA4_OK;

  return rslt;
}
