CO_SDOclient.c 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545
  1. /*
  2. * CANopen Service Data Object - client.
  3. *
  4. * @file CO_SDOclient.c
  5. * @ingroup CO_SDOclient
  6. * @author Janez Paternoster
  7. * @author Matej Severkar
  8. * @copyright 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. #include "301/CO_SDOclient.h"
  27. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE
  28. /* verify configuration */
  29. #if CO_CONFIG_SDO_CLI_BUFFER_SIZE < 7
  30. #error CO_CONFIG_SDO_CLI_BUFFER_SIZE must be set to 7 or more.
  31. #endif
  32. #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ENABLE)
  33. #error CO_CONFIG_FIFO_ENABLE must be enabled.
  34. #endif
  35. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  36. #if !((CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED)
  37. #error CO_CONFIG_SDO_CLI_SEGMENTED must be enabled.
  38. #endif
  39. #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_ALT_READ)
  40. #error CO_CONFIG_FIFO_ALT_READ must be enabled.
  41. #endif
  42. #if !((CO_CONFIG_FIFO) & CO_CONFIG_FIFO_CRC16_CCITT)
  43. #error CO_CONFIG_FIFO_CRC16_CCITT must be enabled.
  44. #endif
  45. #endif
  46. /* default 'protocol switch threshold' size for block transfer */
  47. #ifndef CO_CONFIG_SDO_CLI_PST
  48. #define CO_CONFIG_SDO_CLI_PST 21
  49. #endif
  50. /*
  51. * Read received message from CAN module.
  52. *
  53. * Function will be called (by CAN receive interrupt) every time, when CAN
  54. * message with correct identifier will be received. For more information and
  55. * description of parameters see file CO_driver.h.
  56. */
  57. static void CO_SDOclient_receive(void *object, void *msg) {
  58. CO_SDOclient_t *SDO_C = (CO_SDOclient_t*)object;
  59. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  60. uint8_t *data = CO_CANrxMsg_readData(msg);
  61. /* Ignore messages in idle state and messages with wrong length. Ignore
  62. * message also if previous message was not processed yet and not abort */
  63. if (SDO_C->state != CO_SDO_ST_IDLE && DLC == 8U
  64. && (!CO_FLAG_READ(SDO_C->CANrxNew) || data[0] == 0x80)
  65. ) {
  66. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  67. if (data[0] == 0x80 /* abort from server */
  68. || (SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ
  69. && SDO_C->state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP)
  70. ) {
  71. #endif
  72. /* copy data and set 'new message' flag */
  73. memcpy((void *)&SDO_C->CANrxData[0], (const void *)&data[0], 8);
  74. CO_FLAG_SET(SDO_C->CANrxNew);
  75. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE
  76. /* Optional signal to RTOS, which can resume task, which handles
  77. * SDO client processing. */
  78. if (SDO_C->pFunctSignal != NULL) {
  79. SDO_C->pFunctSignal(SDO_C->functSignalObject);
  80. }
  81. #endif
  82. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  83. }
  84. else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) {
  85. /* block upload, copy data directly */
  86. CO_SDO_state_t state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ;
  87. uint8_t seqno = data[0] & 0x7F;
  88. SDO_C->timeoutTimer = 0;
  89. SDO_C->block_timeoutTimer = 0;
  90. /* verify if sequence number is correct */
  91. if (seqno <= SDO_C->block_blksize
  92. && seqno == (SDO_C->block_seqno + 1)
  93. ) {
  94. SDO_C->block_seqno = seqno;
  95. /* is this the last segment? */
  96. if ((data[0] & 0x80) != 0) {
  97. /* copy data to temporary buffer, because we don't know the
  98. * number of bytes not containing data */
  99. memcpy((void *)&SDO_C->block_dataUploadLast[0],
  100. (const void *)&data[1], 7);
  101. SDO_C->finished = true;
  102. state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP;
  103. }
  104. else {
  105. /* Copy data. There is always enough space in fifo buffer,
  106. * because block_blksize was calculated before */
  107. CO_fifo_write(&SDO_C->bufFifo,
  108. (const char *)&data[1],
  109. 7, &SDO_C->block_crc);
  110. SDO_C->sizeTran += 7;
  111. /* all segments in sub-block has been transferred */
  112. if (seqno == SDO_C->block_blksize) {
  113. state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP;
  114. }
  115. }
  116. }
  117. /* If message is duplicate or sequence didn't start yet, ignore
  118. * it. Otherwise seqno is wrong, so break sub-block. Data after
  119. * last good seqno will be re-transmitted. */
  120. else if (seqno != SDO_C->block_seqno && SDO_C->block_seqno != 0U) {
  121. state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP;
  122. #ifdef CO_DEBUG_SDO_CLIENT
  123. char msg[80];
  124. sprintf(msg,
  125. "sub-block, rx WRONG: sequno=%02X, previous=%02X",
  126. seqno, SDO_C->block_seqno);
  127. CO_DEBUG_SDO_CLIENT(msg);
  128. #endif
  129. }
  130. #ifdef CO_DEBUG_SDO_CLIENT
  131. else {
  132. char msg[80];
  133. sprintf(msg,
  134. "sub-block, rx ignored: sequno=%02X, expected=%02X",
  135. seqno, SDO_C->block_seqno + 1);
  136. CO_DEBUG_SDO_CLIENT(msg);
  137. }
  138. #endif
  139. /* Is exit from sub-block receive state? */
  140. if (state != CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) {
  141. /* Processing will continue in another thread, so make memory
  142. * barrier here with CO_FLAG_CLEAR() call. */
  143. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  144. SDO_C->state = state;
  145. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE
  146. /* Optional signal to RTOS, which can resume task, which handles
  147. * SDO client processing. */
  148. if (SDO_C->pFunctSignal != NULL) {
  149. SDO_C->pFunctSignal(SDO_C->functSignalObject);
  150. }
  151. #endif
  152. }
  153. }
  154. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */
  155. }
  156. }
  157. /******************************************************************************/
  158. CO_ReturnError_t CO_SDOclient_init(CO_SDOclient_t *SDO_C,
  159. void *SDO,
  160. CO_SDOclientPar_t *SDOClientPar,
  161. CO_CANmodule_t *CANdevRx,
  162. uint16_t CANdevRxIdx,
  163. CO_CANmodule_t *CANdevTx,
  164. uint16_t CANdevTxIdx)
  165. {
  166. /* verify arguments */
  167. if (SDO_C == NULL || SDOClientPar == NULL || SDOClientPar->maxSubIndex != 3
  168. || CANdevRx==NULL || CANdevTx==NULL
  169. ) {
  170. return CO_ERROR_ILLEGAL_ARGUMENT;
  171. }
  172. /* Configure object variables */
  173. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL
  174. SDO_C->SDO = (CO_SDO_t *)SDO;
  175. #endif
  176. SDO_C->SDOClientPar = SDOClientPar;
  177. SDO_C->CANdevRx = CANdevRx;
  178. SDO_C->CANdevRxIdx = CANdevRxIdx;
  179. SDO_C->CANdevTx = CANdevTx;
  180. SDO_C->CANdevTxIdx = CANdevTxIdx;
  181. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE
  182. SDO_C->pFunctSignal = NULL;
  183. SDO_C->functSignalObject = NULL;
  184. #endif
  185. /* prepare circular fifo buffer */
  186. CO_fifo_init(&SDO_C->bufFifo, SDO_C->buf,
  187. CO_CONFIG_SDO_CLI_BUFFER_SIZE + 1);
  188. SDO_C->state = CO_SDO_ST_IDLE;
  189. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  190. SDO_C->COB_IDClientToServerPrev = 0;
  191. SDO_C->COB_IDServerToClientPrev = 0;
  192. CO_SDOclient_setup(SDO_C,
  193. SDO_C->SDOClientPar->COB_IDClientToServer,
  194. SDO_C->SDOClientPar->COB_IDServerToClient,
  195. SDO_C->SDOClientPar->nodeIDOfTheSDOServer);
  196. return CO_ERROR_NO;
  197. }
  198. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_CALLBACK_PRE
  199. /******************************************************************************/
  200. void CO_SDOclient_initCallbackPre(CO_SDOclient_t *SDOclient,
  201. void *object,
  202. void (*pFunctSignal)(void *object))
  203. {
  204. if (SDOclient != NULL) {
  205. SDOclient->functSignalObject = object;
  206. SDOclient->pFunctSignal = pFunctSignal;
  207. }
  208. }
  209. #endif
  210. /******************************************************************************/
  211. CO_SDO_return_t CO_SDOclient_setup(CO_SDOclient_t *SDO_C,
  212. uint32_t COB_IDClientToServer,
  213. uint32_t COB_IDServerToClient,
  214. uint8_t nodeIDOfTheSDOServer)
  215. {
  216. uint32_t idCtoS, idStoC;
  217. uint8_t idNode;
  218. /* verify parameters */
  219. if (SDO_C == NULL
  220. || (COB_IDClientToServer & 0x7FFFF800L) != 0
  221. || (COB_IDServerToClient & 0x7FFFF800L) != 0
  222. || nodeIDOfTheSDOServer > 127
  223. ) {
  224. return CO_SDO_RT_wrongArguments;
  225. }
  226. /* Configure object variables */
  227. SDO_C->state = CO_SDO_ST_IDLE;
  228. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  229. /* setup Object Dictionary variables */
  230. if ((COB_IDClientToServer & 0x80000000L) != 0
  231. || (COB_IDServerToClient & 0x80000000L) != 0
  232. || nodeIDOfTheSDOServer == 0
  233. ) {
  234. /* SDO is NOT used */
  235. idCtoS = 0x80000000L;
  236. idStoC = 0x80000000L;
  237. idNode = 0;
  238. }
  239. else {
  240. if (COB_IDClientToServer == 0 || COB_IDServerToClient == 0) {
  241. idCtoS = 0x600 + nodeIDOfTheSDOServer;
  242. idStoC = 0x580 + nodeIDOfTheSDOServer;
  243. }
  244. else {
  245. idCtoS = COB_IDClientToServer;
  246. idStoC = COB_IDServerToClient;
  247. }
  248. idNode = nodeIDOfTheSDOServer;
  249. }
  250. SDO_C->SDOClientPar->COB_IDClientToServer = idCtoS;
  251. SDO_C->SDOClientPar->COB_IDServerToClient = idStoC;
  252. SDO_C->SDOClientPar->nodeIDOfTheSDOServer = idNode;
  253. /* configure SDO client CAN reception, if differs. */
  254. if (SDO_C->COB_IDClientToServerPrev != idCtoS
  255. || SDO_C->COB_IDServerToClientPrev != idStoC
  256. ) {
  257. CO_ReturnError_t ret = CO_CANrxBufferInit(
  258. SDO_C->CANdevRx, /* CAN device */
  259. SDO_C->CANdevRxIdx, /* rx buffer index */
  260. (uint16_t)idStoC, /* CAN identifier */
  261. 0x7FF, /* mask */
  262. 0, /* rtr */
  263. (void*)SDO_C, /* object passed to receive function */
  264. CO_SDOclient_receive); /* this function will process rx msg */
  265. /* configure SDO client CAN transmission */
  266. SDO_C->CANtxBuff = CO_CANtxBufferInit(
  267. SDO_C->CANdevTx, /* CAN device */
  268. SDO_C->CANdevTxIdx, /* index of buffer inside CAN module */
  269. (uint16_t)idCtoS, /* CAN identifier */
  270. 0, /* rtr */
  271. 8, /* number of data bytes */
  272. 0); /* synchronous message flag bit */
  273. SDO_C->COB_IDClientToServerPrev = idCtoS;
  274. SDO_C->COB_IDServerToClientPrev = idStoC;
  275. if (ret != CO_ERROR_NO || SDO_C->CANtxBuff == NULL) {
  276. return CO_SDO_RT_wrongArguments;
  277. }
  278. }
  279. return CO_SDO_RT_ok_communicationEnd;
  280. }
  281. /******************************************************************************
  282. * DOWNLOAD *
  283. ******************************************************************************/
  284. CO_SDO_return_t CO_SDOclientDownloadInitiate(CO_SDOclient_t *SDO_C,
  285. uint16_t index,
  286. uint8_t subIndex,
  287. size_t sizeIndicated,
  288. uint16_t SDOtimeoutTime_ms,
  289. bool_t blockEnable)
  290. {
  291. /* verify parameters */
  292. if (SDO_C == NULL) {
  293. return CO_SDO_RT_wrongArguments;
  294. }
  295. /* save parameters */
  296. SDO_C->index = index;
  297. SDO_C->subIndex = subIndex;
  298. SDO_C->sizeInd = sizeIndicated;
  299. SDO_C->sizeTran = 0;
  300. SDO_C->finished = false;
  301. SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000;
  302. SDO_C->timeoutTimer = 0;
  303. CO_fifo_reset(&SDO_C->bufFifo);
  304. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL
  305. /* if node-ID of the SDO server is the same as node-ID of this node, then
  306. * transfer data within this node */
  307. if (SDO_C->SDO != NULL
  308. && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId
  309. ) {
  310. SDO_C->state = CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER;
  311. }
  312. else
  313. #endif
  314. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  315. if (blockEnable && (sizeIndicated == 0 ||
  316. sizeIndicated > CO_CONFIG_SDO_CLI_PST)
  317. ) {
  318. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ;
  319. }
  320. else
  321. #endif
  322. {
  323. SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ;
  324. }
  325. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  326. return CO_SDO_RT_ok_communicationEnd;
  327. }
  328. void CO_SDOclientDownloadInitiateSize(CO_SDOclient_t *SDO_C,
  329. size_t sizeIndicated)
  330. {
  331. if (SDO_C != NULL) {
  332. SDO_C->sizeInd = sizeIndicated;
  333. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  334. if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ
  335. && sizeIndicated > 0 && sizeIndicated <= CO_CONFIG_SDO_CLI_PST
  336. ) {
  337. SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_REQ;
  338. }
  339. #endif
  340. }
  341. }
  342. /******************************************************************************/
  343. size_t CO_SDOclientDownloadBufWrite(CO_SDOclient_t *SDO_C,
  344. const char *buf,
  345. size_t count)
  346. {
  347. size_t ret = 0;
  348. if (SDO_C != NULL && buf != NULL) {
  349. ret = CO_fifo_write(&SDO_C->bufFifo, buf, count, NULL);
  350. }
  351. return ret;
  352. }
  353. /******************************************************************************/
  354. CO_SDO_return_t CO_SDOclientDownload(CO_SDOclient_t *SDO_C,
  355. uint32_t timeDifference_us,
  356. bool_t abort,
  357. bool_t bufferPartial,
  358. CO_SDO_abortCode_t *SDOabortCode,
  359. size_t *sizeTransferred,
  360. uint32_t *timerNext_us)
  361. {
  362. (void)timerNext_us; (void) bufferPartial; /* may be unused */
  363. CO_SDO_return_t ret = CO_SDO_RT_waitingResponse;
  364. CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE;
  365. if (SDO_C == NULL) {
  366. abortCode = CO_SDO_AB_DEVICE_INCOMPAT;
  367. ret = CO_SDO_RT_wrongArguments;
  368. }
  369. else if (SDO_C->state == CO_SDO_ST_IDLE) {
  370. ret = CO_SDO_RT_ok_communicationEnd;
  371. }
  372. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL
  373. /* Transfer data locally **************************************************/
  374. else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_LOCAL_TRANSFER && !abort) {
  375. if (SDO_C->SDO->state != CO_SDO_ST_IDLE) {
  376. abortCode = CO_SDO_AB_DEVICE_INCOMPAT;
  377. ret = CO_SDO_RT_endedWithClientAbort;
  378. }
  379. else {
  380. /* Max data size is limited to fifo size (for now). */
  381. size_t count = CO_fifo_getOccupied(&SDO_C->bufFifo);
  382. if (SDO_C->sizeInd > 0 && SDO_C->sizeInd != count) {
  383. abortCode = CO_SDO_AB_TYPE_MISMATCH;
  384. ret = CO_SDO_RT_endedWithClientAbort;
  385. }
  386. else {
  387. /* init ODF_arg */
  388. abortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index,
  389. SDO_C->subIndex);
  390. if (abortCode == CO_SDO_AB_NONE) {
  391. /* set buffer and write data to the Object dictionary */
  392. SDO_C->SDO->ODF_arg.data = (uint8_t *)SDO_C->buf;
  393. abortCode = CO_SDO_writeOD(SDO_C->SDO, count);
  394. }
  395. if (abortCode == CO_SDO_AB_NONE) {
  396. SDO_C->sizeTran = count;
  397. ret = CO_SDO_RT_ok_communicationEnd;
  398. }
  399. else {
  400. ret = CO_SDO_RT_endedWithServerAbort;
  401. }
  402. }
  403. }
  404. SDO_C->state = CO_SDO_ST_IDLE;
  405. }
  406. #endif /* CO_CONFIG_SDO_CLI_LOCAL */
  407. /* CAN data received ******************************************************/
  408. else if (CO_FLAG_READ(SDO_C->CANrxNew)) {
  409. /* is SDO abort */
  410. if (SDO_C->CANrxData[0] == 0x80) {
  411. uint32_t code;
  412. memcpy(&code, &SDO_C->CANrxData[4], sizeof(code));
  413. abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code);
  414. SDO_C->state = CO_SDO_ST_IDLE;
  415. ret = CO_SDO_RT_endedWithServerAbort;
  416. }
  417. else if (abort) {
  418. abortCode = (SDOabortCode != NULL)
  419. ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT;
  420. SDO_C->state = CO_SDO_ST_ABORT;
  421. }
  422. else switch (SDO_C->state) {
  423. case CO_SDO_ST_DOWNLOAD_INITIATE_RSP: {
  424. if (SDO_C->CANrxData[0] == 0x60) {
  425. /* verify index and subindex */
  426. uint16_t index;
  427. uint8_t subindex;
  428. index = ((uint16_t) SDO_C->CANrxData[2]) << 8;
  429. index |= SDO_C->CANrxData[1];
  430. subindex = SDO_C->CANrxData[3];
  431. if (index != SDO_C->index || subindex != SDO_C->subIndex) {
  432. abortCode = CO_SDO_AB_PRAM_INCOMPAT;
  433. SDO_C->state = CO_SDO_ST_ABORT;
  434. break;
  435. }
  436. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED
  437. if (SDO_C->finished) {
  438. /* expedited transfer */
  439. SDO_C->state = CO_SDO_ST_IDLE;
  440. ret = CO_SDO_RT_ok_communicationEnd;
  441. }
  442. else {
  443. /* segmented transfer - prepare the first segment */
  444. SDO_C->toggle = 0x00;
  445. SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ;
  446. }
  447. #else
  448. /* expedited transfer */
  449. SDO_C->state = CO_SDO_ST_IDLE;
  450. ret = CO_SDO_RT_ok_communicationEnd;
  451. #endif
  452. }
  453. else {
  454. abortCode = CO_SDO_AB_CMD;
  455. SDO_C->state = CO_SDO_ST_ABORT;
  456. }
  457. break;
  458. }
  459. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED
  460. case CO_SDO_ST_DOWNLOAD_SEGMENT_RSP: {
  461. if ((SDO_C->CANrxData[0] & 0xEF) == 0x20) {
  462. /* verify and alternate toggle bit */
  463. uint8_t toggle = SDO_C->CANrxData[0] & 0x10;
  464. if (toggle != SDO_C->toggle) {
  465. abortCode = CO_SDO_AB_TOGGLE_BIT;
  466. SDO_C->state = CO_SDO_ST_ABORT;
  467. break;
  468. }
  469. SDO_C->toggle = (toggle == 0x00) ? 0x10 : 0x00;
  470. /* is end of transfer? */
  471. if (SDO_C->finished) {
  472. SDO_C->state = CO_SDO_ST_IDLE;
  473. ret = CO_SDO_RT_ok_communicationEnd;
  474. }
  475. else {
  476. SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_REQ;
  477. }
  478. }
  479. else {
  480. abortCode = CO_SDO_AB_CMD;
  481. SDO_C->state = CO_SDO_ST_ABORT;
  482. }
  483. break;
  484. }
  485. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */
  486. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  487. case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP: {
  488. if ((SDO_C->CANrxData[0] & 0xFB) == 0xA0) {
  489. /* verify index and subindex */
  490. uint16_t index;
  491. uint8_t subindex;
  492. index = ((uint16_t) SDO_C->CANrxData[2]) << 8;
  493. index |= SDO_C->CANrxData[1];
  494. subindex = SDO_C->CANrxData[3];
  495. if (index != SDO_C->index || subindex != SDO_C->subIndex) {
  496. abortCode = CO_SDO_AB_PRAM_INCOMPAT;
  497. SDO_C->state = CO_SDO_ST_ABORT;
  498. break;
  499. }
  500. SDO_C->block_crc = 0;
  501. SDO_C->block_blksize = SDO_C->CANrxData[4];
  502. if (SDO_C->block_blksize < 1 || SDO_C->block_blksize > 127)
  503. SDO_C->block_blksize = 127;
  504. SDO_C->block_seqno = 0;
  505. CO_fifo_altBegin(&SDO_C->bufFifo, 0);
  506. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ;
  507. }
  508. else {
  509. abortCode = CO_SDO_AB_CMD;
  510. SDO_C->state = CO_SDO_ST_ABORT;
  511. }
  512. break;
  513. }
  514. case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ:
  515. case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP: {
  516. if (SDO_C->CANrxData[0] == 0xA2) {
  517. /* check number of segments */
  518. if (SDO_C->CANrxData[1] < SDO_C->block_seqno) {
  519. /* NOT all segments transferred successfully.
  520. * Re-transmit data after erroneous segment. */
  521. CO_fifo_altBegin(&SDO_C->bufFifo,
  522. (size_t)SDO_C->CANrxData[1] * 7);
  523. SDO_C->finished = false;
  524. }
  525. else if (SDO_C->CANrxData[1] > SDO_C->block_seqno) {
  526. /* something strange from server, break transmission */
  527. abortCode = CO_SDO_AB_CMD;
  528. SDO_C->state = CO_SDO_ST_ABORT;
  529. break;
  530. }
  531. /* confirm successfully transmitted data */
  532. CO_fifo_altFinish(&SDO_C->bufFifo, &SDO_C->block_crc);
  533. if (SDO_C->finished) {
  534. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_REQ;
  535. } else {
  536. SDO_C->block_blksize = SDO_C->CANrxData[2];
  537. SDO_C->block_seqno = 0;
  538. CO_fifo_altBegin(&SDO_C->bufFifo, 0);
  539. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ;
  540. }
  541. }
  542. else {
  543. abortCode = CO_SDO_AB_CMD;
  544. SDO_C->state = CO_SDO_ST_ABORT;
  545. }
  546. break;
  547. }
  548. case CO_SDO_ST_DOWNLOAD_BLK_END_RSP: {
  549. if (SDO_C->CANrxData[0] == 0xA1) {
  550. /* SDO block download successfully transferred */
  551. SDO_C->state = CO_SDO_ST_IDLE;
  552. ret = CO_SDO_RT_ok_communicationEnd;
  553. }
  554. else {
  555. abortCode = CO_SDO_AB_CMD;
  556. SDO_C->state = CO_SDO_ST_ABORT;
  557. }
  558. break;
  559. }
  560. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */
  561. default: {
  562. abortCode = CO_SDO_AB_CMD;
  563. SDO_C->state = CO_SDO_ST_ABORT;
  564. break;
  565. }
  566. }
  567. SDO_C->timeoutTimer = 0;
  568. timeDifference_us = 0;
  569. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  570. }
  571. else if (abort) {
  572. abortCode = (SDOabortCode != NULL)
  573. ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT;
  574. SDO_C->state = CO_SDO_ST_ABORT;
  575. }
  576. /* Timeout timers *********************************************************/
  577. if (ret == CO_SDO_RT_waitingResponse) {
  578. if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) {
  579. SDO_C->timeoutTimer += timeDifference_us;
  580. }
  581. if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) {
  582. abortCode = CO_SDO_AB_TIMEOUT;
  583. SDO_C->state = CO_SDO_ST_ABORT;
  584. }
  585. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT
  586. else if (timerNext_us != NULL) {
  587. /* check again after timeout time elapsed */
  588. uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer;
  589. if (*timerNext_us > diff) {
  590. *timerNext_us = diff;
  591. }
  592. }
  593. #endif
  594. if (SDO_C->CANtxBuff->bufferFull) {
  595. ret = CO_SDO_RT_transmittBufferFull;
  596. }
  597. }
  598. /* Transmit CAN data ******************************************************/
  599. if (ret == CO_SDO_RT_waitingResponse) {
  600. size_t count;
  601. memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8);
  602. switch (SDO_C->state) {
  603. case CO_SDO_ST_DOWNLOAD_INITIATE_REQ: {
  604. SDO_C->CANtxBuff->data[0] = 0x20;
  605. SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index;
  606. SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8);
  607. SDO_C->CANtxBuff->data[3] = SDO_C->subIndex;
  608. /* get count of data bytes to transfer */
  609. count = CO_fifo_getOccupied(&SDO_C->bufFifo);
  610. /* is expedited transfer, <= 4bytes of data */
  611. if ((SDO_C->sizeInd == 0 && count <= 4)
  612. || (SDO_C->sizeInd > 0 && SDO_C->sizeInd <= 4)
  613. ) {
  614. SDO_C->CANtxBuff->data[0] |= 0x02;
  615. /* verify length, indicate data size */
  616. if (count == 0 || (SDO_C->sizeInd > 0 &&
  617. SDO_C->sizeInd != count)
  618. ) {
  619. SDO_C->state = CO_SDO_ST_IDLE;
  620. abortCode = CO_SDO_AB_TYPE_MISMATCH;
  621. ret = CO_SDO_RT_endedWithClientAbort;
  622. break;
  623. }
  624. if (SDO_C->sizeInd > 0) {
  625. SDO_C->CANtxBuff->data[0] |= 0x01 | ((4 - count) << 2);
  626. }
  627. /* copy data */
  628. CO_fifo_read(&SDO_C->bufFifo,
  629. (char *)&SDO_C->CANtxBuff->data[4], count, NULL);
  630. SDO_C->sizeTran = count;
  631. SDO_C->finished = true;
  632. }
  633. else {
  634. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED
  635. /* segmented transfer, indicate data size */
  636. if (SDO_C->sizeInd > 0) {
  637. uint32_t size = CO_SWAP_32(SDO_C->sizeInd);
  638. SDO_C->CANtxBuff->data[0] |= 0x01;
  639. memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size));
  640. }
  641. #else
  642. SDO_C->state = CO_SDO_ST_IDLE;
  643. abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS;
  644. ret = CO_SDO_RT_endedWithClientAbort;
  645. break;
  646. #endif
  647. }
  648. /* reset timeout timer and send message */
  649. SDO_C->timeoutTimer = 0;
  650. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  651. SDO_C->state = CO_SDO_ST_DOWNLOAD_INITIATE_RSP;
  652. break;
  653. }
  654. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED
  655. case CO_SDO_ST_DOWNLOAD_SEGMENT_REQ: {
  656. /* fill data bytes */
  657. count = CO_fifo_read(&SDO_C->bufFifo,
  658. (char *)&SDO_C->CANtxBuff->data[1],
  659. 7, NULL);
  660. /* verify if sizeTran is too large */
  661. SDO_C->sizeTran += count;
  662. if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) {
  663. SDO_C->sizeTran -= count;
  664. abortCode = CO_SDO_AB_DATA_LONG;
  665. SDO_C->state = CO_SDO_ST_ABORT;
  666. break;
  667. }
  668. /* SDO command specifier */
  669. SDO_C->CANtxBuff->data[0] = SDO_C->toggle | ((7 - count) << 1);
  670. /* is end of transfer? Verify also sizeTran */
  671. if (CO_fifo_getOccupied(&SDO_C->bufFifo) == 0 && !bufferPartial) {
  672. if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) {
  673. abortCode = CO_SDO_AB_DATA_SHORT;
  674. SDO_C->state = CO_SDO_ST_ABORT;
  675. break;
  676. }
  677. SDO_C->CANtxBuff->data[0] |= 0x01;
  678. SDO_C->finished = true;
  679. }
  680. /* reset timeout timer and send message */
  681. SDO_C->timeoutTimer = 0;
  682. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  683. SDO_C->state = CO_SDO_ST_DOWNLOAD_SEGMENT_RSP;
  684. break;
  685. }
  686. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */
  687. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  688. case CO_SDO_ST_DOWNLOAD_BLK_INITIATE_REQ: {
  689. SDO_C->CANtxBuff->data[0] = 0xC4;
  690. SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index;
  691. SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8);
  692. SDO_C->CANtxBuff->data[3] = SDO_C->subIndex;
  693. /* indicate data size */
  694. if (SDO_C->sizeInd > 0) {
  695. uint32_t size = CO_SWAP_32(SDO_C->sizeInd);
  696. SDO_C->CANtxBuff->data[0] |= 0x02;
  697. memcpy(&SDO_C->CANtxBuff->data[4], &size, sizeof(size));
  698. }
  699. /* reset timeout timer and send message */
  700. SDO_C->timeoutTimer = 0;
  701. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  702. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_INITIATE_RSP;
  703. break;
  704. }
  705. case CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ: {
  706. if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) < 7 && bufferPartial) {
  707. /* wait until data are refilled */
  708. break;
  709. }
  710. SDO_C->CANtxBuff->data[0] = ++SDO_C->block_seqno;
  711. /* get up to 7 data bytes */
  712. count = CO_fifo_altRead(&SDO_C->bufFifo,
  713. (char *)&SDO_C->CANtxBuff->data[1], 7);
  714. SDO_C->block_noData = 7 - count;
  715. /* verify if sizeTran is too large */
  716. SDO_C->sizeTran += count;
  717. if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) {
  718. SDO_C->sizeTran -= count;
  719. abortCode = CO_SDO_AB_DATA_LONG;
  720. SDO_C->state = CO_SDO_ST_ABORT;
  721. break;
  722. }
  723. /* is end of transfer? Verify also sizeTran */
  724. if (CO_fifo_altGetOccupied(&SDO_C->bufFifo) == 0 && !bufferPartial){
  725. if (SDO_C->sizeInd > 0 && SDO_C->sizeTran < SDO_C->sizeInd) {
  726. abortCode = CO_SDO_AB_DATA_SHORT;
  727. SDO_C->state = CO_SDO_ST_ABORT;
  728. break;
  729. }
  730. SDO_C->CANtxBuff->data[0] |= 0x80;
  731. SDO_C->finished = true;
  732. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP;
  733. }
  734. /* are all segments in current block transferred? */
  735. else if (SDO_C->block_seqno >= SDO_C->block_blksize) {
  736. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_RSP;
  737. }
  738. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT
  739. else {
  740. /* Inform OS to call this function again without delay. */
  741. if (timerNext_us != NULL) {
  742. *timerNext_us = 0;
  743. }
  744. }
  745. #endif
  746. /* reset timeout timer and send message */
  747. SDO_C->timeoutTimer = 0;
  748. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  749. break;
  750. }
  751. case CO_SDO_ST_DOWNLOAD_BLK_END_REQ: {
  752. SDO_C->CANtxBuff->data[0] = 0xC1 | (SDO_C->block_noData << 2);
  753. SDO_C->CANtxBuff->data[1] = (uint8_t) SDO_C->block_crc;
  754. SDO_C->CANtxBuff->data[2] = (uint8_t) (SDO_C->block_crc >> 8);
  755. /* reset timeout timer and send message */
  756. SDO_C->timeoutTimer = 0;
  757. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  758. SDO_C->state = CO_SDO_ST_DOWNLOAD_BLK_END_RSP;
  759. break;
  760. }
  761. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */
  762. default: {
  763. break;
  764. }
  765. }
  766. }
  767. if (ret == CO_SDO_RT_waitingResponse) {
  768. if (SDO_C->state == CO_SDO_ST_ABORT) {
  769. uint32_t code = CO_SWAP_32((uint32_t)abortCode);
  770. /* Send SDO abort message */
  771. SDO_C->CANtxBuff->data[0] = 0x80;
  772. SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index;
  773. SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8);
  774. SDO_C->CANtxBuff->data[3] = SDO_C->subIndex;
  775. memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code));
  776. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  777. SDO_C->state = CO_SDO_ST_IDLE;
  778. ret = CO_SDO_RT_endedWithClientAbort;
  779. }
  780. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  781. else if (SDO_C->state == CO_SDO_ST_DOWNLOAD_BLK_SUBBLOCK_REQ) {
  782. ret = CO_SDO_RT_blockDownldInProgress;
  783. }
  784. #endif
  785. }
  786. if (sizeTransferred != NULL) {
  787. *sizeTransferred = SDO_C->sizeTran;
  788. }
  789. if (SDOabortCode != NULL) {
  790. *SDOabortCode = abortCode;
  791. }
  792. return ret;
  793. }
  794. /******************************************************************************
  795. * UPLOAD *
  796. ******************************************************************************/
  797. CO_SDO_return_t CO_SDOclientUploadInitiate(CO_SDOclient_t *SDO_C,
  798. uint16_t index,
  799. uint8_t subIndex,
  800. uint16_t SDOtimeoutTime_ms,
  801. bool_t blockEnable)
  802. {
  803. /* verify parameters */
  804. if (SDO_C == NULL) {
  805. return CO_SDO_RT_wrongArguments;
  806. }
  807. /* save parameters */
  808. SDO_C->index = index;
  809. SDO_C->subIndex = subIndex;
  810. SDO_C->sizeInd = 0;
  811. SDO_C->sizeTran = 0;
  812. SDO_C->finished = false;
  813. CO_fifo_reset(&SDO_C->bufFifo);
  814. SDO_C->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000;
  815. SDO_C->timeoutTimer = 0;
  816. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  817. SDO_C->block_SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 700;
  818. #endif
  819. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL
  820. /* if node-ID of the SDO server is the same as node-ID of this node, then
  821. * transfer data within this node */
  822. if (SDO_C->SDO != NULL
  823. && SDO_C->SDOClientPar->nodeIDOfTheSDOServer == SDO_C->SDO->nodeId
  824. ) {
  825. SDO_C->state = CO_SDO_ST_UPLOAD_LOCAL_TRANSFER;
  826. }
  827. else
  828. #endif
  829. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  830. if (blockEnable) {
  831. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ;
  832. }
  833. else
  834. #endif
  835. {
  836. SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_REQ;
  837. }
  838. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  839. return CO_SDO_RT_ok_communicationEnd;
  840. }
  841. /******************************************************************************/
  842. CO_SDO_return_t CO_SDOclientUpload(CO_SDOclient_t *SDO_C,
  843. uint32_t timeDifference_us,
  844. bool_t abort,
  845. CO_SDO_abortCode_t *SDOabortCode,
  846. size_t *sizeIndicated,
  847. size_t *sizeTransferred,
  848. uint32_t *timerNext_us)
  849. {
  850. (void)timerNext_us; /* may be unused */
  851. CO_SDO_return_t ret = CO_SDO_RT_waitingResponse;
  852. CO_SDO_abortCode_t abortCode = CO_SDO_AB_NONE;
  853. if (SDO_C == NULL) {
  854. abortCode = CO_SDO_AB_DEVICE_INCOMPAT;
  855. ret = CO_SDO_RT_wrongArguments;
  856. }
  857. else if (SDO_C->state == CO_SDO_ST_IDLE) {
  858. ret = CO_SDO_RT_ok_communicationEnd;
  859. }
  860. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_LOCAL
  861. /* Transfer data locally **************************************************/
  862. else if (SDO_C->state == CO_SDO_ST_UPLOAD_LOCAL_TRANSFER && !abort) {
  863. if (SDO_C->SDO->state != 0) {
  864. abortCode = CO_SDO_AB_DEVICE_INCOMPAT;
  865. ret = CO_SDO_RT_endedWithClientAbort;
  866. }
  867. else {
  868. /* Max data size is limited to fifo size (for now). */
  869. size_t count = CO_fifo_getSpace(&SDO_C->bufFifo);
  870. /* init ODF_arg */
  871. abortCode = CO_SDO_initTransfer(SDO_C->SDO, SDO_C->index,
  872. SDO_C->subIndex);
  873. if (abortCode == CO_SDO_AB_NONE) {
  874. /* set buffer and read data from the Object dictionary */
  875. SDO_C->SDO->ODF_arg.data = (uint8_t *)SDO_C->buf;
  876. if (SDO_C->SDO->ODF_arg.ODdataStorage == 0) {
  877. /* set length if domain */
  878. SDO_C->SDO->ODF_arg.dataLength = count;
  879. }
  880. abortCode = CO_SDO_readOD(SDO_C->SDO, count);
  881. }
  882. if (abortCode == CO_SDO_AB_NONE) {
  883. /* is SDO buffer too small */
  884. if (SDO_C->SDO->ODF_arg.lastSegment == 0) {
  885. abortCode = CO_SDO_AB_OUT_OF_MEM; /* Out of memory */
  886. ret = CO_SDO_RT_endedWithServerAbort;
  887. }
  888. else {
  889. SDO_C->sizeTran = (size_t)SDO_C->SDO->ODF_arg.dataLength;
  890. /* fifo was written directly, indicate data size manually */
  891. SDO_C->bufFifo.writePtr = SDO_C->sizeTran;
  892. ret = CO_SDO_RT_ok_communicationEnd;
  893. }
  894. }
  895. else {
  896. ret = CO_SDO_RT_endedWithServerAbort;
  897. }
  898. }
  899. SDO_C->state = CO_SDO_ST_IDLE;
  900. }
  901. #endif /* CO_CONFIG_SDO_CLI_LOCAL */
  902. /* CAN data received ******************************************************/
  903. else if (CO_FLAG_READ(SDO_C->CANrxNew)) {
  904. /* is SDO abort */
  905. if (SDO_C->CANrxData[0] == 0x80) {
  906. uint32_t code;
  907. memcpy(&code, &SDO_C->CANrxData[4], sizeof(code));
  908. abortCode = (CO_SDO_abortCode_t)CO_SWAP_32(code);
  909. SDO_C->state = CO_SDO_ST_IDLE;
  910. ret = CO_SDO_RT_endedWithServerAbort;
  911. }
  912. else if (abort) {
  913. abortCode = (SDOabortCode != NULL)
  914. ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT;
  915. SDO_C->state = CO_SDO_ST_ABORT;
  916. }
  917. else switch (SDO_C->state) {
  918. case CO_SDO_ST_UPLOAD_INITIATE_RSP: {
  919. if ((SDO_C->CANrxData[0] & 0xF0) == 0x40) {
  920. /* verify index and subindex */
  921. uint16_t index;
  922. uint8_t subindex;
  923. index = ((uint16_t) SDO_C->CANrxData[2]) << 8;
  924. index |= SDO_C->CANrxData[1];
  925. subindex = SDO_C->CANrxData[3];
  926. if (index != SDO_C->index || subindex != SDO_C->subIndex) {
  927. abortCode = CO_SDO_AB_PRAM_INCOMPAT;
  928. SDO_C->state = CO_SDO_ST_ABORT;
  929. break;
  930. }
  931. if (SDO_C->CANrxData[0] & 0x02) {
  932. /* Expedited transfer */
  933. size_t count = 4;
  934. /* is size indicated? */
  935. if (SDO_C->CANrxData[0] & 0x01) {
  936. count -= (SDO_C->CANrxData[0] >> 2) & 0x03;
  937. }
  938. /* copy data, indicate size and finish */
  939. CO_fifo_write(&SDO_C->bufFifo,
  940. (const char *)&SDO_C->CANrxData[4],
  941. count, NULL);
  942. SDO_C->sizeTran = count;
  943. SDO_C->state = CO_SDO_ST_IDLE;
  944. ret = CO_SDO_RT_ok_communicationEnd;
  945. }
  946. else {
  947. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED
  948. /* segmented transfer, is size indicated? */
  949. if (SDO_C->CANrxData[0] & 0x01) {
  950. uint32_t size;
  951. memcpy(&size, &SDO_C->CANrxData[4], sizeof(size));
  952. SDO_C->sizeInd = CO_SWAP_32(size);
  953. }
  954. SDO_C->toggle = 0x00;
  955. SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ;
  956. #else
  957. abortCode = CO_SDO_AB_UNSUPPORTED_ACCESS;
  958. SDO_C->state = CO_SDO_ST_ABORT;
  959. #endif
  960. }
  961. }
  962. else {
  963. abortCode = CO_SDO_AB_CMD;
  964. SDO_C->state = CO_SDO_ST_ABORT;
  965. }
  966. break;
  967. }
  968. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED
  969. case CO_SDO_ST_UPLOAD_SEGMENT_RSP: {
  970. if ((SDO_C->CANrxData[0] & 0xE0) == 0x00) {
  971. size_t count, countWr;
  972. /* verify and alternate toggle bit */
  973. uint8_t toggle = SDO_C->CANrxData[0] & 0x10;
  974. if (toggle != SDO_C->toggle) {
  975. abortCode = CO_SDO_AB_TOGGLE_BIT;
  976. SDO_C->state = CO_SDO_ST_ABORT;
  977. break;
  978. }
  979. SDO_C->toggle = (toggle == 0x00) ? 0x10 : 0x00;
  980. /* get data size and write data to the buffer */
  981. count = 7 - ((SDO_C->CANrxData[0] >> 1) & 0x07);
  982. countWr = CO_fifo_write(&SDO_C->bufFifo,
  983. (const char *)&SDO_C->CANrxData[1],
  984. count, NULL);
  985. SDO_C->sizeTran += countWr;
  986. /* verify, if there was not enough space in fifo buffer */
  987. if (countWr != count) {
  988. abortCode = CO_SDO_AB_OUT_OF_MEM;
  989. SDO_C->state = CO_SDO_ST_ABORT;
  990. break;
  991. }
  992. /* verify if size of data uploaded is too large */
  993. if (SDO_C->sizeInd > 0
  994. && SDO_C->sizeTran > SDO_C->sizeInd
  995. ) {
  996. abortCode = CO_SDO_AB_DATA_LONG;
  997. SDO_C->state = CO_SDO_ST_ABORT;
  998. break;
  999. }
  1000. /* If no more segments to be upload, finish */
  1001. if (SDO_C->CANrxData[0] & 0x01) {
  1002. /* verify size of data uploaded */
  1003. if (SDO_C->sizeInd > 0
  1004. && SDO_C->sizeTran < SDO_C->sizeInd
  1005. ) {
  1006. abortCode = CO_SDO_AB_DATA_SHORT;
  1007. SDO_C->state = CO_SDO_ST_ABORT;
  1008. } else {
  1009. SDO_C->state = CO_SDO_ST_IDLE;
  1010. ret = CO_SDO_RT_ok_communicationEnd;
  1011. }
  1012. }
  1013. else {
  1014. SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ;
  1015. }
  1016. }
  1017. else {
  1018. abortCode = CO_SDO_AB_CMD;
  1019. SDO_C->state = CO_SDO_ST_ABORT;
  1020. }
  1021. break;
  1022. }
  1023. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */
  1024. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  1025. case CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP: {
  1026. if ((SDO_C->CANrxData[0] & 0xF9) == 0xC0) {
  1027. uint16_t index;
  1028. uint8_t subindex;
  1029. /* get server CRC support info and data size */
  1030. if ((SDO_C->CANrxData[0] & 0x04) != 0) {
  1031. SDO_C->block_crcEnabled = true;
  1032. } else {
  1033. SDO_C->block_crcEnabled = false;
  1034. }
  1035. if (SDO_C->CANrxData[0] & 0x02) {
  1036. uint32_t size;
  1037. memcpy(&size, &SDO_C->CANrxData[4], sizeof(size));
  1038. SDO_C->sizeInd = CO_SWAP_32(size);
  1039. }
  1040. /* verify index and subindex */
  1041. index = ((uint16_t) SDO_C->CANrxData[2]) << 8;
  1042. index |= SDO_C->CANrxData[1];
  1043. subindex = SDO_C->CANrxData[3];
  1044. if (index != SDO_C->index || subindex != SDO_C->subIndex) {
  1045. abortCode = CO_SDO_AB_PRAM_INCOMPAT;
  1046. SDO_C->state = CO_SDO_ST_ABORT;
  1047. }
  1048. else {
  1049. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2;
  1050. }
  1051. }
  1052. /* switch to regular transfer, CO_SDO_ST_UPLOAD_INITIATE_RSP */
  1053. else if ((SDO_C->CANrxData[0] & 0xF0) == 0x40) {
  1054. /* verify index and subindex */
  1055. uint16_t index;
  1056. uint8_t subindex;
  1057. index = ((uint16_t) SDO_C->CANrxData[2]) << 8;
  1058. index |= SDO_C->CANrxData[1];
  1059. subindex = SDO_C->CANrxData[3];
  1060. if (index != SDO_C->index || subindex != SDO_C->subIndex) {
  1061. abortCode = CO_SDO_AB_PRAM_INCOMPAT;
  1062. SDO_C->state = CO_SDO_ST_ABORT;
  1063. break;
  1064. }
  1065. if (SDO_C->CANrxData[0] & 0x02) {
  1066. /* Expedited transfer */
  1067. size_t count = 4;
  1068. /* is size indicated? */
  1069. if (SDO_C->CANrxData[0] & 0x01) {
  1070. count -= (SDO_C->CANrxData[0] >> 2) & 0x03;
  1071. }
  1072. /* copy data, indicate size and finish */
  1073. CO_fifo_write(&SDO_C->bufFifo,
  1074. (const char *)&SDO_C->CANrxData[4],
  1075. count, NULL);
  1076. SDO_C->sizeTran = count;
  1077. SDO_C->state = CO_SDO_ST_IDLE;
  1078. ret = CO_SDO_RT_ok_communicationEnd;
  1079. }
  1080. else {
  1081. /* segmented transfer, is size indicated? */
  1082. if (SDO_C->CANrxData[0] & 0x01) {
  1083. uint32_t size;
  1084. memcpy(&size, &SDO_C->CANrxData[4], sizeof(size));
  1085. SDO_C->sizeInd = CO_SWAP_32(size);
  1086. }
  1087. SDO_C->toggle = 0x00;
  1088. SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_REQ;
  1089. }
  1090. }
  1091. else {
  1092. abortCode = CO_SDO_AB_CMD;
  1093. SDO_C->state = CO_SDO_ST_ABORT;
  1094. }
  1095. break;
  1096. }
  1097. case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ: {
  1098. /* data are copied directly in the receive function */
  1099. break;
  1100. }
  1101. case CO_SDO_ST_UPLOAD_BLK_END_SREQ: {
  1102. if ((SDO_C->CANrxData[0] & 0xE3) == 0xC1) {
  1103. /* Get number of data bytes in last segment, that do not
  1104. * contain data. Then copy remaining data into fifo */
  1105. uint8_t noData = ((SDO_C->CANrxData[0] >> 2) & 0x07);
  1106. CO_fifo_write(&SDO_C->bufFifo,
  1107. (const char *)&SDO_C->block_dataUploadLast[0],
  1108. 7 - noData,
  1109. &SDO_C->block_crc);
  1110. SDO_C->sizeTran += 7 - noData;
  1111. /* verify length */
  1112. if (SDO_C->sizeInd > 0
  1113. && SDO_C->sizeTran != SDO_C->sizeInd
  1114. ) {
  1115. abortCode = (SDO_C->sizeTran > SDO_C->sizeInd) ?
  1116. CO_SDO_AB_DATA_LONG : CO_SDO_AB_DATA_SHORT;
  1117. SDO_C->state = CO_SDO_ST_ABORT;
  1118. break;
  1119. }
  1120. /* verify CRC */
  1121. if (SDO_C->block_crcEnabled) {
  1122. uint16_t crcServer;
  1123. crcServer = ((uint16_t) SDO_C->CANrxData[2]) << 8;
  1124. crcServer |= SDO_C->CANrxData[1];
  1125. if (crcServer != SDO_C->block_crc) {
  1126. abortCode = CO_SDO_AB_CRC;
  1127. SDO_C->state = CO_SDO_ST_ABORT;
  1128. break;
  1129. }
  1130. }
  1131. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_CRSP;
  1132. }
  1133. else {
  1134. abortCode = CO_SDO_AB_CMD;
  1135. SDO_C->state = CO_SDO_ST_ABORT;
  1136. }
  1137. break;
  1138. }
  1139. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */
  1140. default: {
  1141. abortCode = CO_SDO_AB_CMD;
  1142. SDO_C->state = CO_SDO_ST_ABORT;
  1143. break;
  1144. }
  1145. }
  1146. SDO_C->timeoutTimer = 0;
  1147. timeDifference_us = 0;
  1148. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  1149. }
  1150. else if (abort) {
  1151. abortCode = (SDOabortCode != NULL)
  1152. ? *SDOabortCode : CO_SDO_AB_DEVICE_INCOMPAT;
  1153. SDO_C->state = CO_SDO_ST_ABORT;
  1154. }
  1155. /* Timeout timers *********************************************************/
  1156. if (ret == CO_SDO_RT_waitingResponse) {
  1157. if (SDO_C->timeoutTimer < SDO_C->SDOtimeoutTime_us) {
  1158. SDO_C->timeoutTimer += timeDifference_us;
  1159. }
  1160. if (SDO_C->timeoutTimer >= SDO_C->SDOtimeoutTime_us) {
  1161. if (SDO_C->state == CO_SDO_ST_UPLOAD_SEGMENT_REQ ||
  1162. SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP
  1163. ) {
  1164. /* application didn't empty buffer */
  1165. abortCode = CO_SDO_AB_GENERAL;
  1166. } else {
  1167. abortCode = CO_SDO_AB_TIMEOUT;
  1168. }
  1169. SDO_C->state = CO_SDO_ST_ABORT;
  1170. }
  1171. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT
  1172. else if (timerNext_us != NULL) {
  1173. /* check again after timeout time elapsed */
  1174. uint32_t diff = SDO_C->SDOtimeoutTime_us - SDO_C->timeoutTimer;
  1175. if (*timerNext_us > diff) {
  1176. *timerNext_us = diff;
  1177. }
  1178. }
  1179. #endif
  1180. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  1181. /* Timeout for sub-block reception */
  1182. if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) {
  1183. if (SDO_C->block_timeoutTimer < SDO_C->block_SDOtimeoutTime_us) {
  1184. SDO_C->block_timeoutTimer += timeDifference_us;
  1185. }
  1186. if (SDO_C->block_timeoutTimer >= SDO_C->block_SDOtimeoutTime_us) {
  1187. /* SDO_C->state will change, processing will continue in this
  1188. * thread. Make memory barrier here with CO_FLAG_CLEAR() call.*/
  1189. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP;
  1190. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  1191. }
  1192. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT
  1193. else if (timerNext_us != NULL) {
  1194. /* check again after timeout time elapsed */
  1195. uint32_t diff = SDO_C->block_SDOtimeoutTime_us -
  1196. SDO_C->block_timeoutTimer;
  1197. if (*timerNext_us > diff) {
  1198. *timerNext_us = diff;
  1199. }
  1200. }
  1201. #endif
  1202. }
  1203. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */
  1204. if (SDO_C->CANtxBuff->bufferFull) {
  1205. ret = CO_SDO_RT_transmittBufferFull;
  1206. }
  1207. }
  1208. /* Transmit CAN data ******************************************************/
  1209. if (ret == CO_SDO_RT_waitingResponse) {
  1210. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  1211. size_t count;
  1212. #endif
  1213. memset((void *)&SDO_C->CANtxBuff->data[0], 0, 8);
  1214. switch (SDO_C->state) {
  1215. case CO_SDO_ST_UPLOAD_INITIATE_REQ: {
  1216. SDO_C->CANtxBuff->data[0] = 0x40;
  1217. SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index;
  1218. SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8);
  1219. SDO_C->CANtxBuff->data[3] = SDO_C->subIndex;
  1220. /* reset timeout timer and send message */
  1221. SDO_C->timeoutTimer = 0;
  1222. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  1223. SDO_C->state = CO_SDO_ST_UPLOAD_INITIATE_RSP;
  1224. break;
  1225. }
  1226. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED
  1227. case CO_SDO_ST_UPLOAD_SEGMENT_REQ: {
  1228. /* verify, if there is enough space in data buffer */
  1229. if (CO_fifo_getSpace(&SDO_C->bufFifo) < 7) {
  1230. ret = CO_SDO_RT_uploadDataBufferFull;
  1231. break;
  1232. }
  1233. SDO_C->CANtxBuff->data[0] = 0x60 | SDO_C->toggle;
  1234. /* reset timeout timer and send message */
  1235. SDO_C->timeoutTimer = 0;
  1236. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  1237. SDO_C->state = CO_SDO_ST_UPLOAD_SEGMENT_RSP;
  1238. break;
  1239. }
  1240. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_SEGMENTED */
  1241. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  1242. case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ: {
  1243. SDO_C->CANtxBuff->data[0] = 0xA4;
  1244. SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index;
  1245. SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8);
  1246. SDO_C->CANtxBuff->data[3] = SDO_C->subIndex;
  1247. /* calculate number of block segments from free buffer space */
  1248. count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7;
  1249. if (count > 127) {
  1250. count = 127;
  1251. }
  1252. else if (count == 0) {
  1253. abortCode = CO_SDO_AB_OUT_OF_MEM;
  1254. SDO_C->state = CO_SDO_ST_ABORT;
  1255. break;
  1256. }
  1257. SDO_C->block_blksize = (uint8_t)count;
  1258. SDO_C->CANtxBuff->data[4] = SDO_C->block_blksize;
  1259. SDO_C->CANtxBuff->data[5] = CO_CONFIG_SDO_CLI_PST;
  1260. /* reset timeout timer and send message */
  1261. SDO_C->timeoutTimer = 0;
  1262. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  1263. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_INITIATE_RSP;
  1264. break;
  1265. }
  1266. case CO_SDO_ST_UPLOAD_BLK_INITIATE_REQ2: {
  1267. SDO_C->CANtxBuff->data[0] = 0xA3;
  1268. /* reset timeout timers, seqno and send message */
  1269. SDO_C->timeoutTimer = 0;
  1270. SDO_C->block_timeoutTimer = 0;
  1271. SDO_C->block_seqno = 0;
  1272. SDO_C->block_crc = 0;
  1273. /* Block segments will be received in different thread. Make memory
  1274. * barrier here with CO_FLAG_CLEAR() call. */
  1275. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ;
  1276. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  1277. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  1278. break;
  1279. }
  1280. case CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_CRSP: {
  1281. SDO_C->CANtxBuff->data[0] = 0xA2;
  1282. SDO_C->CANtxBuff->data[1] = SDO_C->block_seqno;
  1283. #ifdef CO_DEBUG_SDO_CLIENT
  1284. bool_t transferShort = SDO_C->block_seqno != SDO_C->block_blksize;
  1285. uint8_t seqnoStart = SDO_C->block_seqno;
  1286. #endif
  1287. /* Is last segment? */
  1288. if (SDO_C->finished) {
  1289. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_END_SREQ;
  1290. }
  1291. else {
  1292. /* verify if size of data uploaded is too large */
  1293. if (SDO_C->sizeInd > 0 && SDO_C->sizeTran > SDO_C->sizeInd) {
  1294. abortCode = CO_SDO_AB_DATA_LONG;
  1295. SDO_C->state = CO_SDO_ST_ABORT;
  1296. break;
  1297. }
  1298. /* calculate number of block segments from free buffer space */
  1299. count = CO_fifo_getSpace(&SDO_C->bufFifo) / 7;
  1300. if (count >= 127) {
  1301. count = 127;
  1302. }
  1303. else if (CO_fifo_getOccupied(&SDO_C->bufFifo) > 0) {
  1304. /* application must empty data buffer first */
  1305. ret = CO_SDO_RT_uploadDataBufferFull;
  1306. #ifdef CO_DEBUG_SDO_CLIENT
  1307. if (transferShort) {
  1308. char msg[80];
  1309. sprintf(msg,
  1310. "sub-block, uploadDataBufferFull: sequno=%02X",
  1311. seqnoStart);
  1312. CO_DEBUG_SDO_CLIENT(msg);
  1313. }
  1314. #endif
  1315. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_FLAG_TIMERNEXT
  1316. /* Inform OS to call this function again without delay. */
  1317. if (timerNext_us != NULL) {
  1318. *timerNext_us = 0;
  1319. }
  1320. #endif
  1321. break;
  1322. }
  1323. SDO_C->block_blksize = (uint8_t)count;
  1324. SDO_C->block_seqno = 0;
  1325. /* Block segments will be received in different thread. Make
  1326. * memory barrier here with CO_FLAG_CLEAR() call. */
  1327. SDO_C->state = CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ;
  1328. CO_FLAG_CLEAR(SDO_C->CANrxNew);
  1329. }
  1330. SDO_C->CANtxBuff->data[2] = SDO_C->block_blksize;
  1331. /* reset block_timeoutTimer, but not SDO_C->timeoutTimer */
  1332. SDO_C->block_timeoutTimer = 0;
  1333. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  1334. #ifdef CO_DEBUG_SDO_CLIENT
  1335. if (transferShort && !SDO_C->finished) {
  1336. char msg[80];
  1337. sprintf(msg,
  1338. "sub-block restarted: sequnoPrev=%02X, blksize=%02X",
  1339. seqnoStart, SDO_C->block_blksize);
  1340. CO_DEBUG_SDO_CLIENT(msg);
  1341. }
  1342. #endif
  1343. break;
  1344. }
  1345. case CO_SDO_ST_UPLOAD_BLK_END_CRSP: {
  1346. SDO_C->CANtxBuff->data[0] = 0xA1;
  1347. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  1348. SDO_C->state = CO_SDO_ST_IDLE;
  1349. ret = CO_SDO_RT_ok_communicationEnd;
  1350. break;
  1351. }
  1352. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK */
  1353. default: {
  1354. break;
  1355. }
  1356. }
  1357. }
  1358. if (ret == CO_SDO_RT_waitingResponse) {
  1359. if (SDO_C->state == CO_SDO_ST_ABORT) {
  1360. uint32_t code = CO_SWAP_32((uint32_t)abortCode);
  1361. /* Send SDO abort message */
  1362. SDO_C->CANtxBuff->data[0] = 0x80;
  1363. SDO_C->CANtxBuff->data[1] = (uint8_t)SDO_C->index;
  1364. SDO_C->CANtxBuff->data[2] = (uint8_t)(SDO_C->index >> 8);
  1365. SDO_C->CANtxBuff->data[3] = SDO_C->subIndex;
  1366. memcpy(&SDO_C->CANtxBuff->data[4], &code, sizeof(code));
  1367. CO_CANsend(SDO_C->CANdevTx, SDO_C->CANtxBuff);
  1368. SDO_C->state = CO_SDO_ST_IDLE;
  1369. ret = CO_SDO_RT_endedWithClientAbort;
  1370. }
  1371. #if (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_BLOCK
  1372. else if (SDO_C->state == CO_SDO_ST_UPLOAD_BLK_SUBBLOCK_SREQ) {
  1373. ret = CO_SDO_RT_blockUploadInProgress;
  1374. }
  1375. #endif
  1376. }
  1377. if (sizeIndicated != NULL) {
  1378. *sizeIndicated = SDO_C->sizeInd;
  1379. }
  1380. if (sizeTransferred != NULL) {
  1381. *sizeTransferred = SDO_C->sizeTran;
  1382. }
  1383. if (SDOabortCode != NULL) {
  1384. *SDOabortCode = abortCode;
  1385. }
  1386. return ret;
  1387. }
  1388. /******************************************************************************/
  1389. size_t CO_SDOclientUploadBufRead(CO_SDOclient_t *SDO_C,
  1390. char *buf,
  1391. size_t count)
  1392. {
  1393. size_t ret = 0;
  1394. if (SDO_C != NULL && buf != NULL) {
  1395. ret = CO_fifo_read(&SDO_C->bufFifo, buf, count, NULL);
  1396. }
  1397. return ret;
  1398. }
  1399. /******************************************************************************/
  1400. void CO_SDOclientClose(CO_SDOclient_t *SDO_C) {
  1401. if (SDO_C != NULL) {
  1402. SDO_C->state = CO_SDO_ST_IDLE;
  1403. }
  1404. }
  1405. #endif /* (CO_CONFIG_SDO_CLI) & CO_CONFIG_SDO_CLI_ENABLE */