Due freezes during setup()

HI

My arduino due freezes during setup(). I changed arduino due with a new one since the old one stopped working completly. Changed with an original due from italy.
Im working with 1.8.10 and i tried 1.8.16 but the behavior is the same.
Interesting is that on my final and running system its working but on my prototyp system not. They are an exact copy of each other. So now im afraid if i try it on the running system I would break it too. So I have to find the issue on the prototype system first. Then I dare to make updates on the running system.

I kicked all Serial.print out with the exception of the ones in the setup for bug fixing.

Its round about 2600 lines of code so I didn't upload all of it. Hope this proceeding is okey for you.

Do you know this behavior?

Could you please give me some tips to fix it?

Please give me suggestions, i'll try every thing at this point.

Random input is accepted.

Sketch uses 89268 bytes (17%) of program storage space. Maximum is 524288 bytes.

void setup() {

  delay(3000); 
  pinMode(BUTTON1, INPUT_PULLUP);  //uppper left
  pinMode(BUTTON2, INPUT_PULLUP);  //in the middle left
  pinMode(BUTTON3, INPUT_PULLUP);  //lower left
  pinMode(BUTTON4, INPUT_PULLUP);  //upper right
  pinMode(BUTTON5, INPUT_PULLUP);  //in the middle right
  pinMode(BUTTON6, INPUT_PULLUP);  //lower right
  Serial.begin(115200);     //Serial Monitor
  SerialUSB.begin(115200);  //done 20210120 scanner doesnt work power?
  Serial.println("hello1");
  pinMode(4, OUTPUT);   //At Pin 4 is the SD-Card
  digitalWrite(4, HIGH); //At Pin 4 is the SD-Card
  SD.begin(4);               //At Pin 4 is the SD-Card 
  Serial.println("hello2");
  rtc.begin();          //Real time clock
  Serial.println("hello3");
  udt.begin(0);         //TRAMP 1
  Serial.println("hello4");
  udt2.begin(1);        //TRAMP 2 not needed
  Serial.println("hello5");
  Wire1.begin();        //All I2C communication
  Serial.println(F("hello6"));
  dl.init();            //Daylight source
  Serial.println(F("hello7"));
  dl.setDl_off();

Output serial monitor:
10:44:10.313 -> hello1
10:44:12.325 -> hello2
10:44:12.325 -> hello3
10:44:13.730 -> hello4
10:44:15.227 -> hel

Please ... POST ALL THE CODE.

as wished
due.zip (23.3 KB)

Not as wished. Who wants to open a potentially dangerous zip file? How many phones and tablets can open a zip file? Post your code between code tags as you did before please. And thanks for using code tags in your first post.

#include "main.h"

SD_Card sdc;     //SD-Card
RTC_PCF8523 rtc; //real time clock (timer.h timer.cpp)
TheMatrix display; //The matrix orbital display
Light_Source dl;
UDT_TRAMP udt;  //ADS1015_ADDRESS (0x48)
UDT_TRAMP udt2{ADS1015_ADDRESS2}; //Member initializer 
USBHost usb;
KeyboardController keyboard(usb);
 
EthernetClient EtherClient;
EthernetClient PASVClient;
IPAddress ServerByAddress(0, 0, 0, 0);


void setup() {

  delay(3000); 
  pinMode(BUTTON1, INPUT_PULLUP);  //uppper left
  pinMode(BUTTON2, INPUT_PULLUP);  //in the middle left
  pinMode(BUTTON3, INPUT_PULLUP);  //lower left
  pinMode(BUTTON4, INPUT_PULLUP);  //upper right
  pinMode(BUTTON5, INPUT_PULLUP);  //in the middle right
  pinMode(BUTTON6, INPUT_PULLUP);  //lower right
  Serial.begin(115200);     //Serial Monitor
  SerialUSB.begin(115200);  //done 20210120 scanner doesnt work power?
  Serial.println("hello1");
  pinMode(4, OUTPUT);   //At Pin 4 is the SD-Card
  digitalWrite(4, HIGH); //At Pin 4 is the SD-Card
  SD.begin(4);               //At Pin 4 is the SD-Card 
  Serial.println("hello2");
  rtc.begin();          //Real time clock
  Serial.println("hello3");
  udt.begin(0);         //TRAMP 1
  Serial.println("hello4");
  udt2.begin(1);        //TRAMP 2 not needed
  Serial.println("hello5");
  Wire1.begin();        //All I2C communication
  Serial.println(F("hello6"));
  dl.init();            //Daylight source
  Serial.println(F("hello7"));
  dl.setDl_off();

  sdc.loadCalibratFile();
  Serial.println(F("hello8"));

  DateTime now = rtc.now();

  display.runScriptFile(F("TPSPORTS\\Screen2\\Screen2.bin"));
  g_warmUpTimer.resetTimer();
  g_state=WARM_UP_TIMER;

  display.updateLabel(10,F("Bitte warten")); 
  display.updateLabel(11, F("Konfiguriere Ethernet, 1Min."));
  if (Ethernet.begin(mac) == 0) { //Tries to make connection to network(initialisation), this takes a while and even longer if no cable to the ethernet is conneted.
    display.updateLabel(11, F("Kein Ethernet"));
    g_flag_ethernet=false;
  }   

  
}



/*
 * Reads the buttons and debouncing
 */
void checkButtonActivity()
{

  g_buttonPressed = display.getID();  //For buttons higher than 6, which are on the touchpanel
  
  if (!digitalRead(BUTTON1))//if pulled down, active
  {
    while (!digitalRead(BUTTON1)) // wait as long as pulled down
      delay(100);      
    g_buttonPressed = 1;          //set global variable to button for analysis
  } // endif BUTTON1

  if (!digitalRead(BUTTON2))
  {
    while (!digitalRead(BUTTON2))
      delay(100);
    g_buttonPressed = 2;
  } // endif BUTTON2

  if (!digitalRead(BUTTON3))
  {
    while (!digitalRead(BUTTON3))
      delay(100);
    g_buttonPressed = 3;
  } // endif BUTTON3

  if (!digitalRead(BUTTON4))
  {
    while (!digitalRead(BUTTON4))
      delay(100);
    g_buttonPressed = 4;
  } // endif BUTTON4

  if (!digitalRead(BUTTON5))
  {
    while (!digitalRead(BUTTON5))
      delay(100);
    g_buttonPressed = 5;
  } // endif BUTTON5

  if (!digitalRead(BUTTON6))
  {
    while (!digitalRead(BUTTON6))
      delay(100);
      //the fallowing code is needed that the worker do not press fast several times and the screen skips to fast forward automaticly.
    g_currentMillis_locked_repress=millis();//Store time since begin of system in variable
    if(g_currentMillis_locked_repress - g_startMillis_locked_repress >= g_period_locked_repress) {
        //Should the difference be bigger than a set constant. So is the press of the button valid all other are invalid because to fast repressed.
      g_startMillis_locked_repress=g_currentMillis_locked_repress; //Store last time of valid pressing
      g_buttonPressed = 6;
    }
    
  } // endif BUTTON6
} // end checkButtonActivity()


/*
 * Ethernet Recieve, looks for answer from FTP server
 */
byte eRcv()
{
  byte respCode;
  byte thisByte;
  char outCount; //was global in example

  while (!EtherClient.available()) delay(1);

  respCode = EtherClient.peek();

  outCount = 0;

  while (EtherClient.available())
  {
    thisByte = EtherClient.read();
    Serial.write(thisByte);

    if (outCount < 127)
    {
      g_outBuf[outCount] = thisByte;
      outCount++;
      g_outBuf[outCount] = 0;
    }
  }

  if (respCode >= '4')
  {
    //efail();
    return 0;
  }

  return 1;
}



/*
 * Upload data files to FTP server
 */
byte uploadDataToFTP(){
static bool once=false;
uint16_t sum;
String str;
File root;
File myFile;
File dir;
String temp;
DNSClient dns;

if(once==false){ // Only count once, all files in folder ftp
  display.updateLabel(10,F("Zaehle Dateien fuer Upload")); 
  delay(1000);
  sum= sdc.count("/ftp");  
  display.updateLabel(10,F("Anz. Dateien fuer Upload bereit")); 
  display.updateLabel(11,sum); //clear text box
  delay(1000);
  once =true;
}

if(g_flag_ethernet){//is set on start up when connection with ethernet is possible
dir = SD.open("/ftp");
display.updateLabel(10,F("uploading")); 
while(dir.openNextFile()==true){
  dns.begin(Ethernet.dnsServerIP()); //Domain Name System
  dns.getHostByName(dns_name_of_server,ServerByAddress); //solves hoste name to a IP-address 
  EtherClient.connect(ServerByAddress,21); //connects to ftp-server
  if(EtherClient.connected()){ 
    if (!eRcv()) return 0;
    EtherClient.println(ftp_user);//writes login user 
    if (!eRcv()) return 0;
    EtherClient.println(ftp_pw);//writes login password 
    if (!eRcv()) return 0;  
    EtherClient.println(F("SYST"));//sending FTP-COMMAND
    if (!eRcv()) return 0;
    EtherClient.println(F("Type I"));//sending FTP-COMMAND
    if (!eRcv()) return 0;
    EtherClient.println(F("PASV"));//sending FTP-COMMAND, changing to Passive-Upload 
    if (!eRcv())return 0  ;// 
    char *tStr = strtok(g_outBuf, "(,");//handling passive mode answer with the ports
    int array_pasv[6];
    for ( int i = 0; i < 6; i++) { //reading up to 6 answers
      tStr = strtok(NULL, "(,");
      array_pasv[i] = atoi(tStr);
      if (tStr == NULL)
      {;
      }
    }   
    unsigned int hiPort, loPort;
    hiPort = array_pasv[4] << 8; //shifting answer, editing
    loPort = array_pasv[5] & 255; //masking answer, editing
    hiPort = hiPort | loPort; //making 2 to 1 
    PASVClient.connect(ServerByAddress, hiPort);//connecting another client to passive port
    dir = SD.open("/ftp");// opens folder FTP
    File entry =  dir.openNextFile();//opens a file
    temp = "/ftp/" + (String)entry.name(); //completes folder with file 
    myFile=SD.open(temp);//really opens the file in certain location
  
    while(myFile.available()){//as long as there is chars from file print it to passive port ftp-server
      PASVClient.print(char(myFile.read()));
    }
    myFile.close();// close file
    SD.remove(temp); // delete file
    display.updateLabel(11,--sum); 
    EtherClient.print(F("STOR "));//command ftp-server storing  
    EtherClient.println(entry.name()); //give the name of the file to ftp-server
    PASVClient.stop();//stopping passive connection
    EtherClient.println(F("QUIT"));//command ftp-server to leave
    EtherClient.stop(); //stopping ethernet connection
    }else{
      ;//not connected
      return 0;        
    }
  }
  display.updateLabel(10,F(" "));
  display.updateLabel(11,F(" "));
  g_flag_ethernet=false; //stop uploading from reentering the code above.
}
}

/*
 * State warm up timer 10mins after start to get the bulbs stable
 */
void warmUpTimer()
{
  if(g_warmUpTimer.getRemainingMinutes() >= 0){// as long as timer not zero look only for button 5 for special menu
    switch (g_buttonPressed)
    {
    case 5:  //If pressed go in special mode / code pad
      display.runScriptFile(F("TPSPORTS\\Screen3\\Screen3.bin"));  //load screen
      g_state = CODE_PAD ;   //FSM (finite state machine)
    break;
      default:
      break;
    } 
    display.updateLabel(14, (g_warmUpTimer.getRemainingMinutes()+1));// show minutes remaining
    uploadDataToFTP();   
  }else{ //Timer has run out so scan for 2 buttons
    switch (g_buttonPressed)
    {
    case 5:  //Button code pad
      display.runScriptFile(F("TPSPORTS\\Screen3\\Screen3.bin"));  //load screen
      g_state = CODE_PAD ;   //FSM
    break;  
    case 6:  //Button Forward
      display.runScriptFile(F("TPSPORTS\\Screen7\\Screen7.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_OPTRAY;   //FSM
      break;
    default:
      break;
    } // endswitch 
  }
  
} // 

/*
 * clears code in code_pad mode
 */
void clearCode()
{
 for(int i =0;i<4;i++){
      g_input_code[i] = 0;
    }
    g_printable_chars=0;
    g_input_index=0; 
} //end clearCod

/*
 * reads and controls the characters of code_pad
 */
void updateIndices() 
{
  ++g_input_index;  //counter for position of input code
  if (g_input_index >= 4)
    g_input_index = 0;

  ++g_printable_chars;  //counter for length of input code
  if (g_printable_chars > 4)
    g_printable_chars = 4; 
} // end updateIndices()


/*
 * Actual code_pad, read buttons and evaluation of code
 */
void codePad(){
bool lock = true;
display.updateLabel(14, F("    ")); //clear text box
while(lock){ //lock processor time in here for proper processing
  char check;
  check = display.getID(); //read in code of buttons
    switch (check) //compare input buttons
    {
      case 10: //delete text box
        clearCode();
        display.updateLabel(14, F("    "));     
      break;
      case 11: //Ok button pressed, now compare input code with reference
        if(strncmp(g_input_code,"4567",4)==0){  //if match then go in special menu
          display.runScriptFile(F("TPSPORTS\\Screen4\\Screen4.bin"));  //load screen
          g_state = SERVICE_MAIN ;   //FSM
          lock=false; // release process in order to switch through FSM again.
        }
      break;
      case 12: //goes back to warm up timer
        display.runScriptFile(F("TPSPORTS\\Screen2\\Screen2.bin"));  //load screen
        g_state = WARM_UP_TIMER ;   //FSM
        lock=false;
        break;
      case 255: //special code comand from display which has to be thrown away 
        break;
      default:  //each button has a code this makes a char out of the input code
        g_input_code[g_input_index] = check + 48; // shift in the ASCII-table by 48
        updateIndices(); 
        display.updateLabel(14,g_input_code , g_printable_chars);         
        break; 
    } // endswitch  
  }
}


/*
 * In service mode
 * This function handles the rtc (Real time clock) settings
 */
void serviceRTC(){
  bool once = false;
  uint8_t Hour = 7;
  uint8_t Min = 0;
  uint8_t Day = 1;
  uint8_t Month = 1;
  uint16_t Year = 18;

  bool save = false;

  DateTime now = rtc.now();
  Year = now.year();
  Year -= 2000;
  Month = now.month();
  Day = now.day();
  Hour = now.hour();
  Min = now.minute();
  if (!once) {  //do it only once
    once = true;
    display.updateLabel(3, Day);
    display.updateLabel(2, Month);
    display.updateLabel(1, Year);
    display.updateLabel(4, Hour);
    display.updateLabel(5, Min);

  }

  while (!save)   //do while a certain Button is pressed in this case number 3
  {
    checkButtonActivity(); //read Buttons   
  switch (g_buttonPressed)
  {
    case 3:  //Button Test
      display.runScriptFile(F("TPSPORTS\\Screen4\\Screen4.bin"));  //load screen
      g_state = SERVICE_MAIN ;   //FSM
      save = true;    //set to true to leave do while
    break; 
    case 6:  //Button Test
      rtc.adjust(DateTime(Year + 2000, Month, Day, Hour, Min, 0));
      save = true; delay(100);    
      display.runScriptFile(F("TPSPORTS\\Screen5\\Screen5.bin"));  //load screen
      g_state = SERVICE_RTC ;   //FSM
    break;
      case 13:  //Button 11 on touch screen
        Day++;
        
        if (Day > 31)
          Day = 0;

        //delay(100);
        display.updateLabel(3, Day);
        break;
      case 12:    //Button 12 on touch screen
        Month++;
        
        if (Month > 12)
          Month = 1;

        //delay(100);
        display.updateLabel(2, Month);
        break;
      case 11:    //Button 11 on touch screen
        Year++;
        
        if (Year > 40)
          Year = 20;

        //delay(100);
        display.updateLabel(1, Year);
        break;
      case 14:    //Button 14 on touch screen
        Hour++;
        
        if (Hour > 23)
          Hour = 0;

        //delay(100);
        display.updateLabel(4, Hour);
        break;
      case 15:    //Button 15 on touch screen
        Min++;
        
        if (Min > 59)
         Min = 0;
      
        //delay(100);
        display.updateLabel(5, Min);
        break;
      default:
        break;
    } // endswitch
  } // endwhile   
}


/*
 * helping function of clibrationDL() which refreshes the screen
 */
void updateLabelAndSetLQ(uint16_t& var, bool & toggle, bool & toggle2, bool & toggle3) {
  TheMatrix::updateLabel(10, var);
  if (toggle) {   //twilight
    sdc.set_lux_to_twilight = var;  //newest changed value, store in variable
    dl.dl_twilight = sdc.set_lux_to_twilight; //transfer of into day light class
    dl.setDl_value(var);    //turn on
  }
  if (toggle2) {  //winter
    sdc.set_lux_to_winter = var;
    dl.dl_winter = sdc.set_lux_to_winter; //transfer of into day light class
    dl.setDl_value(var);    //turn on 
  }
  if (toggle3) {  //summer
    sdc.set_lux_to_summer = var;
    dl.dl_summer = sdc.set_lux_to_summer; //transfer of into day light class
    dl.setDl_value(var);    //turn on 
  }
}

/*
 * manages the daylight calibration 
 */
void serviceCalibration(){
static bool toggle_twilight=false;
static bool toggle_winter=false;
static bool toggle_summer=false;
static uint16_t var;
  switch (g_buttonPressed)
  {
    case 3:  //Button 3
      display.runScriptFile(F("TPSPORTS\\Screen4\\Screen4.bin"));  //load screen
      g_state = SERVICE_MAIN ;   //FSM
      toggle_twilight = false;
      toggle_winter = false;
      toggle_summer = false;
      dl.setDl_off();
    break;
    case 6:  //Button 6, save calibration value
      if (toggle_twilight) {   //Check which mode twilight/winter/summer is active
        sdc.set_lux_to_twilight = var;
      }
      if (toggle_winter) {  
        sdc.set_lux_to_winter = var;
      }
      if (toggle_summer) { 
        sdc.set_lux_to_summer = var;
      }
      toggle_twilight = false;
      toggle_winter = false;
      toggle_summer = false;
      sdc.writeCalibratFile();
      delay(250);
      display.updateLabel(10, F("OFF"));
      dl.setDl_off();
    break;  
    default:
      break;     
  }
  if (g_buttonPressed == 10) {   //this is button 10 on touch screen (twilight) day light 
    toggle_twilight = toggle_twilight ? false : true;  // active?
    toggle_winter = false;
    toggle_summer = false;
    if (toggle_twilight) {  //if active, twilight, load current value and turn light source on
      sdc.loadCalibratFile();
      var = sdc.set_lux_to_twilight;
      display.updateLabel(10, var);
      dl.setDl_value(var);
    } else {
      display.TheMatrix::updateLabel(10, F("OFF"));
      dl.setDl_off();
    }
  }
  if (g_buttonPressed == 11) {   //this is button 11 on touch screen (winter) day light 
    toggle_winter = toggle_winter ? false : true;  // active?
    toggle_twilight = false;
    toggle_summer = false;
    if (toggle_winter) {  //if active, winter, load current value and turn light source on
      sdc.loadCalibratFile();
      var = sdc.set_lux_to_winter;
      display.updateLabel(10, var);
      dl.setDl_value(var);
    } else {
      display.TheMatrix::updateLabel(10, F("OFF"));
      dl.setDl_off();
    }
  }
  if (g_buttonPressed == 12) {   //this is button 12 on touch screen (summer) day light 
    toggle_summer = toggle_summer ? false : true;  // active?
    toggle_twilight = false;
    toggle_winter = false;
    if (toggle_summer) {  //if active, summer, load current value and turn light source on
      sdc.loadCalibratFile();
      var = sdc.set_lux_to_summer;
      display.updateLabel(10, var);
      dl.setDl_value(var);
    } else {
      display.TheMatrix::updateLabel(10, F("OFF"));
      dl.setDl_off();
    }
  }  
  if ((g_buttonPressed == 21) && ((toggle_twilight) || (toggle_winter) || (toggle_summer))) { //touch button 21 on screen UP
    var++;
    if (var == 4096) { //max possible value on source
      var = 4095;
    }
    updateLabelAndSetLQ(var, toggle_twilight, toggle_winter, toggle_summer);
  }
  if ((g_buttonPressed == 22) && ((toggle_twilight) || (toggle_winter) || (toggle_summer))) { //touch button 22 on screen DOWN
    var--;
    if (var == 65535) { //overflow 
      var = 0;
    }
    updateLabelAndSetLQ(var, toggle_twilight, toggle_winter, toggle_summer);
  }
  
}


/*
 * main menue service mode
 */
void serviceMain(){
  switch (g_buttonPressed)
  {
    case 1:  //Button 1
      display.runScriptFile(F("TPSPORTS\\Screen7\\Screen7.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_OPTRAY;   //FSM
    break;
    case 2:  //Button 2
      display.runScriptFile(F("TPSPORTS\\Screen5\\Screen5.bin"));  //load screen
      g_state = SERVICE_RTC ;   //FSM
    break;
    case 3:  //Button 3
      display.runScriptFile(F("TPSPORTS\\Screen6\\Screen6.bin"));  //load screen
      g_state = SERVICE_CALIBRATION ;   //FSM
    break;
    case 6:  //Button 6
      display.runScriptFile(F("TPSPORTS\\Screen7\\Screen7.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_OPTRAY;   //FSM
    break;  
    default:
      break;
  } // endswitch    
}

/*
 * Menu sunglasses selected show the other options
 */
void mainMenuSunglassOptray(){
  switch (g_buttonPressed)
  {
    case 2:  //Button Test
      g_retest=true;
      while(g_retest){
        error(F("delete"));
        sdc.loadAnyFile(F("testflow/optray.txt")); //the part between / and . ist the folder for storage and must be created in SD-Card.
      }
      display.runScriptFile(F("TPSPORTS\\Screen7\\Screen7.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_OPTRAY;   //FSM
    break;  
    case 3:  //Button 
      display.runScriptFile(F("TPSPORTS\\Screen10\\Screen10.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_CYBER_OPTIC_SHADES;   //FSM
      break;
    case 5:  //Button 
      g_retest=true;
      while(g_retest){
        g_automatic_run=true;
        error(F("delete"));
        sdc.loadAnyFile(F("testflow/optray.txt"));
      }
      g_automatic_run=false;
      display.runScriptFile(F("TPSPORTS\\Screen7\\Screen7.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_OPTRAY;   //FSM
      break;
    case 6:  //Button 
      display.runScriptFile(F("TPSPORTS\\Screen8\\Screen8.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_EKOI;   //FSM
      break;
    default:
      break;
  } // endswitch
}

/*
 * Menue ski goggles selected show the other options
 */
void mainMenuSunglassEkoi(){
  switch (g_buttonPressed)
  {
    case 2:  //Button Test
      g_retest=true;
      while(g_retest){
        error(F("delete"));
        sdc.loadAnyFile(F("testflow/ekoi.txt")); //the part between / and . ist the folder for storage and must be created in SD-Card.
      }
      display.runScriptFile(F("TPSPORTS\\Screen8\\Screen8.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_EKOI;   //FSM      
    break;  
    case 3:  //Button 
      display.runScriptFile(F("TPSPORTS\\Screen7\\Screen7.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_OPTRAY;   //FSM
      break;
    case 5:  //Button 
      g_retest=true;
      while(g_retest){
        g_automatic_run=true;
        error(F("delete"));
        sdc.loadAnyFile(F("testflow/ekoi.txt"));
      }
      g_automatic_run=false;
      display.runScriptFile(F("TPSPORTS\\Screen8\\Screen8.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_EKOI;   //FSM
      break;
 
    case 6:  //Button 
      display.runScriptFile(F("TPSPORTS\\Screen10\\Screen10.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_CYBER_OPTIC_SHADES;   //FSM
      break;
    default:
      break;
  } // endswitch 
}

/*
 * Menue motorcycle visor show the other options
 */
void mainMenuSunglassCyberOpticShades(){
  switch (g_buttonPressed)
  {
    case 2:  //Button Test
      g_retest=true;
      while(g_retest){
        error(F("delete"));
        sdc.loadAnyFile(F("testflow/cyberopt.txt")); //the part between / and . ist the folder for storage and must be created in SD-Card.
      }
      display.runScriptFile(F("TPSPORTS\\Screen10\\Screen10.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_CYBER_OPTIC_SHADES;   //FSM
    break;  
    case 3:  //Button 
      display.runScriptFile(F("TPSPORTS\\Screen8\\Screen8.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_EKOI;   //FSM
      break;
    case 5:  //Button 
      g_retest=true;
      while(g_retest){
        g_automatic_run=true;
        error(F("delete"));
        sdc.loadAnyFile(F("testflow/cyberopt.txt"));
      }
      g_automatic_run=false;
      display.runScriptFile(F("TPSPORTS\\Screen10\\Screen10.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_CYBER_OPTIC_SHADES;   //FSM
      break;
    case 6:  //Button 
      display.runScriptFile(F("TPSPORTS\\Screen7\\Screen7.bin"));  //load screen
      g_state = MAIN_MENU_SUNGLASS_OPTRAY;   //FSM
      break;
    default:
      break;
  } // endswitch 
}


/*
 * This is the main testflow organizer, there a two states. One, the instruction screen. 
 * Second, the test screen. Divided in two states and always loaded out of sd-card test structure .txt
 */
int8_t GenericTestFlow(){
  bool state = false;
  bool end_of_test = false;
  bool once =true;
  bool once2=true;
  
  do { //catch process until certain conditions are met ex. pressing a certain Button
    checkButtonActivity();
    switch (state) {    //There are two states, one for instruction screen and the other for the acutal testing process
      case false:   //instruction screen state    
        if(sdc.generic_instruction_screen.length() > 0){
          if(once2){// do it once otherwise it flickers
            display.runScriptFile(sdc.generic_instruction_screen);
          }
          once =true;
          once2=false;
        }
        if (g_buttonPressed == 3) {  // Button Back
          once=false;
          storeDataInSDCard(); //if abort test, store it as far the date is generated
          error(F("delete"));
          return -1;  //abort test
        }    
        if ((g_buttonPressed == 6) || (sdc.generic_instruction_screen.length() == 0)) { //Button Forward or go to next state(test) if there is no instruction screen   
          //Button forward pressed or no instruction screen available than go to next state
          state = true;
          once =true;
          once2=false;
          display.runScriptFile(sdc.generic_test_screen);
        }
        break;
      case true:    //state after the instruction screen, the test state
        if(once){
         runSpecificTest();
         testForAutomaticRun();
         once =false;              
        }
        if (g_buttonPressed == 3) {  // Button Back
          once=false;
          storeDataInSDCard(); //if abort test store it as far the date is generated
          error(F("delete"));
          return -1;  //abort test
        } 
        if (g_buttonPressed == 5) { //Test end skip forward to next instruction or test screen
          once =true;
        }                       
        if (g_buttonPressed == 6) { //Test end skip forward to next instruction or test screen
          end_of_test = true;
          once =false;
        }
        break;
    }
  } while (!end_of_test);
      
}


/*
 * Final report "test"
 */
void finalReport(){
  if(g_errors[0].length() >0){ //if error text is in variable then write it to screen
    display.updateLabel(10, F("Fehler 1:"));
    display.updateLabel(20, g_errors[0]);
    display.updateLabel(40, extractStoredData(g_errors[0])+'%');
    display.runLEDstate(30, LED_RED);
    fillInStoreData(1,F("Error_Count")); //store in file that there has an error happened
  }else{
    display.updateLabel(20, F("Trans_OFF"));
    display.updateLabel(21, F("Trans_Summer"));
    display.updateLabel(40,extractStoredData(F("Trans_OFF"))+'%');
    display.updateLabel(41,extractStoredData(F("Trans_SUMMER"))+'%');
    display.runLEDstate(30, LED_GREEN);
  }
  if(g_errors[1].length() >0){//if error text is in variable then write it to screen
    display.updateLabel(11, F("Fehler 2:"));
    display.updateLabel(21, g_errors[1]);
    display.updateLabel(41, extractStoredData(g_errors[1])+'%');
    fillInStoreData(2,F("Error_Count")); //store in file that there has two errors happened
  }
  if(g_errors[2].length() >0){//if error text is in variable then write it to screen
    display.updateLabel(12, F("Fehler 3:"));
    display.updateLabel(22, g_errors[2]);
    display.updateLabel(42, extractStoredData(g_errors[2])+'%');
    fillInStoreData(3,F("Error_Count")); //store in file that there has three errors happened
  }
  error(F("delete")); //delete all errors logged in variable
}

/*
 * Nullabgleich "test" function
 */
void nullabgleich(){
    display.runLEDstate(30, LED_ORANGE);
    udt.autoRange();
    delay(10);
    udt.nullabgleich();
    delay(10);
    g_Transmission0= udt.getMeasure(20);
    udt2.autoRange();
    delay(10);
    udt2.nullabgleich();
    delay(10);
    g_Transmission0_2= udt2.getMeasure(20);
    display.runLEDstate(30, LED_GREEN);  
}

/*
 * Runs test transmission in off state
 */
void transmissionOff(){
char result[6];
    display.runLEDstate(30, LED_ORANGE); // show orange as long as in test
    udt.autoRange(); 
    delay(10); 
    g_TransmissionActual=udt.getMeasure(20);
    g_TransmissionPercent=(g_TransmissionActual / g_Transmission0)*100.0; //calculate relative transmission
    sprintf(result, "%.2f", g_TransmissionPercent); //makes xx.xx
    display.updateLabel(10, result);
    if(g_TransmissionPercent<sdc.generic_high_limit&&g_TransmissionPercent>sdc.generic_low_limit){
      display.runLEDstate(30, LED_GREEN); //pass
    }else{
      error(F("Trans_OFF")); //store string with error text in variable
      display.runLEDstate(30, LED_RED); //fail
    }
    fillInStoreData(g_TransmissionPercent);//fill in the result for log file
}

/*
 * Runs test transmission in on state
 */
void transmissionON(){
String completeFailText="";
String specificFail="";
char result[6];
    display.runLEDstate(30, LED_ORANGE);
    if(sdc.generic_lux == F("TWILIGHT")){ //load specific light source itensity
      specificFail=F("TWILIGHT");
      dl.dl_twilight=sdc.set_lux_to_twilight;
      dl.setDl_twilight();
    }else if(sdc.generic_lux == F("WINTER")){
      specificFail=F("WINTER");
      dl.dl_winter=sdc.set_lux_to_winter;
      dl.setDl_winter();
    }else if(sdc.generic_lux == F("SUMMER")){
      specificFail=F("SUMMER");
      dl.dl_summer=sdc.set_lux_to_summer;
      dl.setDl_summer();
    }
    delay(1500); //gotta wait cuz its a snail of a light source :)
    udt.autoRange(); 
    delay(10); 
    g_TransmissionActual=udt.getMeasure(20);
    g_TransmissionPercent=(g_TransmissionActual / g_Transmission0)*100.0;
    sprintf(result, "%.2f", g_TransmissionPercent); //makes xx.xxx
    display.TheMatrix::updateLabel(10, result);
    dl.setDl_off();
    if(g_TransmissionPercent<sdc.generic_high_limit&&g_TransmissionPercent>sdc.generic_low_limit){
      display.runLEDstate(30, LED_GREEN);  //pass
    }else{
      completeFailText="Trans_"+specificFail; // fail
      error(completeFailText);
      display.runLEDstate(30, LED_RED);
    }
    fillInStoreData(g_TransmissionPercent);
      
}

/*
 * Runs test flicker detection
 */
void flickerDetection(){
  
}

/*
 * Runs test bar detection
 */
void barDetection(){
char result[6];
    display.runLEDstate(30, LED_ORANGE);
    if(sdc.generic_lux == F("SUMMER")){
      dl.dl_summer=sdc.set_lux_to_summer;
      dl.setDl_summer();
    }
    delay(1500); //gotta wait cuz its a snail of a light source :)
    udt.autoRange(); 
    delay(10); 
    g_TransmissionActual_2=udt2.getMeasure(20);
    g_TransmissionPercent_2=(g_TransmissionActual_2 / g_Transmission0_2)*100.0;
    sprintf(result, "%.2f", g_TransmissionPercent_2); //makes xx.xxx
    display.TheMatrix::updateLabel(10, result);
    dl.setDl_off();
    if(g_TransmissionPercent_2<sdc.generic_high_limit&&g_TransmissionPercent_2>sdc.generic_low_limit){
      display.runLEDstate(30, LED_GREEN);  //pass
    }else{
      error(F("Bar detection"));
      display.runLEDstate(30, LED_RED);
    }
    fillInStoreData(g_TransmissionPercent_2);    
}

/*
 * Error handler function
 * Fills error text in array
 * Deletes array also
 */
void error(String error){
  if(error == F("delete")){
     g_errors[0]="";
     g_errors[1]="";
     g_errors[2]="";
  }else{
    if(g_errors[0].length() == 0){
      g_errors[0]=error;   
    }else if(g_errors[1].length() == 0){
      g_errors[1]=error;
    }else if(g_errors[2].length() == 0){
      g_errors[2]=error;
    }
  }
}

/*
 * Interrupt which is caused by the scanner 
 */
void keyReleased() {
  printKey();
}

/*
 * analyses the key
 */
void printKey() {
  char c = keyboard.getKey(); //ascii-code to char
  if (c == '') {  //XOFF  Pause transmission, das ist kein Leerzeichen, sondern Flowcontrol DC3, Ascii 19
    flag_scanner=true;
  } else { //just a regular char
    g_str_scanner += c;
  }
}


/*
 * scanner funtion "test" routine
 */
void scanner(){
  while(1){ //you have to isolate processor time here in order to get scanner over usb working
    checkButtonActivity();
    usb.Task();
    if (g_buttonPressed == 3) { //release usb.Task
        break;
      }
    if (g_buttonPressed == 6) { //release usb.Task
        break;
      }
    if(flag_scanner){ //this flag is set by printKey() and set the end of transmission, show on display
        display.updateLabel(10 , g_str_scanner );
        fillInStoreData(g_str_scanner,F("Optrel_ID"));
        g_str_scanner="";
        flag_scanner=false;   
    }
  }
}

/*
 * Loads the result in array for storage/logging
 * overloaded function()
 */
void fillInStoreData(float result){
char buf[17];
  for(int i=0; i<g_max_row_header;i++){ //circle through header array until current test aka store_name comes up
    if(strcmp(g_str_header_for_storage[i][0],sdc.generic_store_name.c_str())==0 ){//if header and store_name matches then store in array position       
        dtostrf(result,6,2,buf);
        for(int j=0;j<17;j++){ //fill buffer in log-array
          g_str_header_for_storage[i][1][j]=buf[j]; 
        }      
        
      }
  }
}

/*
 * Loads the result in array for storage/logging
 * overloaded function()
 */
void fillInStoreData(float result,String header){
char buf[17];
  for(int i=0; i<g_max_row_header;i++){
    if(strcmp(g_str_header_for_storage[i][0],header.c_str())==0 ){         
        dtostrf(result,6,2,buf);
        for(int j=0;j<17;j++){
          g_str_header_for_storage[i][1][j]=buf[j]; 
        }      
        
      }
  }
}

/*
 * Loads the result in array for storage/logging
 * overloaded function()
 */
void fillInStoreData(String data,String header){
char buf[17];
  for(int i=0; i<g_max_row_header;i++){
    if(strcmp(g_str_header_for_storage[i][0],header.c_str())==0 ){         
        data.toCharArray(buf,17);
        for(int j=0;j<g_max_row_header;j++){
          g_str_header_for_storage[i][1][j]=buf[j]; 
        }       
        
      }
  }
}

/*
 * Goes in a array where stored test results are. Takes them out as a string for final report.
 */
String extractStoredData(String header){
String x;
  for(int i=0; i<g_max_row_header;i++){
    if(strcmp(g_str_header_for_storage[i][0],header.c_str())==0 ){         
        for(int j=0;j<g_max_row_header;j++){
          if(g_str_header_for_storage[i][1][j]=='\0'){
            break;
          }
          x +=  String(g_str_header_for_storage[i][1][j]);
        }       
        
      }
  }
return x;
}


void testForAutomaticRun(){
  if(g_automatic_run==true&&sdc.generic_auto_run=="True"){
    g_buttonPressed=6; //simulate a pressed button
    delay(750);
  }  
}

/*
 * Out of the generic test flow this runs the specific test
 */
void runSpecificTest() {
  if (sdc.scanner) {
    scanner();
  }  
  if (sdc.nullabgleich) { //after evaluation of test flow file, checks if its set, then do the test
    nullabgleich();
  }
  if (sdc.flickerDetection) { //after evaluation of test flow file, checks if its set, then do the test
    flickerDetection();
  }
  if (sdc.transmissionOff) { //after evaluation of test flow file, checks if its set, then do the test
    transmissionOff();
  }
  if (sdc.transmissionOn) { //after evaluation of test flow file, checks if its set, then do the test
    transmissionON();
  }
  if (sdc.barDetection){
    barDetection();
  }
  if (sdc.finalReport) { //after evaluation of test flow file, checks if its set, then do the test
    finalReport();
    storeDataInSDCard();
    deleteData();
  }
}

int EndsWith(const char *str, const char *suffix)
{
    if (!str || !suffix)
        return 0;
    size_t lenstr = strlen(str);
    size_t lensuffix = strlen(suffix);
    if (lensuffix >  lenstr)
        return 0;
    return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}

void deleteData(){
  for(int i=0; i<g_max_row_header;i++) {
    if(!EndsWith(g_str_header_for_storage[i][0],"_u"))
    g_str_header_for_storage[i][1][0] = '\0';// deleting data
  }
}

/*
 * all the logged data in array will be written in sd-card but before the name has to be constructed
 */
void storeDataInSDCard(){
DateTime now = rtc.now();
String fileName="";
String temp ="";
uint32_t seconds = 0;
  fillInStoreData(sdc.testing_instrument_number,F("PruefmittelNR"));//store in log file the Prüfmittelnummer
  fillInStoreData(F("TEFPRO"),F("MachineType")); //store in log file the machine type
  temp=String(now.year(),10)+"."+String(now.month(),10)+"."+String(now.day(),10);// assemble string date
  fillInStoreData(temp,F("TEST_DATE"));//store in log file the date
  temp=String(now.hour(),10)+":"+String(now.minute(),10)+":"+String(now.second(),10);
  fillInStoreData(temp,F("TEST_TIME"));//store in log file the test time
  
  fileName=sdc.testing_tefpro_number;
  seconds=now.year(); //var abuse YYYY
  seconds = seconds - 2000;//var abuse YY
  temp =  String(seconds,36);// 0-Z
  if(temp.length()>1){ //year 36 and above
    temp.remove(0,1); //cut from XY the X and just print Y
  }
  fileName = fileName + temp;
  fileName = fileName + String(now.month(),36);
  fileName = fileName + String(now.day(),36);
  seconds = 0;
  seconds = 3600*now.hour(); //3600=60*60 hours to seconds conversion
  seconds = seconds + 60*now.minute(); //minutes to seconds conversion
  seconds = seconds + now.second();
  fileName = fileName + String(seconds,36);
  sdc.storeData("log",fileName); 
  sdc.storeData("ftp",fileName); //make a second copy for ftp upload
}

/*
 * THE MAIN LOOP of the FSM (finite state machine)
 */
void loop() {

  checkButtonActivity();

  switch (g_state) {

    case WARM_UP_TIMER: warmUpTimer(); break;
    case CODE_PAD: codePad(); break;
    case MAIN_MENU_SUNGLASS_OPTRAY: mainMenuSunglassOptray(); break;
    case MAIN_MENU_SUNGLASS_EKOI: mainMenuSunglassEkoi(); break;
    case MAIN_MENU_SUNGLASS_CYBER_OPTIC_SHADES: mainMenuSunglassCyberOpticShades(); break;
    case SERVICE_MAIN: serviceMain(); break;
    case SERVICE_RTC: serviceRTC(); break;
    case SERVICE_CALIBRATION: serviceCalibration(); break;
    default : ; break;
  }
  g_buttonPressed=255;//point to void

}
-----------------------------------------------------------------------------------------------
sd_card.cpp



#include "SD_Card.h"




// FOR INSPECTION TO IMPLEMENTED COUNTING FILES
 uint16_t SD_Card::count(String Directory)
{
  uint16_t c=0;
    
    File dir = SD.open(Directory);
    while (true)
    {
     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       break;
     }
     //Serial.print(entry.name());
     if (!(entry.isDirectory()))
     { 
         c=c+1;
     }
    }
    
    return c;
}



//loads calibartion file into variables
//read testABCD.txt ex. testpano.txt for further insight
void SD_Card::parsCalibratFile(String line)
{
  if (line == "") {
    line = "NoN NoN";
  }
  String command;
  String parameter;
  String productInFile;

  int firstSpace = line.indexOf(' ');
  command = line.substring(0, firstSpace);
  parameter = line.substring(firstSpace + 1);
  firstSpace = line.indexOf('_');
  productInFile = line.substring(0, firstSpace);
  command.trim();
  parameter.trim();

  if (command == F("TESTING_INSTRUMENT_NUMBER")) {
    testing_instrument_number = parameter;
  }
  if (command == F("TESTING_TEFPRO_NUMBER")) {
    testing_tefpro_number = parameter.toInt();
  }
  if (command == F("SET_LUX_TO_TWILIGHT")) {
    set_lux_to_twilight = parameter.toInt();
  }
  if (command == F("SET_LUX_TO_WINTER")) {
    set_lux_to_winter = parameter.toInt();
  }
  if (command == F("SET_LUX_TO_SUMMER")) {
    set_lux_to_summer = parameter.toInt();
  }

}

/*
 * writes all the logged data in one file in sd-card
 * Per test series on file logged, no single big file for all data
 */
void SD_Card::storeData(String path,String fileName) {
  int top;
  String folderName = path;
  String fullPath = {""};
  int i = 0;
  if(path == "log"){
    fullPath = folderName + "/"+folder_name+"/" + fileName + ".csv"; //folder_name is given through load file(testflow/optray.txt) and the name there cutted (optray) out. 
  }
  if(path == "ftp"){
    fullPath = folderName + "/" + fileName + ".csv";
  }
  File myFile = SD.open((fullPath), FILE_WRITE);
  while (strcmp(g_str_header_for_storage[i][0],"END")!=0) { //At array [i][0] is the header name stored
    myFile.print(g_str_header_for_storage[i][0]);
    myFile.print(";");
    i++;
  }
  top=i;
  myFile.println("");
  for(int i=0; i<top;i++) {
    myFile.print(g_str_header_for_storage[i][1]);   //At array [i][1] is the testdata stored
    myFile.print(";");
  }
  myFile.close();
}


// stores calibration file, after changing ex. time and steps of day light source
void SD_Card::writeCalibratFile() {
  //remove
  SD.remove(F("system/calibrat.txt"));
  // open a new file and immediately close it:
  myFile = SD.open(F("system/calibrat.txt"), FILE_WRITE);
  myFile.close();

  File myFile = SD.open(F("system/calibrat.txt"), FILE_WRITE); //FILE brauch es...
  myFile.print(F("TESTING_INSTRUMENT_NUMBER ")); myFile.println(testing_instrument_number);
  myFile.print(F("TESTING_TEFPRO_NUMBER ")); myFile.println(testing_tefpro_number);
  myFile.print(F("SET_LUX_TO_TWILIGHT ")); myFile.println(set_lux_to_twilight);
  myFile.print(F("SET_LUX_TO_WINTER ")); myFile.println(set_lux_to_winter);
  myFile.print(F("SET_LUX_TO_SUMMER ")); myFile.println(set_lux_to_summer);
  myFile.close();
}

//opens calibration file
void SD_Card::loadCalibratFile()
{
  File dataFile = SD.open("system/calibrat.txt", FILE_READ);
  while (dataFile.available())
  {
    String line = readLineFile(dataFile);
    parsCalibratFile(line);   //reads lines and fills in variables
  }

  dataFile.close();
}

//reads line for line in
String SD_Card::readLineFile(File dataFile)
{
  char nl = 10;
  char cr = 13;
  String line = "";

  char z;

  if (dataFile.available()) {
    z = dataFile.read();
  }
  while (dataFile.available() && z != nl)
  {
    if (z != nl || z != cr) {   //nl= newline cr=carriage return
      line = line + z;
    }
    z = dataFile.read();
  }

  return line;

}

//Loads test file, makes exp. optray.txt and opens test flow file, parsing through
//It also is defined that the text before .txt is the folder storage name which has to be created in advance(not automated)
void SD_Card::loadAnyFile(String product)
{
  int index1 = product.indexOf('/');
  int index2 = product.indexOf('.');
  folder_name = product.substring(index1+1, index2);
  File dataFile = SD.open(product, FILE_READ);
  while (dataFile.available())    //read file as long as there is data
  {
    String line = readLineFile(dataFile);
    if (parsAnyFile(line) == -1) {    //compare strings from file with certain text which we are looking for
      g_retest = false;
      break;
    }
  }
  dataFile.close();
}

int8_t SD_Card::parsAnyFile(String line)
{
  char* char_ary[30];
  if (line == "") {
    line = "NoN NoN";
  }
  String command;
  String parameter;
  int8_t abort;

  int firstSpace = line.indexOf(' ');
  int firstSlashOfComment = line.indexOf('/');
  command = line.substring(0, firstSpace);
  parameter = line.substring(firstSpace + 1, firstSlashOfComment);
  command.trim();
  parameter.trim();



  //***Barcode Scanner***//
  if (command == F("SCANNER")) {
    if ((parameter == F("End")) && scanner) {
      abort = GenericTestFlow();
    }
  }
  if (command == F("SCANNER")) {
    scanner = false;
    if (parameter == F("Begin")) {
      scanner = true;
    }
  }
  if (command == F("SCANNER_TEST")) {
    generic_test_screen = parameter;
  }
  if (command == F("SCANNER_INSTRUCTION")) {
    generic_instruction_screen = parameter;
  }
  if (command == F("SCANNER_STORE_NAME")) {
    generic_store_name=(char *)parameter.c_str();
  }
  if (command == F("SCANNER_AUTO_RUN")) {
    generic_auto_run = parameter;
  } 


  //***NULLABGLEICH ***//
  if (command == F("NULLABGLEICH")) {
    if ((parameter == F("End")) && nullabgleich) {
      abort = GenericTestFlow();
    }
  }
  if (command == F("NULLABGLEICH")) {
    nullabgleich = false;
    if (parameter == F("Begin")) {
      nullabgleich = true;
    }
  }

  if (command == F("NULLABGLEICH_INSTRUCTION")) {
    generic_instruction_screen = parameter;
  }
  if (command == F("NULLABGLEICH_TEST")) {
    generic_test_screen = parameter;
  }
  if (command == F("NULLABGLEICH_AUTO_RUN")) {
    generic_auto_run = parameter;
  } 

  //***TRANSMISSION OFF***//
  if (command == F("TRANSMISSION_OFF")) {
    if ((parameter == F("End")) && transmissionOff) {
      abort = GenericTestFlow();
    }
  }
  if (command == F("TRANSMISSION_OFF")) {
    transmissionOff = false;
    if (parameter == F("Begin")) {
      transmissionOff = true;
    }
  }

  if (command == F("TRANSMISSION_OFF_INSTRUCTION")) {
    generic_instruction_screen = parameter;
  }
  if (command == F("TRANSMISSION_OFF_TEST")) {
    generic_test_screen = parameter;
  }
  if (command == F("TRANSMISSION_OFF_HIGH_LIMIT")) {
    generic_high_limit = parameter.toFloat();
  }
  if (command == F("TRANSMISSION_OFF_LOW_LIMIT")) {
    generic_low_limit = parameter.toFloat();
  }
  if (command == F("TRANSMISSION_OFF_STORE_NAME")) {
    generic_store_name = parameter;
  }
  if (command == F("TRANSMISSION_OFF_AUTO_RUN")) {
    generic_auto_run = parameter;
  }

  //***FLICKER DETECTION***//
  if (command == F("TRANSMISSION_FLICKER")) {
    if ((parameter == F("End")) && flickerDetection) {
      abort = GenericTestFlow();
    }
  }
  if (command == F("TRANSMISSION_FLICKER")) {
    flickerDetection = false;
    if (parameter == F("Begin")) {
      flickerDetection = true;
    }
  }

  if (command == F("TRANSMISSION_FLICKER_INSTRUCTION")) {
    generic_instruction_screen = parameter;
  }
  if (command == F("TRANSMISSION_FLICKER_TEST")) {
    generic_test_screen = parameter;
  }
  if (command == F("TRANSMISSION_FLICKER_LUX")) {
    generic_lux = parameter;
  }
  if (command == F("TRANSMISSION_FLICKER_STORE_NAME")) {
    generic_store_name=(char *)parameter.c_str();
  }

  //***TRANSMISSION ON***//
  if (command == F("TRANSMISSION_ON")) {
    if ((parameter == F("End")) && transmissionOn) {
      abort = GenericTestFlow();
    }
  }
  if (command == F("TRANSMISSION_ON")) {
    transmissionOn = false;
    if (parameter == F("Begin")) {
      transmissionOn = true;
    }
  }

  if (command == F("TRANSMISSION_ON_INSTRUCTION")) {
    generic_instruction_screen = parameter;
  }
  if (command == F("TRANSMISSION_ON_TEST")) {
    generic_test_screen = parameter;
  }
  if (command == F("TRANSMISSION_ON_LUX")) {
    generic_lux = parameter;
  }
  if (command == F("TRANSMISSION_ON_HIGH_LIMIT")) {
    generic_high_limit = parameter.toFloat();
  }
  if (command == F("TRANSMISSION_ON_LOW_LIMIT")) {
    generic_low_limit = parameter.toFloat();
  }
  if (command == F("TRANSMISSION_ON_STORE_NAME")) {
    generic_store_name=(char *)parameter.c_str();
  }
  if (command == F("TRANSMISSION_ON_AUTO_RUN")) {
    generic_auto_run = parameter;
  }

  //*** BAR DETECTION***//
  if (command == F("BAR_DETECTION")) {
    if ((parameter == F("End")) && barDetection) {
      abort = GenericTestFlow();
    }
  }
  if (command == F("BAR_DETECTION")) {
    barDetection = false;
    if (parameter == F("Begin")) {
      barDetection = true;
    }
  }
  if (command == F("BAR_DETECTION_INSTRUCTION")) {
    generic_instruction_screen = parameter;
  }
  if (command == F("BAR_DETECTION_TEST")) {
    generic_test_screen = parameter;
  }
  if (command == F("BAR_DETECTION_ON_LUX")) {
    generic_lux = parameter;
  }
  if (command == F("BAR_DETECTION_HIGH_LIMIT")) {
    generic_high_limit = parameter.toFloat();
  }
  if (command == F("BAR_DETECTION_LOW_LIMIT")) {
    generic_low_limit = parameter.toFloat();
  }
  if (command == F("BAR_DETECTION_STORE_NAME")) {
    generic_store_name=(char *)parameter.c_str();   
  }
  if (command == F("BAR_DETECTION_AUTO_RUN")) {
    generic_auto_run = parameter;
  }

  //***FINAL REPORT ***//
  if (command == F("FINAL_REPORT")) {
    if ((parameter == F("End")) && finalReport) {
      abort = GenericTestFlow();
    }
  }
  if (command == F("FINAL_REPORT")) {
    finalReport = false;
    if (parameter == F("Begin")) {
      finalReport = true;
    }
  }
  if (command == F("FINAL_REPORT_INSTRUCTION")) {
    generic_instruction_screen = parameter;
  }

  if (command == F("FINAL_REPORT_SCREEN")) {
    generic_test_screen = parameter;
  }
  if (command == F("FINAL_REPORT_AUTO_RUN")) {
    generic_auto_run = parameter;
  }  

  if (abort == -1) {
    return -1;
  }
}
------------------------------------------------------------------------------------------------
sd_card.h
//#include <SD.h>


#include <SPI.h>
#include <SD.h>



#ifndef _SD_Card_h
#define _SD_Card_h

extern int8_t GenericTestFlow();
extern bool g_retest;
extern char g_str_header_for_storage[15][2][17];

class SD_Card
{
  protected:

    File myFile;

    //Hilfsfunktionen

    String readLineFile(File dataFile);
    int8_t parsAnyFile(String line);
    void parsCalibratFile(String line);


  public:
    uint16_t count(String Directory);
    void loadCalibratFile();
    void writeCalibratFile();
    void loadAnyFile(String product);
    void storeData(String path,String fileName);
    //generic var

String folder_name;
String generic_auto_run;
String generic_store_name;
String generic_lux;
String generic_instruction_screen;
String generic_test_screen;
String testing_instrument_number;
uint16_t testing_tefpro_number;
uint16_t set_lux_to_twilight;
uint16_t set_lux_to_winter;
uint16_t set_lux_to_summer;
float generic_high_limit;
float generic_low_limit;

bool scanner;
bool nullabgleich;
bool transmissionOff;
bool transmissionOn;
bool finalReport;
bool flickerDetection;
bool barDetection;
};




#endif
-----------------------------------------------------------------------------------------------
udt_tramp.cpp

/*
 Name:		UDT_TRAMPLib.cpp
 Created:	28.09.2016 10:28:47
 Author:	mala
 Editor:	http://www.visualmicro.com
*/

#include "UDT_TRAMP.h"
#include <math.h>  



void UDT_TRAMP::begin() 
{
	begin(0);
}
void UDT_TRAMP::begin(uint8_t adrr_mcp23008)
{
	_mcp.begin(adrr_mcp23008);
	_ads.begin();


	_mcp.pinMode(0, OUTPUT);	//Range 3
	_mcp.pinMode(1, OUTPUT);	//Range 2
	_mcp.pinMode(2, OUTPUT);	//Range 1
	_mcp.pinMode(7, INPUT);		//OVLD

	_mcp.digitalWrite(0, LOW);
	_mcp.digitalWrite(1, LOW);
	_mcp.digitalWrite(2, LOW);
	_exponent = 3;
}

//Overload, udt reached OVLD, which means that analog voltage is over a certain output level and it is necessary to switch to an other amplification factor
bool UDT_TRAMP::getOVLD()
{
	return !_mcp.digitalRead(7);
}

//set udt to a certain amplification factor
void UDT_TRAMP::setRange(uint8_t r)
{
	if (r < 3) { r = 3; }
	if (r > 10) { r = 10; }
	_exponent = r;

	switch (r) 
	{
		case 3: _mcp.digitalWrite(2, LOW); _mcp.digitalWrite(1, LOW); _mcp.digitalWrite(0, LOW); break;
		case 4: _mcp.digitalWrite(2, HIGH); _mcp.digitalWrite(1, LOW); _mcp.digitalWrite(0, LOW); break;
		case 5: _mcp.digitalWrite(2, LOW); _mcp.digitalWrite(1, HIGH); _mcp.digitalWrite(0, LOW); break;
		case 6: _mcp.digitalWrite(2, HIGH); _mcp.digitalWrite(1, HIGH); _mcp.digitalWrite(0, LOW); break;
		case 7: _mcp.digitalWrite(2, LOW); _mcp.digitalWrite(1, LOW); _mcp.digitalWrite(0, HIGH); break;
		case 8: _mcp.digitalWrite(2, HIGH); _mcp.digitalWrite(1, LOW); _mcp.digitalWrite(0, HIGH); break;
		case 9: _mcp.digitalWrite(2, LOW); _mcp.digitalWrite(1, HIGH); _mcp.digitalWrite(0, HIGH); break;
		case 10: _mcp.digitalWrite(2, HIGH); _mcp.digitalWrite(1, HIGH); _mcp.digitalWrite(0, HIGH); break;
	}

}

//read analoge voltage and set range according to incoming voltage in a optimal range
void UDT_TRAMP::autoRange() 
{
	bool zuKlein = false;
	double mv = getMiliVolt(5);

	//Wenn weniger als 0.5V gemessen wird soll die Verstaerkung um 10 erhoeht werden
	if (mv < 500.0) { zuKlein = true; }
	// Ebenfalls soll die Verstaerkung erhoeht werden, wenn mehr als 10V (bei ganz kleinen Spannungen macht der ADC einen Feheler und gibt nicht 0 sondern 65534 aus) gemessen werden aber kein Overload ausgegeben wird
	if ((mv > 10000.0 && !getOVLD())) { /*Serial.println("ADC_Error -> Gain++");*/ zuKlein = true; }
	

	while (zuKlein) 
	{
		zuKlein = false;
		mv = getMiliVolt(5);
		if (mv < 500.0) { zuKlein = true; }
		if (mv > 10000.0 && !getOVLD()) { /*Serial.println("ADC_Error -> Gain++");*/ zuKlein = true; }
		setRange(_exponent + 1);
		if(_exponent==10){ zuKlein = false; } //Verstaerkung kann nicht weiter erhaerht werden -> Abbruch
		delay(100);
	}
	
	while (getOVLD() && (_exponent > 3)) {
		setRange(_exponent - 1);
    delay(100);
	}
}

//returns current range
uint8_t  UDT_TRAMP::getRange()
{
	return _exponent;
}

//reads ADC
uint16_t UDT_TRAMP::getADC()
{
	_ads.readADC_SingleEnded(0);
	delay(10);
	return _ads.readADC_SingleEnded(0);
}

//makes a certain amount of measurements of ADC in ADC steps
double UDT_TRAMP::getADC(uint8_t anzahlMessungen) 
{
	_ads.readADC_SingleEnded(0);
	delay(10); 
	int32_t summe = 0;
	for (int i = 0; i < anzahlMessungen; i++) { summe = summe + _ads.readADC_SingleEnded(0); delay(10); }//100 didnt help
	double r = (double)summe / (double)anzahlMessungen;
	return r;
}

//makes a certain amount of measurements of ADC in miliVolt
double UDT_TRAMP::getMiliVolt(uint8_t anzahlMessungen)
{
	double mV = getADC(anzahlMessungen);
	mV = mV*0.1875;
	return mV;
}

//calculates out of ADC value the measured value
double UDT_TRAMP::getMeasure()
{
	double resultat;

	resultat = getADC()*(pow(10, (7 - _exponent)));
  //resultat = getADC()*(pow(10, (7 - (_exponent-3))));
  //resultat = getADC()*(pow(10, (_exponent-3)));

	return resultat;
}
double UDT_TRAMP::getMeasure(uint8_t anzahlMessungen)
{
	double r = 0;
	for (int i = 0; i < anzahlMessungen; i++) {
		r = r + getMeasure();
	}
	r=r/ anzahlMessungen;

	return r;
}


//-----------------------------//
//		SST Calculation        //
//-----------------------------//

void UDT_TRAMP::nullabgleich()
{
	_nullabgleich = getMeasure();
}

//calculates out of the ADC the SST
double UDT_TRAMP::getSST() 
{
	double sst = 0;
	uint64_t val = 0;
	autoRange();

	

	if (_nullabgleich != 0)
	{
		val = getMeasure();
		double l0 = log10(_nullabgleich);
		double l = log10(val);
		double ld = l - l0;
		double vsst = (ld * 7) / 3;

		sst = 1 - vsst;
	}
  sst+=0.063; //Korrekturfaktor von Mess- Kalkulationsfehler TEFLAB
	return sst;
}

//calculates out of the ADC the SST
double UDT_TRAMP::getSST(uint8_t anzahlMessungen)
{
	double sst = 0;
	double val = 0;  
	autoRange();
	

	if (_nullabgleich != 0)
	{
		val = getMeasure(anzahlMessungen);
		double l0 = log10(_nullabgleich);
		double l = log10(val);
		double ld = l - l0;
		double vsst = (ld * 7) / 3;

		sst = 1 - vsst;
	}
  sst+=0.063; //Korrekturfaktor von Mess- Kalkulationsfehler TEFLAB
	return sst;
}
------------------------------------------------------------------------------------------------
udt_tramp.h


/*
 Name:		UDT_TRAMPLib.h
 Created:	20201006
 Author:	dasc

 Major change is; uint64_t is replaced with double. Because >12 SST we got sever precision issues. The resolution wasnt float, more like steps, so we lost information.

based on library:
 Name:    UDT_TRAMPLib.h
 Created: 28.09.2016 10:28:47
 Author:  mala
 
*/

//#define ADS1015_ADDRESS (0x48)
#define ADS1015_ADDRESS2 (0x49)

#ifndef _UDT_TRAMPLib_h
#define _UDT_TRAMPLib_h

#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <Adafruit_MCP23008.h>
#include <math.h> 

#if defined(ARDUINO) && ARDUINO >= 100
	#include "arduino.h"
#else
	#include "WProgram.h"
#endif
class UDT_TRAMP
{
private:
	  Adafruit_MCP23008 _mcp;
    Adafruit_ADS1115 _ads;
	uint8_t _exponent;
	double _nullabgleich;





public:
  UDT_TRAMP(uint8_t addr = ADS1015_ADDRESS): _ads{addr}
  {
    // Constructor
  }
  
	void begin();
	void begin(uint8_t adrr_mcp23008);


	bool getOVLD();

	void setRange(uint8_t r);
	uint8_t getRange();
	double getMeasure(); //used to be uint64
	double getMeasure(uint8_t anzahlMessungen);
	void autoRange();

	uint16_t getADC();
	double getADC(uint8_t anahlMessungen);
	double getMiliVolt(uint8_t anzahlMessungen);

	void nullabgleich();
	double getSST();
	double getSST(uint8_t anzahlMessungen);

};


#endif
------------------------------------------------------------------------------------------------
lightsource.cpp

/*
  Name:    lightsource.cpp
  Created: xx.01.2021
  Author:  DASC
*/


#include <Arduino.h>
#include "lightsource.h"


void Light_Source::init(void)
{
  Serial3.begin(9600);
}

void Light_Source::setDl_off()
{
setDl_value(0);
}

void Light_Source::setDl_twilight()
{
  setDl_value(dl_twilight);
}

void Light_Source::setDl_winter()
{
  setDl_value(dl_winter);
}

void Light_Source::setDl_summer()
{
  setDl_value(dl_summer);
}

void Light_Source::setDl_value(uint16_t j)
{
  String command;
   
  if(j>4095){j==4095;}
  command = "SET " + String(j, DEC);
  Serial3.println(command);
}

------------------------------------------------------------------------------------------------
lightsource.h

/*
 Name:    light source
 Created: xx.01.2021
 Author:  DASC
*/

class Light_Source
{
protected:


public:

  void init(void);

  uint16_t dl_twilight;  
  uint16_t dl_winter; 
  uint16_t dl_summer; 
  
  void setDl_off();
  void setDl_twilight();
  void setDl_winter();
  void setDl_summer();
  void setDl_value(uint16_t newVal);
};

------------------------------------------------------------------------------------------------
main.h

#include <Wire.h>
#include "SD_Card.h"
#include "timer.h"
#include "matrix.h"
#include <stdio.h>
#include <string.h> 
#include "lightsource.h"
#include "UDT_TRAMP.h"
#include <avr/dtostrf.h>

// ethernet module
#include <Ethernet2.h>
#include <Dns.h>

//usb scanner
#include <KeyboardController.h>

//BUTTONS AND PINS
#define BUTTON1 22       //Button "CANCEL"
#define BUTTON2 23       //Button "OK"
#define BUTTON3 24       //Button "LEFT"
#define BUTTON4 25       //Button "UP"
#define BUTTON5 26       //Button "DOWN"
#define BUTTON6 27       //Button "RIGHT"

//FUNCTION PROTOTYPES
void checkButtonActivity();
void start();
void warmUpTimer();
void codePad();
void clearCode();
void serviceMain();
void serviceRTC();
void serviceCalibration();
void mainMenuSunglassOptray();
void mainMenuSunglassCyberOpticShades();
void mainMenuSunglassEkoi();
void updateIndices();
int8_t GenericTestFlow();
void runSpecificTest();
void testForAutomaticRun();
void finalReport();
void nullabgleich();
void transmissionOff();
void transmissionON();
void flickerDetection();
void barDetection();
void error(String error);
void scanner();
void keyReleased();
void printKey();
String extractStoredData(String header);
void storeData();
void fillInStoreData(float result);
void fillInStoreData(float result,String header);
void fillInStoreData(String data,String header);
void storeDataInSDCard();
byte uploadDataToFTP();
byte eRcv();
void deleteData();
int EndsWith(const char *str, const char *suffix); //capital letters because its reserved

//OBJECT
Timer g_warmUpTimer;

//GLOBAL VARIABLES
unsigned long g_startMillis_locked_repress;  
unsigned long g_currentMillis_locked_repress;  
const unsigned long g_period_locked_repress=1000;  //delay between pressing is 1000ms fast than that will be thrown away.

char g_outBuf[128];
bool g_flag_ethernet=true;
char g_input_code[4];
int g_printable_chars;
int g_input_index{0};
byte g_buttonPressed{255}; //stores the code/value of pressed button
byte g_state{255};  // stores the current state of state machine
bool g_retest;
bool g_automatic_run;
String g_errors[3];
bool flag_scanner=false;
String g_str_scanner="";
byte mac[] = { // MAC of the module, is given, labeled
  0xA8, 0x61, 0x0A, 0xAE, 0x70, 0x4F
};

uint8_t g_max_row_header=15; //count g_str_header_for_storage type the number here 
//Add new positions at the end, before {"END","END"}! It's the only way to go for excel power query
char g_str_header_for_storage[15][2][17]={
  {"PruefmittelNR",""},
  {"MachineType",""},
  {"TEST_DATE",""},
  {"TEST_TIME",""},
  {"Hans_ID",""},
  {"Trans_OFF",""},
  {"Trans_OFF_u","pct"},
  {"Trans_TWILIGHT",""},
  {"Trans_TWILIGHT_u","pct"},
  {"Trans_WINTER",""},
  {"Trans_WINTER_u","pct"},
  {"Trans_SUMMER",""},
  {"Trans_SUMMER_u","pct"},
  {"Error_Count",""},
  {"END","END"}
};

//Stores 0/90degree Transmission from Tramp
double g_Transmission0;
double g_TransmissionActual;
double g_TransmissionPercent;

//Stores 32degree Transmission from Tramp_2
double g_Transmission0_2;
double g_TransmissionActual_2;
double g_TransmissionPercent_2;

//##LOCAL DEBUG FTP SERVER ADDRESS
//const char* dns_name_of_server="172.16.3.107"; //type in the address of ftp server for debug upload
//const String ftp_user="USER any";
//const String ftp_pw="PASS any";


enum LED
{
  LED_OFF,
  LED_GREEN,
  LED_ORANGE,
  LED_RED,
};

enum State{
  START,
  WARM_UP_TIMER,
  CODE_PAD,
  SERVICE_MAIN,
  SERVICE_RTC,
  SERVICE_CALIBRATION,
  MAIN_MENU_SUNGLASS_OPTRAY,
  MAIN_MENU_SUNGLASS_EKOI,
  MAIN_MENU_SUNGLASS_CYBER_OPTIC_SHADES

  };
------------------------------------------------------------------------------------------------
/*
 * Author: RIEN / DASC
 * Created: 13.03.2019
 * Version: 1.1
 * Last update: 10.04.2019
 * This library contains the functions for the Matrix Screen and the i2c functions needed to control it.
 */

#include "matrix.h"
#include <Wire.h>

#define ASCII_Format 0      //Define ASCII label format
#define SPAM_INTERRUPT 20   // Prevent Matrix Screen from crashing when data is spammed to updateLabel(). 10 ms is already Stable!
#define I2C_Address 0x28    //Define default 8bit I2C address of 0x50 >> 1 for 7bit Arduino

// This function activates the buzzer.
void TheMatrix::activateBuzzer(const short frequency, const short duration)
{
  char command[] = { 254, 187, (byte)(frequency >> 8), (byte)(frequency), (byte)(duration >> 8), (byte)(duration)};
  i2cWrite(command, sizeof(command));
}


/* This funtion reads the input (touch) from the Matrix screen using i2c-communications. The position touched
 * on the screen is determined by an ID, that is defined in the GTT Software.
 * The function returns ID 255 if the data read is not 252 and then 135 (in that order).
 * ID 255 has been defined as "do nothing" by the screen developers. They return -1 to an unsigned integer, 
 * which overflows to 255 on the Arduino DUE.
*/
byte TheMatrix::getID()
{
    byte data{i2cRead()};  //Read the command prefix
    //  Serial.print("data0:");Serial.println(data);
    
    if (data == 252) // Magic number!
    {
        //Serial.print("data1:");Serial.println(data);
        data = i2cRead();  //Read the touch prefix
        //      Serial.print("data2:");Serial.println(data);
        if (data == 135) // Magic number!
        {
            int message_length{i2cRead() << 8 | i2cRead()};  //Read mesage length
            byte event{i2cRead()};   //Read event type
            byte id{i2cRead()};  //Read region that generated the touch response
            //Serial.print("getID(), id: "); Serial.println(id);
            return id;
        }
    }
    return 255;   // Reserved ID for automatic break.
}

/*This function reads one byte over i2c
 */
byte TheMatrix::i2cRead()
{
  //  Serial.println("inI2cRead");
  do 
  {
    Wire1.requestFrom(I2C_Address, 1);
  } while (Wire1.available() < 1);
  //    Serial.println("outI2cRead");
  return (Wire1.read());
}

/*This function writes an array of bytes (C-style string) over i2c
 */
void TheMatrix::i2cWrite(const char *data, const byte data_length)
{
  Wire1.beginTransmission(I2C_Address);

  for (int i = 0; i < data_length; i++) 
    Wire1.write(data[i]);

  Wire1.endTransmission();
}

/* ???
 */
void TheMatrix::runLEDstate(const byte index, const byte state) { //whole screen
  char command[] = { 254, 195, index, state};
  i2cWrite(command, sizeof(command));
}

/* These functions write image-files to the Matrix screen in the form of backgrounds.
 */
void TheMatrix::runScriptFile(const String &s) {
  //Serial.print("inRunScriptFileString&s:"); Serial.println(s);
  delay(50); // Soll verhindern wenn Button gelesen wird und sofort geschrieben wird, dass Display nicht abstürtz. Etwa Faktor 2x als sicherheit.
  char command[] = { 254, 93};
  i2cWrite(command, sizeof(command));

  int len = s.length();
  char arr[len + 1];
  s.toCharArray(arr, len + 1);
  i2cWrite(arr, len);

  char terminator[] = {0};
  i2cWrite(terminator, 1);
}

void TheMatrix::runScriptFile(const char *message, const byte messageLength) { //whole screen
  char command[] = { 254, 93};
  i2cWrite(command, sizeof(command));
  i2cWrite(message, messageLength);
  char terminator[] = {0};
  i2cWrite(terminator, 1);
}

void TheMatrix::runScriptFile(const __FlashStringHelper *ifsh) {
  delay(50); // Soll verhindern wenn Button gelesen wird und sofort geschrieben wird, dass Display nicht abstürtz. Etwa Faktor 2x als sicherheit.
  char command[] = { 254, 93};
  i2cWrite(command, sizeof(command));
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  PGM_P p2 = reinterpret_cast<PGM_P>(ifsh);
  size_t n = 0;
  int len = 0;
  while (1) {
    unsigned char d = pgm_read_byte(p2++);
    len++;
    if (d == 0) break;
  }
  char arr[len];
  int x = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    arr[x] = c;
    x++;
    if (c == 0) break;
  }
  i2cWrite(arr, len - 1);

  char terminator[] = {0};
  i2cWrite(terminator, 1);
}

/* This function sets the label font colour.
 */
void TheMatrix::setLabelFontColour(const byte index, const byte red, const byte green, const byte blue)
{
  char command[] = { 254, 21, index, red, green, blue};
  i2cWrite(command, sizeof(command));
  //Response will be handled by loop()
}


/* These functions write a message into a label on the Matrix Screen. 
 * Index is the ID of the label? The message to be shown on the label is passed into the 
 * function as a string. Because i2cWrite() can only process C-style string, the message 
 * is converted into one before it is passed to i2cWrite(). A null terminator is sent after 
 * the end of the new C-style string. 
 */
void TheMatrix::updateLabel(const byte index, const String &message, const byte message_length)
{
  char command[] = { 254, 17, index, ASCII_Format }; // Magic Numbers!
  i2cWrite(command, sizeof(command));

  int len = message.length() + 1;
  char c_message[len];
  message.toCharArray(c_message, len);
  i2cWrite(c_message, message_length);
  
  char terminator[] = { 0 };
  i2cWrite(terminator, 1);

  delay(SPAM_INTERRUPT);
}

void TheMatrix::updateLabel(const byte index, const char *c)
{
  char command[] = { 254, 17, index, 0 };
  i2cWrite(command, sizeof(command));

  int len = strlen(c);
  i2cWrite(c, len);

  char terminator[] = { 0 };
  i2cWrite(terminator, 1);

  delay(SPAM_INTERRUPT);
}

//untested function
void TheMatrix::updateLabel(const byte index, const String &s)
{
  char command[] = { 254, 17, index, 0 };
  i2cWrite(command, sizeof(command));

  int len = s.length();
  char arr[len + 1];
  s.toCharArray(arr, len + 1);
  i2cWrite(arr, len);

  char terminator[] = { 0 };
  i2cWrite(terminator, 1);

  delay(SPAM_INTERRUPT);
}

void TheMatrix::updateLabel(const byte index, const uint32_t n)
{
  char buffer [33];
  byte size;
  char command[] = { 254, 17, index, 0 };
  i2cWrite(command, sizeof(command));
  itoa(n, buffer, 10);
  int len = strlen(buffer);
  i2cWrite(buffer, len);
  char terminator[] = { 0 };
  i2cWrite(terminator, 1);

  delay(SPAM_INTERRUPT);
}

void TheMatrix::updateLabel(const byte index, const __FlashStringHelper *ifsh)
{
  char command[] = { 254, 17, index, 0 };
  i2cWrite(command, sizeof(command));

  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  PGM_P p2 = reinterpret_cast<PGM_P>(ifsh);
  size_t n = 0;
  int len = 0;
  while (1) 
  {
    unsigned char d = pgm_read_byte(p2++);
    len++;
    if (d == 0) break;
  }
  char arr[len];
  int x = 0;
  while (1) 
  {
    unsigned char c = pgm_read_byte(p++);
    arr[x] = c;
    x++;
    if (c == 0) break;
  }
  i2cWrite(arr, len - 1);

  char terminator[] = { 0 };
  i2cWrite(terminator, 1);

  delay(SPAM_INTERRUPT);
}
------------------------------------------------------------------------------------------------
matrix.h

/*
 * Author: RIEN
 * Created: 13.03.2019
 * Version: 1.1
 * Last update: 10.04.2019
 * Header file for the Matrix Screen (matrix.cpp) and its funtions.
 */

#ifndef MATRIX_H
#define MATRIX_H

#include <Wire.h>

/* TheMatrix is a Monostate and therefor does not need to be defined!
 * This can be changed if the need for 2 Matrix screens on the same device ever arises.
 */
class TheMatrix
{
public:
    static void activateBuzzer(const short frequency, const short duration);
    static byte getID();
    static void runLEDstate(const byte index, const byte state);
    static void runScriptFile(const char *message, const byte messageLength);
    static void runScriptFile(const __FlashStringHelper *ifsh);
    static void runScriptFile(const String &s);
    static void setLabelFontColour(const byte index, const byte red, const byte green, const byte blue);
    static void updateLabel(const byte index, const String &message, const byte message_length);
    static void updateLabel(const byte index, const char *c);
    //static void updateLabel(byte index, char c[]); //changed to pointer
    static void updateLabel(const byte index, const String &s);
    static void updateLabel(const byte index, const uint32_t n);
    static void updateLabel(const byte index, const __FlashStringHelper *ifsh);

private:
    static byte i2cRead();
    static void i2cWrite(const char *data, const byte data_length);
};

#endif  // MATRIX_H

------------------------------------------------------------------------------------------------
timer.cpp

/*
 * Author: RIEN
 * Created: 03.05.2019
 * Version: 1.0
 * Last update: -
 * This library contains the functions for the Timers.
 */

#include "timer.h"
#include "Arduino.h"
#include <RTClib.h>

////////////////////////////////////////////////////////////////////////////////
// Timer implementation

// Constructor for passing a timespan variable.
Timer::Timer(const TimeSpan &timeSpan) : m_duration{timeSpan}
{
    //
}

// Constructor for passing time values directly
Timer::Timer(int16_t days, int8_t hours, int8_t minutes, int8_t seconds)
    : m_duration{days, hours, minutes, seconds}
{
    //
}

// Copy Constructor
Timer::Timer(const Timer &copy) : m_duration{copy.m_duration}
{
    //
}

/* Updates the Timer to the time remaining. 
 */
void Timer::updateTimer()
{ 
    m_timer = m_timerEnd - RTC_PCF8523::now();

    if (m_timer.totalseconds() <= 0)
        m_timerDone = true;
}

// Warning: Because this function uses a piece of Hardware (the RTC) it has to be executed in or after setup()!
void Timer::resetTimer()
{ 
    m_timerDone = false;
    m_timerEnd = RTC_PCF8523::now() + m_duration; 
}

int32_t Timer::getRemainingSeconds() 
{
    if (m_timerDone)
        return -1;

    updateTimer();
    return (m_timer.totalseconds() >= 0 ? m_timer.totalseconds() : -1);
}

int8_t Timer::getRemainingMinutes() 
{
    if (m_timerDone)
        return -1;
        
    updateTimer(); 
    return  (m_timer.minutes() >= 0 ? m_timer.minutes() : -1);
}

-------------------------------------------------------------------------------------------------
timer.h

/*
 * Author: RIEN
 * Created: 13.05.2019
 * Version: 1.0
 * Last update: -
 * Header file for Timers (timer.cpp) and its funtions.
 */

#ifndef TIMER_H
#define TIMER_H

#include "Arduino.h"
#include <RTClib.h>

// Class for all timers, e.g. warmup, recalibration, ect.
// A new timer needs to be defined before it can be used. The default timer duration is 30 minutes.
class Timer
{
protected:
    const TimeSpan m_duration;
    DateTime m_timerEnd{0};
    TimeSpan m_timer;
    bool m_timerDone{true};

private:
    void updateTimer();

public:
    // Constructor for passing a timespan variable. Default 30 minutes
    Timer(const TimeSpan &timeSpan  = TimeSpan{0, 0, 10, 0});

    // Constructor for passing time values directly
    Timer(const int16_t days, const int8_t hours, const int8_t minutes, const int8_t seconds);

    // Copy Constructor
    Timer(const Timer &copy);

    const TimeSpan& getDuration() { return m_duration; }
    void resetTimer();
  
    //In order to prevent overflow after a long time span, these get-functions are a bit more complex.
    int32_t getRemainingSeconds();
    int8_t getRemainingMinutes();
}; // end class Timer

#endif
-------------------------------------------------------------------------------------------------
 


Thanks!

How about posting links to your components and your schematic?

Also details of power supply. SD cards and Ethernet adaptors can be quite power hungry and have been known to cause freezes/resets during startup.

shields:
Arduino Ethernet Shield 2 — Arduino Official Store SD-Card slot is used for project.

  • selfmade shield with RTC chip only on top

Daughterboards:
Infrared 4-channel (selfmade)
Transimpedanceamplifier controllerboard (selfmade) (MCP23xxx and a ADC 16bit) Transimpediance Amplifiers – Gamma Scientific
Max 2323 for Ligthsource RS232 communication.

Display:
https://www.matrixorbital.com/communication-protocol/i2c/egtt70a
set up with: 5V i2c

We have 3.3V / 5V and 24VDC powersupplys in use. The amps i dont know now. I might look it up.

I check all supply voltage and its in range or right on spot.

IMHO the issue is likely in SW.

What i still do not get is that on the running machine the set up its working flawlessly. On the prototype it freezes during start up which makes no sense to me. For now i can not risk the running machine with a compile and upload as long as the prototype has an issue.

Thank you for your support. I try to improve my programming skills so any suggestion is welcome. I guess RAM migth be an issue here. But really dont know it for shure.

thanks.

You should. The Amps are equally important as the Volts!

Which voltage are you using when the problem occurs?

I suggest you need to break the problem down. Test each major component in isolation. If they all run ok, begin combining two of them to see if there is some conflict. Then add more components in until the problem occurs. Hopefully this will give you some clue as to which combination or circumstance triggers the freeze.

I do exactly this in the coming few days. I'll report back as soon i know more. I think its a good plan to check the HW thoroughly first.

It seems for me, even the code is big, that no one found in the short time an obvious issue.

Thank you.

i tried to run the code on two diffrent arduino due boards with nothing connected to it. just the arduino board. it freezes in the exact same spot. so in my opinion it has nothing to do with hardware. It should run trough setup with the bare board but it doesnt. so? the code migth be the issue here. any help? suggestions?

i ran older code, 6 month back in time, but the same behavior. i'm guessing more and more somthing is wrong with my windows, drivers, compiler etc.

i deinstalled 1.8.10. restart. installed 1.8.16. restart. same issue.
i tried with putty serial monitor same behavior.
:nauseated_face:

I uninstalled my bluethooth earbuds. Because it was in the Port menue as com92 and com93 listed. then i uploaded again to a bare minimum arduino board. and it ran to hello8. i thougth, well..., i fixed it but NO. i connected to the prototype system again and uploaded to the machine with all the boards and it freezed in the exact same spot. then again on the bare minimum board, same freeze.
Somehow i have to clean all the usb driver coms whatever it is called. becaus the issue lays there. Because after i uninstalled the earbuds it ran once.
how can i do this?

I programmed it then i opened the serial monitor to take a look at helloX. Then i closed it and opened it again. 4 Times it ran to Hello8 but 20 times it freezed as in first post discribed. With bare minimum arduino board.

I also tested on a completly other computer. The same behavior. All tests with the bare minimum arduino board nothing attached.

What the heck is that?

Tried in the board manager 1.6.4 up to 1.6.12, no change in behavior.
Reinstalled USB-COM driver, no change in behavior.
Using 1.8.16 platform, no change in behavior.
Tried with 3 diffrent Due's from 2 diffrent vendor, no change in behavior.

What else can i do?

Nobody is going to be able to tell you where the problem is. You need to DEBUG. You know it is fetting at least as far as printing "hello4", so put the following line of code:

while(1);

right after the Serial.println("hello5"), and see if it gets there. If it does not print "hello5", then you know it's hanging in udt2.begin(). If it does print "hello5", then move the while(1); down after the Serial.println(hello6"). Continue moving it down until it hangs, and you'll know exactly which function is hanging.

I updated MCP and ADS libraries from github. Little change in code for the new libraries. At least it runs through to hello8. But it needs further testing then it may broke other parts of code with the new libraries. testing will give clarification.

To make this thread complete. It wasn't the librarys. I ran out of RAM. I read Arduino-Strings-How-to-Avoid-Memory-Issues and changed + with += and the program runs now. i may change even more as advised in the link. cya