/**************************************************************************
MODULE:    MCOP
CONTAINS:  MicroCANopen Plus implementation
COPYRIGHT: (c) Embedded Systems Academy (EmSA) 2002-2019
           All rights reserved. www.em-sa.com/nxp
DISCLAIM:  Read and understand our disclaimer before using this code!
           www.esacademy.com/disclaim.htm
           This software was written in accordance to the guidelines at
           www.esacademy.com/software/softwarestyleguide.pdf
LICENSE:   THIS IS THE NXP SDK VERSION OF MICROCANOPEN PLUS
           Licensed under a modified BSD License. See LICENSE.INFO
           file in the project root for full license information.
VERSION:   7.01, EmSA 02-APR-20
           $LastChangedDate: 2020-04-02 17:30:41 +0200 (Thu, 02 Apr 2020) $
           $LastChangedRevision: 4909 $
***************************************************************************/

#ifndef _MCOP_H
#define _MCOP_H

#ifdef __cplusplus
extern "C" {
#endif

#include "mco.h"

/**************************************************************************
Defines for SLEEP modes
**************************************************************************/
#if USE_SLEEP
#define SLEEP_MASTER_QUERY_OBJECTION 0x01
#define SLEEP_SLAVE_SLEEP_OBJECTION  0x81
#define SLEEP_MASTER_SET_SLEEP       0x02
#if USE_LSS_SLAVE
#define SLEEP_WAKEUP 0x81
#else
#define SLEEP_WAKEUP 0x82
#endif
#define SLEEP_SLAVE_REQUEST 0x03
#define SLEEP_REASON_NONE   0xFE
#endif // USE_SLEEP

#if USE_EMCY
// This structure holds all emergency configuration
typedef struct
{
    CAN_MSG emcy_msg;
    uint16_t emcy_inhibit;   // Emergency inhibit time in ms
    uint16_t emcy_timestamp; // Timestamp of next allowed emergency
#if ERROR_FIELD_SIZE > 0
    uint32_t Field[ERROR_FIELD_SIZE];
    uint8_t InPtr;
    uint8_t NrOfRec;
#endif
} EMCY_CONFIG; // emergency handling data record
#endif

#if (NR_OF_HB_CONSUMER > 0)
// This structure holds all node specific configuration
typedef struct
{
    uint16_t time;       // Heartbeat Consumer time in ms
    uint16_t timestamp;  // Timestamp of last heartbeat consumed
    uint16_t can_id;     // CAN ID to monitor 0x700 + node ID
    HBCONS_STATE status; // satte of this consumer: off, init, active, lost
} HBCONS_CONFIG;
#endif // (NR_OF_HB_CONSUMER > 0)

/**************************************************************************
DOES:    This function reads data from the process image and copies it
         to an OUTPUT location
RETURNS: Number of bytes that were copied
**************************************************************************/
uint8_t MCO_ReadProcessData(uint8_t MEM_PROC *pDest, // Destination pointer
                            uint8_t length,          // Number of bytes to copy
                            uint16_t offset          // Offset of source data in process image
);

/**************************************************************************
DOES:    This function writes data from an INPUT location to the process
         image
RETURNS: Number of bytes that were copied
**************************************************************************/
uint8_t MCO_WriteProcessData(uint16_t offset,       // Offset of destination data in process image
                             uint8_t length,        // Number of bytes to copy
                             uint8_t MEM_PROC *pSrc // Source pointer
);

#if USE_EMCY
/**************************************************************************
DOES:    Transmits an Emergency Message
RETURNS: 1 if message was transmitted, 0 if transmit queue is full
**************************************************************************/
uint8_t MCOP_PushEMCY(uint16_t emcy_code, // 16 bit error code
                      uint8_t em_1,       // 5 byte manufacturer specific error code
                      uint8_t em_2,
                      uint8_t em_3,
                      uint8_t em_4,
                      uint8_t em_5);

#if ERROR_FIELD_SIZE > 0
#endif
/**************************************************************************
DOES:    This function clears all entries of the error history [1003h]
RETURNS: Nothing
**************************************************************************/
void MCOP_ErrField_Flush(void);

/**************************************************************************
DOES:    This function adds an entry to the error history [1003h]
RETURNS: Nothing
**************************************************************************/
void MCOP_ErrField_Add(uint32_t err_value // the 32bit error code used in the last EMCY
);

/**************************************************************************
DOES:    This function retrieves an entry from the error history [1003h]
         based on the subindex of [1003h]
RETURNS: 32bit error code stored at a subindex
**************************************************************************/
uint32_t MCOP_ErrField_Get(uint8_t subindex // Subindex number of [1003h]
);
#endif

#if (MGR_MONITOR_ALL_NODES == 0)
/* Device version, for SELECTED heartbeats, Manager uses comgr.h*/
#if (NR_OF_HB_CONSUMER > 0)
/**************************************************************************
DOES:    Initializes Heartbeat Consumer
GLOBALS: Inits gHBCons[consumer_channel-1]
**************************************************************************/
void MCOP_InitHBConsumer(uint8_t consumer_channel, // HB Consumer channel
                         uint8_t node_id,          // Node ID to monitor
                         uint16_t hb_time          // Timeout ot use (in ms)
);

/**************************************************************************
DOES:    Checks if a message received contains a heartbeat to be consumed
GLOBALS: Updates gHBCons[consumer_channel-1]
RETURNS: one, if message received was a heartbeat monitored, else zero
**************************************************************************/
uint8_t MCOP_ConsumeHB(CAN_MSG MEM_FAR *pRxCAN // CAN message received
);

/**************************************************************************
DOES:    Checks if a heartbeat consumer timeout occured
RETURNS:
          HBCONS_OFF,    // Disabled
          HBCONS_INIT,   // Initialized, waiting for first 2 heartbeats
          HBCONS_ACTIVE, // Consumer active and OK
          HBCONS_LOST    // Heartbeat lost
**************************************************************************/
HBCONS_STATE MCOP_ProcessHBCheck(uint8_t consumer_channel);

/**************************************************************************
DOES:    Checks if a node ID is already used, needed for conformance test
RETURNS: TRUE, if node_id is already used
**************************************************************************/
uint8_t MCOP_IsHBMonitored(uint8_t channel, uint8_t node_id);
#endif // (NR_OF_HB_CONSUMER > 0)
#endif // ! MGR_MONITOR_ALL_NODES

#if USECB_NMTCHANGE
/**************************************************************************
DOES:    This function is called before a change to the NMT Slave state
         machine is applied. Values passed are one of the following:
         NMTSTATE_BOOT, NMTSTATE_STOP, NMTSTATE_OP or NMTSTATE_PREOP
RETURNS: nothing
**************************************************************************/
void MCOUSER_NMTChange(uint8_t NMTState);
#endif // USECB_NMTCHANGE

#if USECB_SDOREQ
/**************************************************************************
DOES:    This call-back function is called by the SDO Handler for unknown
         SDO Requests. This allows the application to add own, custom
         Object Dictionary entries. When using this call-back function,
         the function is responsible for generating the right response or
         abort. The function MCO_ReplyWith can be used to generate a
         response, the function MCO_SendSDOAbort to generate an abort.
RETURNS: 0 - An SDO Abort was generated by the call-back function
         1 - An SDO Response was generated by the call-back function
         2 - The call-back function did not do anything with Request
**************************************************************************/
#if defined(USE_CANOPEN_FD) && (USE_CANOPEN_FD == 1)
uint8_t MCOUSER_SDORequest(CAN_MSG *USDO_Req);
#else
uint8_t MCOUSER_SDORequest(uint8_t SDO_Data[8]);
#endif
#endif // USECB_SDOREQ

/**************************************************************************
INTERNAL FUNCTIONS FROM MCO.C AND MCOP.C
**************************************************************************/

/**************************************************************************
DOES:    Generates an SDO Abort Response
RETURNS: nothing
**************************************************************************/
void MCO_SendSDOAbort(uint32_t ErrorCode // 4 byte SDO abort error code
);

/**************************************************************************
DOES:    Common exit routine for SDO_Handler.
         Send SDO response with variable length (1-4 bytes).
         Assumes that gTxCAN.ID, LEN and BUF[1-3] are already set.
         Requires data to be in little endian format.
RETURNS: 1 if response transmitted
**************************************************************************/
uint8_t MCO_ReplyWith(uint8_t *pDat, // pointer to sdo data
                      uint8_t len    // number of bytes of data in SDO
);

#if (NR_OF_RPDOS > 0) || (NR_OF_TPDOS > 0)
/**************************************************************************
DOES: Common exit routine for SDO_Handler.
      Send SDO response with write confirmation.
      Assumes that gTxSDO.ID, LEN and BUF[1-3] are already set
**************************************************************************/
void MCOP_WriteConfirm(void);

/**************************************************************************
DOES:    Handles incoming SDO Request for accesses to PDO Communication
         Parameters
RETURNS: 0: No action, SDO request is not for PDO Communication
         1: Access was made, SDO Response sent
         2: Wrong access, SDO Abort sent
GLOBALS: Various global variables with configuration information
**************************************************************************/
uint8_t SDO_HandlePDOComParam(uint8_t PDOType, // 0 for TPDO, 1 for RPDO
                              uint16_t index,  // OD index
                              uint8_t *pData   // pointer to SDO Request message
);
#endif // (NR_OF_RPDOS > 0) || (NR_OF_TPDOS > 0)

#if USE_DYNAMIC_PDO_MAPPING
/**************************************************************************
DOES:    Handles incoming SDO Request for accesses to PDO Mapping
         Parameters
RETURNS: 0: No action, SDO request is not for PDO Mapping
         1: Access was made, SDO Response sent
         2: Wrong access, SDO Abort sent
GLOBALS: Various global variables with configuration information
**************************************************************************/
uint8_t SDO_HandlePDOMapParam(uint8_t PDOType, // 0 for TPDO, 1 for RPDO
                              uint16_t index,  // OD index
                              uint8_t *pData   // pointer to SDO Request message
);
#endif

#if USE_SYNC
/**************************************************************************
DOES:    Processes reception of the SYNC message
RETURNS: 0: No messages processed
         Bit 0 set: SYNC TPDOs transmitted
         Bit 1 set: SYNC RPDOs received
**************************************************************************/
uint8_t MCOP_HandleSYNC(void);
#endif

/**************************************************************************
DOES:    Called when a TPDO needs to be transmitted
RETURNS: nothing
**************************************************************************/
void MCO_TransmitPDO(uint16_t PDONr // TPDO number to transmit
);

#if USE_INHIBIT_TIME
/**************************************************************************
DOES:    Called by application when a TPDO should be transmitted
RETURNS: nothing
**************************************************************************/
void MCO_TriggerTPDO(uint16_t TPDONr // TPDO number to transmit, as gTPDOConfig[] index
);
#endif

/**************************************************************************
DOES:    Checks if message received is guarding request
RETURNS: 0: message received is not guarding request
         1: guarding request received, response sent
**************************************************************************/
uint8_t MCOP_HandleGuarding(uint16_t can_id);

/**************************************************************************
DOES:    Function allowing application access to NMT changes
**************************************************************************/
void MCO_HandleNMTRequest(uint8_t NMTReq);

#if USE_STORE_PARAMETERS
/**************************************************************************
DOES:    Determines offset values for the the different regions
         in non-volatile memory.
         1. LSS + XOD binary eds checksum
         2. Save Parameters 1XXX
         3. Save Parameters 6XXX
         4. Save Parameters 2XXX
         5. First free space
RETURNS: Info on start offsets is copied into the string (5 values)
**************************************************************************/
void MCOSP_GetNVOLUsage(uint16_t pLoc[5] // info is written into this string
);

/**************************************************************************
DOES:    Checks the non-volatile memory for saved parameters and retrives
         them all
RETURNS: Nothing.
**************************************************************************/
void MCOSP_GetStoredParameters(void);

/**************************************************************************
DOES:    Implements the Store Parameters and Restore Parameters
         functionaility.
RETURNS: TRUE, if data was restored
         FALSE. if no valid data was found
**************************************************************************/
uint8_t MCOSP_StoreParameters(uint16_t idx, // set to 0x1010 for store, to 0x1011 for restore
                              uint8_t sub   // subindex
);

/**************************************************************************
DOES:    Initializes access to non-volatile memory.
**************************************************************************/
void NVOL_Init(void);

/**************************************************************************
DOES:    Reads a data byte from non-volatile memory.
         Must be provided by application driver.
NOTE:    The address is relative, an offset to NVOL_STORE_START
RETURNS: The data read from memory
**************************************************************************/
uint8_t NVOL_ReadByte(uint16_t address // location of byte in NVOL memory
);

/**************************************************************************
DOES:    Writes a data byte to non-volatile memory
         Must be provided by application driver.
NOTE:    The address is relative, an offset to NVOL_STORE_START
RETURNS: nothing
**************************************************************************/
void NVOL_WriteByte(uint16_t address, // location of byte in NVOL memory
                    uint8_t data);

/**************************************************************************
DOES:    Is called when a consecutive block of write cycles is complete.
         The driver may buffer the data from calls to NVOL_WriteByte with
         consecutive destination addresses in RAM and then write the entire
         buffer to non-volatile memory upon a call to this function.
**************************************************************************/
void NVOL_WriteComplete(void);
#endif // USE_STORE_PARAMETERS

#if USECB_ODSERIAL
/**************************************************************************
DOES:    Requests the device's serial number from the application.
         Must be passed in little endian format.
RETURNS: Serial number
**************************************************************************/
uint32_t MCOUSER_GetSerial(void);
#endif // USECB_ODSERIAL

#if USE_SLEEP
/**************************************************************************
DOES:    DRIVER LEVEL: Sets the processor into sleep or power down mode.
         Called when a sleep request was received and confirmed.
         Wakeup MUST be through a reset.
**************************************************************************/
void MCOHW_Sleep(void);

/*******************************************************************************
DOES:    APPLICATION LEVEL: Call back function for sleep/wakeup messages
         received as specified in CiA447 V2.
RETURNS: nothing
*******************************************************************************/
void MCOUSER_Sleep(uint8_t node,    // node ID of the node who sent the message
                   uint8_t command, // command byte of the message
                   uint8_t reason   // reason byte of the message
);

/*******************************************************************************
DOES:    Function to transmit wakeup/sleep messages as defined by CiA 447 V2
         SLEEP_MASTER_QUERY_OBJECTION 0x01
         SLEEP_SLAVE_SLEEP_OBJECTION 0x81
         SLEEP_MASTER_SET_SLEEP 0x02
         SLEEP_WAKEUP 0x82
         SLEEP_SLAVE_REQUEST 0x03
         SLEEP_REASON_NONE 0xFE
RETURNS: TRUE, if message was succesfully queued
*******************************************************************************/
uint8_t MCOP_TransmitWakeupSleep(uint8_t statcmd, uint8_t reason);
#endif // USE_SLEEP

#ifdef __cplusplus
}
#endif

#endif // _MCOP_H
/**************************************************************************
END OF FILE
**************************************************************************/
