#include <Keypad.h>

const byte ROWS = 4; //4 rangées
const byte COLS = 3; //3 colonnes

char keys[ROWS][COLS] = {   //les symboles, déclarés par leur code ASCII dans le tableau à 2 dimension
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = { 8, 7, 6, 5 };
byte colPins[COLS] = {4, 3, 2};

Keypad membraneKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);  //On initialise une instance de la classe Keypad

const byte tailleMessageMax = 10;
char message[tailleMessageMax + 1]; // +1 car on doit avoir un caractère de fin de chaîne en C, le '\0'
const char marqueurDeFin = '#';

enum {DEBUT, ACQUISITION, GO} etat = DEBUT;
const byte nombreDAcquisitions = 3;
const unsigned long valeurMax = 9999;
unsigned long nombres[nombreDAcquisitions];
byte indexAcquisition;

boolean ecouter() {
  static byte indexMessage = 0; // static pour se souvenir de cette variable entre 2 appels consécutifs. initialisée qu'une seule fois.
  boolean messageEnCours = true;

  char c = membraneKeypad.getKey();
  if (c != NO_KEY) {
    if (c == marqueurDeFin) {
      message[indexMessage] = '\0'; // on termine la c-string
      indexMessage = 0; // on se remet au début pour la prochaine fois
      messageEnCours = false;
    } else if (indexMessage <= tailleMessageMax - 1)
      message[indexMessage++] = (char) c; // on stocke le chiffre et on passe à la case suivante
  }
  return messageEnCours;
}

void demande() {
  Serial.print("Entrez nombre N° ");
  Serial.print(indexAcquisition + 1);
  Serial.print(" (<= ");
  Serial.print(valeurMax);
  Serial.println(") suivi de # pour valider");
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  switch (etat) {
    case DEBUT:
      indexAcquisition = 0;
      demande();
      etat = ACQUISITION;
      break;

    case ACQUISITION:
      if (! ecouter()) {
        char * endPtr = nullptr;
        nombres[indexAcquisition] = strtoul(message, &endPtr, 10);
        if (endPtr != message && *endPtr == '\0' && nombres[indexAcquisition] <= valeurMax) {
          Serial.print("Reçu : '"); Serial.print(message);
          Serial.print("', j'ai extrait le nombre : "); Serial.println(nombres[indexAcquisition]);
          indexAcquisition++;
          if (indexAcquisition >= nombreDAcquisitions) etat = GO;
          else demande();
        } else { // il n'y avait pas moyen de lire un nombre correct
          Serial.print("Reçu :'"); Serial.print(message);
          Serial.print("' => entrée erronée");
          if (endPtr != message && *endPtr == '\0') Serial.println(" (trop grand)");
          else Serial.println();
          demande();
        }
      }
      break;

    case GO:
      Serial.print("Les ");
      Serial.print(nombreDAcquisitions);
      Serial.print(" nombres sont :");
      for (unsigned long v : nombres) {
        Serial.print(v);
        Serial.print(' ');
      }
      Serial.println("\n------------------\n\n\n");

      etat = DEBUT; // on recommence
      break;

  }

  // ici on peut faire autre chose
}