/* 23.05.2020
 *  LUMIERES DANS LA NUIT
 *  
 *  Petite simulation d'un emetteur morse.
 *  
 *  L'appui sur un interrupteur simule le manipulateur (nommé : switch)
 *  Une led (LedRythme) clignote selon le tempo
 *  Le rythme peut-être ajusté par un potentiomètre (potoRythme)
 *  Une led (Led) simule le message luminueux
 *  Le message envoyé est affiché sur un ecran (ici moniteur serie)
 *  
 *  ***
 *  
 *  la duree d'un point est appelée temps, par analogie avec la musique (dt)
 *  un point, un trait ou une serie d'espace est appelé segment
 *  la tolérence est l'écart accepté par l'appareil entre la durée idéale et la durée réelle
 *  (ex : pour un trait, au lieu de 3 temps,
 *  l'appareil reconnait tout signal de durée supérieure 2.25 temps (tolérence 0.75 temps)
 *  
 *  si l'interrupteur est pressé pendant une duree inferieure a dt + tolérence
 *  => c'est un point
 *  
 *  si 'l'interrupteur est pressé pendant une duree superieure a 3*dt - tolerence
 *  => c'est un trait
 *  
 *  si l'interrupteur est pressé pendant une duree intermédiare
 *  entre dt + tolérence et 3*dt - tolerence
 *  => ?, signe incompris
 *  
 *  si l'interrupteur est relaché pendant X dt:
 *  => X espaces
 *  
 *  
 */

// #### PARAMETRES DE MONTAGES
// a adapter au montage réel

const byte m_pinLed = 2; // branchement de la led
const byte m_pinSwitch = 3; // branchement de l'interrupteur

const byte m_pinLedRythme = 13; // branchement de la led rythme
const byte m_pinPotoRythme = A0; // branchement du potentiomètre



// #### PARAMETRES D'UTILISATIONS
// peuvent être ajustés manuellement

const int m_dt_min = 0; // plus petit dt pouvant être entré par l'utilisateur (en millisecondes)
const int m_dt_max = 500; // plus grand dt .... (en millisecondes)
 
const float m_tolerence = 0.5; // marge sur la duree du signal (long -> (3 - m_tolerence)*m_dt

// #### PARAMETRES INTERNES
// ne pas modifier

unsigned long m_pressedAt;
  // date a laquelle l'interrupteur a été pressé / relaché
  
unsigned long m_pressedFor;
  // duree pendant laquelle est pressé l'interrupteur

bool m_switchState;
  // etat de l'interrupteur

int m_dt;
  // duree d'un temps, correspondant a un point (en milisecondes)
  // determinée par le potentiomètre

bool m_rythmeState = true;
  // etat de la led de rythme

unsigned long m_rythmeChangedAt = millis();
  // date a laquelle a été changé l'état de la led pour la dernière fois




void setup() {
  // initialisation des pins
  pinMode(m_pinLed, OUTPUT);
  digitalWrite(m_pinLed, LOW);

  pinMode(m_pinLedRythme, OUTPUT);
  digitalWrite(m_pinLedRythme, m_rythmeState);
  
  pinMode(m_pinSwitch, INPUT);
  
  pinMode(m_pinPotoRythme, INPUT);

  // initialisation du port serie
  Serial.begin(9600);
  
  // initialisation des parametres
  m_switchState = digitalRead(m_pinSwitch);
  m_pressedAt = millis();

}



void loop() {

  // mesures des entrées
  bool newSwitchState = digitalRead(m_pinSwitch);
  int valPoto = analogRead(m_pinPotoRythme);

  // calcul du nouveaux rythme
  m_dt = map(valPoto, 0, 1024, m_dt_min, m_dt_max);
  
  afficherRythme(); // change l'état de la led rythme si nécessaire

  // affiche le signal sur le moniteur serie si l'état de l'interrupteur a changé
  afficherSignal(newSwitchState);

  // update de l'état de l'interrupteur
  m_switchState = newSwitchState;
}




void afficherRythme(){
  /* change l'état de la led rythme si nécessaire*/
  if (millis() - m_rythmeChangedAt > m_dt / 2.){ // la led est allumée ou éteinte durant m_dt/2
    m_rythmeState = !m_rythmeState; // inverse l'état de la led
    digitalWrite(m_pinLedRythme, m_rythmeState); // allume ou eteind la led
    m_rythmeChangedAt = millis(); // update de l'état de la led
  }
}

void afficherSignal(bool newSwitchState){
  /* lorsque l'interrupteur est relaché / appuyé, affiche le segment sur le moniteur serie
   *  
   * - newSwitchState : bool, nouvel état de l'interrupteur 
   *  
   *  Les signes reconnus sont ".", "-", " "
   */
  if (newSwitchState != m_switchState){ // si l'etat de l'interrupteur a changé
    
    // calcul de la duree durant laquelle l'interrupteur est resté a l'état précedent
    m_pressedFor = millis() - m_pressedAt; 
    
    // enregistrement de la date du nouveau changement d'etat de l'interrupteur
    m_pressedAt = millis();

    // changement d'etat de la led
    digitalWrite(m_pinLed, newSwitchState);

    // interpretation de la duree d'appui ou de relachement de l'interrupteur
    if (m_switchState){ // l'interrupteur etait pressé
      if (m_pressedFor < m_dt * (1 + m_tolerence)){ // d'une pression brève
        Serial.print('.');  
      } else if (m_pressedFor > (3 - m_tolerence)*m_dt 
          && (m_pressedFor < (4 + m_tolerence)*m_dt)) { // d'une pression longue
        Serial.print('-');
      } else { // pression intermédiaire
        Serial.print('?');
      }
      
    } else { // l'interrupteur était relaché
      float spaceNbr = float(m_pressedFor) / m_dt;
        // nombre de temps correspondant à la durée sans signal
      if (spaceNbr < 5){
        for (int i = 0 ; i < round(spaceNbr) ; i++){
          Serial.print(' ');
        }
      } else {
        Serial.print('\n');
      }
    }
  }
} // END afficherSignal
