From 79531f5698f1c10e83edd36e6be12b671b443442 Mon Sep 17 00:00:00 2001
From: 3gg <3gg@shellblade.net>
Date: Sat, 4 Dec 2021 22:14:16 -0800
Subject: Add program.

---
 textil.ino | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 201 insertions(+)
 create mode 100644 textil.ino

diff --git a/textil.ino b/textil.ino
new file mode 100644
index 0000000..846cb41
--- /dev/null
+++ b/textil.ino
@@ -0,0 +1,201 @@
+enum Reles {
+  Rele1,
+  Rele2,
+  Rele3,
+  MAX_RELE,
+};
+
+/* Configuracion */
+
+// Tiempos de espera antes de emitir senyales de salida de rele.
+// Unidades en milisegundos (1s = 1000ms).
+const unsigned long TIEMPO_ESPERA_SALIDA_MS[MAX_RELE] = {
+  5000,  // Rele 1.
+  2000,  // Rele 2.
+  3000,  // Rele 3.
+};
+
+// Pines reles.
+//
+// Pines 0 y 1 en Arduino UNO son para comunicacion serie, no usar.
+const int Rele_Pin[MAX_RELE] = {
+  2,  // Rele 1.
+  3,  // Rele 2.
+  4,  // Rele 3.
+};
+
+// Pin pulsador.
+const int Pulsador_Pin = 5;
+
+enum Estado {
+  Estado_Inicial,
+  Espera_Rele1,
+  Salida_Rele1,
+  Espera_Rele2,
+  Salida_Rele2,
+  Espera_Rele3,
+  Salida_Rele3,
+  Estado_Final,
+  MAX_ESTADO,
+};
+
+enum Transicion {
+  Automatica,  // Transicion automatica.
+  Retardada,   // Transicion automatica retardada.
+  Manual,      // Transicion al pulsar boton.
+};
+
+const Transicion transiciones[MAX_ESTADO] = {
+  Manual,      // Estado_Inicial -> Espera_Rele1
+  Retardada,   //                -> Salida_Rele1
+  Manual,      //                -> Espera_Rele2
+  Retardada,   //                -> Salida_Rele2
+  Manual,      //                -> Espera_Rele3
+  Retardada,   //                -> Salida_Rele3
+  Manual,      //                -> Estado_Final
+  Automatica,  //                -> Estado_Inicial
+};
+
+
+/* Entrada digital con debounce. */
+
+// Tiempo en el que la senyal debe permanecer con un valor constante para
+// que se ejecute la lectura logica de la senyal.
+const unsigned long DEBOUNCE_DELAY_MS = 50;
+
+struct EntradaDigital {
+  int pin;                         // Pin de entrada.
+  int estado;                      // Estado logico actual, LOW o HIGH.
+  int ultima_senyal;               // Ultima senyal de entrada, LOW o HIGH.
+  unsigned long debounce_time_ms;  // Tiempo del ultimo cambio de estado en la entrada.
+};
+
+// Lee un cambio de estado de la entrada digital.
+// Devuelve cierto si se ejecuta un cambio de estado logico, falso en caso contrario.
+bool leer_cambio_de_estado(EntradaDigital& entrada, unsigned long tiempo) {
+  const int senyal_actual = digitalRead(entrada.pin);
+
+  bool estado_cambiado = false;
+  
+  if (senyal_actual != entrada.ultima_senyal) {
+    entrada.debounce_time_ms = tiempo;
+  }
+  else if (
+    ((tiempo - entrada.debounce_time_ms) >= DEBOUNCE_DELAY_MS) &&
+    (senyal_actual != entrada.estado) ){
+      entrada.estado = senyal_actual;
+      estado_cambiado = true;
+  }
+
+  entrada.ultima_senyal = senyal_actual;
+  return estado_cambiado;
+}
+
+
+/* Programa principal. */
+
+Estado estado_actual;
+EntradaDigital pulsador;
+unsigned long tiempo_ultima_transicion;
+
+// Ejecuta una transicion de estado y devuelve el nuevo estado.
+Estado ejecutar_transicion(Estado estado, unsigned long tiempo) {
+  tiempo_ultima_transicion = tiempo;
+  return Estado((estado + 1) % MAX_ESTADO);
+}
+
+// Actualiza la salida despues de un cambio de estado.
+void actualizar_salida(Estado estado_actual) {
+  switch (estado_actual) {
+    case Estado_Inicial:
+      break;
+    case Salida_Rele1:
+      digitalWrite(Rele_Pin[Rele1], HIGH);
+      break;
+    case Espera_Rele2:
+      digitalWrite(Rele_Pin[Rele1], LOW);
+      break;
+    case Salida_Rele2:
+      digitalWrite(Rele_Pin[Rele2], HIGH);
+      break;
+    case Espera_Rele3:
+      digitalWrite(Rele_Pin[Rele2], LOW);
+      break;
+    case Salida_Rele3:
+      digitalWrite(Rele_Pin[Rele3], HIGH);
+      break;
+    case Estado_Final:
+      digitalWrite(Rele_Pin[Rele3], LOW);
+      break;
+    default:
+      break;
+  }
+}
+
+// Devuelve el tiempo de espera para el estado dado.
+unsigned long get_tiempo_espera(Estado estado) {
+  switch (estado) {
+    case Espera_Rele1:
+      return TIEMPO_ESPERA_SALIDA_MS[Rele1];
+    case Espera_Rele2:
+      return TIEMPO_ESPERA_SALIDA_MS[Rele2];
+    case Espera_Rele3:
+      return TIEMPO_ESPERA_SALIDA_MS[Rele3];
+    default:
+      return 0;
+  }
+}
+
+// Inicializacion.
+void setup() {
+  const unsigned long tiempo = millis();
+  
+  for (int i = 0; i < MAX_RELE; ++i) {
+    pinMode(Rele_Pin[i], OUTPUT);
+    digitalWrite(Rele_Pin[i], LOW);
+  }
+  pinMode(Pulsador_Pin, INPUT);
+  
+  estado_actual = Estado_Inicial;
+
+  pulsador = (EntradaDigital) {
+    .pin = Pulsador_Pin,
+    .estado = LOW,
+    .ultima_senyal = LOW,
+    .debounce_time_ms = tiempo,
+  };
+
+  tiempo_ultima_transicion = tiempo;
+}
+
+// Bucle principal.
+void loop() {
+  const unsigned long tiempo = millis();
+  const Estado estado_original = estado_actual;
+
+  switch (transiciones[estado_actual]) {
+    case Automatica:
+      estado_actual = ejecutar_transicion(estado_actual, tiempo);
+      break;
+
+    case Retardada: {
+      const unsigned long tiempo_espera = get_tiempo_espera(estado_actual);
+      if ( (tiempo - tiempo_ultima_transicion) >= tiempo_espera ) {
+        estado_actual = ejecutar_transicion(estado_actual, tiempo);
+      }
+      break;
+    }
+
+    case Manual: {
+      const bool pulsador_estado_cambiado = leer_cambio_de_estado(pulsador, tiempo);
+      if (pulsador_estado_cambiado && pulsador.estado == HIGH) {
+        estado_actual = ejecutar_transicion(estado_actual, tiempo);
+      }
+      break;
+    }
+  }
+
+  if (estado_actual != estado_original) {
+    actualizar_salida(estado_actual);
+  }
+}
-- 
cgit v1.2.3