/*!
 * \file
 *    NUCLEO_F401RE.h
 * \brief
 *    Nucleo F401RE port file. This file contain the implementation of driver
 *    calls for F401RE board.
 *
 * Author: Christos Choutouridis AEM: 8997
 * email : <cchoutou@ece.auth.gr>
 */

#ifndef NUCLEO_F401RE_H_
#define NUCLEO_F401RE_H_

#include <stm32f4xx.h>
#include <stm32f4xx_hal.h>
#include <core_cm4.h>

/*
 * ========= Data types ========
 */

//! Driver status return type
typedef enum {
   LLD_OK = 0,    //!< Indicate successful operation
   LLD_ERROR      //!< Indicate Error
}LLD_Status_en;

typedef  uint8_t              din_t;

#define  OFF                  (0)
#define  ON                   (!OFF)
#ifndef  FALSE
#define  FALSE                (0)
#endif
#ifndef  TRUE
#define  TRUE                 (!FALSE)
#endif


/*
 * =============== System ===============
 */
#if defined ( __GNUC__ ) && !defined (__CC_ARM)
#include <sys/types.h>
#endif
#include <limits.h>

/*
 * Also defined in types.h
 */
#ifndef  _CLOCK_T_
#if defined (__CC_ARM)
 #define _CLOCK_T_ unsigned int
#else
 #define  _CLOCK_T_   unsigned long
#endif
typedef _CLOCK_T_ clock_t;             /*!< CPU time type */
#endif

#ifndef _TIME_T_
#if defined (__CC_ARM)
 #define _TIME_T_ unsigned int
#else
 #define  _TIME_T_   unsigned long
#endif
typedef _TIME_T_ time_t;               /*!< date/time in unix secs past 1-Jan-70 type for 68 years*/
#endif

/*
 * Helper macros
 */
#define _CLOCK_T_MAX_VALUE_            (ULONG_MAX) //!< Helper macro for maximum signed CPU time calculations

/*!
 *  Calculate the positive time difference of _t2_ and _t1_, where
 *  _t1_, _t2_ are clock_t values
 *  \note
 *    _t2_ event comes is AFTER _t1_
 *
 *  ex:
 *  0   1   2   3   4   5   6   7   8   9
 *      ^                       ^
 *      |                       |
 *      a                       b
 *
 * if : t1=a, t2=b      then  dt = b-a             = t2 - t1
 * if : t1=b, t2=a      then  dt = 9 - (b-a) + 1   = UMAX - (t1-t2) + 1
 *
 */
#define _CLOCK_DIFF(_t2_, _t1_)     ( ((_t2_)>(_t1_)) ? ((_t2_)-(_t1_)) : (_CLOCK_T_MAX_VALUE_ - ((_t1_) - (_t2_)) + 1) )

/*
 * CPU time macros
 */
#define  msec2CPUtime(_ms_)      (((_ms_) * get_freq()) / 1000)
#define  sec2CPUtime(_s_)        ((_s_) * get_freq())

#define  CPUtime2msec(_t_)       (((_t_) * 1000) / get_freq())
#define  CPUtime2sec(_t_)        ((_t_) / get_freq())

HAL_StatusTypeDef HAL_SysTick_Init(clock_t sf);

clock_t HAL_SelectSysTickFreq (clock_t sf);
clock_t HAL_GetSysTickFreq (void);
int HAL_SetSysTickFreq (clock_t sf);

/*
 * ================     Jiffies   =====================
 */
#define  JF_TIMER             TIM5
#define  JF_TIM_CLOCK_FREQ    (1000000)      //1MHz it's OK
#define  JF_TIM_VALUE         (JF_TIMER->CNT)
#define  JF_TIMER_CLK_ENABLE  __HAL_RCC_TIM5_CLK_ENABLE

int JF_setfreq (uint32_t jf_freq, uint32_t jiffies);

/*
 * OS like Functionalities
 */
clock_t get_freq (void);
int set_freq (clock_t sf);

clock_t clock (void);
clock_t setclock (clock_t c);

time_t time (time_t *timer);
int settime (const time_t *t);


/*
 * ============== Cycle count ==============
 */
LLD_Status_en CYCLE_Init (void);
clock_t CYCLE_Get (void);

uint8_t _DINx (GPIO_TypeDef *port, uint32_t pin);
uint8_t _DOUTx (GPIO_TypeDef *port, uint32_t pin, uint8_t st);

/*
 * =============== Digital I/O ===============
 * BTN  -- PC13
 * LED  -- PA5 (SB42 is in place) [SB29: PB13]
 */
LLD_Status_en NUCLEO_Port_Init (void);

uint8_t NUCLEO_BTN (void);
void NUCLEO_LED (uint8_t on);


/*
 * ============= Board Init ==============
 */
LLD_Status_en NUCLEO_Init (clock_t sys_freq);

#endif /* NUCLEO_F401RE_H_ */
