import processing.io.*;

/*************************
 common
 **************************/
SPI spiInit(int index)
{
  return spiInit(index, 100000);
}

SPI spiInit(int index, int clk)
{
  if (!(index == 0 || index == 1))
    exit();
  SPI ret;
  ret = new SPI(SPI.list()[index]);
  ret.settings(clk, SPI.MSBFIRST, SPI.MODE0);

  return ret;
}

/*************************
 utility
 **************************/
int[] readRegisterUnsigned(SPI spi, byte addr)
{
  byte[] in = {(byte)(addr | 0x80), 0x00};
  byte[] out= spi.transfer(in);
  int[] ret = { (out[0] < 0 ? out[0] & 0xff : out[0]), (out[1] < 0 ? out[1] & 0xff : out[1])};

  return ret;
}

int[] readRegister(SPI spi, byte addr)
{
  byte[] in = {(byte)(addr | 0x80), 0x00};
  byte[] out= spi.transfer(in);
  int[] ret = { out[0], out[1]};

  return ret;
}

long readRegistersUnsigned(SPI spi, byte msb_, byte lsb_)
{
  int[] msb = readRegisterUnsigned(spi, msb_);
  int[] lsb = readRegisterUnsigned(spi, lsb_);

  return (msb[1] << 8) + lsb[1];
}

long readRegisters(SPI spi, byte msb_, byte lsb_)
{
  int[] msb = readRegister(spi, msb_);
  int[] lsb = readRegister(spi, lsb_);

  return (msb[1] << 8) + lsb[1];
}


byte[] writeRegister(SPI spi, byte addr)
{
  byte[] in = {(byte)(addr & 0x7f), 0x00};
  byte[] out= spi.transfer(in);

  return out;
}

byte[] writeRegister(SPI spi, byte addr, byte data)
{
  byte[] in = {(byte)(addr & 0x7f), data};
  byte[] out= spi.transfer(in);

  return out;
}

/*************************
 MC3008
 **************************/
int getAdcValue(SPI adc, int channel)
{
  byte[] out = {0x01, (byte)((0x08 + channel) << 4), 0x00};
  byte[] in = adc.transfer(out);

  return ((in[1] & 0x03) << 8 ) + (in[2] & 0xff);
}

/*************************
 MPL115A1
 **************************/

//ret [0] : pressure [hPa]
//ret [1] : temperature [degC]
float[] getPressureAndTemperature(SPI spi)
{
  return getPressureAndTemperature(spi, 100);
}

float[] getPressureAndTemperature(SPI spi, int iterNum)
{
  float pressure = 0;
  float temperature = 0;
  for (int loop = 0; loop < iterNum; loop++)
  {
    //set read mode (pressure and temperature)
    writeRegister(spi, (byte)0x24);
    delay(3);

    //pressure
    long press = readRegistersUnsigned(spi, (byte)0x00, (byte)0x02);
    press = press >> 6;

    //temperature
    long temp = readRegistersUnsigned(spi, (byte)0x04, (byte)0x06);
    temp = temp >> 6;

    //a0
    long a0 = readRegisters(spi, (byte)0x08, (byte)0x0a);
    //b1
    long b1 = readRegisters(spi, (byte)0x0c, (byte)0x0e);
    //b2
    long b2 =readRegisters(spi, (byte)0x10, (byte)0x12);
    //c12
    long c12 = readRegisters(spi, (byte)0x14, (byte)0x16);
    //c11
    long c11 = readRegisters(spi, (byte)0x18, (byte)0x1a);
    //c22
    long c22 = readRegisters(spi, (byte)0x1c, (byte)0x1e);

    long c11x1 = c11 * press;
    long a11 = ((b1 << 14) + c11x1) >> 14;
    long c12x2 = c12 * temp;
    long a1 = ((a11 << 11) + c12x2) >> 11;
    long c22x2 = c22 * temp;
    long a2 = ((b2 << 15) + (c22x2 >> 1)) >> 16;
    long a1x1 = a1 * press;
    long y1 = ((a0 << 10) + a1x1) >> 10;
    long a2x2 = a2*temp;
    long pComp = (y1 << 10) + a2x2;
    long siPcomp = pComp / 8192;

    pressure += ((65.0/1023.0)*siPcomp) + 50;
    temperature += (605.75-temp)*0.186916;
  }
  float[] ret = {pressure/(float)iterNum*10.0, temperature/(float)iterNum};
  return ret;
}

/*************************
 BME280
 **************************/
//ret[0]: temperature [degC]
//ret[1]: pressure [hPa]
//ret[2]: humidity [%RH]
float[] getTemperatureHumidityAndPressure(SPI spi)
{
  int[] chipId = readRegisterUnsigned(spi, (byte)0xd0);
  if (chipId[1] != 0x60)
  {
    println("read erro");
  }

  //calib data
  long t1 = readRegistersUnsigned(spi, (byte)0x89, (byte)0x88);
  long t2 = readRegisters(spi, (byte)0x8b, (byte)0x8a);
  long t3 = readRegisters(spi, (byte)0x8d, (byte)0x8c);

  long p1 = readRegistersUnsigned(spi, (byte)0x8f, (byte)0x8e);
  long p2 = readRegisters(spi, (byte)0x91, (byte)0x90);
  long p3 = readRegisters(spi, (byte)0x93, (byte)0x92);
  long p4 = readRegisters(spi, (byte)0x95, (byte)0x94);
  long p5 = readRegisters(spi, (byte)0x97, (byte)0x96);
  long p6 = readRegisters(spi, (byte)0x99, (byte)0x98);
  long p7 = readRegisters(spi, (byte)0x9b, (byte)0x9a);
  long p8 = readRegisters(spi, (byte)0x9d, (byte)0x9c);
  long p9 = readRegisters(spi, (byte)0x9f, (byte)0x9e);

  long h1 = readRegisterUnsigned(spi, (byte)0xa1)[1];
  long h2 = readRegisters(spi, (byte)0xe2, (byte)0xe1);
  long h3 = readRegisterUnsigned(spi, (byte)0xe3)[1];
  long h4 = (readRegister(spi, (byte)0xe4)[1] << 4) + (readRegister(spi, (byte)0xe5)[1] & 0x0f);
  long h5 = (readRegister(spi, (byte)0xe6)[1] << 4) + ((readRegister(spi, (byte)0xe5)[1] >> 4) & 0x0f);
  long h6 = readRegisterUnsigned(spi, (byte)0xe7)[1];

  //write config
  writeRegister(spi, (byte)0xf4, (byte)0x00);
  writeRegister(spi, (byte)0xf5, (byte)0x00);
  writeRegister(spi, (byte)0xf2, (byte)0x07);
  writeRegister(spi, (byte)0xf4, (byte)0xff);

  //temperature
  int[] tmsb =readRegisterUnsigned(spi, (byte)0xfa);
  int[] tlsb =readRegisterUnsigned(spi, (byte)0xfb);
  int[] txlsb =readRegisterUnsigned(spi, (byte)0xfc);
  long adc_T = (tmsb[1] << 12) | (tlsb[1] << 4) | ((txlsb[1] >> 4) & 0x0f);
  long var1 = ((adc_T >> 3) - (t1 << 1)) * t2 >> 11;
  long var2 = ((adc_T >> 4) - t1) * (((adc_T >> 4) - t1) >> 12) * t3 >> 14;
  long t_fine = var1+var2;
  float temperature = ((t_fine*5+128) >> 8)/100.0;

  //pressure
  int[] pmsb =readRegisterUnsigned(spi, (byte)0xf7);
  int[] plsb =readRegisterUnsigned(spi, (byte)0xf8);
  int[] pxlsb =readRegisterUnsigned(spi, (byte)0xf9);
  long adc_P = (pmsb[1] << 12) | (plsb[1] << 4) | ((pxlsb[1] >> 4) & 0x0f);
  var1 = t_fine - 128000;
  var2 = var1 * var1 * p6;
  var2 = var2 + ((var1*p5) << 17);
  var2 = var2 + (p4 << 35);
  var1 = ((var1 * var1 * p3) >> 8) + ((var1 * p2) << 12);
  var1 = (((long)1 << 47) + var1) *p1 >> 33;
  float pressure = 0;
  if (var1 != 0)
  {
    long p_acc = 1048576 - adc_P;
    p_acc = (((p_acc << 31) - var2)*3125)/var1;
    var1 = (p9 * (p_acc >> 13) * (p_acc >> 13)) >> 25;
    var2 = (p8 * p_acc) >> 19;
    pressure  = (((p_acc + var1 + var2) >> 8) + (p7 << 4))/256.0/100.0;
  }

  //humidity
  int[] hmsb =readRegisterUnsigned(spi, (byte)0xfd);
  int[] hlsb =readRegisterUnsigned(spi, (byte)0xfe);
  long adc_H = (hmsb[1] << 8) | hlsb[1];
  var1 = t_fine - (long)76800;
  var1 = (((((adc_H << 14) - (h4 << 20) - (h5 * var1)) + ((long)16384)) >> 15) * (((((((var1 * h6) >> 10) * (((var1 * h3) >> 11) + ((long)32768))) >> 10) + ((long)2097152)) * h2 + 8192) >> 14));
  var1 = (var1 - (((((var1 >> 15) * (var1 >> 15)) >> 7) * (h1)) >> 4));
  var1 = var1 < 0 ? 0 : var1;
  var1 = var1 > (long)419430400 ? (long)419430400 : var1;
  float humidity = (var1 >> 12)/1024.0;

  float[] ret = {temperature, humidity, pressure};
  return ret;
}