/*
 * mcu_tim.h
 *
 *  Created on: 16/04/2021.
 *      Author: alexrayne <alexraynepe196@gmail.com>
  ------------------------------------------------------------------------
    Copyright (c) alexrayne

   All rights reserved.
   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
   - Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   - Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in the
     documentation and/or other materials provided with the distribution.
   - Neither the name of ARM nor the names of its contributors may be used
     to endorse or promote products derived from this software without
     specific prior written permission.
   *
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   POSSIBILITY OF SUCH DAMAGE. *
  ------------------------------------------------------------------------
    this is for STM SPL compatibily wraper for timer devices
 */

#ifndef CPU_RENESAS_RA2L_FSP_MCU_TIM_H_
#define CPU_RENESAS_RA2L_FSP_MCU_TIM_H_

#include <stdint.h>
#include <mcu-chip.h>

#if !defined(RA_H)
#warning "uncknown HAL, expects renesas RA"
#endif

#include <c_compat.h>
#include "cslr.h"

#include "r_timer_api.h"
// provide AGTn timers constants
//#include "r_agt.h"


typedef R_AGT0_Type     TIM_TypeDef;

//#define TIM_idx(TIMx)   (((uint32_t) TIMx - (uint32_t) R_AGT0)) / ((uint32_t) R_AGT1 - (uint32_t) R_AGT0)))
#define TIM_idx(TIMx) ( ( TIMx == R_AGT0)? 0 : ( TIMx == R_AGT1)? 1 : 0 )

#define _TIM_CAT2(a,b)    a##b
#define _TIM_CAT3(a,b,c)  a##b##c

/// @brief FSP configurator generates this IRQn_Type ID in vector_data.h
/// @arg n - digit 0..1
#define AGTn(n)        _TIM_CAT2(R_AGT,n)
#define TIMn_IRQ(n)   _TIM_CAT3(AGT, n, _INT_IRQn)
#define TIMn_CMPA_IRQ(n)   _TIM_CAT3(AGT, n, _COMPARE_A_IRQn)
#define TIMn_CMPB_IRQ(n)   _TIM_CAT3(AGT, n, _COMPARE_B_IRQn)

//-----------------------------------------------------------------
// this is port of through all HALs
#define TIM_STATUS(TIMx)        (TIMx)->AGTCR
#define TIM_VALUE(TIMx)         (TIMx)->AGT



enum AGTStatusFlag{
    AGT_START               = R_AGT0_AGTCR_TSTART_Msk ,
    AGT_CSTF                = R_AGT0_AGTCR_TCSTF_Msk,
    AGT_STOP                = R_AGT0_AGTCR_TSTOP_Msk,

    TIM_IF_TRIG             = R_AGT0_AGTCR_TEDGF_Msk,
    TIM_IF_ZERO             = R_AGT0_AGTCR_TUNDF_Msk,
    TIM_IF_OC1              = R_AGT0_AGTCR_TCMAF_Msk,
    TIM_IF_OC2              = R_AGT0_AGTCR_TCMBF_Msk,

    TIM_IF_OCA              = TIM_IF_OC1,
    TIM_IF_OCB              = TIM_IF_OC2,
    TIM_IF_OCx              = (TIM_IF_OC1 | TIM_IF_OC2) ,
    TIM_IF_OCx_Pos          = R_AGT0_AGTCR_TCMAF_Pos ,

    TIM_ENA                 = AGT_START,
    TIM_IF_RELOAD           = TIM_IF_ZERO,

    TIM_IF_CLEAR_ALL        = 0 ,
    TIM_IF_KEEP_ALL         = (TIM_IF_ZERO | TIM_IF_TRIG | TIM_IF_OCx),
};



static inline
void TIM_enable( TIM_TypeDef* TIMx ){
    TIM_STATUS(TIMx) = TIM_IF_KEEP_ALL | AGT_START;
}

static inline
void TIM_disable( TIM_TypeDef* TIMx ){
    TIM_STATUS(TIMx) = TIM_IF_KEEP_ALL;
}

static inline
bool TIM_is_enabled(TIM_TypeDef* TIMx){
    return (TIM_STATUS(TIMx) & AGT_CSTF) != 0;
}

static inline
void TIM_stop( TIM_TypeDef* TIMx ){
    TIM_STATUS(TIMx) = TIM_IF_KEEP_ALL| AGT_STOP;
}

static inline
void TIM_IF_clear( TIM_TypeDef* TIMx, uint8_t mask ){
    TIM_STATUS(TIMx) = TIM_STATUS(TIMx) & ((~mask & TIM_IF_KEEP_ALL) | AGT_START);
}

INLINE
void TIM_Cmd(TIM_TypeDef* TIMx, int onoff) {
    if ( onoff )
        TIM_enable(TIMx);
    else
        TIM_disable(TIMx);
}

INLINE
void TIM_SetAutoReload(TIM_TypeDef* TIMx, uint16_t x) {
    TIMx->AGT = x;
}


/// @brief AGT not control IE, but enable according functions
///
enum AGTCompFlag{
    TIM_IE_OC1  =   R_AGT0_AGTCMSR_TCMEA_Msk,
    TIM_IE_OC2  =   R_AGT0_AGTCMSR_TCMEB_Msk,
    TIM_IE_OCx  =   (TIM_IE_OC1 | TIM_IE_OC2),

    TIM_IE_OCA  = TIM_IE_OC1 ,
    TIM_IE_OCB  = TIM_IE_OC2 ,
};
//#define TIM_IE_ZERO         TIM_DIER_UIE
//#define TIM_IE_RELOAD       TIM_DIER_UIE
//#define TIM_IE_TRIG         TIM_DIER_TIE

#define TIM_IE(TIMx)                (TIMx)->AGTCMSR
#define TIM_IE_enable(TIMx, mask)   SET_BIT( TIM_IE(TIMx), (mask) )
#define TIM_IE_disable(TIMx, mask)  CLEAR_BIT( TIM_IE(TIMx), (mask) )




typedef enum AGTChID{ TIM_OC1 = 0, TIM_OC2 = 1, } AGTChID;

INLINE
void TIM_SetCHCompare(TIM_TypeDef* TIMx, AGTChID ch, uint16_t x){
    volatile uint16_t* chreg = &(TIMx->AGTCMA);
    chreg[ch] = x;
}



#ifdef __cplusplus
extern "C" {
#endif

typedef enum AGTModeID{
    AGT_MODE            = R_AGT0_AGTMR1_TMOD_Msk,
    AGT_MODE_TIMER      = 0,
    AGT_MODE_PULSE      = 1,    //< Pulse output mode
    AGT_MODE_COUNTER    = 2,    //< Event counter mode
    AGT_MODE_CAP_WIDTH  = 3,    //< Pulse width measurement mode
    AGT_MODE_CAPTURE    = 4,    //< Pulse period measurement mode

    AGT_EDGE            = R_AGT0_AGTMR1_TEDGPL_Msk,
    AGT_EDGE_SINGLE     = 0,
    AGT_EDGE_BOTH       = 1 << R_AGT0_AGTMR1_TEDGPL_Pos,
} AGTModeID;

typedef enum AGTClkSrcID {
    AGT_SRC             = R_AGT0_AGTMR1_TCK_Msk ,
    AGT_SRC_PCLKB       = 0,
    AGT_SRC_PCLKB8      = 1 << R_AGT0_AGTMR1_TCK_Pos,    //<  PCLKB/8
    AGT_SRC_PCLKB2      = 3 << R_AGT0_AGTMR1_TCK_Pos,    //<  PCLKB/2
    AGT_SRC_LCLK        = 4 << R_AGT0_AGTMR1_TCK_Pos,    //<  Prescaler specified by CKS[2:0] bits in the AGTMR2 register
    AGT_SRC_ATG0        = 5 << R_AGT0_AGTMR1_TCK_Pos,    //< Underflow event signal from AGT0
    AGT_SRC_SCLK        = 6 << R_AGT0_AGTMR1_TCK_Pos,    //< Prescaler specified by CKS[2:0] bits in the AGTMR2 register
} AGTClkSrcID;


typedef enum AGTPrescaleID {
    AGTPrescale     = R_AGT0_AGTMR2_CKS_Msk,
    AGTPrescale1    = 0,
    AGTPrescale2    = 1,
    AGTPrescale4    = 2,
    AGTPrescale8    = 3,
    AGTPrescale16   = 4,
    AGTPrescale32   = 5,
    AGTPrescale64   = 6,
    AGTPrescale128  = 7,

    AGTPrescaleTOP  = AGTPrescale128,
} AGTPrescaleID;



struct TIM_InitTypeDef {
    uint8_t     mode;           //< AGTModeID | AGTClkSrcID
    uint8_t     clockdiv;       //< AGTPrescaleID
};
typedef struct TIM_InitTypeDef TIM_InitTypeDef;

// STM LL HAL wraps
void TIM_Init( TIM_TypeDef* TIMx, TIM_InitTypeDef mode);
void TIM_DeInit(TIM_TypeDef* TIMx);

// TIMDevice API
void TIM_cfg_CLK(TIM_TypeDef* TIMx, AGTClkSrcID src, AGTPrescaleID prescale);



#ifdef __cplusplus
}
#endif


#endif /* CPU_RENESAS_RA2L_FSP_MCU_TIM_H_ */
