//! Determines trim values for the target clock. \n
//! The values determined are written to the Flash image for later programming.
//!
//! @param flashImage - Flash image to be updated.
//!
//! @return error code see \ref USBDM_ErrorCode
//!
//! @note If the trim frequency indicated in parameters is zero then no trimming is done.
//!       This is not an error.
//!
USBDM_ErrorCode FlashProgrammer::setFlashTrimValues(FlashImage *flashImage) {
   LOGGING_Q;
   ClockParameters clockTrimParameters;
   USBDM_ErrorCode rc;
   uint16_t ftrimMergeValue __attribute__((unused));

   // Assume no trim or failure
   parameters.setClockTrimValue(0);

   // No trimming required
   if (parameters.getClockTrimFreq() == 0) {
      return PROGRAMMING_RC_OK;
   }
   // Logging::print("setFlashTrimValues() - trimming\n");
   progressTimer->restart("Calculating Clock Trim");

#if TARGET == RS08
   uint32_t NVTRIM_address  = parameters.getClockTrimNVAddress();
   uint32_t NVFTRIM_address = parameters.getClockTrimNVAddress()+1;
#else
   uint32_t NVFTRIM_address  __attribute__((unused)) = parameters.getClockTrimNVAddress();
   uint32_t NVTRIM_address   __attribute__((unused)) = parameters.getClockTrimNVAddress()+1;
#endif

   switch (parameters.getClockType()) {
      case CLKEXT:
      case CLKINVALID:
      default:
         return PROGRAMMING_RC_OK;
      case MKMCGV1:
         // 9-bit value
         rc = trimMCG_Clock(&clockTrimParameters.mcg);
         if (rc != PROGRAMMING_RC_OK) {
            return rc;
         }
         parameters.setClockTrimValue((clockTrimParameters.mcg.mcgTrim<<1)|
                                      (clockTrimParameters.mcg.mcgSC&0x01));
         flashImage->setValue(parameters.getClockTrimNVAddress()+1,
                                         clockTrimParameters.mcg.mcgTrim);
         flashImage->setValue(parameters.getClockTrimNVAddress(),
                                         clockTrimParameters.mcg.mcgSC&0x01);
         return PROGRAMMING_RC_OK;
   }
   return PROGRAMMING_RC_ERROR_ILLEGAL_PARAMS;
}
//! Determines trim values for the target clock. \n
//! The values determined are written to the Flash image for later programming.
//!
//! @param flashImage - Flash image to be updated.
//!
//! @return error code see \ref USBDM_ErrorCode
//!
//! @note If the trim frequency indicated in parameters is zero then no trimming is done.
//!       This is not an error.
//!
USBDM_ErrorCode FlashProgrammer::setFlashTrimValues(FlashImage *flashImage) {
   LOGGING_Q;
   ClockParameters clockTrimParameters;
   USBDM_ErrorCode rc;
   uint16_t  ftrimMergeValue;

   // Assume no trim or failure
   parameters.setClockTrimValue(0);

   // No trimming required
   if (parameters.getClockTrimFreq() == 0) {
      return PROGRAMMING_RC_OK;
   }
   // Logging::print("setFlashTrimValues() - trimming\n");
   progressTimer->restart("Calculating Clock Trim");

#if TARGET == RS08
   uint32_t NVTRIM_address  = parameters.getClockTrimNVAddress();
   uint32_t NVFTRIM_address = parameters.getClockTrimNVAddress()+1;
#else
   uint32_t NVFTRIM_address = parameters.getClockTrimNVAddress();
   uint32_t NVTRIM_address  = parameters.getClockTrimNVAddress()+1;
#endif

   switch (parameters.getClockType()) {
      case CLKEXT:
      case CLKINVALID:
         return PROGRAMMING_RC_OK;
      case S08ICGV1:
      case S08ICGV2:
      case S08ICGV3:
      case S08ICGV4:
         // 8-bit value (LSB ignored)
         rc = trimICG_Clock(&clockTrimParameters.icg);
         if (rc != PROGRAMMING_RC_OK)
            return rc;
         parameters.setClockTrimValue(clockTrimParameters.icg.icgTrim<<1);
         flashImage->setValue(parameters.getClockTrimNVAddress(),
                                         clockTrimParameters.icg.icgTrim);
         return PROGRAMMING_RC_OK;
      case S08ICSV1:
      case S08ICSV2:
      case S08ICSV3:
      case S08ICSV4:
      case RS08ICSV1:
      case RS08ICSOSCV1:
      case S08ICSV2x512:
         // 9-bit value
         rc = trimICS_Clock(&clockTrimParameters.ics);
         if (rc != PROGRAMMING_RC_OK) {
            return rc;
         }
         parameters.setClockTrimValue((clockTrimParameters.ics.icsTrim<<1)|
                                       (clockTrimParameters.ics.icsSC&0x01));
         flashImage->setValue(NVTRIM_address, clockTrimParameters.ics.icsTrim);
         // The FTRIM bit may be combined with other bits such as DMX32 or DRS
         ftrimMergeValue = flashImage->getValue(parameters.getClockTrimNVAddress());
         if (((ftrimMergeValue&0xFF) == 0xFF)||(ftrimMergeValue >= 0xFF00U)) {
            // Image location is unused or contains the unprogrammed FLASH value
            // So no value to merge trim with - clear all other bits
            ftrimMergeValue = 0x00;
         }
         Logging::print("Merging FTRIM with 0x%02X\n", ftrimMergeValue);
         flashImage->setValue(NVFTRIM_address, (ftrimMergeValue&~0x01)|(clockTrimParameters.ics.icsSC&0x01));
         return PROGRAMMING_RC_OK;
      case S08MCGV1:
      case S08MCGV2:
      case S08MCGV3:
         // 9-bit value
         rc = trimMCG_Clock(&clockTrimParameters.mcg);
         if (rc != PROGRAMMING_RC_OK) {
            return rc;
         }
         parameters.setClockTrimValue((clockTrimParameters.mcg.mcgTrim<<1)|
                                      (clockTrimParameters.mcg.mcgSC&0x01));
         flashImage->setValue(parameters.getClockTrimNVAddress()+1,
                                         clockTrimParameters.mcg.mcgTrim);
         flashImage->setValue(parameters.getClockTrimNVAddress(),
                                         clockTrimParameters.mcg.mcgSC&0x01);
         return PROGRAMMING_RC_OK;
   }
   return PROGRAMMING_RC_ERROR_ILLEGAL_PARAMS;
}