#ifndef TG_PMSA003_H
#define TG_PMSA003_H

#include <Arduino.h>
#include <Wire.h>


#define PMSA003_ADDRESS (0x12)

#define SENSOR_DATA_LENGTH 32

typedef struct PMSAQIdata {
  uint16_t pm10_standard,  ///< Standard PM1.0
      pm25_standard,       ///< Standard PM2.5
      pm100_standard;      ///< Standard PM10.0
  uint16_t pm10_env,       ///< Environmental PM1.0
      pm25_env,            ///< Environmental PM2.5
      pm100_env;           ///< Environmental PM10.0
  uint16_t particles_03um, ///< 0.3um Particle Count
      particles_05um,      ///< 0.5um Particle Count
      particles_10um,      ///< 1.0um Particle Count
      particles_25um,      ///< 2.5um Particle Count
      particles_50um,      ///< 5.0um Particle Count
      particles_100um;     ///< 10.0um Particle Count
} PM25_AQI_Data;

//////////////////////////////////////////////////////////////////
/// PMSA003 - Driver class for PMSA003 sensor
///
/// Based on the data sheet provided
///
class PMSA003{
  public:

   enum ChipModel{
        ChipModel_UNKNOWN = 0,
        ChipModel_PMSA003_REV0 = 0x10
   };


    PMSA003(TwoWire* i2c): m_initialized(false),i2c(i2c){}

    ChipModel chipModel();

    bool begin();
    bool reset();

    void read(PM25_AQI_Data& data);


protected:
    bool Initialize();


private:
    bool m_initialized;
    ChipModel m_chip_model;
    TwoWire* i2c;

    static const uint8_t REG_Char1 = 0x00; // 0x42
    static const uint8_t REG_Char2 = 0x01; // 0x4d
    static const uint8_t REG_FrameH = 0x02; // Frame length = 2x13 + 2 
    static const uint8_t REG_FrameL = 0x03; // --
    static const uint8_t REG_d1h = 0x04; // PM1.0 ug/m3 (standard)
    static const uint8_t REG_d1l = 0x05;
    static const uint8_t REG_d2h = 0x06; // PM2.5 ug/m3 (standard)
    static const uint8_t REG_d2l = 0x07;
    static const uint8_t REG_d3h = 0x08; // PM10  ug/m3 (standard)
    static const uint8_t REG_d3l = 0x09;
    static const uint8_t REG_d4h = 0x0A; // PM1.0 ug/m3 (atmospheric env)
    static const uint8_t REG_d4l = 0x0B;
    static const uint8_t REG_d5h = 0x0C; // PM2.5 ug/m3 (atmospheric env)
    static const uint8_t REG_d5l = 0x0D;
    static const uint8_t REG_d6h = 0x0E; // PM10  ug/m3 (atmospheric env)
    static const uint8_t REG_d6l = 0x0F;
    static const uint8_t REG_d7h = 0x10; // >0.3um/0.1L 
    static const uint8_t REG_d7l = 0x11;
    static const uint8_t REG_d8h = 0x12; // >0.5um/0.1L 
    static const uint8_t REG_d8l = 0x13;
    static const uint8_t REG_d9h = 0x14; // >1.0um/0.1L 
    static const uint8_t REG_d9l = 0x15;
    static const uint8_t REG_d10h = 0x16; // >2.5um/0.1L 
    static const uint8_t REG_d10l = 0x17;
    static const uint8_t REG_d11h = 0x18; // >5.0um/0.1L 
    static const uint8_t REG_d11l = 0x19;
    static const uint8_t REG_d12h = 0x1A; // >10.0um/0.1L 
    static const uint8_t REG_d12l = 0x1B;

    static const uint8_t REG_VERSION = 0x1C; // Verion
    static const uint8_t REG_ERR = 0x1D; // Error

    static const uint8_t REG_checkh = 0x1E; // Checksum
    static const uint8_t REG_checkl = 0x1D;

    bool ReadChipID();

    bool ReadRegister(uint8_t addr,uint8_t data[],uint8_t length);
    bool ReadData(uint8_t data[SENSOR_DATA_LENGTH]);

    bool WriteSettings();
    bool WriteRegister(uint16_t addr,uint8_t data);


};

#endif