/*

Features:
  Working:
    Set HV
    Set Threshold
    Print out events
  ToDo:
    Print precise GPS timestamps for events
    HV calibration?
    Threshold calibration?


Bonus:
  A)Temperature
  B) Pressure
  C) XYZ acceleration


*/

#include <Wire.h>

#define LED1_pin 12  // green and lower one
#define LED2_pin 11  // red and upper one

#define TRIGOUT 5
#define STRIGBOUT A0
#define STRIGAOUT A5

#define MAX5387_PA0_pin A9
#define MAX5387_PA1_pin A10
#define MAX5387_PA2_pin A11
#define ref1_pin A1
#define ref2_pin A2

const int HV_MAX_VAL = 89;
const int HV_MIN_VAL = 255;

//set up the pins to remap SPI by hand
const int num_devices = 2;
const int SS_pin[num_devices] = {14, 15};
const int SCK_pin = 17;
//const int MISO_pin = 22;
const int MOSI_pin = 16;

byte thresh1;
byte thresh2;

unsigned long timemeasure;

float instarate;

unsigned long event_count = 0;


void setup() {
  //setup analogue writemode
  analogWriteResolution(12);
  // setup pins
  setPinModes();
  setConstantPins();
  attachInterrupt(digitalPinToInterrupt(TRIGOUT), [=] () {printTimeAndPin(TRIGOUT, "SiPM_c");}, RISING);
  // setup serial comm
  Serial.begin(115200);
  // setup initial thresholds
  //setThreshold(1, 100);
  //setThreshold(2, 100);
  analogWrite(DAC0, 1374);
  analogWrite(DAC1, 1374); 
  // set HV to minimum
  byte HV_val = 104;
  Serial.print("Setting HV to: ");
  Serial.println(HV_val);
  bitBang(HV_val);
}

void loop() {
  Serial.println("Input a command!");
  Serial.println("[1= set both thrsholds; 2= set HV, 3= reset event count]");
  int cmd = readIntFromSerial();
  switch(cmd){
    case 1:
      {
        Serial.println("Set a threshold value [1,4096]: ");
        int value = readIntFromSerial();
        //setThreshold(3, value);
        analogWrite(DAC0, value);
        analogWrite(DAC1, value); 
        break;
      }
    case 2:
      {
        Serial.println("Input a voltage value [1=highest,255=lowest]");
        byte sendValue = (byte) readIntFromSerial();
        if (sendValue < HV_MAX_VAL){
          Serial.print("HV Value is too high! Setting HV to:");
          Serial.println(HV_MAX_VAL);
          bitBang(HV_MAX_VAL); // Transmit data
        } else{
          Serial.print("Setting HV to:");
          Serial.println(sendValue);
          bitBang(sendValue); // Transmit data
        }
        break;
      }
    case 3:
      event_count = 0;
      Serial.println("Event counter set to 0!");
      break;
  }
  
    
}



void setPinModes(){
  // I2C adress pins for the MAX5387
  pinMode(MAX5387_PA0_pin, OUTPUT);
  pinMode(MAX5387_PA1_pin, OUTPUT);
  pinMode(MAX5387_PA2_pin, OUTPUT);
  // Analoge input pins form the threshold
  pinMode(ref1_pin, INPUT);
  pinMode(ref2_pin, INPUT);
  // status LEDs
  pinMode(LED1_pin, OUTPUT);
  pinMode(LED2_pin, OUTPUT);
  // trigger pins
  pinMode(TRIGOUT, INPUT);
  // HV pins
  digitalWrite(SS, HIGH);  // Start with SS high
  for (int i=0; i<num_devices; i++){
    pinMode(SS_pin[i], OUTPUT);
    digitalWrite(SS_pin[i], HIGH);  
  }
  pinMode(SCK_pin, OUTPUT);
  //pinMode(MISO_pin, INPUT); //this is the avalanche pin, not implemented yet
  pinMode(MOSI_pin, OUTPUT);
}

void setConstantPins(){
  // I2C adress pins for the MAX5387
  digitalWrite(MAX5387_PA0_pin, LOW);//configure the address of the MAX5387 pot
  digitalWrite(MAX5387_PA1_pin, LOW);//configure the address of the MAX5387 pot
  digitalWrite(MAX5387_PA2_pin, LOW);//configure the address of the MAX5387 pot
}


// this function sets the thresholds for the MAX5387
// 1 is the first channel, 2 the second and 3 sets both at the same time
void setThreshold(int pot_channel, int value){
  // do a value check
  if (value > 255 || value < 1){
    return;
  } else {
    value = byte(value);
  }
  
  Wire.begin();
  Wire.beginTransmission(byte(0x28)); // transmit to device #112
  switch(pot_channel){
    case 1:
      Serial.print("Setting channel 1 to: ");
      Serial.println(value);
      Wire.write(byte(B00010001)); //sets value to the first channel
      Wire.write(value);
      thresh1 = value;
      break;
    case 2:
      Serial.print("Setting channel 2 to: ");
      Serial.println(value);
      Wire.write(byte(B00010010)); //sets value to the second channel
      Wire.write(value);
      thresh2 = value;
      break;
    case 3:
      Serial.print("Setting both channels channel to: ");
      Serial.println(value);
      Wire.write(byte(B00010011)); //sets value to both channels
      Wire.write(value);
      thresh1 = value;
      thresh2 = value;
      break;
  }
  
  Wire.endTransmission();
}


byte bitBang(byte _send)  // This function is what bitbangs the data
{

  //reception isn't implemented in this version. 
  //byte _receive = 0;
  for(int j=0; j<num_devices; j++){
    digitalWrite(SS_pin[j], LOW);        // SS low 
    for(int i=0; i<8; i++)  // There are 8 bits in a byte
    {
      digitalWrite(MOSI_pin, bitRead(_send, 7-i));    // Set MOSI
      //delay(1);
      digitalWrite(SCK_pin, HIGH);                  // SCK high
      //bitWrite(_receive, i, digitalRead(MISO_pin)); // Capture MISO
      digitalWrite(SCK_pin, LOW);                   // SCK low
    //digitalWrite(MOSI_pin, LOW);    // Set MOSI
      
    }
     digitalWrite(SS_pin[j], HIGH);       // SS high again 
  }
  //return _receive;        // Return the received data
}


void printTimeAndPin(int pin, String name){
  // print when and which pin was interrupted
  /*unsigned long mil = millis();
  unsigned long mic = micros();
  // blink the LED if we had an interrupt from the trigger
  if(pin == TRIGOUT){
    //digitalWrite(LED2_pin, !digitalRead(LED2_pin));   // Toggle led, sucks slightly (visually)
    digitalWrite(LED2_pin, HIGH); // is a bit dim...
  }
  
  Serial.print("T=");
  Serial.print(mil);
  Serial.print(":");
  Serial.print(mic);
  Serial.print(";P=");
  Serial.print(pin);
  Serial.print(";n=");
  Serial.println(name);
  
  if(pin == TRIGOUT){
    digitalWrite(LED2_pin, LOW);
  }
  */
  event_count++;
  Serial.print(name);
  Serial.print(";count=");
  Serial.println(event_count);
  /* This code works out the instant rate and prints it as well. more likely to cause crashes as it's in the interrupt.
  Serial.print(";time=");
  timemeasure = millis();
  Serial.print(timemeasure);
  Serial.print(";rate=");
  instarate = ((event_count*1000)/timemeasure);
  Serial.println(instarate);
*/
}

int readIntFromSerial(){
  int val = Serial.parseInt();
  while (val == 0){
    delay(100);
    val = Serial.parseInt();
  }
  return val;
}
