//Though any type of sensor can be used to receive back data, as an example we are using a BME280 sensor (can
// measure temperature, pressure and humidity in air) from Adafruit as a demonstration. Please follow instruction
// setup on their website for this sensor to understand electrical hookups of Simblee with the sensor pins.
//Furthermore, unless its required to write low level firmware for the sensor, its recommended to install the pre-
// defined library for the sensor online. If you plan to use any other type of sensor or data input, please connect it
// to appropriate pins on Simblee and select appropriate communication protocol like SPI, I2C, UART etc.
//Moreover, the confirmation signals and other custom protocols (X, Y, Z, etc.) are matched between BLE firmware
// and WNBN Server. All of code is customizable and versatile, so for any change or addition to these protocols,
// make sure the changes are mutual on both ends. 

#include <SimbleeBLE.h>
#include "OTA_Bootloader.h"
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define BME_SCK 4         //Pin 13
#define BME_MISO 3        //Pin 12
#define BME_MOSI 5       //Pin 11
#define BME_CS 6         //Pin 10

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI remap for Simblee

unsigned long delayTime;

//Unique key for each message
const char msg_temp = 'T'; //Send temperature sensor data
const char msg_press = 'P'; //Send pressure sensor data
const char msg_hum = 'H'; //Send humidity sensor data

const char msg_reset = 'r'; //Reset Chip
const char msg_Sleep = 's'; //ULP Mode
const char boot = 'z'; //OTA Bootloader Mode
const char ack = 'X'; //Acknowledgement
const char con = 'Y'; //Connect Confirmation
const char discon = 'Z'; //Disconnect Confirmation

//For Receiving Data
boolean temp_flag = LOW;
float tempVal = 0;
String temp_data = "";
boolean press_flag = LOW;
float pressVal = 0;
String press_data = "";
boolean hum_flag= LOW;
float humVal = 0;
String hum_data = "";

//Sleep and Reset flag
boolean Sleep = LOW;

long getDecimal(float val)
{
  int intPart = int(val);
  long decPart = 1000*(val-intPart); 
//Multiplying by 1000 assuming that the float values will have a maximum of 3 decimal places. 
//Change accordingly to match the number of decimal places you need
  if(decPart>0)return(decPart);           //return the decimal part of float number if it is available 
  else if(decPart<0)return((-1)*decPart); //if negative, multiply by -1
  else if(decPart=0)return(00);           //return 0 if decimal part of float number is not available
}

void setup()
{
  //Set Up SimbleeBLE parameters
  SimbleeBLE.deviceName = "WNBN_TPH_Sensor";
  SimbleeBLE.advertisementData = "WNBN";
  SimbleeBLE.advertisementInterval = MILLISECONDS(300);
  SimbleeBLE.txPowerLevel = +4;  // (-20dbM to +4 dBm)

  Serial.begin (9600);
  

  bool status;

  // default settings
  bme.begin();
 // Start the BLE stack
  SimbleeBLE.begin();
}

void SimbleeBLE_onConnect()
{
  SimbleeBLE.send(con); //Send 'Y' as confirmation of connection    
}

// Whenever Simblee Disconnects, it resets itself to be able to connect again
void SimbleeBLE_onDisconnect()
{
  SimbleeBLE.send(discon); //Send 'Z' as confirmation of disconnection
  Simblee_systemReset();   //Reset Simblee   
}

// Receive data function
void SimbleeBLE_onReceive(char *data, int len)
{
  SimbleeBLE.send(ack); //Send back a confirmation that Simblee has received the command
  action(data[0]);        
//In Simblee data[0] stores the received character by default and send it to action function to execute proper codes
}


//These are list of function declaration and definition which are used in the program.
//Depending on the message, carries out the necessary operation.
void action (int now)
{
  if (now == -1)
  {
    return;
  }

  /*|||||||||||||||||||||||||||||||||||||||||||| Bootme mode ||||||||||||||||||||||||||||||||||||||||||||*/

  if (now == boot)
  {
    SimbleeBLE.end(); //Stop BLE mode to enable OTA mode properly
    ota_bootloader_start(); //begins OTA enabled state
  }


  //Reset Simblee
  if (now == msg_reset)
  {
    Simblee_systemReset();
    return;
  }

  //Simblee ULP(Ultra Low Power) and Wake Up Modes
  if (now == msg_Sleep) //If sleep button is pressed, execute the sleep function.
  {
    Sleep = HIGH;
  }

  //For sending temperature data
  if (now == msg_temp)
  {
    temp_flag = ! temp_flag; //Turn temp_flag = HIGH or LOW
  }
  //For sending pressure data
  if (now == msg_press)
  {
    press_flag = ! press_flag; //Turn press_flag = HIGH or LOW
  }
   //For sending humidity data
  if (now == msg_hum)
  {
    hum_flag = ! hum_flag; //Turn hum_flag = HIGH or LOW
  }
}

void loop()
{
  
  if (Sleep == HIGH)
  {
    Simblee_ULPDelay(INFINITE);
    Sleep = LOW;
  }

  if (temp_flag == HIGH)
  {
   tempVal = bme.readTemperature(); 
   Serial.print("Temperature = ");
   Serial.print(tempVal);
   Serial.println(" *C");  
   /////Converting Float to Char Array///////
   temp_data=String(int(tempVal))+ "."+String(getDecimal(tempVal)); 
   //combining both whole and decimal part in string with a fullstop between them
   char temperature[temp_data.length()+1];  //initialize character array to store the values
   //passing the value of the string to the character array   
   temp_data.toCharArray(temperature,temp_data.length()+1); 
   
   SimbleeBLE.send(temperature,6); //Send data in the form of 6 characters
   temp_flag = LOW; //Resetting the flag
   delay(1000);
  }

 if (press_flag == HIGH)
 {
   pressVal = bme.readPressure() / 100.0F;   
   Serial.print("Pressure = ");
   Serial.print(pressVal);
   Serial.println(" hPa"); 
   /////Converting Float to Char Array///////
   press_data=String(int(pressVal))+ "."+String(getDecimal(pressVal)); 
   //combining both whole and decimal part in string with a fullstop between them
   char pressure[press_data.length()+1];  //initialize character array to store the values
   //passing the value of the string to the character array   
   press_data.toCharArray(pressure,press_data.length()+1);    
   
   
   SimbleeBLE.send(pressure,6); //Send data in the form of 6 characters
   press_flag = LOW; //Resetting the flag
 }

  if (hum_flag == HIGH)
 {
   humVal = bme.readHumidity();   
   Serial.print("Humidity = ");
   Serial.print(humVal);
   Serial.println(" %");
   /////Converting Float to Char Array///////
   hum_data=String(int(humVal))+ "."+String(getDecimal(humVal)); 
   //combining both whole and decimal part in string with a fullstop between them
    char humidity[hum_data.length()+1];  //initialize character array to store the values
   hum_data.toCharArray(humidity,hum_data.length()+1);     
   //passing the value of the string to the character array   
   SimbleeBLE.send(humidity, 4); //Send data in the form of 4 characters
   hum_flag = LOW; //Resetting the flag
  }
}
