#include "pwmclass.h"
#include "fifo.h"
#include "player.h"
#include "GsmDecoder.h"
#include "adcdma.h"
#include "oneway.h"
#include "gpio.h"
////////////////////////////////////////////////////////
/* Demo, které jen počítá od 0 do 1000000. Výstup je PWM
 * na pinech PA1/PA8 24kHz. Odvozeno z teploměru na
 * https://github.com/Kizarm/TTSCP_Client/tree/main/kecal/stm
 * 
 * Tohle se do CH32V003 prostě nevejde.
 * 12.05.2024 předěláno na voltmetr. Pin ADC je PA2, tlačítko
 * na PA1 proti 3.3V. Teploměr na čipu stojí za prd, muselo
 * by se to individuálně kalibrovat (nehledě na oteplení čipu).
 */
////////////////////////////////////////////////////////
class Meassure : public OneWay {
  GpioClass          buton;
  FIFO<unsigned, 8u> fifo;
  unsigned           avg, old;
  unsigned           passcnt;
  public:
    explicit Meassure () noexcept : OneWay(),
      buton (GPIOA,1,(GPIO_Speed_In | GPIO_UPDI_MPPO)),
      fifo(), avg(0u), old(0u), passcnt(0u) {
        buton.setPuPd(GPIO_PuPd_DOWN);
      }
    unsigned int Send (uint16_t * const ptr, const unsigned int len) override;
    void out ();
};
static inline unsigned absdiff (const unsigned a, const unsigned b) {
  int d = a - b;
  return d < 0 ? -d : +d;
}
////////////////////////////////////////////////////////
static PwmClass             pwm;
static FIFO<PText, FIFOLEN> fifo;
static TextPlayer           player (fifo);
static GsmDecoder           decoder(fifo);

static AdcDma   adc;
static Meassure meas;

int main () {
  pwm.attach (decoder);
  adc.attach (meas);
  for (;;) {
    meas.out();
  }
  return 0;
}
////////////////////////////////////////////////////////
static constexpr unsigned BK = 3316u << 4;  // Mělo by to být přesně 3300.
unsigned int Meassure::Send(uint16_t * const ptr, const unsigned int len) {
  for (unsigned n=0; n<len; n++) {
    const unsigned mv = (BK * ptr [n]) >> 16;
    avg = (avg * 15 + mv) >> 4; // klouzavý průměr s postupným zapomínáním
  }
  fifo.Write (avg);
  return 0;
}
void Meassure::out() {
  unsigned t;
  if (fifo.Read (t)) {
    if (passcnt) { passcnt -= 1u; } else {  // trochu pozdrž
      const unsigned delta = absdiff(t, old);
      if (delta > 10 or buton) {            // chci výstup
        old = t;
        player.say(old, 3);             // tady se zaplní fronta
        player.say(sayed_texts.units);  // v postatě nevalidními daty
        while (fifo.Read(t));           // takže zde ji vyprázdním
        passcnt = 10u;                  // a nastavím zpoždění (uklidni data)
      }
    }
  }
}