Strange problem with simple counter variable (and solution, but still confusing)

Status
Not open for further replies.
Hello people!

I'm working on a indoor air quality monitor. The Teensy (3.6) reads different sensors, writes new data to related arrays and displays the measures on an e-paper display every 78 seconds. I need to count the valid measures in this arrays, so I count them:
Code:
validMeasures_6H = validMeasures_6H + 1;
    if (validMeasures_6H >= 290) {
      validMeasures_6H = 290;
    }

"validMeasures_6H" is defined as an integer variable. The problem is, that validMeasures_6H stays at the value "1". Then I tried this:

Code:
validMeasures6H = validMeasures6H + 1;
    if (validMeasures6H >= 290) {
      validMeasures6H = 290;
    }

Strange to say this does work. But its becoming more strange. The following code still doesn't work. The variable "counter" stays at "1". "counter" is also defined as an integer variable.

Code:
counter = counter + 1;
    if (counter >= 290) {
      counter = 290;
    }

I have absolutely no idea what's the problem with this code. Here is the complete code. I is a little bit messy. Sorry for that. Maybe anybody has an idea?

Code:
// Innenraumluftqualitätsmonitor

// include library, include base class, make path known
#include <GxEPD.h>

// select the display class to use, only one
#include <GxGDEW075T8/GxGDEW075T8.cpp>      // 7.5" b/w
#include <GxIO/GxIO_SPI/GxIO_SPI.cpp>
#include <GxIO/GxIO.cpp>


#include <U8g2_for_Adafruit_GFX.h>
U8G2_FOR_ADAFRUIT_GFX u8g2_for_adafruit_gfx;


// Pins_arduino.h, e.g. AVR
#define PIN_SPI_SS    (10)
#define PIN_SPI_MOSI  (11)
#define PIN_SPI_MISO  (12)
#define PIN_SPI_SCK   (13)

GxIO_Class io(SPI, /*CS=*/ SS, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9 selected for default of GxEPD_Class
GxEPD_Class display(io /*RST=9*/ /*BUSY=7*/); // default selection of (9), 7



#include "Adafruit_SGP30.h"
  
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

Adafruit_SGP30 sgp;

Adafruit_BME280 bme; // I2C

#include "RunningAverage.h"
RunningAverage averageCO2(60);        // RunningAverage-Objekt für Glättung der CO2-Messwerte
RunningAverage averageTVOC(60);       // RunningAverage-Objekt für Glättung der TVOC-Messwerte
RunningAverage averageTEMP(1);        // RunningAverage-Objekt für Glättung der Temperatur-Messwerte (Muss später auf eine sinnvolle Länge geändert werden.)
RunningAverage averageHUMI(1);        // RunningAverage-Objekt für Glättung der Luftfeuchtigkeits-Messwerte (Muss später auf eine sinnvolle Länge geändert werden.)
RunningAverage averagePRES(1);        // RunningAverage-Objekt für Glättung der Luftdruck-Messwerte (Muss später auf eine sinnvolle Länge geändert werden.)

// Sechs-Stunden-Arrays
unsigned int arrayCO2_6H[291];         // Messwerte für ECO2
unsigned int arrayTVOC_6H[291];        // Messwerte für TVOC
float arrayTEMP_6H[290];               // Messerte für Temperatur
float arrayHUMI_6H[290];               // Messwerte für Luftfeuchtigkeit
float arrayPRES_6H[290];               // Messwerte für Luftdruck
int validMeasures6H;              // Zählt den "Füllstand" der Sechs-Stunden Arrays.
int counter;



// Definiert die Tracking-Variablen für die IF-Abfragen
unsigned long previousMillisBME280 = 0;          // Adafruit BME280
unsigned long previousMillisSGP30 = 0;          // Adafruit SGP30
unsigned long previousMillisArrays = 0;          // Arrays
unsigned long previousMillisDisplay = 0;          // Display

// Definiert die Intervalle für die IF-Abfragen in Millisekunden
const unsigned long intervalBME280 = 78000;        // konstanter Delay für Adafruit BME280
const unsigned long intervalSGP30 = 1000;          // konstanter Delay für Adafruit SGP30 (Der Sensor muss einmal pro Sekunde abgefragt werden, damit die automatische Kalibrierung funktioniert.)
const unsigned long intervalArrays = 78000;        // konstanter Delay für Arrays
const unsigned long intervalDisplay = 78000;        // konstanter Delay für Display


void setup () {
  Serial.begin(115200);
  delay(1000);

  // e-Paper Display Waveshare 7,5 Zoll
  Serial.println();
  Serial.println("Setup Display");
  display.init(115200); // enable diagnostic output on Serial
  Serial.println("Setup done");


  // Air Quality Sensor SGP30
  if (! sgp.begin()){
    Serial.println("Sensor not found :(");
    while (1);
  }
  Serial.print("SGP30 serial number ");
  Serial.print(sgp.serialnumber[0], HEX);
  Serial.print(sgp.serialnumber[1], HEX);
  Serial.println(sgp.serialnumber[2], HEX);

  // If you have a baseline measurement from before you can assign it to start, to 'self-calibrate'
  sgp.setIAQBaseline(0x899D, 0x8D36);

 
  // Temperature, Humidity, Pressure Sensor BME280
  bool status;
  status = bme.begin();  
  if (!status) {
      Serial.println("Could not find a valid BME280 sensor, check wiring!");
      while (1);
  }
  bme.setSampling(Adafruit_BME280::MODE_FORCED,
                    Adafruit_BME280::SAMPLING_X1, // temperature
                    Adafruit_BME280::SAMPLING_X1, // pressure
                    Adafruit_BME280::SAMPLING_X1, // humidity
                    Adafruit_BME280::FILTER_OFF   );
  
  // Leeren der Arrays der RunningAverage-Objekte
  averageCO2.clear();
  averageTVOC.clear();
  averageTEMP.clear();
  averageHUMI.clear();
  averagePRES.clear();
  
  display.setRotation(0);
  display.fillScreen(GxEPD_WHITE);
  display.update();
  u8g2_for_adafruit_gfx.begin(display);                 // connect u8g2 procedures to Adafruit GFX
  
}

void loop() {
// Aktuelle Zeit abfragen
  unsigned long currentMillis = millis();


// Adafruit SGP30 abfragen
  if ((unsigned long)(currentMillis - previousMillisSGP30) >= intervalSGP30) {
    
    // Werte für Temperatur und Luftfeuchtigkeit werden an den Sensor übergeben
    float temperature, humidity;
    if (millis() < 78000) {                                       // Gültige Messwerte liegen erst nach 78 Sekunden vor
      temperature = 25.0;                      // [°C]
      humidity = 50.0;                         // [%RH]
    }
    else {
      temperature = averageTEMP.getAverage(); // [°C]
      humidity = averageHUMI.getAverage();    // [%RH]
    }
    sgp.setHumidity(getAbsoluteHumidity(temperature, humidity));

    // Daten auslesen und an die Glättung übergeben
    if (! sgp.IAQmeasure()) {
      Serial.println("Measurement failed");
      return;
    }
    
    //Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
    //Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");   

    averageCO2.addValue(sgp.eCO2);        // Fügt dem Objekt einen neuen Wert hinzu
    averageTVOC.addValue(sgp.TVOC);       // Fügt dem Objekt einen neuen Wert hinzu

          
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisSGP30 = currentMillis;
  }


  // Adafruit BME280 abfragen
  if ((unsigned long)(currentMillis - previousMillisBME280) >= intervalBME280) {
    
    bme.takeForcedMeasurement();
    averageTEMP.addValue(bme.readTemperature());
    averageHUMI.addValue(bme.readHumidity());
    averagePRES.addValue(bme.readPressure() / 100.0F);

    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisBME280 = currentMillis;
  }


// Arrays mit Daten füllen 
  if ((unsigned long)(currentMillis - previousMillisArrays) >= intervalArrays) {

    // Die Sechs-Stunden-Arrays werden mit Daten befüllt. Die aktuelle Messung steht immer ganz links im Array. Ältere Messungen werden automatisch verschoben.
    addUnsignedIntegerToArray (arrayCO2_6H, averageCO2.getAverage());
    addUnsignedIntegerToArray (arrayTVOC_6H, averageTVOC.getAverage());
    addFloatToArray (arrayTEMP_6H, averageTEMP.getAverage());
    addFloatToArray (arrayHUMI_6H, averageHUMI.getAverage());
    addFloatToArray (arrayPRES_6H, averagePRES.getAverage());

    // Der "Füllstand" der Sechs-Stunden-Arrays wird gezählt
    validMeasures6H = validMeasures6H + 1;
    if (validMeasures6H >= 290) {
      validMeasures6H = 290;
    }
    Serial.print("validMeasures6H: "); Serial.println(validMeasures6H);
    
    counter = counter + 1;
    if (counter >= 290) {
      counter = 290;
    }
    Serial.print("counter: "); Serial.println(counter);
    
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisArrays = currentMillis;
  }
  
  
  // Display
  if ((unsigned long)(currentMillis - previousMillisDisplay) >= intervalDisplay) {

    display.fillScreen(GxEPD_WHITE);                      // Der Displayinhalt wird gelösch
    display.setTextColor(GxEPD_BLACK);

    // Symbole
    display.drawRect(0, 0, 40, 40, GxEPD_BLACK);       // Platzhalter
    display.drawRect(160, 0, 40, 40, GxEPD_BLACK);       // Platzhalter
    display.drawRect(320, 0, 40, 40, GxEPD_BLACK);       // Platzhalter
  
    // Temperatur, Luftfeuchtigkeit und Luftdruck
    display.setFontMode(1);
    display.setBackgroundColor(GxEPD_WHITE);
    display.setForegroundColor(GxEPD_BLACK);
    display.setFont(u8g2_font_helvB14_tf);
    
    display.setCursor(45, 15);
    display.print(arrayTEMP_6H[0], 1);
    display.print("°C");
    
    display.setCursor(205, 15);
    display.print(arrayHUMI_6H[0], 1);
    display.print("% rH");

    display.setCursor(365, 15);
    display.print(arrayPRES_6H[0], 1);
    display.print(" hPa");

    // Anzeige der CO2-Werte
    unsigned int minCO2 = minValue(arrayCO2_6H, validMeasures6H);  // Berechnet den Minimalwert im Array für alle "gültigen" Messwerte)
    Serial.print("minCO2: ");
    Serial.println(minCO2);
    
    unsigned int maxCO2 = maxValue(arrayCO2_6H, validMeasures6H);  // Berechnet den Minimalwert im Array für alle "gültigen" Messwerte)
    Serial.print("maxCO2: ");
    Serial.println(maxCO2);
    
    // Zeigt das Sechs-Stunden-Array für eCO2 an
    if (validMeasures6H > 1) {                                     // Es müssen zwei Messwerte vorliegen, um den Graph zeihenen zu können
      for (int i=0; i < validMeasures6H; i++) {

        display.drawLine((315 - i), (map(arrayCO2_6H[i], 400, maxCO2, 224, 104)), (315 - i - 1), (map(arrayCO2_6H[i + 1], 400,  maxCO2, 224, 104)), GxEPD_BLACK);

      }
    }
    
    // Textanzeige des aktuellsten Werts
    display.setFontMode(1);
    display.setForegroundColor(GxEPD_BLACK);
    display.setFont(u8g2_font_7x13B_mr);
    //display.setTextSize(1);
    display.setCursor(95, 97);
    display.print("Kohlendioxid: ");
    display.print(averageCO2.getAverage(), 0);
    display.println(" ppm");
    
    // Hilfslinien mit Beschriftung
    display.drawRect(25, 104, 290, 120, GxEPD_BLACK);       // Kasten
    for (int i = 30; i < 310; i = i + 6) {                  // Hilfslinie 75%
      display.drawLine(i, 134, (i + 3), 134, GxEPD_BLACK);
    }
    for (int i = 30; i < 310; i = i + 6) {                  // Hilfslinie 50%
      display.drawLine(i, 164, (i + 3), 164, GxEPD_BLACK);
    }
    for (int i = 30; i < 310; i = i + 6) {                  // Hilfslinie 25%
      display.drawLine(i, 194, (i + 3), 194, GxEPD_BLACK);
    }

    display.setFont();
    display.setTextSize(1);        
    display.setCursor(0, 100);                              // Beschriftung 100%
    displayprintAlignRight(maxCO2);
    display.setCursor(0, 130);                              // Beschriftung 75%                  
    displayprintAlignRight(((maxCO2 - 400) * 0.75) + 400);
    display.setCursor(0, 160);                              // Beschriftung 75%                  
    displayprintAlignRight(((maxCO2 - 400) * 0.5) + 400);
    display.setCursor(0, 190);                              // Beschriftung 50%                  
    displayprintAlignRight(((maxCO2 - 400) * 0.25) + 400);
    display.setCursor(0, 220);                              // Beschriftung 0%
    display.print(" 400");
    
    
    // Anzeige der TVOC-Werte
    unsigned int minTVOC = minValue(arrayTVOC_6H, validMeasures6H);             // Berechnet den Minimalwert im Array für die ersten 290 Elemente)
    Serial.print("minTVOC: ");
    Serial.println(minTVOC);
    
    unsigned int maxTVOC = maxValue(arrayTVOC_6H, validMeasures6H);             // Berechnet den Minimalwert im Array für die ersten 290 Elemente)
    Serial.print("maxTVOC: ");
    Serial.println(maxTVOC);

    // Zeigt das Sechs-Stunden-Array für TVOC an
    if (validMeasures6H > 1) {                                                  // Es müssen zwei Messwerte vorliegen, um den Graph zeihenen zu können
      for (int i=0; i < validMeasures6H; i++) {

        display.drawLine((315 - i), (map(arrayTVOC_6H[i], 0, maxTVOC, 374, 254)), (315 - i - 1), (map(arrayTVOC_6H[i + 1], 0,  maxTVOC, 374, 254)), GxEPD_BLACK);

      }
    }  
    // Textanzeige des aktuellsten Werts
    display.setFontMode(1);
    display.setForegroundColor(GxEPD_BLACK);
    display.setFont(u8g2_font_7x13B_mr);
    display.setCursor(65, 247);
    display.print("Organische Verbindungen: ");
    display.print(averageTVOC.getAverage(), 0);
    display.println(" ppb");

    // Hilfslinien mit Beschriftung
    display.drawRect(25, 254, 290, 120, GxEPD_BLACK);       // Kasten
    for (int i = 30; i < 310; i = i + 6) {                 // Hilfslinie 75%
      display.drawLine(i, 284, (i + 3), 284, GxEPD_BLACK);
    }
    for (int i = 30; i < 310; i = i + 6) {                 // Hilfslinie 50%
      display.drawLine(i, 314, (i + 3), 314, GxEPD_BLACK);
    }
    for (int i = 30; i < 310; i = i + 6) {                 // Hilfslinie 25%
      display.drawLine(i, 344, (i + 3), 344, GxEPD_BLACK);
    }
    // Beschriftung y-Achse
    display.setFont();
    display.setTextSize(1);        
    display.setCursor(0, 250);                              // Beschriftung 100%
    displayprintAlignRight(maxTVOC);
    display.setCursor(0, 280);                              // Beschriftung 75%                  
    displayprintAlignRight(maxTVOC * 0.75);
    display.setCursor(0, 310);                             // Beschriftung 75%                  
    displayprintAlignRight(maxTVOC * 0.5);
    display.setCursor(0, 340);                             // Beschriftung 50%                  
    displayprintAlignRight(maxTVOC * 0.25);
    display.setCursor(0, 370);                             // Beschriftung 0%
    display.print("   0");


    // Beschriftung x-Achse
    display.setFont();
    display.setTextSize(1);
    display.setCursor(295, 377); 
    display.println(" Test");

// Anzeige der Temperatur-Werte
    /*unsigned int minTVOC = minValue(arrayTVOC_6H, validMeasures6H);             // Berechnet den Minimalwert im Array für die ersten 290 Elemente)
    Serial.print("minTVOC: ");
    Serial.println(minTVOC);
    
    unsigned int maxTVOC = maxValue(arrayTVOC_6H, validMeasures6H);             // Berechnet den Minimalwert im Array für die ersten 290 Elemente)
    Serial.print("maxTVOC: ");
    Serial.println(maxTVOC);

    // Zeigt das Sechs-Stunden-Array für TVOC an
    if (validMeasures6H > 1) {                                                  // Es müssen zwei Messwerte vorliegen, um den Graph zeihenen zu können
      for (int i=0; i < validMeasures6H; i++) {

        display.drawLine((315 - i), (map(arrayTVOC_6H[i], 0, maxTVOC, 374, 254)), (315 - i - 1), (map(arrayTVOC_6H[i + 1], 0,  maxTVOC, 374, 254)), GxEPD_BLACK);

      }
    }  
    */
    // Textanzeige des aktuellsten Werts
    display.setFontMode(1);
    display.setForegroundColor(GxEPD_BLACK);
    display.setFont(u8g2_font_7x13B_mr);
    display.setCursor(365, 247);
    display.print("Organische Verbindungen: ");
    display.print(averageTVOC.getAverage(), 0);
    display.println(" ppb");

    // Hilfslinien mit Beschriftung
    display.drawRect(346, 254, 290, 120, GxEPD_BLACK);       // Kasten
    for (int i = 351; i < 631; i = i + 6) {                 // Hilfslinie 75%
      display.drawLine(i, 284, (i + 3), 284, GxEPD_BLACK);
    }
    for (int i = 351; i < 631; i = i + 6) {                 // Hilfslinie 50%
      display.drawLine(i, 314, (i + 3), 314, GxEPD_BLACK);
    }
    for (int i = 351; i < 631; i = i + 6) {                 // Hilfslinie 25%
      display.drawLine(i, 344, (i + 3), 344, GxEPD_BLACK);
    }
    // Beschriftung y-Achse
    display.setFont();
    display.setTextSize(1);        
    display.setCursor(321, 250);                              // Beschriftung 100%
    displayprintAlignRight(maxTVOC);
    display.setCursor(321, 280);                              // Beschriftung 75%                  
    displayprintAlignRight(maxTVOC * 0.75);
    display.setCursor(321, 310);                             // Beschriftung 75%                  
    displayprintAlignRight(maxTVOC * 0.5);
    display.setCursor(321, 340);                             // Beschriftung 50%                  
    displayprintAlignRight(maxTVOC * 0.25);
    display.setCursor(321, 370);                             // Beschriftung 0%
    display.print("   0");


    // Beschriftung x-Achse
    display.setFont();
    display.setTextSize(1);
    display.setCursor(616, 377); 
    display.println(" Test");
   
    display.update();

     
    //Speichere die aktuelle Zeit in die zughörige Variable
    previousMillisDisplay = currentMillis;
  } 
  
}

//######################################### Functions ##############################################

// Richtet Ziffern rechtsbündig aus, indem Leerzeichen vorangestellt werden
void displayprintAlignRight(int digits) {
  if(digits < 10) {
    display.print("   ");
  }
  else if (digits < 100) {
    display.print("  ");
  }
  else if (digits < 1000) {
    display.print(" ");
  }
  display.print(digits);
}

// Verschiebt alle Elemente in dem Array um eine Position nach rechts und fügt links einen neuen Unsigned-Integer-Wert hinzu
void addUnsignedIntegerToArray (unsigned int arrayName[], unsigned int value) {
  for (int i = 290; i >= 1; i--) {                          // 290 = Länge des Arrays!
    arrayName[i] = arrayName[i - 1]; 
  }
  arrayName[0] = value;

    Serial.print("Array Test: ");
    for (int i=0; i < 290; i++) {
      Serial.print(arrayName[i]);
      Serial.print("; ");
    }
    Serial.println();
}

// Verschiebt alle Elemente in dem Array um eine Position nach rechts und fügt links einen neuen Floating-Point-Wert hinzu
void addFloatToArray (float arrayName[], float value) {
  for (int i = 290; i >= 1; i--) {                          // 290 = Länge des Arrays!
    arrayName[i] = arrayName[i - 1]; 
  }
  arrayName[0] = value;

    Serial.print("Array Test: ");
    for (int i=0; i < 290; i++) {
      Serial.print(arrayName[i]);
      Serial.print("; ");
    }
    Serial.println();
}

// Bestimmt den Maximalwert in einem Array: "scope" gibt den Bereich an (beginnend bei 0)
unsigned int maxValue (unsigned int arrayName[], int scope) {
  unsigned int maxValue;
  unsigned int kmax = 0;
  unsigned int max = 0;
  for (int k = 0; k <= scope; k++) {
    if (arrayName[k] > max) {
      max = arrayName[k];
      kmax = k;
    }
  }
  return maxValue = arrayName[kmax];
}

// Bestimmt den Minimalwert in einem Array: "scope" gibt den Bereich an (beginnend bei 0)
unsigned int minValue (unsigned int arrayName[], int scope) {
  unsigned int minValue;
  unsigned int kmin = 0;
  unsigned int min = 60000;
  for (int k = 0; k < scope; k++) {
    if (arrayName[k] < min) {
      min = arrayName[k];
      kmin = k;
    }
  }
  return minValue = arrayName[kmin];
}

// Berechnet einen Korrekturwert für den Sensor SGP30
uint32_t getAbsoluteHumidity(float temperature, float humidity) {
  // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
  const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
  const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
  return absoluteHumidityScaled;
}
 
This function is overwriting the variable - "loop (i=" should start at 289 not 290 with this call: < edited to 289 and 290 >

addFloatToArray (arrayPRES_6H, averagePRES.getAverage());

Code:
void addFloatToArray (float arrayName[], float value) {
  for (int i = 290; i >= 1; i--) {                          // 290 = Länge des Arrays!
    arrayName[i] = arrayName[i - 1]; 
  }

Where the defines are:
Code:
... 
float arrayPRES_6H[290];               // Messwerte für Luftdruck
int validMeasures6H;              // Zählt den "Füllstand" der Sechs-Stunden Arrays.
int counter;
 
Last edited:
That works! Thank you for your help!

But I do not unterstand why the function overwrites the variables "validMeasures_6H" and "counter" but not the variable "validMeasures6H". Is that a question of chance?
 
But I do not unterstand why the function overwrites the variables "validMeasures_6H"

I tried looking at your code (from msg #1) but I don't see where "validMeasures_6H" (with an underscore) is defined. It only appears in a small code fragment at the top of msg #1, where that fragment does not show how the variable is actually declared. It's not anywhere in the full program!

Where you declare the variable matters. Global scope variables retain their value. Local variables (which aren't "static") cease to exist when your function doesn't run. Then they exist again the next time the function runs, so you can expect those to lose their value.

But since you didn't show the full code that includes the declaration of that validMeasures_6H, nobody can know whether it's global or local, or static, or something special like a class member. Those sorts of details are very important. That's why we have the Forum Rule about posting *complete* programs. When we can see the complete code, these sorts of subtle details are apparent and let us give you much better help.
 
Glad that worked!

The reason is the variables are side by side in memory and the array reference was going over its boundary end where it overwrote the following data space.
 
I tried looking at your code (from msg #1) but I don't see where "validMeasures_6H" (with an underscore) is defined. It only appears in a small code fragment at the top of msg #1, where that fragment does not show how the variable is actually declared. It's not anywhere in the full program!

Where you declare the variable matters. Global scope variables retain their value. Local variables (which aren't "static") cease to exist when your function doesn't run. Then they exist again the next time the function runs, so you can expect those to lose their value.

But since you didn't show the full code that includes the declaration of that validMeasures_6H, nobody can know whether it's global or local, or static, or something special like a class member. Those sorts of details are very important. That's why we have the Forum Rule about posting *complete* programs. When we can see the complete code, these sorts of subtle details are apparent and let us give you much better help.

Dear Paul,

in the code I've posted I had already changed "validMeasures_6H" to " validMeasures6H". I was confused, because the code didn't worked as expected with the variable name "validMeasures_6H", but it did worked with the variable name "validMeasures6H", both defined global and both as an unsigned integer variable. The only difference was the name of the variable. But defragster has pointed me to the problem. Everything works fine now.

Best,

Peter
 
Status
Not open for further replies.
Back
Top