/**!  @brief Class for managing storing "Adafruit" sensor calibration 
             in internal Flash memory with KVStore
             for Arduino Nano 33 BLE
 * **/

//https://os.mbed.com/docs/mbed-os/v6.12/apis/kvstore.html
//KVStore. TDBStore - Default implementation of the KVStore API. It provides static wear-leveling and quick access for when you have a small number of KV pairs.
//https://os.mbed.com/docs/mbed-os/v6.12/apis/data-architecture.html

#include "KVStore.h"
#include "kvstore_global_api.h"

  /**! XYZ vector of offsets for zero-g, in m/s^2 */
  float accel_zerog[3] = {0, 0, 0};

  /**! XYZ vector of offsets for zero-rate, in rad/s */
  float gyro_zerorate[3] = {0, 0, 0};

  /**! XYZ vector of offsets for hard iron calibration (in uT) */
  float mag_hardiron[3] = {0, 0, 0};

  /**! The 3x3 matrix for soft-iron calibration (unitless) */
  float mag_softiron[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};

  /**! The magnetic field magnitude in uTesla */
  float mag_field = 50;

const char* const ASC_KV_Key0 = "store_flag";
const char* const ASC_KV_Key1 = "store_offsets";

void setGyroCalibration(float x, float y, float z) {
    gyro_zerorate[0]=x;	  
    gyro_zerorate[1]=y;	  
    gyro_zerorate[2]=z;	  
}

float getGyroXCal() {
  return gyro_zerorate[0];
}

float getGyroYCal() {
  return gyro_zerorate[1];
}

float getGyroZCal() {
  return gyro_zerorate[2];
}

bool saveCalibration(void) {
  Serial.println("Save Cal");

  kv_reset("/kv/");

  uint8_t flag=42;
  
  kv_set(ASC_KV_Key0,&flag,sizeof(flag),0);
  
  float offsets[16];
  memcpy(offsets, accel_zerog, 12);       // 3 x 4-byte floats
  memcpy(offsets + 3, gyro_zerorate, 12); // 3 x 4-byte floats
  memcpy(offsets + 6, mag_hardiron, 12);  // 3 x 4-byte floats

  offsets[9] = mag_field;

  offsets[10] = mag_softiron[0];
  offsets[11] = mag_softiron[4];
  offsets[12] = mag_softiron[8];
  offsets[13] = mag_softiron[1];
  offsets[14] = mag_softiron[2];
  offsets[15] = mag_softiron[5];

  kv_set(ASC_KV_Key1, (uint8_t*)&offsets, sizeof(offsets), 0);
  
  return true;
}

bool loadCalibration(void) {

  uint8_t flag;
  
  kv_get(ASC_KV_Key0,&flag,sizeof(flag),0); 

  if (flag=!42) {
    Serial.print("FLAG NOT SET, CALIBRATION NOT FOUND");
    return false;
  }

  float offsets[16];
	
  kv_get(ASC_KV_Key1,(byte*)&offsets,sizeof(offsets),0);
  
  accel_zerog[0] = offsets[0];
  accel_zerog[1] = offsets[1];
  accel_zerog[2] = offsets[2];

  gyro_zerorate[0] = offsets[3];
  gyro_zerorate[1] = offsets[4];
  gyro_zerorate[2] = offsets[5];

  mag_hardiron[0] = offsets[6];
  mag_hardiron[1] = offsets[7];
  mag_hardiron[2] = offsets[8];

  mag_field = offsets[9];

  mag_softiron[0] = offsets[10];
  mag_softiron[1] = offsets[13];
  mag_softiron[2] = offsets[14];
  mag_softiron[3] = offsets[13];
  mag_softiron[4] = offsets[11];
  mag_softiron[5] = offsets[15];
  mag_softiron[6] = offsets[14];
  mag_softiron[7] = offsets[15];
  mag_softiron[8] = offsets[12];

  return true;
}

bool printCalibration(void) {
    Serial.println(F("------------"));

  Serial.print("Accelerometer: ");
  Serial.print(accel_zerog[0]);
  Serial.print(", ");
  Serial.print(accel_zerog[1]);
  Serial.print(", ");
  Serial.print(accel_zerog[2]);
  Serial.println();
	
  Serial.print("Gyroscope: ");
  Serial.print(gyro_zerorate[0]);
  Serial.print(", ");
  Serial.print(gyro_zerorate[1]);
  Serial.print(", ");
  Serial.print(gyro_zerorate[2]);
  Serial.println();
	
  Serial.print("Magnetometer Hard Iron: ");
  Serial.print(mag_hardiron[0]);
  Serial.print(", ");
  Serial.print(mag_hardiron[1]);
  Serial.print(", ");
  Serial.print(mag_hardiron[2]);
  Serial.println();
	
  Serial.print("Magnetic Field: ");
  Serial.print(mag_field);
  Serial.println();
  
  Serial.print("Magnetometer Soft Iron: ");
  Serial.print(mag_softiron[0]);
  Serial.print(", ");
  Serial.print(mag_softiron[1]);
  Serial.print(", ");
  Serial.print(mag_softiron[2]);
  Serial.println();
  Serial.print(mag_softiron[3]);
  Serial.print(", ");
  Serial.print(mag_softiron[4]);
  Serial.print(", ");
  Serial.print(mag_softiron[5]);
  Serial.println();
  Serial.print(mag_softiron[6]);
  Serial.print(", ");
  Serial.print(mag_softiron[7]);
  Serial.print(", ");
  Serial.print(mag_softiron[8]);
  Serial.println();
	
  Serial.println(F("\n------------"));
  return true;
}

bool printSavedCalibration(void) {
  Serial.println(F("------------"));

  uint8_t flag;
  
  kv_get(ASC_KV_Key0,&flag,sizeof(flag),0); 

  if (flag=!42) {
    Serial.print("FLAG NOT SET, CALIBRATION NOT FOUND");
    return false;
  }

  float offsets[16];
	
  kv_get(ASC_KV_Key1,(byte*)&offsets,sizeof(offsets),0);
  
  accel_zerog[0] = offsets[0];
  accel_zerog[1] = offsets[1];
  accel_zerog[2] = offsets[2];

  Serial.print("Accelerometer: ");
  Serial.print(accel_zerog[0]);
  Serial.print(", ");
  Serial.print(accel_zerog[1]);
  Serial.print(", ");
  Serial.print(accel_zerog[2]);
  Serial.println();
	
  gyro_zerorate[0] = offsets[3];
  gyro_zerorate[1] = offsets[4];
  gyro_zerorate[2] = offsets[5];

  Serial.print("Gyroscope: ");
  Serial.print(gyro_zerorate[0]);
  Serial.print(", ");
  Serial.print(gyro_zerorate[1]);
  Serial.print(", ");
  Serial.print(gyro_zerorate[2]);
  Serial.println();
	
  mag_hardiron[0] = offsets[6];
  mag_hardiron[1] = offsets[7];
  mag_hardiron[2] = offsets[8];

  Serial.println("Magnetometer Hard Iron: ");
  Serial.print(mag_hardiron[0]);
  Serial.print(", ");
  Serial.print(mag_hardiron[1]);
  Serial.print(", ");
  Serial.print(mag_hardiron[2]);
  Serial.println();
	
  mag_field = offsets[9];

  Serial.print("Magnetic Field: ");
  Serial.print(mag_field);
  Serial.println();
  
  mag_softiron[0] = offsets[10];
  mag_softiron[1] = offsets[13];
  mag_softiron[2] = offsets[14];
  mag_softiron[3] = offsets[13];
  mag_softiron[4] = offsets[11];
  mag_softiron[5] = offsets[15];
  mag_softiron[6] = offsets[14];
  mag_softiron[7] = offsets[15];
  mag_softiron[8] = offsets[12];

  Serial.print("Magnetometer Soft Iron: ");
  Serial.print(mag_softiron[0]);
  Serial.print(", ");
  Serial.print(mag_softiron[1]);
  Serial.print(", ");
  Serial.print(mag_softiron[2]);
  Serial.println();
  Serial.print(mag_softiron[3]);
  Serial.print(", ");
  Serial.print(mag_softiron[4]);
  Serial.print(", ");
  Serial.print(mag_softiron[5]);
  Serial.println();
  Serial.print(mag_softiron[6]);
  Serial.print(", ");
  Serial.print(mag_softiron[7]);
  Serial.print(", ");
  Serial.print(mag_softiron[8]);
  Serial.println();
	
/*  for (uint16_t a = ee_addr; a < ee_addr + KVStore_CAL_SIZE; a++) {
    uint8_t c = KVStore.read(a);
    Serial.print("0x");
    if (c < 0x10)
      Serial.print('0');
    Serial.print(c, HEX);
    Serial.print(", ");
    if ((a - ee_addr) % 16 == 15) {
      Serial.println();
    }
  }
  */

  Serial.println(F("\n------------"));
  return true;
}
