/// @file pic24.h
/// @authors k. headley
/// @date 11 aug 2017

/// PIC24 peripheral 

/// @sa doxygen-examples.c for more examples of Doxygen markup

/// Terms of use
/// Copyright Information
/// Copyright 2002-2019 MBARI
/// Monterey Bay Aquarium Research Institute, all rights reserved.
/// Terms of Use
/// This program is free software; you can redistribute it and/or modify
/// it under the terms of the GNU General Public License as published by
/// the Free Software Foundation; either version 3 of the License, or
/// (at your option) any later version. You can access the GPLv3 license at
/// http:/// www.gnu.org/licenses/gpl-3.0.html
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
/// GNU General Public License for more details
/// (http:/// www.gnu.org/licenses/gpl-3.0.html)
/// MBARI provides the documentation and software code "as is", with no warranty,
/// express or implied, as to the software, title, non-infringement of third party
/// rights, merchantability, or fitness for any particular purpose, the accuracy of
/// the code, or the performance or results which you may obtain from its use. You
/// assume the entire risk associated with use of the code, and you agree to be
/// responsible for the entire cost of repair or servicing of the program with
/// which you are using the code.
/// In no event shall MBARI be liable for any damages, whether general, special,
/// incidental or consequential damages, arising out of your use of the software,
/// including, but not limited to, the loss or corruption of your data or damages
/// of any kind resulting from use of the software, any prohibited use, or your
/// inability to use the software. You agree to defend, indemnify and hold harmless
/// MBARI and its officers, directors, and employees against any claim, loss,
/// liability or expense, including attorneys' fees, resulting from loss of or
/// damage to property or the injury to or death of any person arising out of the
/// use of the software.
/// The MBARI software is provided without obligation on the part of the
/// Monterey Bay Aquarium Research Institute to assist in its use, correction,
/// modification, or enhancement.
/// MBARI assumes no responsibility or liability for any third party and/or
/// commercial software required for the database or applications. Licensee agrees
/// to obtain and maintain valid licenses for any additional third party software
/// required.

/// Always do this
#ifndef CWG_PIC24_H
#define CWG_PIC24_H

/// Includes 
#include <stdint.h>
#include "GenericTypeDefs.h"
//#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/system.h"
/////previously in mcc.h (deprecated for system.h)
#include <stdint.h>
#include <stdbool.h>
#include "mcc_generated_files/clock.h"
#include "mcc_generated_files/pin_manager.h"

#include "mcc_generated_files/tmr1.h"
#include "mcc_generated_files/tmr2.h"
#include "mcc_generated_files/adc1.h"
#include "mcc_generated_files/ext_int.h"
#include "mcc_generated_files/interrupt_manager.h"
#include "mcc_generated_files/traps.h"
#include "mcc_generated_files/uart3.h"
#include "mcc_generated_files/uart1.h"
#include "mcc_generated_files/uart2.h"
#include "mcc_generated_files/spi1.h"
/////

#include "cwg-shared.h"
#include "cwgsys.h"
/// Macros

/// @def XTFREQ
/// @brief on-board crystal frequency
/// nominal 4 MHz
#define XTFREQ      _XTAL_FREQ 

/// @def PLLMODE
/// @brief on-chip PLL config
#define PLLMODE     1 

/// @def FOSC
/// @brief internal clock frequency
#define FOSC        (XTFREQ * PLLMODE)

/// @def FCY
/// @brief instruction cycle frequency
#define FCY         (FOSC / 2)

/// @def RTCFREQ
/// @brief TMR1 clock frequency
#define RTCFREQ     32768

/// @def BRG4_VAL(X)
/// @brief baud rate generator (div by 4)
/// @param x integer > 9600
/// with UART_BRGH_FOUR - must be used for rates > 9600
#define BRG4_VAL(X)    ((FCY/(X))/4)-1

/// @def BRG16_VAL
/// @brief baud rate generator (div by 16)
/// @param x integer 
/// with UART_BRGH_SIXTEEN 
#define BRG16_VAL(X)    ((FCY/(X))/16)-1

/// @def TICKS_PER_SEC
/// @brief TMR2 ticks per second
#define TICKS_PER_SEC   (100ul)  

/// @def MS_PER_TICK
/// @brief TMR2 milliseconds per tick
#define MS_PER_TICK     (10)    

/// @def TMR1_CKPSF
/// @brief TMR1 clock pre-scaler (float value)
/// The longest time that can be counted in the 16bit register is
/// 2^16/(FREQ/Prescaler), RTCFREQ = 2^15, so pre-scaler of 8 gives 16sec max
/// period, 10 second period is fine.
/// set via TxCONbits.TCKPS
#define TMR1_CKPSF (pow(8.0,(float)(T1CONbits.TCKPS)))

/// @def TMR1_CKPSU32
/// @brief TMR1 clock pre-scaler (uint32_t value)
#define TMR1_CKPSU32 ((uint32_t)TMR1_CKPSF)

/// @def TMR1_CKPSU32
/// @brief TMR1 clock pre-scaler (uint16_t value)
#define TMR1_CKPSU16 ((uint16_t)TMR1_CKPSF)

/// @var extern volatile uint16_t *p24_port_table[6]
/// @brief IO port register address table (used by IO macros)
extern volatile uint16_t *p24_port_table[6];
/// @var extern volatile uint16_t *p24_lat_table[6]
/// @brief IO latch register address table (used by IO macros)
extern volatile uint16_t *p24_lat_table[6];

/// @typedef enum p24_port_t
/// @brief IO port indices into p24_port_table
typedef enum{
    P24_PORTB=0,
    P24_PORTC,
    P24_PORTD,
    P24_PORTE,
    P24_PORTF,
    P24_PORTG
}p24_port_t;

/// @typedef enum p24_lat_t
/// @brief IO port indices into p24_lat_table
typedef enum{
    P24_LATB=0,
    P24_LATC,
    P24_LATD,
    P24_LATE,
    P24_LATF,
    P24_LATG
}p24_lat_t;

/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT0  0x0001
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT1  0x0002
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT2  0x0004
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT3  0x0008
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT4  0x0010
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT5  0x0020
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT6  0x0040
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT7  0x0080
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT8  0x0100
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT9  0x0200
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT10 0x0400
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT11 0x0800
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT12 0x1000
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT13 0x2000
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT14 0x4000
/// @def P24_BITn
/// @brief IO bit mask (for set/get macros)
#define P24_BIT15 0x8000

/// @def P24_READ_BIT
/// @brief read port bit (PORTx)
/// call pic24_init() before using P24 IO macros 
/// @param port p24_port_t enum
/// @param bit P24_BITn macro
#define P24_READ_BIT(port,bit)      ( *p24_port_table[port] & (unsigned int)bit )

/// @def P24_READ_BIT
/// @brief read latch bit (LATx)
/// call pic24_init() before using P24 IO macros 
/// @param lat p24_lat_t enum
/// @param bit P24_BITn macro
#define P24_READ_LATCH_BIT(lat,bit) ( *p24_lat_table[lat] & (unsigned int)bit )

/// @def P24_SET_BITS
/// @brief set latch bit(s) (LATx)
/// call pic24_init() before using P24 IO macros 
/// @param lat p24_lat_t enum
/// @param bit P24_BITn macro
#define P24_SET_BITS(lat,bits) { *p24_lat_table[lat] |= (unsigned int)bits; }
/// @def P24_CLR_BITS
/// @brief clear latch bit(s) (LATx)
/// call pic24_init() before using P24 IO macros 
/// @param lat p24_lat_t enum
/// @param bit P24_BITn macro
#define P24_CLR_BITS(lat,bits) { *p24_lat_table[lat] &= ~(unsigned int)bits; }
/// @def P24_TOG_BITS
/// @brief toggle latch bit(s) (LATx)
/// call pic24_init() before using P24 IO macros 
/// @param lat p24_lat_t enum
/// @param bit P24_BITn macro
#define P24_TOG_BITS(lat,bits) { *p24_lat_table[lat] ^= ~(unsigned int)bits; }

/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_0 0x0000
/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_1 0x0001
/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_2 0x0002
/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_3 0x0003
/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_4 0x0004
/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_5 0x0005
/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_6 0x0006
/// @def P24_INT_PRI_n
/// @brief interrupt priority
#define P24_INT_PRI_7 0x0007
/// @def P24_INT_PRI_MASK
/// @brief interrupt priority mask
#define P24_INT_PRI_MASK (~P24_INT_PRI_7)

/// @def P24_SET_T2
/// @brief set TMR2 counter value
/// @param x 
#define P24_SET_T2(x) (TMR2=x) //{TMR2=x;} 
/// @def P24_T2_CLR_INT_STATUS_BIT
/// @brief clear TMR2 interrupt status bit
#define P24_T2_CLR_INT_STATUS_BIT() (IFS0bits.T2IF = 0)
/// @def P24_T2_SET_INT_PRIORITY
/// @brief set TMR2 interrupt status bit
/// @param x value (0 or 1)
#define P24_T2_SET_INT_PRIORITY(x)  (IPC1bits.T2IP = (x==0?0:1)) 
/// @def P24_T2_INT_EN
/// @brief enable TMR2 interrupt
#define P24_T2_INT_EN()             (IEC0bits.T2IE = 1) 
/// @def P24_T2_INT_EN
/// @brief disable TMR2 interrupt
#define P24_T2_INT_DI()             (IEC0bits.T2IE = 0) 

/// @def P24_SET_T1
/// @brief set TMR1 counter value
/// @param x 
#define P24_SET_T1(x) (TMR1=x) 
#define P24_T1_OFF() (T1CONbits.TON = 0)
#define P24_T1_ON() (T1CONbits.TON = 1)
/// @def P24_T1_CLR_INT_STATUS_BIT
/// @brief clear TMR1 interrupt status bit
#define P24_T1_CLR_INT_STATUS_BIT() (IFS0bits.T1IF = 0)
/// @def P24_T1_SET_INT_PRIORITY
/// @brief set TMR1 interrupt status bit
/// @param x value (0 or 1)
#define P24_T1_SET_INT_PRIORITY(x)  (IPC0bits.T1IP = (x==0?0:1)) 
/// @def P24_T1_INT_EN
/// @brief enable TMR1 interrupt
#define P24_T1_INT_EN()             (IEC0bits.T1IE = 1) 
/// @def P24_T1_INT_EN
/// @brief disable TMR1 interrupt
#define P24_T1_INT_DI()             (IEC0bits.T1IE = 0) 

/// @def P24_SET_PR1
/// @brief set TMR1 counter value
/// @param x 
#define P24_SET_PR1(x) (PR1=x) 
#define P24_PR1_DFL 0x5000

/// @def P24_T1_PERIOD2MSEC
/// @brief  get TMR1 period using PR1 reg
/// casts/order/modifiers matter:
/// change with care
#define P24_T1_PR1_MSEC() ((1000ul * (uint16_t)PR1 * TMR1_CKPSU32)/RTCFREQ)
#define P24_T1_TMR1_MSEC() ((1000ul * (uint16_t)TMR1 * TMR1_CKPSU32)/RTCFREQ)

/// @def P24_PM_GOTO_IDLE_MODE
/// @brief go to IDLE mode (sleep)
#define P24_PM_GOTO_IDLE_MODE() asm ( " PWRSAV #1"  )

/// @def P24_SPI1_IS_EN
/// @brief true (1) if SPI1 enabled
#define P24_SPI1_IS_EN()        (SPI1CON1Lbits.SPIEN)
/// @def P24_SPI1_EN
/// @brief enable SPI1
#define P24_SPI1_EN()           (SPI1CON1Lbits.SPIEN=1)
/// @def P24_SPI1_DIS
/// @brief disable SPI1
#define P24_SPI1_DIS()          (SPI1CON1Lbits.SPIEN=0)
/// @def P24_SPI1_BUF
/// @brief SPI1 buffer (lower byte)
#define P24_SPI1_BUF            SPI1BUFL
/// @def P24_SPI1_SET_CON1
/// @brief set SPI1 control register
/// @param x uint16_t
#define P24_SPI1_SET_CON1(x)    (SPI1CON1L=x)
/// @def P24_SPI1_SET_CON2
/// @brief set SPI1 control register
/// @param x uint16_t
#define P24_SPI1_SET_CON2(x)    (SPI1CON2L=x)
/// @def P24_SPI1_SET_STAT
/// @brief set SPI1 STAT register
/// @param x uint16_t
#define P24_SPI1_SET_STAT(x)    (SPI1STATL=x)
/// @def P24_SPI1_SET_BRGL
/// @brief set SPI1 BRG register
/// @param x uint16_t
#define P24_SPI1_SET_BRGL(x)    (SPI1BRGL=x)
/// @def P24_SPI1_RX_BUF_FULL
/// @brief true if SPI1 RX buffer full
#define P24_SPI1_RX_BUF_FULL()  (SPI1STATLbits.SPIRBF)
/// @def P24_SPI1_TX_BUF_FULL
/// @brief true if SPI1 TX buffer full
#define P24_SPI1_TX_BUF_FULL()  (SPI1STATLbits.SPITBF)
/// @def P24_SPI1_RX_BUF_EMPTY
/// @brief true if SPI1 RX buffer empty
#define P24_SPI1_RX_BUF_EMPTY() (SPI1STATLbits.SPIRBE)
/// @def P24_SPI1_TX_BUF_EMPTY
/// @brief true if SPI1 TX buffer empty
#define P24_SPI1_TX_BUF_EMPTY() (SPI1STATLbits.SPITBE)
/// @def P24_SPI1_WRITE
/// @brief write byte to SPI1
/// @param pb byte pointer (byte*)
#define P24_SPI1_WRITE(pb)      (SPI1BUFL = *((uint8_t*)pb))
/// @def P24_SPI1_READ
/// @brief read byte from SPI1
/// @param pb byte pointer (byte*)
#define P24_SPI1_READ(pb)       (*((uint8_t*)pb) = SPI1BUFL) 
/// @def P24_SPI1_EXCHANGE
/// @brief write/read byte from SPI1
/// @param pb byte pointer tx (byte*)
#define P24_SPI1_EXCHANGE(pbtx) SPI1_Exchange8bit(pbtx)         
#define P24_SPI_MSTEN 0x0020
#define P24_SPI_SPIEN 0x8000

/// @def P24_INT0_CLR_INT_STATUS_BIT
/// @brief clear external INT0 status bit
#define P24_INT0_CLR_INT_STATUS_BIT() (IFS0bits.INT0IF=0)

/// @def P24_U1_TX_INT_EN
/// @brief UARTn TX interrupt enable
#define P24_U1_TX_INT_EN() (IEC0bits.U1TXIE = 1)
/// @def P24_U2_TX_INT_EN
/// @brief UARTn TX interrupt enable
#define P24_U2_TX_INT_EN() (IEC1bits.U2TXIE = 1)
/// @def P24_U3_TX_INT_EN
/// @brief UARTn TX interrupt enable
#define P24_U3_TX_INT_EN() (IEC5bits.U3TXIE = 1)
/// @def P24_U1_TX_INT_DI
/// @brief UARTn TX interrupt disable
#define P24_U1_TX_INT_DI() (IEC0bits.U1TXIE = 0)
/// @def P24_U2_TX_INT_DI
/// @brief UARTn TX interrupt disable
#define P24_U2_TX_INT_DI() (IEC1bits.U2TXIE = 0)
/// @def P24_U3_TX_INT_DI
/// @brief UARTn TX interrupt disable
#define P24_U3_TX_INT_DI() (IEC5bits.U3TXIE = 0)

/// @def P24_U1_RX_INT_EN
/// @brief UARTn RX interrupt enable
#define P24_U1_RX_INT_EN() (IEC0bits.U1RXIE = 1)
/// @def P24_U2_RX_INT_EN
/// @brief UARTn RX interrupt enable
#define P24_U2_RX_INT_EN() (IEC1bits.U2RXIE = 1)
/// @def P24_U3_RX_INT_EN
/// @brief UARTn RX interrupt enable
#define P24_U3_RX_INT_EN() (IEC5bits.U3RXIE = 1)
/// @def P24_U1_RX_INT_DI
/// @brief UARTn RX interrupt disable
#define P24_U1_RX_INT_DI() (IEC0bits.U1RXIE = 0)
/// @def P24_U2_RX_INT_DI
/// @brief UARTn RX interrupt disable
#define P24_U2_RX_INT_DI() (IEC1bits.U2RXIE = 0)
/// @def P24_U3_RX_INT_DI
/// @brief UARTn RX interrupt disable
#define P24_U3_RX_INT_DI() (IEC5bits.U3RXIE = 0)

/// @def P24_U1_RX_INT_CLR_STAT
/// @brief UARTn clear interrupt status bit
#define P24_U1_RX_INT_CLR_STAT() (IFS0bits.U1RXIF = 0)
/// @def P24_U1_TX_INT_CLR_STAT
/// @brief UARTn clear interrupt status bit
#define P24_U1_TX_INT_CLR_STAT() (IFS0bits.U1TXIF = 0)
/// @def P24_U2_RX_INT_CLR_STAT
/// @brief UARTn clear interrupt status bit
#define P24_U2_RX_INT_CLR_STAT() (IFS1bits.U2RXIF = 0)
/// @def P24_U2_TX_INT_CLR_STAT
/// @brief UARTn clear interrupt status bit
#define P24_U2_TX_INT_CLR_STAT() (IFS1bits.U2TXIF = 0)
/// @def P24_U3_RX_INT_CLR_STAT
/// @brief UARTn clear interrupt status bit
#define P24_U3_RX_INT_CLR_STAT() (IFS5bits.U3RXIF = 0)
/// @def P24_U3_TX_INT_CLR_STAT
/// @brief UARTn clear interrupt status bit
#define P24_U3_TX_INT_CLR_STAT() (IFS5bits.U3TXIF = 0)

/// @def P24_U1_EN
/// @brief UARTn enable
#define P24_U1_EN() (U1MODEbits.UARTEN=1)
/// @def P24_U2_EN
/// @brief UARTn enable
#define P24_U2_EN() (U2MODEbits.UARTEN=1)
/// @def P24_U3_EN
/// @brief UARTn enable
#define P24_U3_EN() (U3MODEbits.UARTEN=1)

/// Type Definitions

/// Exports

#ifdef __cplusplus
extern "C" {
#endif
    /// @fn void enterCriticalSection( void )
    /// @brief disable interrupts before entering critical section
    /// @return none
    void enterCriticalSection( void );

    /// @fn void exitCriticalSection( void )
    /// @brief enable interrupts after exiting critical section
    /// @return none
    void exitCriticalSection( void );
    
    /// @fn void pic24_init(void)
    /// @brief extend/override MCC initialization
    /// @return none
    void pic24_init(void);

#ifdef __cplusplus
}
#endif

#endif /// THIS_FILE