#include <SetupPCM.h>


bool R40SetupPCM(InputTDM &aidata, ControlPCM186x &cpcm, bool offs,
		 const InputTDMSettings &aisettings) {
  cpcm.begin();
  bool r = cpcm.setMicBias(false, true);
  if (!r) {
    Serial.println("not available");
    return false;
  }
  cpcm.setRate(aidata, aisettings.rate());
  if (aidata.nchannels() < aisettings.nchannels()) {
    if (aisettings.nchannels() - aidata.nchannels() == 2) {
      if (aisettings.pregain() == 1.0) {
	cpcm.setupChannels(ControlPCM186x::CH3L, ControlPCM186x::CH3R,
			   ControlPCM186x::INVERTED);
        cpcm.setupTDM(aidata, offs);
        Serial.println("configured for 2 channels without preamplifier");
      }
      else {
        cpcm.setupChannels(ControlPCM186x::CH1L, ControlPCM186x::CH1R,
			   ControlPCM186x::INVERTED);
        cpcm.setupTDM(aidata, offs);
        Serial.printf("configured for 2 channels with preamplifier x%.0f\n",
		      aisettings.pregain());
      }
    }
    else {
      if (aisettings.pregain() == 1.0) {
        cpcm.setupChannels(ControlPCM186x::CH3L, ControlPCM186x::CH3R,
			   ControlPCM186x::CH4L, ControlPCM186x::CH4R,
			   ControlPCM186x::INVERTED);
        cpcm.setupTDM(aidata, offs);
        Serial.println("configured for 4 channels without preamplifier");
      }
      else {
        cpcm.setupChannels(ControlPCM186x::CH1L, ControlPCM186x::CH1R,
			   ControlPCM186x::CH2L, ControlPCM186x::CH2R,
			   ControlPCM186x::INVERTED);
        cpcm.setupTDM(aidata, offs);
        Serial.printf("configured for 4 channels with preamplifier x%.0f\n",
		      aisettings.pregain());
      }
    }
    cpcm.setSmoothGainChange(false);
    cpcm.setGainDecibel(aidata, aisettings.gainDecibel());
    cpcm.setFilters(ControlPCM186x::FIR, false);
  }
  else {
    // channels not recorded, but need to be configured to not corrupt TDM bus:
    cpcm.setupChannels(ControlPCM186x::CH1L, ControlPCM186x::CH1R);
    cpcm.setupTDM(offs);
    cpcm.powerdown();
    Serial.println("powered down");
  }
  return true;
}


void R40SetupPCMs(Input &aidata, const InputSettings &aisettings,
		  Device **controls, size_t ncontrols, Stream &stream) {
  aidata.clearChannels();
  ControlPCM186x **pcms = reinterpret_cast<ControlPCM186x**>(controls);
  aisettings.configure(&aidata);
  static_cast<InputTDM&>(aidata).setSwapLR();
  for (size_t k=0; k<ncontrols; k++) {
    stream.printf("Setup PCM186x %d on TDM %d: ", k, pcms[k]->TDMBus());
    R40SetupPCM(static_cast<InputTDM&>(aidata),
		static_cast<ControlPCM186x&>(*pcms[k]), k%2==1,
		static_cast<const InputTDMSettings&>(aisettings));
  }
  stream.println();
}


bool R4SetupPCM(InputTDM &aidata, ControlPCM186x &cpcm, bool offs,
		uint32_t rate, int nchannels, float gain) {
  cpcm.begin();
  bool r = cpcm.setMicBias(false, true);
  if (!r) {
    Serial.println("not available");
    return false;
  }
  cpcm.setRate(aidata, rate);
  if (aidata.nchannels() < nchannels) {
    if (nchannels - aidata.nchannels() == 2) {
      cpcm.setupChannels(ControlPCM186x::CH2L, ControlPCM186x::CH2R,
			 ControlPCM186x::INVERTED);
      cpcm.setupTDM(aidata, offs);
      Serial.println("configured for 2 channels");
    }
    else {
      cpcm.setupChannels(ControlPCM186x::CH2L, ControlPCM186x::CH2R,
			 ControlPCM186x::CH3L, ControlPCM186x::CH3R,
			 ControlPCM186x::INVERTED);
      cpcm.setupTDM(aidata, offs);
      Serial.println("configured for 4 channels");
    }
    cpcm.setSmoothGainChange(false);
    cpcm.setGainDecibel(aidata, gain);
    cpcm.setFilters(ControlPCM186x::FIR, false);
  }
  else {
    // channels not recorded, but need to be configured to not corrupt TDM bus:
    cpcm.setupChannels(ControlPCM186x::CH2L, ControlPCM186x::CH2R);
    cpcm.setupTDM(offs);
    cpcm.powerdown();
    Serial.println("powered down");
  }
  return true;
}


bool R4SetupPCM(InputTDM &aidata, ControlPCM186x &cpcm, bool offs,
		const InputTDMSettings &aisettings) {
  return R4SetupPCM(aidata, cpcm, offs, aisettings.rate(),
		    aisettings.nchannels(), aisettings.gainDecibel());
}


void R4SetupPCMs(Input &aidata, const InputSettings &aisettings,
		 Device **controls, size_t ncontrols, Stream &stream) {
  aidata.clearChannels();
  ControlPCM186x **pcms = reinterpret_cast<ControlPCM186x**>(controls);
  aisettings.configure(&aidata);
  static_cast<InputTDM&>(aidata).setSwapLR();
  for (size_t k=0; k<ncontrols; k++) {
    stream.printf("Setup PCM186x %d on TDM %d: ", k, pcms[k]->TDMBus());
    R4SetupPCM(static_cast<InputTDM&>(aidata),
	       static_cast<ControlPCM186x&>(*pcms[k]), k%2==1,
	       static_cast<const InputTDMSettings&>(aisettings));
  }
  stream.println();
}


void powerdownPCMs(Device **controls, size_t ncontrols) {
  ControlPCM186x **pcms = reinterpret_cast<ControlPCM186x**>(controls);
  for (size_t k=0; k<ncontrols; k++) {
    ControlPCM186x &pcm = static_cast<ControlPCM186x&>(*pcms[k]);
    pcm.powerdown();
  }
}
