etisserant@0: /* etisserant@0: This file is part of CanFestival, a library implementing CanOpen Stack. etisserant@0: etisserant@0: Copyright (C): Edouard TISSERANT and Francis DUPIN etisserant@0: etisserant@0: See COPYING file for copyrights details. etisserant@0: etisserant@0: This library is free software; you can redistribute it and/or etisserant@0: modify it under the terms of the GNU Lesser General Public etisserant@0: License as published by the Free Software Foundation; either etisserant@0: version 2.1 of the License, or (at your option) any later version. etisserant@0: etisserant@0: This library is distributed in the hope that it will be useful, etisserant@0: but WITHOUT ANY WARRANTY; without even the implied warranty of etisserant@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU etisserant@0: Lesser General Public License for more details. etisserant@0: etisserant@0: You should have received a copy of the GNU Lesser General Public etisserant@0: License along with this library; if not, write to the Free Software etisserant@0: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA etisserant@0: */ etisserant@0: etisserant@0: #include etisserant@0: #include etisserant@0: #include etisserant@0: #include etisserant@0: #include etisserant@0: #include etisserant@0: etisserant@0: #include etisserant@0: #include etisserant@0: #include etisserant@0: etisserant@0: #include "def.h" etisserant@0: #include "can.h" etisserant@0: #include "canOpenDriver.h" etisserant@0: #include "sdo.h" etisserant@0: #include "pdo.h" etisserant@0: #include "init.h" etisserant@0: #include "timer.h" etisserant@0: #include "lifegrd.h" etisserant@0: etisserant@0: #include "nmtSlave.h" etisserant@0: etisserant@0: // Adlink 7841 or Peak PCI/CAN board etisserant@0: // --------------------------------- etisserant@0: etisserant@0: // Baudrate values for Peak board : etisserant@0: // CAN_BAUD_1M CAN_BAUD_500K CAN_BAUD_250K CAN_BAUD_125K CAN_BAUD_100K CAN_BAUD_50K etisserant@0: // CAN_BAUD_20K CAN_BAUD_10K CAN_BAUD_5K etisserant@0: etisserant@0: #ifdef CAN_BAUD_250K etisserant@0: # define BAUDRATE CAN_BAUD_250K etisserant@0: #else etisserant@0: // Appli have been compiled for Adlink-arbraca. Baudrate not used etisserant@0: # define BAUDRATE 0 etisserant@0: #endif etisserant@0: etisserant@0: s_BOARD board = {"1", BAUDRATE}; etisserant@0: etisserant@0: etisserant@0: // The variables sent or updated by PDO etisserant@0: // ----------------------------------------------------- etisserant@0: extern UNS8 seconds; // Mapped at index 0x2000, subindex 0x1 etisserant@0: extern UNS8 minutes; // Mapped at index 0x2000, subindex 0x2 etisserant@0: extern UNS8 hours; // Mapped at index 0x2000, subindex 0x3 etisserant@0: extern UNS8 day; // Mapped at index 0x2000, subindex 0x4 etisserant@0: extern UNS32 canopenErrNB; // Mapped at index 0x6000, subindex 0x0 etisserant@0: extern UNS32 canopenErrVAL; // Mapped at index 0x6001, subindex 0x0 etisserant@0: etisserant@0: // Required definition variables etisserant@0: // ----------------------------- etisserant@0: // The variables that you should define for debugging. etisserant@0: // They are used by the macro MSG_ERR and MSG_WAR in applicfg.h etisserant@0: // if the node is a slave, they can be mapped in the object dictionnary. etisserant@0: // if not null, allow the printing of message to the console etisserant@0: // Could be managed by PDO etisserant@0: UNS8 printMsgErrToConsole = 1; etisserant@0: UNS8 printMsgWarToConsole = 1; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*************************User's variables declaration**************************/ etisserant@0: struct tm date; etisserant@0: struct tm *ptrdate; etisserant@0: struct tm date_prec; etisserant@0: time_t tme; etisserant@0: UNS8 lastSecond; etisserant@0: e_nodeState lastState; etisserant@0: pthread_t threadRcvMsg; etisserant@0: pthread_t threadHeartbeatAndSDO; etisserant@0: UNS8 sendingError = 0; etisserant@0: etisserant@0: etisserant@0: /******************************prototypes*****************************/ etisserant@0: /* You *must* have these 2 functions in your code*/ etisserant@0: void heartbeatError(UNS8 heartbeatID); etisserant@0: void SD0timeoutError(UNS8 bus_id, UNS8 line); etisserant@0: etisserant@0: UNS8 scanSDOtimeout(void); etisserant@0: void preOperational(void); etisserant@0: void operational(void); etisserant@0: void stopped(void); etisserant@0: void waitMessage(void); etisserant@0: void waitMessage_heartbeat(void); etisserant@0: etisserant@0: /*********************************************************************/ etisserant@0: void heartbeatError(UNS8 heartbeatID) etisserant@0: { etisserant@0: MSG_ERR(0x1F00, "!!! No heart beat received from node : ", heartbeatID); etisserant@0: } etisserant@0: etisserant@0: /*****************************************************************************/ etisserant@0: void SD0timeoutError (UNS8 bus_id, UNS8 line) etisserant@0: { etisserant@0: // Informations on what occurs are in transfers[bus_id][line].... etisserant@0: // See scanSDOtimeout() in sdo.c etisserant@0: } etisserant@0: etisserant@0: /*********************************** THREADS **********************************/ etisserant@0: //------------------------------------------------------------------------------ etisserant@0: // Wait for a received message etisserant@0: void waitMessage( void ) etisserant@0: { etisserant@0: while (1) { etisserant@0: receiveMsgHandler(0); // blocked until new message etisserant@0: } etisserant@0: } etisserant@0: etisserant@0: //------------------------------------------------------------------------------ etisserant@0: // Heartbeat Manager (sending and receiving) and test SDO timeout etisserant@0: void heartbeatAndSDO(void) etisserant@0: { etisserant@0: while (1) { etisserant@0: heartbeatMGR(); etisserant@0: // Check if some SDO response are missing etisserant@0: scanSDOtimeout(); etisserant@0: // Sleep 10 ms etisserant@0: usleep(10000); etisserant@0: } etisserant@0: } etisserant@0: etisserant@0: /*********************************************************************/ etisserant@0: void preOperational( void ) etisserant@0: { etisserant@0: /* Init some variables */ etisserant@0: canopenErrNB = 0; etisserant@0: canopenErrVAL = 0; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: /********************************************************************/ etisserant@0: void operational( void ) etisserant@0: { etisserant@0: /* read systeme date */ etisserant@0: tme = time (&tme); etisserant@0: ptrdate = gmtime(&tme); etisserant@0: date = *ptrdate; etisserant@0: etisserant@0: /* Update the dictionary */ etisserant@0: day = date.tm_mday; etisserant@0: hours = date.tm_hour; etisserant@0: minutes = date.tm_min; etisserant@0: seconds = date.tm_sec; etisserant@0: etisserant@0: etisserant@0: if ( date_prec.tm_min != date.tm_min ) { etisserant@0: MSG_WAR(0x3F00, "event : minutes change -> node decides to send it. Value : ", date.tm_min); etisserant@0: sendPDOevent( 0, &minutes ); etisserant@0: date_prec = date; etisserant@0: } etisserant@0: if (canopenErrNB == 0) etisserant@0: sendingError = 0; etisserant@0: etisserant@0: if (lastSecond != seconds) { etisserant@0: MSG_WAR (0x3F50, "Seconds = ", seconds); etisserant@0: if ((seconds == 50) && (sendingError == 0)) etisserant@0: { etisserant@0: MSG_ERR(0x1F55, "DEMO of ERROR. Sent by PDO. Value : ", 0xABCD); etisserant@0: sendingError = 1; etisserant@0: } etisserant@0: etisserant@0: if (canopenErrNB) { etisserant@0: MSG_WAR(0x3F56, "ERROR nb : ", canopenErrNB); etisserant@0: } etisserant@0: lastSecond = seconds; etisserant@0: etisserant@0: } etisserant@0: } etisserant@0: etisserant@0: etisserant@0: /*****************************************************************************/ etisserant@0: void stopped( void ) etisserant@0: { etisserant@0: } etisserant@0: etisserant@0: void help() etisserant@0: { etisserant@0: printf("**************************************************************\n"); etisserant@0: printf("* AppliSlave *\n"); etisserant@0: printf("* [-b b] *\n"); etisserant@0: printf("* *\n"); etisserant@0: printf("* b : bus [default 1] *\n"); etisserant@0: printf("* *\n"); etisserant@0: printf("* This exemple run AppliSlave on bus 0 *\n"); etisserant@0: printf("* AppliSlave -b 0 *\n"); etisserant@0: printf("* *\n"); etisserant@0: printf("**************************************************************\n"); etisserant@0: } etisserant@0: etisserant@0: /****************************************************************************/ etisserant@0: /*************************** MAIN *****************************************/ etisserant@0: /****************************************************************************/ etisserant@0: int main(int argc,char **argv) etisserant@0: { etisserant@0: etisserant@0: HANDLE ok; etisserant@0: UNS32 * pSize; etisserant@0: UNS32 size; etisserant@0: pSize = &size; etisserant@0: char c; etisserant@0: extern char *optarg; etisserant@0: etisserant@0: while ((c = getopt(argc, argv, "-b:")) != EOF) etisserant@0: { etisserant@0: switch(c) etisserant@0: { etisserant@0: case 'b' : etisserant@0: if (optarg[0] == 0) etisserant@0: { etisserant@0: help(); etisserant@0: exit(1); etisserant@0: } etisserant@0: board.busname = optarg; etisserant@0: break; etisserant@0: default: etisserant@0: help(); etisserant@0: exit(1); etisserant@0: } etisserant@0: } etisserant@0: etisserant@0: // Global initialization before launching the threads. (also done in init mode. etisserant@0: /* Defining the node Id */ etisserant@0: setNodeId(0x05); etisserant@0: MSG_WAR(0x3F06, "My node ID is : ", getNodeId()); etisserant@0: initCANopenMain(); etisserant@0: initTimer( ); etisserant@0: heartbeatInit(); etisserant@0: initResetMode(); etisserant@0: etisserant@0: /* Launch the thread to receive the messages */ etisserant@0: pthread_create( &threadRcvMsg, NULL, (void *)&waitMessage, NULL); etisserant@0: /* Launch the thread to manage the heartbeat */ etisserant@0: pthread_create( &threadHeartbeatAndSDO, NULL, (void *)&heartbeatAndSDO, NULL); etisserant@0: etisserant@0: /* open the communication with the board */ etisserant@0: ok = f_can_open(& board); etisserant@0: if (ok == NULL) { etisserant@0: MSG_ERR(0x1F02,"Unable to open the board", 0); etisserant@0: MSG_ERR(0x1F03,"Edit includeMakefileLinux to verify that the application is configured for the good board", 0); etisserant@0: exit (-1); etisserant@0: } etisserant@0: else { etisserant@0: MSG_WAR(0x3F03, "Board 1 opened ", 0); etisserant@0: /* slave's state initialization */ etisserant@0: setState(Initialisation); etisserant@0: lastState = Unknown_state; etisserant@0: etisserant@0: etisserant@0: while(1) { /* slave's state machine */ etisserant@0: switch( getState() ) { etisserant@0: case Initialisation: etisserant@0: if (lastState != getState()) etisserant@0: MSG_WAR(0X3F05, "I am in INITIALISATION mode ", 0); etisserant@0: /* Defining the node Id */ etisserant@0: setNodeId(0x05); etisserant@0: MSG_WAR(0x3F06, "My node ID is : ", getNodeId()); etisserant@0: // Node identity ? etisserant@0: { etisserant@0: UNS8 *data; etisserant@0: UNS8 size; etisserant@0: UNS8 dataType; etisserant@0: // Manufacturer Device name (default = empty string) etisserant@0: getODentry(0x1008, 0x0, (void **)&data, &size, &dataType, 0); etisserant@0: MSG_WAR(0x3F09, data, 0); etisserant@0: // Manufacturer Hardware version. (default = compilation. date) etisserant@0: getODentry(0x1009, 0x0, (void **)&data, &size, &dataType, 0); etisserant@0: MSG_WAR(0x3F09, data, 0); etisserant@0: // Manufacturer Software version. (default = compilation. time) etisserant@0: getODentry(0x100A, 0x0, (void **)&data, &size, &dataType, 0); etisserant@0: MSG_WAR(0x3F09, data, 0); etisserant@0: } etisserant@0: etisserant@0: initCANopenMain(); etisserant@0: initTimer( ); etisserant@0: heartbeatInit(); etisserant@0: initResetMode(); etisserant@0: /* the slave send an NMT trame to say to the master etisserant@0: that it is going to enter into operational state etisserant@0: In fact, you must send the boot-up when you are in etisserant@0: operational mode ! etisserant@0: */ etisserant@0: etisserant@0: /* change automatically into pre_operational state */ etisserant@0: lastState = getState(); etisserant@0: setState(Pre_operational); etisserant@0: break; etisserant@0: etisserant@0: case Pre_operational: etisserant@0: if (lastState != getState()) etisserant@0: { etisserant@0: MSG_WAR(0X3F11, "I am in PRE_OPERATIONAL mode ", 0); etisserant@0: // Some stuff to do when the node enter in pre-operational mode etisserant@0: initPreOperationalMode(); etisserant@0: } etisserant@0: if (lastState == Initialisation) etisserant@0: slaveSendBootUp(0); etisserant@0: lastState = getState(); etisserant@0: preOperational( ); etisserant@0: break; etisserant@0: etisserant@0: case Operational: etisserant@0: if (lastState != getState()) etisserant@0: MSG_WAR(0X3F12, "I am in OPERATIONAL mode ", 0); etisserant@0: lastState = getState(); etisserant@0: operational( ); etisserant@0: break; etisserant@0: etisserant@0: case Stopped: etisserant@0: if (lastState != getState()) etisserant@0: MSG_WAR(0X3F13, "I am in STOPPED mode", 0); etisserant@0: lastState = getState(); etisserant@0: stopped( ); etisserant@0: break; etisserant@0: }//end switch case etisserant@0: // Sleep 10 ms etisserant@0: usleep(10000); etisserant@0: }//end while etisserant@0: }//end else etisserant@0: etisserant@0: etisserant@0: return 0; etisserant@0: } etisserant@0: