2 This file is part of CanFestival, a library implementing CanOpen Stack.
4 Copyright (C): Edouard TISSERANT and Francis DUPIN
6 See COPYING file for copyrights details.
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.
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.
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
23 //#define DEBUG_WAR_CONSOLE_ON
24 //#define DEBUG_ERR_CONSOLE_ON
29 /***************************************************************************/
30 // SDO (un)packing macros
32 /** Returns the command specifier (cs, ccs, scs) from the first byte of the SDO
34 #define getSDOcs(byte) (byte >> 5)
36 /** Returns the number of bytes without data from the first byte of the SDO. Coded in 2 bits
38 #define getSDOn2(byte) ((byte >> 2) & 3)
40 /** Returns the number of bytes without data from the first byte of the SDO. Coded in 3 bits
42 #define getSDOn3(byte) ((byte >> 1) & 7)
44 /** Returns the transfer type from the first byte of the SDO
46 #define getSDOe(byte) ((byte >> 1) & 1)
48 /** Returns the size indicator from the first byte of the SDO
50 #define getSDOs(byte) (byte & 1)
52 /** Returns the indicator of end transmission from the first byte of the SDO
54 #define getSDOc(byte) (byte & 1)
56 /** Returns the toggle from the first byte of the SDO
58 #define getSDOt(byte) ((byte >> 4) & 1)
60 /** Returns the index from the bytes 1 and 2 of the SDO
62 #define getSDOindex(byte1, byte2) ((byte2 << 8) | (byte1))
64 /** Returns the subIndex from the byte 3 of the SDO
66 #define getSDOsubIndex(byte3) (byte3)
68 /***************************************************************************
71 void SDOTimeoutAlarm(CO_Data* d, UNS32 id)
73 MSG_ERR(0x1A01, "SDO timeout. SDO response not received.", 0);
74 MSG_WAR(0x2A02, "server node : ", d->transfers[id].nodeId);
75 MSG_WAR(0x2A02, " index : ", d->transfers[id].index);
76 MSG_WAR(0x2A02, " subIndex : ", d->transfers[id].subIndex);
77 // Reset timer handler
78 d->transfers[id].timer = TIMER_NONE;
79 // Call the user function to inform of the problem.
80 (*d->SDOtimeoutError)(id);
81 // Sending a SDO abort
82 sendSDOabort(d, d->transfers[id].whoami,
83 d->transfers[id].index, d->transfers[id].subIndex, SDOABT_TIMED_OUT);
88 #define StopSDO_TIMER(id) \
89 MSG_WAR(0x3A05, "StopSDO_TIMER for line : ", line);\
90 d->transfers[id].timer = DelAlarm(d->transfers[id].timer);
92 #define StartSDO_TIMER(id) \
93 MSG_WAR(0x3A06, "StartSDO_TIMER for line : ", line);\
94 d->transfers[id].timer = SetAlarm(d,id,&SDOTimeoutAlarm,MS_TO_TIMEVAL(SDO_TIMEOUT_MS),0);
96 #define RestartSDO_TIMER(id) \
97 MSG_WAR(0x3A07, "restartSDO_TIMER for line : ", line);\
98 if(d->transfers[id].timer != TIMER_NONE) { StopSDO_TIMER(id) StartSDO_TIMER(id) }
100 /***************************************************************************/
101 /** Reset all sdo buffers
103 void resetSDO (CO_Data* d)
107 /* transfer structure initialization */
108 for (j = 0 ; j < SDO_MAX_SIMULTANEOUS_TRANSFERTS ; j++)
112 /***************************************************************************/
113 UNS32 SDOlineToObjdict (CO_Data* d, UNS8 line)
117 MSG_WAR(0x3A08, "Enter in SDOlineToObjdict ", line);
118 size = d->transfers[line].count;
119 errorCode = setODentry(d, d->transfers[line].index, d->transfers[line].subIndex,
120 (void *) d->transfers[line].data, &size, 1);
121 if (errorCode != OD_SUCCESSFUL)
123 MSG_WAR(0x3A08, "exit of SDOlineToObjdict ", line);
128 /***************************************************************************/
129 UNS32 objdictToSDOline (CO_Data* d, UNS8 line)
135 MSG_WAR(0x3A05, "objdict->line index : ", d->transfers[line].index);
136 MSG_WAR(0x3A06, " subIndex : ", d->transfers[line].subIndex);
138 errorCode = getODentry(d, d->transfers[line].index,
139 d->transfers[line].subIndex,
140 (void *)d->transfers[line].data,
141 &size, &dataType, 0);
143 if (errorCode != OD_SUCCESSFUL)
146 d->transfers[line].count = size;
147 d->transfers[line].offset = 0;
149 // Me laisser ça, please ! (FD)
152 for (i = 0 ; i < 10 ; i++) {
153 MSG_WAR(i, "data= ", d->transfers[line].data[i]);
160 /***************************************************************************/
161 UNS8 lineToSDO (CO_Data* d, UNS8 line, UNS8 nbBytes, UNS8* data) {
165 if ((d->transfers[line].offset + nbBytes) > SDO_MAX_LENGTH_TRANSFERT) {
166 MSG_ERR(0x1A10,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFERT", nbBytes);
169 if ((d->transfers[line].offset + nbBytes) > d->transfers[line].count) {
170 MSG_ERR(0x1A11,"SDO Size of data too large. Exceed count", nbBytes);
173 offset = d->transfers[line].offset;
174 for (i = 0 ; i < nbBytes ; i++)
175 * (data + i) = d->transfers[line].data[offset + i];
176 d->transfers[line].offset = d->transfers[line].offset + nbBytes;
181 /***************************************************************************/
182 UNS8 SDOtoLine (CO_Data* d, UNS8 line, UNS8 nbBytes, UNS8* data)
187 if ((d->transfers[line].offset + nbBytes) > SDO_MAX_LENGTH_TRANSFERT) {
188 MSG_ERR(0x1A15,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFERT", nbBytes);
191 offset = d->transfers[line].offset;
192 for (i = 0 ; i < nbBytes ; i++)
193 d->transfers[line].data[offset + i] = * (data + i);
194 d->transfers[line].offset = d->transfers[line].offset + nbBytes;
198 /***************************************************************************/
199 UNS8 failedSDO (CO_Data* d, UNS8 nodeId, UNS8 whoami, UNS16 index,
200 UNS8 subIndex, UNS32 abortCode)
204 err = getSDOlineOnUse( d, nodeId, whoami, &line );
205 if (!err) // If a line on use have been found.
206 MSG_WAR(0x3A20, "FailedSDO : line found : ", line);
207 if ((! err) && (whoami == SDO_SERVER)) {
208 resetSDOline( d, line );
209 MSG_WAR(0x3A21, "FailedSDO : line released : ", line);
211 if ((! err) && (whoami == SDO_CLIENT)) {
213 d->transfers[line].state = SDO_ABORTED_INTERNAL;
215 MSG_WAR(0x3A22, "Sending SDO abort ", 0);
216 err = sendSDOabort(d, whoami, index, subIndex, abortCode);
218 MSG_WAR(0x3A23, "Unable to send the SDO abort", 0);
224 /***************************************************************************/
225 void resetSDOline ( CO_Data* d, UNS8 line )
228 MSG_WAR(0x3A25, "reset SDO line nb : ", line);
229 initSDOline(d, line, 0, 0, 0, SDO_RESET);
230 for (i = 0 ; i < SDO_MAX_LENGTH_TRANSFERT ; i++)
231 d->transfers[line].data[i] = 0;
234 /***************************************************************************/
235 UNS8 initSDOline (CO_Data* d, UNS8 line, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 state)
237 MSG_WAR(0x3A25, "init SDO line nb : ", line);
238 if (state == SDO_DOWNLOAD_IN_PROGRESS || state == SDO_UPLOAD_IN_PROGRESS){
243 d->transfers[line].nodeId = nodeId;
244 d->transfers[line].index = index;
245 d->transfers[line].subIndex = subIndex;
246 d->transfers[line].state = state;
247 d->transfers[line].toggle = 0;
248 d->transfers[line].count = 0;
249 d->transfers[line].offset = 0;
250 d->transfers[line].dataType = 0;
254 /***************************************************************************/
255 UNS8 getSDOfreeLine ( CO_Data* d, UNS8 whoami, UNS8 *line )
260 for (i = 0 ; i < SDO_MAX_SIMULTANEOUS_TRANSFERTS ; i++){
261 if ( d->transfers[i].state == SDO_RESET ) {
263 d->transfers[i].whoami = whoami;
267 MSG_ERR(0x1A25, "Too many SDO in progress. Aborted.", i);
271 /***************************************************************************/
272 UNS8 getSDOlineOnUse (CO_Data* d, UNS8 nodeId, UNS8 whoami, UNS8 *line)
277 for (i = 0 ; i < SDO_MAX_SIMULTANEOUS_TRANSFERTS ; i++){
278 if ( (d->transfers[i].state != SDO_RESET) &&
279 (d->transfers[i].nodeId == nodeId) &&
280 (d->transfers[i].whoami == whoami) ) {
288 /***************************************************************************/
289 UNS8 closeSDOtransfer (CO_Data* d, UNS8 nodeId, UNS8 whoami)
293 err = getSDOlineOnUse(d, nodeId, whoami, &line);
295 MSG_WAR(0x2A30, "No SDO communication to close for node : ", nodeId);
298 resetSDOline(d, line);
302 /***************************************************************************/
303 UNS8 getSDOlineRestBytes (CO_Data* d, UNS8 line, UNS8 * nbBytes)
305 if (d->transfers[line].count == 0) // if received initiate SDO protocol with e=0 and s=0
308 * nbBytes = d->transfers[line].count - d->transfers[line].offset;
312 /***************************************************************************/
313 UNS8 setSDOlineRestBytes (CO_Data* d, UNS8 line, UNS8 nbBytes)
315 if (nbBytes > SDO_MAX_LENGTH_TRANSFERT) {
316 MSG_ERR(0x1A35,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFERT", nbBytes);
319 d->transfers[line].count = nbBytes;
324 /***************************************************************************/
325 UNS8 sendSDO (CO_Data* d, UNS8 whoami, s_SDO sdo)
332 UNS32 * pwCobId = NULL;
333 UNS8 * pwNodeId = NULL;
338 MSG_WAR(0x3A38, "sendSDO",0);
339 if( !((d->nodeState == Operational) || (d->nodeState == Pre_operational ))) {
340 MSG_WAR(0x2A39, "unable to send the SDO (not in op or pre-op mode", d->nodeState);
344 /*get the server->client cobid*/
345 if ( whoami == SDO_SERVER ) {/*case server. Easy because today only one server SDO is authorized in CanFestival*/
346 offset = d->firstIndex->SDO_SVR;
348 MSG_ERR(0x1A42, "SendSDO : No SDO server found", 0);
351 pwCobId = d->objdict[offset].pSubindex[2].pObject;
352 MSG_WAR(0x3A41, "I am server. cobId : ", *pwCobId);
354 else { /*case client*/
355 /* Get the client->server cobid.*/
357 offset = d->firstIndex->SDO_CLT;
358 lastIndex = d->lastIndex->SDO_CLT;
360 MSG_ERR(0x1A42, "SendSDO : No SDO client index found", 0);
363 /* First, have to find at the index where is defined the communication with the server node */
364 while (offset <= lastIndex){
365 MSG_WAR(0x3A43,"Reading index : ", 0x1280 + sdoNum);
366 if (d->objdict[offset].bSubCount <= 3) {
367 MSG_ERR(0x1A28, "Subindex 3 not found at index ", 0x1280 + sdoNum);
370 pwNodeId = d->objdict[offset].pSubindex[3].pObject;
371 MSG_WAR(0x3A44, "Found nodeId server = ", *pwNodeId);
372 if(*pwNodeId == sdo.nodeId) {
380 MSG_WAR (0x2A45, "No SDO client corresponds to the mesage to send to node ", sdo.nodeId);
383 /* Second, read the cobid client->server */
384 pwCobId = d->objdict[offset].pSubindex[1].pObject;
386 /* message copy for sending */
387 m.cob_id.w = *pwCobId;
388 m.rtr = NOT_A_REQUEST;
389 //the length of SDO must be 8
391 for (i = 0 ; i < 8 ; i++) {
392 m.data[i] = sdo.body.data[i];
394 return (*d->canSend)(&m);
397 /***************************************************************************/
398 UNS8 sendSDOabort (CO_Data* d, UNS8 whoami, UNS16 index, UNS8 subIndex, UNS32 abortCode)
402 MSG_WAR(0x2A50,"Sending SDO abort ", abortCode);
403 sdo.nodeId = *d->bDeviceNodeId;
404 sdo.body.data[0] = 0x80;
406 sdo.body.data[1] = index & 0xFF; // LSB
407 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
409 sdo.body.data[3] = subIndex;
411 sdo.body.data[4] = (UNS8)(abortCode & 0xFF);
412 sdo.body.data[5] = (UNS8)((abortCode >> 8) & 0xFF);
413 sdo.body.data[6] = (UNS8)((abortCode >> 16) & 0xFF);
414 sdo.body.data[7] = (UNS8)((abortCode >> 24) & 0xFF);
415 ret = sendSDO(d, whoami, sdo);
420 /***************************************************************************/
421 UNS8 proceedSDO (CO_Data* d, Message *m)
425 UNS8 nbBytes; // received or to be transmited.
426 UNS8 nodeId = 0; // The node from which the SDO is received
427 UNS8 *pNodeId = NULL;
428 UNS8 whoami = SDO_UNKNOWN; // SDO_SERVER or SDO_CLIENT.
429 UNS32 errorCode; // while reading or writing in the local object dictionary.
430 s_SDO sdo; // SDO to transmit
435 UNS32 * pCobId = NULL;
443 MSG_WAR(0x3A60, "proceedSDO ", 0);
444 whoami = SDO_UNKNOWN;
445 // Looking for the cobId in the object dictionary.
447 offset = d->firstIndex->SDO_SVR;
448 lastIndex = d->lastIndex->SDO_SVR;
450 if(offset) while (offset <= lastIndex) {
451 if (d->objdict[offset].bSubCount <= 1) {
452 MSG_ERR(0x1A61, "Subindex 1 not found at index ", 0x1200 + j);
455 pCobId = d->objdict[offset].pSubindex[1].pObject;
456 if ( *pCobId == (*m).cob_id.w ) {
458 MSG_WAR(0x3A62, "proceedSDO. I am server. index : ", 0x1200 + j);
459 // In case of server, the node id of the client may be unknown. So we put the index minus offset
460 // 0x1200 where the cobid received is defined.
467 if (whoami == SDO_UNKNOWN) {
469 offset = d->firstIndex->SDO_CLT;
470 lastIndex = d->lastIndex->SDO_CLT;
472 if(offset) while (offset <= lastIndex) {
473 if (d->objdict[offset].bSubCount <= 3) {
474 MSG_ERR(0x1A63, "Subindex 3 not found at index ", 0x1280 + j);
477 // a) Looking for the cobid received.
478 pCobId = d->objdict[offset].pSubindex[2].pObject;
479 if (*pCobId == (*m).cob_id.w ) {
480 // b) cobid found, so reading the node id of the server.
481 pNodeId = d->objdict[offset].pSubindex[3].pObject;
484 MSG_WAR(0x3A64, "proceedSDO. I am server. index : ", 0x1280 + j);
485 MSG_WAR(0x3A65, " Server nodeId : ", nodeId);
492 if (whoami == SDO_UNKNOWN) {
493 return 0xFF;// This SDO was not for us !
496 // Test if the size of the SDO is ok
497 if ( (*m).len != 8) {
498 MSG_ERR(0x1A67, "Error size SDO. CobId : ", (*m).cob_id.w);
499 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_GENERAL_ERROR);
503 if (whoami == SDO_CLIENT) {
504 MSG_WAR(0x3A68, "I am CLIENT. Received SDO from nodeId : ", nodeId);
507 MSG_WAR(0x3A69, "I am SERVER. Received SDO cobId : ", (*m).cob_id.w);
510 // Testing the command specifier
511 // Allowed : cs = 0, 1, 2, 3, 4. (= all except those for block tranfert).
512 // cs = other : Not allowed -> abort.
513 switch (getSDOcs(m->data[0])) {
517 if (whoami == SDO_SERVER) {
518 // Receiving a download segment data.
519 // A SDO transfert should have been yet initiated.
520 err = getSDOlineOnUse( d, nodeId, whoami, &line );
522 err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
524 MSG_ERR(0x1A70, "SDO error : Received download segment for unstarted trans. index 0x1200 + ",
526 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
530 RestartSDO_TIMER(line)
531 MSG_WAR(0x3A71, "Received SDO download segment defined at index 0x1200 + ", nodeId);
532 index = d->transfers[line].index;
533 subIndex = d->transfers[line].subIndex;
535 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
536 MSG_ERR(0x1A72, "SDO error : Toggle error : ", getSDOt(m->data[0]));
537 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
540 // Nb of data to be downloaded
541 nbBytes = 7 - getSDOn3(m->data[0]);
542 // Store the data in the transfert structure.
543 err = SDOtoLine(d, line, nbBytes, (*m).data + 1);
545 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
548 // Sending the SDO response, CS = 1
549 sdo.nodeId = *d->bDeviceNodeId; // The node id of the server, (here it is the sender).
550 sdo.body.data[0] = (1 << 5) | (d->transfers[line].toggle << 4);
551 for (i = 1 ; i < 8 ; i++)
552 sdo.body.data[i] = 0;
553 MSG_WAR(0x3A73, "SDO. Send response to download request defined at index 0x1200 + ", nodeId);
554 sendSDO(d, whoami, sdo);
555 // Inverting the toggle for the next segment.
556 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
557 // If it was the last segment,
558 if (getSDOc(m->data[0])) {
559 // Transfering line data to object dictionary.
560 // The code does not use the "d" of initiate frame. So it is safe if e=s=0
561 errorCode = SDOlineToObjdict(d, line);
563 MSG_ERR(0x1A54, "SDO error : Unable to copy the data in the object dictionary", 0);
564 failedSDO(d, nodeId, whoami, index, subIndex, errorCode);
567 // Release of the line
568 resetSDOline(d, line);
569 MSG_WAR(0x3A74, "SDO. End of download defined at index 0x1200 + ", nodeId);
574 // It is a request for a previous upload segment. We should find a line opened for this.
575 err = getSDOlineOnUse( d, nodeId, whoami, &line);
577 err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
579 MSG_ERR(0x1A75, "SDO error : Received segment response for unknown trans. from nodeId", nodeId);
580 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
584 RestartSDO_TIMER(line)
585 index = d->transfers[line].index;
586 subIndex = d->transfers[line].subIndex;
587 // test of the toggle;
588 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
589 MSG_ERR(0x1A76, "SDO error : Received segment response Toggle error. from nodeId", nodeId);
590 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
593 // nb of data to be uploaded
594 nbBytes = 7 - getSDOn3(m->data[0]);
595 // Storing the data in the line structure.
596 err = SDOtoLine(d, line, nbBytes, (*m).data + 1);
598 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
601 // Inverting the toggle for the next segment.
602 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
603 // If it was the last segment,
604 if ( getSDOc(m->data[0])) {
605 // Put in state finished
606 // The code is safe for the case e=s=0 in initiate frame.
608 d->transfers[line].state = SDO_FINISHED;
609 MSG_WAR(0x3A77, "SDO. End of upload from node : ", nodeId);
611 else { // more segments to receive
612 // Sending the request for the next segment.
614 sdo.body.data[0] = (3 << 5) | (d->transfers[line].toggle << 4);
615 for (i = 1 ; i < 8 ; i++)
616 sdo.body.data[i] = 0;
617 sendSDO(d, whoami, sdo);
618 MSG_WAR(0x3A78, "SDO send upload segment request to nodeId", nodeId);
625 // Receive of an initiate download
626 if (whoami == SDO_SERVER) {
627 index = getSDOindex(m->data[1],m->data[2]);
628 subIndex = getSDOsubIndex(m->data[3]);
629 MSG_WAR(0x3A79, "Received SDO Initiate Download (to store data) defined at index 0x1200 + ",
631 MSG_WAR(0x3A80, "Writing at index : ", index);
632 MSG_WAR(0x3A80, "Writing at subIndex : ", subIndex);
634 // Search if a SDO transfert have been yet initiated
635 err = getSDOlineOnUse( d, nodeId, whoami, &line );
637 MSG_ERR(0x1A81, "SDO error : Transmission yet started.", 0);
638 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
641 // No line on use. Great !
642 // Try to open a new line.
643 err = getSDOfreeLine( d, whoami, &line );
645 MSG_ERR(0x1A82, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
646 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
649 initSDOline(d, line, nodeId, index, subIndex, SDO_DOWNLOAD_IN_PROGRESS);
651 if (getSDOe(m->data[0])) { // If SDO expedited
652 // nb of data to be downloaded
653 nbBytes = 4 - getSDOn2(m->data[0]);
654 // Storing the data in the line structure.
655 d->transfers[line].count = nbBytes;
656 err = SDOtoLine(d, line, nbBytes, (*m).data + 4);
659 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
663 // SDO expedited -> transfert finished. Data can be stored in the dictionary.
664 // The line will be reseted when it is downloading in the dictionary.
665 MSG_WAR(0x3A83, "SDO Initiate Download is an expedited transfert. Finished.: ", nodeId);
666 // Transfering line data to object dictionary.
667 errorCode = SDOlineToObjdict(d, line);
669 MSG_ERR(0x1A84, "SDO error : Unable to copy the data in the object dictionary", 0);
670 failedSDO(d, nodeId, whoami, index, subIndex, errorCode);
673 // Release of the line.
674 resetSDOline(d, line);
676 else {// So, if it is not an expedited transfert
677 if (getSDOs(m->data[0])) {
678 // TODO : if e and s = 0, not reading m->data[4] but put nbBytes = 0
679 nbBytes = m->data[4]; // Transfert limited to 255 bytes.
680 err = setSDOlineRestBytes(d, nodeId, nbBytes);
682 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
687 //Sending a SDO, cs=3
688 sdo.nodeId = *d->bDeviceNodeId; // The node id of the server, (here it is the sender).
689 sdo.body.data[0] = 3 << 5;
690 sdo.body.data[1] = index & 0xFF; // LSB
691 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
692 sdo.body.data[3] = subIndex;
693 for (i = 4 ; i < 8 ; i++)
694 sdo.body.data[i] = 0;
695 sendSDO(d, whoami, sdo);
696 } // end if I am SERVER
699 // It is a response for a previous download segment. We should find a line opened for this.
700 err = getSDOlineOnUse( d, nodeId, whoami, &line);
702 err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
704 MSG_ERR(0x1A85, "SDO error : Received segment response for unknown trans. from nodeId", nodeId);
705 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
709 RestartSDO_TIMER(line)
710 index = d->transfers[line].index;
711 subIndex = d->transfers[line].subIndex;
712 // test of the toggle;
713 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
714 MSG_ERR(0x1A86, "SDO error : Received segment response Toggle error. from nodeId", nodeId);
715 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
719 // End transmission or downloading next segment. We need to know if it will be the last one.
720 getSDOlineRestBytes(d, line, &nbBytes);
722 MSG_WAR(0x3A87, "SDO End download. segment response received. OK. from nodeId", nodeId);
724 d->transfers[line].state = SDO_FINISHED;
727 // At least one transfer to send.
729 // several segments to download.
730 // code to send the next segment. (cs = 0; c = 0)
731 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
732 sdo.nodeId = nodeId; // The server node Id;
733 sdo.body.data[0] = (d->transfers[line].toggle << 4);
734 err = lineToSDO(d, line, 7, sdo.body.data + 1);
736 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
742 // code to send the last segment. (cs = 0; c = 1)
743 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
744 sdo.nodeId = nodeId; // The server node Id;
745 sdo.body.data[0] = (d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1;
746 err = lineToSDO(d, line, nbBytes, sdo.body.data + 1);
748 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
751 for (i = nbBytes + 1 ; i < 8 ; i++)
752 sdo.body.data[i] = 0;
754 MSG_WAR(0x3A88, "SDO sending download segment to nodeId", nodeId);
755 sendSDO(d, whoami, sdo);
756 } // end if I am a CLIENT
761 // Receive of an initiate upload.
762 if (whoami == SDO_SERVER) {
763 index = getSDOindex(m->data[1],m->data[2]);
764 subIndex = getSDOsubIndex(m->data[3]);
765 MSG_WAR(0x3A89, "Received SDO Initiate upload (to send data) defined at index 0x1200 + ",
767 MSG_WAR(0x3A90, "Reading at index : ", index);
768 MSG_WAR(0x3A91, "Reading at subIndex : ", subIndex);
769 // Search if a SDO transfert have been yet initiated
770 err = getSDOlineOnUse( d, nodeId, whoami, &line );
772 MSG_ERR(0x1A92, "SDO error : Transmission yet started at line : ", line);
773 MSG_WAR(0x3A93, "nodeId = ", nodeId);
774 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
777 // No line on use. Great !
778 // Try to open a new line.
779 err = getSDOfreeLine( d, whoami, &line );
781 MSG_ERR(0x1A71, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
782 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
785 initSDOline(d, line, nodeId, index, subIndex, SDO_UPLOAD_IN_PROGRESS);
786 // Transfer data from dictionary to the line structure.
787 errorCode = objdictToSDOline(d, line);
790 MSG_ERR(0x1A94, "SDO error : Unable to copy the data from object dictionary. Err code : ",
792 failedSDO(d, nodeId, whoami, index, subIndex, errorCode);
795 // Preparing the response.
796 getSDOlineRestBytes(d, line, &nbBytes); // Nb bytes to transfer ?
797 sdo.nodeId = nodeId; // The server node Id;
799 // normal transfert. (segmented).
800 // code to send the initiate upload response. (cs = 2)
801 sdo.body.data[0] = (2 << 5) | 1;
802 sdo.body.data[1] = index & 0xFF; // LSB
803 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
804 sdo.body.data[3] = subIndex;
805 sdo.body.data[4] = nbBytes; // Limitation of canfestival2 : Max tranfert is 256 bytes.
806 // It takes too much memory to upgrate to 2^32 because the size of data is also coded
807 // in the object dictionary, at every index and subindex.
808 for (i = 5 ; i < 8 ; i++)
809 sdo.body.data[i] = 0;
810 MSG_WAR(0x3A95, "SDO. Sending normal upload initiate response defined at index 0x1200 + ", nodeId);
811 sendSDO(d, whoami, sdo);
814 // Expedited upload. (cs = 2 ; e = 1)
815 sdo.body.data[0] = (2 << 5) | ((4 - nbBytes) << 2) | 3;
816 sdo.body.data[1] = index & 0xFF; // LSB
817 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
818 sdo.body.data[3] = subIndex;
819 err = lineToSDO(d, line, nbBytes, sdo.body.data + 4);
821 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
824 for (i = 4 + nbBytes ; i < 8 ; i++)
825 sdo.body.data[i] = 0;
826 MSG_WAR(0x3A96, "SDO. Sending expedited upload initiate response defined at index 0x1200 + ",
828 sendSDO(d, whoami, sdo);
830 resetSDOline(d, line);
832 } // end if I am SERVER
835 // It is the response for the previous initiate upload request.
836 // We should find a line opened for this.
837 err = getSDOlineOnUse( d, nodeId, whoami, &line);
839 err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
841 MSG_ERR(0x1A97, "SDO error : Received response for unknown upload request from nodeId", nodeId);
842 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
846 RestartSDO_TIMER(line)
847 index = d->transfers[line].index;
848 subIndex = d->transfers[line].subIndex;
850 if (getSDOe(m->data[0])) { // If SDO expedited
851 // nb of data to be uploaded
852 nbBytes = 4 - getSDOn2(m->data[0]);
853 // Storing the data in the line structure.
854 err = SDOtoLine(d, line, nbBytes, (*m).data + 4);
856 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
859 // SDO expedited -> transfert finished. data are available via getReadResultNetworkDict().
860 MSG_WAR(0x3A98, "SDO expedited upload finished. Response received from node : ", nodeId);
862 d->transfers[line].count = nbBytes;
863 d->transfers[line].state = SDO_FINISHED;
866 else { // So, if it is not an expedited transfert
867 // Storing the nb of data to receive.
868 if (getSDOs(m->data[0])) {
869 nbBytes = m->data[4]; // Remember the limitation to 255 bytes to transfert
870 err = setSDOlineRestBytes(d, line, nbBytes);
872 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
876 // Requesting next segment. (cs = 3)
878 sdo.body.data[0] = 3 << 5;
879 for (i = 1 ; i < 8 ; i++)
880 sdo.body.data[i] = 0;
881 MSG_WAR(0x3A99, "SDO. Sending upload segment request to node : ", nodeId);
882 sendSDO(d, whoami, sdo);
889 if (whoami == SDO_SERVER) {
890 // Receiving a upload segment.
891 // A SDO transfert should have been yet initiated.
892 err = getSDOlineOnUse( d, nodeId, whoami, &line );
894 err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
896 MSG_ERR(0x1AA0, "SDO error : Received upload segment for unstarted trans. index 0x1200 + ",
898 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
902 RestartSDO_TIMER(line)
903 MSG_WAR(0x3AA1, "Received SDO upload segment defined at index 0x1200 + ", nodeId);
904 index = d->transfers[line].index;
905 subIndex = d->transfers[line].subIndex;
907 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
908 MSG_ERR(0x1AA2, "SDO error : Toggle error : ", getSDOt(m->data[0]));
909 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
912 // Uploading next segment. We need to know if it will be the last one.
913 getSDOlineRestBytes(d, line, &nbBytes);
915 // The segment to transfer is not the last one.
916 // code to send the next segment. (cs = 0; c = 0)
917 sdo.nodeId = nodeId; // The server node Id;
918 sdo.body.data[0] = (d->transfers[line].toggle << 4);
919 err = lineToSDO(d, line, 7, sdo.body.data + 1);
921 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
924 // Inverting the toggle for the next tranfert.
925 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
926 MSG_WAR(0x3AA3, "SDO. Sending upload segment defined at index 0x1200 + ", nodeId);
927 sendSDO(d, whoami, sdo);
931 // code to send the last segment. (cs = 0; c = 1)
932 sdo.nodeId = nodeId; // The server node Id;
933 sdo.body.data[0] = (d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1;
934 err = lineToSDO(d, line, nbBytes, sdo.body.data + 1);
936 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
939 for (i = nbBytes + 1 ; i < 8 ; i++)
940 sdo.body.data[i] = 0;
941 MSG_WAR(0x3AA4, "SDO. Sending last upload segment defined at index 0x1200 + ", nodeId);
942 sendSDO(d, whoami, sdo);
944 resetSDOline(d, line);
949 // It is the response for the previous initiate download request.
950 // We should find a line opened for this.
951 err = getSDOlineOnUse( d, nodeId, whoami, &line);
953 err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
955 MSG_ERR(0x1AA5, "SDO error : Received response for unknown download request from nodeId", nodeId);
956 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
960 RestartSDO_TIMER(line)
961 index = d->transfers[line].index;
962 subIndex = d->transfers[line].subIndex;
963 // End transmission or requesting next segment.
964 getSDOlineRestBytes(d, line, &nbBytes);
966 MSG_WAR(0x3AA6, "SDO End download expedited. Response received. from nodeId", nodeId);
968 d->transfers[line].state = SDO_FINISHED;
972 // more than one request to send
973 // code to send the next segment. (cs = 0; c = 0)
974 sdo.nodeId = nodeId; // The server node Id;
975 sdo.body.data[0] = (d->transfers[line].toggle << 4);
976 err = lineToSDO(d, line, 7, sdo.body.data + 1);
978 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
984 // code to send the last segment. (cs = 0; c = 1)
985 sdo.nodeId = nodeId; // The server node Id;
986 sdo.body.data[0] = (d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1;
987 err = lineToSDO(d, line, nbBytes, sdo.body.data + 1);
989 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
992 for (i = nbBytes + 1 ; i < 8 ; i++)
993 sdo.body.data[i] = 0;
995 MSG_WAR(0x3AA7, "SDO sending download segment to nodeId", nodeId);
996 sendSDO(d, whoami, sdo);
998 } // end if I am a CLIENT
1002 abortCode = (*m).data[3] |
1004 (m->data[6] << 16) |
1006 // Received SDO abort.
1007 // Looking for the line concerned.
1008 if (whoami == SDO_SERVER) {
1009 err = getSDOlineOnUse( d, nodeId, whoami, &line );
1011 resetSDOline( d, line );
1012 MSG_WAR(0x3AA8, "SD0. Received SDO abort. Line released. Code : ", abortCode);
1015 MSG_WAR(0x3AA9, "SD0. Received SDO abort. No line found. Code : ", abortCode);
1016 // Tips : The end user has no way to know that the server node has received an abort SDO.
1017 // Its is ok, I think.
1019 else { // If I am CLIENT
1020 err = getSDOlineOnUse( d, nodeId, whoami, &line );
1022 // The line *must* be released by the core program.
1024 d->transfers[line].state = SDO_ABORTED_RCV;
1025 MSG_WAR(0x3AB0, "SD0. Received SDO abort. Line state ABORTED. Code : ", abortCode);
1028 MSG_WAR(0x3AB1, "SD0. Received SDO abort. No line found. Code : ", abortCode);
1032 // Error : Unknown cs
1033 MSG_ERR(0x1AB2, "SDO. Received unknown command specifier : ", getSDOcs(m->data[0]));
1040 /*******************************************************************)******/
1041 UNS8 writeNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index,
1042 UNS8 subIndex, UNS8 count, UNS8 dataType, void *data)
1047 s_SDO sdo; // SDO to transmit
1053 UNS8 *pNodeIdServer;
1057 MSG_WAR(0x3AC0, "Send SDO to write in the dictionary of node : ", nodeId);
1058 MSG_WAR(0x3AC1, " At index : ", index);
1059 MSG_WAR(0x3AC2, " subIndex : ", subIndex);
1060 MSG_WAR(0x3AC3, " nb bytes : ", count);
1062 // Verify that there is no SDO communication yet.
1063 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1065 MSG_ERR(0x1AC4, "SDO error : Communication yet established. with node : ", nodeId);
1068 // Taking the line ...
1069 err = getSDOfreeLine( d, SDO_CLIENT, &line );
1071 MSG_ERR(0x1AC5, "SDO error : No line free, too many SDO in progress. Aborted for node : ", nodeId);
1074 // Check which SDO to use to communicate with the node
1075 offset = d->firstIndex->SDO_CLT;
1076 lastIndex = d->lastIndex->SDO_CLT;
1078 MSG_ERR(0x1AC6, "writeNetworkDict : No SDO client index found", 0);
1082 while (offset <= lastIndex) {
1083 if (d->objdict[offset].bSubCount <= 3) {
1084 MSG_ERR(0x1AC8, "Subindex 3 not found at index ", 0x1280 + i);
1087 // looking for the nodeId server
1088 pNodeIdServer = d->objdict[offset].pSubindex[3].pObject;
1089 nodeIdServer = *pNodeIdServer;
1090 MSG_WAR(0x1AD2, "index : ", 0x1280 + i);
1091 MSG_WAR(0x1AD3, "nodeIdServer : ", nodeIdServer);
1093 if(nodeIdServer == nodeId) {
1101 MSG_ERR(0x1AC9, "SDO. Error. No client found to communicate with node : ", nodeId);
1104 MSG_WAR(0x3AD0," SDO client defined at index : ", 0x1280 + i);
1105 initSDOline(d, line, nodeId, index, subIndex, SDO_DOWNLOAD_IN_PROGRESS);
1106 d->transfers[line].count = count;
1107 d->transfers[line].dataType = dataType;
1109 // Copy data to transfers structure.
1110 for (j = 0 ; j < count ; j++) {
1111 # ifdef CANOPEN_BIG_ENDIAN
1113 d->transfers[line].data[count - 1 - j] = ((char *)data)[j];
1114 else // String of bytes.
1115 d->transfers[line].data[j] = ((char *)data)[j];
1117 d->transfers[line].data[j] = ((char *)data)[j];
1120 // Send the SDO to the server. Initiate download, cs=1.
1121 sdo.nodeId = nodeId;
1122 if (count <= 4) { // Expedited transfert
1123 sdo.body.data[0] = (1 << 5) | ((4 - count) << 2) | 3;
1124 for (i = 4 ; i < 8 ; i++)
1125 sdo.body.data[i] = d->transfers[line].data[i - 4];
1126 d->transfers[line].offset = count;
1128 else { // Normal transfert
1129 sdo.body.data[0] = (1 << 5) | 1;
1130 sdo.body.data[4] = count; // nb of byte to transmit. Max = 255. (canfestival2 limitation).
1131 for (i = 5 ; i < 8 ; i++)
1132 sdo.body.data[i] = 0;
1134 sdo.body.data[1] = index & 0xFF; // LSB
1135 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
1136 sdo.body.data[3] = subIndex;
1138 err = sendSDO(d, SDO_CLIENT, sdo);
1140 MSG_ERR(0x1AD1, "SDO. Error while sending SDO to node : ", nodeId);
1142 resetSDOline(d, line);
1150 /***************************************************************************/
1151 UNS8 readNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType)
1159 s_SDO sdo; // SDO to transmit
1160 UNS8 *pNodeIdServer;
1165 MSG_WAR(0x3AD5, "Send SDO to read in the dictionary of node : ", nodeId);
1166 MSG_WAR(0x3AD6, " At index : ", index);
1167 MSG_WAR(0x3AD7, " subIndex : ", subIndex);
1170 // Verify that there is no SDO communication yet.
1171 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1173 MSG_ERR(0x1AD8, "SDO error : Communication yet established. with node : ", nodeId);
1176 // Taking the line ...
1177 err = getSDOfreeLine( d, SDO_CLIENT, &line );
1179 MSG_ERR(0x1AD9, "SDO error : No line free, too many SDO in progress. Aborted for node : ", nodeId);
1183 MSG_WAR(0x3AE0, "Transmission on line : ", line);
1185 // Check which SDO to use to communicate with the node
1186 offset = d->firstIndex->SDO_CLT;
1187 lastIndex = d->lastIndex->SDO_CLT;
1189 MSG_ERR(0x1AE1, "writeNetworkDict : No SDO client index found", 0);
1193 while (offset <= lastIndex) {
1194 if (d->objdict[offset].bSubCount <= 3) {
1195 MSG_ERR(0x1AE2, "Subindex 3 not found at index ", 0x1280 + i);
1198 // looking for the nodeId server
1199 pNodeIdServer = d->objdict[offset].pSubindex[3].pObject;
1200 nodeIdServer = *pNodeIdServer;
1202 if(nodeIdServer == nodeId) {
1210 MSG_ERR(0x1AE3, "SDO. Error. No client found to communicate with node : ", nodeId);
1213 MSG_WAR(0x3AE4," SDO client defined at index : ", 0x1280 + i);
1214 initSDOline(d, line, nodeId, index, subIndex, SDO_UPLOAD_IN_PROGRESS);
1215 getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1216 sdo.nodeId = nodeId;
1217 // Send the SDO to the server. Initiate upload, cs=2.
1218 d->transfers[line].dataType = dataType;
1219 sdo.body.data[0] = (2 << 5);
1220 sdo.body.data[1] = index & 0xFF; // LSB
1221 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
1222 sdo.body.data[3] = subIndex;
1223 for (i = 4 ; i < 8 ; i++)
1224 sdo.body.data[i] = 0;
1225 err = sendSDO(d, SDO_CLIENT, sdo);
1227 MSG_ERR(0x1AE5, "SDO. Error while sending SDO to node : ", nodeId);
1229 resetSDOline(d, line);
1235 /***************************************************************************/
1237 UNS8 getReadResultNetworkDict (CO_Data* d, UNS8 nodeId, void* data, UNS8 *size,
1245 // Looking for the line tranfert.
1246 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1248 MSG_ERR(0x1AF0, "SDO error : No line found for communication with node : ", nodeId);
1249 return SDO_ABORTED_INTERNAL;
1251 if (d->transfers[line].state != SDO_FINISHED)
1252 return d->transfers[line].state;
1254 // Transfert is finished. Put the value in the data.
1255 * size = d->transfers[line].count;
1256 for ( i = 0 ; i < *size ; i++) {
1257 # ifdef CANOPEN_BIG_ENDIAN
1258 if (d->transfers[line].dataType != visible_string)
1259 ( (char *) data)[*size - 1 - i] = d->transfers[line].data[i];
1260 else // String of bytes.
1261 ( (char *) data)[i] = d->transfers[line].data[i];
1263 ( (char *) data)[i] = d->transfers[line].data[i];
1266 return SDO_FINISHED;
1269 /***************************************************************************/
1271 UNS8 getWriteResultNetworkDict (CO_Data* d, UNS8 nodeId, UNS32 * abortCode)
1277 // Looking for the line tranfert.
1278 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1280 MSG_ERR(0x1AF1, "SDO error : No line found for communication with node : ", nodeId);
1281 return SDO_ABORTED_INTERNAL;
1283 * abortCode = d->transfers[line].abortCode;
1284 return d->transfers[line].state;