#include "pwmclass.h"
#include "GsmDecoder.h"

static const unsigned int  DataLenght = 2529384u;
extern "C" void * memcpy(void * dest, const void * src, size_t n);

GsmDecoder::GsmDecoder(GpioClass & io) noexcept : OneWay<uint16_t>(),
  led(io), flash(), gsm(), count(0u), pass(false) {
}
static constexpr int      INPUT_BIT_RANGE = 16;
static constexpr unsigned SIGMA_MASK      = (1u << (INPUT_BIT_RANGE  + 0)) - 1u;
static constexpr unsigned SIGNED_OFFEST   = (1u << (INPUT_BIT_RANGE  - 1));
 // Předpokládá se na vstupu signed int o šířce INPUT_BIT_RANGE
 // přičemž 0 na vstupu odpovídá MAXPWM / 2 na výstupu. Vypadá to divně, ale funguje.
static unsigned pwm_sd (const int input) {
  static unsigned sigma  = 0;   // podstatné je, že proměnná je statická
  const  unsigned sample = (input + SIGNED_OFFEST) * MAXPWM;
  sigma &= SIGMA_MASK;          // v podstatě se odečte hodnota PWM
  sigma += sample;              // integrace prostým součtem
  return sigma  >> INPUT_BIT_RANGE;
}
unsigned GsmDecoder::Send(uint16_t * dptr, const unsigned len) {
  led << pass;
  pass = ! pass;
  const unsigned step = sizeof(gsm_frame);
  static gsm_frame e;
  flash.ReadBlock(count, e, step);
  count += step;
  gsm.decode (e, tmp_buf);
  if (count >= DataLenght) count = 0u;
  for (unsigned n=0u, k=0u; k<len; n++) {
    const int16_t s = tmp_buf[n];
    dptr [k++] = pwm_sd (s);    // vyzkoušená metoda jak vylepšit PWM
    dptr [k++] = pwm_sd (s);    // pokud máme frekvenci PWM větší
    dptr [k++] = pwm_sd (s);    // než vzorkovací frekvence signálu ft = n * fs, n = 3
  }
  return 0;
}