/*********************************************************************
  BeieliScale by nbit Informatik GmbH

*********************************************************************/
#include <lmic.h>
#include <hal/hal.h>
#include <Arduino.h>
#include <SPI.h>
#include <avr/dtostrf.h>
#include "HX711.h"
#include "Adafruit_Si7021.h"
#include "Adafruit_FRAM_SPI.h"

#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL)
// Required for Serial on Zero based boards
#define Serial SERIAL_PORT_USBVIRTUAL
#endif

#define MAX_VALUES_TO_SEND 5

bool send_lora_data = false;
bool lora_package_sent = false;
bool timeout_elapsed = false;


typedef struct {
  byte version;                          // Versionierung des Paketformats
  short weight[MAX_VALUES_TO_SEND];        // Gewicht in 10-Gramm
  short temperature[MAX_VALUES_TO_SEND];   // Temperatur in 1/10 Grad Celsius
  byte vbat;                             // Batteriespannung (1 Einheit => 20 mV)
} LORA_data;

LORA_data lora_data;

typedef struct {
  u1_t nwkskey[16];
  u1_t appskey[16];
  u4_t devaddr;
  u1_t framecounter;
  long cal_w1_0;
  long cal_w2_0;
  float cal_w1_factor;
  float cal_w2_factor;
  short weight[MAX_VALUES_TO_SEND];
  short temperature[MAX_VALUES_TO_SEND];
  byte my_position;
} FRAM_data;

FRAM_data fram_data;
bool usb_power_only;

// Im DEBUG-Modus werden Meldungen auf der seriellen Schnittstelle ausgegeben
#define DEBUG 1

#define DONEPIN  A5
#define VBATPIN  A7
#define LONG_OFFSET  2147483648L
#define MAX_CHARS 80
#define MAX_SHORT 32767

#define NWKSKEY 1
#define APPSKEY 2
#define DEVADDR 3

uint8_t FRAM_CS = 10;

Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_CS);  // use hardware SPI

// Temperatursensor
Adafruit_Si7021 sensor = Adafruit_Si7021();

// die beiden Waagen
HX711 scale1;
HX711 scale2;

char charVal[MAX_CHARS];

// LORA
// LoRaWAN NwkSKey, network session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const PROGMEM u1_t NWKSKEYJOERG[16] = { 0x5F, 0x33, 0x20, 0x8C, 0x13, 0x3A, 0x39, 0x3F, 0xA5, 0x6F, 0xE1, 0xC7, 0x9B, 0x78, 0x2B, 0xDF };

// LoRaWAN AppSKey, application session key
// This is the default Semtech key, which is used by the early prototype TTN
// network.
static const u1_t PROGMEM APPSKEYJOERG[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
;

// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDRJOERG = 0x260112C8 ; // <-- Change this address for every node!

// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }

static uint8_t mydata[] = "Hello, world!";
static osjob_t sendjob;

// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {3, 6, LMIC_UNUSED_PIN},
};

void onEvent (ev_t ev) {
  Serial.print(os_getTime());
  Serial.println("Received Lora Event: ");
  switch (ev) {
    case EV_SCAN_TIMEOUT:
      Serial.println(F("EV_SCAN_TIMEOUT"));
      break;
    case EV_BEACON_FOUND:
      Serial.println(F("EV_BEACON_FOUND"));
      break;
    case EV_BEACON_MISSED:
      Serial.println(F("EV_BEACON_MISSED"));
      break;
    case EV_BEACON_TRACKED:
      Serial.println(F("EV_BEACON_TRACKED"));
      break;
    case EV_JOINING:
      Serial.println(F("EV_JOINING"));
      break;
    case EV_JOINED:
      Serial.println(F("EV_JOINED"));
      break;
    case EV_RFU1:
      Serial.println(F("EV_RFU1"));
      break;
    case EV_JOIN_FAILED:
      Serial.println(F("EV_JOIN_FAILED"));
      break;
    case EV_REJOIN_FAILED:
      Serial.println(F("EV_REJOIN_FAILED"));
      break;
    case EV_TXCOMPLETE:
      Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
      if (LMIC.txrxFlags & TXRX_ACK)
        Serial.println(F("Received ack"));
      if (LMIC.dataLen) {
        Serial.println(F("Received "));
        Serial.println(LMIC.dataLen);
        Serial.println(F(" bytes of payload"));
      }
      lora_package_sent = true;  
      break;
    case EV_LOST_TSYNC:
      Serial.println(F("EV_LOST_TSYNC"));
      break;
    case EV_RESET:
      Serial.println(F("EV_RESET"));
      break;
    case EV_RXCOMPLETE:
      // data received in ping slot
      Serial.println(F("EV_RXCOMPLETE"));
      break;
    case EV_LINK_DEAD:
      Serial.println(F("EV_LINK_DEAD"));
      break;
    case EV_LINK_ALIVE:
      Serial.println(F("EV_LINK_ALIVE"));
      break;
    default:
      Serial.println(F("Unknown event"));
      break;
  }
}

void do_send(osjob_t* j) {
  // Check if there is not a current TX/RX job running
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
  } else {
    // Prepare upstream data transmission at the next possible time.
    //#define VBATPIN A7
    //    float measuredvbat = analogRead(VBATPIN);
    //    measuredvbat *= 2;    // we divided by 2, so multiply back
    //    measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
    //    measuredvbat /= 1024; // convert to voltage
    //    char buffer[8];

    //    dtostrf(measuredvbat, 1, 2, buffer);
    //String res = buffer;
    //res.getBytes(buffer, res.length() + 1);
    //    Serial.print("VBat: " ); Serial.println(measuredvbat);
    //LMIC_setTxData2(1, (uint8_t*) &lora_data, sizeof(lora_data), 0);
    LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
    ShowLoraData();
    
    Serial.println(F("Packet queued"));
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

// END LORA



// Error-Fuction
void error(const __FlashStringHelper*err) {
#if DEBUG
  Serial.println(err);
#endif
}

// Print Function
void print_debug(const char *InputString) {
#if DEBUG
  //Serial.println(millis());
  Serial.println(InputString);
#endif
}

byte dehex(char c) { // Get nibble value 0...15 from character c
  // Treat digit if c<'A', else letter
  return c < 'A' ? c & 0xF : 9 + (c & 0xF);
  // Above assumes that c is a 'hex digit' in 0...9, A or a ... F or f.
  // It would make more sense to just use 16 consecutive characters,
  // like eg 0123456789:;<=>? or @ABCDEFGHIJKLMNO so the above
  // could just say `return c & 0xF;`
}

void WriteKey (String input, int which) {
  const char *hin = input.c_str();  // Get character array
  int clen = input.length() / 2;
  // Next line invalid in C++, ok in C99.  Probably need to
  // instead declare a fixed-length array, cmd[MAXCMDLEN], etc
  char cmd[clen + 1]; // Leave a byte for null terminator
  for (int i = 0; i < 2 * clen; i += 2) {
    cmd[i / 2] = dehex(hin[i]) << 4 | dehex(hin[i + 1]);
  }
  cmd[clen] = 0;                     // Null-byte terminator
  if (which == APPSKEY) {
    memcpy(&fram_data.appskey, &cmd, 16);
  } else if (which == NWKSKEY) {
    memcpy(&fram_data.nwkskey, &cmd, 16);
  } else if (which == DEVADDR) {
    print_debug("write device address");
//    Serial.println(hin)
//    Serial.println(strtol(hin, 0, 16));
    fram_data.devaddr = strtol(hin, 0, 16);
  } else {
    print_debug("Invalid which");
  }
  Save2FRAM();
}

boolean isValidHexKey(String hk, int length) {
  if (hk.length() != length) {
    return false;
  }
  char mychar;
  for (int i = 0; i < hk.length(); i++) {
    mychar = hk.charAt(i);
    if (not(isHexadecimalDigit(mychar))) {
      return false;
    }
  }
  return true;
}

void print_byte_array(u1_t arr[], int n) {
  int i;
  for (i = 0; i < n; i++)
  {
    if (arr[i] < 16) Serial.write('0');
    Serial.print(arr[i], HEX);
  }
}

float GetWeight() {
  long raw_weight1 = scale1.read_average(3);
  long raw_weight2 = scale2.read_average(3);
  
  return (((raw_weight1 - fram_data.cal_w1_0) * fram_data.cal_w1_factor) + ((raw_weight2 - fram_data.cal_w2_0) * fram_data.cal_w2_factor));
}

float GetTemp() {
  return sensor.readTemperature();
}

float GetBat() {
  float vb = analogRead(VBATPIN);
  vb *= 2;    // we divided by 2, so multiply back
  vb *= 3.3;  // Multiply by 3.3V, our reference voltage
  return vb;
}

void ShowFRAMData() {
  Serial.println('{');
  Serial.print("  \"nwkskey\": \"");
  print_byte_array(fram_data.nwkskey, 16);
  Serial.println("\", ");
  Serial.print("  \"appskey\": \"");
  print_byte_array(fram_data.appskey, 16);
  Serial.println("\", ");
  Serial.print("  \"devaddr\": \"");
  Serial.print(fram_data.devaddr,HEX);
  Serial.println("\",");
  Serial.print("  \"framecounter\": ");
  Serial.print(fram_data.framecounter);
  Serial.println(",");
  Serial.print("  \"cal_w1_0\": ");
  Serial.print(fram_data.cal_w1_0);
  Serial.println(",");
  Serial.print("  \"cal_w2_0\": ");
  Serial.print(fram_data.cal_w2_0);
  Serial.println(",");
  Serial.print("  \"cal_w1_factor\": ");
  Serial.print(fram_data.cal_w1_factor);
  Serial.println(",");
  Serial.print("  \"cal_w2_factor\": ");
  Serial.print(fram_data.cal_w2_factor);
  Serial.println(",");
  Serial.print("  \"weight\": [");
  for (int i=0; i < MAX_VALUES_TO_SEND; i++) {
    Serial.print(fram_data.weight[i]);
    if (i < (MAX_VALUES_TO_SEND - 1)) {
      Serial.print(",");
    }
  }
  Serial.println("],");
  Serial.print("  \"temperature\": [");
  for (int i=0; i < MAX_VALUES_TO_SEND; i++) {
    Serial.print(fram_data.temperature[i]);
    if (i < (MAX_VALUES_TO_SEND - 1)) {
      Serial.print(",");
    }
  }
  Serial.println("],");
  Serial.print("  \"my_position\": ");
  Serial.print(fram_data.my_position);
  Serial.println("");  
  Serial.println("}");
}

void Setup() {
  bool exitloop;
  Serial.println("{ \"msg\": \"Entering setup mode\" }");
  String s = Serial.readStringUntil('\n');
  s.trim();
  exitloop = (s == "exit");
  while (!exitloop) {

    if (s == "") {
      //Serial.println("Leerzeile wird ignoriert...");
    }
    else if (s.startsWith("setnwkskey")) {
      String key;
      key = s.substring(11);
      if (isValidHexKey(key, 32)) {
        WriteKey(key, NWKSKEY);
        Serial.println("{ \"msg\": \"setnwkskey was successful\" }");
      }
      else {
        Serial.println("{ \"msg\": \"Ist kein gueltiger Hex Key mit 32 Zeichen\" }");
      }
    }
    else if (s.startsWith("setappskey")) {
      String key;
      key = s.substring(11);
      if (isValidHexKey(key, 32)) {
        WriteKey(key, APPSKEY);
        Serial.println("{ \"msg\": \"setappskey was successful\" }");
      }
      else {
        Serial.println("{ \"msg\": \"Ist kein gueltiger Hex Key mit 32 Zeichen\" }");
      }
    }
    else if (s.startsWith("setdevaddr")) {
      String key;
      key = s.substring(11);
      if (isValidHexKey(key, 8)) {
        WriteKey(key, DEVADDR);
        Serial.println("{ \"msg\": \"setdevaddr was successful\" }");
      }
      else {
        Serial.println("{ \"msg\": \"Ist kein gueltiger Hex Key mit 32 Zeichen\" }");
      }
    }
    else if (s == "getvalues") {
      Serial.println('{');
      Serial.print("  \"weight\": ");
      Serial.print(GetWeight());
      Serial.println(", ");
      Serial.print("  \"temperature\": ");
      Serial.print(GetTemp());
      Serial.println(", ");
      Serial.print("  \"batt\": ");
      Serial.println(GetBat());
      Serial.println("}");
    }
    else if (s == "getrawvalues") {
      Serial.println("getrawvalues...");
      long raw_weight1 = scale1.read_average(3);
      long raw_weight2 = scale2.read_average(3);
      Serial.println("getrawvalues after read scales..");
      Serial.println('{');
      Serial.print("  \"w1_raw\": ");
      Serial.print(raw_weight1);
      Serial.println(", ");
      Serial.print("  \"w2_raw\": ");
      Serial.print(raw_weight2);
      Serial.println("");
      Serial.println("}");
    }
    else if (s == "getframdata") {
      ShowFRAMData();
    }
    else if (s == "getframdata") {
      ShowFRAMData();
    }
    else if (s == "sendloradata") {
      send_lora_data = true;
      exitloop = true;
      Serial.println("{ \"msg\": \"sendloradata sent\" }");
    }
    else if (s == "calibrate_zero_1") {
      long raw_weight1 = scale1.read_average(3);
      fram_data.cal_w1_0 = raw_weight1;
      Serial.println("{ \"msg\": \"calibrate_zero_1 was successful\" }");
    }
    else if (s == "calibrate_zero_2") {
      long raw_weight2 = scale2.read_average(3);
      fram_data.cal_w2_0 = raw_weight2;
      Serial.println("{ \"msg\": \"calibrate_zero_2 was successful\" }");
    }
    else if (s.startsWith("calibrate_1")) {
      String w1_gramm;
      w1_gramm = s.substring(12);
      long raw_weight1 = scale1.read_average(3);
      fram_data.cal_w1_factor = (w1_gramm.toFloat() / (float)raw_weight1);
      Serial.println("{ \"msg\": \"calibrate_1 was successful\" }");
    }
    else if (s.startsWith("calibrate_2")) {
      String w2_gramm;
      w2_gramm = s.substring(12);
      long raw_weight2 = scale2.read_average(3);
      fram_data.cal_w2_factor = (w2_gramm.toFloat() / (float)raw_weight2);
      Serial.println("{ \"msg\": \"calibrate_2 was successful\" }");
    }
    else {
      Serial.println("{ \"msg\": \"You sent me an unknown command (exit to quit setup mode)\" }");
    }
    s = Serial.readStringUntil('\n');
    s.trim();
    exitloop == exitloop || (s == "exit");
  }
  Serial.println("We exited the setup loop...");
}

void Save2FRAM()
{
  fram.writeEnable(true);
  fram.write(0x0, (uint8_t *) &fram_data, sizeof(FRAM_data) );
  fram.writeEnable(false);
}

void ShowLoraData()
{
  Serial.println("Lora Packet:");
  Serial.println(lora_data.version);
  Serial.println(lora_data.weight[0]);
  Serial.println(lora_data.weight[1]);
  Serial.println(lora_data.weight[2]);
  Serial.println(lora_data.weight[3]);
  Serial.println(lora_data.weight[4]);
  Serial.println(lora_data.temperature[0]);
  Serial.println(lora_data.temperature[1]);
  Serial.println(lora_data.temperature[2]);
  Serial.println(lora_data.temperature[3]);
  Serial.println(lora_data.temperature[4]);
  Serial.println(lora_data.vbat);
  Serial.print("Size of Lora Package: ");
  Serial.println(sizeof(LORA_data));
}

// Alles wird im Setup erledigt...
void setup(void)
{
  // DONEPIN must be low...
  pinMode(DONEPIN, OUTPUT);
  digitalWrite(DONEPIN, LOW);

  // Reading battery; Value is in Millivolts
  float vbat = GetBat();
  // Wir nehmen an, dass das USB-Kabel gesteckt ist, wenn die Batteriespannung
  // groesser als 4.4V ist (Schalter muss auf 0 sein!
  usb_power_only = (vbat >= 4400);

  if (usb_power_only) {
    // Initialize serial and wait for port to open:
    Serial.begin(115200);
    Serial.setTimeout(6000);
    //while (!Serial);
    print_debug("Serial Port initialized");
  }
  // fuer Debugzwecke
  pinMode(LED_BUILTIN, OUTPUT);
  if (usb_power_only) {
    digitalWrite(LED_BUILTIN, HIGH);
  } else {
    digitalWrite(LED_BUILTIN, LOW);
  }

  // FRAM
  // we set #8 to High (CS of Lora Module), to be able to use FRAM
  pinMode(8, INPUT_PULLUP);
  digitalWrite(8, HIGH);

  if (fram.begin()) {
    print_debug("Found SPI FRAM");
  } else {
    print_debug("No SPI FRAM found ... check your connections\r\n");
    while (1);
  }

  // wir lesen die FRAM-Werte
  fram.read(0x0, (uint8_t*) &fram_data, sizeof(FRAM_data));

  //ShowFRAMData();
  // END FRAM

  // zuerst wird der HX711 initialisiert
  print_debug("Initializing the scale");
  scale1.begin(A3, A2);
  scale2.begin(A1, A0);

  // Jetzt initialisieren wir den Si7021
  if (!sensor.begin()) {
    print_debug("Did not find Si7021 sensor!");
  }

  boolean success;

  fram_data.weight[fram_data.my_position] = GetWeight();
  fram_data.temperature[fram_data.my_position] = (int)GetTemp() * 10;

  // Wenn die Differenz des Gewichts zu gross ist oder alle Messplaetze belegt sind senden wir das Paket...
  if (fram_data.my_position > 0) {
    if ((fram_data.weight[fram_data.my_position] - fram_data.weight[fram_data.my_position - 1]) >= 9999999) {
      Serial.println("CCC");
      Serial.println(fram_data.my_position);
      send_lora_data = true;
    }
  }
  fram_data.my_position++;

  if (fram_data.my_position == MAX_VALUES_TO_SEND) {
    send_lora_data = true;
  }

  Serial.print("send_lora_data:");
  Serial.print(send_lora_data);
  if (send_lora_data) {
    Serial.println("SendLoraPacket");
    lora_data.version = 1;
    for (int i=0; i < MAX_VALUES_TO_SEND; i++) {
      lora_data.weight[i] = fram_data.weight[i];
      lora_data.temperature[i] = fram_data.temperature[i];
    }
    lora_data.vbat = (byte)(vbat / 20);


    // LORA
#ifdef VCC_ENABLE
    // For Pinoccio Scout boards
    pinMode(VCC_ENABLE, OUTPUT);
    digitalWrite(VCC_ENABLE, HIGH);
    delay(1000);
#endif

    // LMIC init
    os_init();
    // Reset the MAC state. Session and pending data transfers will be discarded.
    LMIC_reset();

    // Set static session parameters. Instead of dynamically establishing a session
    // by joining the network, precomputed session parameters are be provided.
    #ifdef PROGMEM
    Serial.println("PROGMEM...");
    // On AVR, these values are stored in flash and only copied to RAM
    // once. Copy them to a temporary buffer here, LMIC_setSession will
    // copy them into a buffer of its own again.
    uint8_t appskey[sizeof(fram_data.appskey)];
    uint8_t nwkskey[sizeof(fram_data.nwkskey)];
    memcpy_P(appskey, fram_data.appskey, sizeof(fram_data.appskey));
    memcpy_P(nwkskey, fram_data.nwkskey, sizeof(fram_data.nwkskey));
    LMIC_setSession (0x1, DEVADDRJOERG, nwkskey, appskey);
    #else
    // If not running an AVR with PROGMEM, just use the arrays directly
    Serial.println("NOT PROGMEM...");
    //LMIC_setSession (0x1, DEVADDRJOERG, NWKSKEYJOERG, APPSKEYJOERG);
    #endif
    LMIC_setSession (0x1, fram_data.devaddr, nwkskey, appskey);

#if defined(CFG_eu868)
    // Set up the channels used by the Things Network, which corresponds
    // to the defaults of most gateways. Without this, only three base
    // channels from the LoRaWAN specification are used, which certainly
    // works, so it is good for debugging, but can overload those
    // frequencies, so be sure to configure the full frequency range of
    // your network here (unless your network autoconfigures them).
    // Setting up channels should happen after LMIC_setSession, as that
    // configures the minimal channel set.
    // NA-US channels 0-71 are configured automatically
    LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
    LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
    LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
    // TTN defines an additional channel at 869.525Mhz using SF9 for class B
    // devices' ping slots. LMIC does not have an easy way to define set this
    // frequency and support for class B is spotty and untested, so this
    // frequency is not configured here.
#elif defined(CFG_us915)
    // NA-US channels 0-71 are configured automatically
    // but only one group of 8 should (a subband) should be active
    // TTN recommends the second sub band, 1 in a zero based count.
    // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
    LMIC_selectSubBand(1);
#endif

    // Disable link check validation
    LMIC_setLinkCheckMode(0);

    // TTN uses SF9 for its RX2 window.
    LMIC.dn2Dr = DR_SF9;

    // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
    LMIC_setDrTxpow(DR_SF7, 14);

    // Start job
    do_send(&sendjob);

    // END LORA

    while (!lora_package_sent || timeout_elapsed) {
        Serial.println("Run os_runloop_once...");
        os_runloop_once();  // EVTL. NOETIG?????
    }

  }
  Serial.println("BLABLA");
  // soll evtl. das Setup durchgefuehrt werden?
  if (usb_power_only && Serial.available()) {
    Serial.println("GGGGBLABLA");
    String s = Serial.readStringUntil('\n');
    if (s == "setup") {
      Serial.println("SETUPGGGGBLABLA");
      Setup();
    } else {
      Serial.println("{ \"msg\": \"Unknown command (only setup is allowed here)\"");
    }
  }

  // dump the entire 8K of memory!
  if (usb_power_only) {
    uint8_t value;
    for (uint16_t a = 0; a < sizeof(FRAM_data); a++) {
      value = fram.read8(a);
      if ((a % 32) == 0) {
        Serial.print("\n 0x"); Serial.print(a, HEX); Serial.print(": ");
      }
      Serial.print("0x");
      if (value < 0x1)
        Serial.print('0');
      Serial.print(value, HEX); Serial.print(" ");
    }
    Serial.print("\nsizeof(FRAM_data): " + String(sizeof(FRAM_data)));
  }

  // Jetzt sichern wir die Werte
  Save2FRAM();

  //ShowFRAMData();

#if DEBUG
  delay(3000);
#endif

    // Jetzt koennen wir die FRAM-Werte wieder initialisieren
    for (int i=0; i < MAX_VALUES_TO_SEND; i++) {
      fram_data.weight[i] = MAX_SHORT;
      fram_data.temperature[i] = MAX_SHORT;
    }
    fram_data.my_position = 0;

  if (not(send_lora_data)) {
    print_debug("Jetzt senden wir das DONE Signal...");
    while (1) {
      digitalWrite(DONEPIN, HIGH);
      delay(5);
      digitalWrite(DONEPIN, LOW);
      delay(5);
    }
  }
}

void loop(void)
{
  // Hier haben wir nichts zu tun, wir machen alles im Setup...
}
