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)
115 const indextable *ptrTable;
119 size = d->transfers[line].count;
120 errorCode = setODentry(d, d->transfers[line].index, d->transfers[line].subIndex,
121 (void *) d->transfers[line].data, &size, 1);
122 if (errorCode != OD_SUCCESSFUL)
129 /***************************************************************************/
130 UNS32 objdictToSDOline (CO_Data* d, UNS8 line)
138 MSG_WAR(0x3A05, "Reading at index : ", d->transfers[line].index);
139 MSG_WAR(0x3A06, "Reading at subIndex : ", d->transfers[line].subIndex);
141 errorCode = getODentry(d, d->transfers[line].index,
142 d->transfers[line].subIndex,
143 (void *)d->transfers[line].data,
144 &size, &dataType, 0);
146 if (errorCode != OD_SUCCESSFUL)
149 d->transfers[line].count = size;
150 d->transfers[line].offset = 0;
154 /***************************************************************************/
155 UNS8 lineToSDO (CO_Data* d, UNS8 line, UNS8 nbBytes, UNS8* data) {
159 if ((d->transfers[line].offset + nbBytes) > SDO_MAX_LENGTH_TRANSFERT) {
160 MSG_ERR(0x1A10,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFERT", nbBytes);
163 if ((d->transfers[line].offset + nbBytes) > d->transfers[line].count) {
164 MSG_ERR(0x1A11,"SDO Size of data too large. Exceed count", nbBytes);
167 offset = d->transfers[line].offset;
168 for (i = 0 ; i < nbBytes ; i++)
169 * (data + i) = d->transfers[line].data[offset + i];
170 d->transfers[line].offset = d->transfers[line].offset + nbBytes;
175 /***************************************************************************/
176 UNS8 SDOtoLine (CO_Data* d, UNS8 line, UNS8 nbBytes, UNS8* data)
181 if ((d->transfers[line].offset + nbBytes) > SDO_MAX_LENGTH_TRANSFERT) {
182 MSG_ERR(0x1A15,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFERT", nbBytes);
185 offset = d->transfers[line].offset;
186 for (i = 0 ; i < nbBytes ; i++)
187 d->transfers[line].data[offset + i] = * (data + i);
188 d->transfers[line].offset = d->transfers[line].offset + nbBytes;
192 /***************************************************************************/
193 UNS8 failedSDO (CO_Data* d, UNS8 nodeId, UNS8 whoami, UNS16 index,
194 UNS8 subIndex, UNS32 abortCode)
198 err = getSDOlineOnUse( d, nodeId, whoami, &line );
200 MSG_WAR(0x3A20, "FailedSDO : line found : ", line);
201 if ((! err) && (whoami == SDO_SERVER)) {
202 resetSDOline( d, line );
203 MSG_WAR(0x3A21, "FailedSDO : line released : ", line);
205 if ((! err) && (whoami == SDO_CLIENT))
207 d->transfers[line].state = SDO_ABORTED_INTERNAL;
208 MSG_WAR(0x3A22, "Sending SDO abort ", 0);
209 err = sendSDOabort(d, whoami, index, subIndex, abortCode);
211 MSG_WAR(0x3A23, "Unable to send the SDO abort", 0);
217 /***************************************************************************/
218 void resetSDOline ( CO_Data* d, UNS8 line )
222 initSDOline(d, line, 0, 0, 0, SDO_RESET);
223 for (i = 0 ; i < SDO_MAX_LENGTH_TRANSFERT ; i++)
224 d->transfers[line].data[i] = 0;
227 /***************************************************************************/
228 UNS8 initSDOline (CO_Data* d, UNS8 line, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 state)
230 if (state == SDO_DOWNLOAD_IN_PROGRESS || state == SDO_UPLOAD_IN_PROGRESS){
235 d->transfers[line].nodeId = nodeId;
236 d->transfers[line].index = index;
237 d->transfers[line].subIndex = subIndex;
238 d->transfers[line].state = state;
239 d->transfers[line].toggle = 0;
240 d->transfers[line].count = 0;
241 d->transfers[line].offset = 0;
242 d->transfers[line].dataType = 0;
246 /***************************************************************************/
247 UNS8 getSDOfreeLine ( CO_Data* d, UNS8 whoami, UNS8 *line )
252 for (i = 0 ; i < SDO_MAX_SIMULTANEOUS_TRANSFERTS ; i++){
253 if ( d->transfers[i].state == SDO_RESET ) {
255 d->transfers[i].whoami = whoami;
259 MSG_ERR(0x1A25, "Too many SDO in progress. Aborted.", i);
263 /***************************************************************************/
264 UNS8 getSDOlineOnUse (CO_Data* d, UNS8 nodeId, UNS8 whoami, UNS8 *line)
269 for (i = 0 ; i < SDO_MAX_SIMULTANEOUS_TRANSFERTS ; i++){
270 if ( (d->transfers[i].state != SDO_RESET) &&
271 (d->transfers[i].nodeId == nodeId) &&
272 (d->transfers[i].whoami == whoami) ) {
280 /***************************************************************************/
281 UNS8 closeSDOtransfer (CO_Data* d, UNS8 nodeId, UNS8 whoami)
285 err = getSDOlineOnUse(d, nodeId, whoami, &line);
287 MSG_WAR(0x2A30, "No SDO communication to close for node : ", nodeId);
290 resetSDOline(d, line);
294 /***************************************************************************/
295 UNS8 getSDOlineRestBytes (CO_Data* d, UNS8 line, UNS8 * nbBytes)
297 if (d->transfers[line].count == 0) // if received initiate SDO protocol with e=0 and s=0
300 * nbBytes = d->transfers[line].count - d->transfers[line].offset;
304 /***************************************************************************/
305 UNS8 setSDOlineRestBytes (CO_Data* d, UNS8 line, UNS8 nbBytes)
307 if (nbBytes > SDO_MAX_LENGTH_TRANSFERT) {
308 MSG_ERR(0x1A35,"SDO Size of data too large. Exceed SDO_MAX_LENGTH_TRANSFERT", nbBytes);
311 d->transfers[line].count = nbBytes;
316 /***************************************************************************/
317 UNS8 sendSDO (CO_Data* d, UNS8 whoami, s_SDO sdo)
324 UNS32 * pwCobId = NULL;
325 UNS8 * pwNodeId = NULL;
330 MSG_WAR(0x3A38, "sendSDO",0);
331 if( !((d->nodeState == Operational) || (d->nodeState == Pre_operational ))) {
332 MSG_WAR(0x2A39, "unable to send the SDO (not in op or pre-op mode", d->nodeState);
336 /*get the server->client cobid*/
337 if ( whoami == SDO_SERVER ) {/*case server. Easy because today only one server SDO is authorized in CanFestival*/
338 offset = d->firstIndex->SDO_SVR;
340 MSG_ERR(0x1A42, "SendSDO : No SDO server found", 0);
343 pwCobId = d->objdict[offset].pSubindex[2].pObject;
344 MSG_WAR(0x3A41, "I am server. cobId : ", *pwCobId);
346 else { /*case client*/
347 /* Get the client->server cobid.*/
349 offset = d->firstIndex->SDO_CLT;
350 lastIndex = d->lastIndex->SDO_CLT;
352 MSG_ERR(0x1A42, "SendSDO : No SDO client index found", 0);
355 /* First, have to find at the index where is defined the communication with the server node */
356 while (offset <= lastIndex){
357 MSG_WAR(0x3A43,"Reading index : ", 0x1280 + sdoNum);
358 if (d->objdict[offset].bSubCount <= 3) {
359 MSG_ERR(0x1A28, "Subindex 3 not found at index ", 0x1280 + sdoNum);
362 pwNodeId = d->objdict[offset].pSubindex[3].pObject;
363 MSG_WAR(0x3A44, "Found nodeId server = ", *pwNodeId);
364 if(*pwNodeId == sdo.nodeId) {
372 MSG_WAR (0x2A45, "No SDO client corresponds to the mesage to send to node ", sdo.nodeId);
375 /* Second, read the cobid client->server */
376 pwCobId = d->objdict[offset].pSubindex[1].pObject;
378 /* message copy for sending */
379 m.cob_id.w = *pwCobId;
380 m.rtr = NOT_A_REQUEST;
381 //the length of SDO must be 8
383 for (i = 0 ; i < 8 ; i++) {
384 m.data[i] = sdo.body.data[i];
386 return (*d->canSend)(&m);
389 /***************************************************************************/
390 UNS8 sendSDOabort (CO_Data* d, UNS8 whoami, UNS16 index, UNS8 subIndex, UNS32 abortCode)
394 MSG_WAR(0x2A50,"Sending SDO abort", abortCode);
395 sdo.nodeId = *d->bDeviceNodeId;
396 sdo.body.data[0] = 0x80;
398 sdo.body.data[1] = index & 0xFF; // LSB
399 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
401 sdo.body.data[3] = subIndex;
403 sdo.body.data[4] = (UNS8)(abortCode & 0xFF);
404 sdo.body.data[5] = (UNS8)((abortCode >> 8) & 0xFF);
405 sdo.body.data[6] = (UNS8)((abortCode >> 16) & 0xFF);
406 sdo.body.data[7] = (UNS8)((abortCode >> 24) & 0xFF);
407 ret = sendSDO(d, whoami, sdo);
412 /***************************************************************************/
413 UNS8 proceedSDO (CO_Data* d, Message *m)
417 UNS8 nbBytes; // received or to be transmited.
418 UNS8 nodeId = 0; // The node from which the SDO is received
419 UNS8 *pNodeId = NULL;
420 UNS8 whoami = SDO_UNKNOWN; // SDO_SERVER or SDO_CLIENT.
421 UNS32 errorCode; // while reading or writing in the local object dictionary.
422 s_SDO sdo; // SDO to transmit
427 UNS32 * pCobId = NULL;
435 MSG_WAR(0x3A60, "proceedSDO ", 0);
436 whoami = SDO_UNKNOWN;
437 // Looking for the cobId in the object dictionary.
439 offset = d->firstIndex->SDO_SVR;
440 lastIndex = d->lastIndex->SDO_SVR;
442 if(offset) while (offset <= lastIndex) {
443 if (d->objdict[offset].bSubCount <= 1) {
444 MSG_ERR(0x1A61, "Subindex 1 not found at index ", 0x1200 + j);
447 pCobId = d->objdict[offset].pSubindex[1].pObject;
448 if ( *pCobId == (*m).cob_id.w ) {
450 MSG_WAR(0x3A62, "proceedSDO. I am server. index : ", 0x1200 + j);
451 // In case of server, the node id of the client may be unknown. So we put the index minus offset
452 // 0x1200 where the cobid received is defined.
459 if (whoami == SDO_UNKNOWN) {
461 offset = d->firstIndex->SDO_CLT;
462 lastIndex = d->lastIndex->SDO_CLT;
464 if(offset) while (offset <= lastIndex) {
465 if (d->objdict[offset].bSubCount <= 3) {
466 MSG_ERR(0x1A63, "Subindex 3 not found at index ", 0x1280 + j);
469 // a) Looking for the cobid received.
470 pCobId = d->objdict[offset].pSubindex[2].pObject;
471 if (*pCobId == (*m).cob_id.w ) {
472 // b) cobid found, so reading the node id of the server.
473 pNodeId = d->objdict[offset].pSubindex[3].pObject;
476 MSG_WAR(0x3A64, "proceedSDO. I am server. index : ", 0x1280 + j);
477 MSG_WAR(0x3A65, " Server nodeId : ", nodeId);
484 if (whoami == SDO_UNKNOWN) {
485 return 0xFF;// This SDO was not for us !
488 // Test if the size of the SDO is ok
489 if ( (*m).len != 8) {
490 MSG_ERR(0x1A67, "Error size SDO. CobId : ", (*m).cob_id.w);
491 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_GENERAL_ERROR);
495 if (whoami == SDO_CLIENT) {
496 MSG_WAR(0x3A68, "I am CLIENT. Received SDO from nodeId : ", nodeId);
499 MSG_WAR(0x3A69, "I am SERVER. Received SDO cobId : ", (*m).cob_id.w);
502 // Testing the command specifier
503 // Allowed : cs = 0, 1, 2, 3, 4. (= all except those for block tranfert).
504 // cs = other : Not allowed -> abort.
505 switch (getSDOcs(m->data[0])) {
509 if (whoami == SDO_SERVER) {
510 // Receiving a download segment data.
511 // A SDO transfert should have been yet initiated.
512 err = getSDOlineOnUse( d, nodeId, whoami, &line );
514 err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
516 MSG_ERR(0x1A70, "SDO error : Received download segment for unstarted trans. index 0x1200 + ",
518 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
522 RestartSDO_TIMER(line)
523 MSG_WAR(0x3A71, "Received SDO download segment defined at index 0x1200 + ", nodeId);
524 index = d->transfers[line].index;
525 subIndex = d->transfers[line].subIndex;
527 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
528 MSG_ERR(0x1A72, "SDO error : Toggle error : ", getSDOt(m->data[0]));
529 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
532 // Nb of data to be downloaded
533 nbBytes = 7 - getSDOn3(m->data[0]);
534 // Store the data in the transfert structure.
535 err = SDOtoLine(d, line, nbBytes, (*m).data + 1);
537 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
540 // Sending the SDO response, CS = 1
541 sdo.nodeId = *d->bDeviceNodeId; // The node id of the server, (here it is the sender).
542 sdo.body.data[0] = (1 << 5) | (d->transfers[line].toggle << 4);
543 for (i = 1 ; i < 8 ; i++)
544 sdo.body.data[i] = 0;
545 MSG_WAR(0x3A73, "SDO. Send response to download request defined at index 0x1200 + ", nodeId);
546 sendSDO(d, whoami, sdo);
547 // Inverting the toggle for the next segment.
548 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
549 // If it was the last segment,
550 if (getSDOc(m->data[0])) {
551 // Transfering line data to object dictionary.
552 // The code does not use the "d" of initiate frame. So it is safe if e=s=0
553 errorCode = SDOlineToObjdict(d, line);
555 MSG_ERR(0x1A54, "SDO error : Unable to copy the data in the object dictionary", 0);
556 failedSDO(d, nodeId, whoami, index, subIndex, errorCode);
559 // Release of the line
560 resetSDOline(d, line);
561 MSG_WAR(0x3A74, "SDO. End of download defined at index 0x1200 + ", nodeId);
566 // It is a request for a previous upload segment. We should find a line opened for this.
567 err = getSDOlineOnUse( d, nodeId, whoami, &line);
569 err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
571 MSG_ERR(0x1A75, "SDO error : Received segment response for unknown trans. from nodeId", nodeId);
572 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
576 RestartSDO_TIMER(line)
577 index = d->transfers[line].index;
578 subIndex = d->transfers[line].subIndex;
579 // test of the toggle;
580 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
581 MSG_ERR(0x1A76, "SDO error : Received segment response Toggle error. from nodeId", nodeId);
582 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
585 // nb of data to be uploaded
586 nbBytes = 7 - getSDOn3(m->data[0]);
587 // Storing the data in the line structure.
588 err = SDOtoLine(d, line, nbBytes, (*m).data + 1);
590 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
593 // Inverting the toggle for the next segment.
594 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
595 // If it was the last segment,
596 if ( getSDOc(m->data[0])) {
597 // Put in state finished
598 // The code is safe for the case e=s=0 in initiate frame.
600 d->transfers[line].state = SDO_FINISHED;
601 MSG_WAR(0x3A77, "SDO. End of upload from node : ", nodeId);
603 else { // more segments to receive
604 // Sending the request for the next segment.
606 sdo.body.data[0] = (3 << 5) | (d->transfers[line].toggle << 4);
607 for (i = 1 ; i < 8 ; i++)
608 sdo.body.data[i] = 0;
609 sendSDO(d, whoami, sdo);
610 MSG_WAR(0x3A78, "SDO send upload segment request to nodeId", nodeId);
617 // Receive of an initiate download
618 if (whoami == SDO_SERVER) {
619 index = getSDOindex(m->data[1],m->data[2]);
620 subIndex = getSDOsubIndex(m->data[3]);
621 MSG_WAR(0x3A79, "Received SDO Initiate Download (to store data) defined at index 0x1200 + ",
623 MSG_WAR(0x3A80, "Writing at index : ", index);
624 MSG_WAR(0x3A80, "Writing at subIndex : ", subIndex);
626 // Search if a SDO transfert have been yet initiated
627 err = getSDOlineOnUse( d, nodeId, whoami, &line );
629 MSG_ERR(0x1A81, "SDO error : Transmission yet started.", 0);
630 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
633 // No line on use. Great !
634 // Try to open a new line.
635 err = getSDOfreeLine( d, whoami, &line );
637 MSG_ERR(0x1A82, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
638 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
641 initSDOline(d, line, nodeId, index, subIndex, SDO_DOWNLOAD_IN_PROGRESS);
643 if (getSDOe(m->data[0])) { // If SDO expedited
644 // nb of data to be downloaded
645 nbBytes = 4 - getSDOn2(m->data[0]);
646 // Storing the data in the line structure.
647 d->transfers[line].count = nbBytes;
648 err = SDOtoLine(d, line, nbBytes, (*m).data + 4);
651 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
655 // SDO expedited -> transfert finished. Data can be stored in the dictionary.
656 // The line will be reseted when it is downloading in the dictionary.
657 MSG_WAR(0x3A83, "SDO Initiate Download is an expedited transfert. Finished.: ", nodeId);
658 // Transfering line data to object dictionary.
659 errorCode = SDOlineToObjdict(d, line);
661 MSG_ERR(0x1A84, "SDO error : Unable to copy the data in the object dictionary", 0);
662 failedSDO(d, nodeId, whoami, index, subIndex, errorCode);
665 // Release of the line.
666 resetSDOline(d, line);
668 else {// So, if it is not an expedited transfert
669 if (getSDOs(m->data[0])) {
670 // TODO : if e and s = 0, not reading m->data[4] but put nbBytes = 0
671 nbBytes = m->data[4]; // Transfert limited to 255 bytes.
672 err = setSDOlineRestBytes(d, nodeId, nbBytes);
674 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
679 //Sending a SDO, cs=3
680 sdo.nodeId = *d->bDeviceNodeId; // The node id of the server, (here it is the sender).
681 sdo.body.data[0] = 3 << 5;
682 sdo.body.data[1] = index & 0xFF; // LSB
683 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
684 sdo.body.data[3] = subIndex;
685 for (i = 4 ; i < 8 ; i++)
686 sdo.body.data[i] = 0;
687 sendSDO(d, whoami, sdo);
688 } // end if I am SERVER
691 // It is a response for a previous download segment. We should find a line opened for this.
692 err = getSDOlineOnUse( d, nodeId, whoami, &line);
694 err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
696 MSG_ERR(0x1A85, "SDO error : Received segment response for unknown trans. from nodeId", nodeId);
697 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
701 RestartSDO_TIMER(line)
702 index = d->transfers[line].index;
703 subIndex = d->transfers[line].subIndex;
704 // test of the toggle;
705 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
706 MSG_ERR(0x1A86, "SDO error : Received segment response Toggle error. from nodeId", nodeId);
707 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
711 // End transmission or downloading next segment. We need to know if it will be the last one.
712 getSDOlineRestBytes(d, line, &nbBytes);
714 MSG_WAR(0x3A87, "SDO End download. segment response received. OK. from nodeId", nodeId);
716 d->transfers[line].state = SDO_FINISHED;
719 // At least one transfer to send.
721 // several segments to download.
722 // code to send the next segment. (cs = 0; c = 0)
723 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
724 sdo.nodeId = nodeId; // The server node Id;
725 sdo.body.data[0] = (d->transfers[line].toggle << 4);
726 err = lineToSDO(d, line, 7, sdo.body.data + 1);
728 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
734 // code to send the last segment. (cs = 0; c = 1)
735 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
736 sdo.nodeId = nodeId; // The server node Id;
737 sdo.body.data[0] = (d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1;
738 err = lineToSDO(d, line, nbBytes, sdo.body.data + 1);
740 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
743 for (i = nbBytes + 1 ; i < 8 ; i++)
744 sdo.body.data[i] = 0;
746 MSG_WAR(0x3A88, "SDO sending download segment to nodeId", nodeId);
747 sendSDO(d, whoami, sdo);
748 } // end if I am a CLIENT
753 // Receive of an initiate upload.
754 if (whoami == SDO_SERVER) {
755 index = getSDOindex(m->data[1],m->data[2]);
756 subIndex = getSDOsubIndex(m->data[3]);
757 MSG_WAR(0x3A89, "Received SDO Initiate upload (to send data) defined at index 0x1200 + ",
759 MSG_WAR(0x3A90, "Reading at index : ", index);
760 MSG_WAR(0x3A91, "Reading at subIndex : ", subIndex);
761 // Search if a SDO transfert have been yet initiated
762 err = getSDOlineOnUse( d, nodeId, whoami, &line );
764 MSG_ERR(0x1A92, "SDO error : Transmission yet started at line : ", line);
765 MSG_WAR(0x3A93, "nodeId = ", nodeId);
766 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
769 // No line on use. Great !
770 // Try to open a new line.
771 err = getSDOfreeLine( d, whoami, &line );
773 MSG_ERR(0x1A71, "SDO error : No line free, too many SDO in progress. Aborted.", 0);
774 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_LOCAL_CTRL_ERROR);
777 initSDOline(d, line, nodeId, index, subIndex, SDO_UPLOAD_IN_PROGRESS);
778 // Transfer data from dictionary to the line structure.
779 errorCode = objdictToSDOline(d, line);
782 MSG_ERR(0x1A94, "SDO error : Unable to copy the data from object dictionary. Err code : ",
784 failedSDO(d, nodeId, whoami, index, subIndex, errorCode);
787 // Preparing the response.
788 getSDOlineRestBytes(d, line, &nbBytes); // Nb bytes to transfer ?
789 sdo.nodeId = nodeId; // The server node Id;
791 // normal transfert. (segmented).
792 // code to send the initiate upload response. (cs = 2)
793 sdo.body.data[0] = (2 << 5) | 1;
794 sdo.body.data[1] = index & 0xFF; // LSB
795 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
796 sdo.body.data[3] = subIndex;
797 sdo.body.data[4] = nbBytes; // Limitation of canfestival2 : Max tranfert is 256 bytes.
798 // It takes too much memory to upgrate to 2^32 because the size of data is also coded
799 // in the object dictionary, at every index and subindex.
800 for (i = 5 ; i < 8 ; i++)
801 sdo.body.data[i] = 0;
802 MSG_WAR(0x3A95, "SDO. Sending normal upload initiate response defined at index 0x1200 + ", nodeId);
803 sendSDO(d, whoami, sdo);
806 // Expedited upload. (cs = 2 ; e = 1)
807 sdo.body.data[0] = (2 << 5) | ((4 - nbBytes) << 2) | 3;
808 sdo.body.data[1] = index & 0xFF; // LSB
809 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
810 sdo.body.data[3] = subIndex;
811 err = lineToSDO(d, line, nbBytes, sdo.body.data + 4);
813 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
816 for (i = 4 + nbBytes ; i < 8 ; i++)
817 sdo.body.data[i] = 0;
818 MSG_WAR(0x3A96, "SDO. Sending expedited upload initiate response defined at index 0x1200 + ",
820 sendSDO(d, whoami, sdo);
822 resetSDOline(d, line);
824 } // end if I am SERVER
827 // It is the response for the previous initiate upload request.
828 // We should find a line opened for this.
829 err = getSDOlineOnUse( d, nodeId, whoami, &line);
831 err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
833 MSG_ERR(0x1A97, "SDO error : Received response for unknown upload request from nodeId", nodeId);
834 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
838 RestartSDO_TIMER(line)
839 index = d->transfers[line].index;
840 subIndex = d->transfers[line].subIndex;
842 if (getSDOe(m->data[0])) { // If SDO expedited
843 // nb of data to be uploaded
844 nbBytes = 4 - getSDOn2(m->data[0]);
845 // Storing the data in the line structure.
846 err = SDOtoLine(d, line, nbBytes, (*m).data + 4);
848 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
851 // SDO expedited -> transfert finished. data are available via getReadResultNetworkDict().
852 MSG_WAR(0x3A98, "SDO expedited upload finished. Response received from node : ", nodeId);
854 d->transfers[line].count = nbBytes;
855 d->transfers[line].state = SDO_FINISHED;
858 else { // So, if it is not an expedited transfert
859 // Storing the nb of data to receive.
860 if (getSDOs(m->data[0])) {
861 nbBytes = m->data[4]; // Remember the limitation to 255 bytes to transfert
862 err = setSDOlineRestBytes(d, line, nbBytes);
864 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
868 // Requesting next segment. (cs = 3)
870 sdo.body.data[0] = 3 << 5;
871 for (i = 1 ; i < 8 ; i++)
872 sdo.body.data[i] = 0;
873 MSG_WAR(0x3A99, "SDO. Sending upload segment request to node : ", nodeId);
874 sendSDO(d, whoami, sdo);
881 if (whoami == SDO_SERVER) {
882 // Receiving a upload segment.
883 // A SDO transfert should have been yet initiated.
884 err = getSDOlineOnUse( d, nodeId, whoami, &line );
886 err = d->transfers[line].state != SDO_UPLOAD_IN_PROGRESS;
888 MSG_ERR(0x1AA0, "SDO error : Received upload segment for unstarted trans. index 0x1200 + ",
890 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
894 RestartSDO_TIMER(line)
895 MSG_WAR(0x3AA1, "Received SDO upload segment defined at index 0x1200 + ", nodeId);
896 index = d->transfers[line].index;
897 subIndex = d->transfers[line].subIndex;
899 if (d->transfers[line].toggle != getSDOt(m->data[0])) {
900 MSG_ERR(0x1AA2, "SDO error : Toggle error : ", getSDOt(m->data[0]));
901 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_TOGGLE_NOT_ALTERNED);
904 // Uploading next segment. We need to know if it will be the last one.
905 getSDOlineRestBytes(d, line, &nbBytes);
907 // The segment to transfer is not the last one.
908 // code to send the next segment. (cs = 0; c = 0)
909 sdo.nodeId = nodeId; // The server node Id;
910 sdo.body.data[0] = (d->transfers[line].toggle << 4);
911 err = lineToSDO(d, line, 7, sdo.body.data + 1);
913 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
916 // Inverting the toggle for the next tranfert.
917 d->transfers[line].toggle = ! d->transfers[line].toggle & 1;
918 MSG_WAR(0x3AA3, "SDO. Sending upload segment defined at index 0x1200 + ", nodeId);
919 sendSDO(d, whoami, sdo);
923 // code to send the last segment. (cs = 0; c = 1)
924 sdo.nodeId = nodeId; // The server node Id;
925 sdo.body.data[0] = (d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1;
926 err = lineToSDO(d, line, nbBytes, sdo.body.data + 1);
928 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
931 for (i = nbBytes + 1 ; i < 8 ; i++)
932 sdo.body.data[i] = 0;
933 MSG_WAR(0x3AA4, "SDO. Sending last upload segment defined at index 0x1200 + ", nodeId);
934 sendSDO(d, whoami, sdo);
936 resetSDOline(d, line);
941 // It is the response for the previous initiate download request.
942 // We should find a line opened for this.
943 err = getSDOlineOnUse( d, nodeId, whoami, &line);
945 err = d->transfers[line].state != SDO_DOWNLOAD_IN_PROGRESS;
947 MSG_ERR(0x1AA5, "SDO error : Received response for unknown download request from nodeId", nodeId);
948 failedSDO(d, nodeId, whoami, 0, 0, SDOABT_LOCAL_CTRL_ERROR);
952 RestartSDO_TIMER(line)
953 index = d->transfers[line].index;
954 subIndex = d->transfers[line].subIndex;
955 // End transmission or requesting next segment.
956 getSDOlineRestBytes(d, line, &nbBytes);
958 MSG_WAR(0x3AA6, "SDO End download expedited. Response received. from nodeId", nodeId);
960 d->transfers[line].state = SDO_FINISHED;
964 // more than one request to send
965 // code to send the next segment. (cs = 0; c = 0)
966 sdo.nodeId = nodeId; // The server node Id;
967 sdo.body.data[0] = (d->transfers[line].toggle << 4);
968 err = lineToSDO(d, line, 7, sdo.body.data + 1);
970 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
976 // code to send the last segment. (cs = 0; c = 1)
977 sdo.nodeId = nodeId; // The server node Id;
978 sdo.body.data[0] = (d->transfers[line].toggle << 4) | ((7 - nbBytes) << 1) | 1;
979 err = lineToSDO(d, line, nbBytes, sdo.body.data + 1);
981 failedSDO(d, nodeId, whoami, index, subIndex, SDOABT_GENERAL_ERROR);
984 for (i = nbBytes + 1 ; i < 8 ; i++)
985 sdo.body.data[i] = 0;
987 MSG_WAR(0x3AA7, "SDO sending download segment to nodeId", nodeId);
988 sendSDO(d, whoami, sdo);
990 } // end if I am a CLIENT
994 abortCode = (*m).data[3] |
998 // Received SDO abort.
999 // Looking for the line concerned.
1000 if (whoami == SDO_SERVER) {
1001 err = getSDOlineOnUse( d, nodeId, whoami, &line );
1003 resetSDOline( d, line );
1004 MSG_WAR(0x3AA8, "SD0. Received SDO abort. Line released. Code : ", abortCode);
1007 MSG_WAR(0x3AA9, "SD0. Received SDO abort. No line found. Code : ", abortCode);
1008 // Tips : The end user has no way to know that the server node has received an abort SDO.
1009 // Its is ok, I think.
1011 else { // If I am CLIENT
1012 err = getSDOlineOnUse( d, nodeId, whoami, &line );
1014 // The line *must* be released by the core program.
1016 d->transfers[line].state = SDO_ABORTED_RCV;
1017 MSG_WAR(0x3AB0, "SD0. Received SDO abort. Line state ABORTED. Code : ", abortCode);
1020 MSG_WAR(0x3AB1, "SD0. Received SDO abort. No line found. Code : ", abortCode);
1024 // Error : Unknown cs
1025 MSG_ERR(0x1AB2, "SDO. Received unknown command specifier : ", getSDOcs(m->data[0]));
1032 /*******************************************************************)******/
1033 UNS8 writeNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index,
1034 UNS8 subIndex, UNS8 count, UNS8 dataType, void *data)
1039 s_SDO sdo; // SDO to transmit
1045 UNS8 *pNodeIdServer;
1049 MSG_WAR(0x3AC0, "Send SDO to write in the dictionary of node : ", nodeId);
1050 MSG_WAR(0x3AC1, " At index : ", index);
1051 MSG_WAR(0x3AC2, " subIndex : ", subIndex);
1052 MSG_WAR(0x3AC3, " nb bytes : ", count);
1054 // Verify that there is no SDO communication yet.
1055 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1057 MSG_ERR(0x1AC4, "SDO error : Communication yet established. with node : ", nodeId);
1060 // Taking the line ...
1061 err = getSDOfreeLine( d, SDO_CLIENT, &line );
1063 MSG_ERR(0x1AC5, "SDO error : No line free, too many SDO in progress. Aborted for node : ", nodeId);
1066 // Check which SDO to use to communicate with the node
1067 offset = d->firstIndex->SDO_CLT;
1068 lastIndex = d->lastIndex->SDO_CLT;
1070 MSG_ERR(0x1AC6, "writeNetworkDict : No SDO client index found", 0);
1074 while (offset <= lastIndex) {
1075 if (d->objdict[offset].bSubCount <= 3) {
1076 MSG_ERR(0x1AC8, "Subindex 3 not found at index ", 0x1280 + i);
1079 // looking for the nodeId server
1080 pNodeIdServer = d->objdict[offset].pSubindex[3].pObject;
1081 nodeIdServer = *pNodeIdServer;
1082 MSG_WAR(0x1AD2, "index : ", 0x1280 + i);
1083 MSG_WAR(0x1AD3, "nodeIdServer : ", nodeIdServer);
1085 if(nodeIdServer == nodeId) {
1093 MSG_ERR(0x1AC9, "SDO. Error. No client found to communicate with node : ", nodeId);
1096 MSG_WAR(0x3AD0," SDO client defined at index : ", 0x1280 + i);
1097 initSDOline(d, line, nodeId, index, subIndex, SDO_DOWNLOAD_IN_PROGRESS);
1098 d->transfers[line].count = count;
1099 d->transfers[line].dataType = dataType;
1101 // Copy data to transfers structure.
1102 for (j = 0 ; j < count ; j++) {
1103 # ifdef CANOPEN_BIG_ENDIAN
1105 d->transfers[line].data[count - 1 - j] = ((char *)data)[j];
1106 else // String of bytes.
1107 d->transfers[line].data[j] = ((char *)data)[j];
1109 d->transfers[line].data[j] = ((char *)data)[j];
1112 // Send the SDO to the server. Initiate download, cs=1.
1113 sdo.nodeId = nodeId;
1114 if (count <= 4) { // Expedited transfert
1115 sdo.body.data[0] = (1 << 5) | ((4 - count) << 2) | 3;
1116 for (i = 4 ; i < 8 ; i++)
1117 sdo.body.data[i] = d->transfers[line].data[i - 4];
1118 d->transfers[line].offset = count;
1120 else { // Normal transfert
1121 sdo.body.data[0] = (1 << 5) | 1;
1122 sdo.body.data[4] = count; // nb of byte to transmit. Max = 255. (canfestival2 limitation).
1123 for (i = 5 ; i < 8 ; i++)
1124 sdo.body.data[i] = 0;
1126 sdo.body.data[1] = index & 0xFF; // LSB
1127 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
1128 sdo.body.data[3] = subIndex;
1130 err = sendSDO(d, SDO_CLIENT, sdo);
1132 MSG_ERR(0x1AD1, "SDO. Error while sending SDO to node : ", nodeId);
1134 resetSDOline(d, line);
1142 /***************************************************************************/
1143 UNS8 readNetworkDict (CO_Data* d, UNS8 nodeId, UNS16 index, UNS8 subIndex, UNS8 dataType)
1151 s_SDO sdo; // SDO to transmit
1152 UNS8 *pNodeIdServer;
1157 MSG_WAR(0x3AD5, "Send SDO to read in the dictionary of node : ", nodeId);
1158 MSG_WAR(0x3AD6, " At index : ", index);
1159 MSG_WAR(0x3AD7, " subIndex : ", subIndex);
1162 // Verify that there is no SDO communication yet.
1163 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1165 MSG_ERR(0x1AD8, "SDO error : Communication yet established. with node : ", nodeId);
1168 // Taking the line ...
1169 err = getSDOfreeLine( d, SDO_CLIENT, &line );
1171 MSG_ERR(0x1AD9, "SDO error : No line free, too many SDO in progress. Aborted for node : ", nodeId);
1175 MSG_WAR(0x3AE0, "Transmission on line : ", line);
1177 // Check which SDO to use to communicate with the node
1178 offset = d->firstIndex->SDO_CLT;
1179 lastIndex = d->lastIndex->SDO_CLT;
1181 MSG_ERR(0x1AE1, "writeNetworkDict : No SDO client index found", 0);
1185 while (offset <= lastIndex) {
1186 if (d->objdict[offset].bSubCount <= 3) {
1187 MSG_ERR(0x1AE2, "Subindex 3 not found at index ", 0x1280 + i);
1190 // looking for the nodeId server
1191 pNodeIdServer = d->objdict[offset].pSubindex[3].pObject;
1192 nodeIdServer = *pNodeIdServer;
1194 if(nodeIdServer == nodeId) {
1202 MSG_ERR(0x1AE3, "SDO. Error. No client found to communicate with node : ", nodeId);
1205 MSG_WAR(0x3AE4," SDO client defined at index : ", 0x1280 + i);
1206 initSDOline(d, line, nodeId, index, subIndex, SDO_UPLOAD_IN_PROGRESS);
1207 getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1208 sdo.nodeId = nodeId;
1209 // Send the SDO to the server. Initiate upload, cs=2.
1210 d->transfers[line].dataType = dataType;
1211 sdo.body.data[0] = (2 << 5);
1212 sdo.body.data[1] = index & 0xFF; // LSB
1213 sdo.body.data[2] = (index >> 8) & 0xFF; // MSB
1214 sdo.body.data[3] = subIndex;
1215 for (i = 4 ; i < 8 ; i++)
1216 sdo.body.data[i] = 0;
1217 err = sendSDO(d, SDO_CLIENT, sdo);
1219 MSG_ERR(0x1AE5, "SDO. Error while sending SDO to node : ", nodeId);
1221 resetSDOline(d, line);
1227 /***************************************************************************/
1229 UNS8 getReadResultNetworkDict (CO_Data* d, UNS8 nodeId, void* data, UNS8 *size,
1237 // Looking for the line tranfert.
1238 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1240 MSG_ERR(0x1AF0, "SDO error : No line found for communication with node : ", nodeId);
1241 return SDO_ABORTED_INTERNAL;
1243 if (d->transfers[line].state != SDO_FINISHED)
1244 return d->transfers[line].state;
1246 // Transfert is finished. Put the value in the data.
1247 * size = d->transfers[line].count;
1248 for ( i = 0 ; i < *size ; i++) {
1249 # ifdef CANOPEN_BIG_ENDIAN
1250 if (d->transfers[line].dataType != visible_string)
1251 ( (char *) data)[*size - 1 - i] = d->transfers[line].data[i];
1252 else // String of bytes.
1253 ( (char *) data)[i] = d->transfers[line].data[i];
1255 ( (char *) data)[i] = d->transfers[line].data[i];
1258 return SDO_FINISHED;
1261 /***************************************************************************/
1263 UNS8 getWriteResultNetworkDict (CO_Data* d, UNS8 nodeId, UNS32 * abortCode)
1269 // Looking for the line tranfert.
1270 err = getSDOlineOnUse(d, nodeId, SDO_CLIENT, &line);
1272 MSG_ERR(0x1AF1, "SDO error : No line found for communication with node : ", nodeId);
1273 return SDO_ABORTED_INTERNAL;
1275 * abortCode = d->transfers[line].abortCode;
1276 return d->transfers[line].state;