#define MIN(a,b) (a<b)?(a):(b)
#define MAX(a,b) (a>b)?(a):(b)

#define RESPONSE_HEADER_LEN 5 //5 Bytes scheinen konstant zu sein

static byte cmd;

typedef enum RECEIVE_STATE_E {
  STATE_WAIT_FOR_SOF,
  STATE_RECEIVE_SOF,
  STATE_RECEIVE_CMD_DATA,
  STATE_RECEIVE_RESPONSE
  
} RECEIVE_STATE_T;

RECEIVE_STATE_T rec_state = STATE_WAIT_FOR_SOF;

//byte response_buf_cmd1[64];
//byte response_buf_len1 = 0;
byte response_buf_cmd2[64];
byte response_buf_len2 = 0;
byte response_buf_cmd3[64];
byte response_buf_len3 = 0;
byte response_buf_cmd4[64];
byte response_buf_len4 = 0;
byte response_buf_cmd5[64];
byte response_buf_len5 = 0;
byte response_buf_cmd6[64];
byte response_buf_len6 = 0;
unsigned int buf_idx = 0;
unsigned int msg_len = 0;
unsigned int msg_start_idx = 0;
byte response_buf[128];
byte response_len = 0;
byte command_response = 0;
byte db;
byte fe_cnt = 0;
byte cmd_buf[32];
byte cmd_len = 0;
unsigned long last_receive = 0;

typedef struct DATA_3_S
{
  uint8_t header;
  uint16_t volt1;
  uint16_t volt2;
  uint16_t volt3;
  uint16_t volt4;
  uint16_t volt5;
  uint16_t volt6;
  uint16_t volt7;
  uint16_t volt8;
  uint16_t volt9;
  uint16_t volt10;
  uint16_t volt11;
  uint16_t volt12;
  uint16_t volt13;
  uint16_t volt14;
  uint16_t volt15;
  uint16_t volt16;
  uint16_t volt17;
  uint16_t volt18;
  uint16_t volt19;
  uint16_t volt20;
  
} __attribute((packed)) DATA_3_T;

typedef union DATA_3_U
{
  uint8_t raw[CMD_RESP_BUF_LEN];
  DATA_3_T values;
} DATA3;

typedef struct DATA_2_S
{
  uint8_t header;
  uint16_t pack_voltage;
  uint16_t current;
  uint8_t fill1[2]; //0x33 0x33 laut logs bisher
  uint8_t SOC;
  uint8_t fill2; //0x33 laut log
  uint8_t stat;
  uint8_t time_remain;
  uint8_t temp1;
  uint8_t temp2;
  uint8_t temp3;
  uint8_t temp4;
  uint16_t power;
  uint8_t footer;
} __attribute((packed)) DATA_2_T;

typedef union DATA_2_U
{
  uint8_t raw[CMD_RESP_BUF_LEN];
  DATA_2_T values;
} DATA2;

typedef struct DATA_4_S
{
  uint8_t header; //0x10 laut log
  uint8_t serial[16];
  uint8_t fill1;  //0x63 laut logs bisher
  uint8_t footer; //0x16 laut log
} __attribute((packed)) DATA_4_T;

typedef union DATA_4_U
{
  uint8_t raw[CMD_RESP_BUF_LEN];
  DATA_4_T values;
} DATA4;

typedef struct DATA_5_S
{
  uint8_t header; //0x02 laut log
  uint8_t sw_ver;
  uint8_t hw_ver;
  uint8_t fill1;  //0xEA laut logs bisher
  uint8_t footer; //0x16 laut log
} __attribute((packed)) DATA_5_T;

typedef union DATA_5_U
{
  uint8_t raw[CMD_RESP_BUF_LEN];
  DATA_5_T values;
} DATA5;


typedef struct DATA_6_S
{
  uint8_t header; //0x13 laut log
  uint8_t fill1[2];
  uint16_t cycles;
  uint8_t fill2[15];
  uint8_t fill3;  //0x3C laut logs bisher
  uint8_t footer; //0x16 laut log
} __attribute((packed)) DATA_6_T;

typedef union DATA_6_U
{
  uint8_t raw[CMD_RESP_BUF_LEN];
  DATA_6_T values;
} DATA6;


DATA2 data2;
DATA3 data3;
DATA4 data4;
DATA5 data5;
DATA6 data6;

uint16_t byte_swap(uint16_t in)
{
  uint16_t retval;
  uint8_t low, high;

  low = in & 0xFF;
  high = (in >> 8) & 0xFF;
  retval = low << 8 | high;
  return retval;
}

byte decode_cmd()
{
  //0x68 0x31 0xCE 0x68 0x02 0x02 als "Header" nach 0xFE 0xFE 0xFE 0xFE (start of frame)
  if ((cmd_buf[6] == 0x34 ) &&
     (cmd_buf[7] == 0x5F ) &&
     (cmd_buf[8] == 0x66 ))
  {
    return 1;   
  }
  else if ((cmd_buf[6] == 0x60 ) &&
           (cmd_buf[7] == 0x42 ) &&
           (cmd_buf[8] == 0x75 ))
  {
    return 2;   
  }
  else if ((cmd_buf[6] == 0x6F ) &&
           (cmd_buf[7] == 0x5B ) &&
           (cmd_buf[8] == 0x9D ))
  {
    return 3;   
  }
  else if ((cmd_buf[6] == 0x3C ) &&
           (cmd_buf[7] == 0x43 ) &&
           (cmd_buf[8] == 0x52 ))
  {
    return 4;   
  }
  else if ((cmd_buf[6] == 0x35 ) &&
           (cmd_buf[7] == 0x35 ) &&
           (cmd_buf[8] == 0x3D ))
  {
    return 5;   
  }
  else if ((cmd_buf[6] == 0x5C ) &&
           (cmd_buf[7] == 0x46 ) &&
           (cmd_buf[8] == 0x75 ))
  {
    return 6;   
  }
  
  else
  {
    return 0;    
  }
  
}

void print_cmd(void)
{
  unsigned int i=0;
  byte cmd;
#if CMD_DATA_DEBUG

  Serial.print(", CMD:");
  Serial.print(" len=");
  Serial.print(cmd_len);
  Serial.print(", data=");
  
  for (i=0; i<cmd_len;i++)
  {
    Serial.print(" 0x");
    if (cmd_buf[i]<0x10) {Serial.print("0");}
    Serial.print(cmd_buf[i], HEX);
  }
  Serial.print(" ==> ");
#endif

  cmd = decode_cmd();
  switch (cmd)
  {
    case 0:
#if CMD_DATA_DEBUG
        Serial.print("????");
#endif
        command_response = 0;
    break;
    
    case 1:
#if CMD_DATA_DEBUG
        Serial.print("CMD1");
#endif
        command_response = 1;
    break;
    
    case 2:
#if CMD_DATA_DEBUG
        Serial.print("CMD2");
#endif        
        command_response = 2;
    break;
    
    case 3:
#if CMD_DATA_DEBUG
        Serial.print("CMD3");
#endif        
        command_response = 3;
    break;

    case 4:
#if CMD_DATA_DEBUG
        Serial.print("CMD4");
#endif        
        command_response = 4;
    break;

    case 5:
#if CMD_DATA_DEBUG
        Serial.print("CMD5");
#endif        
        command_response = 5;
    break;

    case 6:
#if CMD_DATA_DEBUG
        Serial.print("CMD6");
#endif        
        command_response = 6;
    break;


    
  }
}

void scale_values2(void)
{
  memcpy(data2.raw, response_buf_cmd2, response_buf_len2); //copy data to data structure
  //scale values
  
  scaled_values.pack_voltage = ((float) (byte_swap(data2.values.pack_voltage) - 0x3333))/10.0f;
  scaled_values.current = ((float) (byte_swap(data2.values.current) - 0x3333))/10.0f;
  scaled_values.SOC = (float)(data2.values.SOC - 0x33);
  //TODO scaled_values.stat;
  scaled_values.time_remain = (float)(data2.values.temp1 - 0x33) / 10.0f;  //in hours
  scaled_values.temp1 = (float)(data2.values.temp1 - 0x33);
  scaled_values.temp2 = (float)(data2.values.temp2 - 0x33);
  scaled_values.temp3 = (float)(data2.values.temp3 - 0x33);
  scaled_values.temp4 = (float)(data2.values.temp4 - 0x33);
  //TODO scaled_values.power;
  
}

void scale_values3(void)
{
  
  memcpy(data3.raw, response_buf_cmd3, response_buf_len3); //copy data to data structure

  //scale values
  //TODO: plausi-Check
  scaled_values.volt1 = ((float) (byte_swap(data3.values.volt1) - 0x3333))/1000.0f;
  scaled_values.volt2 = ((float) (byte_swap(data3.values.volt2) - 0x3333))/1000.0f;
  scaled_values.volt3 = ((float) (byte_swap(data3.values.volt3) - 0x3333))/1000.0f;
  scaled_values.volt4 = ((float) (byte_swap(data3.values.volt4) - 0x3333))/1000.0f;
  scaled_values.volt5 = ((float) (byte_swap(data3.values.volt5) - 0x3333))/1000.0f;
  scaled_values.volt6 = ((float) (byte_swap(data3.values.volt6) - 0x3333))/1000.0f;
  scaled_values.volt7 = ((float) (byte_swap(data3.values.volt7) - 0x3333))/1000.0f;
  scaled_values.volt8 = ((float) (byte_swap(data3.values.volt8) - 0x3333))/1000.0f;
  scaled_values.volt9 = ((float) (byte_swap(data3.values.volt9) - 0x3333))/1000.0f;
  scaled_values.volt10 = ((float) (byte_swap(data3.values.volt10) - 0x3333))/1000.0f;
  scaled_values.volt11 = ((float) (byte_swap(data3.values.volt11) - 0x3333))/1000.0f;
  scaled_values.volt12 = ((float) (byte_swap(data3.values.volt12) - 0x3333))/1000.0f;
  scaled_values.volt13 = ((float) (byte_swap(data3.values.volt13) - 0x3333))/1000.0f;
  scaled_values.volt14 = ((float) (byte_swap(data3.values.volt14) - 0x3333))/1000.0f;
  scaled_values.volt15 = ((float) (byte_swap(data3.values.volt15) - 0x3333))/1000.0f;
  scaled_values.volt16 = ((float) (byte_swap(data3.values.volt16) - 0x3333))/1000.0f;
  scaled_values.volt17 = ((float) (byte_swap(data3.values.volt17) - 0x3333))/1000.0f;
  scaled_values.volt18 = ((float) (byte_swap(data3.values.volt18) - 0x3333))/1000.0f;
  scaled_values.volt19 = ((float) (byte_swap(data3.values.volt19) - 0x3333))/1000.0f;
  scaled_values.volt20 = ((float) (byte_swap(data3.values.volt20) - 0x3333))/1000.0f;
}

void scale_values6(void)
{
  memcpy(data6.raw, response_buf_cmd6, response_buf_len6);
  scaled_values.cycles = byte_swap(data6.values.cycles) - 0x3333;
}

bool decode_response(byte command_response, byte response_len)
{
  //bool finished = false;
  unsigned int i=0;

  if (command_response == 1)
  {
    //response to command 1 not used -> ignore (response to command 3 carries the same values)
#if 0
    for (i = RESPONSE_HEADER_LEN; i<response_len; i++)
    {
      response_buf_cmd1[i-RESPONSE_HEADER_LEN] = response_buf[i];
    }
    response_buf_len1 = response_len - RESPONSE_HEADER_LEN;
#endif    
  }
  else if (command_response == 2)
  {
    if (response_len == 23)
    {
      for (i = RESPONSE_HEADER_LEN; i<response_len; i++)
      {
        response_buf_cmd2[i-RESPONSE_HEADER_LEN] = response_buf[i];
      }
      response_buf_len2 = response_len - RESPONSE_HEADER_LEN;
      scale_values2();
      return true;
    }
  }
  else if (command_response == 3)
  {
    if (response_len == 48)
    {
      for (i = RESPONSE_HEADER_LEN; i<response_len; i++)
      {
        response_buf_cmd3[i-RESPONSE_HEADER_LEN] = response_buf[i];
      }
      response_buf_len3 = response_len - RESPONSE_HEADER_LEN;
      scale_values3();
      return true;
    }
  }
  else if (command_response == 4)
  {
    //Serial.println("RESP4");
    for (i = RESPONSE_HEADER_LEN; i<response_len; i++)
    {
      response_buf_cmd4[i-RESPONSE_HEADER_LEN] = response_buf[i];
    }
    response_buf_len4 = response_len - RESPONSE_HEADER_LEN;
    return true;
  }
  else if (command_response == 5)
  {
    //Serial.println("RESP5");
    for (i = RESPONSE_HEADER_LEN; i<response_len; i++)
    {
      response_buf_cmd5[i-RESPONSE_HEADER_LEN] = response_buf[i];
    }
    response_buf_len5 = response_len - RESPONSE_HEADER_LEN;
    return true;
  }
  else if (command_response == 6)
  {
    //Serial.println("RESP6");
    for (i = RESPONSE_HEADER_LEN; i<response_len; i++)
    {
      response_buf_cmd6[i-RESPONSE_HEADER_LEN] = response_buf[i];
    }
    response_buf_len6 = response_len - RESPONSE_HEADER_LEN;
    scale_values6();
    return true;
  }
  
#if 0
  if (6 == cmd_nr)
  {
    Serial.print("RESP");
    Serial.print(cmd_nr);
    Serial.print(":");
    Serial.print(" len=");
    Serial.print(response_len);
    Serial.print(", data=");
    
    if (response_len == 0)
    {
      Serial.print(" no data");
    }
    else
    {
      for (i=RESPONSE_HEADER_LEN; i<response_len;i++)
      {
        Serial.print(" 0x");
        if (response_buf[i]<0x10) {Serial.print("0");}
        Serial.print(response_buf[i], HEX);
        //Serial.print(char(response_buf[i]));
      }
    }
    //Serial.println();
  }
#endif    

  //return finished; 
}

void print_dataset1(void)
{
  unsigned int i, val;
  float fval;



#if 0  
  //Serial.print(response_buf_len1);
  Serial.print("             DATA1: ");
  for (i=0; i<response_buf_len1;i++)
  {
    Serial.print(" 0x");
    if (response_buf_cmd1[i]<0x10) {Serial.print("0");}
    Serial.print(response_buf_cmd1[i], HEX);
  }
  Serial.println();
#endif 

  
#if 0
 
  Serial.print("cell1: ");
  Serial.print(byte_swap(data1.values.volt1), DEC);  
  Serial.print(" raw, ");

  Serial.print("cell2: ");
  Serial.print(byte_swap(data1.values.volt2), DEC);  
  Serial.print(" raw, ");

  Serial.print("cell3: ");
  Serial.print(byte_swap(data1.values.volt3), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell4: ");
  Serial.print(byte_swap(data1.values.volt4), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell5: ");
  Serial.print(byte_swap(data1.values.volt5), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell6: ");
  Serial.print(byte_swap(data1.values.volt6), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell7: ");
  Serial.print(byte_swap(data1.values.volt7), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell8: ");
  Serial.print(byte_swap(data1.values.volt8), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell9: ");
  Serial.print(byte_swap(data1.values.volt9), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell10: ");
  Serial.print(byte_swap(data1.values.volt10), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell11: ");
  Serial.print(byte_swap(data1.values.volt11), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell12: ");
  Serial.print(byte_swap(data1.values.volt12), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell13: ");
  Serial.print(byte_swap(data1.values.volt13), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell14: ");
  Serial.print(byte_swap(data1.values.volt14), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell15: ");
  Serial.print(byte_swap(data1.values.volt15), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell16: ");
  Serial.print(byte_swap(data1.values.volt16), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("cell17: ");
  Serial.print(byte_swap(data1.values.volt17), DEC);  
  Serial.print(" raw, ");
#endif 
  
#if 0
  for (i=35; i<response_buf_len1;i++)
  {
    Serial.print(" 0x");
    if (response_buf_cmd1[i]<0x10) {Serial.print("0");}
    Serial.print(response_buf_cmd1[i], HEX);
  }

#endif  
}


void print_dataset(void)
{
  unsigned int i;
  float hours, current;

  memcpy(data2.raw, response_buf_cmd2, response_buf_len2);
  memcpy(data3.raw, response_buf_cmd3, response_buf_len3);
  memcpy(data4.raw, response_buf_cmd4, response_buf_len4);
  memcpy(data5.raw, response_buf_cmd5, response_buf_len5);
  memcpy(data6.raw, response_buf_cmd6, response_buf_len6);

  print_dataset1();
//fuer Stephan
  Serial.print(", current: ");
  current = (data2.values.current - 0x3333) / 10.0f;
  Serial.print(current, 1);  
  Serial.print("A, ");

  Serial.print("time remain: ");
  hours = (((float)(data2.values.time_remain - 0x33) / 10.0f ));// durch 10 mal 60
  Serial.print(hours, 1);  
  Serial.print(" h, ");
  
  Serial.print("power: ");
  Serial.print(byte_swap(data2.values.power), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("status: ");
  Serial.println(data2.values.stat - 0x33, DEC);  
  
#if 0  
  Serial.print(" - DATA2: ");
  for (i=0; i<response_buf_len2;i++)
  {
    Serial.print(" 0x");
    if (response_buf_cmd2[i]<0x10) {Serial.print("0");}
    Serial.print(response_buf_cmd2[i], HEX);
  }
  Serial.println();
#endif  
#if 0
  Serial.print("pack volt.: ");
  
  Serial.print(byte_swap(data2.values.pack_voltage), DEC);  
  Serial.print(" raw, ");


  Serial.print("current: ");
  current = (data2.values.current_low - 0x33) / 10.0f;
  Serial.print(current, 1);  
  Serial.print("A, ");


  Serial.print("SOC: ");
  Serial.print(data2.values.SOC - 0x33, DEC);  
  Serial.print("%, ");

  Serial.print("Temp1: ");
  Serial.print(data2.values.temp1 - 0x33, DEC);  
  Serial.print("°C, ");
  
  Serial.print("Temp2: ");
  Serial.print(data2.values.temp2 - 0x33, DEC);  
  Serial.print("°C, ");
  
  Serial.print("Temp3: ");
  Serial.print(data2.values.temp3 - 0x33, DEC);  
  Serial.print("°C, ");
  
  Serial.print("Temp4: ");
  Serial.print(data2.values.temp4 - 0x33, DEC);  
  Serial.print("°C, ");
  
  Serial.print("time remain: ");
  hours = (((float)(data2.values.time_remain - 0x33) / 10.0f ));// durch 10 mal 60
  Serial.print(hours, 1);  
  Serial.print(" h, ");
  
  Serial.print("power: ");
  Serial.print(byte_swap(data2.values.power), DEC);  
  Serial.print(" raw, ");
  
  Serial.print("status: ");
  Serial.print(data2.values.stat - 0x33, DEC);  
  //Serial.print(" raw, ");
#endif   
#if 0  
  Serial.print(" - DATA3: ");
  for (i=0; i<response_buf_len3;i++)
  {
    Serial.print(" 0x");
    if (response_buf_cmd3[i]<0x10) {Serial.print("0");}
    Serial.print(response_buf_cmd3[i], HEX);
  }
  Serial.println();
#endif  

  oled_show();
}

float u_min(void)
{
  float retval;

  retval = scaled_values.volt1;
  if (scaled_values.volt2 < retval) retval = scaled_values.volt2;
  if (scaled_values.volt3 < retval) retval = scaled_values.volt3;
  if (scaled_values.volt4 < retval) retval = scaled_values.volt4;
  if (scaled_values.volt5 < retval) retval = scaled_values.volt5;
  if (scaled_values.volt6 < retval) retval = scaled_values.volt6;
  if (scaled_values.volt7 < retval) retval = scaled_values.volt7;
  if (scaled_values.volt8 < retval) retval = scaled_values.volt8;
  if (scaled_values.volt9 < retval) retval = scaled_values.volt9;
  if (scaled_values.volt10 < retval) retval = scaled_values.volt10;
  if (scaled_values.volt11 < retval) retval = scaled_values.volt11;
  if (scaled_values.volt12 < retval) retval = scaled_values.volt12;
  if (scaled_values.volt13 < retval) retval = scaled_values.volt13;
  if (scaled_values.volt14 < retval) retval = scaled_values.volt14;
  if (scaled_values.volt15 < retval) retval = scaled_values.volt15;
  if (scaled_values.volt16 < retval) retval = scaled_values.volt16;
  if (scaled_values.volt17 < retval) retval = scaled_values.volt17;
  
  return (retval);  
 
}

float u_max(void)
{
  float retval;

  retval = scaled_values.volt1;
  if (scaled_values.volt2 > retval) retval = scaled_values.volt2;
  if (scaled_values.volt3 > retval) retval = scaled_values.volt3;
  if (scaled_values.volt4 > retval) retval = scaled_values.volt4;
  if (scaled_values.volt5 > retval) retval = scaled_values.volt5;
  if (scaled_values.volt6 > retval) retval = scaled_values.volt6;
  if (scaled_values.volt7 > retval) retval = scaled_values.volt7;
  if (scaled_values.volt8 > retval) retval = scaled_values.volt8;
  if (scaled_values.volt9 > retval) retval = scaled_values.volt9;
  if (scaled_values.volt10 > retval) retval = scaled_values.volt10;
  if (scaled_values.volt11 > retval) retval = scaled_values.volt11;
  if (scaled_values.volt12 > retval) retval = scaled_values.volt12;
  if (scaled_values.volt13 > retval) retval = scaled_values.volt13;
  if (scaled_values.volt14 > retval) retval = scaled_values.volt14;
  if (scaled_values.volt15 > retval) retval = scaled_values.volt15;
  if (scaled_values.volt16 > retval) retval = scaled_values.volt16;
  if (scaled_values.volt17 > retval) retval = scaled_values.volt17;
  
  return (retval);  
  
}

void oled_show()
{
  static uint8_t cnt = 0;
  float fval;
  uint8_t ver = 0, rel = 0;
  char serial[17];
  uint8_t i;
  // clear the display
  Heltec.display->clear();

  cnt++;

  if (cnt < 5)
  {
    //Page 1
    Heltec.display->setFont(ArialMT_Plain_16);
    Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
    
    Heltec.display->drawString(30, 0, "SOC:" + String((uint8_t)scaled_values.SOC) + "%");
    
    Heltec.display->setFont(ArialMT_Plain_10);
    Heltec.display->drawString(0, 20, "T1:" + String(scaled_values.temp1) + "°");
    Heltec.display->drawString(0, 30, "T2:" + String(scaled_values.temp2) + "°");
    Heltec.display->drawString(0, 40, "T3:" + String(scaled_values.temp3) + "°");
    Heltec.display->drawString(0, 50, "T4:" + String(scaled_values.temp4) + "°");

    fval = u_min();
    Heltec.display->drawString(64, 20, "min:" + String(fval));
    
    fval = u_max();
    Heltec.display->drawString(64, 30, "max:" + String(fval));

    fval = u_max() - u_min();
    Heltec.display->drawString(64, 40, "delta:" + String(fval));
    
  }
  else if (cnt < 10)
  {
    //Page 2
    Heltec.display->setFont(ArialMT_Plain_10);
    Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
    //Spalte 1
    fval = scaled_values.volt1;
    Heltec.display->drawString(0, 0, " 1:" + String(fval));
  
    fval = scaled_values.volt2;
    Heltec.display->drawString(0, 10, " 2:" + String(fval));
  
    fval = scaled_values.volt3;
    Heltec.display->drawString(0, 20, " 3:" + String(fval));
  
    fval = scaled_values.volt4;
    Heltec.display->drawString(0, 30, " 4:" + String(fval));
  
    fval = scaled_values.volt5;
    Heltec.display->drawString(0, 40, " 5:" + String(fval));
  
    fval = scaled_values.volt6;
    Heltec.display->drawString(0, 50, " 6:" + String(fval));
  
    
    //Spalte 2
    fval = scaled_values.volt7;
    Heltec.display->drawString(40, 0, " 7:" + String(fval));
  
    fval = scaled_values.volt8;
    Heltec.display->drawString(40, 10, " 8:" + String(fval));
  
    fval = scaled_values.volt9;
    Heltec.display->drawString(40, 20, " 9:" + String(fval));
  
    fval = scaled_values.volt10;
    Heltec.display->drawString(40, 30, "10:" + String(fval));
    
    fval = scaled_values.volt11;
    Heltec.display->drawString(40, 40, "11:" + String(fval));
    
    fval = scaled_values.volt12;
    Heltec.display->drawString(40, 50, "12:" + String(fval));
    
  
    //Spalte 3
    fval = scaled_values.volt13;
    Heltec.display->drawString(80, 0, "13:" + String(fval));
  
    fval = scaled_values.volt14;
    Heltec.display->drawString(80, 10, "14:" + String(fval));
  
    fval = scaled_values.volt15;
    Heltec.display->drawString(80, 20, "15:" + String(fval));
  
    fval = scaled_values.volt16;
    Heltec.display->drawString(80, 30, "16:" + String(fval));
    
    fval = scaled_values.volt17;
    Heltec.display->drawString(80, 40, "17:" + String(fval));
    
    fval = scaled_values.pack_voltage;
    Heltec.display->drawString(80, 50, "all:" + String(fval));

  }
  else
  {
    //Page 3
    Heltec.display->setFont(ArialMT_Plain_10);
    Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);

    if (data5.values.sw_ver > 0)
    {
      ver = (data5.values.sw_ver - 0x33) / 16;
      rel = (data5.values.sw_ver - 0x33) % 16;
    }
    else
    {
      ver = 0;
      rel = 0;
    }
    
    Heltec.display->drawString(0, 0, "SW:" + String(ver) + "." + String(rel));

    if (data5.values.hw_ver > 0)
    {
      ver = (data5.values.hw_ver - 0x33) / 16;
      rel = (data5.values.hw_ver - 0x33) % 16;
    }
    else
    {
      ver = 0;
      rel = 0;
    }
    
    Heltec.display->drawString(40, 0, "HW:" + String(ver) + "." + String(rel));


    //Serial.print("Serial: ");
    for (i = 0; i < 16; i++)
    {
      serial[i] = data4.values.serial[i] - 0x33;
      //Serial.print(serial[i]);
    }
    //Serial.println();
    serial[16] = 0; //terminate string

    Heltec.display->drawString(0, 16, "Serial: " + String(serial));

    Heltec.display->drawString(0, 32, "cycles: " + String(scaled_values.cycles));
    
    if (cnt == 15)
    {
      cnt = 0;
    }
  }
  
  // write the buffer to the display
  Heltec.display->display();
}

//true = fertig
bool receive_main(uint8_t cmd_nr)
{
  static unsigned long now = 0;
  bool retval = false;
  bool valid = false;

  if (cmd_nr > 0)
  {
    rec_state = STATE_RECEIVE_RESPONSE;
  }

  switch (rec_state)
  {
    case STATE_WAIT_FOR_SOF:
      if (Serial2.available())
      {
        rec_state = STATE_RECEIVE_SOF;
      }
    break;
    
    case STATE_RECEIVE_SOF:
      if (Serial2.available())
      {
        db = Serial2.read();
        TOGGLE_LED;
        if ( 0xFE == db)
        {
          fe_cnt++;
          if (fe_cnt == 4)
          {
            //Serial.print("REC_SOF, ");
            fe_cnt = 0;
            rec_state = STATE_RECEIVE_CMD_DATA;
            last_receive = millis();
          }
        }
        else
        {
          //byte gehört nicht zur SOF Sequenz
        }
      }
    break;

    case STATE_RECEIVE_CMD_DATA:
      if (Serial2.available())
      {
        Serial.print(".");
        cmd_buf[cmd_len] = Serial2.read();
        TOGGLE_LED;
        cmd_len++;
        last_receive = millis();
      }
      else
      {
        now = millis();
        if ((now - last_receive) > CMD_RESPONSE_DELTA)  
        {
          //Kommando scheint abgeschlossen, was jetzt kommt, ist (wohl) die Antwort ;-)
          cmd = decode_cmd();
          
          cmd_len = 0;
          rec_state = STATE_RECEIVE_RESPONSE;
        }
        else
        {
          //noch nicht wechseln, da können noch Daten kommen, die zum Kommando gehören
        }
      }
    
    break;
    
    case STATE_RECEIVE_RESPONSE:
      if (Serial2.available())
      {
        //Serial.print("D");
        response_buf[response_len] = Serial2.read();
        TOGGLE_LED;
        response_len++;
        last_receive = millis();
      }
      else
      {
        now = millis();
        if ((now - last_receive) > RESONSE_NEXT_CMD_DELTA)  
        {
          //Kommando scheint abgeschlossen, was jetzt kommt, ist (wohl) die Antwort ;-)
          if (response_len > 0)
          {
            valid = decode_response(cmd_nr, response_len);
          }  
          response_len = 0; //reset for next response
          
          retval = true;  //end of response
          
          //if (3 == command_response)
          //{
            print_dataset();
          //}
          //reset buffer
          memset(response_buf, 0, sizeof(response_buf));
          rec_state = STATE_WAIT_FOR_SOF;
          
        }
        else
        {
          //noch nicht wechseln, da können noch Daten kommen, die zur Antwort gehören
        }
      }
    
    break;
    
  }
  
  return retval;  
}
