#include "core/config.h" // DEBUG
#include <intrinsics.h>
#include "core/csect.h"

 #pragma pack( push, 1 )
 typedef struct __sCRITICALSECTION_int_nc
 {  
    volatile unsigned long xStdLock_int_reg;    
    
    union
    {
        uint16_t reserved;
        
        struct
        {
           uint8_t bInitialized;
           uint8_t bLocked;           
        };
    };
 }
 sCSect_t;

 typedef struct __sCRITICALSECTION_int_c
 {  
    volatile int32_t xStdLock_int_reg;    
    
    union
    {
        uint16_t reserved;
        
        struct
        {
           #if CSECT_IMPLEMENTATION_SIMPLE == 0
           uint8_t bInitialized;
           #endif
           uint8_t nCounter;           
        };
    };
 }
 sCSectCnt_t;
 #pragma pack( pop )

 #if CSECT_IMPLEMENTATION_SIMPLE
 static sCSectCnt_t sys_csect = {    
    .nCounter = 0,
    .xStdLock_int_reg = 0
 };
 #endif
 
 #if CSECT_IMPLEMENTATION_SIMPLE == 0
 void csect_create( xCSect_t * pSectDescriptor )
 {
    sCSect_t * p = ((sCSect_t*)(pSectDescriptor));
    
    if( p != NULL )
    {
        p->bInitialized = (uint8_t)(~0);
        p->bLocked = (uint8_t)(0);        
        p->xStdLock_int_reg = 0;        
    }
 }
 
 void csect_delete( xCSect_t * pSectDescriptor )
 {
    sCSect_t * p = ((sCSect_t*)(pSectDescriptor));
    
    if( p != NULL )
    {
        p->bInitialized = (uint8_t)(0);
        p->bLocked = (uint8_t)(0);                
        p->xStdLock_int_reg = 0;
    }
 }
 
 void csect_enter( xCSect_t * pSectDescriptor )
 {
    sCSect_t * p = ((sCSect_t*)(pSectDescriptor));
    
    if( p != NULL && (p->bInitialized != 0) )
    {
        if( p->bLocked == 0 )
        {
            p->xStdLock_int_reg = __get_interrupt_state();

            __disable_interrupt();
            
            p->bLocked = (uint8_t)(~0);
        }        
    }
 }
 
 void csect_leave( xCSect_t * pSectDescriptor )
 {
    sCSect_t * p = ((sCSect_t*)(pSectDescriptor));
    
    if( p != NULL && (p->bInitialized != 0) )
    {
        if( p->bLocked != 0 )
        {
            p->bLocked = 0;
            
            __set_interrupt_state( p->xStdLock_int_reg );
        }
    }     
 }
 
 void csectcnt_create( xCSectCnt_t * pSectDescriptor )
 {
    sCSectCnt_t * p = ((sCSectCnt_t*)(pSectDescriptor));
    
    if( p != NULL )
    {
        p->bInitialized = (uint8_t)(~0);
        p->nCounter = 0;        
        p->xStdLock_int_reg = 0;        
    }
 }
 
 void csectcnt_delete( xCSectCnt_t * pSectDescriptor )
 {
    sCSectCnt_t * p = ((sCSectCnt_t*)(pSectDescriptor));
    
    if( p != NULL )
    {
        p->bInitialized = (uint8_t)(0);
        p->nCounter = 0;        
        p->xStdLock_int_reg = 0;
    }
 }
 #endif

 #if CSECT_IMPLEMENTATION_SIMPLE == 1
 static void csectcnt_enter()
 #else
 void csectcnt_enter( xCSectCnt_t * pSectDescriptor )
 #endif
 {
    #if CSECT_IMPLEMENTATION_SIMPLE == 1
    sCSectCnt_t * p = &sys_csect;
    #else
    sCSectCnt_t * p = ((sCSectCnt_t*)(pSectDescriptor));
    #endif
    
    #if CSECT_IMPLEMENTATION_SIMPLE == 0
    if( p != NULL && (p->bInitialized != 0) )
    #endif
    {
        if( p->nCounter == 0 )
        {
            p->xStdLock_int_reg = __get_interrupt_state();

            __disable_interrupt();

            #if CONFIG_CSECT_DEBUG
            CONFIG_CSECT_DEBUG_SETPIN
            #endif
            
            p->nCounter++;
        }
        else if( p->nCounter < 255 )
        {
            p->nCounter++;
        }
    }
 }
 
 #if CSECT_IMPLEMENTATION_SIMPLE == 1
 static void csectcnt_leave()
 #else
 void csectcnt_leave( xCSectCnt_t * pSectDescriptor )
 #endif
 {
    #if CSECT_IMPLEMENTATION_SIMPLE == 1
    sCSectCnt_t * p = &sys_csect;
    #else
    sCSectCnt_t * p = ((sCSectCnt_t*)(pSectDescriptor));
    #endif

    #if CSECT_IMPLEMENTATION_SIMPLE == 0
    if( p != NULL && (p->bInitialized != 0) )
    #endif
    {
        if( p->nCounter > 1 )
        {
            p->nCounter--;
        }
        else if( p->nCounter == 1 )
        {
            p->nCounter--;
            
            #if CONFIG_CSECT_DEBUG
            CONFIG_CSECT_DEBUG_CLRPIN
            #endif

            __set_interrupt_state( p->xStdLock_int_reg );
        }
    }     
 }

 #if CSECT_IMPLEMENTATION_SIMPLE == 1
 void csect_enter()
 {
      csectcnt_enter();
 }

 void csect_leave()
 {
      csectcnt_leave();
 }
 #endif
