W5100 server and client problem

Hi,

I have a W5100 sheild and Mega2560 working fairly well as a server. The Windows PC client requests data (actcually temperature and voltages ) every second from the server and the server responds with the required data.
The server serves the HTML webpage from a sd card on the w5100 but the actual data is generated in the Mega2560.

The system works ok most of the time, but from time to time the server fails to server the data for about 10 seconds before coming back to life.

The problem is I don't know how to fault find where the problem lies.

When the server responds I also toggle a digital output line which is how I know the server is not responding.

But it could equally be that the windows client has stopped requesting or the server is dropping the requests for some uknown reason.

I'd appreciate some guidance on how to fault find this problem. The code is based on the server example.

Regards Tim

Can you not use Serial Monitor, inserting debug messages appropriately in your code to figure out where it's taking a nap? My guess would be, you've either got a sluggish chunk of code somewhere, or something's fishy with the SD, but without debug, you're flying blind.

Hi Thanks for the reply / suggestion.

As it turns out I've tried that and it seems to be looping just fine.
In fact I measured the time it takes to execute all of the functions in the main loop and discovered that the temp sensor was taking 200mS to respond so I fixed the code code to only periodically take temperature readings just in case that was the problem.

However as the client only requests data every second the server has plenty of time to respond.

Some times the system will run perfectly for hours on end then it'll drop out for 10 seconds before recommencing.

There's no congestion on my local network and ping times are consistently sub 1mS.
I just need to determine if it's a client or server problem.

My gut tells me its the chrome browser on the client side not talking to the server - but I have no idea how to check this - maybe I need to use wireshark somehow to see if the client is sending the request every second as expected?

Thanks Tim

Experienced same issues. Turns out, since the outdated w5100 chip use same spi bus as the sd card on the cheap chinese modules, you get into connection problems when reading from the sd card, like big files. Solution, ditch the common spi bus....

You've no way to flag when a request is sent, when it's 'on the wire', and when it's acknowledged in the receiver? If that's the case, can't help you. Someone else will come along...

But that, should be sniffable with SM. Issue debug characters. 'R', 'F', 'G', 'S'. Received request, Fetching Data, Got Data, Sent Data. If the pattern you see in Serial Monitor's timestamps changes, you've got it.

Interesting - I hadn't considered SPI contention, guess I need to look into that further but given the SD card would only be required to serve the main webpage once at the start and data transfers are taken care of by Ajax then there shouldn't be any contention ?

Wish I was better at this kind of debug......

Yep tried that and when it goes quiet there is no received request to start the transfer.

How could we possibly know, you do not present any code, wiring setup or complete hardware list. So we present simple assumptions for your mystery. In the mean while, you should consider the advise of use the serial monitor as debugging tool.

So you're saying your 'request' is sent on schedule from the source, and sometimes circles the planet for a while before arriving at the receiver. Interesting. Can't help you, you're right, you need to see what's 'on the wire', when, with reference to events at both ends.

I did think about posting the code but I'm more interested in debugging tips / tools to use to find the root cause.
I'm an electronics engineer with 50 years man and boy experience so pretty sure my hardware is ok plus the code works 99% of time - just this annoying glitch which creeps in from time to time.

My usual solution is to walk away from the problem for a few days then take a fresh look and see what happens - but so far this hasn't worked :slight_smile:

I'll prepare the code for posting including the HTML sd card file.

Regards Tim

here's the arduino code quite a lot of it and after this is the html file.

It's based on code wrtten by F6AAM but tweaked to my needs - apologies for the size and style of the code - but it does work, sort off ...


/* The following code is a modified / simplified version of Télémesure et commande d'un PA DATV pour QO100 par liaison ethernet (F6AAM) */
 
#include <avr/wdt.h>  
#include <EEPROM.h>   
#include <SPI.h>      
#include <Ethernet.h> 
#include <SD.h>       
#include <OneWire.h>  

#include "look_up_tables.h"


volatile long ii,jj;

const int DS18B20_PIN = 5; // was 40
const int DS18B20_ID=0x28;

OneWire ds(DS18B20_PIN); // on pin DS18B20_PIN (a 4.7K resistor is necessary)

float DS18B20_temperature;

const byte RESOLUTION_12_BITS = 0b01111111; // 800 ms
const byte RESOLUTION_11_BITS = 0b01011111; // 400 ms
const byte RESOLUTION_10_BITS = 0b00111111; // 200 ms
const byte RESOLUTION_9_BITS = 0b00011111;  // 100 ms

// ----------- variables for RF power 
int iii;

float level_CH_1;
float level_CH_2;
float seuil_R_P_HF;


char str_valeur[10] = {0};
char str_valeur2[10] = {0};
char str_valeur3[10] = {0};
char str_valeur4[10] = {0};

byte web_page = 1;

/******************************************************************/

// -------- variables for EEPROM

static const unsigned long STRUCT_MAGIC = 123456780; // si modifié le logiciel rechargera les valeurs de limites par défaut définie plus bas
// De plus au tout premier lancement du programme sur la platine Arduino, les valeurs par défaut seront chargées dans l'EEPROM qui est évidemment vide !!


// eeprom stucture for high and low limits 
struct MaStructure {
  unsigned long magic;
  float lim_temp_haute;
  float lim_temp_basse;
  float lim_U_PA;
  float lim_I_PA;
  float lim_Dir_RF;
  float lim_Refl_RF;

  float lim_htr_high ; // temp when htr turns off
  float lim_htr_low ;  // temp when htr turns on
   
};
/** global variables  */
MaStructure ms;
MaStructure ms_lue;
//MaStructure ms_Adjust_HF;
/******************************************************************/
const int SERIAL_PORT=9600; // pour débogage avec le moniteur série
/******************************************************************/
// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   100
/******************************************************************/
// MAC address from Ethernet shield sticker under board
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xAA, 0xAA };
IPAddress ip(192, 168, 1, 23);   // IP address, may need to change depending on network
EthernetServer server(80);       // create a server at port 80
File webFile;                    // the web page file on the SD card
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0;              // index into HTTP_req buffer

boolean Relay_PTT = 0; // stores the states of the Relays
boolean Relay_PA = 0;
boolean Relay_FAN = 0;
boolean Relay_AUX = 0;
boolean Watchdog = 0;
boolean alarm_T_PA_Arduino = 0;
boolean alarm_U_PA_Arduino = 0;
boolean alarm_I_PA_Arduino = 0;
boolean alarm_Dir_power_Arduino = 0;
boolean alarm_Refl_power_Arduino = 0;
boolean maj_EEPROM = 0;

boolean req_lim = 0; // pour savoir si une demande des limites est faite par le client

// variables to store min and max values

float T_PA_max = 0;
float U_PA_max = 0;
float I_PA_max = 0;
float Dir_RF_max = 0;
float Refl_RF_max = 0;
float U_PA, I_PA;
unsigned long temp_update_timer = 0 ;

byte count_envoi_index = 0;

 byte addr[8];

//this function setups up and starts the watchdog timer
void setWDT(byte sWDT) {
   WDTCSR |= 0b00011000;
   WDTCSR = sWDT |  WDTO_2S; //Set WDT based user setting and for 2 second interval
   wdt_reset();
}

byte PA_OFF_ON_LINK_OFF = 0; // variable qui determine si le serveur coupe les relais PA et PTT sur une coupure de liaison ethernet

ISR (WDT_vect) // routine d'interruption executée si la liaison ethernet est coupée (le Watchdog n'a pas été remis à zéro dans un délai de 2 secondes)
{
  if (PA_OFF_ON_LINK_OFF == 1) { // si l'utilisateur a choisi de couper PTT et PA en cas de coupure liaison ethernet
    // on coupe le PTT 
    Relay_PTT = 0;  // save Relay state
    digitalWrite(6, LOW); 
    // delay manually as we're in an ISR
    for (ii = 1; ii <= 1000; ii++) {
       for (jj = 1; jj <= 500; jj++) {
       }
    }
    // puis on coupe l'alim PA 
    Relay_PA = 0;  // save Relay state
    digitalWrite(7, LOW); 
  }  
}  // end of WDT_vect

void setup()

{
 
    cli();// disable all interrupts
    wdt_disable();  // Disable the watchdog and wait for more than 3 seconds 
    delay(3000);  // Done so that the Arduino doesn't keep resetting infinitely in case of wrong configuration 
    setWDT(0b01000000); //set watchdog for interrupt
    sei();//enable interrupts
  
    web_page = 1;

    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    
    Serial.begin(115200);       // for debugging
    
    // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        Serial.println("ERROR - Can't find index.htm file!");
        return;  // can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");

    
  // set up temp sensor
  ds.search(addr);
  changeResolution( addr, RESOLUTION_9_BITS);
  DS18B20_temperature = getTemperatureDS18b20();

    // Relays
    pinMode(6, OUTPUT);
    pinMode(7, OUTPUT);
    pinMode(8, OUTPUT);
    pinMode(9, OUTPUT);
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);

    pinMode(2, OUTPUT);
    digitalWrite(2, LOW);
    
    Ethernet.begin(mac, ip);  // initialize Ethernet device
    server.begin();           // start to listen for clients
    
    Serial.print("\nLe serveur est sur l'adresse : ");
    Serial.println(Ethernet.localIP()); //on affiche l'adresse IP de la connexion

    // Charge la mémoire EEPROM
    chargeEEPROM();

}


/** Sauvegarde en mémoire EEPROM le contenu actuel de la structure */
void sauvegardeEEPROM() {
  // Met à jour le nombre magic et le numéro de version avant l'écriture
  ms.magic = STRUCT_MAGIC;
 
  //Serial.println("*******************************INITIALISATION EEPROM ****************************/");
  EEPROM.put(0, ms);
}

/** Charge le contenu de la mémoire EEPROM dans la structure */
void chargeEEPROM() {
Serial.print("STRUCT_MAGIC = ");Serial.println(STRUCT_MAGIC);

  // Lit la mémoire EEPROM
  EEPROM.get(0, ms);
  
  // Detection d'une mémoire non initialisée
  byte erreur = ms.magic != STRUCT_MAGIC;

  if (erreur) {
    Serial.println("ms.magic != STRUCT_MAGIC");
    // Default values ​​for the very first start of the program
    
    ms.lim_temp_haute = 50.0;
    ms.lim_temp_basse = 30.0;
    ms.lim_U_PA = 33.0;
    ms.lim_I_PA = 14.0;
    ms.lim_Dir_RF = 51.50;     // > 100W
    ms.lim_Refl_RF = 39.0;    // 8W

    ms.lim_htr_high = 8 ; // htr off at > 8
    ms.lim_htr_low  = 3 ;  // htr on at  < 4
    
    // Sauvegarde les nouvelles données
    sauvegardeEEPROM();
  }

}

void mesures() { // takes 22mS without measuring temp

 
    EEPROM.get(0, ms_lue); // takes 80uS

    if (DS18B20_temperature >  ms_lue.lim_temp_haute) { // on ne veut pas dépasser le seuil de Température

      T_PA_max = DS18B20_temperature; // on garde la valeur qui a dépassé le seuil max
      // on coupe le PTT immédiatement 
      Relay_PTT = 0;  // save Relay state
      digitalWrite(6, LOW); // on coupe le relais PTT
      //delay(500); // on temporise pour ne pas couper le relai PA au maximum de courant
      Relay_PA = 0;  // save Relay state 
      digitalWrite(7, LOW); // puis on coupe le relais PA
      alarm_T_PA_Arduino = 1; 
    }

 
 // control htr aux relay

     if (DS18B20_temperature < ms_lue.lim_htr_low  && Relay_AUX != 1 ) {            // on ne veut pas dépasser le seuil de tension PA     
      Relay_AUX = 1;  // save Relay state
      digitalWrite(9, HIGH); // on coupe le relais PTT
    }



     if (DS18B20_temperature > ms_lue.lim_htr_high && Relay_AUX != 0 ) {            // takes 10uS
      
      Relay_AUX = 0;  // save Relay state
      digitalWrite(9, LOW); // on coupe le relais PTT

    }

 
    // control fan relay
    // turn off fan if psu off & temp 2 below on threshold and tx off OR psu on & temp 2 below on threshold and tx off
     if ((DS18B20_temperature < (ms.lim_temp_basse - 2)  && Relay_PA == 0  && Relay_PTT == 0  && Relay_FAN == 1) || (DS18B20_temperature < (ms.lim_temp_basse -2 ) && Relay_PA == 1  && Relay_PTT == 0) && Relay_FAN == 1) 
          {                  
            Relay_FAN = 0;  // save Relay state
            digitalWrite(8, LOW); // turn off fan
          }

   // turn on fan if on tx regardless or keep /turn it on if tempis above threshold

     else if (( Relay_PTT == 1 && Relay_FAN == 0 ) || (DS18B20_temperature > ms.lim_temp_basse && Relay_FAN == 0  ) )
          {
            Relay_FAN = 1;  // save Relay state
            digitalWrite(8, HIGH); // turn off fan
          }
 
    // measure PA Vdd takes 6mS

    float U;
    U = analogRead(2); // on mesure la tension U sur A2
    for(iii=0;iii<49; iii++)                 // iii = counter index      
        U  =  U + analogRead(2);       // on fait 49 lectures
    U  = U/50 ;                        // on fait la moyenne
    U_PA = U /25.33 ;       // formule issue de l'EEPROM was 25.5
    if (U_PA > ms_lue.lim_U_PA) {            // on ne veut pas dépasser le seuil de tension PA
      U_PA_max = U_PA;                       // on garde la valeur qui a dépassé le seuil max
      // on coupe l'alim PA immédiatement 
      Relay_PTT = 0;  // save Relay state
      digitalWrite(6, LOW); // on coupe le relais PTT
      
      Relay_PA = 0;  // save Relay state 
      digitalWrite(7, LOW); // puis on coupe le relais PA
      alarm_U_PA_Arduino = 1;
 
    }

  
    // measure PA Idd and use for power output takes 16mS
    float I;
    I = analogRead(3); // on mesure le courant I_PA sur A3
    for(iii=0;iii<127; iii++)                       // iii = counter index      
        I  =  I + analogRead(3);              // on fait 199 lectures
    I  = I/128 ;                              // on fait la moyenne

    I_PA = I * 0.01491 ; //  conver bit count to amps

    if (I_PA > ms_lue.lim_I_PA) {                   // on ne veut pas dépasser le seuil de courant PA
      I_PA_max = I_PA;                              // on garde la valeur qui a dépassé le seuil max
      Relay_PTT = 0;  // save Relay state
      digitalWrite(6, LOW); // on coupe le relais PTT
      Relay_PA = 0;  // save Relay state 
      digitalWrite(7, LOW); // puis on coupe le relais PA
      alarm_I_PA_Arduino = 1; 
    }

    
    // RF power forward power measurement  takes 120uS 

    level_CH_1 = calculate_power_CH_1(); 
    if (level_CH_1 > ms_lue.lim_Dir_RF) {         // on ne veut pas dépasser le seuil de puissance directe
      Dir_RF_max = level_CH_1;                    // on garde la valeur qui a dépassé le seuil max
      Relay_PTT = 0;                              // save Relay state
      digitalWrite(6, LOW);                      // on coupe le relais PTT
      Relay_PA = 0;                               // save Relay state 
      digitalWrite(7, LOW);                      // puis on coupe le relais PA
      alarm_Dir_power_Arduino = 1;    
    } 
 


    level_CH_2 = calculate_power_CH_2(); // takes 180uS to end

    seuil_R_P_HF = ms_lue.lim_Refl_RF;

    if (level_CH_2 > seuil_R_P_HF) {              // on ne veut pas dépasser le seuil de puissance réfléchie

      Refl_RF_max = level_CH_2;                   // on garde la valeur qui a dépassé le seuil max
      // on coupe le PTT immédiatement 
      Relay_PTT = 0;                              // save Relay state
      digitalWrite(6, LOW);                      // on coupe le relais PTT
      Relay_PA = 0;                               // save Relay state 
      digitalWrite(7, LOW);                      // puis on coupe le relais PA
      alarm_Refl_power_Arduino = 1;   
    } 
 
    
}

void loop() { 

  
    
    EthernetClient client = server.available();  // try to get client

if (temp_update_timer <= millis()) 
       {
           temp_update_timer = millis() + 5000 ; // Delay to limit speed of update 
    DS18B20_temperature = getTemperatureDS18b20(); // On lance la fonction d'acquisition de T°
    Serial.print("time to measure temp ");
    Serial.println(DS18B20_temperature);

       }

    mesures(); // takes 22mS as temp now only checked every 5 seconds

    if (client) {  // got client? takes 60mS to execute
      digitalWrite(2, HIGH);
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                
                if (c == '\n' && currentLineIsBlank) {
                    
                    wdt_reset();  /* Reset the watchdog */
                    
                    client.println("HTTP/1.1 200 OK");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();

                        // we test if loading request advanced version
                        if (StrContains(HTTP_req, "&advanced")) { // request to load the advanced.htm page to the next new client
                          web_page = 1; 
                        }

                      
                        // we test if loading request short version
                        if (StrContains(HTTP_req, "&short")) { // request to load the index.htm page to the next new client
                          web_page = 2;   
                        }
                        
                        
                        // we test the action to be taken if an Ethernet link cut is detected
                        Read_req_coupure_PA_on_link_off();
                        
                        // we will test if a limits request is requested by the client (normally carried out each time the index page is loaded on the client side)
                        Read_req_lim();
                       
                        // control of relays and watchdog
                        SetRelays();
                        
                        // we test if new limits are sent by the client
                        if (!req_lim) {
                          // read the new limits sent by the client and if different, store them in the EEPROM
                          SetLimits();
                        }

                
                        // reseter éventuellement les alarmes si demandées par le client
                        Reset_alarme();
                        
                        // sending response to the customer containing measurements, relay status, alarms, etc.
                        XML_response(client);
                       
                    }
                    else {  // HTTP request for web page (only once when program start ! )
                      if (!(StrContains(HTTP_req, "favicon"))) {// certains Navigateurs demandent une image icon
                        // il ne faut donc pas envoyer 2 fois la page html ! Merci Yves F4HSL !
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println();

                        
                  
                        if (web_page == 1)
                        {
                          // send web page advanced.htm - contains version whith diplay, commands and calibration
                          webFile = SD.open("advanced.htm");       // open web page file
                        }
                      
                        else {
                        // send web page index.htm - contains version whith with only display
                          webFile = SD.open("index.htm");       // open web page file
                        }
                       
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // send web page to client
                            }
                            webFile.close();
                        }
                     }
                     else Serial.println(HTTP_req);
                    }
 
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(10);      // give the web browser time to receive the data
        client.stop(); // close the connection
          digitalWrite(2, LOW);
    } // end if (client)
}





void SetRelays(void) // lire les commandes du client pour actionner les relais
{
    // Relay 1 (pin 6) // pour le relais PTT
    if (StrContains(HTTP_req, "&PTT=1")) { // on inverse la sortie car la carte relais est active Ă  l'Ă©tat bas !
        Relay_PTT = 1;  // save Relay state
        digitalWrite(6, HIGH);
    }
    else if (StrContains(HTTP_req, "&PTT=0")) {
        Relay_PTT = 0;  // save Relay state
        digitalWrite(6, LOW);
    }
    // Relay 2 (pin 7) // pour le relais alim secteur PA
    if (StrContains(HTTP_req, "&PA=1")) {
        Relay_PA = 1;  // save Relay state
        digitalWrite(7, HIGH);
    }
    else if (StrContains(HTTP_req, "&PA=0")) {
        Relay_PA = 0;  // save Relay state
        digitalWrite(7, LOW);
        //Serial.println("DECODAGE MESSAGE DU CLIENT ' PA POWER OFF ' ");
        //Serial.println(HTTP_req);
    }
    // Relay 3 (pin 8) // pour le relais FAN (ventilateurs)
    if (StrContains(HTTP_req, "&FAN=1")) {
        Relay_FAN = 1;  // save Relay state
        digitalWrite(8, HIGH);
    }
    else if (StrContains(HTTP_req, "&FAN=0")) {
        Relay_FAN = 0;  // save Relay state
        digitalWrite(8, LOW);
    }
    // Relay 4 (pin 9) // non utilsé pour l'instant
    if (StrContains(HTTP_req, "&AUX=1")) {
        Relay_AUX = 1;  // save Relay state
        digitalWrite(9, HIGH);
    }
    else if (StrContains(HTTP_req, "&AUX=0")) {
        Relay_AUX = 0;  // save Relay state
        digitalWrite(9, LOW);
    }
   
}

void Reset_alarme() {
  if (StrContains(HTTP_req, "&Reset_alarme")) {
    alarm_T_PA_Arduino = 0;
    alarm_U_PA_Arduino = 0;
    alarm_I_PA_Arduino = 0;
    alarm_Dir_power_Arduino = 0;
    alarm_Refl_power_Arduino = 0;
  }
}



void Read_req_lim(void) // we test if a limits request is requested by the client
{
  if (StrContains(HTTP_req, "&str_req_lim")) req_lim = 1; 
  else req_lim = 0; 
}

void Read_req_coupure_PA_on_link_off(void) // we read what action to take if the ethernet connection is cut
{
  if (StrContains(HTTP_req, "&PA_off_on_link_off")) PA_OFF_ON_LINK_OFF = 1;
  if (StrContains(HTTP_req, "&NO_PA_off_on_link_off")) PA_OFF_ON_LINK_OFF = 0;  
}

void SetLimits(void) //
{
    
    EEPROM.get(0, ms_lue);
   //Affiche_EEPROM(); // pour debogger !

    maj_EEPROM = 0; // pour indiquer qu'il n'y aura pas Ă  priori de mise Ă  jour Ă  faire de l'EEPROM
   
    // lire les éventuelles nouvelles limites envoyées par le client
    
    if (StrContains(HTTP_req, "&Lim_temp_haute=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_temp_haute=");// on récupère le résultat dans la variable globale str_valeur
        ms.lim_temp_haute = (float) atof(str_valeur);
       
        str_valeur[0] = 0;
        // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_temp_haute != ms.lim_temp_haute){
           T_PA_max = 0;
           maj_EEPROM = 1;  
        }
    }


/////// Store htr off high temp to eeprom

 if (StrContains(HTTP_req, "&Lim_htr_high=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_htr_high=");
        ms.lim_htr_high = (float) atof(str_valeur);
       
        str_valeur[0] = 0;
        // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_htr_high != ms.lim_htr_high){
           maj_EEPROM = 1;  
        }

    }

/////// Store htr on low temp to eeprom

if (StrContains(HTTP_req, "&Lim_htr_low=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_htr_low=");
        ms.lim_htr_low = (float) atof(str_valeur);
        
        str_valeur[0] = 0;
        // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_htr_low != ms.lim_htr_low){
           maj_EEPROM = 1;  
        }

    }

/////////////////////////////////////////////////////////////////////////////////////////

    if (StrContains(HTTP_req, "&Lim_temp_basse=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_temp_basse=");
        ms.lim_temp_basse = (float) atof(str_valeur);
    
        str_valeur[0] = 0;
        // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_temp_basse != ms.lim_temp_basse){
           maj_EEPROM = 1;  
        }
    }
    if (StrContains(HTTP_req, "&Lim_U_PA=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_U_PA=");
        ms.lim_U_PA = (float) atof(str_valeur);
      
        str_valeur[0] = 0;
        // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_U_PA != ms.lim_U_PA){
           U_PA_max = 0;
           maj_EEPROM = 1;  
        }
    }
    if (StrContains(HTTP_req, "&Lim_I_PA=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_I_PA=");
        ms.lim_I_PA = (float) atof(str_valeur);
       
        str_valeur[0] = 0;
        // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_I_PA != ms.lim_I_PA){
           I_PA_max = 0;
           maj_EEPROM = 1;  
        }
        
    }
    if (StrContains(HTTP_req, "&Lim_Dir_RF=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_Dir_RF=");
        ms.lim_Dir_RF = (float) atof(str_valeur);
       
        str_valeur[0] = 0;
        // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_Dir_RF != ms.lim_Dir_RF){
           Dir_RF_max = 0;
           maj_EEPROM = 1;  
        }
    }
    if (StrContains(HTTP_req, "&Lim_Refl_RF=")) { 
        // on lit la valeur
        StrRead(HTTP_req, "Lim_Refl_RF=");
        ms.lim_Refl_RF = (float) atof(str_valeur);
        
        str_valeur[0] = 0;
         // tester si la valeur coté client est différente de la valeur en EEPROM
        if (ms_lue.lim_Refl_RF != ms.lim_Refl_RF){
           Refl_RF_max = 0;
           maj_EEPROM = 1;  
        }
    }

   

    
    if (maj_EEPROM) {
      
      EEPROM.put(0, ms);
    }
}


void Affiche_EEPROM() {  // display eeprom
  MaStructure m;    
  EEPROM.get(0, m);
  
  Serial.print("*******************************************magic = ");
  Serial.println(m.magic);
  Serial.print("*******************************************lim_temp_haute = ");
  Serial.println(m.lim_temp_haute);
  Serial.print("*******************************************lim_temp_basse = ");
  Serial.println(m.lim_temp_basse);
  Serial.print("*******************************************lim_U_PA = ");
  Serial.println(m.lim_U_PA);
  Serial.print("*******************************************lim_I_PA = ");
  Serial.println(m.lim_I_PA);
  Serial.print("*******************************************lim_Dir_RF = ");
  Serial.println(m.lim_Dir_RF);
  Serial.print("*******************************************lim_Refl_RF = ");
  Serial.println(m.lim_Refl_RF);

  Serial.print("*******************************************lim_htr_low = ");
  Serial.println(m.lim_htr_low);

  Serial.print("*******************************************lim_htr_high = ");
  Serial.println(m.lim_htr_high);

}


// send the XML file with analog values, switch status
// and Relays status
void XML_response(EthernetClient cl)
{
    int analog_val;            // stores value read from analog inputs
    int count;                 // used by 'for' loops
  
    cl.print("<?xml version = \"1.0\" ?>");
    cl.print("<inputs>");
    // envoi des mesures
    cl.print("<temp>");
    cl.print(DS18B20_temperature); 
    cl.println("</temp>");

    cl.print("<U_PA>");
    cl.print(U_PA,1);
    cl.println("</U_PA>");

    cl.print("<I_PA>");
    cl.print(I_PA,1);
    cl.println("</I_PA>"); 

    cl.print("<Dir_RF>");
    cl.print(level_CH_1);
    cl.println("</Dir_RF>");

    cl.print("<Refl_RF>");
    cl.print(level_CH_2);
    cl.println("</Refl_RF>"); 

   
    // envoi Ă©tats des relais
    
    // etat relais PTT
    cl.print("<etat_PTT>");
    if (Relay_PTT) {
        cl.print("on");
    }
    else {
        cl.print("off");
    }
    cl.println("</etat_PTT>");

    // etat relais PA
    cl.print("<etat_PA>");
    if (Relay_PA == 1) {
        cl.print("on");
    }
    else if (Relay_PA == 0) {
        cl.print("off");
    }
     cl.println("</etat_PA>");

    // etat relais FAN
    cl.print("<etat_FAN>");
    
    if (Relay_FAN) {
        cl.print("on");
    }
    else {
        cl.print("off");
    }
    cl.println("</etat_FAN>");

    // etat relais AUX
    cl.print("<etat_AUX>");
    
    if (Relay_AUX) {
        cl.print("on");
    }
    else {
        cl.print("off");
    }
    cl.println("</etat_AUX>");
    
    //Envoi du  Watchdog : on envoie alternativement des messages Watchdog on et off au client pour qu'il puisse vérifier que la liaison ethernet fonctionne de son coté
    cl.print("<Watchdog>");
    if (Watchdog) {
        Watchdog = 0;
        cl.print("off");
       
    }
    else {
        Watchdog = 1;    
        cl.print("on");
       
    }
    cl.println("</Watchdog>");

    //Envoi du type de page programmé pour la prochaine connexion
    cl.print("<web_page>");
    if (web_page == 1) {
      // will send web page advanced.htm on next connexion
      cl.print("full");
    }
  
    else {
      // will send web page index.htm on next connexion
      cl.print("short");       
    }
    cl.println("</web_page>");
 
    // envoi alarm_T_PA_Arduino au client
    
    if (alarm_T_PA_Arduino) {
      cl.print("<alarm_T_PA_Arduino>");
      
      cl.print(T_PA_max);
      
      cl.println("</alarm_T_PA_Arduino>");
      
    }   
    
    // envoi alarm_U_PA_Arduino au client
    
    if (alarm_U_PA_Arduino) {
      cl.print("<alarm_U_PA_Arduino>");
      
      cl.print(U_PA_max);
      
      cl.println("</alarm_U_PA_Arduino>");
      
    }
       
    // envoi alarm_I_PA_Arduino au client
    
    if (alarm_I_PA_Arduino) {
      cl.print("<alarm_I_PA_Arduino>");
      
      cl.print(I_PA_max);
      
      cl.println("</alarm_I_PA_Arduino>");
      
    }

    // envoi alarm_Dir_power_Arduino au client
    
    if (alarm_Dir_power_Arduino) {
      cl.print("<alarm_Dir_power_Arduino>");
      
      cl.print(Dir_RF_max);
      
      cl.println("</alarm_Dir_power_Arduino>");
      
    }
    
    // envoi alarm_Refl_power_Arduino au client
    if (alarm_Refl_power_Arduino) {
       cl.print("<alarm_Refl_power_Arduino>");
       
       cl.print(Refl_RF_max);
       
       cl.println("</alarm_Refl_power_Arduino>");
       
    }

    if (req_lim == 1) { // if limits are requested by the customer
                        // send limits to client
       
      cl.print("<lim_T_H>");
      cl.print(ms.lim_temp_haute,1);
      cl.print("</lim_T_H>");
      cl.print("<lim_T_B>");
      cl.print(ms.lim_temp_basse,1);
      cl.print("</lim_T_B>");
      cl.print("<lim_U_PA>");
      cl.print(ms.lim_U_PA,1);
      cl.print("</lim_U_PA>");
      cl.print("<lim_I_PA>");
      cl.print(ms.lim_I_PA,1);
      cl.print("</lim_I_PA>");
      cl.print("<lim_Dir_RF>");
      cl.print(ms.lim_Dir_RF,1);
      cl.print("</lim_Dir_RF>");
      cl.print("<lim_Refl_RF>");
      cl.print(ms.lim_Refl_RF,1);
      cl.print("</lim_Refl_RF>");

      cl.print("<lim_htr_low>");
      cl.print(ms.lim_htr_low,1);
      cl.print("</lim_htr_low>");

      cl.print("<lim_htr_high>");
      cl.print(ms.lim_htr_high,1);
      cl.print("</lim_htr_high>");
  
      req_lim = 0;
    }
    cl.print("</inputs>");    
}

// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
char StrContains(char *str, char *sfind)
{
    char found = 0;
    char index = 0;
    char len;

    len = strlen(str);
    
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }

    return 0;
}

void StrRead(char *str, char *sfind) // extrait la valeur numérique de la chaine sfind dans la chaine str et la recopie dans la chaine globale str_valeur
{
    str_valeur[0]=0;
    char i = 0; 
    char j = 0; 
    char * pch;
    pch = strstr (str,sfind); 
    while (pch[i] != '=') {
      i++;
    }
    i++;   
    while (pch[i] != '&') {
      str_valeur[j] = pch[i] ;
      i++;
      j++;
    }
    str_valeur[j]=0;
}

void StrRead_2val(char *str, char *sfind) // extrait 2 valeurs numériques de la chaine sfind dans la chaine str et la recopie dans les 2 chaine globales str_valeur et str_valeur2
{
    str_valeur[0]=0;
    str_valeur2[0]=0;
    char i = 0; 
    char j = 0; 
    char * pch;
    pch = strstr (str,sfind); //renvoie un pointeur sur le début de sfind
    while (pch[i] != '=') {
      i++;
    }
    i++;   
    while (pch[i] != '/') {
      str_valeur[j] = pch[i] ;
      i++;
      j++;
    }
    i++;    // on pointe juste après le /
    str_valeur[j]=0;
    j=0;
    while (pch[i] != '&') {
      str_valeur2[j] = pch[i] ;
      i++;
      j++;
    }
    str_valeur2[j]=0;    
}

void StrRead_4val(char *str, char *sfind) // extracts 4 numeric values ​​from the string sfind into the string str
                                          // and copy it into the 4 global strings str_value, str_value2, str_value3, str_value4
                                          // the 4 values ​​are separated by '/' the last value ends with '&'
{
    str_valeur[0]=0;
    str_valeur2[0]=0;
    str_valeur3[0]=0;
    str_valeur4[0]=0;
    char i = 0; 
    char j = 0; 
    char * pch;
    pch = strstr (str,sfind); //returns a pointer to the start of sfind
    while (pch[i] != '=') {
      i++;
    }
    
    i++;     // on pointe juste après le =  
    while (pch[i] != '/') {
      str_valeur[j] = pch[i] ;
      i++;
      j++;
    }
    str_valeur[j]=0;

    // recherche du DPS2
    i++;    // on pointe juste après le /
    j=0;
    while (pch[i] != '/') {
      str_valeur2[j] = pch[i] ;
      i++;
      j++;
    }
    str_valeur2[j]=0; 

    // recherche de DPL1
    i++;    // on pointe juste après le /
    j=0;
    while (pch[i] != '/') {
      str_valeur3[j] = pch[i] ;
      i++;
      j++;
    }
    str_valeur3[j]=0; 

    // recherche de DPL2
    i++;    // on pointe juste après le /    
    j=0;
    while (pch[i] != '&') {
      str_valeur4[j] = pch[i] ;
      i++;
      j++;
    }
    str_valeur4[j]=0;    
}

/* --------------- Acquisition de la température ----------------------------------- */
float getTemperatureDS18b20(){

  
  byte i;
  byte data[12];
  float temp =0.0;
  
  //There is only one sensor, so we load the unique address.
 // ds.search(addr);
  /*
  // Cette fonction sert à surveiller si la transmission s'est bien passée
  if (OneWire::crc8( addr, 7) != addr[7]) {
    Serial.println("getTemperatureDS18b20 : <!> CRC is not valid! <!>");
    return false;
  }
  
  // On vérifie que l'élément trouvé est bien un DS18B20
  if (addr[0] != DS18B20_ID) {
    Serial.println("L'équipement trouvé n'est pas un DS18B20");
    return false;
  }
  */
  
  // programmer une résolution de 9 bits takes 10mS
  //changeResolution( addr, RESOLUTION_9_BITS);
  
  // Ask the sensor to memorize the temperature and give it 200ms to do so (see datasheet)
  ds.reset();
  ds.select(addr);
  ds.write(0x44);
  delay(200);
  // Demander au capteur de nous envoyer la température mémorisée
  ds.reset();
  ds.select(addr);
  ds.write(0xBE);
  


  // Le MOT reçu du capteur fait 9 octets, on les charge donc un par un dans le tableau data[]
  for ( i = 0; i < 9; i++) {
   data[i] = ds.read();
  }
  // Puis on converti la température (*0.0625 car la température est stockée sur 12 bits)
  temp = ( (data[1] << 8) + data[0] )*0.0625;

  return temp;
}


/** Change la résolution du capteur de température */
void changeResolution(const byte addr[], byte resolution) {

  /* Reset le bus 1-Wire, sélectionne le capteur et envoie une demande d'écriture du scratchpad */
  ds.reset();
  ds.select(addr);
  ds.write(0x4E);
  
  /* Ecrit dans le scratchpad */
  ds.write(0x00);
  ds.write(0x00);
  ds.write(resolution);

  /* Fin d'Ă©criture */
  ds.reset();
}


// -----------------------------------------------------------------------------------------------------

float calculate_power_CH_1()    // takes 120uS                         
{  
 
float rfp ;

rfp = I_PA * 10 ; // use global I_PA and X10 for look up table
float Level_CH_1 =  lookup_forward_RF_power(Forward_RF_power_table, (float)rfp, Forward_RF_Power_TABLE_SIZE); // forward power in watts

return Level_CH_1;
}

// -----------------------------------------------------------------------------------------------------

float  calculate_power_CH_2()      // takes 150uS                          
{ 
  
	uint16_t adc_RF_Power_count;
	float Level_CH_2;
	
	adc_RF_Power_count = analogRead(A5);  // get RF PA adc reading
	Level_CH_2	 = lookup_Reflected_RF_Power(RF_Power_table, (float)adc_RF_Power_count, Reflected_RF_Power_TABLE_SIZE); // convert to dBm

  return Level_CH_2;
}


	float lookup_forward_RF_power (const look_up_RFP * table, float x, int size)
	{
		int i;
		float m;
		i = 0;
		while((i < (size)) && (x > table[i].x) ){		//find the two points in the table to use
			i++;
		}
		if ( i == size ){								//make sure the point isn't past the end of the table
			return table[i-1].y;
		}
		
		if ( i == 0 ){									//make sure the point isn't before the beginning of the table
			return table[i].y;
		}
		
		m = (table[i].y - table[i-1].y) / ( table[i].x - table[i-1].x);			//calculate the slope
		return m * (x - table[i].x) + table[i].y;								//this is the solution to the point slope formula
	}

  

float lookup_Reflected_RF_Power (const look_up_Reflected_RF_Power * table, float x, int size)
	{
		int i;
		float m;
		i = 0;
		while((i < (size)) && (x > table[i].x) ){		//find the two points in the table to use
			i++;
		}
		if ( i == size ){								//make sure the point isn't past the end of the table
			return table[i-1].y;
		}
		
		if ( i == 0 ){									//make sure the point isn't before the beginning of the table
			return table[i].y;
		}
		
		m = (table[i].y - table[i-1].y) / ( table[i].x - table[i-1].x);			//calculate the slope
		return m * (x - table[i].x) + table[i].y;								//this is the solution to the point slope formula
	}


Here's the html index

<!DOCTYPE html>



<html>
    <head>
        <title>QO100 PA control index</title>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        <script>
        
        var period = 1400; // time between 2 requests
        
        function getRandomArbitrary(min, max) { // define random period in ms between 2 GetArduinoIO()'calls
		  period = Math.random() * (max - min) + min;
		  period = period.toFixed(0); 
		}
		
		window.onload = getRandomArbitrary(1300, 1800); 

        
        var strload = "";

		var temp = 0.0;
		var U_PA = 0.0;
		var I_PA = 0.0;
		var Dir_RF = 0.0;
		var W_dir_RF = 0.0;
		var Refl_RF = 0.0;
		var W_Refl_RF = 0.0;
		var RL = 0;
		var SWR = 100000;
		var k = 0;
		var web_page ='';
		
		
		
		function GetArduinoIO()
		{
			nocache = "&nocache=" + Math.random() * 1000000;
			var request = new XMLHttpRequest();
			
			request.onreadystatechange = function()
			{
				if (this.readyState == 4) {
					if (this.status == 200) {
						if (this.responseXML != null) {
							
							var count;
							
							var chaine = this.response; 
							
							var position = chaine.indexOf("<temp>"); 
							if (position != -1) {
								temp = parseFloat(this.responseXML.getElementsByTagName('temp')[0].childNodes[0].nodeValue); 
								document.getElementsByClassName("temp")[0].innerHTML = temp.toFixed(1);
								
							}
							var position = chaine.indexOf("<U_PA>"); 
							if (position != -1) {
								U_PA = parseFloat(this.responseXML.getElementsByTagName('U_PA')[0].childNodes[0].nodeValue); 
								document.getElementsByClassName("U_PA")[0].innerHTML = U_PA.toFixed(1);
								
							}
							var position = chaine.indexOf("<I_PA>"); 
							if (position != -1) {
								I_PA = parseFloat(this.responseXML.getElementsByTagName('I_PA')[0].childNodes[0].nodeValue); 
								document.getElementsByClassName("I_PA")[0].innerHTML = I_PA.toFixed(1);
								
							}
							
							var position = chaine.indexOf("<Dir_RF>"); 
							if (position != -1) {
								Dir_RF = parseFloat(this.responseXML.getElementsByTagName('Dir_RF')[0].childNodes[0].nodeValue);
								W_Dir_RF = Math.pow(10, (Dir_RF/10))/1000;
								document.getElementsByClassName("W_Dir_RF")[0].innerHTML = W_Dir_RF.toFixed(0);
								
							}
							
							var position = chaine.indexOf("<Refl_RF>"); 
							if (position != -1) {
								Refl_RF = parseFloat(this.responseXML.getElementsByTagName('Refl_RF')[0].childNodes[0].nodeValue);
								W_Refl_RF = Math.pow(10, (Refl_RF/10))/1000;
								document.getElementsByClassName("W_Refl_RF")[0].innerHTML = W_Refl_RF.toFixed(1);
								k = Math.sqrt(W_Refl_RF/W_Dir_RF);
								SWR = (1+k)/(1-k);
								document.getElementsByClassName("SWR")[0].innerHTML = SWR.toFixed(2);
								
							}
							var position = chaine.indexOf("<web_page>"); 
							if (position != -1) {
								web_page = this.responseXML.getElementsByTagName('web_page')[0].childNodes[0].nodeValue;
								if (web_page == "full") {
									document.getElementById("full_vers").checked = true;
								}
								
								else document.getElementById("short_vers").checked = true;
							}
						
						} 
						
					} 
				} 
			} 

			// préparer la requête à envoyer au serveur
			request.open("GET", "ajax_inputs" + strload + nocache, true);
			
			// envoyer la requĂŞte au serveur
			request.send(null);
			strload = "";

			setTimeout('GetArduinoIO()', period); // n'autoriser la relance de GetArduino() qu'au bout de period s

		} // fin GetAduino()
		
	
		function change_load(type) {
			if (type == 'L') {
				strload = "&advanced";
			}
			
			else if (type == 'S') {
				strload = "&short";
			}
			else strload = "";
		}
			
			
		</script>
		
	<style>

		
		.IO_box {
			float: left;
			margin: 0 20px 20px 0;
			width: 800px;
		}

		h1 {
			font-size: 120%;
			color: blue;
			margin: 0 0 10px 0;
		}
		h2 {
			font-size: 85%;
			/*color: #5734E6;*/
			color: green;
			margin: 5px 0 5px 0;
		}
		h3 {
			font-size: 150%;
			color: #00A000;
			margin: 5px 0 5px 0;
		}
		p, form, button {
			font-size: 80%;
			color: #252525;
		}
		

	</style>
	
    </head>
    <body onload="GetArduinoIO()">
			
        <div class="IO_box">
			<table>
			<tbody>
			<tr><td nowrap ><p><h3><span class="temp">...</span> °C  /  </h3></td><td nowrap></h3></td></p>
			<td nowrap ><p><h3><span class="U_PA">...</span> V  /  </h3></td><td nowrap></h3></td></p>	
			<td nowrap ><p><h3><span class="I_PA">...</span> A  /  </h3></td><td nowrap></h3></td></p>
			<td nowrap ><p><h3>  Fwd RF : <span class="W_Dir_RF">...</span> W </h3></td><td nowrap></h3></td></p>
			<td nowrap ><p><h3>  Ref RF : <span class="W_Refl_RF">...</span> W </h3></td><td nowrap></h3></td></p>
			<td nowrap ><p><h3>  VSWR : <span class="SWR">...</span> </h3></td></p></tr>
			</tbody>
			</table>

			
			
		</div>
		<div class="IO_box">
			choice for next load version :
			<input type="radio" name="full_version" id="full_vers" value="false"  onchange="change_load('L')" > full version
			<input type="radio" name="full_version" id="short_vers" value="false" onchange="change_load('S')"> display only
			
		</div>
    </body>
</html>

and here's the advanced.htm file

<!DOCTYPE html>



<html>
    <head>
	<title>QO 100 PA control full</title>
	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
	<script>
        var strload = "";
		var strRelay1 = "";
		var strRelay2 = "";
		var strRelay3 = "";
		var strRelay4 = "";
		var strSeuilTH = "";
		var strSeuilTB = "";
		var strSeuilU = "";
		var strSeuilI = "";
		var strSeuilDRF = "";
		var strSeuilRRF = "";
		var strReset_alarme = "";
		var str_corr_U = "";
		var str_save_G_U_PA = "";
		var str_GI = ""; 
		
		var strSeuilHHO = "";		
		var strSeuilLHO = "";
		
		var PTT_state = 0;
		var PA_state = 0;
		var FAN_state = 0;
		var analog = "";
		var temp = 0.0;
		var U_PA = 0.0;
		var I_PA = 0.0;
		var Dir_RF = 0.0;
		var W_dir_RF = 0.0;
		var Refl_RF = 0.0;
		var W_Refl_RF = 0.0;
		var RL = 0;
		var SWR = 100000;
		var k = 0;
		var alarm_T_PA_Arduino = 0;
		var alarm_U_PA_Arduino = 0;
		var alarm_I_PA_Arduino = 0;
		var alarm_DP_PA_Arduino = 0;
		var alarm_RP_PA_Arduino = 0;
		var count_requete = 0;
		var compteur = 0;
		var nb_envoi = 0;
		var option_coupure = false;		
		var nb_coupure = 0;
		
		var web_page ='';
		
		function showAlert() {  // function called if we enter the GetArduinoIO() function more than twice without response from the server,
								// we then consider that the ethernet link is defective!
								//alert("Ethernet link broken!");
			  document.getElementById("liaison_eth").className = "liaison_eth_off";
			  document.getElementById("liaison_eth").value = "!!! OFF !!! ";
			  document.getElementById("etat_eth").className = "etat_eth_off";
			  nb_coupure++;
			  mes_nb_coupure = 'total cuts env. ' + nb_coupure + 's';
			  document.getElementById("etat_eth").value = mes_nb_coupure;
			  
			  if (document.getElementById("option1").checked == true) {
			  
				  if (FAN_state == 1) {
				  
					  // we cut the PTT and PA buttons because the same alert was detected on the server side with the PA and PTT relays cut off!
			
					  document.getElementById("etat_PTT").value = "TX is OFF air";
					  document.getElementById("etat_PTT").className = "etat_PTT_OFF";
					  PTT_state = 0;
					  document.getElementById("etat_PA").value = "PSU is OFF";
					  document.getElementById("etat_PA").className = "etat_PA_OFF";
					  PA_state = 0;
					  document.getElementById("Bouton_PTT_ON").disabled = true;
					  document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
					  document.getElementById("Bouton_PTT_OFF").disabled = true;
					  document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";

					  document.getElementById("Bouton_PA_OFF").disabled = true;
					  document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
				  
				  
					  document.getElementById("Bouton_PA_ON").disabled = false;
					  document.getElementById("Bouton_PA_ON").className = "PA_ON";
					 
				  }
				  else {
					  document.getElementById("Bouton_PA_ON").disabled = true;
					  document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
					
				  }
			  }
			  			  
		}
		


		
		function GetArduinoIO()
		{
			nocache = "&nocache=" + Math.random() * 1000000;
			var request = new XMLHttpRequest();
			
			request.onreadystatechange = function()
			{
				if (this.readyState == 4) {
					if (this.status == 200) {
						if (this.responseXML != null) {
							// XML file received - contains analog values, switch values and Relay stats etc ..
							var count;
							var message = ""; // message d'erreur éventuellement affiché 
							var chaine = this.response; // on récupère toute la réponse faite par le serveur
							
							var position = chaine.indexOf("<temp>"); 
							if (position != -1) {
								temp = parseFloat(this.responseXML.getElementsByTagName('temp')[0].childNodes[0].nodeValue); 
								document.getElementsByClassName("temp")[0].innerHTML = temp.toFixed(1);
								
							}
							var position = chaine.indexOf("<U_PA>"); 
							if (position != -1) {
								U_PA = parseFloat(this.responseXML.getElementsByTagName('U_PA')[0].childNodes[0].nodeValue); 
								document.getElementsByClassName("U_PA")[0].innerHTML = U_PA.toFixed(1);
								
								
							}
							var position = chaine.indexOf("<I_PA>"); 
							if (position != -1) {
								I_PA = parseFloat(this.responseXML.getElementsByTagName('I_PA')[0].childNodes[0].nodeValue); 
								document.getElementsByClassName("I_PA")[0].innerHTML = I_PA.toFixed(1);
								
								
							}
							
							var position = chaine.indexOf("<Dir_RF>"); 
							if (position != -1) {
								Dir_RF = parseFloat(this.responseXML.getElementsByTagName('Dir_RF')[0].childNodes[0].nodeValue);
								document.getElementsByClassName("D_RF")[0].innerHTML = Dir_RF;

								W_Dir_RF = Math.pow(10, (Dir_RF/10))/1000;
								document.getElementsByClassName("W_Dir_RF")[0].innerHTML = W_Dir_RF.toFixed(1);
								
							}
							
							var position = chaine.indexOf("<Refl_RF>"); 
							if (position != -1) {
								Refl_RF = parseFloat(this.responseXML.getElementsByTagName('Refl_RF')[0].childNodes[0].nodeValue);
								document.getElementsByClassName("R_RF")[0].innerHTML = Refl_RF;
							
								W_Refl_RF = Math.pow(10, (Refl_RF/10))/1000;
								document.getElementsByClassName("W_Refl_RF")[0].innerHTML = W_Refl_RF.toFixed(1);
								
								RL = Refl_RF - Dir_RF;
								k = Math.sqrt(W_Refl_RF/W_Dir_RF);
								SWR = (1+k)/(1-k);
								document.getElementsByClassName("RL")[0].innerHTML = RL.toFixed(1);
								document.getElementsByClassName("SWR")[0].innerHTML = SWR.toFixed(2);
								
							}
							
							var position = chaine.indexOf("<web_page>"); 
							if (position != -1) {
								web_page = this.responseXML.getElementsByTagName('web_page')[0].childNodes[0].nodeValue;
								if (web_page == "full") {
									document.getElementById("full_vers").checked = true;
								}
								
								else document.getElementById("short_vers").checked = true;
							}
							
							//read the status of relays sent by the server
							// Relay 1 PTT

							if (this.responseXML.getElementsByTagName('etat_PTT')[0].childNodes[0].nodeValue === "on") {
								document.getElementById("etat_PTT").value = "TX is ON air";
								document.getElementById("etat_PTT").className = "etat_PTT_ON";								
								PTT_state = 1;
							}
							else {
								document.getElementById("etat_PTT").value = "TX is OFF air";
								document.getElementById("etat_PTT").className = "etat_PTT_OFF";
								PTT_state = 0;
							}
		
							// Relay 2 PA
							if (this.responseXML.getElementsByTagName('etat_PA')[0].childNodes[0].nodeValue === "on") {
								document.getElementById("etat_PA").value = "PSU is ON";
								document.getElementById("etat_PA").className = "etat_PA_ON";
								PA_state = 1;
							}
							else {
								document.getElementById("etat_PA").value = "PSU is OFF";
								document.getElementById("etat_PA").className = "etat_PA_OFF";
								PA_state = 0;
							}
							
							// Relay 3  FAN
							if (this.responseXML.getElementsByTagName('etat_FAN')[0].childNodes[0].nodeValue === "on") {								
								document.getElementById("etat_FAN").value = "FAN is ON";
								document.getElementById("etat_FAN").className = "etat_FAN_ON";
								FAN_state = 1;
							}
							else {
								document.getElementById("etat_FAN").value = "FAN is OFF";
								document.getElementById("etat_FAN").className = "etat_FAN_OFF";
								FAN_state = 0;
							}
							
							// Relay 4  AUX
							if (this.responseXML.getElementsByTagName('etat_AUX')[0].childNodes[0].nodeValue === "on") {								
								document.getElementById("etat_AUX").value = "Heater is ON";
								document.getElementById("etat_AUX").className = "etat_AUX_ON";
								AUX_state = 1;
							}
							else {
								document.getElementById("etat_AUX").value = "Heater is OFF";
								document.getElementById("etat_AUX").className = "etat_AUX_OFF";
								AUX_state = 0;
							}

							
							if (this.responseXML.getElementsByTagName('Watchdog')[0].childNodes[0].nodeValue === "on") {
								document.getElementById("liaison_eth").className = "liaison_eth_on";
								document.getElementById("liaison_eth").value = "    ON     ";
								
								compteur = 0;
								
							}
							else {
								document.getElementById("liaison_eth").className = "liaison_eth_on";
								document.getElementById("liaison_eth").value = "    on     ";
								
								compteur = 0;
								
							}
						
							
							//READ THE LIMITS SENT BY THE SERVER AT THE START OF THE CONNECTION or just after loading the page
							// if limits have been received, display them in their respective fields
							// normally this only occurs following a reset of the Arduino server and connection
							
							
							var position = chaine.indexOf("lim_T_H"); 
							if (position != -1) {
								document.getElementById("seuil_haut_temp").value = this.responseXML.getElementsByTagName('lim_T_H')[0].childNodes[0].nodeValue;
							}
							position = chaine.indexOf("lim_T_B"); 
							if (position != -1) {
								document.getElementById("seuil_bas_temp").value = this.responseXML.getElementsByTagName('lim_T_B')[0].childNodes[0].nodeValue;
							}
							position = chaine.indexOf("lim_U_PA"); 
							if (position != -1) {
								document.getElementById("seuil_haut_U_PA").value = this.responseXML.getElementsByTagName('lim_U_PA')[0].childNodes[0].nodeValue;
							}
							position = chaine.indexOf("lim_I_PA"); 
							if (position != -1) {
								document.getElementById("seuil_haut_I_PA").value = this.responseXML.getElementsByTagName('lim_I_PA')[0].childNodes[0].nodeValue;
							}
							position = chaine.indexOf("lim_Dir_RF"); 
							if (position != -1) {
								document.getElementById("seuil_haut_Dir_RF").value = this.responseXML.getElementsByTagName('lim_Dir_RF')[0].childNodes[0].nodeValue;
							}
							position = chaine.indexOf("lim_Refl_RF"); 
							if (position != -1) {
								document.getElementById("seuil_haut_Refl_RF").value = this.responseXML.getElementsByTagName('lim_Refl_RF')[0].childNodes[0].nodeValue;
							}
							
							position = chaine.indexOf("lim_htr_low"); 
							if (position != -1) {
								document.getElementById("seuil_haut_htr_off").value = this.responseXML.getElementsByTagName('lim_htr_low')[0].childNodes[0].nodeValue;
							}
							
							position = chaine.indexOf("lim_htr_high"); 
							if (position != -1) {
								document.getElementById("seuil_haut_htr_on").value = this.responseXML.getElementsByTagName('lim_htr_high')[0].childNodes[0].nodeValue;
							}
							
							// taking into account alarms coming from the Arduino server
									
							position = chaine.indexOf("alarm_T_PA_Arduino"); 
							if (position != -1) {
								message = "Temp. =  "+ this.responseXML.getElementsByTagName('alarm_T_PA_Arduino')[0].childNodes[0].nodeValue + "°C";
								document.getElementById("dep_temp").value = message;
								document.getElementById('dep_temp').style.backgroundColor='#00FFFF'; 
								document.getElementById('dep_temp').style.color='#FF0F0F';
								
								alarm_T_PA_Arduino = 1;
								document.getElementById("Bouton_PA_ON").disabled = true;
								document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
								document.getElementById("Bouton_PA_OFF").disabled = true;
								document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
								document.getElementById("Bouton_PTT_ON").disabled = true;
								document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
								document.getElementById("Bouton_PTT_OFF").disabled = true;
								document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";
								
							}
						
							else {
								alarm_T_PA_Arduino = 0;
								
							}
							
							
							position = chaine.indexOf("alarm_U_PA_Arduino"); 
							if (position != -1) {
								message = "U = "+ this.responseXML.getElementsByTagName('alarm_U_PA_Arduino')[0].childNodes[0].nodeValue + "V";
								document.getElementById("dep_U_PA").value = message;
								document.getElementById('dep_U_PA').style.backgroundColor='#00FFFF'; 
								document.getElementById('dep_U_PA').style.color='#FF0F0F';
								
								alarm_U_PA_Arduino = 1;
								document.getElementById("Bouton_PA_ON").disabled = true;
								document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
								document.getElementById("Bouton_PA_OFF").disabled = true;
								document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
								document.getElementById("Bouton_PTT_ON").disabled = true;
								document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
								document.getElementById("Bouton_PTT_OFF").disabled = true;
								document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";
					
							}
						
							else {
								alarm_U_PA_Arduino = 0;
								
							}
							
							position = chaine.indexOf("alarm_I_PA_Arduino"); 
							if (position != -1) {
								message = "I = "+ this.responseXML.getElementsByTagName('alarm_I_PA_Arduino')[0].childNodes[0].nodeValue + "A";
								document.getElementById("dep_I_PA").value = message;
								document.getElementById('dep_I_PA').style.backgroundColor='#00FFFF'; 
								document.getElementById('dep_I_PA').style.color='#FF0F0F';
								
								alarm_I_PA_Arduino = 1;
								document.getElementById("Bouton_PA_ON").disabled = true;
								document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
								document.getElementById("Bouton_PA_OFF").disabled = true;
								document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
								document.getElementById("Bouton_PTT_ON").disabled = true;
								document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
								document.getElementById("Bouton_PTT_OFF").disabled = true;
								document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";

							}
						
							else {
							
								alarm_I_PA_Arduino = 0;
							}
							
							position = chaine.indexOf("alarm_Dir_power_Arduino"); 
							if (position != -1) {
								message = "Dir RF = "+ this.responseXML.getElementsByTagName('alarm_Dir_power_Arduino')[0].childNodes[0].nodeValue + "dBm";
								document.getElementById("dep_Dir_RF").value = message;
								document.getElementById('dep_Dir_RF').style.backgroundColor='#00FFFF'; 
								document.getElementById('dep_Dir_RF').style.color='#FF0F0F';

								alarm_DP_PA_Arduino = 1;
								document.getElementById("Bouton_PA_ON").disabled = true;
								document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
								document.getElementById("Bouton_PA_OFF").disabled = true;
								document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
								document.getElementById("Bouton_PTT_ON").disabled = true;
								document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
								document.getElementById("Bouton_PTT_OFF").disabled = true;
								document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";

							}
						
							else {			
								alarm_DP_PA_Arduino = 0;
							}
							
							position = chaine.indexOf("alarm_Refl_power_Arduino"); 
							if (position != -1) {
								message = "Refl RF = "+ this.responseXML.getElementsByTagName('alarm_Refl_power_Arduino')[0].childNodes[0].nodeValue + "dBm";
								document.getElementById("dep_Refl_RF").value = message;
								document.getElementById('dep_Refl_RF').style.backgroundColor='#00FFFF'; 
								document.getElementById('dep_Refl_RF').style.color='#FF0F0F';

								alarm_RP_PA_Arduino = 1;
								document.getElementById("Bouton_PA_ON").disabled = true;
								document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
								document.getElementById("Bouton_PA_OFF").disabled = true;
								document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
								document.getElementById("Bouton_PTT_ON").disabled = true;
								document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
								document.getElementById("Bouton_PTT_OFF").disabled = true;
								document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";

							}
						
							else {
							
								alarm_RP_PA_Arduino = 0;
							
							}
							

						
						} // fin de if (this.responseXML != null) {
						//Maj_boutons(FAN_state, PA_state, PTT_state, AUX_state);
						Maj_boutons( PA_state, PTT_state);
						
					} // fin de if (this.status == 200) {
				} // fin de if (this.readyState == 4) {
			} //fin de request.onreadystatechange = function()
			

			// ask the server to send the limits
			if (count_requete <= 1) {
				count_requete++;
				str_req_lim = "&str_req_lim";
			}
			else {
				count_requete = 2; // to limit to 1 request
				str_req_lim = "";
			}
			
			
		//	str_req_lim = "&str_req_lim";
			
			// tell the server if it should cut off the PA and PTT in the event of ethernet cutoff detection
			if (document.getElementById("option1").checked == true) {
				//envoi++;
				//if (envoi < 4) 
				str_PA_off_on_link_off = "&PA_off_on_link_off";
			}
			else {
				str_PA_off_on_link_off ="&NO_PA_off_on_link_off";
			}
			
			
			// prepare the request to send to the server
			request.open("GET", "ajax_inputs" + strload + str_PA_off_on_link_off + str_req_lim + strRelay1 + strRelay2 + strRelay3 + strRelay4
			 + strSeuilTH + strSeuilTB + strSeuilU + strSeuilI + strSeuilDRF + strSeuilRRF
			 + str_corr_U + str_save_G_U_PA  + str_GI
			
			 
			 + strSeuilHHO
			 + strSeuilLHO
			 
			 
			 + strReset_alarme + nocache, true);
		
			// send request to server
			request.send(null);
			strload = "";
			strRelay1 = "";
			strRelay2 = "";
			strRelay3 = "";
			strRelay4 = "";
			strSeuilTH = "";
			strSeuilTB = "";
			strSeuilU = "";
			strSeuilI = "";
			strSeuilDRF = "";
			strSeuilRRF = "";
			
			strSeuilHHO = "";			
			strSeuilLHO = "";
						
			strReset_alarme = "";
			str_PA_off_on_link_off = "";
			str_corr_U = "";
			str_save_G_U_PA = "";
			str_GI = "";

				
			compteur++;
			if (compteur > 2) 	showAlert(); // si on entre dans la fonction GetArduinoIO() plus de 2 fois sans réponse du serveur, 
											 // on considère que la liaison ethernet est défectueuse !

			setTimeout('GetArduinoIO()', 1000); // n'autoriser la relance de GetArduino() qu'au bout de 1s
		} // fin GetAduino()
		
		function Maj_boutons(etat_PA, etat_PTT) // PTT Relay 
		//function Maj_boutons(etat_FAN, etat_PA, etat_PTT, etat_AUX) // PTT Relay 
		{
		if ((alarm_U_PA_Arduino == 0) && (alarm_I_PA_Arduino == 0) && (alarm_DP_PA_Arduino == 0) && (alarm_RP_PA_Arduino == 0) && (alarm_T_PA_Arduino == 0)){ 
// if no Arduino alarm
// update button state
		
				
				if ( (etat_PA == 0) && (etat_PTT == 0)) { // current state PA = 0; PTT = 0  all off so only allow pa_on to be set
				
				
		
					document.getElementById("Bouton_PA_ON").disabled = false;
					document.getElementById("Bouton_PA_ON").className = "PA_ON";
					document.getElementById("Bouton_PA_OFF").disabled = true;
					document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
				
					document.getElementById("Bouton_PTT_ON").disabled = true;
					document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
					document.getElementById("Bouton_PTT_OFF").disabled = true;
					document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";
				}
			
			
				else if ((etat_PA == 1) && (etat_PTT == 0)) { //  PA = 1; PTT = 0, psu is on so only allow tx ptt on or psu off to be set
					

					document.getElementById("Bouton_PA_ON").disabled = true;
					document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
					document.getElementById("Bouton_PA_OFF").disabled = false;
					document.getElementById("Bouton_PA_OFF").className = "PA_OFF";
				
					document.getElementById("Bouton_PTT_ON").disabled = false;
					document.getElementById("Bouton_PTT_ON").className = "PTT_ON";
					document.getElementById("Bouton_PTT_OFF").disabled = true;
					document.getElementById("Bouton_PTT_OFF").className = "PTT_IDLE";
					
				}
				else if  ((etat_PA == 1) && (etat_PTT == 1)){ //  PA = 1; PTT = 1 only allow ptt to be set off
				

			
				
					document.getElementById("Bouton_PA_ON").disabled = true;
					document.getElementById("Bouton_PA_ON").className = "PA_IDLE";
					document.getElementById("Bouton_PA_OFF").disabled = true;
					document.getElementById("Bouton_PA_OFF").className = "PA_IDLE";
				
					document.getElementById("Bouton_PTT_ON").disabled = true;
					document.getElementById("Bouton_PTT_ON").className = "PTT_IDLE";
					document.getElementById("Bouton_PTT_OFF").disabled = false;
					document.getElementById("Bouton_PTT_OFF").className = "PTT_OFF";
					
				}
				
			}
		}
	
		        		
		// lecture des boutons de commande
		function Btn_PTT_ON() // PTT Relay 
		{
			
				var seuil_haut_temp = document.getElementById("seuil_haut_temp").value;
				if ((temp < seuil_haut_temp) && (PA_state === 1) ) { // PTT Relay can be set ON only if temp < high treshold and PSU on
					strRelay1 = "&PTT=1";
				}
			
		}
		
		function Btn_PTT_OFF() // PTT Relay 
		{
			
				if ((PA_state === 1)) { 
					strRelay1 = "&PTT=0";
				}
			
			
		}
		
		
		function Btn_PA_ON() // PA Power (mains supply of the 28V power supply or 28V output if we add an additional relay which supports 20A!)
		{
				if (PTT_state === 0)  { // PA Power can be set ON only if FAN is ON and TX OFF
					strRelay2 = "&PA=1";
				}			
		}
		
		function Btn_PA_OFF() // PA Power (mains supply of the 28V power supply or 28V output if we add an additional relay which supports 20A!)
		{
				if (PTT_state === 0)  { // PA Power can be set OFF only if FAN is ON and TX OFF
					strRelay2 = "&PA=0";
				}
		}
				
		
		function Reset_alarme(){
		
				document.getElementById("dep_temp").value = "";
				document.getElementById('dep_temp').style.backgroundColor='#FFFFFF'; 
				document.getElementById('dep_temp').style.color='#FFFFFF';
				
				document.getElementById("dep_U_PA").value="";
				document.getElementById('dep_U_PA').style.backgroundColor='#FFFFFF'; 
				document.getElementById('dep_U_PA').style.color='#FFFFFF';
			
				document.getElementById("dep_I_PA").value = "";
				document.getElementById('dep_I_PA').style.backgroundColor='#FFFFFF'; 
				document.getElementById('dep_I_PA').style.color='#FFFFFF';
			
				document.getElementById("dep_Dir_RF").value = "";
				document.getElementById('dep_Dir_RF').style.backgroundColor='#FFFFFF'; 
				document.getElementById('dep_Dir_RF').style.color='#FFFFFF';
			
				document.getElementById("dep_Refl_RF").value = "";
				document.getElementById('dep_Refl_RF').style.backgroundColor='#FFFFFF'; 
				document.getElementById('dep_Refl_RF').style.color='#FFFFFF';
				
				document.getElementById("etat_eth").className = "liaison_eth_on";
			    document.getElementById("etat_eth").value = "";
				
				strReset_alarme = "&Reset_alarme";
				nb_coupure = 0;
		}
		
		function change_lim(lim) {
		
				//count_requete = 0;
				
			if (lim == 'TH') {
				// string filling strSeuilTH to send the new value to the server
				if(isNaN(document.getElementById("seuil_haut_temp").value) == false) // la valeur est un nombre
				{
					seuil_haut_temp = parseFloat(document.getElementById("seuil_haut_temp").value);
					strSeuilTH = "&Lim_temp_haute=" + seuil_haut_temp + "&";
				}
				else // la valeur du champ n'est pas un nombre !
				{
					alert('Please enter a valid number!');
				}	
			}
			
			else if (lim == 'TB') {
				// string filling strSeuilTB to send the new value to the server
				if(isNaN(document.getElementById("seuil_bas_temp").value) == false) // la valeur est un nombre
				{
				seuil_bas_temp = parseFloat(document.getElementById("seuil_bas_temp").value);
				strSeuilTB = "&Lim_temp_basse=" + seuil_bas_temp + "&";
				}
				else {
					alert('Please enter a valid number!');
				}
			}
			
			else if (lim == 'U') {
				// string filling strSeuilU to send the new value to the server
				if(isNaN(document.getElementById("seuil_haut_U_PA").value) == false) // la valeur est un nombre
				{
				seuil_haut_U_PA = parseFloat(document.getElementById("seuil_haut_U_PA").value);
				strSeuilU = "&Lim_U_PA=" + seuil_haut_U_PA + "&";
				}
				else {
					alert('Please enter a valid number!');
				}
				
			}
			else if (lim == 'I') {
				if(isNaN(document.getElementById("seuil_haut_I_PA").value) == false) // la valeur est un nombre
				{
				// filling streulI string to send the new value to the server
				seuil_haut_I_PA= parseFloat(document.getElementById("seuil_haut_I_PA").value);
				strSeuilI = "&Lim_I_PA=" + seuil_haut_I_PA + "&";
				}
				else {
					alert('Please enter a valid number!');
				}
				
			}
			else if (lim == 'DRF') {
				if(isNaN(document.getElementById("seuil_haut_Dir_RF").value) == false) // la valeur est un nombre
				{
				// string filling strSeuilDRF to send the new value to the server
				seuil_Dir_RF = parseFloat(document.getElementById("seuil_haut_Dir_RF").value);
				strSeuilDRF = "&Lim_Dir_RF=" + seuil_Dir_RF + "&";
				}
				else {
					alert('Please enter a valid number!');
				}
				
				}
				
				
			else if (lim == 'HHO') {  // change heater off threshold
				if(isNaN(document.getElementById("seuil_haut_htr_on").value) == false) // la valeur est un nombre
				{
				// string filling strSeuilHHO to send the new value to the server
				seuil_HHO = parseFloat(document.getElementById("seuil_haut_htr_on").value);
				strSeuilHHO = "&Lim_htr_high=" + seuil_HHO + "&";
				}
				else {
					alert('Please enter a valid number!');
				}
			
				
								}
								
			else if (lim == 'LHO') { // change htr off threshold
				if(isNaN(document.getElementById("seuil_haut_htr_off").value) == false) // la valeur est un nombre
				{
				// string filling strSeuilHHO to send the new value to the server
				seuil_LHO = parseFloat(document.getElementById("seuil_haut_htr_off").value);
				strSeuilLHO = "&Lim_htr_low=" + seuil_LHO + "&";
				}
				else {
					alert('Please enter a valid number!');
				}
			
				
								}
			
			
				
		
			
			else if (lim == 'RRF') {
				if(isNaN(document.getElementById("seuil_haut_Refl_RF").value) == false) // la valeur est un nombre
				{
				// remplissage chaine strAlarRRF pour envoyer la nouvelle valeur au serveur
				seuil_Refl_RF = parseFloat(document.getElementById("seuil_haut_Refl_RF").value);
				strSeuilRRF = "&Lim_Refl_RF=" + seuil_Refl_RF + "&";
				}
				else {
					alert('Veuillez entrer un nombre valide !');
				}
			}
		}



		
		function debut_seuils_alarmes() {
			document.getElementById("Bt_param").style.display = "none";
			document.getElementById("seuils_alarmes").style.display = "block";
			document.getElementById("reglages").style.display = "none";
		}
		
		function fin_seuils_alarmes() {
			document.getElementById("Bt_param").style.display = "block";
			document.getElementById("seuils_alarmes").style.display = "none";
		}
		
		
		
		function fenetre_param() {
			document.getElementById("reglages").style.display = "block";
		}
		
	
			
		function change_load(type) {
			if (type == 'L') {
				strload = "&advanced";
			}
			
			else if (type == 'S') {
				strload = "&short";
			}
			else strload = "";
		}
			

		
	</script>
	
	
	<style>
	
		.PTT_OFF {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		.PTT_IDLE {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:gray; color:#737373;  }
		.PTT_ON {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }
	
		.PA_OFF {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		.PA_IDLE {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:gray; color:#737373;  }
		.PA_ON {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }
		
		.FAN_OFF {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		.FAN_IDLE {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:gray; color:#737373; }
		.FAN_ON {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }
		
		.AUX_OFF {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		.AUX_IDLE {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:gray; color:#737373; }
		.AUX_ON {width: 125px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }
		
		.etat_PTT_OFF {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		
		.etat_PTT_ON {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }
		
		.etat_PA_OFF {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		
		.etat_PA_ON {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }
		
		.etat_FAN_OFF {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		
		
		.etat_FAN_ON {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }
		
		.etat_AUX_OFF {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:green; }
		
		.etat_AUX_ON {width: 240px; height: 30px; font-size: 25px; -webkit-appearance: none; background-color:red; }

		.Bt_Alarm {width: 140px; height: 30px; font-size: 15px; -webkit-appearance: none; background-color:white; }
		
		
		.IO_box {
			float: left;
			margin: 0 20px 20px 0;
			border: 2px solid green;
			padding: 0 5px 0 5px;
			width: 600px;
		}
		.I_Button {
			float: left;
			margin: 0 20px 20px 0;
			border: 0px solid green;
			padding: 0 5px 0 5px;
			width: 600px;
		}
		
		h1 {
			font-size: 120%;
			color: blue;
			margin: 0 0 10px 0;
		}
		h2 {
			font-size: 85%;
			/*color: #5734E6;*/
			color: green;
			margin: 5px 0 5px 0;
		}
		h3 {
			font-size: 150%;
			color: #00A000;
			margin: 5px 0 5px 0;
		}
		p, form, button {
			font-size: 80%;
			color: #252525;
		}
		.small_text {
			font-size: 70%;
			color: #737373;
		}
		.alarme {
			height:20px;
			width:200px;
		}
		.limite {
			height:20px;
			width:60px;
		}
		.limite_erreur {
			height:20px;
			width:60px;
			background-color:red;
		}
		.liaison_eth_on {
			font-size: 150%;
			color: #00A000;
			margin: 5px 0 5px 0;
			width: 150px;
		}
		.liaison_eth_off {
			font-size: 150%;
			color: white;
			background-color:red;
			margin: 5px 0 5px 0;
			width: 150px;
		}
		.etat_eth_off {
			font-size: 50%;
			color: white;
			background-color:red;
			margin: 5px 0 5px 0;
			width: 150px;
		}
		.message {
			height:20px;
			width:590px;
			background-color:yellow;
		}
		.bouton_valid_cal_true {
			background-color:yellow;
		}
		.bouton_valid_cal_false {
			background-color:gray;
		}
		
	</style>
	
    </head>
    <body onload="GetArduinoIO()">
		<h2>	<svg width="550px" height="60px">
				<text font-size="24"  x="50" y="40" fill="green">
					QO-100 PA telemetry</text>
				
			</svg>
		</h2>
        <div class="IO_box">
			<h2>Measurements </h2>
			<table>
			<tbody>
			<tr><td nowrap ><p><h3>Temp : <span class="temp">...................</span> °C  </h3></td><td nowrap><input type="text" class="alarm" id="dep_temp" readonly value="..."></input></h3></td></p></tr>
			<tr><td nowrap ><p><h3>PA Voltage : <span class="U_PA">...</span> V </h3></td><td nowrap><input type="text" class="alarm" id="dep_U_PA" readonly value="..."></input></h3></td></p></tr>		
			<tr><td nowrap ><p><h3>PA Current : <span class="I_PA">...</span> A </h3></td><td nowrap><input type="text" class="alarm" id="dep_I_PA" readonly value="..."></input></h3></td></p></tr>
			<tr><td nowrap ><p><h3>Forward Power : <span class="D_RF">...</span> dBm ( <span class="W_Dir_RF">...</span> W ) </h3></td><td nowrap><input type="text" class="alarm" id="dep_Dir_RF" readonly value="..."></input></h3></td></p></tr>
			<tr><td nowrap ><p><h3>Reflected Power: <span class="R_RF">...</span> dBm ( <span class="W_Refl_RF">...</span> W ) </h3></td><td nowrap><input type="text" class="alarm" id="dep_Refl_RF" readonly value="..."></input></h3></td></p></tr>			
			<tr><td nowrap ><p></td><td nowrap><button type="button" id="Alarme_Bt" class="Bt_Alarm"  onclick="Reset_alarme()">Reset Alarms</button></td></p></tr>		
			</tbody>
			</table>

			<p><h3>RL : <span class="RL">...</span> dB ( VSWR : <span class="SWR">...</span> ) </h3></p>
			
			<p><h3>Ethernet status : <input type="text" class="liaison_eth_on" id="liaison_eth" readonly value="..."></input>
			<input type="text" class="liaison_eth_on" id="etat_eth" readonly value="..."></input></h3></p>
			<input type="radio" name="option_coupure" id="option1" value="false"  > Disable PA on link error
			<input type="radio" name="option_coupure" value="true" checked > Do not disable PA on link error
			
		</div>
		
		<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
		
		<div class="IO_box">
			<h2>Command</h2>
		
			
			<button type="button" id="Bouton_PTT_ON" class="PTT_IDLE" disabled onclick="Btn_PTT_ON()">TX ON</button>  <input type="text" class="etat_PTT_OFF" id="etat_PTT" readonly value="PTT relay is OFF"></input>
			<button type="button" id="Bouton_PTT_OFF" class="PTT_IDLE" disabled onclick="Btn_PTT_OFF()">TX OFF</button>  <br /><br />
			<button type="button" id="Bouton_PA_ON" class="PA_IDLE" disabled  onclick="Btn_PA_ON()">PSU ON</button>  <input type="text" class="etat_PA_OFF" id="etat_PA" readonly value="PA Power is OFF"></input>
			<button type="button" id="Bouton_PA_OFF" class="PA_IDLE" disabled onclick="Btn_PA_OFF()">PSU OFF</button><br /><br /> 
			<input type="text" class="etat_FAN_OFF" id="etat_FAN"  value="FAN is OFF"></input>			
			<input type="text" class="etat_AUX_OFF" id="etat_AUX"  value="Heater is OFF"></input>
			
		</div>

		<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
		<div class="I_Button" id="Bt_param" style="display:block">
			<button type="button" id="param" onclick="debut_seuils_alarmes()">Set alarm thresholds</button><br />
		</div>
		
		<div class="IO_box" id="reglages" style="display:none">
				<br />
				<div class="I_Button">
					<button type="button" id="reglages_alarmes" onclick="debut_seuils_alarmes()">Set alarm thresholds</button><br />
				</div>	
			</div>
			
			
		
			<br>
		

			<div class="IO_box" id="seuils_alarmes" style="display:none">
			
				<h2>Set temperature thresholds</h2>				
				PA temperature PTT inhibit threshold <input type="text" class="limite" id="seuil_haut_temp" value = ... onchange="change_lim('TH')"></input> °C <br /><br />
				Minimum fan off temperature <input type="text" class="limite" id="seuil_bas_temp" value = ... onchange="change_lim('TB')"></input> °C <br /><br />
				
				<h2>PA maximum voltage threshold </h2>				
				Inhibit PTT PA voltage threshold <input type="text" class="limite" id="seuil_haut_U_PA" value = ... onchange="change_lim('U')"></input> V <br /><br />
				
				<h2>Maximum PA current threshold</h2>				
				Inhibit PTT PA current threshold <input type="text" class="limite" id="seuil_haut_I_PA" value = ... onchange="change_lim('I')"></input> A <br /><br />
				
				<h2>Maximum RF power threshold </h2>				
				Inhibit PTT PA maximum power threshold <input type="text" class="limite" id="seuil_haut_Dir_RF" value = ... onchange="change_lim('DRF')"></input> dBm <br /><br />
				
				<h2>Maximum Reflected RF power threshold </h2>				
				Inhibit PTT PA refected power threshold <input type="text" class="limite" id="seuil_haut_Refl_RF" value = ... onchange="change_lim('RRF')"></input> dBm <br /><br />
				
				<h2>Heater on low temperature </h2>				
				Turn heater on low threshold <input type="text" class="limite" id="seuil_haut_htr_off" value = ... onchange="change_lim('LHO')"></input>  °C <br /><br />
				
				<h2>Heater off high temperature </h2>				
				Turn heater off high threshold <input type="text" class="limite" id="seuil_haut_htr_on" value = ... onchange="change_lim('HHO')"></input> °C  <br /><br />
								
				<button type="button" id="reglages_alarmes" onclick="fin_seuils_alarmes()">Exit</button><br />
		
			</div>
		
		</div>
		<div class="IO_box">
			choice for next load version :
			<input type="radio" name="full_version" id="full_vers" value="false"  onchange="change_load('L')" > full version
			<input type="radio" name="full_version" id="short_vers" value="false" onchange="change_load('S')"> display only
			
		</div>
		
    </body>
</html>

Look up tables


///////////  Forward RF Power Look up table ////////////////////

typedef struct {
	float x;
	float y;
} look_up_RFP;


#define Forward_RF_Power_TABLE_SIZE 13  // put in progmem to save space

look_up_RFP  Forward_RF_power_table[Forward_RF_Power_TABLE_SIZE]  = {
	{.x=	0	,	.y=	0	},
	{.x=	13	,	.y=	33	}, // 2w in dBm
	{.x=	18	,	.y= 36	},  // 4
	{.x=	25	,	.y=	39	},  // 8
	{.x=	36	,	.y=	42	}, // 16
	{.x=	51	,	.y=	45	},  // 32
	{.x=	57	,	.y=	46	},    // 45
	{.x=	65	,	.y=	47	},	// 50
	{.x=	83	,	.y=	49	},  // 80
	{.x=	106	,	.y=	50.8	}, // 120
	{.x=	107	,	.y=	51	},  // 125 
	{.x=	110	,	.y=	51.1	},  // 130 
  {.x=	115	,	.y=	51.8	},  // 150 
};


float lookup_forward_RF_power (const look_up_RFP * table, float x, int size);



///////////  Reflected RF Power Look up table ////////////////////

typedef struct {
	float x;
	float y;
} look_up_Reflected_RF_Power;


#define Reflected_RF_Power_TABLE_SIZE 6  // put in progmem to save space

look_up_Reflected_RF_Power  RF_Power_table[Reflected_RF_Power_TABLE_SIZE]  = {
	{.x=	0	,	.y=	0	},
	{.x=	5	,	.y=	33	},  // 2 watts
	{.x=	15	,	.y=	36	},  // 4 watts
	{.x=	35	,	.y=	39	},  // 8 watts
	{.x=	74	,	.y=	42	}, // 16 watts
	{.x=	150	,	.y=	45	}, // 32
	
};


float lookup_Reflected_RF_Power (const look_up_Reflected_RF_Power * table, float x, int size);


Have you tried using the browser console for error searching? Wireshark for packet sniffing? I use ajax myself and found cors problemens, that solved my case.

Hi Tordens
I'm not too good with Wireshark, but will make an effort to use it more efficiently to at least determine on which side the problem lies.
I used the browser console tools to fix my html errors but have not been successful so far with this bug / problem.
I don't understand what you meant by " I use ajax myself and found cors problemens, that solved my case.", if you have the time please elaborate.

Regards Tim

PS the reason I was reluctant to post the code was its size and I didn't expect anyone to wade through it all.

Observation, FWIW.

 // delay manually as we're in an ISR
    for (ii = 1; ii <= 1000; ii++) {
       for (jj = 1; jj <= 500; jj++) {
       }
    }

ISR best practice is to get in, set a flag to say we've been there, and exit. What's the rationale for needing to delay for what is likely a lot more than a second?
I'd set up a quick test, see how long that little gem takes to execute. Maybe, that interrupt is hanging up your reception, or transmission.

good point - I'll fix that bit of code to work as you suggest.
I must have missed that when I was tweaking the original code F6AAM code.

So that delay within the wdt ISR was taking a second and was not really necessary anyway.
I modified the ISR to set a flag and shut down the power to ensure rapid response then do house keeping outside of the ISR so no more delay within the ISR.
I'll run some more long term tests to see if that has helped.
Regards Tim

1 Like

That was the only thing that jumped out at me, anyway. Good luck.

1 Like

Just a quick up date.

Since I modified the wdt ISR to simply set a flag and toggle an output (as opposed to the delay and other stuff) everything seems much improved.

I have three mega's running with different IP addresses and after 3 days of running them 24/7 there's no recorded drop outs.

That said I'm still a little puzzled how fixing the wdt could have helped with the original problem.

Thanks to everyone who commented on this problem.

I'm now moving onto another issues regarding size and speed of webpages but will start another thread on that one.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.