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: