Skip to end of metadata
Go to start of metadata

This section explains the callback functions that are available for use by some communication objects. These callbacks allow your application to customize certain actions while the CANOpen stack is processing communication objects.

The callbacks are available for the following CANopen services processing:

  • Parameters
  • Process Data Object (PDO)
  • Network Management (NMT)
  • Heartbeat consumer (NMT error control) 

Initializing Callbacks

Communication object callbacks can be set when calling CANopen_NodeAdd(). The second parameter of this function takes a pointer to a CANOPEN_EVENT_FNCTS structure.  Listing - Communication Object Callbacks provides an example of how to declare the callbacks.

RTOS_ERR             err;
CANOPEN_NODE_HANDLE  node_handle;
CANOPEN_NODE_SPEC    spec_node;
 
CANOPEN_EVENT_FNCTS  event_fnt = {
    .RpdoOnRx      = &RpdoOnRx,
    .TpdoOnTx      = &TpdoOnTx,
    .StateOnChange = &StateOnChange,
    .HbcOnEvent    = &HBCOnEvent,
    .HbcOnChange   = &HbcOnChange,
    .ParamOnLoad   = &ParamOnLoad,
    .ParamOnSave   = &ParamOnSave,
    .ParamOnDflt   = &ParamOnDflt
};
 
    
node_handle = CANopen_NodeAdd(&spec_node,
                              &event_fnt,
                              &err);
APP_RTOS_ASSERT_DBG((err.Code == RTOS_ERR_NONE), ;);
Listing - Communication Object Callbacks

Parameters

Your application has access to three callbacks to manage the storing and restoring of object dictionary parameters.  Listing - Example of CANOPEN_PARAM Usage provides a basic definition of an object dictionary with the store and restore features enabled and shows an example of how to declare the parameters group. 

typedef  struct  APP_PARAM_GROUP {
    CPU_INT32U      AppVar_1005_0;         /* ------------------ [1005:0] SYNC ------------------- */
    CPU_INT32U      AppVar_1010_0;         /* [1010:0] Store parameters                            */
    CPU_INT32U      AppVar_1010_1;         /* [1010:1] Save all parameter                          */
    CPU_INT08U      AppVar_1011_0;         /* [1011:0] Restore parameters                          */
    CPU_INT32U      AppVar_1011_1;         /* [1011:1] Restore all parameter                       */
} APP_PG;
 
...
 
APP_PG  App_ParamGrp  = {                  (1)
        .AppVar_1005_0 = 0x80,             
        .AppVar_1010_0 = 1,              
        .AppVar_1010_1 = 1,              
        .AppVar_1011_0 = 1,            
        .AppVar_1011_1 = 1,              
};
 
APP_PG  App_ParamDef = {                   (2)
        .AppVar_1005_0 = 0x80,             
        .AppVar_1010_0 = 0,             
        .AppVar_1010_1 = 0,                
        .AppVar_1011_0 = 0,            
        .AppVar_1011_1 = 0,               
};
 
...
 
const CANOPEN_PARAM App_ParamGrpCfg = {    (3)
    .MemBlkSize     = sizeof(APP_PG),
    .StartMemBlkPtr = (CPU_INT08U *)&App_ParamGrp,
    .DfltMemBlkPtr  = (CPU_INT08U *)&App_ParamDef,
    .ResetType      = CANOPEN_RESET_COMM,  (4)
    .IdPtr          = (void*)"AppParam",
    .Val            = CANOPEN_PARAM___E
};
 
...
 
const CANOPEN_OBJ AppObjDir[] = {          
    /*--------------------------------------------------------------------------------------------*/
    /* [1005:xx] - SYNC */
    { CANOPEN_KEY(0x1005,0x0, CANOPEN_OBJ_UNSIGNED32|CANOPEN_OBJ____RW), 0, 
      (CPU_INT32U)&App_ParamGrp.AppVar_1005_0 },
    /*--------------------------------------------------------------------------------------------*/
    /* [1010:xx] - Store parameters */
    { CANOPEN_KEY(0x1010,0x0, CANOPEN_OBJ_UNSIGNED8|CANOPEN_OBJ____R_), 0, 
      (CPU_INT32U)&App_ParamGrp.AppVar_1010_0 },
    { CANOPEN_KEY(0x1010,0x1, CANOPEN_OBJ_UNSIGNED32|CANOPEN_OBJ____RW), CANOPEN_OBJ_TYPE_PARAM, 
      (CPU_INT32U)&App_ParamGrpCfg },      (5)
    /*--------------------------------------------------------------------------------------------*/
    /* [1011:xx] - Restore parameters */
    { CANOPEN_KEY(0x1011,0x0, CANOPEN_OBJ_UNSIGNED8|CANOPEN_OBJ____R_), 0, 
      (CPU_INT32U)&App_ParamGrp.AppVar_1011_0 },
    { CANOPEN_KEY(0x1011,0x1, CANOPEN_OBJ_UNSIGNED32|CANOPEN_OBJ____RW), CANOPEN_OBJ_TYPE_PARAM, 
      (CPU_INT32U)&App_ParamGrpCfg },
    CANOPEN_OBJ_DICT_ENDMARK
};
Listing - Example of CANOPEN_PARAM Usage

(1) This structure holds all the values used by the object dictionary. All these values can be restored to their original state using the communication object at index 0x1011 (restore parameters).

(2) This structure holds the default values of a specific part of the object dictionary. These values are written back to the object dictionary when using the communication object at index 0x1011 (restore parameters).

(3) This structure is used to store pointers to data structures such as the default and current values of the object dictionary.

(4) Specifies the reset type for a parameter group. This can be CANOPEN_RESET_NODE or CANOPEN_RESET_COMM. If CANOPEN_RESET_NODE  is used, the parameters of the manufacturer-specific profile area and the standardized device profile area are both set to their power-on values. If CANOPEN_RESET_COMM is used, the parameters of the communication profile area are set to their power-on values.

(5) A pointer to the configuration structure must be passed as data to the store/restore communication object into the object dictionary.

ParamOnLoad()

This callback is of type ParamOnLoad(). This callback is optional and must be defined in your application.

The callback restores the current object dictionary with default values from a memory segmentListing - ParamOnLoad() Example show a basic implementation of the ParamOnLoad() callback.

CPU_BOOLEAN Ex_ParamOnLoad (CANOPEN_NODE_HANDLE   handle,
                            CANOPEN_PARAM        *p_pg)
{
    PP_UNUSED_PARAM(handle);
    
    Mem_Copy(p_pg->StartMemBlkPtr,              /* Pointer to parameter memory block in object dictionary.   */
             p_pg->DfltMemBlkPtr,               /* Pointer to memory segment from where values are restored. */   
             p_pg->MemBlkSize);
    
    return (DEF_TRUE);
}
Listing - ParamOnLoad() Example

ParamOnSave()

This callback is of type ParamOnSave(). This callback is optional and must be defined in your application.

The callback is called when a master writes a valid signature at the index 0x1010 (store parameters) of the node's object dictionary. The signature that enables the parameters to be stored is "save" – that is, in hexadecimal, 0x65766173, which represents 'e', 'v', 'a', 's'.

The current state of the object dictionary is saved into memory for future use.

 CPU_BOOLEAN  Ex_ParamOnSave (CANOPEN_NODE_HANDLE   handle,
                              CANOPEN_PARAM        *p_pg)
{
    /* The object dictionary must be stored somewhere in memory for future use.
       The pointer p_pg->StartMemBlkPtr contains the address of the first entry 
       of the object dictionary. The number of bytes in the object dictionary 
       is given by p_pg->MemBlkSize. */

    return (DEF_TRUE);
}
Listing - ParamOnSave() Example

ParamOnDflt()

This callback is of type ParamOnDflt(). This callback is optional and must be defined in your application.

The callback is called when a master writes a valid signature at the index 0x1011 (restore default parameters) of the node's object dictionary. The signature that enables the default parameters to be restored is "load" – that is, in hexadecimal, 0x64616F6C, which represents 'd', 'a', 'o', 'l'.  Listing - ParamOnDflt() Example shows a basic implementation of the ParamOnDflt() callback.

CPU_BOOLEAN Ex_ParamOnDflt (CANOPEN_NODE_HANDLE   handle,
                            CANOPEN_PARAM        *p_pg)
{
    PP_UNUSED_PARAM(handle);
     
    Mem_Copy(p_pg->StartMemBlkPtr,              /* Pointer to parameter memory block in object dictionary.   */
             p_pg->DfltMemBlkPtr,               /* Pointer to memory segment from where values are restored. */   
             p_pg->MemBlkSize);
     
    return (DEF_TRUE);
}
Listing - ParamOnDflt() Example

PDO

PDO callbacks are useful for checking data payloads after a PDO message is received or before it is transmitted. This payload data is stored in the second argument of each PDO callback.

This structure is used to store various information about a message received from or transmitted to the bus. CANOPEN_IF_FRM shows a brief description of each argument of the following structure.

typedef struct canopen_if_frm {                              
    CPU_INT32U  MsgId;                                     
    CPU_INT08U  Data[8];                                      
    CPU_INT08U  DLC;                                          
    CPU_INT08U  MsgNum;
} CANOPEN_IF_FRM;
Listing - CANopen Frame Structure

TpdoOnTx()

TpdoOnTx() is called before every TPDO transmission. It can be used to change the PDO data before sending it.

This callback is of type TpdoOnTx()TpdoOnTx() is optional and must be defined in your application.  Listing - TpdoOnTx() Example shows a basic implementation of the TpdoOnTx() callcack.

void Ex_TpdoOnTx (CANOPEN_NODE_HANDLE   handle,
                  CANOPEN_IF_FRM       *p_frm)
{
    PP_UNUSED_PARAM(handle);
                                         /* Change payload data before sending it over the bus.  */
    p_frm->Data[0u] = 1u;
    p_frm->Data[1u] = 2u;
    p_frm->Data[2u] = 3u;
    p_frm->Data[3u] = 4u;

    p_frm->DLC = 4u;                     /* Change the message length.                           */
}
Listing - TpdoOnTx() Example

RpdoOnRx()

RpdoOnRx() is called every time an asynchronous RPDO message is received.

This callback is of type RpdoOnRx()RpdoOnRx() is optional and must be defined in your application.  Listing - RpdoOnRx() Example shows a basic implementation of the RpdoOnRx() callback.

void Ex_RpdoOnRx (CANOPEN_NODE_HANDLE   handle,
                  CANOPEN_IF_FRM       *p_frm)
{
    PP_UNUSED_PARAM(handle);
                                                                
    for (CPU_INT32U loop = 0; loop < p_frm->DLC; loop ++) {
        printf("%d ", p_frm->Data[loop]);   /* Print every characters from the data payload.        */
    }
}
Listing - RpdoOnRx() Example

NMT

The node's NMT feature (Network Management) allows a master to control the internal node states by sending commands over the CAN bus.  One unique callback allows the user application to be notified about a state transition. 

Listing - CANopen State Enumeration is used to define the different states taken by a node. CANOPEN_NODE_STATE shows a brief description of each enumeration state.

typedef enum canopen_node_state {
    CANOPEN_INVALID = 0,                                
    CANOPEN_INIT,                                        
    CANOPEN_PREOP,                                   
    CANOPEN_OPERATIONAL,                                 
    CANOPEN_STOP,                               
    CANOPEN_STATE_QTY                                    
} CANOPEN_NODE_STATE;
Listing - CANopen State Enumeration

StateOnChange()

This callback is used when the NMT state is changed. This callback is of type StateOnChange(). This callback is optional and must be defined in your application.

Heartbeat Consumer

Two callbacks are available to notify your application about the heartbeat producer activity.

HbcOnEvent()

This callback is used when a heartbeat consumer timer elapses and is triggered before receiving the corresponding heartbeat message from the heartbeat producer being monitored.

This callback is of type HbcOnEvent(). This callback is optional and must be defined in your application.

HbcOnChange()

This callback is used when a heartbeat consumer monitor detects a state change in a monitored node.

This callback is of type HbcOnChange(). This callback is optional and must be defined in your application.

  • No labels