etisserant@52: 
etisserant@52: #include "canfestival.h"
Edouard@776: #include "dcf.h"
etisserant@52: 
etisserant@178: /* CanFestival nodes generated OD headers*/
etisserant@52: %(nodes_includes)s
etisserant@52: 
etisserant@52: #define BOARD_DECL(nodename, busname, baudrate)\
etisserant@52:     s_BOARD nodename##Board = {busname, baudrate};
etisserant@52: 
etisserant@178: /* CAN channels declaration */
etisserant@52: %(board_decls)s
etisserant@52: 
etisserant@178: /* Keep track of init level to cleanup correctly */
etisserant@52: static int init_level=0;
etisserant@178: /* Retrieve PLC cycle time */
Edouard@1428: extern unsigned long long common_ticktime__;
etisserant@52: 
etisserant@178: /* Per master node slavebootup callbacks. Checks that
etisserant@178:  * every node have booted before calling Master_post_SlaveBootup */
etisserant@169: %(slavebootups)s
etisserant@169: 
etisserant@178: /* One slave node post_sync callback.
greg@336:  * Used to align PLC tick-time on CANopen SYNC
etisserant@178:  */
etisserant@178: %(post_sync)s
etisserant@178: 
Edouard@778: /* Triggers DCF transission
Edouard@778:  */
Edouard@778: %(pre_op)s
Edouard@778: 
etisserant@178: #define NODE_FORCE_SYNC(nodename) \
etisserant@57:     /* Artificially force sync state to 1 so that it is not started */\
etisserant@57:     nodename##_Data.CurrentCommunicationState.csSYNC = -1;\
etisserant@57:     /* Force sync period to common_ticktime__ so that other node can read it*/\
etisserant@57:     *nodename##_Data.COB_ID_Sync = 0x40000080;\
Edouard@1428:     *nodename##_Data.Sync_Cycle_Period = common_ticktime__ / 1000;
etisserant@178: 
Edouard@1397: static void DeferedInitAlarm(CO_Data* d, UNS32 id){
Edouard@1397:     /* Node will start beeing active on the network after this */
Edouard@1397:     setState(d, Initialisation);
Edouard@1397: }
Edouard@1397: 
etisserant@178: #define NODE_INIT(nodename, nodeid) \
etisserant@52:     /* Defining the node Id */\
etisserant@52:     setNodeId(&nodename##_Data, nodeid);\
Edouard@1397:     SetAlarm(&nodename##_Data,0,&DeferedInitAlarm,MS_TO_TIMEVAL(100),0);
etisserant@52: 
etisserant@178: #define NODE_MASTER_INIT(nodename, nodeid) \
greg@336:     NODE_FORCE_SYNC(nodename) \
greg@336:     NODE_INIT(nodename, nodeid)
etisserant@178: 
etisserant@178: #define NODE_SLAVE_INIT(nodename, nodeid) \
greg@336:     NODE_INIT(nodename, nodeid)
etisserant@178: 
Edouard@1397: static void InitNodes(CO_Data* d, UNS32 id)
etisserant@52: {
greg@336:     %(slavebootup_register)s
greg@336:     %(post_sync_register)s
Edouard@778:     %(pre_op_register)s
etisserant@52:     %(nodes_init)s
etisserant@52: }
etisserant@52: 
greg@336: #define NODE_STOP(nodename) \
greg@336:     if(init_level-- > 0)\
greg@336:     {\
greg@336:         masterSendNMTstateChange(&nodename##_Data, 0, NMT_Reset_Node);\
greg@336:         setState(&nodename##_Data, Stopped);\
greg@336:     }
greg@336: 
Edouard@1397: static void Exit(CO_Data* d, UNS32 id)
greg@144: {
greg@336:     %(nodes_stop)s
greg@144: }
greg@144: 
etisserant@52: #define NODE_CLOSE(nodename) \
greg@336:     if(init_level_c-- > 0)\
etisserant@52:     {\
greg@336:       canClose(&nodename##_Data);\
etisserant@52:     }
etisserant@52: 
edouard@512: void __cleanup_%(locstr)s(void)
etisserant@52: {
etisserant@52:     // Stop timer thread
etisserant@203:     if(init_level-- > 0){
greg@360:     int init_level_c = init_level;
greg@144:         StopTimerLoop(&Exit);
etisserant@203:         %(nodes_close)s
greg@336:     }
greg@360: 
greg@360:     TimerCleanup();
etisserant@52: }
etisserant@52: 
edouard@512: #ifndef stderr
edouard@512: #define fprintf(...)
edouard@512: #define fflush(...)
edouard@512: #endif
edouard@512: 
etisserant@52: #define NODE_OPEN(nodename)\
etisserant@52:     if(!canOpen(&nodename##Board,&nodename##_Data)){\
etisserant@235:         fprintf(stderr,"Cannot open CAN intefrace %%s at speed %%s\n for CANopen node \"" #nodename "\"",nodename##Board.busname, nodename##Board.baudrate);\
etisserant@235:         fflush(stderr);\
etisserant@52:         return -1;\
etisserant@52:     }\
etisserant@52:     init_level++;
etisserant@52: 
etisserant@52: /***************************  INIT  *****************************************/
etisserant@52: int __init_%(locstr)s(int argc,char **argv)
etisserant@52: {
etisserant@57: #ifndef NOT_USE_DYNAMIC_LOADING
etisserant@75:     if( !LoadCanDriver("%(candriver)s") ){
etisserant@57:         fprintf(stderr, "Cannot load CAN interface library for CanFestival (%(candriver)s)\n");\
edouard@512:         fflush(stderr);\
edouard@512:         return -1;\
etisserant@57:     }
greg@336: #endif
greg@360: 
greg@360:     TimerInit();
greg@336: 
etisserant@52:     %(nodes_open)s
etisserant@52: 
etisserant@52:     // Start timer thread
etisserant@52:     StartTimerLoop(&InitNodes);
etisserant@57:     init_level++;
etisserant@52:     return 0;
etisserant@52: }
etisserant@52: 
etisserant@57: #define NODE_SEND_SYNC(nodename)\
Edouard@776:     if(getState(&nodename##_Data)==Operational){\
Edouard@776:         sendSYNCMessage(&nodename##_Data);\
Edouard@776:     }
etisserant@57: 
edouard@512: void __retrieve_%(locstr)s(void)
etisserant@52: {
etisserant@57:     /* Locks the stack, so that no changes occurs while PLC access variables
greg@336:      * TODO : implement buffers to avoid such a big lock
etisserant@57:      *  */
etisserant@52:     EnterMutex();
etisserant@178:     /* Send Sync */
etisserant@57:     %(nodes_send_sync)s
etisserant@52: }
etisserant@52: 
etisserant@57: #define NODE_PROCEED_SYNC(nodename)\
etisserant@57:     proceedSYNC(&nodename##_Data);
etisserant@57: 
edouard@512: void __publish_%(locstr)s(void)
etisserant@52: {
etisserant@178:     /* Process sync event */
etisserant@57:     %(nodes_proceed_sync)s
etisserant@52:     LeaveMutex();
etisserant@52: }
etisserant@52: