1 /*
2  * CANopen Service Data Object - client.
3  *
4  * @file        CO_SDOmaster.c
5  * @ingroup     CO_SDOmaster
6  * @author      Janez Paternoster
7  * @author      Matej Severkar
8  * @copyright   2004 - 2020 Janez Paternoster
9  *
10  * This file is part of CANopenNode, an opensource CANopen Stack.
11  * Project home page is <https://github.com/CANopenNode/CANopenNode>.
12  * For more information on CANopen see <http://www.can-cia.org/>.
13  *
14  * Licensed under the Apache License, Version 2.0 (the "License");
15  * you may not use this file except in compliance with the License.
16  * You may obtain a copy of the License at
17  *
18  *     http://www.apache.org/licenses/LICENSE-2.0
19  *
20  * Unless required by applicable law or agreed to in writing, software
21  * distributed under the License is distributed on an "AS IS" BASIS,
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23  * See the License for the specific language governing permissions and
24  * limitations under the License.
25  */
26 
27 
28 #include "CO_driver.h"
29 #include "CO_SDO.h"
30 #include "CO_SDOmaster.h"
31 #include "crc16-ccitt.h"
32 
33 
34 /* Client command specifier */
35 #define CCS_DOWNLOAD_INITIATE           1
36 #define CCS_DOWNLOAD_SEGMENT            0
37 
38 #define CCS_UPLOAD_INITIATE             2
39 #define CCS_UPLOAD_SEGMENT              3
40 
41 #define CCS_ABORT                       4
42 
43 #define CCS_UPLOAD_BLOCK                5
44 #define CCS_DOWNLOAD_BLOCK              6
45 
46 /* Server Command Specifier */
47 #define SCS_UPLOAD_INITIATE             2
48 #define SCS_UPLOAD_SEGMENT              0
49 
50 #define SCS_DOWNLOAD_INITIATED          3
51 #define SCS_DOWNLOAD_SEGMENT            1
52 
53 #define SCS_ABORT                       4
54 
55 #define SCS_DOWNLOAD_BLOCK              5
56 #define SCS_UPLOAD_BLOCK                6
57 
58 
59 /* client states */
60 #define SDO_STATE_NOTDEFINED            0
61 #define SDO_STATE_ABORT                 1
62 
63 /* DOWNLOAD EXPEDITED/SEGMENTED */
64 #define SDO_STATE_DOWNLOAD_INITIATE     10
65 #define SDO_STATE_DOWNLOAD_REQUEST      11
66 #define SDO_STATE_DOWNLOAD_RESPONSE     12
67 
68 /* UPLOAD EXPEDITED/SEGMENTED */
69 #define SDO_STATE_UPLOAD_INITIATED      20
70 #define SDO_STATE_UPLOAD_REQUEST        21
71 #define SDO_STATE_UPLOAD_RESPONSE       22
72 
73 /* DOWNLOAD BLOCK */
74 #define SDO_STATE_BLOCKDOWNLOAD_INITIATE        100
75 #define SDO_STATE_BLOCKDOWNLOAD_INPROGRES       101
76 #define SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK       102
77 #define SDO_STATE_BLOCKDOWNLOAD_CRC             103
78 #define SDO_STATE_BLOCKDOWNLOAD_CRC_ACK         104
79 
80 /* UPLOAD BLOCK */
81 #define SDO_STATE_BLOCKUPLOAD_INITIATE          200
82 #define SDO_STATE_BLOCKUPLOAD_INITIATE_ACK      201
83 #define SDO_STATE_BLOCKUPLOAD_INPROGRES         202
84 #define SDO_STATE_BLOCKUPLOAD_SUB_END           203
85 #define SDO_STATE_BLOCKUPLOAD_BLOCK_ACK         204
86 #define SDO_STATE_BLOCKUPLOAD_BLOCK_ACK_LAST    205
87 #define SDO_STATE_BLOCKUPLOAD_BLOCK_CRC         206
88 #define SDO_STATE_BLOCKUPLOAD_BLOCK_END         207
89 
90 
91 /*
92  * Read received message from CAN module.
93  *
94  * Function will be called (by CAN receive interrupt) every time, when CAN
95  * message with correct identifier will be received. For more information and
96  * description of parameters see file CO_driver.h.
97  */
CO_SDOclient_receive(void * object,const CO_CANrxMsg_t * msg)98 static void CO_SDOclient_receive(void *object, const CO_CANrxMsg_t *msg){
99     CO_SDOclient_t *SDO_C;
100 
101     SDO_C = (CO_SDOclient_t*)object;    /* this is the correct pointer type of the first argument */
102 
103     /* verify message length and message overflow (previous message was not processed yet) */
104     if((msg->DLC == 8U) && (!IS_CANrxNew(SDO_C->CANrxNew)) && (SDO_C->state != SDO_STATE_NOTDEFINED)){
105         if(SDO_C->state != SDO_STATE_BLOCKUPLOAD_INPROGRES) {
106             /* copy data and set 'new message' flag */
107             SDO_C->CANrxData[0] = msg->data[0];
108             SDO_C->CANrxData[1] = msg->data[1];
109             SDO_C->CANrxData[2] = msg->data[2];
110             SDO_C->CANrxData[3] = msg->data[3];
111             SDO_C->CANrxData[4] = msg->data[4];
112             SDO_C->CANrxData[5] = msg->data[5];
113             SDO_C->CANrxData[6] = msg->data[6];
114             SDO_C->CANrxData[7] = msg->data[7];
115 
116             SET_CANrxNew(SDO_C->CANrxNew);
117         }
118         else {
119             /* block upload, copy data directly */
120             uint8_t seqno;
121 
122             SDO_C->CANrxData[0] = msg->data[0];
123             seqno = SDO_C->CANrxData[0] & 0x7f;
124             SDO_C->timeoutTimer = 0;
125             SDO_C->timeoutTimerBLOCK = 0;
126 
127             /* check correct sequence number. */
128             if(seqno == (SDO_C->block_seqno + 1)) {
129                 /* block_seqno is correct */
130                 uint8_t i;
131 
132                 SDO_C->block_seqno++;
133 
134                 /* copy data */
135                 for(i=1; i<8; i++) {
136                     SDO_C->buffer[SDO_C->dataSizeTransfered++] = msg->data[i];
137                     if(SDO_C->dataSizeTransfered >= SDO_C->bufferSize) {
138                         /* buffer full, break reception */
139                         SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END;
140                         SET_CANrxNew(SDO_C->CANrxNew);
141                         break;
142                     }
143                 }
144 
145                 /* break reception if last segment or block sequence is too large */
146                 if(((SDO_C->CANrxData[0] & 0x80U) == 0x80U) || (SDO_C->block_seqno >= SDO_C->block_blksize)) {
147                     SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END;
148                     SET_CANrxNew(SDO_C->CANrxNew);
149                 }
150             }
151             else if((seqno == SDO_C->block_seqno) || (SDO_C->block_seqno == 0U)){
152                 /* Ignore message, if it is duplicate or if sequence didn't started yet. */
153             }
154             else {
155                 /* seqno is totally wrong, break reception. */
156                 SDO_C->state = SDO_STATE_BLOCKUPLOAD_SUB_END;
157                 SET_CANrxNew(SDO_C->CANrxNew);
158             }
159         }
160 
161         /* Optional signal to RTOS, which can resume task, which handles SDO client. */
162         if(IS_CANrxNew(SDO_C->CANrxNew) && SDO_C->pFunctSignal != NULL) {
163             SDO_C->pFunctSignal();
164         }
165     }
166 }
167 
168 
169 /******************************************************************************/
CO_SDOclient_init(CO_SDOclient_t * SDO_C,CO_SDO_t * SDO,CO_SDOclientPar_t * SDOClientPar,CO_CANmodule_t * CANdevRx,uint16_t CANdevRxIdx,CO_CANmodule_t * CANdevTx,uint16_t CANdevTxIdx)170 CO_ReturnError_t CO_SDOclient_init(
171         CO_SDOclient_t         *SDO_C,
172         CO_SDO_t               *SDO,
173         CO_SDOclientPar_t      *SDOClientPar,
174         CO_CANmodule_t         *CANdevRx,
175         uint16_t                CANdevRxIdx,
176         CO_CANmodule_t         *CANdevTx,
177         uint16_t                CANdevTxIdx)
178 {
179     /* verify arguments */
180     if(SDO_C==NULL || SDO==NULL || SDOClientPar==NULL || SDOClientPar->maxSubIndex!=3 ||
181         CANdevRx==NULL || CANdevTx==NULL){
182         return CO_ERROR_ILLEGAL_ARGUMENT;
183     }
184 
185     /* Configure object variables */
186     SDO_C->state = SDO_STATE_NOTDEFINED;
187     CLEAR_CANrxNew(SDO_C->CANrxNew);
188 
189     SDO_C->pst    = 21; /*  block transfer */
190     SDO_C->block_size_max = 127; /*  block transfer */
191 
192     SDO_C->SDO = SDO;
193     SDO_C->SDOClientPar = SDOClientPar;
194 
195     SDO_C->pFunctSignal = NULL;
196 
197     SDO_C->CANdevRx = CANdevRx;
198     SDO_C->CANdevRxIdx = CANdevRxIdx;
199     SDO_C->CANdevTx = CANdevTx;
200     SDO_C->CANdevTxIdx = CANdevTxIdx;
201 
202     SDO_C->COB_IDClientToServerPrev = 0;
203     SDO_C->COB_IDServerToClientPrev = 0;
204     CO_SDOclient_setup(SDO_C, SDO_C->SDOClientPar->COB_IDClientToServer,
205                               SDO_C->SDOClientPar->COB_IDServerToClient,
206                               SDO_C->SDOClientPar->nodeIDOfTheSDOServer);
207 
208     return CO_ERROR_NO;
209 }
210 
211 
212 /******************************************************************************/
CO_SDOclient_initCallback(CO_SDOclient_t * SDOclient,void (* pFunctSignal)(void))213 void CO_SDOclient_initCallback(
214         CO_SDOclient_t         *SDOclient,
215         void                  (*pFunctSignal)(void))
216 {
217     if(SDOclient != NULL){
218         SDOclient->pFunctSignal = pFunctSignal;
219     }
220 }
221 
222 
223 /******************************************************************************/
CO_SDOclient_setup(CO_SDOclient_t * SDO_C,uint32_t COB_IDClientToServer,uint32_t COB_IDServerToClient,uint8_t nodeIDOfTheSDOServer)224 CO_SDOclient_return_t CO_SDOclient_setup(
225         CO_SDOclient_t         *SDO_C,
226         uint32_t                COB_IDClientToServer,
227         uint32_t                COB_IDServerToClient,
228         uint8_t                 nodeIDOfTheSDOServer)
229 {
230     uint32_t idCtoS, idStoC;
231     uint8_t idNode;
232 
233     /* verify parameters */
234     if(SDO_C == NULL || (COB_IDClientToServer&0x7FFFF800L) != 0 ||
235             (COB_IDServerToClient&0x7FFFF800L) != 0 || nodeIDOfTheSDOServer > 127)
236     {
237         return CO_SDOcli_wrongArguments;
238     }
239 
240     /* Configure object variables */
241     SDO_C->state = SDO_STATE_NOTDEFINED;
242     CLEAR_CANrxNew(SDO_C->CANrxNew);
243 
244     /* setup Object Dictionary variables */
245     if((COB_IDClientToServer & 0x80000000L) != 0 || (COB_IDServerToClient & 0x80000000L) != 0 || nodeIDOfTheSDOServer == 0){
246         /* SDO is NOT used */
247         idCtoS = 0x80000000L;
248         idStoC = 0x80000000L;
249         idNode = 0;
250     }
251     else{
252         if(COB_IDClientToServer == 0 || COB_IDServerToClient == 0){
253             idCtoS = 0x600 + nodeIDOfTheSDOServer;
254             idStoC = 0x580 + nodeIDOfTheSDOServer;
255         }
256         else{
257             idCtoS = COB_IDClientToServer;
258             idStoC = COB_IDServerToClient;
259         }
260         idNode = nodeIDOfTheSDOServer;
261     }
262 
263     SDO_C->SDOClientPar->COB_IDClientToServer = idCtoS;
264     SDO_C->SDOClientPar->COB_IDServerToClient = idStoC;
265     SDO_C->SDOClientPar->nodeIDOfTheSDOServer = idNode;
266 
267     /* configure SDO client CAN reception, if differs. */
268     if(SDO_C->COB_IDClientToServerPrev != idCtoS || SDO_C->COB_IDServerToClientPrev != idStoC) {
269         CO_CANrxBufferInit(
270                 SDO_C->CANdevRx,            /* CAN device */
271                 SDO_C->CANdevRxIdx,         /* rx buffer index */
272                 (uint16_t)idStoC,           /* CAN identifier */
273                 0x7FF,                      /* mask */
274                 0,                          /* rtr */
275                 (void*)SDO_C,               /* object passed to receive function */
276                 CO_SDOclient_receive);      /* this function will process received message */
277 
278         /* configure SDO client CAN transmission */
279         SDO_C->CANtxBuff = CO_CANtxBufferInit(
280                 SDO_C->CANdevTx,            /* CAN device */
281                 SDO_C->CANdevTxIdx,         /* index of specific buffer inside CAN module */
282                 (uint16_t)idCtoS,           /* CAN identifier */
283                 0,                          /* rtr */
284                 8,                          /* number of data bytes */
285                 0);                         /* synchronous message flag bit */
286 
287         SDO_C->COB_IDClientToServerPrev = idCtoS;
288         SDO_C->COB_IDServerToClientPrev = idStoC;
289     }
290 
291     return CO_SDOcli_ok_communicationEnd;
292 }
293 
294 
295 /******************************************************************************/
CO_SDOclient_abort(CO_SDOclient_t * SDO_C,uint32_t code)296 static void CO_SDOclient_abort(CO_SDOclient_t *SDO_C, uint32_t code){
297     SDO_C->CANtxBuff->data[0] = 0x80;
298     SDO_C->CANtxBuff->data[1] = SDO_C->index & 0xFF;
299     SDO_C->CANtxBuff->data[2] = (SDO_C->index>>8) & 0xFF;
300     SDO_C->CANtxBuff->data[3] = SDO_C->subIndex;
301     CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &code);
302     CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
303     SDO_C->state = SDO_STATE_NOTDEFINED;
304     CLEAR_CANrxNew(SDO_C->CANrxNew);
305 }
306 
307 
308 /******************************************************************************/
CO_SDOTxBufferClear(CO_SDOclient_t * SDO_C)309 static void CO_SDOTxBufferClear(CO_SDOclient_t *SDO_C) {
310     uint16_t i;
311 
312     for(i=0; i<8; i++) {
313         SDO_C->CANtxBuff->data[i] = 0;
314     }
315     SDO_C->CANtxBuff->bufferFull = 0;
316 }
317 
318 
319 /*******************************************************************************
320  *
321  * DOWNLOAD
322  *
323  *
324  ******************************************************************************/
CO_SDOclientDownloadInitiate(CO_SDOclient_t * SDO_C,uint16_t index,uint8_t subIndex,uint8_t * dataTx,uint32_t dataSize,uint8_t blockEnable)325 CO_SDOclient_return_t CO_SDOclientDownloadInitiate(
326         CO_SDOclient_t         *SDO_C,
327         uint16_t                index,
328         uint8_t                 subIndex,
329         uint8_t                *dataTx,
330         uint32_t                dataSize,
331         uint8_t                 blockEnable)
332 {
333     /* verify parameters */
334     if(SDO_C == NULL || dataTx == 0 || dataSize == 0) {
335         return CO_SDOcli_wrongArguments;
336     }
337 
338     /* save parameters */
339     SDO_C->buffer = dataTx;
340     SDO_C->bufferSize = dataSize;
341 
342     SDO_C->state = SDO_STATE_DOWNLOAD_INITIATE;
343 
344     /* prepare CAN tx message */
345     CO_SDOTxBufferClear(SDO_C);
346 
347     SDO_C->index = index;
348     SDO_C->subIndex = subIndex;
349     SDO_C->CANtxBuff->data[1] = index & 0xFF;
350     SDO_C->CANtxBuff->data[2] = index >> 8;
351     SDO_C->CANtxBuff->data[3] = subIndex;
352 
353     /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */
354     if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){
355 
356         /* Optional signal to RTOS. We can immediately continue SDO Client */
357         if(SDO_C->pFunctSignal != NULL) {
358             SDO_C->pFunctSignal();
359         }
360 
361         return CO_SDOcli_ok_communicationEnd;
362     }
363 
364     if(dataSize <= 4){
365         uint16_t i;
366         /* expedited transfer */
367         SDO_C->CANtxBuff->data[0] = 0x23 | ((4-dataSize) << 2);
368 
369         /* copy data */
370         for(i=dataSize+3; i>=4; i--) SDO_C->CANtxBuff->data[i] = dataTx[i-4];
371     }
372     else if((SDO_C->bufferSize > SDO_C->pst) && blockEnable != 0){ /*  BLOCK transfer */
373         /*  set state of block transfer */
374         SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_INITIATE;
375 
376         /*  init HEAD of packet */
377         SDO_C->CANtxBuff->data[0] = CCS_DOWNLOAD_BLOCK<<5;
378         /*  set flag for CRC */
379         SDO_C->CANtxBuff->data[0] |= 0x01<<2;
380 
381         /*  size indicator: */
382         SDO_C->CANtxBuff->data[0] |= 0x01<<1;
383         /*  set length of data */
384         SDO_C->CANtxBuff->data[4] = (uint8_t) dataSize;
385         SDO_C->CANtxBuff->data[5] = (uint8_t) (dataSize >> 8);
386         SDO_C->CANtxBuff->data[6] = (uint8_t) (dataSize >> 16);
387         SDO_C->CANtxBuff->data[7] = (uint8_t) (dataSize >> 24);
388 
389     }
390     else{
391         uint32_t len;
392         /* segmented transfer */
393         SDO_C->CANtxBuff->data[0] = 0x21;
394         len = dataSize;
395         CO_memcpySwap4(&SDO_C->CANtxBuff->data[4], &len);
396     }
397 
398     /* empty receive buffer, reset timeout timer and send message */
399     CLEAR_CANrxNew(SDO_C->CANrxNew);
400     SDO_C->timeoutTimer = 0;
401     CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
402 
403     return CO_SDOcli_ok_communicationEnd;
404 }
405 
406 
407 /******************************************************************************/
CO_SDOclientDownload(CO_SDOclient_t * SDO_C,uint16_t timeDifference_ms,uint16_t SDOtimeoutTime,uint32_t * pSDOabortCode)408 CO_SDOclient_return_t CO_SDOclientDownload(
409         CO_SDOclient_t         *SDO_C,
410         uint16_t                timeDifference_ms,
411         uint16_t                SDOtimeoutTime,
412         uint32_t               *pSDOabortCode)
413 {
414     CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse;
415 
416     /* verify parameters */
417     if(SDO_C == NULL) {
418         return CO_SDOcli_wrongArguments;
419     }
420 
421     /* clear abort code */
422     *pSDOabortCode = CO_SDO_AB_NONE;
423 
424     /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */
425     if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){
426         SDO_C->state = SDO_STATE_NOTDEFINED;
427         CLEAR_CANrxNew(SDO_C->CANrxNew);
428 
429         /* If SDO server is busy return error */
430         if(SDO_C->SDO->state != 0){
431             return CO_SDOcli_endedWithClientAbort;
432         }
433 
434         /* init ODF_arg */
435         *pSDOabortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, SDO_C->subIndex);
436         if((*pSDOabortCode) != CO_SDO_AB_NONE){
437             return CO_SDOcli_endedWithServerAbort;
438         }
439 
440         /* set buffer */
441         SDO_C->SDO->ODF_arg.data = SDO_C->buffer;
442 
443         /* write data to the Object dictionary */
444         *pSDOabortCode = CO_SDO_writeOD(SDO_C->SDO, SDO_C->bufferSize);
445         if((*pSDOabortCode) != CO_SDO_AB_NONE){
446             return CO_SDOcli_endedWithServerAbort;
447         }
448 
449         return CO_SDOcli_ok_communicationEnd;
450     }
451 
452 
453 /*  RX data ****************************************************************************************** */
454     if(IS_CANrxNew(SDO_C->CANrxNew)){
455         uint8_t SCS = SDO_C->CANrxData[0]>>5;    /* Client command specifier */
456 
457         /* ABORT */
458         if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){
459             SDO_C->state = SDO_STATE_NOTDEFINED;
460             CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]);
461             CLEAR_CANrxNew(SDO_C->CANrxNew);
462             return CO_SDOcli_endedWithServerAbort;
463         }
464 
465         switch (SDO_C->state){
466 
467             case SDO_STATE_DOWNLOAD_INITIATE:{
468 
469                 if (SCS == SCS_DOWNLOAD_INITIATED){
470                     if(SDO_C->bufferSize <= 4){
471                         /* expedited transfer */
472                         SDO_C->state = SDO_STATE_NOTDEFINED;
473                         CLEAR_CANrxNew(SDO_C->CANrxNew);
474                         return CO_SDOcli_ok_communicationEnd;
475                     }
476                     else{
477                         /* segmented transfer - prepare the first segment */
478                         SDO_C->bufferOffset = 0;
479                         SDO_C->toggle =0;
480                         SDO_C->state = SDO_STATE_DOWNLOAD_REQUEST;
481                     }
482                 }
483                 else{
484                     *pSDOabortCode = CO_SDO_AB_CMD;
485                     SDO_C->state = SDO_STATE_ABORT;
486                 }
487                 break;
488             }
489 
490             case SDO_STATE_DOWNLOAD_RESPONSE:{
491 
492                 if (SCS == SCS_DOWNLOAD_SEGMENT){
493                     /* verify toggle bit */
494                     if((SDO_C->CANrxData[0]&0x10) != (SDO_C->toggle<<4)){
495                         *pSDOabortCode = CO_SDO_AB_TOGGLE_BIT;
496                         SDO_C->state = SDO_STATE_ABORT;
497                         break;
498                     }
499                     /* alternate toggle bit */
500                     if (SDO_C->toggle ==0x00)
501                         SDO_C->toggle =0x01;
502                     else
503                         SDO_C->toggle =0x00;
504 
505                     /* is end of transfer? */
506                     if(SDO_C->bufferOffset == SDO_C->bufferSize){
507                         SDO_C->state = SDO_STATE_NOTDEFINED;
508                         CLEAR_CANrxNew(SDO_C->CANrxNew);
509                         return CO_SDOcli_ok_communicationEnd;
510                     }
511                     SDO_C->state = SDO_STATE_DOWNLOAD_REQUEST;
512                 }
513                 else{
514                     *pSDOabortCode = CO_SDO_AB_CMD;
515                     SDO_C->state = SDO_STATE_ABORT;
516                 }
517                 break;
518             }
519 
520             case SDO_STATE_BLOCKDOWNLOAD_INITIATE:{ /* waiting on reply on block download initiated */
521                 if (SCS == SCS_DOWNLOAD_BLOCK){
522                     uint16_t IndexTmp;
523                     IndexTmp = SDO_C->CANrxData[2];
524                     IndexTmp = IndexTmp << 8;
525                     IndexTmp |= SDO_C->CANrxData[1];
526 
527                     if(IndexTmp != SDO_C->index || SDO_C->CANrxData[3] != SDO_C->subIndex) {
528                         /*  wrong index */
529                         *pSDOabortCode = CO_SDO_AB_PRAM_INCOMPAT;
530                         SDO_C->state = SDO_STATE_ABORT;
531                         break;
532                     }
533                     /*  set blksize */
534                     SDO_C->block_blksize = SDO_C->CANrxData[4];
535 
536                     SDO_C->block_seqno = 0;
537                     SDO_C->bufferOffset = 0;
538                     SDO_C->bufferOffsetACK = 0;
539                     SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_INPROGRES;
540                 }
541                 else{
542                     *pSDOabortCode = CO_SDO_AB_CMD;
543                     SDO_C->state = SDO_STATE_ABORT;
544                 }
545                 break;
546             }
547 
548             case SDO_STATE_BLOCKDOWNLOAD_INPROGRES:
549             case SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK:{ /*  waiting block ACK */
550                 if (SCS == SCS_DOWNLOAD_BLOCK){
551                     /*  check server subcommand */
552                     if((SDO_C->CANrxData[0] & 0x02) == 0){
553                         /* wrong server sub command */
554                         *pSDOabortCode = CO_SDO_AB_CMD;
555                         SDO_C->state = SDO_STATE_ABORT;
556                         break;
557                     }
558                     /*  check number of segments */
559                     if(SDO_C->CANrxData[1] != SDO_C->block_blksize){
560                         /*  NOT all segments transferred successfully */
561                         SDO_C->bufferOffsetACK += SDO_C->CANrxData[1] * 7;
562                         SDO_C->bufferOffset = SDO_C->bufferOffsetACK;
563                     }
564                     else{
565                         SDO_C->bufferOffsetACK = SDO_C->bufferOffset;
566                     }
567                     /*  set size of next block */
568                     SDO_C->block_blksize = SDO_C->CANrxData[2];
569                     SDO_C->block_seqno = 0;
570 
571                     if(SDO_C->bufferOffset >= SDO_C->bufferSize)
572                         SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_CRC;
573                     else
574                         SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_INPROGRES;
575                 }
576                 else{
577                     *pSDOabortCode = CO_SDO_AB_CMD;
578                     SDO_C->state = SDO_STATE_ABORT;
579                 }
580                 break;
581             }
582 
583             case SDO_STATE_BLOCKDOWNLOAD_CRC_ACK:{
584                 if (SCS == SCS_DOWNLOAD_BLOCK){
585                     if((SDO_C->CANrxData[0] & 0x01) == 0){
586                         /*  wrong server sub command */
587                         *pSDOabortCode = CO_SDO_AB_CMD;
588                         SDO_C->state = SDO_STATE_ABORT;
589                         break;
590                     }
591                     /*  SDO block download successfully transferred */
592                     SDO_C->state = SDO_STATE_NOTDEFINED;
593                     SDO_C->timeoutTimer = 0;
594                     CLEAR_CANrxNew(SDO_C->CANrxNew);
595                     return CO_SDOcli_ok_communicationEnd;
596                 }
597                 else{
598                     *pSDOabortCode = CO_SDO_AB_CMD;
599                     SDO_C->state = SDO_STATE_ABORT;
600                     break;
601                 }
602             }
603 
604             default:{
605                 *pSDOabortCode = CO_SDO_AB_CMD;
606                 SDO_C->state = SDO_STATE_ABORT;
607                 break;
608             }
609         }
610         SDO_C->timeoutTimer = 0;
611         CLEAR_CANrxNew(SDO_C->CANrxNew);
612     }
613 
614 /*  TMO *********************************************************************************************** */
615     if(SDO_C->timeoutTimer < SDOtimeoutTime){
616         SDO_C->timeoutTimer += timeDifference_ms;
617     }
618     if(SDO_C->timeoutTimer >= SDOtimeoutTime){ /*  communication TMO */
619         *pSDOabortCode = CO_SDO_AB_TIMEOUT;
620         CO_SDOclient_abort(SDO_C, *pSDOabortCode);
621         return CO_SDOcli_endedWithTimeout;
622     }
623 
624 /*  TX data ******************************************************************************************* */
625     if(SDO_C->CANtxBuff->bufferFull) {
626         return CO_SDOcli_transmittBufferFull;
627     }
628 
629     CO_SDOTxBufferClear(SDO_C);
630     switch (SDO_C->state){
631         /*  ABORT */
632         case SDO_STATE_ABORT:{
633             SDO_C->state = SDO_STATE_NOTDEFINED;
634             CO_SDOclient_abort (SDO_C, *pSDOabortCode);
635             ret = CO_SDOcli_endedWithClientAbort;
636             break;
637         }
638             /*  SEGMENTED */
639         case SDO_STATE_DOWNLOAD_REQUEST:{
640             uint16_t i, j;
641             /* calculate length to be sent */
642             j = SDO_C->bufferSize - SDO_C->bufferOffset;
643             if(j > 7) j = 7;
644             /* fill data bytes */
645             for(i=0; i<j; i++)
646                 SDO_C->CANtxBuff->data[i+1] = SDO_C->buffer[SDO_C->bufferOffset + i];
647 
648             for(; i<7; i++)
649                 SDO_C->CANtxBuff->data[i+1] = 0;
650 
651             SDO_C->bufferOffset += j;
652             /* SDO command specifier */
653             SDO_C->CANtxBuff->data[0] = CCS_DOWNLOAD_SEGMENT | ((SDO_C->toggle)<<4) | ((7-j)<<1);
654             /* is end of transfer? */
655             if(SDO_C->bufferOffset == SDO_C->bufferSize){
656                 SDO_C->CANtxBuff->data[0] |= 1;
657             }
658             /* Send next SDO message */
659             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
660             SDO_C->state = SDO_STATE_DOWNLOAD_RESPONSE;
661             break;
662         }
663 
664         /*  BLOCK */
665         case SDO_STATE_BLOCKDOWNLOAD_INPROGRES:{
666             SDO_C->block_seqno += 1;
667             SDO_C->CANtxBuff->data[0] = SDO_C->block_seqno;
668 
669             if(SDO_C->block_seqno >= SDO_C->block_blksize){
670                 SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK;
671             }
672             /*  set data */
673             SDO_C->block_noData = 0;
674 
675             uint8_t i;
676             for(i = 1; i < 8; i++){
677                 if(SDO_C->bufferOffset < SDO_C->bufferSize){
678                     SDO_C->CANtxBuff->data[i] = *(SDO_C->buffer + SDO_C->bufferOffset);
679                 }
680                 else{
681                     SDO_C->CANtxBuff->data[i] = 0;
682                     SDO_C->block_noData += 1;
683                 }
684 
685                 SDO_C->bufferOffset += 1;
686             }
687 
688             if(SDO_C->bufferOffset >= SDO_C->bufferSize){
689                 SDO_C->CANtxBuff->data[0] |= 0x80;
690                 SDO_C->block_blksize = SDO_C->block_seqno;
691                 SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_BLOCK_ACK;
692             }
693 
694             /*  tx data */
695             SDO_C->timeoutTimer = 0;
696             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
697 
698             break;
699         }
700 
701         case SDO_STATE_BLOCKDOWNLOAD_CRC:{
702             SDO_C->CANtxBuff->data[0] = (CCS_DOWNLOAD_BLOCK<<5) | (SDO_C->block_noData << 2) | 0x01;
703 
704             uint16_t tmp16;
705 
706             tmp16 = crc16_ccitt((unsigned char *)SDO_C->buffer, (unsigned int)SDO_C->bufferSize, 0);
707 
708             SDO_C->CANtxBuff->data[1] = (uint8_t) tmp16;
709             SDO_C->CANtxBuff->data[2] = (uint8_t) (tmp16>>8);
710 
711             /*  set state */
712             SDO_C->state = SDO_STATE_BLOCKDOWNLOAD_CRC_ACK;
713             /*  tx data */
714             SDO_C->timeoutTimer = 0;
715             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
716 
717             break;
718         }
719 
720         default:{
721             break;
722         }
723     }
724 
725     if(SDO_C->state == SDO_STATE_BLOCKDOWNLOAD_INPROGRES) {
726         ret = CO_SDOcli_blockDownldInProgress;
727     }
728 
729     return ret;
730 }
731 
732 
733 /*******************************************************************************
734  *
735  * UPLOAD
736  *
737  ******************************************************************************/
CO_SDOclientUploadInitiate(CO_SDOclient_t * SDO_C,uint16_t index,uint8_t subIndex,uint8_t * dataRx,uint32_t dataRxSize,uint8_t blockEnable)738 CO_SDOclient_return_t CO_SDOclientUploadInitiate(
739         CO_SDOclient_t         *SDO_C,
740         uint16_t                index,
741         uint8_t                 subIndex,
742         uint8_t                *dataRx,
743         uint32_t                dataRxSize,
744         uint8_t                 blockEnable)
745 {
746     /* verify parameters */
747     if(SDO_C == NULL || dataRx == 0 || dataRxSize < 4) {
748         return CO_SDOcli_wrongArguments;
749     }
750 
751     /* save parameters */
752     SDO_C->buffer = dataRx;
753     SDO_C->bufferSize = dataRxSize;
754 
755     /* prepare CAN tx message */
756     CO_SDOTxBufferClear(SDO_C);
757 
758     SDO_C->index = index;
759     SDO_C->subIndex = subIndex;
760 
761     SDO_C->CANtxBuff->data[1] = index & 0xFF;
762     SDO_C->CANtxBuff->data[2] = index >> 8;
763     SDO_C->CANtxBuff->data[3] = subIndex;
764 
765 
766     if(blockEnable == 0){
767         SDO_C->state = SDO_STATE_UPLOAD_INITIATED;
768         SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_INITIATE<<5);
769     }
770     else{
771         SDO_C->state = SDO_STATE_BLOCKUPLOAD_INITIATE;
772 
773         /*  header */
774         SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5);
775 
776         /*  set CRC */
777         SDO_C->CANtxBuff->data[0] |= 0x04;
778 
779         /*  set number of segments in block */
780         SDO_C->block_blksize = SDO_C->block_size_max;
781         if ((SDO_C->block_blksize *7) > SDO_C->bufferSize){
782             return CO_SDOcli_wrongArguments;
783         }
784 
785         SDO_C->CANtxBuff->data[4] = SDO_C->block_blksize;
786         SDO_C->CANtxBuff->data[5] = SDO_C->pst;
787 
788 
789         SDO_C->block_seqno = 0;
790     }
791 
792     /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */
793     if(SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){
794 
795         /* Optional signal to RTOS. We can immediately continue SDO Client */
796         if(SDO_C->pFunctSignal != NULL) {
797             SDO_C->pFunctSignal();
798         }
799 
800         return CO_SDOcli_ok_communicationEnd;
801     }
802 
803     /* empty receive buffer, reset timeout timer and send message */
804     CLEAR_CANrxNew(SDO_C->CANrxNew);
805     SDO_C->timeoutTimer = 0;
806     SDO_C->timeoutTimerBLOCK =0;
807     CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
808 
809     return CO_SDOcli_ok_communicationEnd;
810 }
811 
812 
813 /******************************************************************************/
CO_SDOclientUpload(CO_SDOclient_t * SDO_C,uint16_t timeDifference_ms,uint16_t SDOtimeoutTime,uint32_t * pDataSize,uint32_t * pSDOabortCode)814 CO_SDOclient_return_t CO_SDOclientUpload(
815         CO_SDOclient_t         *SDO_C,
816         uint16_t                timeDifference_ms,
817         uint16_t                SDOtimeoutTime,
818         uint32_t               *pDataSize,
819         uint32_t               *pSDOabortCode)
820 {
821     uint16_t indexTmp;
822     uint32_t tmp32;
823     CO_SDOclient_return_t ret = CO_SDOcli_waitingServerResponse;
824 
825     /* verify parameters */
826     if(SDO_C == NULL) {
827         return CO_SDOcli_wrongArguments;
828     }
829 
830     /* clear abort code */
831     *pSDOabortCode = CO_SDO_AB_NONE;
832 
833     /* if nodeIDOfTheSDOServer == node-ID of this node, then exchange data with this node */
834     if(SDO_C->SDO && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId){
835         SDO_C->state = SDO_STATE_NOTDEFINED;
836         CLEAR_CANrxNew(SDO_C->CANrxNew);
837 
838         /* If SDO server is busy return error */
839         if(SDO_C->SDO->state != 0){
840             *pSDOabortCode = CO_SDO_AB_DEVICE_INCOMPAT;
841             return CO_SDOcli_endedWithClientAbort;
842         }
843 
844         /* init ODF_arg */
845         *pSDOabortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index, SDO_C->subIndex);
846         if((*pSDOabortCode) != CO_SDO_AB_NONE){
847             return CO_SDOcli_endedWithServerAbort;
848         }
849 
850         /* set buffer and length if domain */
851         SDO_C->SDO->ODF_arg.data = SDO_C->buffer;
852         if(SDO_C->SDO->ODF_arg.ODdataStorage == 0)
853             SDO_C->SDO->ODF_arg.dataLength = SDO_C->bufferSize;
854 
855         /* read data from the Object dictionary */
856         *pSDOabortCode = CO_SDO_readOD(SDO_C->SDO, SDO_C->bufferSize);
857         if((*pSDOabortCode) != CO_SDO_AB_NONE){
858             return CO_SDOcli_endedWithServerAbort;
859         }
860 
861         /* set data size */
862         *pDataSize = SDO_C->SDO->ODF_arg.dataLength;
863 
864         /* is SDO buffer too small */
865         if(SDO_C->SDO->ODF_arg.lastSegment == 0){
866             *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM;    /* Out of memory */
867             return CO_SDOcli_endedWithServerAbort;
868         }
869 
870         return CO_SDOcli_ok_communicationEnd;
871     }
872 
873 
874 /*  RX data ******************************************************************************** */
875     if(IS_CANrxNew(SDO_C->CANrxNew)){
876         uint8_t SCS = SDO_C->CANrxData[0]>>5;    /* Client command specifier */
877 
878         /*  ABORT */
879         if (SDO_C->CANrxData[0] == (SCS_ABORT<<5)){
880             SDO_C->state = SDO_STATE_NOTDEFINED;
881             CLEAR_CANrxNew(SDO_C->CANrxNew);
882             CO_memcpySwap4(pSDOabortCode , &SDO_C->CANrxData[4]);
883             return CO_SDOcli_endedWithServerAbort;
884         }
885         switch (SDO_C->state){
886             case SDO_STATE_UPLOAD_INITIATED:{
887 
888 
889 
890                 if (SCS == SCS_UPLOAD_INITIATE){
891                     if(SDO_C->CANrxData[0] & 0x02){
892                         uint8_t size;
893                         /* Expedited transfer */
894                         if(SDO_C->CANrxData[0] & 0x01)/* is size indicated */
895                             size = 4 - ((SDO_C->CANrxData[0]>>2)&0x03);    /* size */
896                         else
897                             size = 4;
898 
899                         *pDataSize = size;
900 
901                         /* copy data */
902                         while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size];
903                         SDO_C->state = SDO_STATE_NOTDEFINED;
904                         CLEAR_CANrxNew(SDO_C->CANrxNew);
905 
906                         return CO_SDOcli_ok_communicationEnd;
907                     }
908                     else{
909                         /* segmented transfer - prepare first segment */
910                         SDO_C->bufferOffset = 0;
911                         SDO_C->state = SDO_STATE_UPLOAD_REQUEST;
912 
913                         SDO_C->toggle =0;
914                         /* continue with segmented upload */
915                     }
916                 }
917                 else{
918                     *pSDOabortCode = CO_SDO_AB_CMD;
919                     SDO_C->state = SDO_STATE_ABORT;
920                 }
921                 break;
922             }
923 
924             case SDO_STATE_UPLOAD_RESPONSE:{
925                 if (SCS == SCS_UPLOAD_SEGMENT){
926                      uint16_t size, i;
927                     /* verify toggle bit */
928                     if((SDO_C->CANrxData[0] &0x10) != (~SDO_C->toggle &0x10)){
929                         *pSDOabortCode = CO_SDO_AB_TOGGLE_BIT;
930                         SDO_C->state = SDO_STATE_ABORT;
931                         break;
932                     }
933                     /* get size */
934                     size = 7 - ((SDO_C->CANrxData[0]>>1)&0x07);
935                     /* verify length */
936                     if((SDO_C->bufferOffset + size) > SDO_C->bufferSize){
937                         *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM;    /* Out of memory */
938                         SDO_C->state = SDO_STATE_ABORT;
939                         break;
940                     }
941                     /* copy data to buffer */
942                     for(i=0; i<size; i++)
943                     SDO_C->buffer[SDO_C->bufferOffset + i] = SDO_C->CANrxData[1 + i];
944                     SDO_C->bufferOffset += size;
945                     /* If no more segments to be uploaded, finish communication */
946                     if(SDO_C->CANrxData[0] & 0x01){
947                         *pDataSize = SDO_C->bufferOffset;
948                         SDO_C->state = SDO_STATE_NOTDEFINED;
949                         CLEAR_CANrxNew(SDO_C->CANrxNew);
950                         return CO_SDOcli_ok_communicationEnd;
951                     }
952                     /* set state */
953                     SDO_C->state = SDO_STATE_UPLOAD_REQUEST;
954                     break;
955                 }
956                 else{
957                     *pSDOabortCode = CO_SDO_AB_CMD;
958                     SDO_C->state = SDO_STATE_ABORT;
959                 }
960                 break;
961             }
962 
963             case SDO_STATE_BLOCKUPLOAD_INITIATE:{
964                 if (SCS == SCS_UPLOAD_BLOCK){ /*  block upload initiate response */
965 
966                     SDO_C->state = SDO_STATE_BLOCKUPLOAD_INITIATE_ACK;
967 
968                     /*  SCR support */
969                     if((SDO_C->CANrxData[0] & 0x04) != 0)
970                         SDO_C->crcEnabled = 1; /*  CRC suported */
971                     else
972                         SDO_C->crcEnabled = 0; /*  CRC not suported */
973 
974                     /*  chech Index ans subnindex */
975                     indexTmp = SDO_C->CANrxData[2];
976                     indexTmp = indexTmp << 8;
977                     indexTmp |= SDO_C->CANrxData[1];
978 
979                     if(indexTmp != SDO_C->index || SDO_C->CANrxData[3] != SDO_C->subIndex){
980                         *pSDOabortCode = CO_SDO_AB_PRAM_INCOMPAT;
981                         SDO_C->state = SDO_STATE_ABORT;
982                     }
983 
984                     /*  set length */
985                     if(SDO_C->CANrxData[0]&0x02){
986                         uint32_t len;
987                         CO_memcpySwap4(&len, &SDO_C->CANrxData[4]);
988                         SDO_C->dataSize = len;
989                     }
990                     else{
991                         SDO_C->dataSize = 0;
992                     }
993 
994                     /*  check available buffer size */
995                     if (SDO_C->dataSize > SDO_C->bufferSize){
996                         *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM;
997                         SDO_C->state = SDO_STATE_ABORT;
998                     }
999 
1000                     SDO_C->dataSizeTransfered =0;
1001                 }
1002                 else if (SCS == SCS_UPLOAD_INITIATE){ /*  switch to regular segmented transfer */
1003                     if(SDO_C->CANrxData[0] & 0x02){
1004                         uint8_t size;
1005                         /* Expedited transfer */
1006                         if(SDO_C->CANrxData[0] & 0x01)/* is size indicated */
1007                             size = 4 - ((SDO_C->CANrxData[0]>>2)&0x03);    /* size */
1008                         else
1009                             size = 4;
1010 
1011                         *pDataSize = size;
1012 
1013                         /* copy data */
1014                         while(size--) SDO_C->buffer[size] = SDO_C->CANrxData[4+size];
1015                         SDO_C->state = SDO_STATE_NOTDEFINED;
1016                         CLEAR_CANrxNew(SDO_C->CANrxNew);
1017 
1018                         return CO_SDOcli_ok_communicationEnd;
1019                     }
1020                     else{
1021                         /* segmented transfer - prepare first segment */
1022                         SDO_C->bufferOffset = 0;
1023                         SDO_C->state = SDO_STATE_UPLOAD_REQUEST;
1024 
1025                         SDO_C->toggle =0;
1026                         /* continue with segmented upload */
1027                     }
1028                 }
1029                 else{ /*  unknown SCS */
1030                     *pSDOabortCode = CO_SDO_AB_CMD;
1031                     SDO_C->state = SDO_STATE_ABORT;
1032                 }
1033                 break;
1034             }
1035 
1036             case SDO_STATE_BLOCKUPLOAD_INPROGRES:{
1037                 /* data are copied directly in receive function */
1038                 break;
1039             }
1040 
1041             case SDO_STATE_BLOCKUPLOAD_SUB_END:{
1042                 /* data was copied by receive function, sub-block is finished */
1043                 /* Is last segment? */
1044                 if(SDO_C->CANrxData[0] & 0x80) {
1045                     /* Is data size indicated and wrong? */
1046                     if((SDO_C->dataSize != 0) && (SDO_C->dataSize > SDO_C->dataSizeTransfered)) {
1047                         *pSDOabortCode = CO_SDO_AB_TYPE_MISMATCH;
1048                         SDO_C->state = SDO_STATE_ABORT;
1049                     }
1050                     else {
1051                         SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK_LAST;
1052                     }
1053                 }
1054                 else {
1055                     /* Is SDO buffer overflow? */
1056                     if(SDO_C->dataSizeTransfered >= SDO_C->bufferSize) {
1057                         *pSDOabortCode = CO_SDO_AB_OUT_OF_MEM;
1058                         SDO_C->state = SDO_STATE_ABORT;
1059                     }
1060                     else {
1061                         SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK;
1062                     }
1063                 }
1064                 break;
1065             }
1066 
1067             case SDO_STATE_BLOCKUPLOAD_BLOCK_CRC:{
1068                 if (SCS == SCS_UPLOAD_BLOCK){
1069                     tmp32 = ((SDO_C->CANrxData[0]>>2) & 0x07);
1070                     SDO_C->dataSizeTransfered -= tmp32;
1071 
1072                     SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_END;
1073                     if (SDO_C->crcEnabled){
1074                         uint16_t tmp16;
1075                         CO_memcpySwap2(&tmp16, &SDO_C->CANrxData[1]);
1076 
1077                         if (tmp16 != crc16_ccitt((unsigned char *)SDO_C->buffer, (unsigned int)SDO_C->dataSizeTransfered, 0)){
1078                             *pSDOabortCode = CO_SDO_AB_CRC;
1079                             SDO_C->state = SDO_STATE_ABORT;
1080                         }
1081                         else{
1082                             SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_END;
1083                         }
1084                     }
1085                     else{
1086                         SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_END;
1087                     }
1088 
1089                 }
1090                 else{
1091                     *pSDOabortCode = CO_SDO_AB_GENERAL;
1092                     SDO_C->state = SDO_STATE_ABORT;
1093                 }
1094                 break;
1095             }
1096 
1097             default:{
1098                 *pSDOabortCode = CO_SDO_AB_CMD;
1099                 SDO_C->state = SDO_STATE_ABORT;
1100                 break;
1101             }
1102         }
1103         SDO_C->timeoutTimer = 0;
1104         CLEAR_CANrxNew(SDO_C->CANrxNew);
1105     }
1106 
1107 /*  TMO *************************************************************************************************** */
1108     if(SDO_C->timeoutTimer < SDOtimeoutTime){
1109         SDO_C->timeoutTimer += timeDifference_ms;
1110         if (SDO_C->state == SDO_STATE_BLOCKUPLOAD_INPROGRES)
1111             SDO_C->timeoutTimerBLOCK += timeDifference_ms;
1112     }
1113     if(SDO_C->timeoutTimer >= SDOtimeoutTime){ /*  communication TMO */
1114         *pSDOabortCode = CO_SDO_AB_TIMEOUT;
1115         CO_SDOclient_abort(SDO_C, *pSDOabortCode);
1116         return CO_SDOcli_endedWithTimeout;
1117     }
1118     if(SDO_C->timeoutTimerBLOCK >= (SDOtimeoutTime/2)){ /*  block TMO */
1119         SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_ACK;
1120     }
1121 
1122 
1123 /*  TX data ******************************************************************************** */
1124     if(SDO_C->CANtxBuff->bufferFull) {
1125         return CO_SDOcli_transmittBufferFull;
1126     }
1127 
1128     CO_SDOTxBufferClear(SDO_C);
1129     switch (SDO_C->state){
1130         case SDO_STATE_ABORT:{
1131             SDO_C->state = SDO_STATE_NOTDEFINED;
1132             CO_SDOclient_abort (SDO_C, *pSDOabortCode);
1133             ret = CO_SDOcli_endedWithClientAbort;
1134             break;
1135         }
1136 
1137         /*  SEGMENTED UPLOAD */
1138         case SDO_STATE_UPLOAD_REQUEST:{
1139             SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_SEGMENT<<5) | (SDO_C->toggle & 0x10);
1140             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
1141 
1142             SDO_C->state = SDO_STATE_UPLOAD_RESPONSE;
1143             SDO_C->toggle = ~SDO_C->toggle;
1144 
1145             break;
1146         }
1147         /*  BLOCK */
1148         case SDO_STATE_BLOCKUPLOAD_INITIATE_ACK:{
1149             SDO_C->timeoutTimerBLOCK = 0;
1150             SDO_C->block_seqno = 0;
1151             SDO_C->state = SDO_STATE_BLOCKUPLOAD_INPROGRES;
1152 
1153             /*  header */
1154             SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x03;
1155             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
1156 
1157             break;
1158         }
1159 
1160         case SDO_STATE_BLOCKUPLOAD_BLOCK_ACK_LAST:{
1161             /*  header */
1162             SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x02;
1163             SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno;
1164 
1165             SDO_C->block_seqno = 0;
1166             SDO_C->timeoutTimerBLOCK = 0;
1167 
1168             SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_CRC;
1169 
1170             SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize;
1171             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
1172 
1173             break;
1174         }
1175 
1176         case SDO_STATE_BLOCKUPLOAD_BLOCK_ACK:{
1177             /*  header */
1178             SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x02;
1179             SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno;
1180 
1181             /*  set next block size */
1182             if (SDO_C->dataSize != 0){
1183                 if(SDO_C->dataSizeTransfered >= SDO_C->dataSize){
1184                     SDO_C->block_blksize = 0;
1185                     SDO_C->state = SDO_STATE_BLOCKUPLOAD_BLOCK_CRC;
1186                 }
1187                 else{
1188                     tmp32 = ((SDO_C->dataSize - SDO_C->dataSizeTransfered) / 7);
1189                     if(tmp32 >= SDO_C->block_size_max){
1190                         SDO_C->block_blksize = SDO_C->block_size_max;
1191                     }
1192                     else{
1193                         if((SDO_C->dataSize - SDO_C->dataSizeTransfered) % 7 == 0)
1194                             SDO_C->block_blksize = tmp32;
1195                         else
1196                             SDO_C->block_blksize = tmp32 + 1;
1197                     }
1198                     SDO_C->block_seqno = 0;
1199                     SDO_C->timeoutTimerBLOCK = 0;
1200                     SDO_C->state = SDO_STATE_BLOCKUPLOAD_INPROGRES;
1201                 }
1202             }
1203             else{
1204                 SDO_C->block_seqno = 0;
1205                 SDO_C->timeoutTimerBLOCK = 0;
1206 
1207                 SDO_C->state = SDO_STATE_BLOCKUPLOAD_INPROGRES;
1208             }
1209             SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize;
1210             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
1211 
1212             break;
1213         }
1214 
1215         case SDO_STATE_BLOCKUPLOAD_BLOCK_END:{
1216             SDO_C->CANtxBuff->data[0] = (CCS_UPLOAD_BLOCK<<5) | 0x01;
1217 
1218             CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
1219 
1220             *pDataSize = SDO_C->dataSizeTransfered;
1221 
1222             SDO_C->state = SDO_STATE_NOTDEFINED;
1223 
1224             ret = CO_SDOcli_ok_communicationEnd;
1225             break;
1226         }
1227 
1228         default:
1229             break;
1230     }
1231 
1232     if(SDO_C->state == SDO_STATE_BLOCKUPLOAD_INPROGRES) {
1233         ret = CO_SDOcli_blockUploadInProgress;
1234     }
1235 
1236     return ret;
1237 }
1238 
1239 
1240 /******************************************************************************/
CO_SDOclientClose(CO_SDOclient_t * SDO_C)1241 void CO_SDOclientClose(CO_SDOclient_t *SDO_C){
1242     if(SDO_C != NULL) {
1243         SDO_C->state = SDO_STATE_NOTDEFINED;
1244     }
1245 }
1246