/* ###################################################################
**     This component module is generated by Processor Expert. Do not modify it.
**     Filename    : McuFXOS8700.h
**     CDE edition : Standard
**     Project     : FRDM-K64F_Generator
**     Processor   : MK64FN1M0VLL12
**     Component   : FXOS8700CQ
**     Version     : Component 01.036, Driver 01.00, CPU db: 3.00.000
**     Compiler    : GNU C Compiler
**     Date/Time   : 2021-12-26, 16:08, # CodeGen: 770
**     Abstract    :
**         Implements a Driver for the MMA8451 accelerometer from Freescale.
**     Settings    :
**          Component Name                                 : McuFXOS8700
**          Slave Address                                  : 1E
**          I2C Bus                                        : McuGenericI2C
**          Constant Offsets                               : Enabled
**            X offset                                     : 0
**            Y offset                                     : 0
**            Z offset                                     : 0
**          Shell                                          : Enabled
**            Shell                                        : McuShell
**            Utility                                      : McuUtility
**     Contents    :
**         Enable              - uint8_t McuFXOS8700_Enable(void);
**         Disable             - uint8_t McuFXOS8700_Disable(void);
**         MagEnable           - uint8_t McuFXOS8700_MagEnable(void);
**         MagDisable          - uint8_t McuFXOS8700_MagDisable(void);
**         isEnabled           - uint8_t McuFXOS8700_isEnabled(bool *isEnabled);
**         SwReset             - uint8_t McuFXOS8700_SwReset(void);
**         ReadReg8            - uint8_t McuFXOS8700_ReadReg8(uint8_t addr, uint8_t *val);
**         WriteReg8           - uint8_t McuFXOS8700_WriteReg8(uint8_t addr, uint8_t val);
**         GetX                - int16_t McuFXOS8700_GetX(void);
**         GetY                - int16_t McuFXOS8700_GetY(void);
**         GetZ                - int16_t McuFXOS8700_GetZ(void);
**         GetRaw8XYZ          - uint8_t McuFXOS8700_GetRaw8XYZ(void* *xyz);
**         CalibrateX1g        - void McuFXOS8700_CalibrateX1g(void);
**         CalibrateY1g        - void McuFXOS8700_CalibrateY1g(void);
**         CalibrateZ1g        - void McuFXOS8700_CalibrateZ1g(void);
**         GetXmg              - int16_t McuFXOS8700_GetXmg(void);
**         GetYmg              - int16_t McuFXOS8700_GetYmg(void);
**         GetZmg              - int16_t McuFXOS8700_GetZmg(void);
**         MeasureGetRawX      - uint16_t McuFXOS8700_MeasureGetRawX(void);
**         MeasureGetRawY      - uint16_t McuFXOS8700_MeasureGetRawY(void);
**         MeasureGetRawZ      - uint16_t McuFXOS8700_MeasureGetRawZ(void);
**         GetXOffset          - int16_t McuFXOS8700_GetXOffset(void);
**         GetYOffset          - int16_t McuFXOS8700_GetYOffset(void);
**         GetZOffset          - int16_t McuFXOS8700_GetZOffset(void);
**         GetX1gValue         - int16_t McuFXOS8700_GetX1gValue(void);
**         GetY1gValue         - int16_t McuFXOS8700_GetY1gValue(void);
**         GetZ1gValue         - int16_t McuFXOS8700_GetZ1gValue(void);
**         SetFastMode         - uint8_t McuFXOS8700_SetFastMode(bool on);
**         WhoAmI              - uint8_t McuFXOS8700_WhoAmI(uint8_t *value);
**         GetTemperature      - uint8_t McuFXOS8700_GetTemperature(int8_t *temperature);
**         GetMagX             - uint8_t McuFXOS8700_GetMagX(int16_t *value);
**         GetMagY             - uint8_t McuFXOS8700_GetMagY(int16_t *value);
**         GetMagZ             - uint8_t McuFXOS8700_GetMagZ(int16_t *value);
**         ParseCommand        - uint8_t McuFXOS8700_ParseCommand(const unsigned char *cmd, bool *handled,...
**         MagneticSensorReset - uint8_t McuFXOS8700_MagneticSensorReset(void);
**         Init                - uint8_t McuFXOS8700_Init(void);
**         Deinit              - uint8_t McuFXOS8700_Deinit(void);
**
** * Copyright (c) 2013-2021, Erich Styger
**  * Web:         https://mcuoneclipse.com
**  * SourceForge: https://sourceforge.net/projects/mcuoneclipse
**  * Git:         https://github.com/ErichStyger/McuOnEclipse_PEx
**  * All rights reserved.
**  *
**  * Redistribution and use in source and binary forms, with or without modification,
**  * are permitted provided that the following conditions are met:
**  *
**  * - Redistributions of source code must retain the above copyright notice, this list
**  *   of conditions and the following disclaimer.
**  *
**  * - Redistributions in binary form must reproduce the above copyright notice, this
**  *   list of conditions and the following disclaimer in the documentation and/or
**  *   other materials provided with the distribution.
**  *
**  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
**  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
**  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
**  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
**  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
**  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
**  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
**  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
**  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
**  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** ###################################################################*/
/*!
** @file McuFXOS8700.h
** @version 01.00
** @brief
**         Implements a Driver for the MMA8451 accelerometer from Freescale.
*/         
/*!
**  @addtogroup McuFXOS8700_module McuFXOS8700 module documentation
**  @{
*/         

/* MODULE McuFXOS8700. */

#include "McuFXOS8700.h"

#define McuFXOS8700_CPU_IS_LITTLE_ENDIAN 1 /* Cpu is little endian */

typedef struct {
  int16_t NxOff; /* offset for X axis */
  int16_t NyOff; /* offset for Y axis */
  int16_t NzOff; /* offset for Z axis */
} tAccelCal;

/* default calibration values from component properties */
static const tAccelCal InitialCalibration = { /* Initial default calibration values */
  0, /* X offset */
  0, /* Y offset */
  0, /* Z offset */
};
static tAccelCal sCalValues; /* calibration values in RAM */

#define CalNxOff   sCalValues.NxOff
#define CalNyOff   sCalValues.NyOff
#define CalNzOff   sCalValues.NzOff

static uint8_t PrintStatus(const McuShell_StdIOType *io) {
  unsigned char buf[42];
  int8_t temperature;
  uint16_t val;
  uint8_t val8;
  bool isEnabled;
  int16_t val16s;

  McuShell_SendStatusStr((unsigned char*)"McuFXOS8700", (unsigned char*)"FXOS8700 sensor status\r\n", io->stdOut);

  McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x");
  McuUtility_strcatNum8Hex(buf, sizeof(buf), (uint8_t)McuFXOS8700_I2C_ADDR);
  McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
  McuShell_SendStatusStr((unsigned char*)"  I2C addr", buf, io->stdOut);

  if (McuFXOS8700_isEnabled(&isEnabled)!=ERR_OK) {
    McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAIL!\r\n");
  } else {
    if (isEnabled) {
      McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"yes\r\n");
    } else {
      McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"no\r\n");
    }
  }
  McuShell_SendStatusStr((unsigned char*)"  enabled", buf, io->stdOut);

  McuShell_SendStatusStr((unsigned char*)"  raw", (unsigned char*)"0x", io->stdOut);
  val = McuFXOS8700_MeasureGetRawX();
  buf[0] = '\0';
  McuUtility_strcatNum16Hex(buf, sizeof(buf), (uint16_t)val);
  McuShell_SendStr(buf, io->stdOut);
  McuShell_SendStr((unsigned char*)" (", io->stdOut);
  McuShell_SendNum16s((int16_t)val, io->stdOut);
  McuShell_SendStr((unsigned char*)"), 0x", io->stdOut);

  val = McuFXOS8700_MeasureGetRawY();
  buf[0] = '\0';
  McuUtility_strcatNum16Hex(buf, sizeof(buf), (uint16_t)val);
  McuShell_SendStr(buf, io->stdOut);
  McuShell_SendStr((unsigned char*)" (", io->stdOut);
  McuShell_SendNum16s((int16_t)val, io->stdOut);
  McuShell_SendStr((unsigned char*)"), 0x", io->stdOut);

  val = McuFXOS8700_MeasureGetRawZ();
  buf[0] = '\0';
  McuUtility_strcatNum16Hex(buf, sizeof(buf), (uint16_t)val);
  McuShell_SendStr(buf, io->stdOut);
  McuShell_SendStr((unsigned char*)" (", io->stdOut);
  McuShell_SendNum16s((int16_t)val, io->stdOut);
  McuShell_SendStr((unsigned char*)")\r\n", io->stdOut);

  McuShell_SendStatusStr((unsigned char*)"  calibOffset", (unsigned char*)"", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetXOffset(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetYOffset(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetZOffset(), io->stdOut);
  McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);

  McuShell_SendStatusStr((unsigned char*)"  calib 1g", (unsigned char*)"", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetX1gValue(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetY1gValue(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetZ1gValue(), io->stdOut);
  McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);

  McuShell_SendStatusStr((unsigned char*)"  GetX,Y,Z", (unsigned char*)"", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetX(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetY(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetZ(), io->stdOut);
  McuShell_SendStr((unsigned char*)" (raw+offset)\r\n", io->stdOut);

  McuShell_SendStatusStr((unsigned char*)"  mg X,Y,Z", (unsigned char*)"", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetXmg(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetYmg(), io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  McuShell_SendNum16s(McuFXOS8700_GetZmg(), io->stdOut);
  McuShell_SendStr((unsigned char*)" (milli-g)\r\n", io->stdOut);

  if (McuFXOS8700_GetTemperature(&temperature)==ERR_OK) {
    McuUtility_Num8sToStr(buf, sizeof(buf), temperature);
    McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" degree C (offset ");
    McuUtility_strcatNum8s(buf, sizeof(buf), McuFXOS8700_DIE_TEMP_OFFSET);
    McuUtility_strcat(buf, sizeof(buf), (unsigned char*)" degree C)\r\n");
  } else {
    McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
  }
  McuShell_SendStatusStr((unsigned char*)"  Temperature", buf, io->stdOut);

  if (McuFXOS8700_WhoAmI(&val8)==ERR_OK) {
    McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"0x");
    McuUtility_strcatNum8Hex(buf, sizeof(buf), val8);
    McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
  } else {
    McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"FAILED\r\n");
  }
  McuShell_SendStatusStr((unsigned char*)"  Who am I", buf, io->stdOut);

  McuShell_SendStatusStr((unsigned char*)"  GetMagX,Y,Z", (unsigned char*)"", io->stdOut);
  val16s = 0;
  (void)McuFXOS8700_GetMagX(&val16s);
  McuShell_SendNum16s(val16s, io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  (void)McuFXOS8700_GetMagY(&val16s);
  McuShell_SendNum16s(val16s, io->stdOut);
  McuShell_SendStr((unsigned char*)" ", io->stdOut);
  (void)McuFXOS8700_GetMagZ(&val16s);
  McuShell_SendNum16s(val16s, io->stdOut);
  McuShell_SendStr((unsigned char*)"\r\n", io->stdOut);

  return ERR_OK;
}

static uint8_t PrintHelp(const McuShell_StdIOType *io) {
  McuShell_SendHelpStr((unsigned char*)"McuFXOS8700", (unsigned char*)"Group of McuFXOS8700 commands\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  calibrate x|y|z", (unsigned char*)"Performs accelerometer calibration\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  swreset", (unsigned char*)"Performs a device software reset\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  magreset", (unsigned char*)"Performs a magenetometer sensor reset\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  enable|disable", (unsigned char*)"Enables or disables the accelerometer sensor\r\n", io->stdOut);
  McuShell_SendHelpStr((unsigned char*)"  mag enable|disable", (unsigned char*)"Enables or disables the magnet sensor\r\n", io->stdOut);
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  GetRaw8XYZ (component FXOS8700CQ)
**
**     Description :
**         Returns in an array the x, y and z accelerometer as 8bit
**         values.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * xyz             - Pointer to an array of three unsigned 8bit
**                           values which are used to return the
**                           accelerometer values.
**     Returns     :
**         ---             - Error code, ERR_OK for no error.
** ===================================================================
*/
uint8_t McuFXOS8700_GetRaw8XYZ(uint8_t *xyz)
{
  static const uint8_t addr = McuFXOS8700_OUT_X_MSB;

  return McuGenericI2C_ReadAddress(McuFXOS8700_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &xyz[0], 3);
}

/*
** ===================================================================
**     Method      :  Deinit (component FXOS8700CQ)
**
**     Description :
**         Counterpart to Init() method.
**     Parameters  : None
**     Returns     :
**         ---             - Error code, ERR_OK if everything is ok.
** ===================================================================
*/
uint8_t McuFXOS8700_Deinit(void)
{
  return ERR_OK; /* nothing to do */
}

/*
** ===================================================================
**     Method      :  Init (component FXOS8700CQ)
**
**     Description :
**         Initializes the device driver
**     Parameters  : None
**     Returns     :
**         ---             - Error code, ERR_OK if everything is ok.
** ===================================================================
*/
uint8_t McuFXOS8700_Init(void)
{
  sCalValues.NxOff = InitialCalibration.NxOff;
  sCalValues.NyOff = InitialCalibration.NyOff;
  sCalValues.NzOff = InitialCalibration.NzOff;
  return McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, McuFXOS8700_ACTIVE_BIT_MASK); /* enable device */
}

/*
** ===================================================================
**     Method      :  CalibrateX1g (component FXOS8700CQ)
**
**     Description :
**         Performs a calibration of the sensor. It is assumed that the
**         Y and Z sensors have 0 g, and the X sensor has 1 g.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuFXOS8700_CalibrateX1g(void)
{
  /* assumption is that accelerometer is placed with 1g for X and 0g for Y and Z */
  int32_t X=0, Y=0, Z=0;
  uint8_t i;

  /* Get the raw data and remove 2 bits (16bit to 14bit) */
  for (i=0; i<8; i++) {
   X += ((int16_t)McuFXOS8700_MeasureGetRawX() >> 2);
   Y += ((int16_t)McuFXOS8700_MeasureGetRawY() >> 2);
   Z += ((int16_t)McuFXOS8700_MeasureGetRawZ() >> 2);
  }
  /* build average of 8 measured values */
  X >>= 3;
  Y >>= 3;
  Z >>= 3;
  /* store the calibration values */
  /* offset: both Y and Z shall have zero g */
  sCalValues.NzOff = (X - (1000 << 2));
  sCalValues.NyOff = (int16_t)Y;
  sCalValues.NzOff = (int16_t)Z;
}

/*
** ===================================================================
**     Method      :  CalibrateY1g (component FXOS8700CQ)
**
**     Description :
**         Performs a calibration of the sensor. It is assumed that the
**         X and Z sensors have 0 g, and the Y sensor has 1 g.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuFXOS8700_CalibrateY1g(void)
{
  /* assumption is that accelerometer is placed with 1g for Y and 0g for X and Z */
  int32_t X=0, Y=0, Z=0;
  uint8_t i;

  /* Get the raw data and remove 2 bits (16bit to 14bit) */
  for (i=0; i<8; i++) {
   X += ((int16_t)McuFXOS8700_MeasureGetRawX() >> 2);
   Y += ((int16_t)McuFXOS8700_MeasureGetRawY() >> 2);
   Z += ((int16_t)McuFXOS8700_MeasureGetRawZ() >> 2);
  }
  /* build average of 8 measured values */
  X >>= 3;
  Y >>= 3;
  Z >>= 3;
  /* store the calibration values */
  /* offset: both X and Z shall have zero g */
  sCalValues.NxOff = X;
  sCalValues.NzOff = (Y - (1000 << 2));
  sCalValues.NzOff = Z;
}

/*
** ===================================================================
**     Method      :  CalibrateZ1g (component FXOS8700CQ)
**
**     Description :
**         Performs a calibration of the sensor. It is assumed that the
**         X and Y sensors have 0 g, and the Z sensor has 1 g.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuFXOS8700_CalibrateZ1g(void)
{
  /* assumption is that accelerometer is placed with 1g for Z and 0g for X and Y */
  int32_t X=0, Y=0, Z=0;
  uint8_t i;

  /* Get the raw data and remove 2 bits (16bit to 14bit) */
  for (i=0; i<8; i++) {
   X += ((int16_t)McuFXOS8700_MeasureGetRawX() >> 2);
   Y += ((int16_t)McuFXOS8700_MeasureGetRawY() >> 2);
   Z += ((int16_t)McuFXOS8700_MeasureGetRawZ() >> 2);
  }
  /* build average of 8 measured values */
  X >>= 3;
  Y >>= 3;
  Z >>= 3;
  /* store the calibration values */
  /* offset: both X and Y shall have zero g (midpoint) */
  sCalValues.NxOff = X;
  sCalValues.NyOff = Y;
  sCalValues.NzOff = (Z - (1000 << 2));
}

/*
** ===================================================================
**     Method      :  GetXmg (component FXOS8700CQ)
**
**     Description :
**         Returns the X value in mg
**     Parameters  : None
**     Returns     :
**         ---             - The g value in 1/1000g units
** ===================================================================
*/
int16_t McuFXOS8700_GetXmg(void)
{
  return McuFXOS8700_GetX() / 4;
}

/*
** ===================================================================
**     Method      :  GetYmg (component FXOS8700CQ)
**
**     Description :
**         Returns the Y value in mg
**     Parameters  : None
**     Returns     :
**         ---             - The g value in 1/1000g units
** ===================================================================
*/
int16_t McuFXOS8700_GetYmg(void)
{
  return McuFXOS8700_GetY() / 4;
}

/*
** ===================================================================
**     Method      :  GetZmg (component FXOS8700CQ)
**
**     Description :
**         Returns the Z value in mg
**     Parameters  : None
**     Returns     :
**         ---             - The g value in 1/1000g units
** ===================================================================
*/
int16_t McuFXOS8700_GetZmg(void)
{
  return McuFXOS8700_GetZ() / 4;
}

/*
** ===================================================================
**     Method      :  MeasureGetRawX (component FXOS8700CQ)
**
**     Description :
**         Performs a measurement on X channel and returns the raw
**         value.
**     Parameters  : None
**     Returns     :
**         ---             - X sensor value
** ===================================================================
*/
uint16_t McuFXOS8700_MeasureGetRawX(void)
{
  union {
    uint8_t buf[2]; /* value from device is in big endian */
    uint16_t be;
  } val;
  static const uint8_t addr = McuFXOS8700_OUT_X_MSB;

  val.be = 0; /* init */
  if(McuGenericI2C_ReadAddress(McuFXOS8700_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &val.buf[0], sizeof(val.buf))!=ERR_OK) {
    return 0; /* failure */
  }
#if McuFXOS8700_CPU_IS_LITTLE_ENDIAN
  return (uint16_t)((val.buf[0]<<8)|val.buf[1]); /* transform into LE value */
#else
  return val.be; /* already in BE */
#endif
}

/*
** ===================================================================
**     Method      :  MeasureGetRawY (component FXOS8700CQ)
**
**     Description :
**         Performs a measurement on Y channel and returns the raw
**         value.
**     Parameters  : None
**     Returns     :
**         ---             - Y sensor value
** ===================================================================
*/
uint16_t McuFXOS8700_MeasureGetRawY(void)
{
  union {
    uint8_t buf[2]; /* value from device is in big endian */
    uint16_t be;
  } val;
  static const uint8_t addr = McuFXOS8700_OUT_Y_MSB;

  val.be = 0; /* init */
  if(McuGenericI2C_ReadAddress(McuFXOS8700_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &val.buf[0], sizeof(val.buf))!=ERR_OK) {
    return 0; /* failure */
  }
#if McuFXOS8700_CPU_IS_LITTLE_ENDIAN
  return (uint16_t)((val.buf[0]<<8)|val.buf[1]); /* transform into LE value */
#else
  return val.be; /* already in BE */
#endif
}

/*
** ===================================================================
**     Method      :  MeasureGetRawZ (component FXOS8700CQ)
**
**     Description :
**         Performs a measurement on Z channel and returns the raw
**         value.
**     Parameters  : None
**     Returns     :
**         ---             - Z sensor value
** ===================================================================
*/
uint16_t McuFXOS8700_MeasureGetRawZ(void)
{
  union {
    uint8_t buf[2]; /* value from device is in big endian */
    uint16_t be;
  } val;
  static const uint8_t addr = McuFXOS8700_OUT_Z_MSB;

  val.be = 0; /* init */
  if(McuGenericI2C_ReadAddress(McuFXOS8700_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &val.buf[0], sizeof(val.buf))!=ERR_OK) {
    return 0; /* failure */
  }
#if McuFXOS8700_CPU_IS_LITTLE_ENDIAN
  return (uint16_t)((val.buf[0]<<8)|val.buf[1]); /* transform into LE value */
#else
  return val.be; /* already in BE */
#endif
}

/*
** ===================================================================
**     Method      :  GetXOffset (component FXOS8700CQ)
**
**     Description :
**         Returns the offset applied to the X value.
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
int16_t McuFXOS8700_GetXOffset(void)
{
  return CalNxOff;
}

/*
** ===================================================================
**     Method      :  GetYOffset (component FXOS8700CQ)
**
**     Description :
**         Returns the offset applied to the Y value.
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
int16_t McuFXOS8700_GetYOffset(void)
{
  return CalNyOff;
}

/*
** ===================================================================
**     Method      :  GetZOffset (component FXOS8700CQ)
**
**     Description :
**         Returns the offset applied to the Z value.
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
int16_t McuFXOS8700_GetZOffset(void)
{
  return CalNzOff;
}

/*
** ===================================================================
**     Method      :  GetX1gValue (component FXOS8700CQ)
**
**     Description :
**         Returns the value for 1g for channel  X.
**     Parameters  : None
**     Returns     :
**         ---             - 1g value for X
** ===================================================================
*/
int16_t McuFXOS8700_GetX1gValue(void)
{
  return 4096;
}

/*
** ===================================================================
**     Method      :  GetY1gValue (component FXOS8700CQ)
**
**     Description :
**         Returns the value for 1g for channel  Y.
**     Parameters  : None
**     Returns     :
**         ---             - 1g value for Y
** ===================================================================
*/
int16_t McuFXOS8700_GetY1gValue(void)
{
  return 4096;
}

/*
** ===================================================================
**     Method      :  GetZ1gValue (component FXOS8700CQ)
**
**     Description :
**         Returns the value for 1g for channel  Z.
**     Parameters  : None
**     Returns     :
**         ---             - 1g value for Z
** ===================================================================
*/
int16_t McuFXOS8700_GetZ1gValue(void)
{
  return 4096;
}

/*
** ===================================================================
**     Method      :  GetX (component FXOS8700CQ)
**
**     Description :
**         Retrieves the value for the X axis. The value is adjusted
**         with the zero calibration value (0 for 0 g, negative for
**         negative acceleration and positive for positive acceleration).
**     Parameters  : None
**     Returns     :
**         ---             - Measured X value
** ===================================================================
*/
int16_t McuFXOS8700_GetX(void)
{
  int16_t value;

  value = (int16_t)McuFXOS8700_MeasureGetRawX() >> 2; /* remove 2 bits (16bit to 14bit) */
  value -= CalNxOff; /* adjust with calibration offset */
  return value;
}

/*
** ===================================================================
**     Method      :  GetY (component FXOS8700CQ)
**
**     Description :
**         Retrieves the value for the Y axis. The value is adjusted
**         with the zero calibration value (0 for 0 g, negative for
**         negative acceleration and positive for positive acceleration).
**     Parameters  : None
**     Returns     :
**         ---             - Measured Y value
** ===================================================================
*/
int16_t McuFXOS8700_GetY(void)
{
  int16_t value;

  value = (int16_t)McuFXOS8700_MeasureGetRawY() >> 2; /* remove 2 bits (16bit to 14bit) */
  value -= CalNyOff; /* adjust with calibration offset */
  return value;
}

/*
** ===================================================================
**     Method      :  GetZ (component FXOS8700CQ)
**
**     Description :
**         Retrieves the value for the Z axis. The value is adjusted
**         with the zero calibration value (0 for 0 g, negative for
**         negative acceleration and positive for positive acceleration).
**     Parameters  : None
**     Returns     :
**         ---             - Measured Z value
** ===================================================================
*/
int16_t McuFXOS8700_GetZ(void)
{
  int16_t value;

  value = (int16_t)McuFXOS8700_MeasureGetRawZ() >> 2; /* remove 2 bits (16bit to 14bit) */
  value -= CalNzOff; /* adjust with calibration offset */
  return value;
}

/*
** ===================================================================
**     Method      :  ParseCommand (component FXOS8700CQ)
**
**     Description :
**         Shell Command Line parser. This method is enabled/disabled
**         depending on if you have the Shell enabled/disabled in the
**         properties.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * cmd             - Pointer to command string
**       * handled         - Pointer to variable which tells if
**                           the command has been handled or not
**       * io              - Pointer to I/O structure
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io)
{
  if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "McuFXOS8700 help")==0) {
    *handled = TRUE;
    return PrintHelp(io);
  } else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "McuFXOS8700 status")==0)) {
    *handled = TRUE;
    return PrintStatus(io);
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 calibrate x")==0) {
    *handled = TRUE;
    McuFXOS8700_CalibrateX1g();
    return ERR_OK;
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 calibrate y")==0) {
    *handled = TRUE;
    McuFXOS8700_CalibrateY1g();
    return ERR_OK;
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 calibrate z")==0) {
    *handled = TRUE;
    McuFXOS8700_CalibrateZ1g();
    return ERR_OK;
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 enable")==0) {
    *handled = TRUE;
    return McuFXOS8700_Enable();
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 disable")==0) {
    *handled = TRUE;
    return McuFXOS8700_Disable();
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 mag enable")==0) {
    *handled = TRUE;
    return McuFXOS8700_MagEnable();
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 mag disable")==0) {
    *handled = TRUE;
    return McuFXOS8700_MagDisable();
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 swreset")==0) {
    *handled = TRUE;
    if (McuFXOS8700_SwReset()!=ERR_OK) {
      McuShell_SendStr((unsigned char*)"SW reset failed!\r\n", io->stdErr);
      return ERR_FAILED;
    } else {
      return ERR_OK;
    }
  } else if (McuUtility_strcmp((char*)cmd, (char*)"McuFXOS8700 magreset")==0) {
    *handled = TRUE;
    if (McuFXOS8700_MagneticSensorReset()!=ERR_OK) {
      McuShell_SendStr((unsigned char*)"Magnetometer sensor reset failed!\r\n", io->stdErr);
      return ERR_FAILED;
    } else {
      return ERR_OK;
    }
  }
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  SetFastMode (component FXOS8700CQ)
**
**     Description :
**         Turns the F_READ (Fast Read Mode) on or off
**     Parameters  :
**         NAME            - DESCRIPTION
**         on              - if to turn the F_READ mode on or off
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_SetFastMode(bool on)
{
  uint8_t val, res;

  res = McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, &val);
  if (res!=ERR_OK) {
    return res;
  }
  if (on) {
    val |= McuFXOS8700_F_READ_BIT_MASK; /* enable F_READ: Fast read mode, data format limited to single byte (auto increment counter will skip LSB) */
  } else {
    val &= ~McuFXOS8700_F_READ_BIT_MASK; /* disable F_READ: Fast read mode, data format limited to single byte (auto increment counter will skip LSB) */
  }
  return McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, val);
}

/*
** ===================================================================
**     Method      :  MagEnable (component FXOS8700CQ)
**
**     Description :
**         Enables the magnetometer
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_MagEnable(void)
{
  uint8_t val, res;

  // write 0001 1111 = 0x1F to magnetometer control register 1
  // [7]: m_acal=0: auto calibration disabled
  // [6]: m_rst=0: no one-shot magnetic reset
  // [5]: m_ost=0: no one-shot magnetic measurement
  // [4-2]: m_os=111=7: 8x oversampling (for 200Hz) to reduce magnetometer noise
  // [1-0]: m_hms=11=3: select hybrid mode with accel and magnetometer active
  val = 0x1F;
  res = McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_M_CTRL_REG_1, val);
  if (res!=ERR_OK) {
    return res;
  }

  // write 0010 0000 = 0x20 to magnetometer control register 2
  // [7]: reserved
  // [6]: reserved
  // [5]: hyb_autoinc_mode=1 to map the magnetometer registers to follow the
  // accelerometer registers
  // [4]: m_maxmin_dis=0 to retain default min/max latching even though not used
  // [3]: m_maxmin_dis_ths=0
  // [2]: m_maxmin_rst=0
  // [1-0]: m_rst_cnt=00 to enable magnetic reset each cycle
  val = 0x20;
  res = McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_M_CTRL_REG_2, val);
  if (res!=ERR_OK) {
    return res;
  }
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  MagDisable (component FXOS8700CQ)
**
**     Description :
**         Disables the magnetometer
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_MagDisable(void)
{
  return ERR_OK; /* not doing anything */
}

/*
** ===================================================================
**     Method      :  Enable (component FXOS8700CQ)
**
**     Description :
**         Enables the device with setting the ACTIVE bit in the CTRL
**         register 1
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_Enable(void)
{
  uint8_t val, res;

  res = McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, &val);
  if (res!=ERR_OK) {
    return res;
  }
  if (val&McuFXOS8700_ACTIVE_BIT_MASK) {
    return ERR_OK; /* already enabled */
  }
  McuWait_Waitms(1); /* for unknown reasons, need to wait for 1 ms after reading the register */
  val |= McuFXOS8700_ACTIVE_BIT_MASK; /* enable device */
  return McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, val);
}

/*
** ===================================================================
**     Method      :  Disable (component FXOS8700CQ)
**
**     Description :
**         Disables the device with clearing the ACTIVE bit in the CTRL
**         register 1
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_Disable(void)
{
  uint8_t val, res;

  res = McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, &val);
  if (res!=ERR_OK) {
    return res;
  }
  if ((val&McuFXOS8700_ACTIVE_BIT_MASK)==0) {
    return ERR_OK; /* already disabled */
  }
  McuWait_Waitms(1); /* for unknown reasons, need to wait for 1 ms after reading the register */
  val &= ~McuFXOS8700_ACTIVE_BIT_MASK; /* disable device */
  return McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, val);
}

/*
** ===================================================================
**     Method      :  isEnabled (component FXOS8700CQ)
**
**     Description :
**         Returns the status of the the ACTIVE bit in the CTRL
**         register 1
**     Parameters  :
**         NAME            - DESCRIPTION
**       * isEnabled       - Pointer to where to store the
**                           result, TRUE if ACTIVE bit is set, FALSE
**                           otherwise
**     Returns     :
**         ---             - error code
** ===================================================================
*/
uint8_t McuFXOS8700_isEnabled(bool *isEnabled)
{
  uint8_t val, res;

  res = McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_1, &val);
  if (res!=ERR_OK) {
    return ERR_FAILED;
  }
  *isEnabled = (val&McuFXOS8700_ACTIVE_BIT_MASK)!=0; /* TRUE if bit is set, FALSE otherwise */
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  WhoAmI (component FXOS8700CQ)
**
**     Description :
**         Returns the value of the WHO_AM_I (0x0D) register
**     Parameters  :
**         NAME            - DESCRIPTION
**       * value           - Pointer to value to store
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_WhoAmI(uint8_t *value)
{
  return McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_WHO_AM_I, value);
}

/*
** ===================================================================
**     Method      :  GetTemperature (component FXOS8700CQ)
**
**     Description :
**         Returns the temperature of the die as signed 8bit values in
**         degree Celsius
**     Parameters  :
**         NAME            - DESCRIPTION
**       * temperature     - Pointer to variable where
**                           to store the temperature
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_GetTemperature(int8_t *temperature)
{
  int8_t temp;

  if (McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_DIE_TEMP, (uint8_t*)&temp) != ERR_OK) {
    return ERR_FAILED;
  }
  *temperature = (int8_t)(temp+McuFXOS8700_DIE_TEMP_OFFSET);
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  GetMagX (component FXOS8700CQ)
**
**     Description :
**         Returns the X magnetometer value.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * value           - Pointer to where to store the value.
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_GetMagX(int16_t *value)
{
  union {
    uint8_t buf[2]; /* value from device is in big endian */
    int16_t be;
  } val;
  static const uint8_t addr = McuFXOS8700_M_OUT_X_MSB;

  if(McuGenericI2C_ReadAddress(McuFXOS8700_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &val.buf[0], sizeof(val.buf))!=ERR_OK) {
    return ERR_FAILED; /* failure */
  }
#if McuFXOS8700_CPU_IS_LITTLE_ENDIAN
  *value = (int16_t)((val.buf[0]<<8)|val.buf[1]); /* transform into LE value */
#else
  *value = val.be; /* already in BE */
#endif
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  GetMagY (component FXOS8700CQ)
**
**     Description :
**         Returns the Y magnetometer value.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * value           - Pointer to where to store the value.
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_GetMagY(int16_t *value)
{
  union {
    uint8_t buf[2]; /* value from device is in big endian */
    int16_t be;
  } val;
  static const uint8_t addr = McuFXOS8700_M_OUT_Y_MSB;

  if(McuGenericI2C_ReadAddress(McuFXOS8700_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &val.buf[0], sizeof(val.buf))!=ERR_OK) {
    return ERR_FAILED; /* failure */
  }
#if McuFXOS8700_CPU_IS_LITTLE_ENDIAN
  *value = (int16_t)((val.buf[0]<<8)|val.buf[1]); /* transform into LE value */
#else
  *value = val.be; /* already in BE */
#endif
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  GetMagZ (component FXOS8700CQ)
**
**     Description :
**         Returns the Z magnetometer value.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * value           - Pointer to where to store the value.
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_GetMagZ(int16_t *value)
{
  union {
    uint8_t buf[2]; /* value from device is in big endian */
    int16_t be;
  } val;
  static const uint8_t addr = McuFXOS8700_M_OUT_Z_MSB;

  if(McuGenericI2C_ReadAddress(McuFXOS8700_I2C_ADDR, (uint8_t*)&addr, sizeof(addr), &val.buf[0], sizeof(val.buf))!=ERR_OK) {
    return ERR_FAILED; /* failure */
  }
#if McuFXOS8700_CPU_IS_LITTLE_ENDIAN
  *value = (int16_t)((val.buf[0]<<8)|val.buf[1]); /* transform into LE value */
#else
  *value = val.be; /* already in BE */
#endif
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  MagneticSensorReset (component FXOS8700CQ)
**
**     Description :
**         Initiates a magnetic sensor reset cycle that will restore
**         correct operation after exposure to an excessive magnetic
**         field which exceeds the Full Scale Range but is less than
**         the Maximum Applied Magnetic Field.
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_MagneticSensorReset(void)
{
  uint8_t val;

  if (McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_2, &val)!=ERR_OK) {
    return ERR_FAILED;
  }
  val |= McuFXOS8700_CTRL_REG_2_MASK_RST; /* set one shot reset bit */
  return McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_2, val);
}

/*
** ===================================================================
**     Method      :  ReadReg8 (component FXOS8700CQ)
**
**     Description :
**         Reads an 8bit device register
**     Parameters  :
**         NAME            - DESCRIPTION
**         addr            - device memory map address
**       * val             - Pointer to value
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_ReadReg8(uint8_t addr, uint8_t *val)
{
  if (McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, addr, val)!=ERR_OK) {
    return ERR_FAILED;
  }
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  WriteReg8 (component FXOS8700CQ)
**
**     Description :
**         Write an 8bit device register
**     Parameters  :
**         NAME            - DESCRIPTION
**         addr            - device memory map address
**         val             - value to write
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_WriteReg8(uint8_t addr, uint8_t val)
{
  return McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, addr, val);
}

/*
** ===================================================================
**     Method      :  SwReset (component FXOS8700CQ)
**
**     Description :
**         Perform a software reset using the rst bit in the CTRL
**         register 2
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuFXOS8700_SwReset(void)
{
  uint8_t val, res;

  res = McuGenericI2C_ReadByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_2, &val);
  if (res!=ERR_OK) {
    return res;
  }
  val |= McuFXOS8700_CTRL_REG_2_MASK_RST; /* reset device */
  res = McuGenericI2C_WriteByteAddress8(McuFXOS8700_I2C_ADDR, McuFXOS8700_CTRL_REG_2, val);
  if (res!=ERR_OK) {
    return res;
  }
  McuWait_Waitms(1); /* wait for one ms after sending the software reset */
  return ERR_OK;
}

/* END McuFXOS8700. */

/*!
** @}
*/
