MCUXpresso_MIMXRT1021xxxxx/middleware/canopen/mco/mco.h
2022-08-23 23:00:33 +08:00

1320 lines
60 KiB
C

/**************************************************************************
MODULE: MCO
CONTAINS: Main MicroCANopen implementation
COPYRIGHT: (c) Embedded Systems Academy (EmSA) 2002-2020
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.10, ESA 20-SEP-02
$LastChangedDate: 2020-09-14 15:26:54 +0200 (Mon, 14 Sep 2020) $
$LastChangedRevision: 5045 $
***************************************************************************/
#ifndef _MCO_H
#define _MCO_H
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************
Version Information, here V7.10
**************************************************************************/
#define _MCOPVERSION_ 7
#define _MCOSUBPVERSION_ 10
/**************************************************************************
CANopen FD Base Specification Information, here
CiA 1301 Part 0, Sub-part 0, Version 1, Sub-version 0, Class 0
**************************************************************************/
#define COFD_BASE_SPEC 0x51500100ul
// The following configuration files need to be supplied by the application
#include "nodecfg.h"
#include "mco_types.h"
#include "procimg.h"
/**************************************************************************
ENSURE THAT IN REGARDS TO OPTIMIZATION THE DEFAULT CONFIGURATION IS USED,
IF NOT SELECTED OTHERWISE in nodecfg.h
**************************************************************************/
#if (ENFORCE_DEFAULT_CONFIGURATION == 1)
// 1 or more TPDOs use the event timer
#define USE_EVENT_TIME 1
// 1 or more TPDOs are change-of-state and use the inhibit timer
#define USE_INHIBIT_TIME 1
// 1 or more PDOs use the SYNC signal
#define USE_SYNC 1
// 1 to allow PDO mapping to be configurable
#ifndef USE_DYNAMIC_PDO_MAPPING
#define USE_DYNAMIC_PDO_MAPPING 0
#endif
// Do not use static PDO comunication parameters
#define USE_STATIC_PDO 0
// Heartbeat consumer is dynamic / configurable
#define DYNAMIC_HB_CONSUMER 1
// Use MicroCANopen Plus functionality
#define USE_MCOP 1
// Produce emergencies when required
#define USE_EMCY 1
// Size of error field history [1003h]
#define ERROR_FIELD_SIZE 4
// Support segmented SDOs
#define USE_EXTENDED_SDO 1
// Do not use Node Guarding
#define USE_NODE_GUARDING 0
// If enabled, the call-back function MCOUSER_SDORequest() is called every
// time the CANopen stack receives an SDO Request that it cannot handle
#define USECB_SDOREQ 0
// If enabled, use extended call backs MCOUSER_XSDOInitWrite()
// and MCOUSER_XSDOWriteSegment() to enable custom segmented SDO handling
// NOTE: This requires a complete custom SDO handler!
#define USE_XSDOCB_WRITE 0
// Custom SDO channel handling
#define USE_CiA447 0
#define USE_SDOMESH 0
#endif
// Manager functionality, if not defined, disable
#ifndef MGR_MONITOR_ALL_NODES
#define MGR_MONITOR_ALL_NODES 0
#endif
/**************************************************************************
CANopen NMT (Network Management) Master Msg and Slave States
**************************************************************************/
#define NMTMSG_OP 1
#define NMTMSG_STOP 2
#define NMTMSG_PREOP 128
#define NMTMSG_RESETAPP 129
#define NMTMSG_RESETCOM 130
#define NMTSTATE_BOOT 0
#define NMTSTATE_STOP 4
#define NMTSTATE_OP 5
#define NMTSTATE_PREOP 127
/**************************************************************************
EMCY error codes used when calling MCOP_PushEMCY
**************************************************************************/
#define EMCY_NO_ERROR 0x0000 // No Error / Reset
#define EMCY_INTERN_SW 0x6100 // Internal software - generic (fatal error)
#define EMCY_DATA_SET 0x6300 // Data set - generic (fatal error)
#define EMCY_HB_ERR 0x8130 // Life guard error or heartbeat error
#define EMCY_PROT_ERR 0x8200 // Protocol error - generic
#define EMCY_PDO_LEN 0x8210 // PDO not processed due to length error
#define EMCY_SYNC_LEN 0x8240 // SYNC not processed due to length error
// EMCY active system bits
#define EMCYSBIT_PROT (1 << 1) // Protocol
#define EMCYSBIT_SYNCLEN (1 << 2) // SYNC received has wrong lenth
/**************************************************************************
CANopen FD error status bits
**************************************************************************/
#define ERST_PRIO(prio) (prio & 0x07) // Priority, 0=highest, 7=lowest
#define ERST_CLASS_NREC 0x08 // Error class, 0=recoverable, 1=non-recoverable
#define ERST_STATE_OCC 0x10 // Error state, 0=removed, 1=occurred
#define ERST_STATE_MOCC 0x20 // Error occurred multiple times
/**************************************************************************
Error codes used when calling MCOUSER_FatalError
**************************************************************************/
#define ERR_WARN 0x4000 // Warning only, continue execution
#define ERROFL_EMCY 0x4810 // Transmit buffer overflow, TPDO message lost
#define ERROFL_PDO 0x4820 // Transmit buffer overflow, TPDO message lost
#define ERROFL_SDO 0x4830 // Transmit buffer overflow, SDO message lost
#define ERROFL_HBT 0x4840 // Transmit buffer overflow, Heartbeat message lost
#define ERR_FATAL 0x8000 // Fatal error, should abort/reset
#define ERRFT_INIT 0x8010 // MCOHW Init failed
#define ERRFT_PARA 0x8011 // MCO essential parameters error
#define ERRFT_RXFLTN 0x8021 // Out of CAN receive filters, NMT
#define ERRFT_RXFLTP 0x8022 // Out of CAN receive filters, PDO
#define ERRFT_RXFLTS 0x8023 // Out of CAN receive filters, SDO
#define ERRFT_IPP 0x8031 // Init PDO Parameters out of range
#define ERRFT_PIR 0x8032 // Process Image access out of range
#define ERRFT_TPDOR 0x8041 // Out of TPDOs
#define ERRFT_RPDOR 0x8042 // Out of RPDOs
#define ERRFT_RPMAP 0x8043 // Found no RPDO Mapping
/**************************************************************************
DEFINES FOR ACCESS TYPE TO OD ENRIES
Readable, Writable, Read-Mapable, Write-Mapable, Call-Back
**************************************************************************/
#define ODRD 0x10
#define ODWR 0x20
#define RMAP 0x40
#define WMAP 0x80
#define COFD 0x08 // flag for entry that is only used with CANopen FD
/**************************************************************************
MACROS FOR PLATFORM-ENDIANNESS-INDEPENDENT LITTLE-ENDIAN MEMORY ACCESS
**************************************************************************/
#define GEN_RD32(ptr) \
(((uint32_t)(*((uint8_t *)ptr + 3)) << 24) | ((uint32_t)(*((uint8_t *)ptr + 2) & 0xFF) << 16) | \
((uint32_t)(*((uint8_t *)ptr + 1) & 0xFF) << 8) | (uint32_t)(*((uint8_t *)ptr) & 0xFF))
#define GEN_RD24(ptr) \
(((uint32_t)(*((uint8_t *)ptr + 2) & 0xFF) << 16) | ((uint32_t)(*((uint8_t *)ptr + 1) & 0xFF) << 8) | \
(uint32_t)(*((uint8_t *)ptr) & 0xFF))
#define GEN_RD16(ptr) (((uint16_t)(*((uint8_t *)ptr + 1)) << 8) | (uint16_t)(*((uint8_t *)ptr) & 0xFF))
#define GEN_RD8(ptr) (*((uint8_t *)ptr) & 0xFF)
#define GEN_WR32(ptr, value) \
do \
{ \
*((uint8_t *)ptr + 3) = (uint8_t)(((uint32_t)(value) >> 24) & 0xFF); \
*((uint8_t *)ptr + 2) = (uint8_t)(((uint32_t)(value) >> 16) & 0xFF); \
*((uint8_t *)ptr + 1) = (uint8_t)(((uint32_t)(value) >> 8) & 0xFF); \
*((uint8_t *)ptr) = (uint8_t)((uint32_t)(value)&0xFF); \
} while (0)
#define GEN_WR24(ptr, value) \
do \
{ \
*((uint8_t *)ptr + 2) = (uint8_t)(((uint32_t)(value) >> 16) & 0xFF); \
*((uint8_t *)ptr + 1) = (uint8_t)(((uint32_t)(value) >> 8) & 0xFF); \
*((uint8_t *)ptr) = (uint8_t)((uint32_t)(value)&0xFF); \
} while (0)
#define GEN_WR16(ptr, value) \
do \
{ \
*((uint8_t *)ptr + 1) = (uint8_t)(((uint16_t)(value) >> 8) & 0xFF); \
*((uint8_t *)ptr) = (uint8_t)((uint16_t)(value)&0xFF); \
} while (0)
#define GEN_WR8(ptr, value) \
do \
{ \
*((uint8_t *)ptr) = (uint8_t)(value & 0xFF); \
} while (0)
/**************************************************************************
MACROS FOR OBJECT DICTIONARY ENTRIES
**************************************************************************/
#define GETBYTE(val, pos) (((val) >> (pos)) & 0xFF)
#define GETBYTES16(val) GETBYTE(val, 0), GETBYTE(val, 8)
#define GETBYTES32(val) GETBYTE(val, 0), GETBYTE(val, 8), GETBYTE(val, 16), GETBYTE(val, 24)
#define SDOREPLY(index, sub, len, val) 0x43 | ((4 - (len)) << 2), GETBYTES16(index), sub, GETBYTES32(val)
#define SDOREPLY4(index, sub, len, d1, d2, d3, d4) 0x43 | ((4 - (len)) << 2), GETBYTES16(index), sub, d1, d2, d3, d4
#define ODENTRY(index, sub, len, offset) \
{ \
GETBYTES16(index), sub, len, GETBYTES16(offset) \
}
#if USE_EXTENDED_SDO
#if USE_GENOD_PTR
#define ODGENTRYC(index, sub, acc, len, ptr) \
{ \
GETBYTES16(index), sub, acc, GETBYTES16(len), (uint8_t *)ptr \
}
#define ODGENTRYP(index, sub, acc, len, off) \
{ \
GETBYTES16(index), sub, acc, GETBYTES16(len), &(gProcImg[off]) \
}
#else
#define ODGENTRYP(index, sub, acc, len, off) \
{ \
GETBYTES16(index), sub, acc, GETBYTES16(len), GETBYTES16(off) \
}
#endif
#endif // USE_EXTENDED_SDO
// invalid process image offset
#define INVALID_PI_OFFSET 0xFFFF
/**************************************************************************
DO NOT USE THESE PIxxACC MACROS!
USE PI_READ AND PI_WRITE INSTEAD!
NEW VERSIONS SUPPORT RTOS, DATA CONSITENCY, SIMULATION
MACROS FOR PROCESS IMAGE ACCESS 8bit, 16bit and 32bit access
**************************************************************************/
/*
#define PI8ACC(offset) (gProcImg[offset])
#define PI16ACC(offset) (*((uint16_t *) &(gProcImg[offset])))
#define PI32ACC(offset) (*((uint32_t *) &(gProcImg[offset])))
*/
/**************************************************************************
CAN SETTINGS DEPENDING ON THE VERSION OF CAN USED
**************************************************************************/
// With CAN FD, there are up to 64 bytes per message, otherwise 8
#if defined(USE_CANOPEN_FD) && (USE_CANOPEN_FD == 1)
#define CAN_MAX_DATA_SIZE 64
#define EMCY_DATA_SIZE 20
#else
#define CAN_MAX_DATA_SIZE 8
#define EMCY_DATA_SIZE 8
#endif
/**************************************************************************
LIMITS FOR ESSENTIAL SETTINGS, PROJECT CAN OVERRIDE
**************************************************************************/
#if !defined(NODE_ID_MIN)
#define NODE_ID_MIN 1
#endif
#if !defined(NODE_ID_MAX)
#define NODE_ID_MAX 127
#endif
/**************************************************************************
MACROS FOR ACCESS TO INTERNAL VARIABLES SOMETIMES NEEDED BY APPLICATION
**************************************************************************/
#define MY_NODE_ID (gMCOConfig.Node_ID)
#define MY_NMT_STATE (gMCOConfig.heartbeat_msg.BUF[0])
/**************************************************************************
MACROS FOR CAN-ID DEFINITION
**************************************************************************/
#if CAN_ID_SIZE == 16
typedef uint16_t COBID_TYPE;
#define COBID_DISABLED 0x8000U
#define COBID_RTR 0x4000U
#define COBID_EXT 0x2000U
#define COBID_OPT_MASK 0xE000U
#define COBID_PDO_DEFAULT 0x0000U
#elif CAN_ID_SIZE == 32
typedef uint32_t COBID_TYPE;
#define COBID_DISABLED 0x80000000UL
#define COBID_RTR 0x40000000UL
#define COBID_EXT 0x20000000UL
#define COBID_OPT_MASK 0xE0000000UL
#define COBID_PDO_DEFAULT 0x00000000UL
#else
#error Only CAN_ID_SIZE 16 or 32 is possible
#endif
// CAN-ID used for NMT Master message
#define NMT_MASTER_ID 0
// CAN-ID for LSS reception (slave) or transmission (master)
#define LSS_MASTER_ID 2021ul
// CAN-ID for LSS transmission (slave) or reception (master)
#define LSS_SLAVE_ID 2020ul
/**************************************************************************
MACROS FOR CAN-ID USAGE
**************************************************************************/
#define IS_CANID_LSS_REQUEST(canid) ((canid) == LSS_MASTER_ID)
#define IS_CANID_LSS_RESPONSE(canid) (((canid) == LSS_SLAVE_ID) || (((canid) >= 0x07D0) && ((canid) < 0x07E0)))
#define IS_CAN_ID_MY_HB(canid) ((canid) == 0x700 + MY_NODE_ID)
#define IS_CANID_RESTRICTED(canid) \
(((canid) < 0x0080) || (((canid) > 0x0100) && ((canid) <= 0x0180)) || \
(((canid) > 0x0580) && ((canid) < 0x0600)) || (((canid) > 0x0600) && ((canid) < 0x0680)) || \
(((canid) >= 0x06E0) && ((canid) < 0x0700)) || (((canid) > 0x0700) && ((canid) < 0x0800)))
#if (USE_CiA447 == 1)
#define IS_NODE_ID_VALID(nodeid) ((nodeid >= 2) && (nodeid <= 16))
#define IS_CAN_ID_GWHB(canid) ((canid) == 0x701)
// SDO Transfers: Server = j, Client = i
// Request from client node i to server node j
// (0x240 + ((i-1) & 0xC) << 6) + (((i-1) & 0x03) << 4) + j-1)
// Response from server node j to client node i
// (0x1C0 + ((i-1) & 0xC) << 6) + (((i-1) & 0x03) << 4) + j-1)
#define IS_CAN_ID_EMERGENCY(canid) (((canid) >= 0x081) && ((canid) <= 0x090))
#define IS_CAN_ID_HEARTBEAT(canid) (((canid) >= 0x701) && ((canid) <= 0x710))
#define IS_CAN_ID_ISO_TP(canid) \
(((canid) == 0x251) || ((canid) == 0x262) || ((canid) == 0x273) || ((canid) == 0x344) || ((canid) == 0x355) || \
((canid) == 0x366) || ((canid) == 0x377) || ((canid) == 0x448) || ((canid) == 0x459) || ((canid) == 0x46A) || \
((canid) == 0x47B) || ((canid) == 0x54C) || ((canid) == 0x55D) || ((canid) == 0x56D) || ((canid) == 0x56E) || \
((canid) == 0x57F))
#define IS_CAN_ID_SDOREQUEST(canid) \
(((canid) == 0x600 + MY_NODE_ID) || \
(((canid) > 0x0240) && ((canid) < 0x0580) && (((canid)&0x00CF) == (0x0040 + MY_NODE_ID - 1))))
#define IS_CAN_ID_SDOREQUEST_TX(canid) \
(((canid) >= 0x0240) && ((canid) < 0x0580) && \
(((canid)&0x0730) == (((MY_NODE_ID - 1) & 0x0C) << 6) + (((MY_NODE_ID - 1) & 0x03) << 4)))
#define IS_CAN_ID_SDORESPONSE(canid) \
(((canid) > 0x01C0) && ((canid) < 0x04FF) && \
(((canid)&0x07F0) == 0x1C0 + (((MY_NODE_ID - 1) & 0x0C) << 6) + (((MY_NODE_ID - 1) & 0x03) << 4)))
#define IS_CAN_ID_SDORESPONSE_TX(canid) \
(((canid) == 0x580 + MY_NODE_ID) || (((canid) > 0x01C0) && ((canid) < 0x04FF) && (((canid)&0x00C0) == 0x0C0) && \
(((canid)&0x000F) == (MY_NODE_ID - 1))))
#define CAN_ID_SDORESPONSE_FROM_RXID(canid) ((canid)-0x80)
#define CAN_ID_SDOREQUEST(client_nodeid, server_nodeid) \
(0x240 + (((client_nodeid - 1) & 0x0C) << 6) + (((client_nodeid - 1) & 0x03) << 4) + server_nodeid - 1)
#define CAN_ID_SDORESPONSE(client_nodeid, server_nodeid) \
(0x1C0 + (((client_nodeid - 1) & 0x0C) << 6) + (((client_nodeid - 1) & 0x03) << 4) + server_nodeid - 1)
#define SDOSERVER(tx_canid) ( \
((tx_canid) == 0x580 + MY_NODE_ID) \
? (MY_NODE_ID-1) \
: ((((tx_canid)-0x100) >> 6) & 0x0C) + (((tx_canid) >> 4) & 0x03)) \
)
#define CAN_ID_PDO_CiA447(node) \
(0x40000180ul + (((uint16_t)((node - 1) & 7) << 7)) + (((uint16_t)((node - 1) & 8)) << 2))
#define IS_NODE_CiA301_CLIENT() (MY_NODE_ID == 1)
#define IS_CAN_ID_MINE(canid) \
(((canid) == 0x080 + MY_NODE_ID) || ((canid) == 0x580 + MY_NODE_ID) || (IS_CAN_ID_SDOREQUEST_TX((canid))) || \
(IS_CAN_ID_SDORESPONSE_TX((canid))) || ((canid) == CAN_ID_PDO_CiA447(MY_NODE_ID)))
#elif (USE_SDOMESH == 1)
#define IS_NODE_ID_VALID(nodeid) ((nodeid >= 1) && (nodeid <= 16))
#define IS_CAN_ID_EMERGENCY(canid) (((canid) >= 0x081) && ((canid) <= 0x0FF))
#define IS_CAN_ID_HEARTBEAT(canid) (((canid) >= 0x701) && ((canid) <= 0x77F))
#define IS_CAN_ID_SDOREQUEST(canid) ((((canid)&0x700) == 0x600) && (((canid)&0x00F) == (MY_NODE_ID - 1)))
#define IS_CAN_ID_SDORESPONSE(canid) \
(((MY_NODE_ID < 9) && (((canid)&0x700) == 0x500) && (((canid)&0x0F0) == ((MY_NODE_ID + 7) << 4))) || \
((MY_NODE_ID > 8) && (((canid)&0x700) == 0x100) && (((canid)&0x0F0) == ((MY_NODE_ID - 9) << 4))))
#define CAN_ID_SDORESPONSE_FROM_RXID(canid) \
(((((canid)&0x0F0) >> 4) < 8) ? (0x500 + (((((canid)&0x0F0) >> 4) + 8) << 4) + ((canid)&0xF)) : \
(0x100 + (((((canid)&0x0F0) >> 4) - 8) << 4) + ((canid)&0xF)))
#define CAN_ID_SDOREQUEST(client_nodeid, server_nodeid) \
(0x600 + (((client_nodeid - 1) & 0xF) << 4) + ((server_nodeid - 1) & 0xF))
#define CAN_ID_SDORESPONSE(client_nodeid, server_nodeid) \
((client_nodeid < 9) ? 0x500 + ((((client_nodeid - 1) & 0xF) + 8) << 4) + ((server_nodeid - 1) & 0xF) : \
0x100 + ((((client_nodeid - 1) & 0xF) - 8) << 4) + ((server_nodeid - 1) & 0xF))
#define SDOSERVER(tx_canid) \
(((gTxSDO.ID & 0x700) == 0x500) ? (((gTxSDO.ID & 0x0F0) >> 4) - 8) : (((gTxSDO.ID & 0x0F0) >> 4) + 8))
#define IS_NODE_CiA301_CLIENT() (TRUE)
#else // standard CANopen
#define IS_NODE_ID_VALID(node_id) ((node_id >= NODE_ID_MIN) && (node_id <= NODE_ID_MAX))
#define IS_CAN_ID_EMERGENCY(canid) (((canid) >= 0x081) && ((canid) <= 0x0FF))
#define IS_CAN_ID_HEARTBEAT(canid) (((canid) >= 0x701) && ((canid) <= 0x77F))
#if defined(USE_CANOPEN_FD) && (USE_CANOPEN_FD == 1)
#define IS_CAN_ID_SDOREQUEST(canid) (((canid) >= 0x601) && ((canid) <= 0x67F))
#define IS_CAN_ID_SDORESPONSE(canid) (((canid) >= 0x581) && ((canid) <= 0x5FF))
#define CAN_ID_SDORESPONSE_FROM_RXID(canid) (0x580 + MY_NODE_ID)
#define CAN_ID_SDOREQUEST(client_nodeid, server_nodeid) (0x600 + client_nodeid)
#define CAN_ID_SDORESPONSE(client_nodeid, server_nodeid) (0x580 + server_nodeid)
#define SDOSERVER(tx_canid) 0
#else
#define IS_CAN_ID_SDOREQUEST(canid) ((canid) == 0x600 + MY_NODE_ID)
#define IS_CAN_ID_SDORESPONSE(canid) (((canid) >= 0x581) && ((canid) <= 0x5FF))
#define CAN_ID_SDORESPONSE_FROM_RXID(canid) ((canid)-0x80)
#define CAN_ID_SDOREQUEST(client_nodeid, server_nodeid) (0x600 + server_nodeid)
#define CAN_ID_SDORESPONSE(client_nodeid, server_nodeid) (0x580 + server_nodeid)
#define SDOSERVER(tx_canid) 0
#endif
#if MGR_MONITOR_ALL_NODES == 1
#define IS_NODE_CiA301_CLIENT() (TRUE)
#else
#define IS_NODE_CiA301_CLIENT() (FALSE)
#endif
#endif
/**************************************************************************
SDO ABORT MESSAGES
**************************************************************************/
#define SDO_ABORT_TOGGLE 0x05030000UL
#define SDO_ABORT_UNKNOWN_COMMAND 0x05040001UL
#define SDO_ABORT_INVALID_SEQ 0x05040003UL
#define SDO_ABORT_CRC 0x05040004UL
#define SDO_ABORT_UNSUPPORTED 0x06010000UL
#define SDO_ABORT_WRITEONLY 0x06010001UL
#define SDO_ABORT_READONLY 0x06010002UL
#define SDO_ABORT_NOT_EXISTS 0x06020000UL
#define SDO_ABORT_PARAMETER 0x06040043UL
#define SDO_ABORT_TYPEMISMATCH 0x06070010UL
#define SDO_ABORT_DATATOBIG 0x06070012UL
#define SDO_ABORT_UNKNOWNSUB 0x06090011UL
#define SDO_ABORT_VALUE_RANGE 0x06090030UL
#define SDO_ABORT_VALUE_HIGH 0x06090031UL
#define SDO_ABORT_VALUE_LOW 0x06090032UL
#define SDO_ABORT_GENERAL 0x08000000UL
#define SDO_ABORT_TRANSFER 0x08000020UL
#define SDO_ABORT_NOTRANSFERCTRL 0x08000021UL
#define SDO_ABORT_NOTMAPPED 0x06040041UL
#define SDO_ABORT_MAPLENGTH 0x06040042UL
#define SDO_ABORT_TIMEOUT 0x05040000UL
#define SDO_ABORT_NOTRANSFER 0x08040020UL
#define SDO_ABORT_NOMEM 0x05040005UL
/**************************************************************************
Status bits for function MCOHW_GetStatus
**************************************************************************/
#define HW_INIT 0x01
#define HW_CERR 0x02
#define HW_ERPA 0x04
#define HW_RXOR 0x08
#define HW_TXOR 0x10
#define HW_TXBSY 0x40
#define HW_BOFF 0x80
/**************************************************************************
Defines for LED control
**************************************************************************/
#if USE_LEDS
// LED Flash Patterns
// Flickering directly implemented in lss.c
#define LED_OFF 0
#define LED_ON 0xFF
#define LED_BLINK 0x7F
// Single, double, triple and quadruple flashes
#define LED_FLASH1 1
#define LED_FLASH2 2
#define LED_FLASH3 3
#define LED_FLASH4 4
#endif // USE_LEDS
/**************************************************************************
Utility macro to print preprocessor define value with
#pragma message(VAR_NAME_VALUE(SOMEDEFINE))
**************************************************************************/
#define VALUE_TO_STRING(x) #x
#define VALUE(x) VALUE_TO_STRING(x)
#define VAR_NAME_VALUE(var) #var "=" VALUE(var)
/**************************************************************************
States for Heartbeat Consumer handling
**************************************************************************/
typedef enum
{
HBCONS_OFF, // Disabled
HBCONS_INIT, // Initialized, waiting for second heartbeat
HBCONS_ACTIVE, // Consumer active and OK
HBCONS_LOST, // Heartbeat lost
HBCONS_SLEEP // Device in sleep
} HBCONS_STATE;
/**************************************************************************
GLOBAL TYPE DEFINITIONS
**************************************************************************/
// Data structure for a single CAN message
typedef struct
{ // order optimized for allignment
uint8_t BUF[CAN_MAX_DATA_SIZE]; // Data buffer
COBID_TYPE ID; // Message Identifier
uint8_t LEN; // Data length (0-CAN_MAX_DATA_SIZE)
} CAN_MSG;
// This structure holds all node specific configuration
typedef struct
{
CAN_MSG heartbeat_msg; // Heartbeat message contents
uint16_t Baudrate; // Current baudrate in kbit
#if defined(USE_CANOPEN_FD) && (USE_CANOPEN_FD == 1)
uint16_t BRSBaudrate; // For CAN FD: Data (BRS) baudrate in kbit
#endif
uint16_t heartbeat_time; // Heartbeat time in ms
uint16_t heartbeat_timestamp; // Timestamp of last heartbeat
uint16_t last_fatal; // Last Fatal Error code
uint16_t last_rxtime; // Timestamp of last CAN receive
#if USE_SYNC
#if USE_SYNC_PRODUCER
uint32_t SYNC_cycle; // SYNC producer cycle time (OD 1006h)
#endif
COBID_TYPE SYNC_id; // CAN ID used for SYNC (OD 1005h)
uint8_t SYNC_cntovr; // Synchronous counter overflow (OD 1019h) 0=off
#endif
#if NR_OF_TPDOS > 255
uint16_t nrTPDOs;
#else
#if NR_OF_TPDOS > 0
uint16_t nrTPDOs;
#endif
#endif
#if NR_OF_RPDOS > 255
uint16_t nrRPDOs;
#else
#if NR_OF_RPDOS > 0
uint16_t nrRPDOs;
#endif
#endif
#if USE_LEDS
uint16_t LED_timestamp; // LED control timestamp
uint8_t LEDtoggle; // Toggler for blinking or flickering pattern
uint8_t LEDRun; // Current pattern on run led
uint8_t LEDcntR; // Current flash counter on run led
uint8_t LEDErr; // Current pattern on error led
uint8_t LEDcntE; // Current flash counter on error led
#endif // USE_LEDS
uint8_t Node_ID; // Current Node ID (1-126)
uint8_t error_code; // Bits: 0=RxQueue 1=TxQueue 3=CAN 7=first_op
uint8_t error_register; // Error regiter for OD entry [1001,00]
#if USE_NODE_GUARDING
uint8_t NGtoggle; // Toggle value for node guarding
#endif
uint8_t HWStatus; // CAN HW status
} MCO_CONFIG;
// Enumeration type for inhibit status
typedef enum
{
INHITIM_EXPIRED, // Inhibit timer not started or expired
INHITIM_RUNNING_NO_TRIGGER, // Inhibit timer started, not yet triggered for transmission
INHITIM_RUNNING_TRIGGERED // Transmit msg waiting for expiration of inhibit
} INHITIM_TYPE;
// This structure holds all the TPDO configuration data for one TPDO
typedef struct
{
CAN_MSG CANmsg; // Current/last CAN message to be transmitted
uint16_t offset; // Offest to application data in process image
uint16_t PDONr; // PDO number (1-512)
#if USE_EVENT_TIME
uint16_t event_time; // Event timer in ms (0 for COS only operation)
uint16_t event_timestamp; // If event timer is used, this is the
// timestamp for the next transmission
#endif
#if USE_INHIBIT_TIME
uint16_t inhibit_time; // Inhibit timer in ms (0 if COS not used)
uint16_t inhibit_timestamp; // If inhibit timer is used, this is the
// timestamp for the next transmission
INHITIM_TYPE inhibit_status; // Status of inhibit timer
#endif
#if USE_SYNC
uint8_t SYNCcnt; // SYNC counter for counting SYNC signals
uint8_t SYNCmatch; // If SYNC with counter is used, trigger on this match
#endif
uint8_t TType; // Transmission Type
} TPDO_CONFIG;
// This structure holds all the RPDO configuration data for one RPDO
typedef struct
{
#if USE_SYNC
uint8_t BUF[8]; // SYNC data buffer
#endif
COBID_TYPE CANID; // Message Identifier
uint16_t offset; // Pointer to destination of data
uint16_t PDONr; // PDO number (1-512)
uint8_t len; // Data length (0-8)
uint8_t TType; // Transmission Type
#if USECB_ODDATARECEIVED
uint16_t map; // offset to RPDO mapping in SDOResponseTable
#endif // USECB_ODDATARECEIVED
} RPDO_CONFIG;
/**************************************************************************
GLOBAL TYPES: Object Dictionary tables
**************************************************************************/
// This structure holds all data for one process data entry in the OD
typedef struct
{
uint8_t idx_lo; // Index of OD entry
uint8_t idx_hi;
uint8_t subidx; // Subindex of OD entry
uint8_t len; // Data length in bytes (1-4), plus bits ODRD, ODWR, RMAP/WMAP
uint8_t off_lo; // Offset to process data in process image
uint8_t off_hi;
} OD_PROCESS_DATA_ENTRY;
#if USE_EXTENDED_SDO
// This structure holds all data for generic entries into the OD
typedef struct
{
uint8_t idx_lo; // Index of OD entry
uint8_t idx_hi;
uint8_t subidx; // Subindex of OD entry
uint8_t access; // Bits ODRD, ODWR
uint8_t len_lo; // Length of data
uint8_t len_hi;
#if USE_GENOD_PTR
uint8_t *pDat;
#else
uint8_t off_lo; // Offset to process data in process image
uint8_t off_hi;
#endif
} OD_GENERIC_DATA_ENTRY;
#endif // USE_EXTENDED_SDO
#if defined(USE_CANOPEN_FD) && (USE_CANOPEN_FD == 1)
// defines for OD entry location
typedef enum
{
ODLOC_UNKNOWN,
ODLOC_SDOREPLY,
ODLOC_ODENTRY,
ODLOC_ODGENTRY
} ODLocationType;
#endif // USE_CANOPEN_FD
#if (INDEX_FOR_DIAGNOSTICS != 0)
/**************************************************************************
GLOBAL TYPES: Diagnostic Data Record
**************************************************************************/
typedef struct
{ // Subindexes provided at Index INDEX_FOR_DIAGNOSTICS
// 0: 22
// 1: Identification (hard coded)
// 2: Version (hard coded)
// 3: Functionailty (hard coded)
uint32_t Status; // 4
#if (TXFIFOSIZE > 0)
uint32_t TxFIFOStatus; // 5: from lo to hi byte: FIFO size, max use, ovrflow count, 81 on ovrflow
#endif
#if (RXFIFOSIZE > 0)
uint32_t RxFIFOStatus; // 6: from lo to hi byte: FIFO size, max use, ovrflow count, 81 on ovrflow
#endif
#if (MGRFIFOSIZE > 0)
uint32_t RxMgrFIFOStatus; // 7: from lo to hi byte: FIFO size, max use, ovrflow count, 81 on ovrflow
#endif
uint16_t ProcTickPerSecCur; // 8
uint16_t ProcTickPerSecMin; // 9
uint16_t ProcTickPerSecMax; // 10
uint16_t ProcTickBurstMax; // 11
uint16_t ProcRxPerSecCur; // 12
uint16_t ProcRxPerSecMin; // 13
uint16_t ProcRxPerSecMax; // 14
// 15: Reserved
#if MGR_MONITOR_ALL_NODES
uint16_t ProcMgrTickPerSecCur; // 16
uint16_t ProcMgrTickPerSecMin; // 17
uint16_t ProcMgrTickPerSecMax; // 18
uint16_t ProcMgrTickBurstMax; // 19
uint16_t ProcMgrRxPerSecCur; // 20
uint16_t ProcMgrRxPerSecMin; // 21
uint16_t ProcMgrRxPerSecMax; // 22
#endif
// working variables
uint16_t TickCnt; // Counting calls to MCO_ProcessStackTick()
uint16_t RxCnt; // Counting calls to MCO_ProcessStackRx()
uint16_t BurstCnt; // Counting retrun values of TRUE for MCO_ProcessStackTick()
uint16_t NextSecond; // Analyse diagnostics once per second
#if MGR_MONITOR_ALL_NODES
uint16_t MgrTickCnt;
uint16_t MgrRxCnt;
uint16_t MgrBurstCnt;
uint16_t MgrNextSecond;
#endif
} MCO_DIAGNOSTICS;
#endif
/**************************************************************************
GLOBAL VARIABLES
**************************************************************************/
// this structure holds all node specific configuration
extern MCO_CONFIG MEM_FAR gMCOConfig;
#if (INDEX_FOR_DIAGNOSTICS != 0)
// MCO diagnostics record
extern MCO_DIAGNOSTICS MEM_FAR gMCODiag;
#endif
// Global timer/conter variable, incremented every millisecond
extern uint16_t volatile gTimCnt;
// The process image
extern uint8_t MEM_PROC gProcImg[];
// table with SDO Responses for read requests to OD - defined in user_xxx.c
extern uint8_t MEM_CONST gSDOResponseTable[];
// table with Object Dictionary entries to process Data - defined in user_xxx.c
extern OD_PROCESS_DATA_ENTRY MEM_CONST gODProcTable[];
#if USE_EXTENDED_SDO
// table with generic OD entries
extern OD_GENERIC_DATA_ENTRY MEM_CONST gODGenericTable[];
#endif
#if NR_OF_TPDOS > 0
// this structure holds all the TPDO configuration data
extern TPDO_CONFIG MEM_FAR gTPDOConfig[NR_OF_TPDOS];
#endif
#if NR_OF_RPDOS > 0
// this structure holds all the RPDO configuration data for up to 4 RPDOs
extern RPDO_CONFIG MEM_FAR gRPDOConfig[NR_OF_RPDOS];
#endif
/**************************************************************************
GLOBAL FUNCTIONS
**************************************************************************/
/**************************************************************************
DOES: Initializes the MicroCANopen stack
It must be called from within MCOUSER_ResetCommunication
RETURNS: TRUE, if init OK, else FALSE (also when unconfigured and in LSS)
**************************************************************************/
uint8_t MCO_Init(uint16_t Baudrate, // CAN baudrate in kbit(1000,800,500,250,125,50,25 or 10)
#if defined(USE_CANOPEN_FD) && (USE_CANOPEN_FD == 1)
uint16_t BRSBaudRate,
#endif
uint8_t Node_ID, // CANopen node ID (1-126)
uint16_t Heartbeat // Heartbeat time in ms (0 for none)
);
/**************************************************************************
DOES: (Re-)Initializes CANopen system entries by reading them from the
Object Dictionary currently in use. Call after MCO_Init() or
whenever loading/activating a new Object Dictionary.
Uses globals gSDOResponseTable, gODProcTable, gProcImg
RETURNS: nothing
**************************************************************************/
void MCO_UpdateSystemFromOD(void);
/**************************************************************************
DOES: This function initializes a transmit PDO. Once initialized, the
MicroCANopen stack automatically handles transmitting the PDO.
The application can directly change the data at any time.
NOTE: For data consistency, the application should not write to the data
while function MCO_ProcessStack executes.
RETURNS: nothing
**************************************************************************/
void MCO_InitTPDO(uint16_t PDO_NR, // TPDO number (1-512)
uint32_t CAN_ID, // CAN identifier to be used (set to 0 to use default)
uint16_t event_tim, // Transmitted every event_tim ms
// (set to 0 if ONLY inhibit_tim should be used)
uint16_t inhibit_tim, // Inhibit time in ms for change-of-state transmit
// (set to 0 if ONLY event_tim should be used)
uint8_t len, // Number of data bytes in TPDO
uint16_t offset // Offset to data location in process image
);
/**************************************************************************
DOES: This function initializes a transmit PDO. Once initialized, the
MicroCANopen stack automatically handles transmitting the PDO.
The application can directly change the data at any time.
NOTE: For data consistency, the application should not write to the data
while function MCO_ProcessStack executes.
This is an extended version of MCO_InitTPDO() that includes the
transmission type. MCO_InitTPDO() is still available for backward-
compatibility.
RETURNS: nothing
**************************************************************************/
void MCO_InitTPDOFull(uint16_t PDO_NR, // TPDO number (1-512)
uint32_t CAN_ID, // CAN identifier to be used (set to 0 to use default)
uint16_t event_time, // Transmitted every event_tim ms
uint16_t inhibit_time, // Inhibit time in ms for change-of-state transmit
// (set to 0 if ONLY event_tim should be used)
uint8_t trans_type, // Transmission type of the TPDO
uint8_t len, // Number of data bytes in TPDO
uint16_t offset // Offset to data location in process image
);
/**************************************************************************
DOES: This function changes the COBID of a TPDO
RETURNS: nothing
**************************************************************************/
void MCO_ChangeTPDOID(uint16_t PDO_NR, // RPDO number (1-512)
uint32_t CAN_ID // CAN identifier to be used
);
/**************************************************************************
DOES: This function initializes a receive PDO. Once initialized, the
MicroCANopen stack automatically updates the data at offset.
NOTE: For data consistency, the application should not read the data
while function MCO_ProcessStack executes.
RETURNS: nothing
**************************************************************************/
void MCO_InitRPDO(uint16_t PDO_NR, // RPDO number (1-512)
uint32_t CAN_ID, // CAN identifier to be used (set to 0 to use default)
uint8_t len, // Number of data bytes in RPDO
uint16_t offset // Offset to data location in process image
);
/**************************************************************************
DOES: This function changes the COBID of a RPDO
RETURNS: nothing
**************************************************************************/
void MCO_ChangeRPDOID(uint16_t PDO_NR, // RPDO number (1-512)
uint32_t CAN_ID // CAN identifier to be used
);
/**************************************************************************
DOES: This function implements the main MicroCANopen protocol stack.
It must be called frequently to ensure proper operation of the
communication stack.
Typically it is called from the while(1) loop in main.
RETURNS: 0 if nothing was done, 1 if a CAN message was sent or received
**************************************************************************/
uint8_t MCO_ProcessStack(void);
/**************************************************************************
ALTERNATE PROCESS FUNCTION TO BE USED WITH RTOS INTEGRATION
DOES: This function processes the next CAN message from the CAN receive
queue. When using an RTOS, this can be turned into a task
triggered by a CAN receive event.
RETURNS: FALSE, if no message was processed,
TRUE, if a CAN message received was processed
**************************************************************************/
uint8_t MCO_ProcessStackRx(void);
/**************************************************************************
ALTERNATE PROCESS FUNCTION TO BE USED WITH RTOS INTEGRATION
DOES: This function executes all sub functions required to keep the
CANopen stack operating. It should be called frequently. When used
in an RTOS it should be called repeatedly every RTOS time tick
until it returns zero.
RETURNS: FALSE, if there was nothing to process
TRUE, if stack functions were executed
**************************************************************************/
uint8_t MCO_ProcessStackTick(void);
/**************************************************************************
USER CALL-BACK FUNCTIONS
These must be implemented by the application.
**************************************************************************/
/**************************************************************************
DOES: Call-back function for reset application.
Starts the watchdog and waits until watchdog causes a reset.
RETURNS: nothing
**************************************************************************/
void MCOUSER_ResetApplication(void);
/**************************************************************************
DOES: This function both resets and initializes both the CAN interface
and the CANopen protocol stack. It is called from within the
CANopen protocol stack, if a NMT master message was received that
demanded "Reset Communication".
This function should call MCO_Init and MCO_InitTPDO/MCO_InitRPDO.
RETURNS: nothing
**************************************************************************/
void MCOUSER_ResetCommunication(void);
/**************************************************************************
DOES: This function is called if a fatal error occurred.
Error codes of mcohwxxx.c are in the range of 0x8000 to 0x87FF.
Error codes of mco.c are in the range of 0x8800 to 0x8FFF.
All other error codes may be used by the application.
RETURNS: nothing
**************************************************************************/
void MCOUSER_FatalError(uint16_t ErrCode // To debug, search source code for the ErrCode encountered
);
/**************************************************************************
OPTIONAL USER CALL-BACK FUNCTIONS
These must be implemented by the application, if enabled by nodecfg.h
Default implementation in user_callback.c
**************************************************************************/
/**************************************************************************
DOES: Call-back function, heartbeat lost, timeout occured.
Gets called when a heartbeat timeout occured for a node.
RETURNS: Nothing
**************************************************************************/
void MCOUSER_HeartbeatLost(uint8_t node_id);
#if USECB_TIMEOFDAY
/**************************************************************************
DOES: This function is called if the message with the time object has
been received.
RETURNS: nothing
**************************************************************************/
void MCOUSER_TimeOfDay(uint32_t millis, // Milliseconds since midnight
uint16_t days // Number of days since January 1st, 1984
);
#endif // USECB_TIMEOFDAY
#if USECB_RPDORECEIVE
/**************************************************************************
DOES: This function is called after an RPDO has been received and stored
into the Process Image.
RETURNS: nothing
**************************************************************************/
void MCOUSER_RPDOReceived(uint16_t RPDONr, // RPDO Number
uint16_t offset, // Offset to RPDO data in Process Image
uint8_t len // Length of RPDO
);
#endif // USECB_RPDORECEIVE
#if USECB_ODDATARECEIVED
/**************************************************************************
DOES: This function is called after Object Dictionary data was received
(works for SDO/USDO and PDO).
RETURNS: nothing
**************************************************************************/
void MCOUSER_ODData(uint8_t client_nid, // node ID from where data arrived (0 if unknown)
uint16_t idx, // Index
uint8_t subidx, // Subindex
uint8_t MEM_PROC *pDat, // pointer to data
uint16_t len // length of data
);
#endif // USECB_ODDATARECEIVED
#if USECB_TPDORDY
/**************************************************************************
DOES: This function is called before a TPDO is sent. For triggering
modes that are outside of the application's doing (Event Timer,
SYNC), it is called before the send data is retrieved from the
Process Image. This allows the application to update the TPDO
data if necessary.
NOTE: This function is also called before a change-of-state or
application-triggered TPDO is sent, but updating the Process Image
will not have any effect on the TPDO data in this case.
RETURNS: TRUE to allow the PDO to be sent, FALSE to stop PDO transmission
**************************************************************************/
uint8_t MCOUSER_TPDOReady(uint16_t TPDONr, // TPDO Number
uint8_t TPDOTrigger // Trigger for this TPDO's transmission:
// 0: Event Timer
// 1: SYNC
// 2: SYNC+COS
// 3: COS or application trigger
);
#endif // USECB_TPDORDY
#if USECB_SYNCRECEIVE
/**************************************************************************
DOES: This function is called with every SYNC message received.
It allows the application to now apply all sync-triggered TPDO
data to be applied to the application.
RETURNS: nothing
**************************************************************************/
void MCOUSER_SYNCReceived(void);
/**************************************************************************
DOES: This function is called with every SYNC message received.
VERSION for SYNC messages WITH counter value.
It allows the application to now apply all sync-triggered TPDO
data to be applied to the application.
RETURNS: nothing
**************************************************************************/
void MCOUSER_SYNCCNTReceived(uint8_t counter_value);
#endif
#if USECB_SDO_RD_PI
/**************************************************************************
DOES: This function is called before an SDO or USDO read request is
executed reading from the process image. The application can
use this function to either update the data or to deny access
(by returning an SDO or USDO Abort code).
RETURNS: 0, if access is granted, data can be copied and returned or
CANopen SDO or USDO Abort Code - in which case the (U)SDO
transfer is aborted
**************************************************************************/
uint32_t MCOUSER_SDORdPI(uint8_t client_nid, // node ID from where the request came (0 if unknown)
uint16_t index, // Index of Object Dictionary entry
uint8_t subindex, // Subindex of Object Dictionary entry
uint16_t offset, // Offset to data in process image
uint16_t len // Length of data
);
#endif // USECB_SDO_RD_PI
#if USECB_SDO_RD_AFTER
/**************************************************************************
DOES: This function is called after an SDO or USDO read request was
executed. The application can use this to clear the data or
mark it as read.
RETURNS: Nothing
**************************************************************************/
void MCOUSER_SDORdAft(uint8_t client_nid, // node ID from where the request came (0 if unknown)
uint16_t index, // Index of Object Dictionary entry
uint8_t subindex, // Subindex of Object Dictionary entry
uint16_t offset, // Offset to data in process image
uint16_t len // Length of data
);
#endif // USECB_SDO_RD_AFTER
#if USECB_SDO_WR_PI
/**************************************************************************
DOES: This function is called before an SDO or USDO write request is
executed writing to the process image. The application can use
this function to check the data (e.g. range check) BEFORE it
gets written to the process image.
RETURNS: 0, if access is granted, data can be copied to process image or
CANopen SDO or USDO Abort Code - in which case the (U)SDO
transfer is aborted
**************************************************************************/
uint32_t MCOUSER_SDOWrPI(uint8_t client_nid, // node ID from where the request came (0 if unknown)
uint16_t index, // Index of Object Dictionary entry
uint8_t subindex, // Subindex of Object Dictionary entry
uint16_t offset, // Offset to data in process image
uint8_t *pDat, // Pointer to data received
uint16_t len // Length of data
);
#endif // USECB_SDO_WR_PI
#if USECB_SDO_WR_AFTER
/**************************************************************************
DOES: This function is called after an SDO write request was executed.
Data is now in the process image and can be processed.
RETURNS: Nothing
**************************************************************************/
void MCOUSER_SDOWrAft(uint8_t client_nid, // node ID from where the request came (0 if unknown)
uint16_t index, // Index of Object Dictionary entry
uint8_t subindex, // Subindex of Object Dictionary entry
uint16_t offset, // Offset to data in process image
uint16_t len // Length of data
);
#endif // USECB_SDO_WR_AFTER
#if USECB_APPSDO_READ
/*******************************************************************************
DOES: Call Back function to allow implementation of custom, application
specific OD Read entries
RETURNS: 0x00 - OD entry not handled by this function
0x01 - OD entry handled by this function
0x05 - Abort with "attempting to read a write-only object"
0x06 - Abort with "entry does not exist"
0x08 - Abort with "data type doesn't match" (CANopen FD only)
*******************************************************************************/
uint8_t MCOUSER_AppSDOReadInit(uint8_t sdoserver_client_nid, // CANopen: The SDO server number on which
// the request came in.
// CANopen FD: The USDO client node ID
// from which the request came in.
uint16_t idx, // Index of OD entry
uint8_t subidx, // Subindex of OD entry
uint32_t MEM_FAR *totalsize, // RETURN: total size of data, only set if >*size
uint32_t MEM_FAR *size, // RETURN: size of data buffer
uint8_t *MEM_FAR *pDat, // RETURN: pointer to data buffer
uint8_t MEM_FAR *type // RETURN: data type (CANopen FD only)
);
/*******************************************************************************
DOES: Call Back function to allow implementation of custom, application
specific OD Read entries, called at end of transfer with the option
to add more data.
RETURNS: Nothing
*******************************************************************************/
void MCOUSER_AppSDOReadComplete(uint8_t sdoserver_client_nid, // CANopen: The SDO server number on which
// the request came in.
// CANopen FD: The USDO client node ID
// from which the request came in.
uint16_t idx, // Index of OD entry
uint8_t subidx, // Subindex of OD entry
uint32_t MEM_FAR *size // RETURN: size of next block of data, 0 for no further data
);
#endif // USECB_APPSDO_READ
#if USECB_APPSDO_WRITE
/*******************************************************************************
DOES: Call Back function to allow implementation of custom, application
specific OD Write entries
RETURNS: 0x00 - OD entry not handled by this function
0x01 - OD entry handled by this function
0x04 - Abort with "attempting to write a read-only object"
0x06 - Abort with "entry does not exist"
0x08 - Abort with "data typ doesn't match" (CANopen FD only)
*******************************************************************************/
uint8_t MCOUSER_AppSDOWriteInit(uint8_t sdoserver_client_nid, // CANopen: The SDO server number on which
// the request came in.
// CANopen FD: The USDO client node ID
// from which the request came in.
uint16_t idx, // Index of OD entry
uint8_t subidx, // Subindex of OD entry
uint32_t MEM_FAR *totalsize, // RETURN: total maximum size of data, only set if >*size
uint32_t MEM_FAR *size, // Data size, if known. RETURN: max size of data buffer
uint8_t *MEM_FAR *pDat, // RETURN: pointer to data buffer
uint8_t MEM_FAR *type // RETURN: data type (CANopen FD only)
);
/*******************************************************************************
DOES: Call Back function to allow implementation of custom, application
specific OD Write entries, call at end of transfer of a block. For
multiple blocks per transfer, the same buffer is used for all blocks.
RETURNS: 0x00 - OD entry not handled by this function
0x01 - OD entry handled by this function
0x04 - Abort with "attempting to write a read-only object"
*******************************************************************************/
uint8_t MCOUSER_AppSDOWriteComplete(uint8_t sdoserver_client_nid, // CANopen: The SDO server number on which
// the request came in.
// CANopen FD: The USDO client node ID
// from which the request came in.
uint16_t idx, // Index of OD entry
uint8_t subidx, // Subindex of OD entry
uint32_t size, // Number of bytes written (of last block)
uint32_t more // number of bytes still to come (of total transfer)
);
#endif // USECB_APPSDO_WRITE
#if USE_XSDOCB_WRITE
/**************************************************************************
DOES: This function is called before a segmented SDO write access is
made. The application can use this to implement custom, segmented
SDO write transfers.
RETURNS: TRUE, if this access is supported by the application
**************************************************************************/
uint8_t MCOUSER_XSDOInitWrite(uint16_t index,
uint8_t subindex,
uint32_t size // size in bytes
);
/*******************************************************************************
DOES: After an access was approved by the application by the
MCOUSER_XSDOInitWrite function, this function is called with each
new segment received.
RETURNS: TRUE if no error occured and the data was processed
FALSE if a major error occured and the transfer needs to be aborted
*******************************************************************************/
uint8_t MCOUSER_XSDOWriteSegment(uint8_t last, // Is set to 1 if this is the last segment
uint8_t len, // length of segment (0-7)
uint8_t *pDat // pointer to 'len' data bytes
);
#endif // USE_XSDOCB_WRITE
#ifdef USECB_RX_UNKNOWN
/*******************************************************************************
DOES: CAN message received that was not processed by Micro CANpopen.
(unknown message)
RETURNS: TRUE if message was processed
FALSE if message was ignored
*******************************************************************************/
uint8_t MCOUSER_UnknownReceived(CAN_MSG *pRxCAN // Pointer to CAN message received
);
#endif
#if USE_DYNAMIC_PDO_MAPPING
/**************************************************************************
DOES: RESETS SINGLE PDO MAPPING ENTRY TO DEFAULT
RETURNS: TRUE, if PDO found and reset,
FALSE, if PDO not implemented
GLOBALS: Sets gRPDOmap and gTPDOmap to values defined in gSDOResponseTable
***************************************************************************/
uint8_t XPDO_ResetPDOMapEntry(uint8_t TxRx, // Set to 0 for TPDO, 1 for RPDO
uint16_t PDONr // Number of PDO, 1 to 512
);
#endif
#if defined(USECB_EMCY) && USECB_EMCY
/**************************************************************************
DOES: Process pending or clearing Emergency events (set or release).
USE: Use this to implement an active error list and to keep track
of application specific error codes.
RETURNS: 0 - No objection from application to transmit EMCY message
!=0 - Application requests, that EMCY message is NOT generated
**************************************************************************/
uint8_t MCOUSER_EMCY(uint8_t ev_clr, // set to TRUE if this is to clear a previous EMCY event
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 defined(USE_CANOPEN_FD) && (USE_CANOPEN_FD == 1)
,
uint8_t dev_num, // logical device number
uint16_t spec_num, // CiA specification number
uint8_t status, // status
uint32_t time_lo, // timestamp bits 0-31
uint16_t time_hi // timestamp bits 32-47
#endif // USE_CANOPEN_FD
);
#endif // USECB_EMCY
/*******************************************************************************
DOES: Internal functions of MCOP that get used in multiple modules
Search tables with OD definitions for a specific index/subindex
RETURNS: 0xFFFF if not found, else offset in tabel
*******************************************************************************/
uint16_t MCO_SearchOD(uint16_t index, // Index of OD entry searched
uint8_t subindex // Subindex of OD entry searched
);
uint16_t MCO_SearchODProcTable(uint16_t index, // Index of OD entry searched
uint8_t subindex // Subindex of OD entry searched
);
uint8_t XSDO_SearchODGenTable(uint16_t index, // Index of OD entry searched
uint8_t subindex, // Subindex of OD entry searched
uint8_t *access,
uint32_t *len,
uint8_t **pDat);
/**************************************************************************
DOES: Internal function, checks if this OD entry is a system entry and
if it is applies the data to the system variable(s)
RETURNS: 0xFFFFFFFF if access success, else SDO abort code
**************************************************************************/
uint32_t MCO_ApplySystemEntry(uint16_t index, uint8_t subindex, uint32_t dat);
#if USE_CiA447
/**************************************************************************
DOES: Advanced call-back function for expedited SDO write accesses made.
Version that includes node ID number of node making the request
RETURNS: nothing
**************************************************************************/
void MCOUSER_NodeSpecificSDOWrite(uint8_t node, // node id of node that made the request (if known, else zero)
uint16_t idx,
uint8_t sub,
uint16_t offset,
uint8_t len);
/**************************************************************************
DOES: Working on CiA447 background tasks and timeouts
RETURNS: nothing
**************************************************************************/
void PROFILE_Process447(void);
void CiA447_Process(void);
#endif
/**************************************************************************
Plausability check for settings
**************************************************************************/
#if (NR_OF_TPDOS > 0)
#if !USE_EVENT_TIME
#if !USE_INHIBIT_TIME
#error At least one, USE_EVENT_TIME or USE_INHIBIT_TIME must be defined!
#endif
#endif
#endif
#if USE_STORE_PARAMETERS
#if !USE_EVENT_TIME
#error When using Save Parameters, USE_EVENT_TIME must be used, too
#endif
#if !USE_INHIBIT_TIME
#error When using Save Parameters, USE_INHIBIT_TIME must be used, too
#endif
#endif
#if ((NR_OF_TPDOS > 512) || (NR_OF_RPDOS > 512))
#error Illegal number of PDOs
#endif
#if ERROR_FIELD_SIZE > 253
#error Illegal size of error field
#endif
#if USE_XOD_ACCESS == 1
#if USE_DYNAMIC_PDO_MAPPING == 1
#error USE_XOD_ACCESS can not be combined with USE_DYNAMIC_PDO_MAPPING
#endif
#if USE_GENOD_PTR == 1
#error USE_XOD_ACCESS can not be combined with USE_GENOD_PTR
#endif
#if CAN_ID_SIZE != 32
#error USE_XOD_ACCESS requires CAN_ID_SIZE to be 32
#endif
#endif
#if USE_29BIT_LSSFEEDBACK == 1
#if CAN_ID_SIZE != 32
#error USE_29BIT_LSSFEEDBACK requires CAN_ID_SIZE to be 32
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif // _MCO_H
/**************************************************************************
END OF FILE
**************************************************************************/