examples/AppliMaster_Linux/appli.c
changeset 93 16c8ceea8f18
parent 92 0d84d95790d9
child 94 bdf4c86be6b2
equal deleted inserted replaced
92:0d84d95790d9 93:16c8ceea8f18
     1 /*
       
     2 This file is part of CanFestival, a library implementing CanOpen Stack. 
       
     3 
       
     4 Copyright (C): Edouard TISSERANT and Francis DUPIN
       
     5 
       
     6 See COPYING file for copyrights details.
       
     7 
       
     8 This library is free software; you can redistribute it and/or
       
     9 modify it under the terms of the GNU Lesser General Public
       
    10 License as published by the Free Software Foundation; either
       
    11 version 2.1 of the License, or (at your option) any later version.
       
    12 
       
    13 This library is distributed in the hope that it will be useful,
       
    14 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16 Lesser General Public License for more details.
       
    17 
       
    18 You should have received a copy of the GNU Lesser General Public
       
    19 License along with this library; if not, write to the Free Software
       
    20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    21 */
       
    22 
       
    23 #include <stdio.h>
       
    24 #include <string.h>
       
    25 #include <sys/time.h>
       
    26 #include <pthread.h>
       
    27 #include <unistd.h>
       
    28 #include <stdlib.h>
       
    29 
       
    30 
       
    31 #include <applicfg.h>
       
    32 #include <timerhw.h>
       
    33 #include <linuxCan.h>
       
    34 
       
    35 #include "def.h"
       
    36 #include "can.h"
       
    37 #include "objdictdef.h"
       
    38 #include "objacces.h"
       
    39 #include "canOpenDriver.h"
       
    40 #include "sdo.h"
       
    41 #include "pdo.h"
       
    42 #include "init.h"
       
    43 #include "timer.h"
       
    44 #include "lifegrd.h"
       
    45 #include "sync.h"
       
    46 
       
    47 #include "nmtMaster.h"
       
    48 
       
    49 
       
    50 
       
    51 // For prototype of exit();
       
    52 #define exit _exit
       
    53  
       
    54 
       
    55 // Adlink 7841 or Peak PCI/CAN board
       
    56 // ---------------------------------
       
    57 
       
    58 // Baudrate values for Peak board :
       
    59 // CAN_BAUD_1M CAN_BAUD_500K CAN_BAUD_250K CAN_BAUD_125K CAN_BAUD_100K CAN_BAUD_50K
       
    60 // CAN_BAUD_20K CAN_BAUD_10K CAN_BAUD_5K
       
    61 
       
    62 #ifdef CAN_BAUD_250K
       
    63 # define BAUDRATE CAN_BAUD_250K
       
    64 #else
       
    65 // Appli have been compiled for Adlink-arbraca. Baudrate not used
       
    66 # define BAUDRATE 0
       
    67 #endif
       
    68 
       
    69 s_BOARD board = {"0", BAUDRATE};
       
    70 
       
    71 
       
    72 // Required definition variables
       
    73 // -----------------------------
       
    74 // The variables that you should define for debugging.
       
    75 // They are used by the macro MSG_ERR and MSG_WAR in applicfg.h
       
    76 // if the node is a slave, they can be mapped in the object dictionnary.
       
    77 
       
    78 UNS8 printMsgErrToConsole = 1;
       
    79 UNS8 printMsgWarToConsole = 1;
       
    80 
       
    81 // The variables mapped in the object dictionnary
       
    82 // ----------------------------------------------
       
    83 extern UNS32 canopenErrNB_node5;   // Mapped at index 0x6000, subindex 0x0
       
    84 extern UNS32 canopenErrVAL_node5;  // Mapped at index 0x6001, subindex 0x0
       
    85 extern UNS8 second;		   // Mapped at index 0x6002, subindex 0x1
       
    86 extern UNS8 minutes;		   // Mapped at index 0x6002, subindex 0x2
       
    87 extern UNS8 hour;		   // Mapped at index 0x6002, subindex 0x3
       
    88 extern UNS8 day;		   // Mapped at index 0x6002, subindex 0x4
       
    89 extern UNS32 canopenErrNB;	   // Mapped at index 0x6003, subindex 0x1
       
    90 extern UNS32 canopenErrVAL;	   // Mapped at index 0x6003, subindex 0x2
       
    91 
       
    92       
       
    93 /*************************User's variables declaration**************************/
       
    94 pthread_t threadM;
       
    95 pthread_t threadH;
       
    96 pthread_t threadS;
       
    97 UNS8 connectedNode[128];
       
    98 
       
    99 /* The variable to map in a PDO is defined at index and subIndex. Its length is size bytes */
       
   100 typedef struct mappedVar 
       
   101 {
       
   102   UNS32 index;
       
   103   UNS8  subIndex;
       
   104   UNS8  size; // in byte
       
   105 } s_mappedVar;
       
   106 
       
   107 typedef struct heartbeatConsumer
       
   108 {
       
   109   UNS8 nodeProducer;
       
   110   UNS16 time_ms;
       
   111 } s_heartbeatConsumer;
       
   112 
       
   113 /**************************prototypes*****************************************/
       
   114 /* You *must* have these 2 functions in your code*/
       
   115 void heartbeatError (UNS8 heartbeatID );
       
   116 void SD0timeoutError(UNS8 bus_id, UNS8 line);
       
   117 
       
   118 void waitMessage (void );
       
   119 void heartBeat (void );
       
   120 void transmitSync (void);
       
   121 e_nodeState stateNode (UNS8 node);
       
   122 void configure_master_SDO (UNS32 index, UNS8 serverNode);
       
   123 UNS8 waitingWriteToSlaveDict (UNS8 slaveNode, UNS8 error);
       
   124 UNS8 waitingReadToSlaveDict (UNS8 slaveNode, void * data, UNS8 * size, UNS8 error);
       
   125 UNS8 configure_client_SDO (UNS8 slaveNode, UNS8 clientNode);
       
   126 void masterMappingPDO (UNS32 indexPDO, UNS32 cobId, 
       
   127 		      s_mappedVar *tabMappedVar, UNS8 nbVar);
       
   128 void slaveMappingPDO (UNS8 slaveNode, UNS32 indexPDO, UNS32 cobId, 
       
   129 		     s_mappedVar *tabMappedVar, UNS8 nbVar);
       
   130 void masterHeartbeatConsumer (s_heartbeatConsumer 
       
   131 			     *tabHeartbeatConsumer, UNS8 nbHeartbeats);
       
   132 void masterHeartbeatProducer (UNS16 time);
       
   133 void slaveHeartbeatConsumer (UNS8 slaveNode, s_heartbeatConsumer 
       
   134 			    *tabHeartbeatConsumer, UNS8 nbHeartbeats);
       
   135 void slaveHeartbeatProducer (UNS8 slaveNode, UNS16 time);
       
   136 void masterPDOTransmissionMode (UNS32 indexPDO,  UNS8 transType);
       
   137 void slavePDOTransmissionMode (UNS8 slaveNode, UNS32 indexPDO,  UNS8 transType);
       
   138 void masterSYNCPeriod (UNS32 SYNCPeriod);
       
   139 int main (int argc,char **argv);
       
   140 
       
   141 /*****************************************************************************/
       
   142 void heartbeatError(UNS8 heartbeatID)
       
   143 {
       
   144   // MSG_ERR should send the values canopenErrNB and canopenErrVAL on event in a PDO,
       
   145   // But we do not have mapped the variables in a PDO, so it sends nothing.
       
   146   // See the note at the end of END CONFIGURING THE NETWORK.
       
   147   MSG_WAR(0x2F00, "HeartBeat, no response from node : ", heartbeatID);
       
   148 }
       
   149 
       
   150 /*****************************************************************************/
       
   151 void SD0timeoutError (UNS8 bus_id, UNS8 line)
       
   152 {
       
   153   // Informations on what occurs are in transfers[bus_id][line]....
       
   154   // See scanSDOtimeout() in sdo.c
       
   155 }
       
   156 
       
   157 /*********************************** THREADS **********************************/
       
   158 //------------------------------------------------------------------------------
       
   159 // Wait for a received message
       
   160 void waitMessage(void)
       
   161 {       
       
   162   while (1) {
       
   163     receiveMsgHandler(0); // blocked until new message
       
   164   }
       
   165 }
       
   166 
       
   167 //------------------------------------------------------------------------------
       
   168 /* Sending SYNC */
       
   169 void transmitSync(void)
       
   170 {
       
   171   while (1) {
       
   172   computeSYNC(); // Use the value in the dictionnary
       
   173   usleep(1000); // Sleep 1 ms
       
   174 
       
   175   }
       
   176 }
       
   177 
       
   178 /************************** FUNCTIONS TO CONFIGURE THE NETWORK******************/
       
   179 
       
   180 
       
   181 
       
   182 //------------------------------------------------------------------------------
       
   183 /* Node mode result after NodeGuard query */
       
   184 e_nodeState stateNode(UNS8 node) 
       
   185 {
       
   186   e_nodeState state = getNodeState(0, node);
       
   187   switch (state) {
       
   188   case Unknown_state: 
       
   189     MSG_WAR(0x3F05, "Not connected (Does not have sent its status) node :", node);
       
   190     break;
       
   191   case Operational: 
       
   192     MSG_WAR(0x3F06, "Ok, in operational mode, node : ", node);
       
   193     break;
       
   194   case Pre_operational: 
       
   195     MSG_WAR(0x3F07, "OK in pre-operational mode, node : ", node);
       
   196     break;
       
   197   default:
       
   198     MSG_WAR(0x3F08, "OK connected but in curious mode, node : ", node);
       
   199   }
       
   200   return state;
       
   201 }
       
   202 
       
   203 //------------------------------------------------------------------------------
       
   204 /* The master is writing in its dictionnary to configure the SDO parameters 
       
   205 to communicate with server_node
       
   206 */
       
   207 void configure_master_SDO(UNS32 index, UNS8 serverNode)
       
   208 {
       
   209   UNS32 data32;
       
   210   UNS8  data8;
       
   211   UNS8 sizeData = 4 ; // in bytes
       
   212 
       
   213   /* At subindex 1, the cobId of the Can message from the client.
       
   214   It is always defined inside the server dictionnary as 0x600 + server_node.
       
   215   So, we have no choice here ! */
       
   216   data32 = 0x600 + serverNode;
       
   217   setODentry(index, 1, &data32, sizeData, 0);
       
   218 
       
   219   {
       
   220     // Test
       
   221     UNS32  *pbData;
       
   222     UNS8 length;
       
   223     UNS32 returnValue;
       
   224     UNS8 dataType;
       
   225     // Relecture
       
   226     MSG_WAR(0x1000, "Reading index : ", index);
       
   227     MSG_WAR(0x1000, "     subindex : ", 1);
       
   228     returnValue = getODentry(index, 1, (void * *)&pbData, (UNS8 *)&length, &dataType, 0);
       
   229     MSG_WAR(0x1000, "          val : ", *pbData);
       
   230   }
       
   231 
       
   232 
       
   233   /* At subindex 2, the cobId of the Can message from the server to the client.
       
   234   It is always defined inside the server dictionnary as 0x580 + client_node.
       
   235   So, we have no choice here ! */
       
   236   data32 = 0x580 + serverNode;
       
   237   setODentry(index, 2, &data32, sizeData, 0);
       
   238 
       
   239   /* At subindex 3, the node of the server */
       
   240   data8 = serverNode;
       
   241   sizeData = 1;
       
   242   setODentry(index, 3, &data8, sizeData, 0);
       
   243 
       
   244   {
       
   245     UNS8  *pbData;
       
   246     UNS8 length;
       
   247     UNS32 returnValue;
       
   248     UNS8 dataType;
       
   249     // Relecture
       
   250     MSG_WAR(0x1000, "Reading  index : ", index);
       
   251     MSG_WAR(0x1000, "      subindex : ", 3);
       
   252     returnValue = getODentry(index, 1, (void * *)&pbData, (UNS8 *)&length, &dataType, 0);
       
   253     MSG_WAR(0x1000, "           val : ", *pbData);
       
   254   }
       
   255 }
       
   256 
       
   257 //------------------------------------------------------------------------------
       
   258 /*
       
   259  */
       
   260 UNS8 waitingWriteToSlaveDict(UNS8 slaveNode, UNS8 error)
       
   261 {
       
   262   UNS8 err;
       
   263   UNS32 abortCode;
       
   264   MSG_WAR(0x3F21, "Sending SDO to write in dictionnary of node : ", slaveNode);
       
   265   if (error) {
       
   266     MSG_ERR(0x1F22, "Unable to send the SDO to node ", slaveNode);
       
   267     return -1;
       
   268   }
       
   269   /* Waiting until the slave has responded */
       
   270   while (getWriteResultNetworkDict (0, slaveNode, &abortCode) == SDO_DOWNLOAD_IN_PROGRESS) {
       
   271     // Check if some SDO response are missing
       
   272     scanSDOtimeout();
       
   273   }
       
   274 
       
   275   err = getWriteResultNetworkDict (0, slaveNode, &abortCode);
       
   276   if (err == SDO_FINISHED) {
       
   277     MSG_WAR(0x3F22, "SDO download finished to Node : ", slaveNode);
       
   278     // Release the line. Don't forget !!!
       
   279     closeSDOtransfer(0, slaveNode, SDO_CLIENT);
       
   280     return 0;
       
   281   }
       
   282 
       
   283   if (err == SDO_ABORTED_RCV) {
       
   284     MSG_WAR(0x2F20, "Received SDO abort from node : ", slaveNode);
       
   285   }
       
   286 
       
   287   if (err == SDO_ABORTED_INTERNAL) {
       
   288     MSG_WAR(0x2F20, "Internal SDO abort for node : ", slaveNode);
       
   289   }
       
   290   // Looking for the line transfert number to read the index, subindex and releasing the line.
       
   291   {
       
   292     UNS8 line;
       
   293     err = getSDOlineOnUse(0, slaveNode, SDO_CLIENT, &line);
       
   294     if (err) {
       
   295       MSG_WAR(0x2F21, "No line found for node : ", slaveNode);
       
   296       exit(-1);
       
   297     }
       
   298     MSG_WAR (0x2F22, "while writing at his index : ", transfers[0][line].index);
       
   299     MSG_WAR (0x2F23, "                  subIndex : ", transfers[0][line].subIndex);
       
   300     //Releasing the line.
       
   301     closeSDOtransfer(0, slaveNode, SDO_CLIENT);
       
   302     exit(-1);
       
   303   }
       
   304  return 0;
       
   305 }
       
   306 
       
   307 //------------------------------------------------------------------------------
       
   308 /*
       
   309  */
       
   310 UNS8 waitingReadToSlaveDict(UNS8 slaveNode, void * data, UNS8 * size, UNS8 error)
       
   311 {
       
   312   UNS8 err;
       
   313   UNS32 abortCode;
       
   314   MSG_WAR(0x3F2A, "Sending SDO to read in dictionnary of node : ", slaveNode);
       
   315   if (error) {
       
   316     MSG_ERR(0x1F2B, "Unable to send the SDO to node ", slaveNode);
       
   317     return -1;
       
   318   }
       
   319   /* Waiting until the slave has responded */
       
   320   while (getReadResultNetworkDict (0, slaveNode, data, size, &abortCode) == SDO_UPLOAD_IN_PROGRESS) {
       
   321     // Check if some SDO response are missing
       
   322     scanSDOtimeout();
       
   323   }
       
   324   err = getReadResultNetworkDict (0, slaveNode, data, size, &abortCode);
       
   325   if (err == SDO_FINISHED) {
       
   326     MSG_WAR(0x3F2C, "SDO upload finished to Node : ", slaveNode);
       
   327     // Release the line. Don't forget !!!
       
   328     closeSDOtransfer(0, slaveNode, SDO_CLIENT);
       
   329     return 0;
       
   330   }
       
   331   if (err == SDO_ABORTED_RCV) {
       
   332     MSG_WAR(0x2F2D, "Received SDO abort from node : ", slaveNode);
       
   333   }
       
   334 
       
   335   if (err == SDO_ABORTED_INTERNAL) {
       
   336     MSG_WAR(0x2F2E, "Internal SDO abort for node : ", slaveNode);
       
   337   }
       
   338   // Looking for the line transfert number to read the index, subindex and releasing the line.
       
   339   {
       
   340     UNS8 line;
       
   341     err = getSDOlineOnUse(0, slaveNode, SDO_CLIENT, &line);
       
   342     if (err) {
       
   343       MSG_WAR(0x2F2F, "No line found for node : ", slaveNode);
       
   344       exit(-1);
       
   345     }
       
   346     MSG_WAR (0x2F30, "while writing at his index : ", transfers[0][line].index);
       
   347     MSG_WAR (0x2F31, "                  subIndex : ", transfers[0][line].subIndex);
       
   348     //Releasing the line.
       
   349     closeSDOtransfer(0, slaveNode, SDO_CLIENT);
       
   350     exit(-1);
       
   351   }    
       
   352 
       
   353  return 0;
       
   354 }
       
   355 
       
   356 
       
   357 //------------------------------------------------------------------------------
       
   358 /* The master is writing in the slave dictionnary to configure the SDO parameters
       
   359 Remember that the slave is the server, and the master is the client.
       
   360  */ 
       
   361 UNS8 configure_client_SDO(UNS8 slaveNode, UNS8 clientNode)
       
   362 {
       
   363   UNS8 data;
       
   364   UNS8 NbDataToWrite = 1 ; // in bytes
       
   365   UNS8 err = 0;
       
   366   MSG_WAR(0x3F20, "Configuring SDO by writing in dictionnary Node", slaveNode);
       
   367   /* It is only to put at subindex 3 the serverNode. It is optionnal.
       
   368      In the slave dictionary, only one SDO server is defined, at index 
       
   369      0x1200 */
       
   370   data = clientNode;
       
   371   err = writeNetworkDict(0, slaveNode, 0x1200, 3, NbDataToWrite, 0, &data); 
       
   372   waitingWriteToSlaveDict(slaveNode, err);
       
   373  
       
   374   return 0;
       
   375 }		
       
   376   
       
   377 //------------------------------------------------------------------------------
       
   378 
       
   379 void masterMappingPDO(UNS32 indexPDO, UNS32 cobId, 
       
   380 		      s_mappedVar *tabMappedVar, UNS8 nbVar)
       
   381 {
       
   382   UNS32 *pbData;
       
   383   UNS32 data32; 
       
   384   UNS8 i;
       
   385   UNS8 size = 0;
       
   386   UNS8 dataType;
       
   387 
       
   388   if ((indexPDO >= 0x1400) && (indexPDO <= 0x15FF))
       
   389     MSG_WAR(0x3F30, "Configuring MASTER for PDO receive, COBID : ", cobId);
       
   390 
       
   391   if ((indexPDO >= 0x1800) && (indexPDO <= 0x19FF))
       
   392     MSG_WAR(0x3F31, "Configuring MASTER for PDO transmit, COBID : ", cobId);
       
   393 
       
   394   /* At indexPDO, subindex 1, defining the cobId of the PDO */
       
   395   setODentry(indexPDO, 1, &cobId, 4, 0);
       
   396   /* The mapping ... */
       
   397   /* ----------------*/
       
   398   /* At subindex 0, the number of variables in the PDO */
       
   399   setODentry(indexPDO + 0x200, 0, &nbVar, 1, 0);
       
   400   getODentry(indexPDO + 0x200, 0, (void * *)&pbData, &size, &dataType, 0);
       
   401   /* At each subindex 1 .. nbVar, The index,subindex and size of the variable to map in 
       
   402      the PDO. The first variable after the COBID is defined at subindex 1, ... 
       
   403      The data to write is the concatenation on 32 bits of (msb ... lsb) : 
       
   404      index(16b),subIndex(8b),sizeVariable(8b)
       
   405 */
       
   406   for (i = 0 ; i < nbVar ; i++) {
       
   407     data32 = ((tabMappedVar + i)->index << 16) |
       
   408       (((tabMappedVar + i)->subIndex & 0xFF) << 8) |
       
   409       ((tabMappedVar + i)->size & 0xFF);
       
   410     // Write dictionary
       
   411     setODentry(indexPDO + 0x200, i + 1, &data32, 4, 0);
       
   412 
       
   413 #   ifdef MORE_COMMENTS
       
   414     printf("Mapped variable defined  at index 0x%X, subIndex 0x%X, %d bits\n", 
       
   415 	   (tabMappedVar + i)->index, (tabMappedVar + i)->subIndex, 8 * (tabMappedVar + i)->size);
       
   416     // Only to verify.
       
   417     // Read dictionnary
       
   418     getODentry(indexPDO + 0x200, i + 1, (void * *)&pbData, &size, &dataType, 0);
       
   419     printf("Writen à  index 0x%X, subIndex 0x%X, %d bits : 0x%08X\n", 
       
   420 	   indexPDO + 0x200, i + 1, 8 * size, *pbData);
       
   421 #   endif
       
   422     
       
   423   }
       
   424 }
       
   425 
       
   426 //------------------------------------------------------------------------------
       
   427 /*
       
   428  */
       
   429 
       
   430 void slaveMappingPDO(UNS8 slaveNode, UNS32 indexPDO, UNS32 cobId, 
       
   431 		     s_mappedVar *tabMappedVar, UNS8 nbVar)
       
   432 {
       
   433   UNS32 data32; 
       
   434   UNS8 i;
       
   435   UNS8 err;
       
   436   UNS8 nbBytes = 1;
       
   437   if ((indexPDO >= 0x1400) && (indexPDO <= 0x15FF))
       
   438     MSG_WAR(0x3F32, "Configuring slave for PDO receive, COBID : ", cobId);
       
   439 
       
   440   if ((indexPDO >= 0x1800) && (indexPDO <= 0x19FF))
       
   441     MSG_WAR(0x3F33, "Configuring slave for PDO transmit, COBID : ", cobId);
       
   442 
       
   443   /* At indexPDO, subindex 1, defining the cobId of the PDO */
       
   444   err = writeNetworkDict(0, slaveNode, indexPDO, 1, 4, 0, &cobId); 
       
   445   waitingWriteToSlaveDict(slaveNode, err);
       
   446 
       
   447   /* The mapping ... */
       
   448   /* ----------------*/
       
   449   /* At subindex 0, the number of variables in the PDO */
       
   450   err = writeNetworkDict(0, slaveNode, indexPDO + 0x200, 0, nbBytes, 0, &nbVar); 
       
   451   waitingWriteToSlaveDict(slaveNode, err);
       
   452 
       
   453   /* At each subindex 1 .. nbVar, The index,subindex and size of the variable to map in 
       
   454      the PDO. The first variable after the COBID is defined at subindex 1, ... 
       
   455      The data to write is the concatenation on 32 bits of (msb ... lsb) : 
       
   456      index(16b),subIndex(8b),sizeVariable(8b)
       
   457 */
       
   458   for (i = 0 ; i < nbVar ; i++) {
       
   459     data32 = ((tabMappedVar + i)->index << 16) |
       
   460       (((tabMappedVar + i)->subIndex & 0xFF) << 8) |
       
   461       ((tabMappedVar + i)->size & 0xFF);
       
   462 
       
   463     // Write dictionary
       
   464     err = writeNetworkDict(0, slaveNode, indexPDO + 0x200, i + 1, 4, 0, &data32); 
       
   465     waitingWriteToSlaveDict(slaveNode, err);
       
   466 
       
   467 #   ifdef MORE_COMMENTS
       
   468     printf("Mapped variable defined  at index 0x%X, subIndex 0x%X, %d bits\n", 
       
   469 	   (tabMappedVar + i)->index, (tabMappedVar + i)->subIndex, 8 * (tabMappedVar + i)->size);
       
   470 
       
   471     printf("At node 0x%X Writen at  index 0x%X, subIndex 0x%X, %d bits : 0x%08X\n", 
       
   472 	   slaveNode, indexPDO + 0x200, i + 1, 32, data32);
       
   473 #   endif
       
   474     
       
   475   }
       
   476 }
       
   477 
       
   478 //------------------------------------------------------------------------------
       
   479 /*
       
   480  */
       
   481 void masterHeartbeatConsumer(s_heartbeatConsumer 
       
   482 			     *tabHeartbeatConsumer, UNS8 nbHeartbeats)
       
   483 {
       
   484   UNS32 data;
       
   485   UNS8 i;
       
   486   UNS8 nbHB = nbHeartbeats;
       
   487 
       
   488   MSG_WAR(0x3F40, "Configuring heartbeats consumers for master", 0);
       
   489   /* At index 1016, subindex 0 : the nb of consumers (ie nb of nodes of which are expecting heartbeats) */
       
   490   setODentry(0x1016, 0, & nbHB, 1, 0);
       
   491   
       
   492   /* At Index 1016, subindex 1, ... : 32 bit values : msb ... lsb :
       
   493      00 - node_consumer (8b) - time_ms (16b)
       
   494      Put 0 to ignore the entry.
       
   495   */
       
   496   for (i = 0 ; i < nbHeartbeats ; i++) {
       
   497     data = (((tabHeartbeatConsumer + i)->nodeProducer & 0xFF)<< 16) | ((tabHeartbeatConsumer + i)->time_ms & 0xFFFF);
       
   498     setODentry(0x1016, i + 1, & data, 4, 0);
       
   499   }
       
   500 }
       
   501 
       
   502 //------------------------------------------------------------------------------
       
   503 /*
       
   504  */
       
   505 
       
   506 void masterHeartbeatProducer(UNS16 time)
       
   507 {
       
   508   UNS16 hbTime = time;
       
   509   MSG_WAR(0x3F45, "Configuring heartbeat producer for master", 0);
       
   510   /* At index 1017, subindex 0, defining the time to send the heartbeat. Put 0 to never send heartbeat */
       
   511   setODentry(0x1017, 0, &hbTime, 2, 0);
       
   512 }
       
   513 
       
   514 //------------------------------------------------------------------------------
       
   515 /*
       
   516  */
       
   517 void slaveHeartbeatConsumer(UNS8 slaveNode, s_heartbeatConsumer 
       
   518 			    *tabHeartbeatConsumer, UNS8 nbHeartbeats)
       
   519 {
       
   520   UNS32 data;
       
   521   UNS8 err;
       
   522   UNS8 i;
       
   523   
       
   524   MSG_WAR(0x3F46, "Configuring heartbeats consumers for node  : ", slaveNode);
       
   525   
       
   526   /* At Index 1016, subindex 1, ... : 32 bit values : msb ... lsb :
       
   527      00 - node_consumer (8b) - time_ms (16b)
       
   528      Put 0 to ignore the entry.
       
   529   */
       
   530   for (i = 0 ; i < nbHeartbeats ; i++) {
       
   531     data = (((tabHeartbeatConsumer + i)->nodeProducer & 0xFF)<< 16) | 
       
   532       ((tabHeartbeatConsumer + i)->time_ms & 0xFFFF);
       
   533     err = writeNetworkDict(0, slaveNode, 0x1016, i + 1, 4, 0, &data); 
       
   534     waitingWriteToSlaveDict(slaveNode, err);
       
   535   }
       
   536 }
       
   537 
       
   538 //------------------------------------------------------------------------------
       
   539 /*
       
   540  */
       
   541 
       
   542 void slaveHeartbeatProducer(UNS8 slaveNode, UNS16 time)
       
   543 {
       
   544   UNS8 err;
       
   545   MSG_WAR(0x3F47, "Configuring heartbeat producer for node  : ", slaveNode);
       
   546   /* At index 1017, subindex 0, defining the time to send the heartbeat. Put 0 to never send heartbeat */
       
   547 
       
   548   err = writeNetworkDict(0, slaveNode, 0x1017, 0, 2, 0, &time); 
       
   549   waitingWriteToSlaveDict(slaveNode, err);
       
   550 }
       
   551 
       
   552 //------------------------------------------------------------------------------
       
   553 /*
       
   554  */
       
   555 
       
   556 void masterPDOTransmissionMode(UNS32 indexPDO,  UNS8 transType)
       
   557 {
       
   558   MSG_WAR(0x3F48, "Configuring transmission from master, indexPDO : ", indexPDO);
       
   559  
       
   560   /* At subindex 2, the transmission type */
       
   561   setODentry(indexPDO, 2, &transType, 1, 0);
       
   562 }
       
   563 
       
   564 
       
   565 //------------------------------------------------------------------------------
       
   566 /*
       
   567  */
       
   568 
       
   569 void slavePDOTransmissionMode(UNS8 slaveNode, UNS32 indexPDO,  UNS8 transType)
       
   570 {
       
   571   UNS8 err;
       
   572   MSG_WAR(0x3F41, "Configuring transmission mode for node : ", slaveNode);
       
   573   MSG_WAR(0x3F42, "                              indexPDO : ", indexPDO);
       
   574 
       
   575   err = writeNetworkDict(0, slaveNode, indexPDO, 2, 1, 0, &transType); 
       
   576   waitingWriteToSlaveDict(slaveNode, err);
       
   577 
       
   578 }
       
   579 
       
   580 //------------------------------------------------------------------------------
       
   581 /*
       
   582  */
       
   583 
       
   584 void masterSYNCPeriod(UNS32 SYNCPeriod)
       
   585 {
       
   586   UNS32 cobId = 0x40000080;
       
   587   MSG_WAR(0x3F49, "Configuring master to send SYNC every ... micro-seconds :", SYNCPeriod);
       
   588   /* At index 0x1006, subindex 0 : the period in ms */
       
   589   setODentry(0x1006, 0, &SYNCPeriod , 4, 0);
       
   590   /* At index 0x1005, subindex 0 : Device generate SYNC signal with CobId 0x80 */
       
   591   setODentry(0x1005, 0, &cobId, 4, 0);
       
   592 }
       
   593 
       
   594 void help()
       
   595 {
       
   596   printf("**************************************************************\n");
       
   597   printf("*  AppliMaster                                               *\n");
       
   598   printf("*                [-b b]                                      *\n");
       
   599   printf("*                                                            *\n");
       
   600   printf("*     b : bus [default 0]                                    *\n");
       
   601   printf("*                                                            *\n");
       
   602   printf("*  This exemple run AppliMaster on bus 0                     *\n");
       
   603   printf("*   AppliMaster -b 0                                         *\n");
       
   604   printf("*                                                            *\n");
       
   605   printf("**************************************************************\n");
       
   606 }
       
   607 
       
   608 /****************************************************************************/
       
   609 /***************************  MAIN  *****************************************/
       
   610 /****************************************************************************/
       
   611 int main(int argc,char **argv)
       
   612 {
       
   613   UNS8 second_last;
       
   614   UNS8 minutes_last;
       
   615   UNS8 sendingResetError = 0;
       
   616   int i;
       
   617   HANDLE ok;
       
   618   char c;
       
   619   extern char *optarg;
       
   620 
       
   621   while ((c = getopt(argc, argv, "-b:")) != EOF)
       
   622   {
       
   623     switch(c)
       
   624     {
       
   625       case 'b' :
       
   626         if (optarg[0] == 0)
       
   627         {
       
   628           help();
       
   629           exit(1);
       
   630         }
       
   631         board.busname = optarg;
       
   632         break;
       
   633       default:
       
   634         help();
       
   635         exit(1);
       
   636     }
       
   637   }
       
   638 
       
   639   /****************************** INITIALISATION *******************************/
       
   640   
       
   641   /* Launch the timer*/
       
   642     initTimer( );
       
   643 
       
   644   /* arrays initialisation, etc */
       
   645   initCANopenMain();     
       
   646       
       
   647   /* arrays initialisation, etc */
       
   648   initCANopenMaster();  
       
   649 
       
   650   /* Defining the node Id */
       
   651   setNodeId(0x01);
       
   652   MSG_WAR(0x3F50, "My node ID is : ", getNodeId()); 
       
   653 
       
   654   /* Put the master in operational mode */
       
   655   setState(Operational);
       
   656 
       
   657 
       
   658   /* Init the table of connected nodes */
       
   659   for (i = 0 ; i < 128 ; i++)
       
   660     connectedNode[i] = 0;
       
   661 
       
   662   
       
   663   ok = f_can_open(& board);
       
   664   if (ok == NULL) {
       
   665     MSG_ERR(0x1F02,"Unable to open the board", 0);
       
   666     MSG_ERR(0x1F03,"Edit includeMakefileLinux to verify that the application is configured for the good board", 0);
       
   667     exit (-1);
       
   668   }
       
   669   else {
       
   670     MSG_WAR(0x3F03, "Board 0 opened ", 0);
       
   671   }
       
   672   
       
   673 
       
   674   /* Launch the thread to receive the messages */
       
   675   pthread_create( &threadM, NULL, (void *)&waitMessage, NULL);	
       
   676 
       
   677 
       
   678 
       
   679 
       
   680 
       
   681 
       
   682 
       
   683 
       
   684 
       
   685 
       
   686 
       
   687 
       
   688 
       
   689 
       
   690 
       
   691   /******************** CONFIGURING THE NETWORK **************************/
       
   692   
       
   693   /* Which nodes are connected ? */
       
   694   /* Sending a request Node guard to node 5 and 6 */
       
   695   MSG_WAR(0x3F04, "Sending a node guard to node : ", 5);
       
   696   masterReadNodeState(0, 0x05);
       
   697   /* Sending a message to the node 6, only as example */
       
   698   MSG_WAR(0x3F04, "Sending a node guard to node : ", 6);
       
   699   masterReadNodeState(0, 0x06);
       
   700   /* Waiting for a second the response */
       
   701   sleep(1);
       
   702   
       
   703   /* Whose node have answered ? */
       
   704   connectedNode[5] = stateNode(5);
       
   705   connectedNode[6] = stateNode(6);
       
   706 
       
   707   /* Configure the SDO master to communicate with node 5 and node 6 */
       
   708   configure_master_SDO(0x1280, 0x05);
       
   709 
       
   710 
       
   711   /* Configure the SDO of node 5 */
       
   712   /* getNodeId() returns my node Id */
       
   713   configure_client_SDO(0x05, getNodeId());
       
   714   /* Mapping of the PDO 
       
   715      Chose some COBID in (hexa) 181-1FF, 201-27F, 281-2FF, 301-37F, 
       
   716      381-3FF, 401-47F, 481-4FF, 501-57F,
       
   717      without other restriction.
       
   718      (Of course, you must not define 2 PDO transmit with the same cobId !!)
       
   719   */
       
   720  
       
   721   /*
       
   722      *** PDO node 1 <-- node 5 ***
       
   723      *** cobId 0x181 *************
       
   724      MASTER (node 1)
       
   725      Mapped to variables (node1) [index-subindex-size_bits]: 
       
   726        day    [0x6002 - 0x04 - 8]
       
   727        hour   [0x6002 - 0x03 - 8]
       
   728        second [0x6002 - 0x01 - 8]
       
   729 
       
   730      SLAVE (node 5)
       
   731      Mapped to variables (node5) [index-subindex-size_bits]: 
       
   732        day    [0x2000 - 0x04 - 8]
       
   733        hour   [0x2000 - 0x03 - 8]
       
   734        second [0x2000 - 0x01 - 8]
       
   735 */
       
   736 
       
   737   /* Configuring the first PDO receive, defined at index 0x1400 and 0x1600 */
       
   738   {
       
   739     s_mappedVar tabMappedVar[8] = { {0x6002,4,8}, {0x6002,3,8}, {0x6002,1,8}, };
       
   740     masterMappingPDO(0x1400, 0x181, tabMappedVar, 3);
       
   741   }
       
   742 
       
   743   /* Configuring the first PDO transmit, defined at index 0x1800 and 0x1A00 */
       
   744   {
       
   745     s_mappedVar tabMappedVar[8] = { {0x2000,4,8}, {0x2000,3,8}, {0x2000,1,8}, };
       
   746     slaveMappingPDO(0x05, 0x1800, 0x181, tabMappedVar, 3);
       
   747   }
       
   748    /*
       
   749      *** PDO node 1 <-- node 5 ***
       
   750      *** cobId 0x182 *************
       
   751      MASTER (node 1)
       
   752      Mapped to variables (node1) [index-subindex-size_bits]: 
       
   753        minute    [0x6002 - 0x02 - 8]
       
   754 
       
   755      SLAVE (node 5)
       
   756      Mapped to variables (node5) [index-subindex-size_bits]: 
       
   757        minute    [0x2000 - 0x02 - 8]
       
   758    */
       
   759 
       
   760   /* Configuring PDO receive, defined at index 0x1400 and 0x1600 */
       
   761   {
       
   762     s_mappedVar tabMappedVar[8] = { {0x6002,2,8} };
       
   763     masterMappingPDO(0x1401, 0x182, tabMappedVar, 1);
       
   764   }
       
   765 
       
   766   /* Configuring PDO transmit, defined at index 0x1800 and 0x1A00 */
       
   767   {
       
   768     s_mappedVar tabMappedVar[8] = { {0x2000,2,8} };
       
   769     slaveMappingPDO(0x05, 0x1801, 0x182, tabMappedVar, 1);
       
   770   }
       
   771 
       
   772 
       
   773   /*
       
   774      *** PDO node 1 <-- node 5 ***
       
   775      *** cobId 0x183 *************
       
   776      Error management :  By this way, The node can send by PDO an error
       
   777      MASTER (node 1)
       
   778      Mapped to variables (node1) [index-subindex-size_bits]: 
       
   779        canopenErrNb_node5   [0x6000 - 0x00 - 32]
       
   780        canopenErrVal_node5  [0x6001 - 0x00 - 32] 
       
   781 
       
   782      SLAVE (node 5)
       
   783      Mapped to variables (node5) [index-subindex-size_bytes]: 
       
   784        canopenErrNb     [0x6000 - 0x00 - 32]
       
   785        canopenErrVal    [0x6001 - 0x00 - 32]  
       
   786   */
       
   787 
       
   788   /* Configuring  PDO receive, defined at index 0x1402 and 0x1602 */
       
   789   {
       
   790     s_mappedVar tabMappedVar[8] = { {0x6000,0,32}, {0x6001, 0, 32}};
       
   791     masterMappingPDO(0x1402, 0x183, tabMappedVar, 2);
       
   792   }
       
   793 
       
   794   /* Configuring PDO transmit, defined at index 0x1802 and 0x1A02 */
       
   795   {
       
   796     s_mappedVar tabMappedVar[8] = { {0x6000,0,32}, {0x6001, 0, 32}};
       
   797     slaveMappingPDO(0x05, 0x1802, 0x183, tabMappedVar, 2);
       
   798   }
       
   799  
       
   800   /*
       
   801      *** PDO node 1 --> node 5 ***
       
   802      *** cobId 0x184 *************
       
   803      Error management :  To reset the error
       
   804      MASTER (node 1)
       
   805      Mapped to variables (node1) [index-subindex-size_bits]: 
       
   806        canopenErrNb_node5     [0x6000 - 0x00 - 32]
       
   807        canopenErrVal_node5    [0x6001 - 0x00 - 32] 
       
   808 
       
   809      SLAVE (node 5)
       
   810      Mapped to variables (node5) [index-subindex-size_bytes]: 
       
   811        canopenErrNb     [0x6000 - 0x00 - 32]
       
   812        canopenErrVal    [0x6001 - 0x00 - 32]  
       
   813   */
       
   814 
       
   815   /* Configuring  PDO transmit, defined at index 0x1803 and 0x1103 */
       
   816   {
       
   817     s_mappedVar tabMappedVar[8] = { {0x6000,0,32}, {0x6001, 0, 32}};
       
   818     masterMappingPDO(0x1801, 0x184, tabMappedVar, 2);
       
   819   }
       
   820 
       
   821   /* Configuring PDO transmit, defined at index 0x1403 and 0x1603 */
       
   822   {
       
   823     s_mappedVar tabMappedVar[8] = { {0x6000,0,32}, {0x6001, 0, 32}};
       
   824     slaveMappingPDO(0x05, 0x1400, 0x184, tabMappedVar, 2);
       
   825   }
       
   826 
       
   827   /* Configuring the node 5 heartbeat */
       
   828   /* Check every 3000 ms if it have received a heartbeat from node 1 */
       
   829   {
       
   830     UNS8 nbHeartbeatsToReceive = 1;
       
   831     s_heartbeatConsumer tabHeartbeatConsumer[10] = {{1, 0xBB8}};
       
   832     slaveHeartbeatConsumer(0x05, tabHeartbeatConsumer, nbHeartbeatsToReceive);
       
   833   }
       
   834   /* Sending every 1000 ms an heartbeat */
       
   835   slaveHeartbeatProducer(0x05, 0x3E8);
       
   836 
       
   837   /* Configuring the master heartbeat */
       
   838   /* Check every 3000 ms if it have received a heartbeat from node 5 */
       
   839     {
       
   840     UNS8 nbHeartbeatsToReceive = 1;
       
   841     s_heartbeatConsumer tabHeartbeatConsumer[10] = {{5, 0xBB8}};
       
   842     masterHeartbeatConsumer(tabHeartbeatConsumer, nbHeartbeatsToReceive);
       
   843   }
       
   844 
       
   845     /* Sending every 1000 ms an heartbeat */
       
   846     masterHeartbeatProducer(0x3E8);
       
   847 
       
   848 
       
   849     
       
   850     /* Configuring the transmission mode of the PDO */
       
   851     slavePDOTransmissionMode(0x05, 0x1800,  TRANS_EVERY_N_SYNC (1));
       
   852     slavePDOTransmissionMode(0x05, 0x1801,  TRANS_EVENT);
       
   853     slavePDOTransmissionMode(0x05, 0x1802,  TRANS_EVENT);
       
   854     masterPDOTransmissionMode(0x1801,  TRANS_EVENT);
       
   855 
       
   856     /* Configuring the master to send a SYNC message every 1 s */
       
   857     /* Note than any other node can send the SYNC instead of the master */
       
   858     masterSYNCPeriod(1000000); 
       
   859 
       
   860     {
       
   861       // Reading the period of heartbeat which has been written in node 5 dictionary
       
   862       UNS8 node = 5;
       
   863       UNS16 index = 0x1017;
       
   864       UNS8 subindex = 0;
       
   865       //UNS8 notused = 0;
       
   866       UNS16 hb = 0;
       
   867       UNS8  size_data = 0;
       
   868       UNS8 error;
       
   869       MSG_WAR(0x3F50, "Reading dictionary noeud 5, 1017/0", 0);
       
   870       error = readNetworkDict(0, node, index, subindex, 0);
       
   871       //error = readNetworkDict(0, node, index, subindex, &notused);
       
   872       if (error) {
       
   873 	MSG_ERR(0x1F50, "!!! ERROR reading dictionary noeud 5, 1017/0", 0);
       
   874 	exit (-1);
       
   875       }
       
   876       /* Waiting until the server has responded */
       
   877       error = waitingReadToSlaveDict(node,  (UNS16 *)&hb,  &size_data, error);
       
   878       MSG_WAR(0x1F51, "Read dictionary of node 5, index/subindex 1017/0 value = ", hb);
       
   879       MSG_WAR(0x1F51, "         size of data (bytes) = ", size_data);
       
   880     }
       
   881 
       
   882 
       
   883 
       
   884     /* Put the node 5 in operational mode 
       
   885        The mode is changed according to the slave state machine mode :
       
   886          initialisation  ---> pre-operational (Automatic transition)
       
   887          pre-operational <--> operational
       
   888          pre-operational <--> stopped
       
   889          pre-operational, operational, stopped -> initialisation
       
   890        NMT_Start_Node           // Put the node in operational mode       
       
   891        NMT_Stop_Node		// Put the node in stopped mode    
       
   892        NMT_Enter_PreOperational // Put the node in pre_operational mode
       
   893        NMT_Reset_Node		// Put the node in initialization mode 
       
   894        NMT_Reset_Comunication	// Put the node in initialization mode 
       
   895     */
       
   896     masterSendNMTstateChange(0, 0x05, NMT_Start_Node);
       
   897 
       
   898 
       
   899     // Note
       
   900     //-----
       
   901     // We do not have mapped the variable canopenErrNB and canopenErrVAL.
       
   902     // We should have done that !
       
   903     // the macro MSG_ERR try to send the PDO(s) which contains these two variables.
       
   904     // While the PDO will not be found, if you are printing the warnings in file pdo.c,
       
   905     // it will print "0X393B Unable to send variable on event :  not mapped in a PDO to send on event" for  
       
   906     // example when you enter the function heartbeatError. 
       
   907 
       
   908    /******************** END CONFIGURING THE NETWORK **********************/
       
   909     
       
   910     /* Launch the thread to send the SYNC message    */
       
   911     pthread_create( &threadS, NULL, (void *)&transmitSync , NULL);
       
   912     /* Init the errors values that may send the node 5 */
       
   913     canopenErrNB_node5 = 0;
       
   914     canopenErrVAL_node5 = 0;
       
   915     
       
   916     /****************************** RUNNING *******************************/
       
   917 
       
   918   /* SDO test with node 5 */
       
   919   {
       
   920     // Reading string
       
   921     UNS8 dataW[20];
       
   922     UNS8 dataR[20];
       
   923     UNS8 size;
       
   924     UNS8 err;
       
   925     MSG_WAR(0x3F05, "Test SDO", 0);
       
   926 
       
   927     MSG_WAR(0x3F10, "Writing string to node 5 index 0x6002, subindex 0 ...", 0);
       
   928     strcpy(dataW, "Au Revoir");
       
   929     MSG_WAR(0x3F10, dataW, 0);
       
   930     size = 20;
       
   931     err = writeNetworkDict(0, 5, 0x6002, 0, 10, visible_string, dataW);
       
   932     err = waitingWriteToSlaveDict(5, err);
       
   933   
       
   934     err = readNetworkDict(0, 5, 0x6002, 0, visible_string);
       
   935     err = waitingReadToSlaveDict(5, dataR, &size, err);
       
   936     MSG_WAR(0x3F08, "Data read from node 5 index 0x6002, subindex 0 ..." , 0);
       
   937     MSG_WAR(0x3F08, dataR, 0);
       
   938     
       
   939     MSG_WAR(0x3F08, "node 5. Hardware version. (default = compil. date) ...", 0);
       
   940     err = readNetworkDict(0, 5, 0x1009, 0, visible_string);
       
   941     err = waitingReadToSlaveDict(5, dataR, &size, err);
       
   942     MSG_WAR(0x3F08, dataR, 0);
       
   943 
       
   944     MSG_WAR(0x3F08, "node 5. Software version. (default = compil. time) ...", 0);
       
   945     err = readNetworkDict(0, 5, 0x100A, 0, visible_string);
       
   946     err = waitingReadToSlaveDict(5, dataR, &size, err);
       
   947     MSG_WAR(0x3F08, dataR, 0);
       
   948   }
       
   949 
       
   950   // Node identity ?
       
   951     {
       
   952       UNS8 *data;
       
   953       UNS8 size;
       
   954       UNS8 dataType;
       
   955       // Manufacturer Device name (default = empty string)
       
   956       getODentry(0x1008, 0x0, (void **)&data, &size, &dataType, 0);
       
   957       MSG_WAR(0x3F09, data, 0);
       
   958       // Manufacturer Hardware version. (default = compilation. date)
       
   959       getODentry(0x1009, 0x0, (void **)&data, &size, &dataType, 0);
       
   960       MSG_WAR(0x3F09, data, 0);
       
   961       // Manufacturer Software version. (default = compilation. time)
       
   962       getODentry(0x100A, 0x0, (void **)&data, &size, &dataType, 0);
       
   963       MSG_WAR(0x3F09, data, 0);
       
   964     }
       
   965 
       
   966     while (1) {
       
   967       if (minutes != minutes_last) {
       
   968 	printf("Minutes changed\n");
       
   969 	minutes_last = minutes;
       
   970       }
       
   971 
       
   972       if (second != second_last) {
       
   973 	printf("Date : %d, %02dH%02d-%02d\n", day, hour, minutes, second);
       
   974 	second_last = second;
       
   975 
       
   976 	if (canopenErrNB_node5) {
       
   977 	  printf("Received an error from node 5, NB : 0x%X, value : 0x%X\n", 
       
   978 		canopenErrNB_node5 , canopenErrVAL_node5);
       
   979 	  // Resetting the error
       
   980 	  canopenErrNB_node5 = 0;
       
   981 	  canopenErrVAL_node5 = 0;
       
   982 	  sendingResetError = 1;
       
   983 	}
       
   984        
       
   985 	if ((second < 5) && sendingResetError) {
       
   986 	  printf("Sending to node 5 a PDO event to reset the error NB: 0x%X and VAL: 0x%X\n",
       
   987 		 canopenErrNB_node5, canopenErrVAL_node5);
       
   988 	    
       
   989 	  sendPDOevent(0, &canopenErrNB_node5);
       
   990 	  sendingResetError = 0; 
       
   991 	}
       
   992       
       
   993       
       
   994       }	// end if (second != second_last)
       
   995 
       
   996       // Testing if heartsbeat have been received, and send a heartbeat if it is time.
       
   997       // I have put that in a thread, but I don't know why, on HB not received,
       
   998       // it doesn't returns from heartbeatError() to the thread.
       
   999       heartbeatMGR();  
       
  1000       
       
  1001       usleep(10000);
       
  1002       
       
  1003     }
       
  1004   return 0;
       
  1005 }