etisserant@52: 
etisserant@52: #include "canfestival.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 */
etisserant@57: extern int common_ticktime__;
etisserant@52: 
etisserant@178: /* Called once all NetworkEdit declares slaves have booted*/
greg@160: static void Master_post_SlaveBootup(CO_Data* d, UNS8 nodeId)
etisserant@59: {
etisserant@59:     /* Put the master in operational mode */
etisserant@59:     setState(d, Operational);
etisserant@59:       
etisserant@59:     /* Ask slave node to go in operational mode */
etisserant@59:     masterSendNMTstateChange (d, 0, NMT_Start_Node);
etisserant@59: }
etisserant@59: 
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.
etisserant@178:  * Used to align PLC tick-time on CANopen SYNC 
etisserant@178:  */
etisserant@178: %(post_sync)s
etisserant@178: 
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;\
etisserant@178:     *nodename##_Data.Sync_Cycle_Period = common_ticktime__ * 1000;
etisserant@178: 
etisserant@178: #define NODE_INIT(nodename, nodeid) \
etisserant@52:     /* Defining the node Id */\
etisserant@52:     setNodeId(&nodename##_Data, nodeid);\
etisserant@52:     /* init */\
etisserant@52:     setState(&nodename##_Data, Initialisation);
etisserant@52: 
etisserant@178: #define NODE_MASTER_INIT(nodename, nodeid) \
etisserant@178: 	NODE_FORCE_SYNC(nodename) \
etisserant@178: 	NODE_INIT(nodename, nodeid)
etisserant@178: 
etisserant@178: #define NODE_SLAVE_INIT(nodename, nodeid) \
etisserant@178: 	NODE_INIT(nodename, nodeid)
etisserant@178: 
etisserant@52: void InitNodes(CO_Data* d, UNS32 id)
etisserant@52: {
etisserant@178: 	%(slavebootup_register)s
etisserant@178: 	%(post_sync_register)s
etisserant@52:     %(nodes_init)s
etisserant@52: }
etisserant@52: 
greg@144: void Exit(CO_Data* d, UNS32 id)
greg@144: {
greg@144: }
greg@144: 
etisserant@52: #define NODE_CLOSE(nodename) \
etisserant@57:     if(init_level-- > 0)\
etisserant@52:     {\
etisserant@52:         EnterMutex();\
greg@160:         masterSendNMTstateChange(&nodename##_Data, 0, NMT_Reset_Node);\
etisserant@52:         setState(&nodename##_Data, Stopped);\
etisserant@52:         LeaveMutex();\
etisserant@52:         canClose(&nodename##_Data);\
etisserant@52:     }
etisserant@52: 
etisserant@52: void __cleanup_%(locstr)s()
etisserant@52: {
etisserant@52:     %(nodes_close)s
etisserant@52:     
etisserant@52:     // Stop timer thread
etisserant@57:     if(init_level-- > 0)
greg@144:         StopTimerLoop(&Exit);
etisserant@52: 
etisserant@156:     #if !defined(WIN32) || defined(__CYGWIN__)
etisserant@156:    		TimerCleanup();
etisserant@156:     #endif
etisserant@52: }
etisserant@52: 
etisserant@52: #define NODE_OPEN(nodename)\
etisserant@52:     if(!canOpen(&nodename##Board,&nodename##_Data)){\
etisserant@52:         printf("Cannot open " #nodename " Board (%%s,%%s)\n",nodename##Board.busname, nodename##Board.baudrate);\
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");\
etisserant@57:         return -1;
etisserant@57:     }
etisserant@57: #endif      
etisserant@156: 	#if !defined(WIN32) || defined(__CYGWIN__)
etisserant@156: 		TimerInit();
etisserant@156: 	#endif
etisserant@156: 	
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)\
etisserant@57:     sendSYNCMessage(&nodename##_Data);
etisserant@57: 
lbessard@137: void __retrieve_%(locstr)s()
etisserant@52: {
etisserant@57:     /* Locks the stack, so that no changes occurs while PLC access variables
etisserant@57:      * 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: 
etisserant@52: void __publish_%(locstr)s()
etisserant@52: {
etisserant@178:     /* Process sync event */
etisserant@57:     %(nodes_proceed_sync)s
etisserant@52:     LeaveMutex();
etisserant@52: }
etisserant@52: