/*********************************************************************************************************************
 * Copyright (c) 2021, Infineon Technologies AG
 *
 * 
 * Distributed under the Boost Software License, Version 1.0.
 * 
 * 
 * Boost Software License - Version 1.0 - August 17th, 2003
 * 
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 * 
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 * 
 *********************************************************************************************************************/


/********************************************************************************************************
 * @file        TLE926x.c
 *
 * @brief       Implementation of main library functions
 *
 * @version     V1.0.0
 * @date        
 * @author      Fedy Farhat
 * @author      Michael Schaffarczyk
 ********************************************************************************************************/


/* ================================================================================ */
/* ============================   HEADER FILES     ================================ */
/* ================================================================================ */

#include "TLE926x.h"
#include "SBC_TLE926x.h"
#include <stdio.h>
#include "plib_port.h"


/* ================================================================================ */
/* ==============================   Variables     ================================= */
/* ================================================================================ */
#ifndef TRUE
#define TRUE  1
#endif

#ifndef FALSE
#define FALSE 0
#endif

static uint8_t wd_config;
/* --------------------------------  ISR Handling --------------------------------- */


static    SBC_Func_Callback                 SBC_ISR_Callbacks[60];
static    uint32_t                          SBC_ISR_Vectors[60];
static    uint8_t                           SBC_ISR_ReadOutRegs[60];
static    uint8_t                           SBC_ISR_ReadOutVals[60];
static    uint8_t                           SBC_RegisteredCallbacks = 0;
static    uint8_t                           SBC_RegisteredRedoutRegs = 0;
uint16_t  SBC_Mode=0;
uint16_t  SBC_Mode_VCC1=0;
uint16_t  SBC_Mode_VCC2=0;

/* ================================================================================ */
/* ===========================   Library Functions     ============================ */
/* ================================================================================ */


/* --------------------------------  Main Functions ------------------------------- */

// trigger the Watchdog
SBC_ErrorCode sbc_wd_trigger(void) {
    SBC_ErrorCode errCode; 
//    if (wd_config == (sbc_read_reg(SBC_WD_CTRL)&0xFF)) {
//        return sbc_write_reg(SBC_WD_CTRL, wd_config, NULL);
//    } 
    sbc_write_reg(SBC_WD_CTRL, wd_config, NULL);

//    SBC_Mode_VCC2 = sbc_read_reg(SBC_SUP_STAT_1);
//    SBC_Mode_VCC1 = sbc_read_reg(SBC_SUP_STAT_2);
//	sbc_write_reg(SBC_M_S_CTRL,0x8,0);
//    errCode.SBC_Register = SBC_WD_CTRL;
//    errCode.flippedBitsMask = ((uint8_t)sbc_read_reg(SBC_WD_CTRL)) ^ wd_config;                        
//    errCode.expectedValue = wd_config;
    errCode.SBC_Register = 0;
    errCode.flippedBitsMask = 0;                        
    errCode.expectedValue = 0;
    return errCode;
}
void sbc_trig_reset(void)
{
    /*soft reset*/
    //sbc_write_reg_field (SBC_M_S_CTRL, MODE_MASK, SBC_RESET, 0x00); // M_S_CTRL(0x81)
    sbc_init();
}

// Read the addressed register
uint16_t sbc_read_reg(sbc_register_t sbc_register) {
    /* Read and return data - Bit[15:8] = Status Information Field - Bit [7:0] Register data */
    return  SBC_SPI_TRANSFER16(SBC_READ_MASK & sbc_register, 0x00);                                 
}

// Read register bit 
uint8_t sbc_read_reg_field(sbc_register_t sbc_register, sbc_bit_mask_t bit_mask) {
    uint8_t data = ((uint8_t)sbc_read_reg(sbc_register)) & 0xFFU;                                                
    return (data & bit_mask) >> SBC_BITPOSITION(bit_mask);                                               
}

 
// Write value to a register
SBC_ErrorCode sbc_write_reg(sbc_register_t sbc_register, uint8_t SBC_Val, uint16_t * returnval) {                      
    SBC_ErrorCode errCode;                                                                                 
    uint16_t returndata = SBC_SPI_TRANSFER16(SBC_WRITE_BIT | sbc_register, SBC_Val);                            
    if(returnval != NULL) {                                                                                
        *returnval = returndata;                                                                        
    }

//    errCode.SBC_Register = sbc_register;
//    errCode.flippedBitsMask = ((uint8_t)sbc_read_reg(sbc_register)) ^ SBC_Val;                             
//    errCode.expectedValue = SBC_Val;
    errCode.SBC_Register = 0;
    errCode.flippedBitsMask = 0;                             
    errCode.expectedValue = 0;

    return errCode; 
}

/*Write bit value in register*/
SBC_ErrorCode sbc_write_reg_field(sbc_register_t sbc_register, sbc_bit_mask_t bit_mask, uint8_t val, uint16_t * returnval) { 
    SBC_ErrorCode errCode;

    /* Read data out of register to be manipulated */
    uint16_t returndata = sbc_read_reg(sbc_register);
    if(returnval != NULL) {
        *returnval = returndata;
    }
     /* pick the first 8 bit of read SBC_Reg, meant register data [7:0]*/
    uint8_t data = (uint8_t)returndata;

    /* Set the used bit field to all 0 */
    data &= ~(bit_mask); 
                            
    /* Configure new data to bit field */
    data |= (val << SBC_BITPOSITION(bit_mask)); 

    (void)SBC_SPI_TRANSFER16(SBC_WRITE_BIT | sbc_register, data); 
                                                            
    errCode.SBC_Register = sbc_register;  
    errCode.expectedValue = (val <<  SBC_BITPOSITION(bit_mask)); 
    uint8_t actualValue = ((uint8_t)sbc_read_reg(sbc_register)) & bit_mask; 
    errCode.flippedBitsMask = errCode.expectedValue ^ actualValue; 
                                                                
    return errCode; 
}

void delay(uint32_t val)
{
	uint32_t temp = 0xFFFF;

	while(val--)
	{
		while(temp--);
		temp = 0xFFFF;
	}
}

void CyclicTskSchM_TimerSync (void);

/* initialize SBC */
SBC_ErrorCode sbc_init(void) {                                           
    SBC_ErrorCode errCode;
    uint8_t i;
    uint8_t delay_cnt;
    uint8_t WD_CTRL = CW_WD_CTRL;
	uint8_t checksum = WD_CTRL; 
    uint16_t readback;
                                        
    checksum = checksum ^ checksum >> 4; 
    checksum = checksum ^ checksum >> 2;      
    checksum = checksum ^ checksum >> 1;
 

    if((checksum & 1) > 0) { 
        /* Set parity bit */
        WD_CTRL = WD_CTRL | 0x80U; // 
    }
	wd_config = WD_CTRL;

    /* Describes initialization sequence.
       init Sequence containing {reg_address, reg_value}*/
    uint8_t initSequence[4][2] = {
        {SBC_WD_CTRL, WD_CTRL},//0x04               TimeOut; 200ms period
        {SBC_M_S_CTRL, CW_M_S_CTRL},//0x08          SBC normal;vcc3off;vcc2 on in normal;
        {SBC_BUS_CTRL_1, CW_BUS_CTRL_1},//0x03      lin off; can normal

        /* End Configuration */ 
        {0x00U, 0x00U}
    };


	    delay_cnt = 10;
	    do{
	    	CyclicTskSchM_TimerSync();
	    }while(delay_cnt--);
 


    /* Write all initialization items to Lite SBC 
     write the above defined reg_values inside the real registers on Lite SBC*/
    i =0;
    while(initSequence[i][0] != 0x00U || initSequence[i][1] != 0x00U) {
        while((readback&0xff) != initSequence[i][1])
        {
            errCode = sbc_write_reg((sbc_register_t) initSequence[i][0],(sbc_register_t) initSequence[i][1], &readback);             
        }
    
        i++;
    }

    errCode.SBC_Register = 0x00;
    errCode.flippedBitsMask = 0x00;
    errCode.expectedValue = 0x00;
    return errCode;
}
#if 0
/* initialize SBC */
SBC_ErrorCode sbc_init(void) {                                           
    SBC_ErrorCode errCode;
    
    uint16_t famprod;
    uint8_t sbc_family;
    //uint8_t sbc_product;
    uint8_t i;
    uint8_t cond;
	uint8_t delay_cnt;
	
	uint8_t sbc_reset_init;
	uint8_t sbc_init;
	uint8_t sbc_init_cnt;

    uint8_t WD_CTRL = CW_WD_CTRL;
    //uint8_t SWK_ID3_CTRL, SWK_ID2_CTRL, SWK_ID1_CTRL, SWK_ID0_CTRL;
    //uint8_t SWK_MASK_ID3_CTRL, SWK_MASK_ID2_CTRL, SWK_MASK_ID1_CTRL, SWK_MASK_ID0_CTRL;
    uint8_t SWK_CAN_FD_CTRL = CW_SWK_CAN_FD_CTRL;

	uint8_t checksum = WD_CTRL; 

                        
    checksum = checksum ^ checksum >> 4; 
    checksum = checksum ^ checksum >> 2;      
    checksum = checksum ^ checksum >> 1;
 

    if((checksum & 1) > 0) { 
        /* Set parity bit */
        WD_CTRL = WD_CTRL | 0x80U; // 
    }
	wd_config = WD_CTRL;

    /* Check if ID is configured to be extended */
    if((CW_SWK_ID0_CTRL &  IDE_MASK ) == SBC_IDE_EXTENDED) {

    } else {

    }
    

    /* DIS_ERR_CNT is set only when FD Tolerance is set.
       Set DIS_ERR_CNT value to 1 if the value of CAN_FD_EN is 1 */
   
    if((CW_SWK_CAN_FD_CTRL & CAN_FD_EN_MASK) == SBC_CAN_FD_EN_ENABLED) {
        SWK_CAN_FD_CTRL |= SBC_DIS_ERR_CNT_DISABLED << SBC_BITPOSITION(DIS_ERR_CNT_MASK);
    }

    /* Describes initialization sequence.
       init Sequence containing {reg_address, reg_value}*/
    uint8_t initSequence[45][2] = {
		{SBC_WD_CTRL, WD_CTRL},
        {SBC_M_S_CTRL, CW_M_S_CTRL},
        {SBC_BUS_CTRL_1, CW_BUS_CTRL_1},
        {SBC_WK_CTRL_1, CW_WK_CTRL_1},
        {0x00U, 0x00U},
        {SBC_HW_CTRL, CW_HW_CTRL},
        {SBC_BUS_CTRL_2, CW_BUS_CTRL_2},
        {SBC_WK_CTRL_2, CW_WK_CTRL_2},
        {SBC_WK_PUPD_CTRL, CW_WK_PUPD_CTRL},
        {SBC_WK_FLT_CTRL, CW_WK_FLT_CTRL},
        {SBC_TIMER1_CTRL, CW_TIMER1_CTRL},
        {SBC_TIMER2_CTRL, CW_TIMER2_CTRL},
        {SBC_SW_SD_CTRL, CW_SW_SD_CTRL},
        {SBC_HS_CTRL_1, CW_HS_CTRL1},
        {SBC_HS_CTRL_2, CW_HS_CTRL2},
        {SBC_PWM1_CTRL, CW_PWM1_CTRL},
        {SBC_PWM2_CTRL, CW_PWM2_CTRL},
        {SBC_PWM_FREQ_CTRL, CW_PWM_FREQ_CTRL}, /* The desired duty cycle should be set first before GPIO is enabled as PWM HS or PWM LS. */
        {SBC_GPIO_CTRL, CW_GPIO_CTRL},

        /* -------------------------- SELECTIVE WAKE REGISTERS --------------------------- */

        /* Configuring CDR */ // CDR = Clock and Data Recovery
        {SBC_SWK_CDR_CTRL2, CW_SWK_CDR_CTRL2},
        {SBC_SWK_BTL1_CTRL, CW_SWK_BTL1_CTRL},
        {SBC_SWK_BTL2_CTRL, CW_SWK_BTL2_CTRL},
        {SBC_SWK_CDR_LIMIT_HIGH, CW_SWK_CDR_LIMIT_HIGH_CTRL},
        {SBC_SWK_CDR_LIMIT_LOW, CW_SWK_CDR_LIMIT_LOW_CTRL},
        {SBC_SWK_CDR_CTRL1, ((SBC_SEL_FILT_TC16 << SBC_BITPOSITION(SELFILT_MASK)) | (SBC_CDR_EN_ENABLED << SBC_BITPOSITION(CDR_EN_MASK)))},
                          
                        

        /* Set ID */
        {SBC_SWK_ID3_CTRL, CW_SWK_ID3_CTRL},
        {SBC_SWK_ID2_CTRL, CW_SWK_ID2_CTRL},
        {SBC_SWK_ID1_CTRL, CW_SWK_ID1_CTRL},
        {SBC_SWK_ID0_CTRL, CW_SWK_ID0_CTRL},

        /* Set Mask */
        {SBC_SWK_MASK_ID3_CTRL, CW_SWK_MASK_ID3_CTRL},
        {SBC_SWK_MASK_ID2_CTRL, CW_SWK_MASK_ID2_CTRL},
        {SBC_SWK_MASK_ID1_CTRL, CW_SWK_MASK_ID1_CTRL},
        {SBC_SWK_MASK_ID0_CTRL, CW_SWK_MASK_ID0_CTRL},

        /* Set Data */ 

        {SBC_SWK_DATA7_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 24)},
        {SBC_SWK_DATA6_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 16)},
        {SBC_SWK_DATA5_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 8)},
        {SBC_SWK_DATA4_CTRL, (uint8_t)(CW_SWK_DATA_H_CTRL >> 0)},
        {SBC_SWK_DATA3_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 24)},
        {SBC_SWK_DATA2_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 16)},
        {SBC_SWK_DATA1_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 8)},
        {SBC_SWK_DATA0_CTRL, (uint8_t)(CW_SWK_DATA_L_CTRL >> 0)},

            

         /* Set DLC */
       {SBC_SWK_DLC_CTRL, CW_SWK_DLC_CTRL}, 

       {SBC_SWK_CAN_FD_CTRL, CW_SWK_CAN_FD_CTRL},
		{SBC_BUS_CTRL_1, CW_BUS_CTRL_1},
        /* End Configuration */ 
        {0x00U, 0x00U}
    };

    /* Call SPI Init */ 
    if(sbc_spi_init() != 0) { 
        errCode.SBC_Register = 0x00;
        errCode.flippedBitsMask = 0x01; 
        errCode.expectedValue = 0x00;
        return errCode;
    };


/* Check if SBC is Mid-Range SBC */
    famprod = sbc_read_reg(SBC_FAM_PROD_STAT);
    sbc_family = (famprod & FAM_MASK) >> 8;
    cond = (sbc_family == MID_RANGE_SBC_FAMILY) || (sbc_family == MID_RANGE_PLUS_SBC_FAMILY);
    if (!cond) {

    }
	    PORT_PinWrite(PORT_PIN_PA15, 1);

    while(1)
    {
		sbc_reset_init = TRUE;
	    /*soft reset*/
	    sbc_write_reg_field (SBC_M_S_CTRL, MODE_MASK, SBC_RESET, 0x00); // M_S_CTRL(0x81)
	    delay_cnt = 10;
	    do{
	    	CyclicTskSchM_TimerSync();
	    }while(delay_cnt--);

	    /* reset index */
	    i =0;
		sbc_init_cnt = 0;
	    /* Write all initialization items to Lite SBC 
	     write the above defined reg_values inside the real registers on Lite SBC*/
	    while(1)
	   	{
			sbc_init = TRUE;
		    while(initSequence[i][0] != 0x00U || initSequence[i][1] != 0x00U) {
		     errCode = sbc_write_reg((sbc_register_t) initSequence[i][0],(sbc_register_t) initSequence[i][1], NULL);
		        if(errCode.flippedBitsMask > 0) {
		            //return errCode;
		            sbc_init = FALSE;
		            break;
		        }
		        i++;
		    }
			if(sbc_init == TRUE)
			{
				break;
			}
			else
			{
				sbc_init_cnt ++;
				if(sbc_init_cnt >= 10)
				{
					sbc_reset_init = FALSE;
					break;
				}
			}
	   	}
	   if(sbc_reset_init == TRUE)/*init ok*/
	   {
		   break;
	   }
    }
    PORT_PinWrite(PORT_PIN_PA15, 0);
    errCode.SBC_Register = 0x00;
    errCode.flippedBitsMask = 0x00;
    errCode.expectedValue = 0x00;
    return errCode;
}
#endif




/* --------------------------------  ISR Functions -------------------------------- */

/* Callback function*/
void sbc_register_callback(uint32_t vector_isr, void (*Callback_Handler)(uint8_t callbackHandler)) {

    /* Save callback */
    SBC_ISR_Callbacks[SBC_RegisteredCallbacks] = Callback_Handler;

    /* Save callback vector */
    
    SBC_ISR_Vectors[SBC_RegisteredCallbacks] =  vector_isr;

    /* Check if the register will be readout already to avoid double-readout later */
    uint8_t RegFound = 0;
    for (uint8_t i = 0; i < SBC_RegisteredRedoutRegs; i++) {
        if (SBC_ISR_ReadOutRegs[i] == ( vector_isr >> 24)) {  
                                                             
                                                             
            RegFound = 1;
        }
    }

    /* If readout status-reg was not found, register in the readout list */
    if (RegFound == 0) {
        SBC_ISR_ReadOutRegs[SBC_RegisteredRedoutRegs] = (uint8_t)( vector_isr>> 24);
        SBC_RegisteredRedoutRegs++;
    }

    SBC_RegisteredCallbacks++;
}


SBC_ErrorCode SBC_ISR(void) {
    SBC_ErrorCode errCode;

    /* Readout all registered status-registers */
    for (uint8_t i = 0; i < SBC_RegisteredRedoutRegs; i++) {
        SBC_ISR_ReadOutVals[i] = (uint8_t) sbc_read_reg( (sbc_register_t) SBC_ISR_ReadOutRegs[i]);
    }

    /* Handle all interrupts */
    
    for (uint8_t i = 0; i < SBC_RegisteredCallbacks; i++) {
        /* Decode ISR Vector */
        uint8_t Compare = (uint8_t)SBC_ISR_Vectors[i];
        uint8_t FieldPos = (uint8_t)(SBC_ISR_Vectors[i] >> 8);
        uint8_t FieldMsk = (uint8_t)(SBC_ISR_Vectors[i] >> 16);
        uint8_t RegAddr = (uint8_t)(SBC_ISR_Vectors[i] >> 24);

        /* Readback of associated status-bit */
        uint8_t ReadBack = 0;
        for (uint8_t j = 0; j < SBC_RegisteredRedoutRegs; j++) {
            if (SBC_ISR_ReadOutRegs[j] == RegAddr) {
                ReadBack = SBC_ISR_ReadOutVals[j];
                break;
          }
        }

        /* If compare-values matched -> proceed callback and clear field */
        if (((ReadBack & FieldMsk) >> FieldPos) == Compare) {
            SBC_ISR_Callbacks[i](ReadBack);
        }
    }

    /* Clear all ISR related registers */
    for (uint8_t i = 0; i < SBC_RegisteredRedoutRegs; i++) {
        errCode = sbc_write_reg( (sbc_register_t) SBC_ISR_ReadOutRegs[i], 0x00U, NULL);
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
    }

    errCode.SBC_Register = 0x00U;
    errCode.flippedBitsMask = 0x00U;
    errCode.expectedValue = 0x00U;
    return errCode;
}



/* --------------------------------  API Calls  ----------------------------------- */
/* enter Normal Mode*/
SBC_ErrorCode sbc_mode_normal(void) {
    return sbc_write_reg_field(SBC_M_S_CTRL, MODE_MASK, SBC_NORMAL_MODE, NULL);
}

/* enter Stop Mode*/
SBC_ErrorCode sbc_mode_stop (void) {
    return sbc_write_reg_field(SBC_M_S_CTRL, MODE_MASK, SBC_STOP_MODE, NULL);
}

/* enter Sleep Mode*/
SBC_ErrorCode sbc_mode_sleep(void) {
    uint8_t registerReadOut;

    SBC_ErrorCode errCode;



/* Check SBC in Normal Mode */
    uint8_t readData = sbc_read_reg(SBC_M_S_CTRL);
    readData >>= SBC_BITPOSITION(MODE_MASK);

    if (readData != SBC_NORMAL_MODE) {
        errCode = sbc_mode_normal();
        return errCode;
    }

    /* If CAN PN is configured */
    if(MATH_EN_PN != 0) {

        /* Reading value of SWK_STAT. */
        registerReadOut = (uint8_t)sbc_read_reg(SBC_SWK_STAT);

        /* The selective wake routine should be aborted if sync is not set. 
           Note: for SYNC to be set the transceiver must have been in Normal Mode and */
        if((registerReadOut & SYNC_MASK ) >> SBC_BITPOSITION(SYNC_MASK) != SYNC_VALID_FRAME_RECEIVED) {
            errCode.SBC_Register = SBC_SWK_STAT;
            errCode.flippedBitsMask = SYNC_MASK;
            errCode.expectedValue =  SYNC_VALID_FRAME_RECEIVED << SBC_BITPOSITION(SYNC_MASK);
            return errCode;
        }


        /* Set SWK Configuration valid */
        // set CFG_VAL = 1
         
        errCode = sbc_write_reg_field(SBC_SWK_CTRL, CFG_VAL_MASK, SBC_CFG_VAL_VALID, NULL);
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
    
    
    /* Clear SYSERR bit */
    
        errCode = sbc_write_reg_field(SBC_BUS_STAT_1, SYSERR_MASK, 0x00, NULL);
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        } 

        /* Set CAN Mode to off and once again to desired configuration */
        // CAN OFF
        errCode = sbc_write_reg_field(SBC_BUS_CTRL_1, CAN_MASK, CAN_OFF, NULL); 
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
    // CAN ON (with SWK)
        errCode = sbc_write_reg_field(SBC_BUS_CTRL_1, CAN_MASK, CAN_WAKECAPABLE_SWK, NULL);
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }

     /* Check SWK_STAT for SYNC == 1 && SWK_SET == 1 && WUF == 0 && WUP == 0. Ignore CANSIL */
    registerReadOut = (uint8_t)sbc_read_reg(SBC_SWK_STAT);
        if(        ((SYNC_MASK & registerReadOut) == SYNC_MASK)
            && ((SWK_SET_MASK & registerReadOut) == SWK_SET_MASK)
            && ((WUP_MASK & registerReadOut) != WUP_MASK)
            && ((WUF_MASK & registerReadOut) != WUF_MASK)) {
        /* Empty */ 

        } else {
            errCode.SBC_Register = SBC_SWK_STAT;
            errCode.expectedValue = 0b01000100U;
            errCode.flippedBitsMask = errCode.expectedValue ^ registerReadOut;  
            return errCode;
        }
    
    
    
    }

  

    /* Clear Wake Status Registers, so that SBC can sleep. */
    errCode = sbc_write_reg(SBC_WK_STAT_1, 0x00, NULL);
    if(errCode.flippedBitsMask > 0) {
        return errCode;
    }
    errCode = sbc_write_reg(SBC_WK_STAT_2, 0x00, NULL);
    if(errCode.flippedBitsMask > 0) {
        return errCode;
    }
  
    /* Select sleep mode */
     sbc_write_reg_field(SBC_M_S_CTRL, MODE_MASK, SBC_SLEEP_MODE, NULL);
     
    errCode.SBC_Register = 0x00U;
    errCode.flippedBitsMask = 0x00U;
    errCode.expectedValue = 0x00U;
    return errCode;
}

/* configure HSx  */
SBC_ErrorCode sbc_hsx_config(sbc_hsx_t hsX, sbc_hs_config_t hsConfig) {
    SBC_ErrorCode errCode = {0,0,0};

    switch (hsX) {
    case HS1:
        errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS1_MASK, hsConfig, NULL);
        break;
    case HS2:
        errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS2_MASK, hsConfig, NULL);
        break;
    case HS3:
        errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS3_MASK, hsConfig, NULL);
        break;
    case HS4:
        errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS4_MASK, hsConfig, NULL);
        break;

    default:
        return errCode;
    }
    return errCode;
}



/* CAN MODE*/ 
SBC_ErrorCode sbc_can_mode(sbc_can_t CANmode )  
{
    SBC_ErrorCode errCode; 
    errCode =  sbc_write_reg_field(SBC_BUS_CTRL_1, CAN_MASK, CANmode, NULL);
   
return errCode; 
}


/* LIN MODE */
SBC_ErrorCode sbc_lin_mode(sbc_lin_module_t linModule, sbc_lin_mode_t linMode) {
    SBC_ErrorCode errCode = {0,0,0};
    uint8_t mr_sbc_variant = sbc_read_reg(SBC_FAM_PROD_STAT) & PROD_MASK;
       /* check if it is a variant with minimum 1 LIN interface*/
    if (mr_sbc_variant & 0b1000) { 
        if (linModule == LIN1) {
            errCode = sbc_write_reg_field(SBC_BUS_CTRL_1, LIN1_MASK, linMode, NULL);
        } else {
             /* cheack if it is a variant with 2 LIN interfaces*/
            if (mr_sbc_variant & 0b1100) {
                errCode = sbc_write_reg_field(SBC_BUS_CTRL_2, LIN2_MASK, linMode, NULL);
            } else {
                 
                return errCode; // default value 0 
            }
        }
    } else {

        return errCode; // default value 0 
    }
    return errCode;
}
/* WRITE IN System status register*/
SBC_ErrorCode sbc_sys_stat_write(uint8_t status) {
  return sbc_write_reg(SBC_SYS_STAT_CTRL, status, NULL);
}

/* Read register system status*/
uint8_t sbc_sys_stat_read(void) {
    return sbc_read_reg(SBC_SYS_STAT_CTRL);
}
// disabling WD  and entering stop mode
SBC_ErrorCode sbc_mode_stop_without_watchdog(void) {
    SBC_ErrorCode errCode = sbc_write_reg_field(SBC_WK_CTRL_1, WD_STM_EN_1_MASK, WATCHDOG_DEACTIVED_IN_STOP_MODE, NULL);

  if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
    errCode = sbc_write_reg_field(SBC_WD_CTRL, WD_STM_EN_0_MASK, WATCHDOG_DEACTIVED_IN_STOP_MODE, NULL);
   if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
    return sbc_mode_stop();
}


/* configure cyclic sense function*/
SBC_ErrorCode sbc_cyclicsense(sbc_timer_t timer, sbc_timer_per_t timerPeriod, sbc_timer_on_t timerOnTime, sbc_hsx_t hsX, sbc_wk_t wk, sbc_wk_pupd_t pupdConfig) {
    SBC_ErrorCode errCode={0,0,0};

    if (timer == TIMER1) {
        errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_ON_MASK, TIMER_ONTIME_OFF_LOW, NULL);
      if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        switch (hsX)
        {
        case HS1:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS1_MASK, CONTROLLED_BY_TIMER1, NULL);
            break;
        case HS2:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS2_MASK, CONTROLLED_BY_TIMER1, NULL);
            break;
        case HS3:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS3_MASK, CONTROLLED_BY_TIMER1, NULL);
            break;
        case HS4:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS4_MASK, CONTROLLED_BY_TIMER1, NULL);
            break;
        default:
            return errCode;
        }

       if(errCode.flippedBitsMask > 0){
            return errCode;
        }
        switch (wk) {
        case WK1:
            errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK1_FLT_MASK, FILTER_ONTIME_END_TIMER1, NULL);
            if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
            errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK1_PUPD_MASK, pupdConfig, NULL);
            break;
        case WK2:
            errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK2_FLT_MASK, FILTER_ONTIME_END_TIMER1, NULL);
           if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
            errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK2_PUPD_MASK, pupdConfig, NULL);
            break;
        case WK3:
            errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK3_FLT_MASK, FILTER_ONTIME_END_TIMER1, NULL);
           if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
            errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK3_PUPD_MASK, pupdConfig, NULL);
            break;
        default:
            break;
        }
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }

        errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_PER_MASK, timerPeriod, NULL);

      if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_ON_MASK, timerOnTime, NULL);
    }
    else if (timer == TIMER2)
    {
        errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_ON_MASK, TIMER_ONTIME_OFF_LOW, NULL);
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        switch (hsX) {
        case HS1:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS1_MASK, CONTROLLED_BY_TIMER2, NULL);
            break;
        case HS2:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_1, HS2_MASK, CONTROLLED_BY_TIMER2, NULL);
            break;
        case HS3:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS3_MASK, CONTROLLED_BY_TIMER2, NULL);
            break;
        case HS4:
            errCode = sbc_write_reg_field(SBC_HS_CTRL_2, HS4_MASK, CONTROLLED_BY_TIMER2, NULL);
            break;
        default:
            return errCode;
        }

      if(errCode.flippedBitsMask > 0) {
            return errCode;
        }

        switch (wk)
        {
        case WK1:
            errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK1_FLT_MASK, FILTER_ONTIME_END_TIMER2, NULL);
           if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
            errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK1_PUPD_MASK, pupdConfig, NULL);
            break;
        case WK2:
            errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK2_FLT_MASK, FILTER_ONTIME_END_TIMER2, NULL);
          if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
            errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK2_PUPD_MASK, pupdConfig, NULL);
            break;
        case WK3:
            errCode = sbc_write_reg_field(SBC_WK_FLT_CTRL, WK3_FLT_MASK, FILTER_ONTIME_END_TIMER2, NULL);
           if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
            errCode = sbc_write_reg_field(SBC_WK_PUPD_CTRL, WK3_PUPD_MASK, pupdConfig, NULL);
            break;
        default:
            break;
        }
        errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_PER_MASK, timerPeriod, NULL);
       if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_ON_MASK, timerOnTime, NULL);
    } else {
        return errCode;
    }
    return errCode;
}

/* configure cyclic wake function*/
SBC_ErrorCode sbc_cyclicwake(sbc_timer_t timer, sbc_timer_per_t timer_period, sbc_timer_on_t timer_on_time) {
    SBC_ErrorCode errCode={0,0,0};

    if (timer == TIMER1) {
        errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER1_WK_EN_MASK, TIMER_WAKE_DISABLED, NULL);
       if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_PER_MASK, timer_period, NULL);
       if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_TIMER1_CTRL, TIMER1_ON_MASK, timer_on_time, NULL);
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER1_WK_EN_MASK, TIMER_WAKE_ENABLED, NULL);
    } 
    else if (timer == TIMER2) {
        errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER2_WK_EN_MASK, TIMER_WAKE_DISABLED, NULL);
       if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        
        errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_PER_MASK, timer_period, NULL);
       if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_TIMER2_CTRL, TIMER2_ON_MASK, timer_on_time, NULL);
       if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_WK_CTRL_1, TIMER2_WK_EN_MASK, TIMER_WAKE_ENABLED, NULL);
}   else {
        return errCode;
    }
    return errCode;
}


/* configure watchdog*/
SBC_ErrorCode sbc_configure_watchdog(sbc_wd_win_t wdWindow, sbc_wd_en_wk_bus_t wdEnableAfterBusWake, sbc_wd_timer_t wdTimer) {
    SBC_ErrorCode errCode;
     /* Calculate checksum */ 
    uint8_t wd_ctrl = (wdWindow << SBC_BITPOSITION(WD_WIN_MASK))
                    | (wdEnableAfterBusWake << SBC_BITPOSITION(WD_EN_WK_BUS_MASK))
                    | (wdTimer << SBC_BITPOSITION(WD_TIMER_MASK));
    uint8_t checksum = wd_ctrl; 

                        
                        
    checksum = checksum ^ checksum >> 4; 
    checksum = checksum ^ checksum >> 2;      
    checksum = checksum ^ checksum >> 1;
 

    if((checksum & 1) > 0) { 
        /* Set parity bit */
        wd_ctrl = wd_ctrl | 0x80U; // 
    }
    errCode = sbc_write_reg(SBC_WD_CTRL, wd_ctrl, NULL);
    if (errCode.flippedBitsMask == 0) {

        /* Save new Watchdog configuration to global variable */
        wd_config = wd_ctrl;
    }
    return errCode;
}

/* configure PWM*/
SBC_ErrorCode sbc_configure_pwm(sbc_pwm_t pwm, sbc_pwm_freq_t frequency, uint8_t dutyCycle) {
    SBC_ErrorCode errCode={0,0,0};
    switch (pwm) {
    case PWM1:
        errCode = sbc_write_reg(SBC_PWM1_CTRL, dutyCycle, NULL);
       if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_PWM_FREQ_CTRL, PWM1_FREQ_MASK, frequency, NULL);
        break;
    case PWM2:
        errCode = sbc_write_reg(SBC_PWM2_CTRL, dutyCycle, NULL);
        if(errCode.flippedBitsMask > 0) {
            return errCode;
        }
        errCode = sbc_write_reg_field(SBC_PWM_FREQ_CTRL, PWM2_FREQ_MASK, frequency, NULL);
        break;

    default:
        return errCode;
    }
    return errCode;
}

/* configure PWM percentage*/
SBC_ErrorCode sbc_configure_pwm_percentage(sbc_pwm_t pwm, sbc_pwm_freq_t frequency, double duty_cycle) {
    return sbc_configure_pwm(pwm, frequency, (uint8_t)(duty_cycle*0xFFU));
}

/* Configure GPIO*/
SBC_ErrorCode sbc_configure_gpio(sbc_gpiox_t gpio, sbc_gpio_t gpio_config) {
    SBC_ErrorCode errCode= {0,0,0};
    switch (gpio) {
    case GPIO1:
        errCode = sbc_write_reg_field(SBC_GPIO_CTRL, GPIO1_MASK, gpio_config, NULL);
        break;
    case GPIO2:
        errCode = sbc_write_reg_field(SBC_GPIO_CTRL, GPIO2_MASK, gpio_config, NULL);
        break;

    default:
        return errCode;
    }

    return errCode;
}


/* Configure Failure Output*/
SBC_ErrorCode sbc_fo_x(uint8_t on) {
    if (on) {
        return sbc_write_reg_field(SBC_HW_CTRL, FO_ON_MASK, FO_ON_ACTIVE, NULL);   
    } else {
        return sbc_write_reg_field(SBC_HW_CTRL, FO_ON_MASK, FO_ON_NOT_ACTIVE, NULL);   
    }
}
/* configure VCC2*/
SBC_ErrorCode sbc_switch_vcc2(sbc_vcc2_on_t vcc2_value) {
 SBC_ErrorCode errCode;

  errCode =  sbc_write_reg_field(SBC_M_S_CTRL, VCC2_ON_MASK, vcc2_value, NULL);
   
    return errCode;
}
/* configure VCC3*/
SBC_ErrorCode sbc_switch_vcc3(sbc_vcc3_on_t vcc3_value) {
     SBC_ErrorCode errCode;
 errCode =  sbc_write_reg_field(SBC_M_S_CTRL, VCC3_ON_MASK , vcc3_value, NULL);
    
         return errCode;
}
