/*
   Sparkfun's ADXL345 Library Main Header File
   ADXL345.h

   E.Robert @ SparkFun Electronics
   Created: Jul 13, 2016
   Updated: Sep 06, 2016

   Hardware Resources:
   - Arduino Development Board
   - SparkFun Triple Access Accelerometer ADXL345

   Development Environment Specifics:
   Arduino 1.6.8
   SparkFun Triple Axis Accelerometer Breakout - ADXL345
   Arduino Uno
 */

#include "Arduino.h"

#ifndef ADXL345_h
# define ADXL345_h

/*************************** REGISTER MAP ***************************/
# define ADXL345_DEVID                   0x00         // Device ID
# define ADXL345_RESERVED1               0x01         // Reserved. Do Not Access.
# define ADXL345_THRESH_TAP              0x1D         // Tap Threshold.
# define ADXL345_OFSX                    0x1E         // X-Axis Offset.
# define ADXL345_OFSY                    0x1F         // Y-Axis Offset.
# define ADXL345_OFSZ                    0x20         // Z- Axis Offset.
# define ADXL345_DUR                             0x21 // Tap Duration.
# define ADXL345_LATENT                  0x22         // Tap Latency.
# define ADXL345_WINDOW                  0x23         // Tap Window.
# define ADXL345_THRESH_ACT              0x24         // Activity Threshold
# define ADXL345_THRESH_INACT    0x25                 // Inactivity Threshold
# define ADXL345_TIME_INACT              0x26         // Inactivity Time
# define ADXL345_ACT_INACT_CTL   0x27                 // Axis Enable Control for Activity and Inactivity Detection
# define ADXL345_THRESH_FF               0x28         // Free-Fall Threshold.
# define ADXL345_TIME_FF                 0x29         // Free-Fall Time.
# define ADXL345_TAP_AXES                0x2A         // Axis Control for Tap/Double Tap.
# define ADXL345_ACT_TAP_STATUS  0x2B                 // Source of Tap/Double Tap
# define ADXL345_BW_RATE                 0x2C         // Data Rate and Power mode Control
# define ADXL345_POWER_CTL               0x2D         // Power-Saving Features Control
# define ADXL345_INT_ENABLE              0x2E         // Interrupt Enable Control
# define ADXL345_INT_MAP                 0x2F         // Interrupt Mapping Control
# define ADXL345_INT_SOURCE              0x30         // Source of Interrupts
# define ADXL345_DATA_FORMAT             0x31         // Data Format Control
# define ADXL345_DATAX0                  0x32         // X-Axis Data 0
# define ADXL345_DATAX1                  0x33         // X-Axis Data 1
# define ADXL345_DATAY0                  0x34         // Y-Axis Data 0
# define ADXL345_DATAY1                  0x35         // Y-Axis Data 1
# define ADXL345_DATAZ0                  0x36         // Z-Axis Data 0
# define ADXL345_DATAZ1                  0x37         // Z-Axis Data 1
# define ADXL345_FIFO_CTL                0x38         // FIFO Control
# define ADXL345_FIFO_STATUS             0x39         // FIFO Status

# define ADXL345_BW_1600                 0xF          // 1111		IDD = 40uA
# define ADXL345_BW_800                  0xE          // 1110		IDD = 90uA
# define ADXL345_BW_400                  0xD          // 1101		IDD = 140uA
# define ADXL345_BW_200                  0xC          // 1100		IDD = 140uA
# define ADXL345_BW_100                  0xB          // 1011		IDD = 140uA
# define ADXL345_BW_50                   0xA          // 1010		IDD = 140uA
# define ADXL345_BW_25                   0x9          // 1001		IDD = 90uA
# define ADXL345_BW_12_5             0x8              // 1000		IDD = 60uA
# define ADXL345_BW_6_25                 0x7          // 0111		IDD = 50uA
# define ADXL345_BW_3_13                 0x6          // 0110		IDD = 45uA
# define ADXL345_BW_1_56                 0x5          // 0101		IDD = 40uA
# define ADXL345_BW_0_78                 0x4          // 0100		IDD = 34uA
# define ADXL345_BW_0_39                 0x3          // 0011		IDD = 23uA
# define ADXL345_BW_0_20                 0x2          // 0010		IDD = 23uA
# define ADXL345_BW_0_10                 0x1          // 0001		IDD = 23uA
# define ADXL345_BW_0_05                 0x0          // 0000		IDD = 23uA


/************************** INTERRUPT PINS **************************/
# define ADXL345_INT1_PIN                0x00 // INT1: 0
# define ADXL345_INT2_PIN                0x01 // INT2: 1


/********************** INTERRUPT BIT POSITION **********************/
# define ADXL345_INT_DATA_READY_BIT              0x07
# define ADXL345_INT_SINGLE_TAP_BIT              0x06
# define ADXL345_INT_DOUBLE_TAP_BIT              0x05
# define ADXL345_INT_ACTIVITY_BIT                0x04
# define ADXL345_INT_INACTIVITY_BIT              0x03
# define ADXL345_INT_FREE_FALL_BIT               0x02
# define ADXL345_INT_WATERMARK_BIT               0x01
# define ADXL345_INT_OVERRUNY_BIT                0x00

# define ADXL345_DATA_READY                              0x07
# define ADXL345_SINGLE_TAP                              0x06
# define ADXL345_DOUBLE_TAP                              0x05
# define ADXL345_ACTIVITY                                0x04
# define ADXL345_INACTIVITY                              0x03
# define ADXL345_FREE_FALL                               0x02
# define ADXL345_WATERMARK                               0x01
# define ADXL345_OVERRUNY                                0x00


/****************************** ERRORS ******************************/
# define ADXL345_OK                      1 // No Error
# define ADXL345_ERROR           0         // Error Exists

# define ADXL345_NO_ERROR        0         // Initial State
# define ADXL345_READ_ERROR      1         // Accelerometer Reading Error
# define ADXL345_BAD_ARG         2         // Bad Argument


class ADXL345 {
public:

  bool status;     // Set When Error Exists

  byte error_code; // Initial State
  double gains[3]; // Counts to Gs

  ADXL345(uint8_t i2c_addr);
  ADXL345(int CS);
  void powerOn();
  void powerOff();
  int  getDevID();
  void readAccel(int *xyx);
  void readAccel(int *x,
                 int *y,
                 int *z);
  void get_Gxyz(double *xyz);

  void setTapThreshold(int tapThreshold);
  int  getTapThreshold();
  void setAxisGains(double *_gains);
  void getAxisGains(double *_gains);
  void setAxisOffset(int x,
                     int y,
                     int z);
  void getAxisOffset(int *x,
                     int *y,
                     int *z);
  void setTapDuration(int tapDuration);
  int  getTapDuration();
  void setDoubleTapLatency(int doubleTapLatency);
  int  getDoubleTapLatency();
  void setDoubleTapWindow(int doubleTapWindow);
  int  getDoubleTapWindow();
  void setActivityThreshold(int activityThreshold);
  int  getActivityThreshold();
  void setInactivityThreshold(int inactivityThreshold);
  int  getInactivityThreshold();
  void setTimeInactivity(int timeInactivity);
  int  getTimeInactivity();
  void setFreeFallThreshold(int freeFallthreshold);
  int  getFreeFallThreshold();
  void setFreeFallDuration(int freeFallDuration);
  int  getFreeFallDuration();

  bool isActivityXEnabled();
  bool isActivityYEnabled();
  bool isActivityZEnabled();
  bool isInactivityXEnabled();
  bool isInactivityYEnabled();
  bool isInactivityZEnabled();
  bool isActivityAc();
  bool isInactivityAc();
  void setActivityAc(bool state);
  void setInactivityAc(bool state);

  bool getSuppressBit();
  void setSuppressBit(bool state);
  bool isTapDetectionOnX();
  void setTapDetectionOnX(bool state);
  bool isTapDetectionOnY();
  void setTapDetectionOnY(bool state);
  bool isTapDetectionOnZ();
  void setTapDetectionOnZ(bool state);
  void setTapDetectionOnXYZ(bool stateX,
                            bool stateY,
                            bool stateZ);

  void setActivityX(bool state);
  void setActivityY(bool state);
  void setActivityZ(bool state);
  void setActivityXYZ(bool stateX,
                      bool stateY,
                      bool stateZ);
  void setInactivityX(bool state);
  void setInactivityY(bool state);
  void setInactivityZ(bool state);
  void setInactivityXYZ(bool stateX,
                        bool stateY,
                        bool stateZ);

  bool   isActivitySourceOnX();
  bool   isActivitySourceOnY();
  bool   isActivitySourceOnZ();
  bool   isTapSourceOnX();
  bool   isTapSourceOnY();
  bool   isTapSourceOnZ();
  bool   isAsleep();

  bool   isLowPower();
  void   setLowPower(bool state);
  double getRate();
  void   setRate(double rate);
  void   set_bw(byte bw_code);
  byte   get_bw_code();

  bool   triggered(byte interrupts,
                   int  mask);

  byte   getInterruptSource();
  bool   getInterruptSource(byte interruptBit);
  bool   getInterruptMapping(byte interruptBit);
  void   setInterruptMapping(byte interruptBit,
                             bool interruptPin);
  bool   isInterruptEnabled(byte interruptBit);
  void   setInterrupt(byte interruptBit,
                      bool state);
  void   setImportantInterruptMapping(int single_tap,
                                      int double_tap,
                                      int free_fall,
                                      int activity,
                                      int inactivity);
  void InactivityINT(bool status);
  void ActivityINT(bool status);
  void FreeFallINT(bool status);
  void doubleTapINT(bool status);
  void singleTapINT(bool status);

  void getRangeSetting(byte *rangeSetting);
  void setRangeSetting(int val);
  bool getSelfTestBit();
  void setSelfTestBit(bool selfTestBit);
  bool getSpiBit();
  void setSpiBit(bool spiBit);
  bool getInterruptLevelBit();
  void setInterruptLevelBit(bool interruptLevelBit);
  bool getFullResBit();
  void setFullResBit(bool fullResBit);
  bool getJustifyBit();
  void setJustifyBit(bool justifyBit);
  void printAllRegister();

private:

  void writeTo(byte address,
               byte val);
  void writeToI2C(byte address,
                  byte val);
  void writeToSPI(byte address,
                  byte val);
  void readFrom(byte address,
                int  num,
                byte buff[]);
  void readFromI2C(byte address,
                   int  num,
                   byte buff[]);
  void readFromSPI(byte address,
                   int  num,
                   byte buff[]);
  void setRegisterBit(byte regAdress,
                      int  bitPos,
                      bool state);
  bool getRegisterBit(byte regAdress,
                      int  bitPos);
  byte _buff[6]; //	6 Bytes Buffer
  int _CS               = 10;
  bool I2C              = true;
  unsigned long SPIfreq = 5000000;
  uint8_t _i2c_addr;
};
void print_byte(byte val);
#endif // ifndef ADXL345_h
