#include <Arduino.h>
/*
 Software para controlar bomba WP-40 - 1 canal
 Arduino
 Bomba WP-40
 Transformador
 Reset do Arduino faz a função Feed(Para a bomba por 5m) e reinicializa passados esses 5m.
 */
// constantes
const int ModoFuncionamento = 3;
const int PWMPin =  9;
// Variaveis:
int EstadoPulse = 0;
long previousMillis = 0;
unsigned long currentMillis = millis();
void setup()
{
  // Inicializa PWM
  Serial.begin(9600);
  pinMode(PWMPin, OUTPUT);
  previousMillis = millis();
  /* Isto faz uma espera de 5 Minutos (5*60 = 300 Segundos = 300000 Milisegundos quando se faz o reset do arduino) Podem retirar se não quiserem esta funcionalidade, ou optar por colocar um butão e nesse caso a pausa teria que ser feita com milis() e quando pressionado o botão, fazer o delay do tempo que se quiser */
  //delay(300000);
}
/* Pulse(Imax, Imin, MilSegundos) - Modo 1
 Recebe de entrada:
 Imax: Intensidade máxima do Pulse
 Imin: Intensidade Minima depois do pulse
 MilSegundos: Nr de MiliSegundos de intervalo entre intesidade Máxima e Minima
 O Objectivo é variar directo, sem incremento gradual entre a velocidade máxima e velocidade minima pelo nr de segundos indicado
 Ex:
 Pulse(255, 100, 500)
 A Bomba deveria começar a cerca de 40%(100/255) durante 0,5 Segundos, em seguida faz 100% durante 0,5 Segundos
 */
void Pulse(int Imax, int Imin, int MiliSegundos)
{
  currentMillis = millis();
  if(currentMillis - previousMillis > MiliSegundos) {
    previousMillis = currentMillis;
    if(EstadoPulse==0){
      analogWrite(PWMPin, Imax);
      EstadoPulse = 1;
    } else {
      analogWrite(PWMPin, Imin);
      EstadoPulse = 0;
    }
  }
}
/* RampUp(IntMin, IntMax, Increm, Percent) - Modo 2
 Recebe de entrada:
 IntMin: Intensidade Inicial
 IntMax: Intensidade Final
 Increm: Nr de MiliSegundos de intervalo entre intesidade
 O Objectivo é variar directo com incremento gradual entre a intensidade minima e máxima, com Increm segundos de intervalo entre o incremento
 Ex:
 RampUp(50, 225, 500, 15)
 A Bomba faria:
 Começa nos 20% e fica durante 0,5 Seg
 Incrementa 15 ao PWM(65/255) ficando a 25% durante 0,5 Seg
 Vai incrementando 5% durante 0,5 Seg até chegar a 88%(225/255)
 */
void RampUp(int IntMin, int IntMax, int Increm, int Percent) {
  int ValorPwm = IntMin;
  analogWrite(PWMPin, ValorPwm);
  do
  {
    currentMillis = millis();
    if(currentMillis - previousMillis > Increm) {
      previousMillis = currentMillis;
      if(ValorPwm > IntMax) {
        ValorPwm = IntMax;
      }
      analogWrite(PWMPin, ValorPwm);
      ValorPwm = ValorPwm + Percent;
    }
  }
  while(ValorPwm < IntMax && ValorPwm >= IntMin);
}
/* RampDown(IntMin, IntMax, Increm, Percent) - Modo 2
 Recebe de entrada:
 IntMin: Intensidade Inicial
 IntMax: Intensidade Final
 Increm: Nr de MiliSegundos de intervalo entre intesidade
 O Objectivo é variar directo com incremento gradual entre a intensidade minima e máxima, com Increm segundos de intervalo entre o incremento
 Ex:
 RampUp(50, 225, 500, 15)
 A Bomba faria:
 Começa nos 20% e fica durante 0,5 Seg
 Incrementa 15 ao PWM(65/255) ficando a 25% durante 0,5 Seg
 Vai incrementando 5% durante 0,5 Seg até chegar a 88%(225/255)
 */
void RampDown(int IntMin, int IntMax, int Increm, int Percent) {
  int ValorPWM = IntMax;
  analogWrite(PWMPin, ValorPWM);
  do
  {
    currentMillis = millis();
    if(currentMillis - previousMillis > Increm) {
      previousMillis = currentMillis;
      if(ValorPWM < IntMin) {
        ValorPWM = IntMin;
      }
      analogWrite(PWMPin, ValorPWM);
      ValorPWM = ValorPWM - Percent;
    }
  }
  while(ValorPWM <= IntMax && ValorPWM > IntMin);
}
/*
Modo a utilizar dentro do ReefCrazy - Faz nX Pulse
 */
void PulseSingle(int Imax, int MiliSegundos, int NrTimes)
{
  int Contador = 0;
  do {
    Contador = Contador + 1;
    analogWrite(PWMPin, Imax);
    delay(MiliSegundos);
    analogWrite(PWMPin, 0);
    delay(100);
  }
  while (Contador <= NrTimes);
}
/* ReefCrazy(IntMin, IntMax, SegMud) - Modo 3
 Recebe de Entrada:
 Intensidade Minima: Intensidade minima a que a bomba Roda
 Intensidade Máxima: Intensidade Máxima a que a bomba roda
 Segundos entre as mudanças: Segundos até mudança de modo aleatório
 */
void ReefCrazy(int IntMin, int IntMax, int SegMud)
{
  int RNumber = random(IntMin, IntMax);
  int MidleR = (IntMin + IntMax) / 2;
  if(RNumber > (MidleR - 20) && RNumber < (MidleR + 20)) {
     PulseSingle(200, 500, 3);
  }
  if(RNumber > MidleR) {
    RampDown(IntMin, MidleR, 500, 15);
  }
  else
  {
    RampUp(MidleR, IntMax, 500, 15);
  }
  RNumber = random(IntMin, IntMax);
  MidleR = (IntMin + IntMax) / 2;
}
/* Modo 4
 Sem parametros de entrada, sobe dos 0 aos 125PWM, faz Pulse 2X, continua a subir aos 255;
 Começa a descer dos 255 até 125, faz pulse, e continua até 0;
 */
void JumpingHorse()
{
  RampUp(0, 125, 200, 5);
  PulseSingle(200, 500, 2);
  RampUp(125, 255, 200, 5);
  RampDown(125, 255, 200, 5);
  PulseSingle(200, 500, 2);
  RampDown(0, 125, 200, 5);
}
/* Modo 5
 - Nutrient Export Mode(5 Pulses a 0,5s, muito pequenos, mais 5 maiores, pulse grande para fazer onda, e o processo de pulses inverso).
 */
void NutrientZero()
{
  PulseSingle(125, 500, 5);
  PulseSingle(225, 500, 5);
  PulseSingle(255, 1000, 1);
  PulseSingle(225, 500, 5);
  PulseSingle(125, 500, 5);
}
/* Modo Desligar - Modo 6 Para fazer por exemplo manutenção ao aquario, fica preparado para quem usar botão*/
void Desligar()
{
  analogWrite(PWMPin, 0);
}
void loop(){
  if (ModoFuncionamento == 1) {
    Pulse(235, 50, 500);
  }
  if (ModoFuncionamento == 2) {
    RampUp(50, 225, 500, 15);
    RampDown(50, 225, 500, 15);
  }
  if (ModoFuncionamento == 3) {
    ReefCrazy(50, 225, 500);
  }
  if (ModoFuncionamento == 4) {
    JumpingHorse();
  }
  if (ModoFuncionamento == 5) {
    NutrientZero();
  }
  if (ModoFuncionamento == 6) {
    Desligar();
  }
}