/*  
 *   Stand: 25.08.2021
 *   Author: Julian Rico
 *   
 *   Teststand für Stromzähler-Empfänger.
 *   
 *   Diese Software bietet ein Interface, um den Empfänger zu testen.
 *   Der Benutzer kann Zahlen eingeben, welche als Zählstand interpretiert werden.
 *   Der Zählstand wird dann in Form eines SML Pakets verschickt.
 */

/* Defines */
#define BAUDRATE    9600
#define BUFFERSIZE  100

/* Globale Variablen */
int BUFFER[BUFFERSIZE]; // Buffer für Einlesen serieller Daten
float kWh;              // Speichervariable für berechneten Input
int i, j;               // Laufvariablen

/* Funktionsprototypen */
void readInput();
void sendSML(unsigned long mWh);

/* Setup: einmalig */
void setup() {

  // Debug LED
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  // Serial Setup
  Serial.begin(BAUDRATE);
  Serial.println("¡Bitte geben Sie einen ganzzahligen Wert ein [kWh]!");
  Serial.flush(); 
}

/* Hauptprogramm */
void loop() {

  // Warten auf Eingabe von Bediener
  if (Serial.available() > 0)
    {
      digitalWrite(LED_BUILTIN, HIGH);
      readInput();   
    }
    delay(50);
}

void readInput() {
  // Einlesen
  i = 0;
  do {
    if (i<BUFFERSIZE) {
      BUFFER[i] = Serial.read();
      i++;
    }
  } while (Serial.available());
  i--; // Letzter Eintrag in Buffer ist LF

  // Input umrechnen
  kWh = 0;
  for (j = i; j > 0; j--) {
    kWh = kWh + (BUFFER[j-1]-48) * pow(10, (i-j));
  }
  
  // SML senden
  // +0.5 für korrektes Auf- und Abrunden, cast rundet immer ab, 
  // *10.000 für kWh->mWh
  sendSML(((unsigned long)(kWh+0.5)*10000)); 

  // Buffer löschen
  for (j = 0; j < i+2; j++)
    BUFFER[j] = 0;
}

void sendSML(unsigned long mWh) {
  // Hier wird ein Teil einer SML Nachricht verschickt
  // Konkret handelt es sich um die Sequence mit dem OBIS Kenncode 
  // 1.8.0*255 (=Gesamtverbrauch)
  Serial.write(0x77);   /* 'M' ASCII = 77 - SML_Message.messageBody.
                        SML_GetList_Reponse.valList.valListEntry (Sequence) */
  Serial.write(0x07);   /* 07 - objName (TL[1] + octet-string[6] */
  Serial.write(0x01);   /* 01 - objName Teil A */
  Serial.write(0x00);   /* 00 - objName Teil B */
  Serial.write(0x01);   /* 01 - objName Teil C */
  Serial.write(0x08);   /* 08 - objName Teil D */
  Serial.write(0x00);   /* 00 - objName Teil E */
  Serial.write(0xFF);   /* FF - objName Teil F */
  Serial.write(0x01);   /* 01 - Status  (optional: 01 bedeutet "nicht versorgt") */
  Serial.write(0x01);   /* 01 - valTime (optional: 01 bedeutet "nicht versorgt") */
  Serial.write(0x01);   /* 01 - unit    (optional: 01 bedeutet "nicht versorgt") */
  Serial.write(0x01);   /* 01 - scaler  (optional: 01 bedeutet "nicht versorgt") */
  Serial.write(0x59);   /* 01 - value (TL[1] + Integer[8]) */
  Serial.write(0x00);   /* value[0] -- wir bekommen nur 4 Byte, 
                            daher die ersten 4 nullen */
  Serial.write(0x00);   /* value[1] -- wir bekommen nur 4 Byte, 
                            daher die ersten 4 nullen */
  Serial.write(0x00);   /* value[2] -- wir bekommen nur 4 Byte, 
                            daher die ersten 4 nullen */
  Serial.write(0x00);   /* value[3] -- wir bekommen nur 4 Byte, 
                            daher die ersten 4 nullen */

  // Letzten 4 Bytes: mWh (unsigned long) konvertieren in 4 Bytes
  unsigned long temp;   
  temp = (mWh & 0xFF000000) >> 24;
  Serial.write(temp); /* value[4] */
  temp = (mWh & 0x00FF0000) >> 16;
  Serial.write(temp); /* value[5] */
  temp = (mWh & 0x0000FF00) >> 8;
  Serial.write(temp); /* value[6] */
  temp = (mWh & 0x000000FF);
  Serial.write(temp); /* value[7] */
  
  Serial.println();
  Serial.println("¡Bei Bedarf nächsten ganzzahligen Wert eingeben [kWh]!"); 
}
