/*******************************************************************************
  GPIO PLIB

  Company:
    Microchip Technology Inc.

  File Name:
    plib_gpio.h

  Summary:
    GPIO PLIB Header File

  Description:
    This library provides an interface to control and interact with Parallel
    Input/Output controller (GPIO) module.

*******************************************************************************/

/*******************************************************************************
* Copyright (C) 2019 Microchip Technology Inc. and its subsidiaries.
*
* Subject to your compliance with these terms, you may use Microchip software
* and any derivatives exclusively with Microchip products. It is your
* responsibility to comply with third party license terms applicable to your
* use of third party software (including open source software) that may
* accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
* INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
* WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
* BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*******************************************************************************/

#ifndef PLIB_GPIO_H
#define PLIB_GPIO_H

#include <device.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

// DOM-IGNORE-BEGIN
#ifdef __cplusplus  // Provide C++ Compatibility

    extern "C" {

#endif
// DOM-IGNORE-END

// *****************************************************************************
// *****************************************************************************
// Section: Data types and constants
// *****************************************************************************
// *****************************************************************************


/*** Macros for Input_2_Sel pin ***/
#define Input_2_Sel_Set()               (LATBSET = (1<<9))
#define Input_2_Sel_Clear()             (LATBCLR = (1<<9))
#define Input_2_Sel_Toggle()            (LATBINV= (1<<9))
#define Input_2_Sel_OutputEnable()      (TRISBCLR = (1<<9))
#define Input_2_Sel_InputEnable()       (TRISBSET = (1<<9))
#define Input_2_Sel_Get()               ((PORTB >> 9) & 0x1)
#define Input_2_Sel_PIN                  GPIO_PIN_RB9

/*** Macros for LCD_Data_7 pin ***/
#define LCD_Data_7_Set()               (LATCSET = (1<<6))
#define LCD_Data_7_Clear()             (LATCCLR = (1<<6))
#define LCD_Data_7_Toggle()            (LATCINV= (1<<6))
#define LCD_Data_7_OutputEnable()      (TRISCCLR = (1<<6))
#define LCD_Data_7_InputEnable()       (TRISCSET = (1<<6))
#define LCD_Data_7_Get()               ((PORTC >> 6) & 0x1)
#define LCD_Data_7_PIN                  GPIO_PIN_RC6

/*** Macros for IR_RX pin ***/
#define IR_RX_Set()               (LATCSET = (1<<7))
#define IR_RX_Clear()             (LATCCLR = (1<<7))
#define IR_RX_Toggle()            (LATCINV= (1<<7))
#define IR_RX_OutputEnable()      (TRISCCLR = (1<<7))
#define IR_RX_InputEnable()       (TRISCSET = (1<<7))
#define IR_RX_Get()               ((PORTC >> 7) & 0x1)
#define IR_RX_PIN                  GPIO_PIN_RC7
#define IR_RX_InterruptEnable()   (CNENCSET = (1<<7))
#define IR_RX_InterruptDisable()  (CNENCCLR = (1<<7))

/*** Macros for Input_Sel_Up pin ***/
#define Input_Sel_Up_Set()               (LATCSET = (1<<8))
#define Input_Sel_Up_Clear()             (LATCCLR = (1<<8))
#define Input_Sel_Up_Toggle()            (LATCINV= (1<<8))
#define Input_Sel_Up_OutputEnable()      (TRISCCLR = (1<<8))
#define Input_Sel_Up_InputEnable()       (TRISCSET = (1<<8))
#define Input_Sel_Up_Get()               ((PORTC >> 8) & 0x1)
#define Input_Sel_Up_PIN                  GPIO_PIN_RC8

/*** Macros for Input_Sel_Dn pin ***/
#define Input_Sel_Dn_Set()               (LATCSET = (1<<9))
#define Input_Sel_Dn_Clear()             (LATCCLR = (1<<9))
#define Input_Sel_Dn_Toggle()            (LATCINV= (1<<9))
#define Input_Sel_Dn_OutputEnable()      (TRISCCLR = (1<<9))
#define Input_Sel_Dn_InputEnable()       (TRISCSET = (1<<9))
#define Input_Sel_Dn_Get()               ((PORTC >> 9) & 0x1)
#define Input_Sel_Dn_PIN                  GPIO_PIN_RC9

/*** Macros for Input_3_Sel pin ***/
#define Input_3_Sel_Set()               (LATBSET = (1<<10))
#define Input_3_Sel_Clear()             (LATBCLR = (1<<10))
#define Input_3_Sel_Toggle()            (LATBINV= (1<<10))
#define Input_3_Sel_OutputEnable()      (TRISBCLR = (1<<10))
#define Input_3_Sel_InputEnable()       (TRISBSET = (1<<10))
#define Input_3_Sel_Get()               ((PORTB >> 10) & 0x1)
#define Input_3_Sel_PIN                  GPIO_PIN_RB10

/*** Macros for Input_4_Sel pin ***/
#define Input_4_Sel_Set()               (LATBSET = (1<<11))
#define Input_4_Sel_Clear()             (LATBCLR = (1<<11))
#define Input_4_Sel_Toggle()            (LATBINV= (1<<11))
#define Input_4_Sel_OutputEnable()      (TRISBCLR = (1<<11))
#define Input_4_Sel_InputEnable()       (TRISBSET = (1<<11))
#define Input_4_Sel_Get()               ((PORTB >> 11) & 0x1)
#define Input_4_Sel_PIN                  GPIO_PIN_RB11

/*** Macros for ADC_RESET pin ***/
#define ADC_RESET_Set()               (LATBSET = (1<<13))
#define ADC_RESET_Clear()             (LATBCLR = (1<<13))
#define ADC_RESET_Toggle()            (LATBINV= (1<<13))
#define ADC_RESET_OutputEnable()      (TRISBCLR = (1<<13))
#define ADC_RESET_InputEnable()       (TRISBSET = (1<<13))
#define ADC_RESET_Get()               ((PORTB >> 13) & 0x1)
#define ADC_RESET_PIN                  GPIO_PIN_RB13

/*** Macros for SYS_RESET pin ***/
#define SYS_RESET_Set()               (LATASET = (1<<10))
#define SYS_RESET_Clear()             (LATACLR = (1<<10))
#define SYS_RESET_Toggle()            (LATAINV= (1<<10))
#define SYS_RESET_OutputEnable()      (TRISACLR = (1<<10))
#define SYS_RESET_InputEnable()       (TRISASET = (1<<10))
#define SYS_RESET_Get()               ((PORTA >> 10) & 0x1)
#define SYS_RESET_PIN                  GPIO_PIN_RA10

/*** Macros for EEPROM_25AA256_CS_L pin ***/
#define EEPROM_25AA256_CS_L_Set()               (LATASET = (1<<7))
#define EEPROM_25AA256_CS_L_Clear()             (LATACLR = (1<<7))
#define EEPROM_25AA256_CS_L_Toggle()            (LATAINV= (1<<7))
#define EEPROM_25AA256_CS_L_OutputEnable()      (TRISACLR = (1<<7))
#define EEPROM_25AA256_CS_L_InputEnable()       (TRISASET = (1<<7))
#define EEPROM_25AA256_CS_L_Get()               ((PORTA >> 7) & 0x1)
#define EEPROM_25AA256_CS_L_PIN                  GPIO_PIN_RA7

/*** Macros for ADAU1467_SCK pin ***/
#define ADAU1467_SCK_Get()               ((PORTB >> 14) & 0x1)
#define ADAU1467_SCK_PIN                  GPIO_PIN_RB14

/*** Macros for EEPROM_25AA256_SCK pin ***/
#define EEPROM_25AA256_SCK_Get()               ((PORTB >> 15) & 0x1)
#define EEPROM_25AA256_SCK_PIN                  GPIO_PIN_RB15

/*** Macros for TOSLINK_SEL pin ***/
#define TOSLINK_SEL_Set()               (LATASET = (1<<0))
#define TOSLINK_SEL_Clear()             (LATACLR = (1<<0))
#define TOSLINK_SEL_Toggle()            (LATAINV= (1<<0))
#define TOSLINK_SEL_OutputEnable()      (TRISACLR = (1<<0))
#define TOSLINK_SEL_InputEnable()       (TRISASET = (1<<0))
#define TOSLINK_SEL_Get()               ((PORTA >> 0) & 0x1)
#define TOSLINK_SEL_PIN                  GPIO_PIN_RA0

/*** Macros for ADAU1467_SDI pin ***/
#define ADAU1467_SDI_Get()               ((PORTA >> 1) & 0x1)
#define ADAU1467_SDI_PIN                  GPIO_PIN_RA1

/*** Macros for EEPROM_25AA256_SDO pin ***/
#define EEPROM_25AA256_SDO_Get()               ((PORTB >> 2) & 0x1)
#define EEPROM_25AA256_SDO_PIN                  GPIO_PIN_RB2

/*** Macros for ROT_ENC_SEL pin ***/
#define ROT_ENC_SEL_Set()               (LATBSET = (1<<3))
#define ROT_ENC_SEL_Clear()             (LATBCLR = (1<<3))
#define ROT_ENC_SEL_Toggle()            (LATBINV= (1<<3))
#define ROT_ENC_SEL_OutputEnable()      (TRISBCLR = (1<<3))
#define ROT_ENC_SEL_InputEnable()       (TRISBSET = (1<<3))
#define ROT_ENC_SEL_Get()               ((PORTB >> 3) & 0x1)
#define ROT_ENC_SEL_PIN                  GPIO_PIN_RB3

/*** Macros for LCD_RS pin ***/
#define LCD_RS_Set()               (LATCSET = (1<<0))
#define LCD_RS_Clear()             (LATCCLR = (1<<0))
#define LCD_RS_Toggle()            (LATCINV= (1<<0))
#define LCD_RS_OutputEnable()      (TRISCCLR = (1<<0))
#define LCD_RS_InputEnable()       (TRISCSET = (1<<0))
#define LCD_RS_Get()               ((PORTC >> 0) & 0x1)
#define LCD_RS_PIN                  GPIO_PIN_RC0

/*** Macros for LCD_RW pin ***/
#define LCD_RW_Set()               (LATCSET = (1<<1))
#define LCD_RW_Clear()             (LATCCLR = (1<<1))
#define LCD_RW_Toggle()            (LATCINV= (1<<1))
#define LCD_RW_OutputEnable()      (TRISCCLR = (1<<1))
#define LCD_RW_InputEnable()       (TRISCSET = (1<<1))
#define LCD_RW_Get()               ((PORTC >> 1) & 0x1)
#define LCD_RW_PIN                  GPIO_PIN_RC1

/*** Macros for LCD_E pin ***/
#define LCD_E_Set()               (LATCSET = (1<<2))
#define LCD_E_Clear()             (LATCCLR = (1<<2))
#define LCD_E_Toggle()            (LATCINV= (1<<2))
#define LCD_E_OutputEnable()      (TRISCCLR = (1<<2))
#define LCD_E_InputEnable()       (TRISCSET = (1<<2))
#define LCD_E_Get()               ((PORTC >> 2) & 0x1)
#define LCD_E_PIN                  GPIO_PIN_RC2

/*** Macros for ADAU1467_SDO pin ***/
#define ADAU1467_SDO_Get()               ((PORTA >> 8) & 0x1)
#define ADAU1467_SDO_PIN                  GPIO_PIN_RA8

/*** Macros for ADAU1467_CE pin ***/
#define ADAU1467_CE_Set()               (LATBSET = (1<<4))
#define ADAU1467_CE_Clear()             (LATBCLR = (1<<4))
#define ADAU1467_CE_Toggle()            (LATBINV= (1<<4))
#define ADAU1467_CE_OutputEnable()      (TRISBCLR = (1<<4))
#define ADAU1467_CE_InputEnable()       (TRISBSET = (1<<4))
#define ADAU1467_CE_Get()               ((PORTB >> 4) & 0x1)
#define ADAU1467_CE_PIN                  GPIO_PIN_RB4

/*** Macros for EEPROM_25AA256_SDI pin ***/
#define EEPROM_25AA256_SDI_Get()               ((PORTA >> 4) & 0x1)
#define EEPROM_25AA256_SDI_PIN                  GPIO_PIN_RA4

/*** Macros for ROT_ENC_EXIT pin ***/
#define ROT_ENC_EXIT_Set()               (LATASET = (1<<9))
#define ROT_ENC_EXIT_Clear()             (LATACLR = (1<<9))
#define ROT_ENC_EXIT_Toggle()            (LATAINV= (1<<9))
#define ROT_ENC_EXIT_OutputEnable()      (TRISACLR = (1<<9))
#define ROT_ENC_EXIT_InputEnable()       (TRISASET = (1<<9))
#define ROT_ENC_EXIT_Get()               ((PORTA >> 9) & 0x1)
#define ROT_ENC_EXIT_PIN                  GPIO_PIN_RA9

/*** Macros for LCD_Data_4 pin ***/
#define LCD_Data_4_Set()               (LATCSET = (1<<3))
#define LCD_Data_4_Clear()             (LATCCLR = (1<<3))
#define LCD_Data_4_Toggle()            (LATCINV= (1<<3))
#define LCD_Data_4_OutputEnable()      (TRISCCLR = (1<<3))
#define LCD_Data_4_InputEnable()       (TRISCSET = (1<<3))
#define LCD_Data_4_Get()               ((PORTC >> 3) & 0x1)
#define LCD_Data_4_PIN                  GPIO_PIN_RC3

/*** Macros for LCD_Data_5 pin ***/
#define LCD_Data_5_Set()               (LATCSET = (1<<4))
#define LCD_Data_5_Clear()             (LATCCLR = (1<<4))
#define LCD_Data_5_Toggle()            (LATCINV= (1<<4))
#define LCD_Data_5_OutputEnable()      (TRISCCLR = (1<<4))
#define LCD_Data_5_InputEnable()       (TRISCSET = (1<<4))
#define LCD_Data_5_Get()               ((PORTC >> 4) & 0x1)
#define LCD_Data_5_PIN                  GPIO_PIN_RC4

/*** Macros for LCD_Data_6 pin ***/
#define LCD_Data_6_Set()               (LATCSET = (1<<5))
#define LCD_Data_6_Clear()             (LATCCLR = (1<<5))
#define LCD_Data_6_Toggle()            (LATCINV= (1<<5))
#define LCD_Data_6_OutputEnable()      (TRISCCLR = (1<<5))
#define LCD_Data_6_InputEnable()       (TRISCSET = (1<<5))
#define LCD_Data_6_Get()               ((PORTC >> 5) & 0x1)
#define LCD_Data_6_PIN                  GPIO_PIN_RC5

/*** Macros for ROT_ENC_2 pin ***/
#define ROT_ENC_2_Set()               (LATBSET = (1<<5))
#define ROT_ENC_2_Clear()             (LATBCLR = (1<<5))
#define ROT_ENC_2_Toggle()            (LATBINV= (1<<5))
#define ROT_ENC_2_OutputEnable()      (TRISBCLR = (1<<5))
#define ROT_ENC_2_InputEnable()       (TRISBSET = (1<<5))
#define ROT_ENC_2_Get()               ((PORTB >> 5) & 0x1)
#define ROT_ENC_2_PIN                  GPIO_PIN_RB5

/*** Macros for ROT_ENC_1 pin ***/
#define ROT_ENC_1_Set()               (LATBSET = (1<<7))
#define ROT_ENC_1_Clear()             (LATBCLR = (1<<7))
#define ROT_ENC_1_Toggle()            (LATBINV= (1<<7))
#define ROT_ENC_1_OutputEnable()      (TRISBCLR = (1<<7))
#define ROT_ENC_1_InputEnable()       (TRISBSET = (1<<7))
#define ROT_ENC_1_Get()               ((PORTB >> 7) & 0x1)
#define ROT_ENC_1_PIN                  GPIO_PIN_RB7

/*** Macros for Input_1_Sel pin ***/
#define Input_1_Sel_Set()               (LATBSET = (1<<8))
#define Input_1_Sel_Clear()             (LATBCLR = (1<<8))
#define Input_1_Sel_Toggle()            (LATBINV= (1<<8))
#define Input_1_Sel_OutputEnable()      (TRISBCLR = (1<<8))
#define Input_1_Sel_InputEnable()       (TRISBSET = (1<<8))
#define Input_1_Sel_Get()               ((PORTB >> 8) & 0x1)
#define Input_1_Sel_PIN                  GPIO_PIN_RB8


// *****************************************************************************
/* GPIO Port

  Summary:
    Identifies the available GPIO Ports.

  Description:
    This enumeration identifies the available GPIO Ports.

  Remarks:
    The caller should not rely on the specific numbers assigned to any of
    these values as they may change from one processor to the next.

    Not all ports are available on all devices.  Refer to the specific
    device data sheet to determine which ports are supported.
*/
#define    GPIO_PORT_A  (0U)
#define    GPIO_PORT_B  (1U)
#define    GPIO_PORT_C  (2U)
typedef uint32_t GPIO_PORT;

// *****************************************************************************
/* GPIO Port Pins

  Summary:
    Identifies the available GPIO port pins.

  Description:
    This enumeration identifies the available GPIO port pins.

  Remarks:
    The caller should not rely on the specific numbers assigned to any of
    these values as they may change from one processor to the next.

    Not all pins are available on all devices.  Refer to the specific
    device data sheet to determine which pins are supported.
*/
#define    GPIO_PIN_RA0  (0U)
#define    GPIO_PIN_RA1  (1U)
#define    GPIO_PIN_RA2  (2U)
#define    GPIO_PIN_RA3  (3U)
#define    GPIO_PIN_RA4  (4U)
#define    GPIO_PIN_RA7  (7U)
#define    GPIO_PIN_RA8  (8U)
#define    GPIO_PIN_RA9  (9U)
#define    GPIO_PIN_RA10  (10U)
#define    GPIO_PIN_RB0  (16U)
#define    GPIO_PIN_RB1  (17U)
#define    GPIO_PIN_RB2  (18U)
#define    GPIO_PIN_RB3  (19U)
#define    GPIO_PIN_RB4  (20U)
#define    GPIO_PIN_RB5  (21U)
#define    GPIO_PIN_RB7  (23U)
#define    GPIO_PIN_RB8  (24U)
#define    GPIO_PIN_RB9  (25U)
#define    GPIO_PIN_RB10  (26U)
#define    GPIO_PIN_RB11  (27U)
#define    GPIO_PIN_RB13  (29U)
#define    GPIO_PIN_RB14  (30U)
#define    GPIO_PIN_RB15  (31U)
#define    GPIO_PIN_RC0  (32U)
#define    GPIO_PIN_RC1  (33U)
#define    GPIO_PIN_RC2  (34U)
#define    GPIO_PIN_RC3  (35U)
#define    GPIO_PIN_RC4  (36U)
#define    GPIO_PIN_RC5  (37U)
#define    GPIO_PIN_RC6  (38U)
#define    GPIO_PIN_RC7  (39U)
#define    GPIO_PIN_RC8  (40U)
#define    GPIO_PIN_RC9  (41U)

    /* This element should not be used in any of the GPIO APIs.
       It will be used by other modules or application to denote that none of the GPIO Pin is used */
#define    GPIO_PIN_NONE    (-1)

typedef uint32_t GPIO_PIN;

typedef  void (*GPIO_PIN_CALLBACK) ( GPIO_PIN pin, uintptr_t context);

void GPIO_Initialize(void);

// *****************************************************************************
// *****************************************************************************
// Section: GPIO Functions which operates on multiple pins of a port
// *****************************************************************************
// *****************************************************************************

uint32_t GPIO_PortRead(GPIO_PORT port);

void GPIO_PortWrite(GPIO_PORT port, uint32_t mask, uint32_t value);

uint32_t GPIO_PortLatchRead ( GPIO_PORT port );

void GPIO_PortSet(GPIO_PORT port, uint32_t mask);

void GPIO_PortClear(GPIO_PORT port, uint32_t mask);

void GPIO_PortToggle(GPIO_PORT port, uint32_t mask);

void GPIO_PortInputEnable(GPIO_PORT port, uint32_t mask);

void GPIO_PortOutputEnable(GPIO_PORT port, uint32_t mask);

void GPIO_PortInterruptEnable(GPIO_PORT port, uint32_t mask);

void GPIO_PortInterruptDisable(GPIO_PORT port, uint32_t mask);

// *****************************************************************************
// *****************************************************************************
// Section: Local Data types and Prototypes
// *****************************************************************************
// *****************************************************************************

typedef struct {

    /* target pin */
    GPIO_PIN                 pin;

    /* Callback for event on target pin*/
    GPIO_PIN_CALLBACK        callback;

    /* Callback Context */
    uintptr_t               context;

} GPIO_PIN_CALLBACK_OBJ;

// *****************************************************************************
// *****************************************************************************
// Section: GPIO Functions which operates on one pin at a time
// *****************************************************************************
// *****************************************************************************

static inline void GPIO_PinWrite(GPIO_PIN pin, bool value)
{
    GPIO_PortWrite((GPIO_PORT)(pin>>4), (uint32_t)(0x1) << (pin & 0xFU), (uint32_t)(value) << (pin & 0xFU));
}

static inline bool GPIO_PinRead(GPIO_PIN pin)
{
    return (bool)(((GPIO_PortRead((GPIO_PORT)(pin>>4))) >> (pin & 0xFU)) & 0x1U);
}

static inline bool GPIO_PinLatchRead(GPIO_PIN pin)
{
    return (bool)((GPIO_PortLatchRead((GPIO_PORT)(pin>>4)) >> (pin & 0xFU)) & 0x1U);
}

static inline void GPIO_PinToggle(GPIO_PIN pin)
{
    GPIO_PortToggle((GPIO_PORT)(pin>>4), 0x1UL << (pin & 0xFU));
}

static inline void GPIO_PinSet(GPIO_PIN pin)
{
    GPIO_PortSet((GPIO_PORT)(pin>>4), 0x1UL << (pin & 0xFU));
}

static inline void GPIO_PinClear(GPIO_PIN pin)
{
    GPIO_PortClear((GPIO_PORT)(pin>>4), 0x1UL << (pin & 0xFU));
}

static inline void GPIO_PinInputEnable(GPIO_PIN pin)
{
    GPIO_PortInputEnable((GPIO_PORT)(pin>>4), 0x1UL << (pin & 0xFU));
}

static inline void GPIO_PinOutputEnable(GPIO_PIN pin)
{
    GPIO_PortOutputEnable((GPIO_PORT)(pin>>4), 0x1UL << (pin & 0xFU));
}

static inline void GPIO_PinInterruptEnable(GPIO_PIN pin)
{
    GPIO_PortInterruptEnable((GPIO_PORT)(pin>>4), 0x1UL << (pin & 0xFU));
}

static inline void GPIO_PinInterruptDisable(GPIO_PIN pin)
{
    GPIO_PortInterruptDisable((GPIO_PORT)(pin>>4), 0x1UL << (pin & 0xFU));
}

bool GPIO_PinInterruptCallbackRegister(
    GPIO_PIN pin,
    const   GPIO_PIN_CALLBACK callback,
    uintptr_t context
);

// DOM-IGNORE-BEGIN
#ifdef __cplusplus  // Provide C++ Compatibility

    }

#endif
// DOM-IGNORE-END
#endif // PLIB_GPIO_H
