text:
/**
 * @file    eTimer_v1/icu_lld.c
 * @brief   SPC5xx low level ICU driver code.
 *
 * @addtogroup ICU
 * @{
 */

#include "hal.h"

#if HAL_USE_ICU || defined(__DOXYGEN__)

/*===========================================================================*/
/* Driver local definitions.                                                 */
/*===========================================================================*/

/*===========================================================================*/
/* Driver exported variables.                                                */
/*===========================================================================*/

/**
 * @brief   ICUD1 driver identifier.
 * @note    The driver ICUD1 allocates the complex timer SMOD0 when enabled.
 */
#if SPC5_ICU_USE_SMOD0 || defined(__DOXYGEN__)
ICUDriver ICUD1;
#endif

/**
 * @brief   ICUD2 driver identifier.
 * @note    The driver ICUD2 allocates the complex timer SMOD1 when enabled.
 */
#if SPC5_ICU_USE_SMOD1 || defined(__DOXYGEN__)
ICUDriver ICUD2;
#endif

/**
 * @brief   ICUD3 driver identifier.
 * @note    The driver ICUD3 allocates the complex timer SMOD2 when enabled.
 */
#if SPC5_ICU_USE_SMOD2 || defined(__DOXYGEN__)
ICUDriver ICUD3;
#endif

/**
 * @brief   ICUD4 driver identifier.
 * @note    The driver ICUD4 allocates the complex timer SMOD3 when enabled.
 */
#if SPC5_ICU_USE_SMOD3 || defined(__DOXYGEN__)
ICUDriver ICUD4;
#endif

/**
 * @brief   ICUD5 driver identifier.
 * @note    The driver ICUD5 allocates the complex timer SMOD4 when enabled.
 */
#if SPC5_ICU_USE_SMOD4 || defined(__DOXYGEN__)
ICUDriver ICUD5;
#endif

/**
 * @brief   ICUD6 driver identifier.
 * @note    The driver ICUD6 allocates the complex timer SMOD5 when enabled.
 */
#if SPC5_ICU_USE_SMOD5 || defined(__DOXYGEN__)
ICUDriver ICUD6;
#endif

/**
 * @brief   ICUD7 driver identifier.
 * @note    The driver ICUD7 allocates the complex timer SMOD6 when enabled.
 */
#if SPC5_ICU_USE_SMOD6 || defined(__DOXYGEN__)
ICUDriver ICUD7;
#endif

/**
 * @brief   ICUD8 driver identifier.
 * @note    The driver ICUD8 allocates the complex timer SMOD7 when enabled.
 */
#if SPC5_ICU_USE_SMOD7 || defined(__DOXYGEN__)
ICUDriver ICUD8;
#endif

/**
 * @brief   ICUD9 driver identifier.
 * @note    The driver ICUD9 allocates the complex timer SMOD8 when enabled.
 */
#if SPC5_ICU_USE_SMOD8 || defined(__DOXYGEN__)
ICUDriver ICUD9;
#endif

/**
 * @brief   ICUD10 driver identifier.
 * @note    The driver ICUD10 allocates the complex timer SMOD9 when enabled.
 */
#if SPC5_ICU_USE_SMOD9 || defined(__DOXYGEN__)
ICUDriver ICUD10;
#endif

/**
 * @brief   ICUD11 driver identifier.
 * @note    The driver ICUD11 allocates the complex timer SMOD10 when enabled.
 */
#if SPC5_ICU_USE_SMOD10 || defined(__DOXYGEN__)
ICUDriver ICUD11;
#endif

/**
 * @brief   ICUD12 driver identifier.
 * @note    The driver ICUD12 allocates the complex timer SMOD11 when enabled.
 */
#if SPC5_ICU_USE_SMOD11 || defined(__DOXYGEN__)
ICUDriver ICUD12;
#endif

/**
 * @brief   ICUD13 driver identifier.
 * @note    The driver ICUD13 allocates the complex timer SMOD12 when enabled.
 */
#if SPC5_ICU_USE_SMOD12 || defined(__DOXYGEN__)
ICUDriver ICUD13;
#endif

/**
 * @brief   ICUD14 driver identifier.
 * @note    The driver ICUD14 allocates the complex timer SMOD13 when enabled.
 */
#if SPC5_ICU_USE_SMOD13 || defined(__DOXYGEN__)
ICUDriver ICUD14;
#endif

/**
 * @brief   ICUD15 driver identifier.
 * @note    The driver ICUD15 allocates the complex timer SMOD14 when enabled.
 */
#if SPC5_ICU_USE_SMOD14 || defined(__DOXYGEN__)
ICUDriver ICUD15;
#endif

/**
 * @brief   ICUD16 driver identifier.
 * @note    The driver ICUD16 allocates the complex timer SMOD15 when enabled.
 */
#if SPC5_ICU_USE_SMOD15 || defined(__DOXYGEN__)
ICUDriver ICUD16;
#endif

/**
 * @brief   ICUD17 driver identifier.
 * @note    The driver ICUD17 allocates the complex timer SMOD16 when enabled.
 */
#if SPC5_ICU_USE_SMOD16 || defined(__DOXYGEN__)
ICUDriver ICUD17;
#endif

/**
 * @brief   ICUD18 driver identifier.
 * @note    The driver ICUD18 allocates the complex timer SMOD17 when enabled.
 */
#if SPC5_ICU_USE_SMOD17 || defined(__DOXYGEN__)
ICUDriver ICUD18;
#endif

/*===========================================================================*/
/* Driver local variables.                                                   */
/*===========================================================================*/

/**
 * @brief   Number of active eTimer Submodules.
 */
static uint32_t icu_active_submodules0;
static uint32_t icu_active_submodules1;
static uint32_t icu_active_submodules2;

/**
 * @brief   Width and Period registers.
 */
uint16_t width;
uint16_t period;

/*===========================================================================*/
/* Driver local functions.                                                   */
/*===========================================================================*/

/**
 * @brief   Shared IRQ handler.
 *
 * @param[in] icup      pointer to the @p ICUDriver object
 */
static void icu_lld_serve_interrupt(ICUDriver *icup) {
  uint16_t sr = icup->etimerp->CHANNEL[icup->smod_number].STS.R &
                icup->etimerp->CHANNEL[icup->smod_number].INTDMA.R;

  if (ICU_SKIP_FIRST_CAPTURE) {
    if ((sr & 0x0008) != 0) { /* TOF */
      icup->etimerp->CHANNEL[icup->smod_number].STS.B.TOF = 1U;
      _icu_isr_invoke_overflow_cb(icup);
    }
    if ((sr & 0x0040) != 0) { /* ICF1 */
      if (icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.CNTMODE ==
          SPC5_ETIMER_CNTMODE_RFE_SIHA) {
        icup->etimerp->CHANNEL[icup->smod_number].STS.B.ICF1 = 1U;
        icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.CNTMODE =
            SPC5_ETIMER_CNTMODE_RE;
      }
      else {
        icup->etimerp->CHANNEL[icup->smod_number].STS.B.ICF1 = 1U;
        if (icup->etimerp->CHANNEL[icup->smod_number].CTRL3.B.C1FCNT == 2) {
          period = icup->etimerp->CHANNEL[icup->smod_number].CAPT1.R;
          period = icup->etimerp->CHANNEL[icup->smod_number].CAPT1.R;
        } else {
          period = icup->etimerp->CHANNEL[icup->smod_number].CAPT1.R;
        }
        _icu_isr_invoke_period_cb(icup);
      }
    }
    else if ((sr & 0x0080) != 0) { /* ICF2 */
      if (icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.CNTMODE ==
          SPC5_ETIMER_CNTMODE_RFE_SIHA) {
        icup->etimerp->CHANNEL[icup->smod_number].STS.B.ICF2 = 1U;
        icup->etimerp->CHANNEL[icup->smod_number].CNTR.R = 0;
      }
      else {
        icup->etimerp->CHANNEL[icup->smod_number].STS.B.ICF2 = 1U;
        if (icup->etimerp->CHANNEL[icup->smod_number].CTRL3.B.C2FCNT == 2) {
          width = icup->etimerp->CHANNEL[icup->smod_number].CAPT2.R;
          width = icup->etimerp->CHANNEL[icup->smod_number].CAPT2.R;
        } else {
          width = icup->etimerp->CHANNEL[icup->smod_number].CAPT2.R;
        }
        _icu_isr_invoke_width_cb(icup);
      }
    }
  } else { /* ICU_SKIP_FIRST_CAPTURE = TRUE*/
    if ((sr & 0x0008) != 0) { /* TOF */
      icup->etimerp->CHANNEL[icup->smod_number].STS.B.TOF = 1U;
      _icu_isr_invoke_overflow_cb(icup);
    }
    if ((sr & 0x0040) != 0) { /* ICF1 */
      icup->etimerp->CHANNEL[icup->smod_number].STS.B.ICF1 = 1U;
      if (icup->etimerp->CHANNEL[icup->smod_number].CTRL3.B.C1FCNT == 2) {
        period = icup->etimerp->CHANNEL[icup->smod_number].CAPT1.R;
        period = icup->etimerp->CHANNEL[icup->smod_number].CAPT1.R;
      } else {
        period = icup->etimerp->CHANNEL[icup->smod_number].CAPT1.R;
      }
      _icu_isr_invoke_period_cb(icup);
    }
    else if ((sr & 0x0080) != 0) { /* ICF2 */
      icup->etimerp->CHANNEL[icup->smod_number].STS.B.ICF2 = 1U;
      if (icup->etimerp->CHANNEL[icup->smod_number].CTRL3.B.C2FCNT == 2) {
        width = icup->etimerp->CHANNEL[icup->smod_number].CAPT2.R;
        width = icup->etimerp->CHANNEL[icup->smod_number].CAPT2.R;
      } else {
        width = icup->etimerp->CHANNEL[icup->smod_number].CAPT2.R;
      }
      _icu_isr_invoke_width_cb(icup);
    }
  } /* ICU_SKIP_FIRST_CAPTURE = FALSE */
}

/**
 * @brief   eTimer SubModules initialization.
 * @details This function must be invoked with interrupts disabled.
 *
 * @param[in] sdp       pointer to a @p ICUDriver object
 * @param[in] config    the architecture-dependent ICU driver configuration
 */
static void spc5_icu_smod_init(ICUDriver *icup) {
  uint32_t psc = (icup->clock / icup->config->frequency);

  osalDbgAssert((psc <= 0xFFFF) &&
                ((psc * icup->config->frequency) == icup->clock) &&
                ((psc == 1) || (psc == 2) || (psc == 4) ||
                 (psc == 8) || (psc == 16) || (psc == 32) ||
                 (psc == 64) || (psc == 128)),
                "invalid frequency");

  /* Set primary source and clock prescaler.*/
  switch (psc) {
  case 1:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_1;
    break;
  case 2:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_2;
    break;
  case 4:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_4;
    break;
  case 8:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_8;
    break;
  case 16:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_16;
    break;
  case 32:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_32;
    break;
  case 64:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_64;
    break;
  case 128:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.PRISRC =
        SPC5_ETIMER_IP_BUS_CLOCK_DIVIDE_BY_128;
    break;
  }

  /* Set control registers.*/
  icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.ONCE = 0U;
  icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.LENGTH = 0U;
  icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.DIR = 0U;
  icup->etimerp->CHANNEL[icup->smod_number].CTRL2.B.PIPS = 0U;

  /* Set secondary source.*/
  switch (icup->smod_number) {
  case 0:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.SECSRC =
        SPC5_ETIMER_COUNTER_0_INPUT_PIN;
    break;
  case 1:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.SECSRC =
        SPC5_ETIMER_COUNTER_1_INPUT_PIN;
    break;
  case 2:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.SECSRC =
        SPC5_ETIMER_COUNTER_2_INPUT_PIN;
    break;
  case 3:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.SECSRC =
        SPC5_ETIMER_COUNTER_3_INPUT_PIN;
    break;
  case 4:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.SECSRC =
        SPC5_ETIMER_COUNTER_4_INPUT_PIN;
    break;
  case 5:
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.SECSRC =
        SPC5_ETIMER_COUNTER_5_INPUT_PIN;
    break;
  }

  /* Set secondary source polarity.*/
  if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH) {
    icup->etimerp->CHANNEL[icup->smod_number].CTRL2.B.SIPS = 0U;
  }
  else {
    icup->etimerp->CHANNEL[icup->smod_number].CTRL2.B.SIPS = 1U;
  }

  /* Direct pointers to the capture registers in order to make reading
     data faster from within callbacks.*/
  icup->pccrp = .
  icup->wccrp = &width;

  /* Enable channel.*/
  icup->etimerp->ENBL.B.ENBL |= 1U << (icup->smod_number);
}

/*===========================================================================*/
/* Driver interrupt handlers.                                                */
/*===========================================================================*/

#if SPC5_ICU_USE_SMOD0
#if !defined(SPC5_ETIMER0_TC0IR_HANDLER)
#error "SPC5_ETIMER0_TC0IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer0 Channel 0 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER0_TC0IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD1);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD0 */

#if SPC5_ICU_USE_SMOD1
#if !defined(SPC5_ETIMER0_TC1IR_HANDLER)
#error "SPC5_ETIMER0_TC1IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer0 Channel 1 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER0_TC1IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD2);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD1 */

#if SPC5_ICU_USE_SMOD2
#if !defined(SPC5_ETIMER0_TC2IR_HANDLER)
#error "SPC5_ETIMER0_TC2IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer0 Channel 2 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER0_TC2IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD3);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD2 */

#if SPC5_ICU_USE_SMOD3
#if !defined(SPC5_ETIMER0_TC3IR_HANDLER)
#error "SPC5_ETIMER0_TC3IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer0 Channel 3 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER0_TC3IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD4);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD3 */

#if SPC5_ICU_USE_SMOD4
#if !defined(SPC5_ETIMER0_TC4IR_HANDLER)
#error "SPC5_ETIMER0_TC4IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer0 Channel 4 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER0_TC4IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD5);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD4 */

#if SPC5_ICU_USE_SMOD5
#if !defined(SPC5_ETIMER0_TC5IR_HANDLER)
#error "SPC5_ETIMER0_TC5IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer0 Channel 5 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER0_TC5IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD6);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD5 */

#if SPC5_ICU_USE_SMOD6
#if !defined(SPC5_ETIMER1_TC0IR_HANDLER)
#error "SPC5_ETIMER1_TC0IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer1 Channel 0 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER1_TC0IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD7);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD6 */

#if SPC5_ICU_USE_SMOD7
#if !defined(SPC5_ETIMER1_TC1IR_HANDLER)
#error "SPC5_ETIMER1_TC1IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer1 Channel 1 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER1_TC1IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD8);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD7 */

#if SPC5_ICU_USE_SMOD8
#if !defined(SPC5_ETIMER1_TC2IR_HANDLER)
#error "SPC5_ETIMER1_TC2IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer1 Channel 2 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER1_TC2IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD9);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD8 */

#if SPC5_ICU_USE_SMOD9
#if !defined(SPC5_ETIMER1_TC3IR_HANDLER)
#error "SPC5_ETIMER1_TC3IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer1 Channel 3 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER1_TC3IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD10);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD9 */

#if SPC5_ICU_USE_SMOD10
#if !defined(SPC5_ETIMER1_TC4IR_HANDLER)
#error "SPC5_ETIMER1_TC4IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer1 Channel 4 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER1_TC4IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD11);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD10 */

#if SPC5_ICU_USE_SMOD11
#if !defined(SPC5_ETIMER1_TC5IR_HANDLER)
#error "SPC5_ETIMER1_TC5IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer1 Channel 5 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER1_TC5IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD12);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD11 */

#if SPC5_ICU_USE_SMOD12
#if !defined(SPC5_ETIMER2_TC0IR_HANDLER)
#error "SPC5_ETIMER2_TC0IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer2 Channel 0 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER2_TC0IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD13);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD12 */

#if SPC5_ICU_USE_SMOD13
#if !defined(SPC5_ETIMER2_TC1IR_HANDLER)
#error "SPC5_ETIMER2_TC1IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer2 Channel 1 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER2_TC1IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD14);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD13 */

#if SPC5_ICU_USE_SMOD14
#if !defined(SPC5_ETIMER2_TC2IR_HANDLER)
#error "SPC5_ETIMER2_TC2IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer2 Channel 2 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER2_TC2IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD15);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD14 */

#if SPC5_ICU_USE_SMOD15
#if !defined(SPC5_ETIMER2_TC3IR_HANDLER)
#error "SPC5_ETIMER2_TC3IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer2 Channel 3 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER2_TC3IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD16);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD15 */

#if SPC5_ICU_USE_SMOD16
#if !defined(SPC5_ETIMER2_TC4IR_HANDLER)
#error "SPC5_ETIMER2_TC4IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer2 Channel 4 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER2_TC4IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD17);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD16 */

#if SPC5_ICU_USE_SMOD17
#if !defined(SPC5_ETIMER2_TC5IR_HANDLER)
#error "SPC5_ETIMER2_TC5IR_HANDLER not defined"
#endif
/**
 * @brief   eTimer2 Channel 5 interrupt handler.
 * @note    It is assumed that the various sources are only activated if the
 *          associated callback pointer is not equal to @p NULL in order to not
 *          perform an extra check in a potentially critical interrupt handler.
 *
 * @isr
 */
OSAL_IRQ_HANDLER(SPC5_ETIMER2_TC5IR_HANDLER) {

  OSAL_IRQ_PROLOGUE();

  icu_lld_serve_interrupt(&ICUD18);

  OSAL_IRQ_EPILOGUE();
}
#endif /* SPC5_ICU_USE_SMOD17 */

/*===========================================================================*/
/* Driver exported functions.                                                */
/*===========================================================================*/

/**
 * @brief   Low level ICU driver initialization.
 *
 * @notapi
 */
void icu_lld_init(void) {

  /* Submodules initially all not in use.*/
  icu_active_submodules0 = 0;
  icu_active_submodules1 = 0;
  icu_active_submodules2 = 0;

  /* Reset width and period registers.*/
  width = 0;
  period = 0;

#if SPC5_ICU_USE_SMOD0
  /* Driver initialization.*/
  icuObjectInit(&ICUD1);
  ICUD1.etimerp = &SPC5_ETIMER_0;
  ICUD1.smod_number = 0U;
  ICUD1.clock = SPC5_ETIMER0_CLK;
#endif

#if SPC5_ICU_USE_SMOD1
  /* Driver initialization.*/
  icuObjectInit(&ICUD2);
  ICUD2.etimerp = &SPC5_ETIMER_0;
  ICUD2.smod_number = 1U;
  ICUD2.clock = SPC5_ETIMER0_CLK;
#endif

#if SPC5_ICU_USE_SMOD2
  /* Driver initialization.*/
  icuObjectInit(&ICUD3);
  ICUD3.etimerp = &SPC5_ETIMER_0;
  ICUD3.smod_number = 2U;
  ICUD3.clock = SPC5_ETIMER0_CLK;
#endif

#if SPC5_ICU_USE_SMOD3
  /* Driver initialization.*/
  icuObjectInit(&ICUD4);
  ICUD4.etimerp = &SPC5_ETIMER_0;
  ICUD4.smod_number = 3U;
  ICUD4.clock = SPC5_ETIMER0_CLK;
#endif

#if SPC5_ICU_USE_SMOD4
  /* Driver initialization.*/
  icuObjectInit(&ICUD5);
  ICUD5.etimerp = &SPC5_ETIMER_0;
  ICUD5.smod_number = 4U;
  ICUD5.clock = SPC5_ETIMER0_CLK;
#endif

#if SPC5_ICU_USE_SMOD5
  /* Driver initialization.*/
  icuObjectInit(&ICUD6);
  ICUD6.etimerp = &SPC5_ETIMER_0;
  ICUD6.smod_number = 5U;
  ICUD6.clock = SPC5_ETIMER0_CLK;
#endif

#if SPC5_ICU_USE_SMOD6
  /* Driver initialization.*/
  icuObjectInit(&ICUD7);
  ICUD7.etimerp = &SPC5_ETIMER_1;
  ICUD7.smod_number = 0U;
  ICUD7.clock = SPC5_ETIMER1_CLK;
#endif

#if SPC5_ICU_USE_SMOD7
  /* Driver initialization.*/
  icuObjectInit(&ICUD8);
  ICUD8.etimerp = &SPC5_ETIMER_1;
  ICUD8.smod_number = 1U;
  ICUD8.clock = SPC5_ETIMER1_CLK;
#endif

#if SPC5_ICU_USE_SMOD8
  /* Driver initialization.*/
  icuObjectInit(&ICUD9);
  ICUD9.etimerp = &SPC5_ETIMER_1;
  ICUD9.smod_number = 2U;
  ICUD9.clock = SPC5_ETIMER1_CLK;
#endif

#if SPC5_ICU_USE_SMOD9
  /* Driver initialization.*/
  icuObjectInit(&ICUD10);
  ICUD10.etimerp = &SPC5_ETIMER_1;
  ICUD10.smod_number = 3U;
  ICUD10.clock = SPC5_ETIMER1_CLK;
#endif

#if SPC5_ICU_USE_SMOD10
  /* Driver initialization.*/
  icuObjectInit(&ICUD11);
  ICUD11.etimerp = &SPC5_ETIMER_1;
  ICUD11.smod_number = 4U;
  ICUD11.clock = SPC5_ETIMER1_CLK;
#endif

#if SPC5_ICU_USE_SMOD11
  /* Driver initialization.*/
  icuObjectInit(&ICUD12);
  ICUD12.etimerp = &SPC5_ETIMER_1;
  ICUD12.smod_number = 5U;
  ICUD12.clock = SPC5_ETIMER1_CLK;
#endif

#if SPC5_ICU_USE_SMOD12
  /* Driver initialization.*/
  icuObjectInit(&ICUD13);
  ICUD13.etimerp = &SPC5_ETIMER_2;
  ICUD13.smod_number = 0U;
  ICUD13.clock = SPC5_ETIMER2_CLK;
#endif

#if SPC5_ICU_USE_SMOD13
  /* Driver initialization.*/
  icuObjectInit(&ICUD14);
  ICUD14.etimerp = &SPC5_ETIMER_2;
  ICUD14.smod_number = 1U;
  ICUD14.clock = SPC5_ETIMER2_CLK;
#endif

#if SPC5_ICU_USE_SMOD14
  /* Driver initialization.*/
  icuObjectInit(&ICUD15);
  ICUD15.etimerp = &SPC5_ETIMER_2;
  ICUD15.smod_number = 2U;
  ICUD15.clock = SPC5_ETIMER2_CLK;
#endif

#if SPC5_ICU_USE_SMOD15
  /* Driver initialization.*/
  icuObjectInit(&ICUD16);
  ICUD16.etimerp = &SPC5_ETIMER_2;
  ICUD16.smod_number = 3U;
  ICUD16.clock = SPC5_ETIMER2_CLK;
#endif

#if SPC5_ICU_USE_SMOD16
  /* Driver initialization.*/
  icuObjectInit(&ICUD17);
  ICUD17.etimerp = &SPC5_ETIMER_2;
  ICUD17.smod_number = 4U;
  ICUD17.clock = SPC5_ETIMER2_CLK;
#endif

#if SPC5_ICU_USE_SMOD17
  /* Driver initialization.*/
  icuObjectInit(&ICUD18);
  ICUD18.etimerp = &SPC5_ETIMER_2;
  ICUD18.smod_number = 5U;
  ICUD18.clock = SPC5_ETIMER2_CLK;
#endif

#if SPC5_ICU_USE_ETIMER0

  INTC.PSR[SPC5_ETIMER0_TC0IR_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;
  INTC.PSR[SPC5_ETIMER0_TC1IR_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;
  INTC.PSR[SPC5_ETIMER0_TC2IR_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;
  INTC.PSR[SPC5_ETIMER0_TC3IR_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;
  INTC.PSR[SPC5_ETIMER0_TC4IR_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;
  INTC.PSR[SPC5_ETIMER0_TC5IR_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;
  INTC.PSR[SPC5_ETIMER0_WTIF_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;
  INTC.PSR[SPC5_ETIMER0_RCF_NUMBER].R = SPC5_ICU_ETIMER0_PRIORITY;

#endif

#if SPC5_ICU_USE_ETIMER1

  INTC.PSR[SPC5_ETIMER1_TC0IR_NUMBER].R = SPC5_ICU_ETIMER1_PRIORITY;
  INTC.PSR[SPC5_ETIMER1_TC1IR_NUMBER].R = SPC5_ICU_ETIMER1_PRIORITY;
  INTC.PSR[SPC5_ETIMER1_TC2IR_NUMBER].R = SPC5_ICU_ETIMER1_PRIORITY;
  INTC.PSR[SPC5_ETIMER1_TC3IR_NUMBER].R = SPC5_ICU_ETIMER1_PRIORITY;
  INTC.PSR[SPC5_ETIMER1_TC4IR_NUMBER].R = SPC5_ICU_ETIMER1_PRIORITY;
  INTC.PSR[SPC5_ETIMER1_TC5IR_NUMBER].R = SPC5_ICU_ETIMER1_PRIORITY;
  INTC.PSR[SPC5_ETIMER1_RCF_NUMBER].R = SPC5_ICU_ETIMER1_PRIORITY;

#endif

#if SPC5_ICU_USE_ETIMER2

  INTC.PSR[SPC5_ETIMER2_TC0IR_NUMBER].R = SPC5_ICU_ETIMER2_PRIORITY;
  INTC.PSR[SPC5_ETIMER2_TC1IR_NUMBER].R = SPC5_ICU_ETIMER2_PRIORITY;
  INTC.PSR[SPC5_ETIMER2_TC2IR_NUMBER].R = SPC5_ICU_ETIMER2_PRIORITY;
  INTC.PSR[SPC5_ETIMER2_TC3IR_NUMBER].R = SPC5_ICU_ETIMER2_PRIORITY;
  INTC.PSR[SPC5_ETIMER2_TC4IR_NUMBER].R = SPC5_ICU_ETIMER2_PRIORITY;
  INTC.PSR[SPC5_ETIMER2_TC5IR_NUMBER].R = SPC5_ICU_ETIMER2_PRIORITY;
  INTC.PSR[SPC5_ETIMER2_RCF_NUMBER].R = SPC5_ICU_ETIMER2_PRIORITY;

#endif
}

/**
 * @brief   Configures and activates the ICU peripheral.
 *
 * @param[in] icup      pointer to the @p ICUDriver object
 *
 * @notapi
 */
void icu_lld_start(ICUDriver *icup) {

  osalDbgAssert(icu_active_submodules0 < 6, "too many submodules");
  osalDbgAssert(icu_active_submodules1 < 6, "too many submodules");
  osalDbgAssert(icu_active_submodules2 < 6, "too many submodules");

  if (icup->state == ICU_STOP) {
#if SPC5_ICU_USE_SMOD0
    if (&ICUD1 == icup)
      icu_active_submodules0++;
#endif
#if SPC5_ICU_USE_SMOD1
    if (&ICUD2 == icup)
      icu_active_submodules0++;
#endif
#if SPC5_ICU_USE_SMOD2
    if (&ICUD3 == icup)
      icu_active_submodules0++;
#endif
#if SPC5_ICU_USE_SMOD3
    if (&ICUD4 == icup)
      icu_active_submodules0++;
#endif
#if SPC5_ICU_USE_SMOD4
    if (&ICUD5 == icup)
      icu_active_submodules0++;
#endif
#if SPC5_ICU_USE_SMOD5
    if (&ICUD6 == icup)
      icu_active_submodules0++;
#endif
#if SPC5_ICU_USE_SMOD6
    if (&ICUD7 == icup)
      icu_active_submodules1++;
#endif
#if SPC5_ICU_USE_SMOD7
    if (&ICUD8 == icup)
      icu_active_submodules1++;
#endif
#if SPC5_ICU_USE_SMOD8
    if (&ICUD9 == icup)
      icu_active_submodules1++;
#endif
#if SPC5_ICU_USE_SMOD9
    if (&ICUD10 == icup)
      icu_active_submodules1++;
#endif
#if SPC5_ICU_USE_SMOD10
    if (&ICUD11 == icup)
      icu_active_submodules1++;
#endif
#if SPC5_ICU_USE_SMOD11
    if (&ICUD12 == icup)
      icu_active_submodules1++;
#endif
#if SPC5_ICU_USE_SMOD12
    if (&ICUD13 == icup)
      icu_active_submodules2++;
#endif
#if SPC5_ICU_USE_SMOD13
    if (&ICUD14 == icup)
      icu_active_submodules2++;
#endif
#if SPC5_ICU_USE_SMOD14
    if (&ICUD15 == icup)
      icu_active_submodules2++;
#endif
#if SPC5_ICU_USE_SMOD15
    if (&ICUD16 == icup)
      icu_active_submodules2++;
#endif
#if SPC5_ICU_USE_SMOD16
    if (&ICUD17 == icup)
      icu_active_submodules2++;
#endif
#if SPC5_ICU_USE_SMOD17
    if (&ICUD18 == icup)
      icu_active_submodules2++;
#endif

    /* Set eTimer0 Clock.*/
#if SPC5_ICU_USE_ETIMER0

    /* If this is the first Submodule activated then the eTimer0 is enabled.*/
    if (icu_active_submodules0 == 1) {
      halSPCSetPeripheralClockMode(SPC5_ETIMER0_PCTL,
                                   SPC5_ICU_ETIMER0_START_PCTL);
    }
#endif

    /* Set eTimer1 Clock.*/
#if SPC5_ICU_USE_ETIMER1
    /* If this is the first Submodule activated then the eTimer1 is enabled.*/
    if (icu_active_submodules1 == 1) {
      halSPCSetPeripheralClockMode(SPC5_ETIMER1_PCTL,
                                   SPC5_ICU_ETIMER1_START_PCTL);
    }
#endif

    /* Set eTimer2 Clock.*/
#if SPC5_ICU_USE_ETIMER2
    /* If this is the first Submodule activated then the eTimer2 is enabled.*/
    if (icu_active_submodules2 == 1) {
      halSPCSetPeripheralClockMode(SPC5_ETIMER2_PCTL,
                                   SPC5_ICU_ETIMER2_START_PCTL);
    }
#endif

    /* Timer disabled.*/
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.CNTMODE =
        SPC5_ETIMER_CNTMODE_NO_OPERATION;

    /* Clear pending IRQs (if any).*/
    icup->etimerp->CHANNEL[icup->smod_number].STS.R = 0xFFFF;

    /* All IRQs and DMA requests disabled.*/
    icup->etimerp->CHANNEL[icup->smod_number].INTDMA.R = 0U;

    /* Compare Load 1 and Compare Load 2 disabled.*/
    icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CLC1 = 0U;
    icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CLC2 = 0U;

    /* Capture 1 and Capture 2 disabled.*/
    icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CPT1MODE =
        SPC5_ETIMER_CPT1MODE_DISABLED;
    icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CPT2MODE =
        SPC5_ETIMER_CPT2MODE_DISABLED;

    /* Counter reset to zero.*/
    icup->etimerp->CHANNEL[icup->smod_number].CNTR.R = 0U;
  }

  /* Configuration.*/
  spc5_icu_smod_init(icup);
}

/**
 * @brief   Deactivates the ICU peripheral.
 *
 * @param[in] icup      pointer to the @p ICUDriver object
 *
 * @notapi
 */
void icu_lld_stop(ICUDriver *icup) {

  osalDbgAssert(icu_active_submodules0 < 6, "too many submodules");
  osalDbgAssert(icu_active_submodules1 < 6, "too many submodules");
  osalDbgAssert(icu_active_submodules2 < 6, "too many submodules");

  if (icup->state == ICU_READY) {

#if SPC5_ICU_USE_SMOD0
    if (&ICUD1 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFE;
      icu_active_submodules0--;
    }
#endif
#if SPC5_ICU_USE_SMOD1
    if (&ICUD2 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFD;
      icu_active_submodules0--;
    }
#endif
#if SPC5_ICU_USE_SMOD2
    if (&ICUD3 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFB;
      icu_active_submodules0--;
    }
#endif
#if SPC5_ICU_USE_SMOD3
    if (&ICUD4 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xF7;
      icu_active_submodules0--;
    }
#endif
#if SPC5_ICU_USE_SMOD4
    if (&ICUD5 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xEF;
      icu_active_submodules0--;
    }
#endif
#if SPC5_ICU_USE_SMOD5
    if (&ICUD6 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xDF;
      icu_active_submodules0--;
    }
#endif
#if SPC5_ICU_USE_SMOD6
    if (&ICUD7 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFE;
      icu_active_submodules1--;
    }
#endif
#if SPC5_ICU_USE_SMOD7
    if (&ICUD8 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFD;
      icu_active_submodules1--;
    }
#endif
#if SPC5_ICU_USE_SMOD8
    if (&ICUD9 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFB;
      icu_active_submodules1--;
    }
#endif
#if SPC5_ICU_USE_SMOD9
    if (&ICUD10 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xF7;
      icu_active_submodules1--;
    }
#endif
#if SPC5_ICU_USE_SMOD10
    if (&ICUD11 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xEF;
      icu_active_submodules1--;
    }
#endif
#if SPC5_ICU_USE_SMOD11
    if (&ICUD12 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xDF;
      icu_active_submodules1--;
    }
#endif
#if SPC5_ICU_USE_SMOD12
    if (&ICUD13 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFE;
      icu_active_submodules2--;
    }
#endif
#if SPC5_ICU_USE_SMOD13
    if (&ICUD14 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFD;
      icu_active_submodules2--;
    }
#endif
#if SPC5_ICU_USE_SMOD14
    if (&ICUD15 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xFB;
      icu_active_submodules2--;
    }
#endif
#if SPC5_ICU_USE_SMOD15
    if (&ICUD16 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xF7;
      icu_active_submodules2--;
    }
#endif
#if SPC5_ICU_USE_SMOD16
    if (&ICUD17 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xEF;
      icu_active_submodules2--;
    }
#endif
#if SPC5_ICU_USE_SMOD17
    if (&ICUD18 == icup) {
      /* Disable channel.*/
      icup->etimerp->ENBL.B.ENBL &= 0xDF;
      icu_active_submodules2--;
    }
#endif
    /* eTimer0 clock deactivation.*/
#if SPC5_ICU_USE_ETIMER0
    /* If it is the last active submodules then the eTimer0 is disabled.*/
    if (icu_active_submodules0 == 0) {
      if (icup->etimerp->ENBL.B.ENBL == 0) {
        halSPCSetPeripheralClockMode(SPC5_ETIMER0_PCTL,
                                     SPC5_ICU_ETIMER0_STOP_PCTL);
      }
    }
#endif

    /* eTimer1 clock deactivation.*/
#if SPC5_ICU_USE_ETIMER1
    /* If it is the last active submodules then the eTimer1 is disabled.*/
    if (icu_active_submodules1 == 0) {
      if (icup->etimerp->ENBL.B.ENBL == 0) {
        halSPCSetPeripheralClockMode(SPC5_ETIMER1_PCTL,
                                     SPC5_ICU_ETIMER1_STOP_PCTL);
      }
    }
#endif

    /* eTimer2 clock deactivation.*/
#if SPC5_ICU_USE_ETIMER2
    /* If it is the last active submodules then the eTimer2 is disabled.*/
    if (icu_active_submodules2 == 0) {
      if (icup->etimerp->ENBL.B.ENBL == 0) {
        halSPCSetPeripheralClockMode(SPC5_ETIMER2_PCTL,
                                     SPC5_ICU_ETIMER2_STOP_PCTL);
      }
    }
#endif
  }
}

/**
 * @brief   Enables the input capture.
 *
 * @param[in] icup      pointer to the @p ICUDriver object
 *
 * @notapi
 */
void icu_lld_enable(ICUDriver *icup) {

  /* Clear pending IRQs (if any).*/
  icup->etimerp->CHANNEL[icup->smod_number].STS.R = 0xFFFF;

  /* Set Capture 1 and Capture 2 Mode.*/
  icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CPT1MODE =
      SPC5_ETIMER_CPT1MODE_RISING_EDGE;
  icup->etimerp->CHANNEL[icup->smod_number].CTRL3.B.ROC =
      SPC5_ETIMER_ROC_REL_ON_CAP1;
  icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CPT2MODE =
      SPC5_ETIMER_CPT2MODE_FALLING_EDGE;

  /* Active interrupts.*/
  if (icup->config->period_cb != NULL || icup->config->width_cb != NULL) {
    icup->etimerp->CHANNEL[icup->smod_number].INTDMA.B.ICF1IE = 1U;
    icup->etimerp->CHANNEL[icup->smod_number].INTDMA.B.ICF2IE = 1U;
  }
  if (icup->config->overflow_cb != NULL) {
    icup->etimerp->CHANNEL[icup->smod_number].INTDMA.B.TOFIE = 1U;
  }

  /* Set Capture FIFO Water Mark.*/
  icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CFWM = 0U;

  /* Enable Counter.*/
  if (ICU_SKIP_FIRST_CAPTURE) {
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.CNTMODE =
        SPC5_ETIMER_CNTMODE_RFE_SIHA;
  }
  else {
    icup->etimerp->CHANNEL[icup->smod_number].CTRL.B.CNTMODE =
        SPC5_ETIMER_CNTMODE_RE;
  }

  /* Enable Capture process.*/
  icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.ARM = 1U;
}

/**
 * @brief   Disables the input capture.
 *
 * @param[in] icup      pointer to the @p ICUDriver object
 *
 * @notapi
 */
void icu_lld_disable(ICUDriver *icup) {

  /* Disable Capture process.*/
  icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.ARM = 0U;

  /* Clear pending IRQs (if any).*/
  icup->etimerp->CHANNEL[icup->smod_number].STS.R = 0xFFFF;

  /* Set Capture 1 and Capture 2 Mode to Disabled.*/
  icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CPT1MODE =
      SPC5_ETIMER_CPT1MODE_DISABLED;
  icup->etimerp->CHANNEL[icup->smod_number].CCCTRL.B.CPT2MODE =
      SPC5_ETIMER_CPT2MODE_DISABLED;

  /* Disable interrupts.*/
  if (icup->config->period_cb != NULL || icup->config->width_cb != NULL) {
    icup->etimerp->CHANNEL[icup->smod_number].INTDMA.B.ICF1IE = 0U;
    icup->etimerp->CHANNEL[icup->smod_number].INTDMA.B.ICF2IE = 0U;
  }
  if (icup->config->overflow_cb != NULL)
    icup->etimerp->CHANNEL[icup->smod_number].INTDMA.B.TOFIE = 0U;
}

#endif /* HAL_USE_ICU */

/** @} */


text:
SYNONYM

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
Bull. Soc. mycol. Fr. 30(3): 342 (1914)

#### Original name
Coriolus subcalvus Pat., 1914

### Remarks
null

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace Deimos;

class PreRelease
{

    const GOLD_MASTER       = 4;
    const RELEASE_CANDIDATE = 3; // rc

    const ALPHA = 1;
    const BETA  = 2;
    const DEV   = 0;

    const STABLE = 9;

    /**
     * @var string
     */
    private $value;

    /**
     * PreRelease constructor.
     *
     * @param $string
     */
    public function __construct($string)
    {
        $this->value = $string;
    }

    /**
     * @return string
     */
    public function __toString()
    {

        $string = mb_strtolower($this->value);

        switch ($string)
        {

            case 'dev':
                return (string)self::DEV;

            case 'rc':
            case 'release-candidate':
                return (string)self::RELEASE_CANDIDATE;

            case 'gm':
            case 'gold-master':
                return (string)self::GOLD_MASTER;

            case 'alpha':
                return (string)self::ALPHA;

            case 'beta':
                return (string)self::BETA;

            case 'stable':
            default:
                return (string)self::STABLE;

        }

    }

}


text:
//
//  metering.h
//  FxDSP
//
//  Created by Hamilton Kibbe on 5/22/15.
//  Copyright (c) 2015 Hamilton Kibbe. All rights reserved.
//

#ifndef __FxDSP__metering__
#define __FxDSP__metering__

#ifdef __cplusplus
extern "C" {
#endif

typedef enum
{
    FULL_SCALE,
    K_12,
    K_14,
    K_20
} MeterScale;

float
phase_correlation(float* left, float* right, unsigned n_samples);

double
phase_correlationD(double* left, double* right, unsigned n_samples);

float
balance(float* left, float* right, unsigned n_samples);

double
balanceD(double* left, double* right, unsigned n_samples);

float
vu_peak(float* signal, unsigned n_samples, MeterScale scale);

double
vu_peakD(double* signal, unsigned n_samples, MeterScale scale);

#ifdef __cplusplus
}
#endif

#endif /* defined(__FxDSP__metering__) */


text:
require 'easy_type'
require 'utils/wls_access'
require 'utils/settings'
require 'utils/title_parser'
require 'facter'

module Puppet
  #
  newtype(:wls_jms_connection_factory) do
    include EasyType
    include Utils::WlsAccess
    extend Utils::TitleParser

    desc 'This resource allows you to manage a CF in a JMS Module of an WebLogic domain.'

    ensurable

    set_command(:wlst)

    to_get_raw_resources do
      Puppet.info "index #{name}"
      environment = { 'action' => 'index', 'type' => 'wls_jms_connection_factory' }
      wlst template('puppet:///modules/orawls/providers/wls_jms_connection_factory/index.py.erb', binding), environment
    end

    on_create  do | command_builder |
      Puppet.info "create #{name} "
      template('puppet:///modules/orawls/providers/wls_jms_connection_factory/create.py.erb', binding)
    end

    on_modify  do | command_builder |
      Puppet.info "modify #{name} "
      template('puppet:///modules/orawls/providers/wls_jms_connection_factory/modify.py.erb', binding)
    end

    on_destroy  do | command_builder |
      Puppet.info "destroy #{name} "
      template('puppet:///modules/orawls/providers/wls_jms_connection_factory/destroy.py.erb', binding)
    end

    parameter :domain
    parameter :name
    parameter :jmsmodule
    parameter :connection_factory_name
    parameter :timeout
    property :jndiname
    property :subdeployment
    property :defaulttargeting
    property :transactiontimeout
    property :xaenabled
    property :clientidpolicy
    property :subscriptionsharingpolicy
    property :messagesmaximum
    property :reconnectpolicy
    property :loadbalancingenabled
    property :serveraffinityenabled
    property :attachjmsxuserid

    add_title_attributes(:jmsmodule, :connection_factory_name) do
      /^((.*\/)?(.*):(.*)?)$/
    end

  end
end


text:
<?php

namespace Detail\Persistence\Options;

use Detail\Core\Options\AbstractOptions;

class DoctrineOptions extends AbstractOptions
{
    /**
     * @var boolean
     */
    protected $regUuidType = false;

    /**
     * @var boolean
     */
    protected $regDatetimeNoTzType = false;

    /**
     * @var boolean
     */
    protected $regDatetimeImmutableNoTzType = false;

    /**
     * @var Doctrine\CacheOptions[]
     */
    protected $caches = array();

    /**
     * @return boolean
     */
    public function registerUuidType()
    {
        return $this->regUuidType;
    }

    /**
     * @param boolean $regUuidType
     */
    public function setRegisterUuidType($regUuidType)
    {
        $this->regUuidType = (boolean) $regUuidType;
    }

    /**
     * @return boolean
     */
    public function registerDatetimeNoTzType()
    {
        return $this->regDatetimeNoTzType;
    }

    /**
     * @param boolean $regDatetimeNoTzType
     */
    public function setRegisterDatetimeNoTzType($regDatetimeNoTzType)
    {
        $this->regDatetimeNoTzType = (boolean) $regDatetimeNoTzType;
    }

    /**
     * @return boolean
     */
    public function registerDatetimeImmutableNoTzType()
    {
        return $this->regDatetimeImmutableNoTzType;
    }

    /**
     * @param boolean $regDatetimeImmutableNoTzType
     */
    public function setRegisterDatetimeImmutableNoTzType($regDatetimeImmutableNoTzType)
    {
        $this->regDatetimeImmutableNoTzType = (boolean) $regDatetimeImmutableNoTzType;
    }

    /**
     * @return Doctrine\CacheOptions[]
     */
    public function getCaches()
    {
        return $this->caches;
    }

    /**
     * @param Doctrine\CacheOptions[] $caches
     */
    public function setCaches(array $caches)
    {
        $this->caches = $this->createOptions($caches, Doctrine\CacheOptions::CLASS);
    }

    /**
     * @param array $values
     * @param string $class
     * @return array
     */
    protected function createOptions(array $values, $class)
    {
        $options = array();

        foreach ($values as $name => $config) {
            $options[$name] = new $class($config);
        }

        return $options;
    }
}


text:
Knihovna JUnit slouží k implementaci a exekuci jednotkových a integračních testů. Kromě podpory pro implementaci a exekuci testů obsahuje i rozličné funkce pro kontrolu a porovnávání hodnot. Celá knihovna je navržena tak, aby byl kód přehledný a obsahoval minimální množství infrastrukturního kódu.

### Filozofie

Jednotkový test je speciální druh testu, ve kterém se testuje jedna jediná komponenta a všechny její vnější závislosti jsou simulovány. Takový test má za úkol zadanou komponentu důkladně otestovat v normálních i krajních podmínek. Pokud jsou takto otestovány všechny komponenty, je celkem vysoká pravděpodobnost, že bude celý program fungovat dobře.

Velkou výhodou při používání jednotkového testování je i fakt, že psaní testovatelného kódu zvyšuje kvalitu všech komponent, a tedy v konečném důsledku i celého programu. Komponenta, která se nedá otestovat, je pravděpodobně špatně navržená - je nedostatečně oddělená od okolního světa, což odporuje několika dobrým praktikám objektového návrhu.

V Javě je nejmenší jednotkou třída, respektive metoda třídy. Závislostmi třídy jsou myšleny jiné třídy, které jsou k jejímu fungování nutné.

### Implementace testů

V JUnit je každý test reprezentován třídou, jejíž název je odvozen z názvu testované třídy a příponou *Test* (například **CalculatorTest**, **UserManagementServiceTest**). JUnit od verze 4 může být zcela řízen anotacemi, takže testovací třída nemusí od žádné jiné třídy dědit a ani není nutné ji přidávat do nějakých seznamů, jako tomu bylo dříve. Testovací třída bsahuje skutečně jen samotný test, případně přípravu testovacích dat. simulovaných závislostí a jejich následný úklid.

Nejjednodušší test vypadá na první pohled jako obyčejná třída. Jediným rozdílem je přítomnost anotací z knihovny JUnit. Mezi základní anotace patří *javadoc:org.junit.Test* označující veřejné metody, které mají být v rámci testu spuštěny.

```java
public class SomeTest {
  @Test
  public void testSomething() {
    // ...
  }
}
```

#### Akce před testem a po testu

Pokud je třeba před testem či po testu vykonat nějaké akce, lze využít těchto anotací:

- *javadoc:org.junit.Before* - metoda se provede před každým spuštěním testovací metody v této třídě
- *javadoc:org.junit.After* - metoda se provede po každém spuštění testovací metody v této třídě
- *javadoc:org.junit.BeforeClass* - metoda se provede před spuštěním první testovací metody v této třídě (metoda musí být statická)
- *javadoc:org.junit.AfterClass* - metoda se provede po dokončení všech metod z této testovací třídy (metoda musí být statická)

Do metod s anotací *javadoc:org.junit.Before* se často vkládá společný kód pro inicializaci komponenty a jejich závislostí. Inicializace komponenty před každým testem způsobí, že je pro každý test připravena vždy ve stejném výchozím stavu a nemá vliv, v jakém pořadí se testovací metody spouštějí. U testů není prioritou výkon, ale jejich korektnost a úplnost.

```java
public class SomeTest {
  private Calculator calculator;

  @Before
  public void turnOn() {
    calculator = new Calculator();
    calculator.enableAdding();
    calculator.enableSubtracting();
  }

  @After
  public void turnOff() {
    calculator.turnOff();
  }

  @Test
  public void test() {
    // ...
  }
}
```

Pro vlastní implementaci podobných funkcí lze využít [Rules](https://github.com/junit-team/junit4/wiki/rules).

#### Ověřování výsledků

Pro logické hodnoty:

```java
// hodnota musí být TRUE
Assert.assertTrue(myReturnValue);
// hodnota musí být FALSE
Assert.assertFalse(myReturnValue);
```

Pro obecné hodnoty:

```java
// objekt *A* musí být NULL
Assert.assertNull(a);
// objekt *A* nesmí být NULL
Assert.assertNotNull(a);
// objekt *A* se musí rovnat objektu *E* (equals)
Assert.assertEquals(e, a);
// objekt *A* se nesmí rovnat objektu *E* (equals)
Assert.assertNotEquals(e, a);
// instance *A* musí být shodná s instancí *E* (==)
Assert.assertSame(e, a);
// instance *A* nesmí být shodná s instancí *E* (==)
Assert.assertNotSame(e, a);
```

#### Ověřování pomocí Matchers

Knihovna [Hamcrest Matchers](http://hamcrest.org/) se stala de-facto standardem pro tvorbu validačních tříd, tzv. **matcherů**. Matcher je v podstatě jen predikát, který obdrží objekt a odpoví, zda je podle něho daný objekt validní.

Můžete využít již připravené matchery, implementovat vlastní (jako implementaci rozhraní *javadoc:org.hamcrest.Matcher* nebo *javadoc:org.hamcrest.TypeSafeMatcher*), nebo je vzájemně kombinovat pomocí již existujících logických operátorů (*allOf* = AND, *anyOf* = OR).

```java
Assert.assertThat(
  actualValue,
  CoreMatchers.equalTo("John")
);

Assert.assertThat(
  actualValue,
  CoreMatchers.allOf(
    new StringStartsWith("prefix"),
    new StringEndsWith("suffix")
  )
);
```

#### Ověřování pomocí AssertJ

Pro verifikaci výsledků lze použít i knihovnu [AssertJ](http://joel-costigliola.github.io/assertj/).
Ta je výborná zejména pro verifikaci kolekcí - například seznamů, množin a map.

```java
// základní ověřování
assertThat(frodo.getName())
    .isEqualTo("Frodo");

assertThat(frodo)
    .isNotEqualTo(sauron);
```

```java
// ověřování výjimek
assertThatThrownBy(() -> { throw new Exception("boom!"); })
        .hasMessage("boom!");
```

```java
// ověřování prvků v seznamu
assertThat(fellowshipOfTheRing)
    .extracting(TolkienCharacter::getName)
    .contains("Sam", "Legolas")
```

```java
// ověřování prvků v mapě
assertThat(ringBearers)
    .containsValues(frodo, galadriel);

assertThat(ringBearersByName).containsOnly(
        entry(sam.getName(), sam),
        entry(frodo.getName(), frodo),
        entry(gandalf.getName(), gandalf),
        entry(galadriel.getName(), galadriel)
);
```

### Spuštění testů

#### Spuštění v rámci buildu pomocí Maven

Maven podporu pro testy má již vestavěnou, takže není nutné do *pom.xml* příliš zasahovat, pokud nevyžadujete nějaké speciální nastavení.

Nejdříve je nutné přidat závislost na JUnit se scopem *test*. To zařídí, že se knihovna JUnit nebude vyskytovat ve výsledném buildu, použije se jen pro tvorbu a  spuštění testů.

```xml
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.XX</version>
  <scope>test</scope>
</dependency>
```

Testy se standardně umisťují do této adresářové struktury:

- **/src/test/java** = složka pro testovací třídy
- **/src/test/resources** = složka pro testovací resources

Třídy a resources z tého struktury rozšíří produkční classpath a navíc mají navíc k dispozici všechny závislosti se scopem *test*.

Testy se budou spouštět automaticky s každým buildem (pokud to nechceme, stačí přidat parametr *-DskipTests=true*).

Samostatně lze spustit testy například takto:

```bash
mvn clean test
```

#### Spuštění z kódu

Spustit testy lze pomocí metody *runClasses* třídy *javadoc:org.junit.runner.JUnitCore*. Spustit lze libovolné množství testů.

```java
org.junit.runner.JUnitCore.runClasses(MyTest1.class, MyTest2.class);
```

#### Spuštění z příkazové řádky

Předpokladem pro spuštění z příkazové řádky je přítomnost knihovny JUnit i požadovaných testů na classpath. Spustit lze libovolné množství testů.

```bash
java org.junit.runner.JUnitCore MyTest1.class MyTest2.class
```

### Tipy a triky

#### Testování se souborovým systémem

K vytvoření testovacích souborů lze využít třídu *javadoc:org.junit.rules.TemporaryFolder*. Tato proměnná musí být deklarovaná veřejně a anotovaná jako *javadoc:org.junit.Rule*. Systém JUnit vytvoří dočasný adresář před spuštěním testů a po dokončení každé testovací metody (nezávisle na jejím výsledku) smaže všechny soubory, které testovací metoda vytvořila.

```java
public class FileSystemUnitTest {
  @Rule
  public TemporaryFolder temporaryFolder = new TemporaryFolder();

  @Test
  public void testSomeFileFunction() throws IOException {
    File newFile = temporaryFolder.newFile("output.txt");
    // ...
  }
}
```

#### Testování s databází

Jako databáze vhodná pro jednotkové testy se ukázala [H2 Database](http://www.h2database.com/html/main.html). Ta nabízí embedded i in-memory režim a umožňuje snadnou inicializaci databáze ze skriptů pomocí třídy *javadoc:org.h2.tools.RunScript*:

```java
RunScript.execute(connection, new FileReader("create_db.sql"));
```

Při použití frameworku Spring se inicialize ještě trochu zjednoduší:

```xml
<jdbc:embedded-database id="dataSource" type="H2">
  <jdbc:script location="classpath:db/sql/create-db.sql" />
  <jdbc:script location="classpath:db/sql/insert-data.sql" />
</jdbc:embedded-database>
```

#### Testování se Spring kontextem

K testování se Spring kontextem je nutné do testovacích závislostí přidat *org.springframework.test*. Pomocí anotace *javadoc:org.junit.runner.RunWith* přítomné v JUnit se pak definuje, že se daný unit test bude spouštět pomocí speciální třídy, která pak podle dalších anotací provede potřebná nastavení třídy unit testu.

Tímto způsobem lze testovat různé beany přítomné v kontextu a validovat jejich vlastnosti. Obecně se však podobný test doporučuje brát spíše jako integrační testy vyšší úrovně, které testují pouze to, že je kontext validní (lze jej vytvořit) a jednotlivé závislosti si "sednou" dobře dohromady. Funkce jednotlivých bean by měly být otestovány zvlášť bez nutnosti vůbec nějaký kontext vytvářet.

```java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UnitTestWithSpringContext {
    @Autowired
    private MyBean myBean;

    @Test
    public void testMyBeanIsValid() {
        assertTrue(myBean.isValid());
    }
}
```

#### Tvorba mocků

K tvorbě mocků lze využít například framework [Mockito](wiki/mockito).

#### Přeskočení testů

Přeskočit testovací metodu nebo celý test lze pomocí anotace *javadoc:org.junit.Ignore*.

```java
@Ignore
@Test
public void testSomething() {
  // ...
}
```

```java
@Ignore
public class SomeTest1() {
  // ...
}
```

#### Očekávané výjimky

Chyby v programech se stávají a je dobré mít otestované jejich chování i v těchto krajních případech. A to nejen kvůli dosažení vysokého procenta pokrytí, ale hlavně kvůli zajištění rozumného zotavení programu po chybě.

```java
@Test(expected = IOException.class)
public void testWithTimeout() {
  throw new IOException("This test will pass.");
}
```

#### Časový limit

Pokud zadaný test nedoběhne do stanovené doby, označí se jako nesplněný. Osobně tuto konstrukci příliš nedoporučuji

```java
@Test(timeout = 1000)
public void testWithTimeout() {
  // ...
}
```

### Reference

- http://junit.org/
- https://github.com/junit-team/junit4/wiki/rules
- http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html


text:
module Codestart
  module Output
    def file_tip(action, path)
      puts "      #{action.shell_green}  #{path}"
    end
  end

  module FileIO
    def write_lines(path, lines)
      File.open path, 'w' do |f|
        lines.each do |line|
          f.write line
        end
      end
    end

    def create_from_lines(path, lines)
      write_lines path, lines
      file_tip 'create', path
    end

    def insert_lines(lines, position, new_lines)
      part0 = lines[0...position]
      part1 = lines[position..-1]
      return part0 + new_lines + part1
    end

    def find_position(lines, query)
      position = 0
      lines.each do |line|
        break if line.index(query) == 0
        position += 1
      end
      return position
    end

    def create_from_erb(template, target_path)
      write_erb template, target_path
      file_tip 'create', target_path
    end

    def create_dir_and_file_from_erb(target_dir, template)
      FileUtils.mkdir_p target_dir
      path = File.join target_dir, template.sub(/\.erb$/, '')
      create_from_erb template, path
    end

    private

      def write_erb(template, target_path)
        source = File.join @templates_dir, template
        File.open target_path, 'w' do |f|
          f.write ERB.new(File.read(source)).result binding
        end
      end
  end

  class RailsEngineGenerator
    include Output
    include FileIO

    def initialize(args)
      @args = args

      @gem_dir = File.join __dir__, '..'
      @templates_dir = File.join @gem_dir, 'templates'

      puts "rails engine 项目代码构建工具".shell_yellow
      @project_name = args[0]
      @dash_project_name = @project_name
    end

    def project_name_valid?
      if @project_name.blank?
        puts '请输入: codestart <engine_name>'.shell_red
        return false
      end
      if @project_name.include? '-'
        @project_name = @project_name.gsub('-', '_')
        puts "由于名称包含 - , 已在必要的地方替换为 #{@project_name}".shell_red
      end
      return true
    end

    def is_dir_exist?
      path = @dash_project_name

      # 删除目标目录
      if @args[1] == '-rm'
        system "rm -rf #{path}"
      end

      if File.exist? path
        puts "文件目录 #{path} 已存在".shell_red
        return true
      end
      return false
    end

    def init_gem
      puts '  初始化 gem'
      system "bundle gem #{@project_name}"
    end

    def add_dependency
      puts "  给 gemspec 添加依赖"
      path = "#{@project_name}/#{@project_name}.gemspec"

      lines = File.read(path).lines
      # 去掉 TODO
      pos0 = find_position lines, '  spec.summary'
      pos1 = find_position lines, '  spec.description'
      lines[pos0] = '  spec.summary       = ""' + "\n"
      lines[pos1] = '  spec.description   = ""' + "\n"

      # 添加依赖
      end_line_pos = find_position lines, 'end'
      output = insert_lines lines, end_line_pos, [
          "\n",
          "  # 以下为 rails engine 依赖\n",
          "  spec.add_development_dependency 'actionpack', '~> 4.2.0'\n",
          "  spec.add_development_dependency 'activesupport', '~> 4.2.0'\n\n",
          "  spec.add_development_dependency 'jquery-rails', '>= 3.1.0'\n",
          "  spec.add_development_dependency 'uglifier'\n"
        ]

      write_lines path, output
      file_tip 'modify', path
    end

    def change_gemfile_source
      puts "  修改 Gemfile source 为 ruby.taobao.org"
      path = File.join @project_name, 'Gemfile'

      lines = File.read(path).lines
      lines[0] = "source 'http://ruby.taobao.org/'\n"

      write_lines path, lines
      file_tip 'modify', path
    end

    def change_lib_module_file
      puts "  创建 #{@module_name} module"
      path = File.join @project_name, 'lib', "#{@project_name}.rb"

      lines = [
        "module #{@module_name}\n",
        "  class << self\n",
        "    def #{@project_name}_config\n",
        "      self.instance_variable_get(:@#{@project_name}_config) || {}\n",
        "    end\n",
        "\n",
        "    def set_mount_prefix(mount_prefix)\n",
        "      config = #{@module_name}.#{@project_name}_config\n",
        "      config[:mount_prefix] = mount_prefix\n",
        "      #{@module_name}.instance_variable_set(:@#{@project_name}_config, config)\n",
        "    end\n",
        "\n",
        "    def get_mount_prefix\n",
        "      #{@project_name}_config[:mount_prefix]\n",
        "    end\n",
        "  end\n",
        "end\n",
        "\n",
        "# 引用 rails engine\n",
        "require '#{@project_name}/engine'\n",
        "require '#{@project_name}/rails_routes'\n"
      ]

      write_lines path, lines
      file_tip 'modify', path
    end

    def add_rails_engine_file
      puts "  创建 rails engine 文件"
      path = File.join @project_name, 'lib', @project_name, 'engine.rb'

      create_from_erb 'engine.rb.erb', path
    end

    def add_rails_routes_rb_file
      puts "  创建 rails_routes.rb 文件"
      path = File.join @project_name, 'lib', @project_name, 'rails_routes.rb'

      create_from_erb 'rails_routes.rb.erb', path
    end

    def run_bundle
      FileUtils.cd @project_name do
        system "bundle"
      end
    end

    def add_controllers_files
      puts "  创建 controllers"

      controllers_dir = File.join @project_name, 'app/controllers', @project_name
      create_dir_and_file_from_erb controllers_dir,
        'application_controller.rb.erb'
      create_dir_and_file_from_erb controllers_dir,
        'home_controller.rb.erb'
    end

    def add_views_files
      puts "  创建 views"

      layout_dir = File.join @project_name, 'app/views/layouts', @project_name
      layout_path = File.join layout_dir, 'application.html.haml'

      view_dir = File.join @project_name, 'app/views', @project_name, 'home'
      view_path = File.join view_dir, 'index.html.haml'

      FileUtils.mkdir_p layout_dir
      FileUtils.mkdir_p view_dir

      create_from_erb 'application.html.haml.erb', layout_path
      create_from_erb 'index.html.haml.erb', view_path
    end

    def add_assets_files
      puts "  创建 assets"

      js_dir = File.join @project_name, 'app/assets/javascripts', @project_name
      js_path = File.join js_dir, 'application.js'
      css_dir = File.join @project_name, 'app/assets/stylesheets', @project_name
      css_path = File.join css_dir, 'application.css'
      ui_scss_path = File.join css_dir, 'ui.scss'

      FileUtils.mkdir_p js_dir
      FileUtils.mkdir_p css_dir

      create_from_erb 'application.js.erb', js_path
      create_from_erb 'application.css.erb', css_path
      create_from_erb 'ui.scss.erb', ui_scss_path
    end

    def add_routes_file
      puts "  创建 routes"

      config_dir = File.join @project_name, 'config'
      routes_path = File.join config_dir, 'routes.rb'
      FileUtils.mkdir_p config_dir
      FileUtils.touch routes_path

      create_from_erb 'routes.rb.erb', routes_path
    end

    def add_keep_dirs
      models_dir = File.join @project_name, 'app/models'
      FileUtils.mkdir_p models_dir
      FileUtils.touch File.join models_dir, '.keep'
    end

    def copy_sample
      source_sample_dir = File.join @gem_dir, 'sample/'
      target_sample_dir = File.join @project_name, 'sample/'

      FileUtils.cp_r source_sample_dir, target_sample_dir
      file_tip 'create', target_sample_dir

      # 修改 Gemfile
      gemfile_path = File.join target_sample_dir, 'Gemfile'
      File.open gemfile_path, 'a' do |f|
        f.write "\n"
        f.write "gem '#{@dash_project_name}', path: '../'"
      end

      # 修改 routes.rb
      routes_path = File.join target_sample_dir, 'config/routes.rb'
      lines = File.read(routes_path).lines
      lines[1] = "  #{@module_name}::Routing.mount '/', :as => '#{@project_name}'\n"
      write_lines routes_path, lines

      # 修改 mongoid.yml
      mongoid_yml_path = File.join target_sample_dir, 'config/mongoid.yml'
      result = ERB.new(File.read(mongoid_yml_path)).result binding
      File.open mongoid_yml_path, 'w' do |f|
        f.write result
      end
    end

    def modify_for_dash_name
      return if !@dash_project_name.include? '-'

      puts "进行必要的补充调整"

      # 修改工程名
      system "mv #{@project_name} #{@dash_project_name}"
      file_tip 'chname', "#{@project_name} -> #{@dash_project_name}"

      # 修改 gemspec 名称和内容
      p1 = "#{@dash_project_name}/#{@project_name}.gemspec"
      p2 = "#{@dash_project_name}/#{@dash_project_name}.gemspec"
      system "mv #{p1} #{p2}"
      file_tip 'chname', "#{p1} -> #{p2}"
      lines = File.read(p2).lines
      lines[6] = "  spec.name          = '#{@dash_project_name}'\n"
      write_lines p2, lines
      file_tip 'modify', p2

      # 修改 lib/ 下的 rb
      p1 = "#{@dash_project_name}/lib/#{@project_name}.rb"
      p2 = "#{@dash_project_name}/lib/#{@dash_project_name}.rb"
      system "mv #{p1} #{p2}"
      file_tip 'chname', "#{p1} -> #{p2}"

      # 修改 Gemfile
      path = "#{@dash_project_name}/Gemfile"
      lines = File.read(path).lines
      lines[2] = "# Specify your gem's dependencies in #{@dash_project_name}.gemspec\n"
      write_lines path, lines
      file_tip 'modify', path
    end

    def generate
      return if not project_name_valid?
      return if is_dir_exist?

      @module_name = @project_name.camelize

      # 创建 gem
      init_gem

      # 给 gemspec 添加依赖
      add_dependency

      # 修改 gem 的 Gemfile 更改 source
      change_gemfile_source

      # 创建 rails engine 文件
      add_rails_engine_file

      # 创建 rails_routes.rb 文件
      add_rails_routes_rb_file

      # 修改 lib/xxx.rb 文件,增加 module
      change_lib_module_file

      # bundle
      # run_bundle

      # 创建 controllers 文件
      add_controllers_files

      # 创建 views 文件
      add_views_files

      # 创建 assets 文件
      add_assets_files

      # 创建 routes 文件
      add_routes_file

      # 添加一些 .keep 文件
      add_keep_dirs

      # 复制 sample 文件夹
      copy_sample

      # 当文件名里有 -, 进行必要的调整
      modify_for_dash_name

      FileUtils.cd @dash_project_name do
        system 'rm -rf .git'
        system 'git init'
      end
    end

  end
end


text:
#import "NSCustomView.h"
#import <Foundation/NSString.h>
#import <Foundation/NSKeyedArchiver.h>

@implementation NSCustomView

- (id)initWithCoder:(NSCoder *)coder {
   if ([coder allowsKeyedCoding]) {
      NSString *className = [(NSKeyedUnarchiver *)coder decodeObjectForKey:@"NSClassName"];
      Class     class = NSClassFromString(className);
      if (class == nil) {
         NSLog(@"NSCustomView unknown class %@", className);
         return self;
      }
      else {
         NSKeyedUnarchiver *keyed=(NSKeyedUnarchiver *)coder;
         NSRect frame=NSZeroRect;
         if([keyed containsValueForKey:@"NSFrame"])
            frame=[keyed decodeRectForKey:@"NSFrame"];
         else if([keyed containsValueForKey:@"NSFrameSize"])
            frame.size=[keyed decodeSizeForKey:@"NSFrameSize"];

         NSView *newView=[[class alloc] initWithFrame:frame];
         if([keyed containsValueForKey:@"NSvFlags"])
             newView->_autoresizingMask=((unsigned int)[keyed decodeIntForKey:@"NSvFlags"])&0x3F;
         if([keyed containsValueForKey:@"NSTag"])
             newView->_tag=[keyed decodeIntForKey:@"NSTag"];
         [newView->_subviews addObjectsFromArray:[keyed decodeObjectForKey:@"NSSubviews"]];
         [newView->_subviews makeObjectsPerformSelector:@selector(_setSuperview:) withObject:newView];
         [_subviews removeAllObjects];
         [self release];
         return newView;
      }
   }
   else {
      [NSException raise:NSInvalidArgumentException format:@"-[%@ %s] does not handle %@",isa,sel_getName(_cmd),[coder class]];
      return self;
   }
}

@end