/*
Name:       Test_KeyboardServo5.ino
Created:	31.10.2024
Author:     jpbbricole
Remarque:	Pression sur 4 touches + Enter d'un clavier au moyen d'un servo
			Introduction et extraction de la carte au  moyen d'un servo
*/
#include <Servo.h> // https://github.com/netlabtoolkit/VarSpeedServo#class-methods

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

enum {servoNumTouche1, servoNumTouche2, servoNumTouche3, servoNumTouche4, servoNumToucheEnter};

struct servoToucheDef     // Définition des servo de touches
{
	const int pin; // Pin de connexion
	int speed; // Vitesse
	int positionOff; // Position à l'arrêt
	int positionOn; // Position en travail
};

servoToucheDef servoTouchesPar[] = // Paramètres des servo de touches
{
	// pin   vitesse   off    on
	{   7,    120,     900,  1900},
	{   8,    120,     900,  1900},
	{   9,    120,     900,  1900},
	{  10,    120,     900,  1900},
	{  11,    120,     900,  1900},
};

const int servoTouchesNombre = sizeof(servoTouchesPar) / sizeof(servoTouchesPar[0]);

Servo servoTouches[servoTouchesNombre];     // Tableau des servo
const boolean servoAttente = true; // Si attendre fin du mouvement

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 < servoTouchesNombre; s ++)
	{
		servoTouches[s].attach(servoTouchesPar[s].pin);     // Activation des servo
		servoTouches[s].write(servoTouchesPar[s].positionOff);     // Servo off
	}
	servoCarte.attach(servoCartePar.pin);
	servoCarte.write(servoCartePar.positionOff);     // Servo off

	Serial.println("Entrez une commande:");
	Serial.println("CODE3447");
	Serial.println("CODE3408");
	Serial.println("CARTEIN");
	Serial.println("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 servo (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]);
		servoPressKey(codeKeyIndex);
	}
	Serial.println(F("Fin de composition"));
}

//------------------------------------- Fonction pour simuler l'appui sur une touche numérique
void servoPressKey(int keyIndex)
{
	Serial.println("\tPression touche: " + touchesLabels.substring(keyIndex, keyIndex +1));
	servoTouches[keyIndex].write(servoTouchesPar[keyIndex].positionOn);     // Servo on
	delay(800);
	servoTouches[keyIndex].write(servoTouchesPar[keyIndex].positionOff);     // Servo off
	delay(800);
}
Touche 3
Code 3478
Touche 7
Touche 4
Touche 8
Touche Enter
Carte