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 <unistd.h> |
|
26 #include <stdlib.h> |
|
27 #include <time.h> |
|
28 #include <pthread.h> |
|
29 |
|
30 #include <applicfg.h> |
|
31 #include <timerhw.h> |
|
32 #include <linuxCan.h> |
|
33 |
|
34 #include "def.h" |
|
35 #include "can.h" |
|
36 #include "canOpenDriver.h" |
|
37 #include "sdo.h" |
|
38 #include "pdo.h" |
|
39 #include "init.h" |
|
40 #include "timer.h" |
|
41 #include "lifegrd.h" |
|
42 |
|
43 #include "nmtSlave.h" |
|
44 |
|
45 // Adlink 7841 or Peak PCI/CAN board |
|
46 // --------------------------------- |
|
47 |
|
48 // Baudrate values for Peak board : |
|
49 // CAN_BAUD_1M CAN_BAUD_500K CAN_BAUD_250K CAN_BAUD_125K CAN_BAUD_100K CAN_BAUD_50K |
|
50 // CAN_BAUD_20K CAN_BAUD_10K CAN_BAUD_5K |
|
51 |
|
52 #ifdef CAN_BAUD_250K |
|
53 # define BAUDRATE CAN_BAUD_250K |
|
54 #else |
|
55 // Appli have been compiled for Adlink-arbraca. Baudrate not used |
|
56 # define BAUDRATE 0 |
|
57 #endif |
|
58 |
|
59 s_BOARD board = {"1", BAUDRATE}; |
|
60 |
|
61 |
|
62 // The variables sent or updated by PDO |
|
63 // ----------------------------------------------------- |
|
64 extern UNS8 seconds; // Mapped at index 0x2000, subindex 0x1 |
|
65 extern UNS8 minutes; // Mapped at index 0x2000, subindex 0x2 |
|
66 extern UNS8 hours; // Mapped at index 0x2000, subindex 0x3 |
|
67 extern UNS8 day; // Mapped at index 0x2000, subindex 0x4 |
|
68 extern UNS32 canopenErrNB; // Mapped at index 0x6000, subindex 0x0 |
|
69 extern UNS32 canopenErrVAL; // Mapped at index 0x6001, subindex 0x0 |
|
70 |
|
71 // Required definition variables |
|
72 // ----------------------------- |
|
73 // The variables that you should define for debugging. |
|
74 // They are used by the macro MSG_ERR and MSG_WAR in applicfg.h |
|
75 // if the node is a slave, they can be mapped in the object dictionnary. |
|
76 // if not null, allow the printing of message to the console |
|
77 // Could be managed by PDO |
|
78 UNS8 printMsgErrToConsole = 1; |
|
79 UNS8 printMsgWarToConsole = 1; |
|
80 |
|
81 |
|
82 |
|
83 /*************************User's variables declaration**************************/ |
|
84 struct tm date; |
|
85 struct tm *ptrdate; |
|
86 struct tm date_prec; |
|
87 time_t tme; |
|
88 UNS8 lastSecond; |
|
89 e_nodeState lastState; |
|
90 pthread_t threadRcvMsg; |
|
91 pthread_t threadHeartbeatAndSDO; |
|
92 UNS8 sendingError = 0; |
|
93 |
|
94 |
|
95 /******************************prototypes*****************************/ |
|
96 /* You *must* have these 2 functions in your code*/ |
|
97 void heartbeatError(UNS8 heartbeatID); |
|
98 void SD0timeoutError(UNS8 bus_id, UNS8 line); |
|
99 |
|
100 UNS8 scanSDOtimeout(void); |
|
101 void preOperational(void); |
|
102 void operational(void); |
|
103 void stopped(void); |
|
104 void waitMessage(void); |
|
105 void waitMessage_heartbeat(void); |
|
106 |
|
107 /*********************************************************************/ |
|
108 void heartbeatError(UNS8 heartbeatID) |
|
109 { |
|
110 MSG_ERR(0x1F00, "!!! No heart beat received from node : ", heartbeatID); |
|
111 } |
|
112 |
|
113 /*****************************************************************************/ |
|
114 void SD0timeoutError (UNS8 bus_id, UNS8 line) |
|
115 { |
|
116 // Informations on what occurs are in transfers[bus_id][line].... |
|
117 // See scanSDOtimeout() in sdo.c |
|
118 } |
|
119 |
|
120 /*********************************** THREADS **********************************/ |
|
121 //------------------------------------------------------------------------------ |
|
122 // Wait for a received message |
|
123 void waitMessage( void ) |
|
124 { |
|
125 while (1) { |
|
126 receiveMsgHandler(0); // blocked until new message |
|
127 } |
|
128 } |
|
129 |
|
130 //------------------------------------------------------------------------------ |
|
131 // Heartbeat Manager (sending and receiving) and test SDO timeout |
|
132 void heartbeatAndSDO(void) |
|
133 { |
|
134 while (1) { |
|
135 heartbeatMGR(); |
|
136 // Check if some SDO response are missing |
|
137 scanSDOtimeout(); |
|
138 // Sleep 10 ms |
|
139 usleep(10000); |
|
140 } |
|
141 } |
|
142 |
|
143 /*********************************************************************/ |
|
144 void preOperational( void ) |
|
145 { |
|
146 /* Init some variables */ |
|
147 canopenErrNB = 0; |
|
148 canopenErrVAL = 0; |
|
149 } |
|
150 |
|
151 |
|
152 /********************************************************************/ |
|
153 void operational( void ) |
|
154 { |
|
155 /* read systeme date */ |
|
156 tme = time (&tme); |
|
157 ptrdate = gmtime(&tme); |
|
158 date = *ptrdate; |
|
159 |
|
160 /* Update the dictionary */ |
|
161 day = date.tm_mday; |
|
162 hours = date.tm_hour; |
|
163 minutes = date.tm_min; |
|
164 seconds = date.tm_sec; |
|
165 |
|
166 |
|
167 if ( date_prec.tm_min != date.tm_min ) { |
|
168 MSG_WAR(0x3F00, "event : minutes change -> node decides to send it. Value : ", date.tm_min); |
|
169 sendPDOevent( 0, &minutes ); |
|
170 date_prec = date; |
|
171 } |
|
172 if (canopenErrNB == 0) |
|
173 sendingError = 0; |
|
174 |
|
175 if (lastSecond != seconds) { |
|
176 MSG_WAR (0x3F50, "Seconds = ", seconds); |
|
177 if ((seconds == 50) && (sendingError == 0)) |
|
178 { |
|
179 MSG_ERR(0x1F55, "DEMO of ERROR. Sent by PDO. Value : ", 0xABCD); |
|
180 sendingError = 1; |
|
181 } |
|
182 |
|
183 if (canopenErrNB) { |
|
184 MSG_WAR(0x3F56, "ERROR nb : ", canopenErrNB); |
|
185 } |
|
186 lastSecond = seconds; |
|
187 |
|
188 } |
|
189 } |
|
190 |
|
191 |
|
192 /*****************************************************************************/ |
|
193 void stopped( void ) |
|
194 { |
|
195 } |
|
196 |
|
197 void help() |
|
198 { |
|
199 printf("**************************************************************\n"); |
|
200 printf("* AppliSlave *\n"); |
|
201 printf("* [-b b] *\n"); |
|
202 printf("* *\n"); |
|
203 printf("* b : bus [default 1] *\n"); |
|
204 printf("* *\n"); |
|
205 printf("* This exemple run AppliSlave on bus 0 *\n"); |
|
206 printf("* AppliSlave -b 0 *\n"); |
|
207 printf("* *\n"); |
|
208 printf("**************************************************************\n"); |
|
209 } |
|
210 |
|
211 /****************************************************************************/ |
|
212 /*************************** MAIN *****************************************/ |
|
213 /****************************************************************************/ |
|
214 int main(int argc,char **argv) |
|
215 { |
|
216 |
|
217 HANDLE ok; |
|
218 UNS32 * pSize; |
|
219 UNS32 size; |
|
220 pSize = &size; |
|
221 char c; |
|
222 extern char *optarg; |
|
223 |
|
224 while ((c = getopt(argc, argv, "-b:")) != EOF) |
|
225 { |
|
226 switch(c) |
|
227 { |
|
228 case 'b' : |
|
229 if (optarg[0] == 0) |
|
230 { |
|
231 help(); |
|
232 exit(1); |
|
233 } |
|
234 board.busname = optarg; |
|
235 break; |
|
236 default: |
|
237 help(); |
|
238 exit(1); |
|
239 } |
|
240 } |
|
241 |
|
242 // Global initialization before launching the threads. (also done in init mode. |
|
243 /* Defining the node Id */ |
|
244 setNodeId(0x05); |
|
245 MSG_WAR(0x3F06, "My node ID is : ", getNodeId()); |
|
246 initCANopenMain(); |
|
247 initTimer( ); |
|
248 heartbeatInit(); |
|
249 initResetMode(); |
|
250 |
|
251 /* Launch the thread to receive the messages */ |
|
252 pthread_create( &threadRcvMsg, NULL, (void *)&waitMessage, NULL); |
|
253 /* Launch the thread to manage the heartbeat */ |
|
254 pthread_create( &threadHeartbeatAndSDO, NULL, (void *)&heartbeatAndSDO, NULL); |
|
255 |
|
256 /* open the communication with the board */ |
|
257 ok = f_can_open(& board); |
|
258 if (ok == NULL) { |
|
259 MSG_ERR(0x1F02,"Unable to open the board", 0); |
|
260 MSG_ERR(0x1F03,"Edit includeMakefileLinux to verify that the application is configured for the good board", 0); |
|
261 exit (-1); |
|
262 } |
|
263 else { |
|
264 MSG_WAR(0x3F03, "Board 1 opened ", 0); |
|
265 /* slave's state initialization */ |
|
266 setState(Initialisation); |
|
267 lastState = Unknown_state; |
|
268 |
|
269 |
|
270 while(1) { /* slave's state machine */ |
|
271 switch( getState() ) { |
|
272 case Initialisation: |
|
273 if (lastState != getState()) |
|
274 MSG_WAR(0X3F05, "I am in INITIALISATION mode ", 0); |
|
275 /* Defining the node Id */ |
|
276 setNodeId(0x05); |
|
277 MSG_WAR(0x3F06, "My node ID is : ", getNodeId()); |
|
278 // Node identity ? |
|
279 { |
|
280 UNS8 *data; |
|
281 UNS8 size; |
|
282 UNS8 dataType; |
|
283 // Manufacturer Device name (default = empty string) |
|
284 getODentry(0x1008, 0x0, (void **)&data, &size, &dataType, 0); |
|
285 MSG_WAR(0x3F09, data, 0); |
|
286 // Manufacturer Hardware version. (default = compilation. date) |
|
287 getODentry(0x1009, 0x0, (void **)&data, &size, &dataType, 0); |
|
288 MSG_WAR(0x3F09, data, 0); |
|
289 // Manufacturer Software version. (default = compilation. time) |
|
290 getODentry(0x100A, 0x0, (void **)&data, &size, &dataType, 0); |
|
291 MSG_WAR(0x3F09, data, 0); |
|
292 } |
|
293 |
|
294 initCANopenMain(); |
|
295 initTimer( ); |
|
296 heartbeatInit(); |
|
297 initResetMode(); |
|
298 /* the slave send an NMT trame to say to the master |
|
299 that it is going to enter into operational state |
|
300 In fact, you must send the boot-up when you are in |
|
301 operational mode ! |
|
302 */ |
|
303 |
|
304 /* change automatically into pre_operational state */ |
|
305 lastState = getState(); |
|
306 setState(Pre_operational); |
|
307 break; |
|
308 |
|
309 case Pre_operational: |
|
310 if (lastState != getState()) |
|
311 { |
|
312 MSG_WAR(0X3F11, "I am in PRE_OPERATIONAL mode ", 0); |
|
313 // Some stuff to do when the node enter in pre-operational mode |
|
314 initPreOperationalMode(); |
|
315 } |
|
316 if (lastState == Initialisation) |
|
317 slaveSendBootUp(0); |
|
318 lastState = getState(); |
|
319 preOperational( ); |
|
320 break; |
|
321 |
|
322 case Operational: |
|
323 if (lastState != getState()) |
|
324 MSG_WAR(0X3F12, "I am in OPERATIONAL mode ", 0); |
|
325 lastState = getState(); |
|
326 operational( ); |
|
327 break; |
|
328 |
|
329 case Stopped: |
|
330 if (lastState != getState()) |
|
331 MSG_WAR(0X3F13, "I am in STOPPED mode", 0); |
|
332 lastState = getState(); |
|
333 stopped( ); |
|
334 break; |
|
335 }//end switch case |
|
336 // Sleep 10 ms |
|
337 usleep(10000); |
|
338 }//end while |
|
339 }//end else |
|
340 |
|
341 |
|
342 return 0; |
|
343 } |
|
344 |
|