/*
Name:       Test_KeyboardSolenoides.ino
Created:	02.11.2024
Author:     jpbbricole
Remarque:	Pression sur 4 touches + Enter d'un clavier au moyen d'un solenoide
			Introduction et extraction de la carte au  moyen d'un servo
*/
#include <Servo.h>

//------------------------------------- Servo 
const String touchesLabels = "3478E"; // Touches desservie par un des 4 servo

enum {solenoideNumTouche1, solenoideNumTouche2, solenoideNumTouche3, solenoideNumTouche4, solenoideNumToucheEnter};

struct solenoideToucheDef     // Définition des solenoides de touches
{
	const int pin; // Pin de connexion
	unsigned long tempo; // Temps de pression
};

solenoideToucheDef solenoideTouchesPar[] = // Paramètres des solenoides de touches
{
	// pin    tempo
	{  11,    800},
	{  10,    800},
	{   9,    800},
	{   8,    800},
	{   7,    800},
};

const int solenoideTouchesNombre = sizeof(solenoideTouchesPar) / sizeof(solenoideTouchesPar[0]);
const int solenoideEtatOn = HIGH; // Etat pour faire tirer le solenoide

struct servoCarteDef     // Définition des servo de la carte
{
	const int pin = 12; // Pin de connexion
	int speed = 110; // Vitesse
	int positionOff = 900; // Position à l'arrêt
	int positionOn = 1900; // Position en travail
};
servoCarteDef servoCartePar; // Paramètres du servo de la carte
Servo servoCarte; // Servo de la carte

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

	//------------------------------------ initialisation des servo
	for (int s = 0; s < solenoideTouchesNombre; s ++)
	{
		pinMode(solenoideTouchesPar[s].pin, OUTPUT);
		digitalWrite(solenoideTouchesPar[s].pin, !solenoideEtatOn); // Faire tomber le solenoide
		//servoTouches[s].attach(solenoideTouchesPar[s].pin);     // Activation des servo
		//servoTouches[s].write(solenoideTouchesPar[s].positionOff, solenoideTouchesPar[s].speed, servoAttente);     // Servo off
	}
	servoCarte.attach(servoCartePar.pin);
	servoCarte.write(servoCartePar.positionOff);     // Servo off

	Serial.println(F("Entrez une commande:"));
	Serial.println(F("CODE3447"));
	Serial.println(F("CODE3408"));
	Serial.println(F("CARTEIN"));
	Serial.println(F("CARTEOUT"));
}

void loop()
{
	if (Serial.available())
	{
		cmdExecute( Serial.readStringUntil('\n'));
	}
}
/*
Commandes depuis le moniteur:
CARTEIN Introduction de la carte
CARTEOUT retrait de la carte
CODE4437E	Compose le code 4437 et la touche Enter
*/

void cmdExecute(String cmd) // Execution de la commande
{
	cmd.trim(); // Nettoyer les 2 bouts de la chaîne
	cmd.toUpperCase(); // Tout en majuscules
	cmd.replace(" ", ""); // Supprimer les espaces
	
	Serial.println("Execution de: " + cmd);
	
	if (cmd.startsWith(F("CODE"))) // Composition d'un code
	{
		cmd.replace(F("CODE"), ""); // Ne garder que les chiffres
		codeComposeCheck(cmd);
	}
	else if (cmd.startsWith(F("CARTE"))) // Carte
	{
		Serial.print("\tCarte ");
		cmd.replace(F("CARTE"), ""); // Ne garder que les chiffres
		if (cmd == "IN")
		{
			Serial.println("Introduction");
			carteIntroduction();
		}
		else if (cmd == "OUT")
		{
			Serial.println("Retrait");
			carteRetrait();
		}
		else
		{
			Serial.println("Commande inconnue " + cmd);
		}
	}
	else
	{
		Serial.println("\tCommande inconnue !!! " + cmd);
	}
}

//------------------------------------- Carte
void carteIntroduction()
{
	servoCarte.write(servoCartePar.positionOn);     // Carte introduite
}

void carteRetrait()
{
	servoCarte.write(servoCartePar.positionOff);     // Carte retirée
}

void codeComposeCheck(String code)
{
	Serial.println("Code a composer: " + code);
	
	boolean codeOk = codePossible(code);
//Serial.println(codeOk);
	if (codeOk)
	{
		Serial.println("Code OK");
		codeCompose(code);
	}
	else
	{
		Serial.println("Code ???");
	}
}

/*
Test s'il est possible de composer ce code en fonction de la position des solenoides (touchesLabels[])
*/
boolean codePossible(String codeTest)
{
	for (int c = 0; c < codeTest.length(); c ++)
	{
		String codeNum = (String)codeTest[c];
		if (touchesLabels.indexOf(codeNum) == -1) // Si touche pas desservie
		{
			return false;
		}
	}
	return true; // Touche desservie
}

void codeCompose(String codeDial) // Composition du code
{
	Serial.println("Composition du code; " + codeDial);

	for (int c = 0; c < codeDial.length(); c ++)
	{
		String codeKey = (String)codeDial[c];
		int codeKeyIndex = touchesLabels.indexOf((String)codeDial[c]);
		solenoidesPressKey(codeKeyIndex);
	}
	Serial.println(F("Fin de composition"));
}

//------------------------------------- Fonction pour simuler l'appui sur une touche numérique
void solenoidesPressKey(int keyIndex)
{
	Serial.println("\tPression touche: " + touchesLabels.substring(keyIndex, keyIndex +1));
	digitalWrite(solenoideTouchesPar[keyIndex].pin, solenoideEtatOn); // Faire tomber le solenoide
	delay(solenoideTouchesPar[keyIndex].tempo);
	digitalWrite(solenoideTouchesPar[keyIndex].pin, !solenoideEtatOn); // Faire tomber le solenoide
	delay(solenoideTouchesPar[keyIndex].tempo);
}
S 3
Code 3478
S 7
S 4
S 8
S Enter
Carte