//! \brief Configures the target clock appropriately for flash programming
//!        The speed would be the maximum safe value for an untrimmed target
//!
//! @param busFrequency    - Resulting BDM frequency after clock adjustment \n
//!                          For a HCS08/CFV1 with CLKSW=1 this will be the bus frequency
//!
//! @return error code, see \ref USBDM_ErrorCode
//!
USBDM_ErrorCode FlashProgrammer::configureTargetClock(unsigned long  *busFrequency) {
   LOGGING_E;

   //! MCG parameters for flash programming 4/8 MHz
   static const MK_MCG_ClockParameters_t MCG_FlashSpeedParameters = {
         // bdm clock = reference clock * 1024/2
         /* .mcgC1   = */ 0x04, // IREFS
         /* .mcgC2   = */ 0x40, // BDIV=/2
         /* .mcgC3   = */ 0x01, // VDIV=x4 (not used)
         /* .mcgTrim = */ 0x80, // TRIM=nominal
         /* .mcgSC   = */ 0x00, // FTRIM=0
         /* .mcgCT   = */ 0x00, // DMX32=0, DRS=0
   };

   MK_MCG_ClockParameters_t   MCG_SpeedParameters   = MCG_FlashSpeedParameters;

//   Logging::print("Configuring Target clock\n");

   switch (parameters.getClockType()) {
      case CLKEXT:
      case CLKINVALID:
      default:
         return configureExternal_Clock(busFrequency);
      case MKMCGV1:
         // Program clock for approx. 8 MHz
         MCG_SpeedParameters.mcgCT = 0x01; // DRS = 1
         return configureMCG_Clock(busFrequency, &MCG_SpeedParameters);
         break;
   }
   return PROGRAMMING_RC_ERROR_ILLEGAL_PARAMS;
}
USBDM_ErrorCode FlashProgrammer::trimMCG_Clock(MCG_ClockParameters_t *clockParameters) {
   LOGGING_E;

   static const MCG_ClockParameters_t MCG_LowSpeedParameters = {
         // bus clock = reference clock * (512,1024)/8/2
         //           = (32,64)*refClk (~32.5kHz)
         //           ~ (1,2) MHz
         /* .mcgC1   = */ 0x04, // IREFS
         /* .mcgC2   = */ 0xC0, // BDIV=/8
         /* .mcgC3   = */ 0x01, // VDIV=x4 (not used)
         /* .mcgTrim = */ 0x80, // TRIM=default
         /* .mcgSC   = */ 0x00, // FTRIM=0
         /* .mcgCT   = */ 0x00, // DMX32=0, DRS=0
   };

   uint32_t MCGTRIM                = parameters.getClockAddress()+2;
   unsigned int  clockMultiplier;
   unsigned long targetBusFrequency;
   unsigned long originalBusFrequency;
   unsigned long measuredBusFrequency;
   uint16_t trimValue;
   USBDM_ErrorCode rc;

   switch (parameters.getClockType()) {
      case S08MCGV2:
      case S08MCGV3:
         clockMultiplier = 512;
         break;
      case S08MCGV1:
         clockMultiplier = 1024;
         break;
      default:
         return PROGRAMMING_RC_ERROR_ILLEGAL_PARAMS;
   }

   targetBusFrequency = parameters.getClockTrimFreq()*(clockMultiplier/8/2);

   *clockParameters = MCG_LowSpeedParameters;

   Logging::print("TrimF = %.2f kHz, clock Multiplier=%d => Trim bus Freq=%.2f kHz\n",
         parameters.getClockTrimFreq()/1000.0, (1024/8/2), targetBusFrequency/1000.0);

   // Program clock for a low speed to improve accuracy of trimming
   rc = configureMCG_Clock(&originalBusFrequency, clockParameters);
   if (rc != PROGRAMMING_RC_OK) {
      return rc;
   }
//   Logging::print("trimMGCClock(Clock Freq = %.2f kHz, bus Freq = %.2f kHz)\n",
//           parameters.getClockTrimFreq()/1000.0, bdmFrequency/1000.0);

   rc = FlashProgrammer::trimTargetClock(MCGTRIM, targetBusFrequency, &trimValue, &measuredBusFrequency, TRUE);
   if (rc != PROGRAMMING_RC_OK) {
      return rc;
   }
   Logging::print("Desired Freq = %.2f kHz, "
         "Meas. Freq=%.2f kHz, Trim=0x%02X/%1.1X\n",
         parameters.getClockTrimFreq()/1000.0,
         (measuredBusFrequency/(clockMultiplier/16))/1000.0,
         trimValue>>1, trimValue&0x01);

   // Update trim value
   clockParameters->mcgTrim  = trimValue>>1;
   clockParameters->mcgSC   |= trimValue&0x01;

   return rc;
}
//! \brief Configures the target clock appropriately for flash programming
//!        The speed would be the maximum safe value for an untrimmed target
//!
//! @param busFrequency    - Resulting BDM frequency after clock adjustment \n
//!                          For a HCS08/CFV1 with CLKSW=1 this will be the bus frequency
//!
//! @return error code, see \ref USBDM_ErrorCode
//!
USBDM_ErrorCode FlashProgrammer::configureTargetClock(unsigned long  *busFrequency) {
   LOGGING_E;

   //! ICSCG parameters for flash programming (Maximum safe speed untrimmed 4/8MHz)
   static const ICS_ClockParameters_t ICS_FlashSpeedParameters = {
         // bdm clock = reference clock * 512/1024
         /* .icsC1   = */ 0x04, // IREFS
         /* .icsC2   = */ 0x40, // BDIV=/2
         /* .icsTrim = */ 0x80, // TRIM=nominal
         /* .icsSC   = */ 0x00, // DRS=0,DMX32=0,FTRIM=0
   };
   //! ICSCG parameters for flash programming (Maximum safe speed untrimmed 4/8MHz)
   static const ICS_ClockParameters_t ICSV4_FlashSpeedParameters = {
         // bdm clock = reference clock * 512/1024
         /* .icsC1   = */ 0x04, // IREFS
         /* .icsC2   = */ 0x20, // BDIV=/2
         /* .icsTrim = */ 0x80, // TRIM=nominal
         /* .icsSC   = */ 0x00, // DRS=0,DMX32=0,FTRIM=0
   };
   //! ICGCG parameters for flash programming
   static const ICG_ClockParameters_t ICG_FlashSpeedParameters = {
         // bdm clock = 64*MFDt*reference clock/(7*RDFt) = 64*14*refClk/(7*2*2) = 32*refClk
         /* .icgC1     = */ 0x48, // CLKS=01, RANGE=1
         /* .icgC2     = */ 0x51, // MFD=5, RFD=1
         /* .icgFilter = */ 0x00, // Not used
         /* .icgTrim   = */ 0x80, // TRIM=128
   };
   //! ICGCG parameters for flash programming 4/8 MHz
   static const MCG_ClockParameters_t MCG_FlashSpeedParameters = {
         // bdm clock = reference clock * 1024/2
         /* .mcgC1   = */ 0x04, // IREFS
         /* .mcgC2   = */ 0x40, // BDIV=/2
         /* .mcgC3   = */ 0x01, // VDIV=x4 (not used)
         /* .mcgTrim = */ 0x80, // TRIM=nominal
         /* .mcgSC   = */ 0x00, // FTRIM=0
         /* .mcgCT   = */ 0x00, // DMX32=0, DRS=0
   };

   ICS_ClockParameters_t   ICS_SpeedParameters   = ICS_FlashSpeedParameters;
   ICS_ClockParameters_t   ICSV4_SpeedParameters = ICSV4_FlashSpeedParameters;
   ICG_ClockParameters_t   ICG_SpeedParameters   = ICG_FlashSpeedParameters;
   MCG_ClockParameters_t   MCG_SpeedParameters   = MCG_FlashSpeedParameters;

//   Logging::print("Configuring Target clock\n");

   switch (parameters.getClockType()) {
      case CLKEXT:
      case CLKINVALID:
         return configureExternal_Clock(busFrequency);
      case S08ICGV1:
      case S08ICGV2:
      case S08ICGV3:
      case S08ICGV4:
         // Program clock for approx. 8 MHz
         return configureICG_Clock(busFrequency, &ICG_SpeedParameters);
      case S08ICSV1:
      case S08ICSV2:
      case S08ICSV2x512:
      case S08ICSV3:
      case RS08ICSV1:
      case RS08ICSOSCV1:
         // Program clock for approx. 4/8 MHz
         return configureICS_Clock(busFrequency, &ICS_SpeedParameters);
      case S08ICSV4:
         // Program clock for approx. 4/8 MHz
         return configureICS_Clock(busFrequency, &ICSV4_SpeedParameters);
      case S08MCGV1:
      case S08MCGV3:
         // Program clock for approx. 4/8 MHz
         return configureMCG_Clock(busFrequency, &MCG_SpeedParameters);
         break;
      case S08MCGV2:
         // Program clock for approx. 8 MHz
         MCG_SpeedParameters.mcgCT = 0x01; // DRS = 1
         return configureMCG_Clock(busFrequency, &MCG_SpeedParameters);
         break;
   }
   return PROGRAMMING_RC_ERROR_ILLEGAL_PARAMS;
}