/**************************************************************************
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 08:30:41 -0700 (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
**************************************************************************/
