CO_SDOserver.c 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478
  1. /*
  2. * CANopen Service Data Object - server.
  3. *
  4. * @file CO_SDOserver.c
  5. * @ingroup CO_SDOserver
  6. * @author Janez Paternoster
  7. * @copyright 2004 - 2020 Janez Paternoster
  8. *
  9. * This file is part of CANopenNode, an opensource CANopen Stack.
  10. * Project home page is <https://github.com/CANopenNode/CANopenNode>.
  11. * For more information on CANopen see <http://www.can-cia.org/>.
  12. *
  13. * Licensed under the Apache License, Version 2.0 (the "License");
  14. * you may not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * http://www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an "AS IS" BASIS,
  21. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. */
  25. #include "301/CO_driver.h"
  26. #include "301/CO_SDOserver.h"
  27. #include "301/crc16-ccitt.h"
  28. /* Client command specifier, see DS301 */
  29. #define CCS_DOWNLOAD_INITIATE 1U
  30. #define CCS_DOWNLOAD_SEGMENT 0U
  31. #define CCS_UPLOAD_INITIATE 2U
  32. #define CCS_UPLOAD_SEGMENT 3U
  33. #define CCS_DOWNLOAD_BLOCK 6U
  34. #define CCS_UPLOAD_BLOCK 5U
  35. #define CCS_ABORT 0x80U
  36. #if CO_CONFIG_SDO_BUFFER_SIZE < 7
  37. #error CO_CONFIG_SDO_BUFFER_SIZE must be greater than 7
  38. #endif
  39. static void CO_SDO_receive_done(CO_SDO_t *SDO){
  40. #if CO_SDO_RX_DATA_SIZE > 1
  41. uint8_t rcv = SDO->CANrxRcv;
  42. uint8_t newRcv = rcv;
  43. if (++newRcv >= CO_SDO_RX_DATA_SIZE)
  44. newRcv = 0;
  45. SDO->CANrxRcv = newRcv;
  46. CO_FLAG_SET(SDO->CANrxNew[rcv]);
  47. #else
  48. CO_FLAG_SET(SDO->CANrxNew[0]);
  49. #endif
  50. }
  51. /*
  52. * Read received message from CAN module.
  53. *
  54. * Function will be called (by CAN receive interrupt) every time, when CAN
  55. * message with correct identifier will be received. For more information and
  56. * description of parameters see file CO_driver.h.
  57. */
  58. static void CO_SDO_receive(void *object, void *msg);
  59. static void CO_SDO_receive(void *object, void *msg){
  60. CO_SDO_t *SDO;
  61. uint8_t rcv, *CANrxData;
  62. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  63. uint8_t *data = CO_CANrxMsg_readData(msg);
  64. SDO = (CO_SDO_t*)object; /* this is the correct pointer type of the first argument */
  65. rcv = SDO->CANrxRcv;
  66. CANrxData = SDO->CANrxData[rcv];
  67. /* verify message length and message queue overflow (if previous messages were not processed yet) */
  68. if ((DLC == 8U) && (!CO_FLAG_READ(SDO->CANrxNew[rcv]))){
  69. if (SDO->state != CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) {
  70. /* copy data and set 'new message' flag */
  71. memcpy(CANrxData, data, DLC);
  72. CO_SDO_receive_done(SDO);
  73. }
  74. else {
  75. /* block download, copy data directly */
  76. uint8_t seqno;
  77. CANrxData[0] = data[0];
  78. seqno = CANrxData[0] & 0x7fU;
  79. SDO->timeoutTimer = 0;
  80. /* clear timeout in sub-block transfer indication if set before */
  81. if (SDO->timeoutSubblockDownolad) {
  82. SDO->timeoutSubblockDownolad = false;
  83. }
  84. /* check correct sequence number. */
  85. if (seqno == (SDO->sequence + 1U)) {
  86. /* sequence is correct */
  87. /* check if buffer can store whole message just in case */
  88. if (CO_CONFIG_SDO_BUFFER_SIZE - SDO->bufferOffset >= 7) {
  89. uint8_t i;
  90. SDO->sequence++;
  91. /* copy data */
  92. for(i=1; i<8; i++) {
  93. SDO->ODF_arg.data[SDO->bufferOffset++] = data[i]; //SDO->ODF_arg.data is equal as SDO->databuffer
  94. }
  95. /* break reception if last segment, block ends or block sequence is too large */
  96. if (((CANrxData[0] & 0x80U) == 0x80U) || (SDO->sequence >= SDO->blksize)) {
  97. SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP;
  98. CO_SDO_receive_done(SDO);
  99. }
  100. } else {
  101. /* buffer is full, ignore this segment, send response without resetting sequence */
  102. SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2;
  103. CO_SDO_receive_done(SDO);
  104. }
  105. }
  106. else if ((seqno == SDO->sequence) || (SDO->sequence == 0U)) {
  107. /* Ignore message, if it is duplicate or if sequence didn't started yet. */
  108. }
  109. else {
  110. /* seqno is wrong, send response without resetting sequence */
  111. SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2;
  112. CO_SDO_receive_done(SDO);
  113. }
  114. }
  115. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  116. /* Optional signal to RTOS, which can resume task, which handles SDO server. */
  117. if (CO_FLAG_READ(SDO->CANrxNew[rcv]) && SDO->pFunctSignalPre != NULL) {
  118. SDO->pFunctSignalPre(SDO->functSignalObjectPre);
  119. }
  120. #endif
  121. }
  122. }
  123. /*
  124. * Function for accessing _SDO server parameter_ for default SDO (index 0x1200)
  125. * from SDO server.
  126. *
  127. * For more information see file CO_SDOserver.h.
  128. */
  129. static CO_SDO_abortCode_t CO_ODF_1200(CO_ODF_arg_t *ODF_arg);
  130. static CO_SDO_abortCode_t CO_ODF_1200(CO_ODF_arg_t *ODF_arg){
  131. uint8_t *nodeId;
  132. uint32_t value;
  133. CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
  134. nodeId = (uint8_t*) ODF_arg->object;
  135. value = CO_getUint32(ODF_arg->data);
  136. /* if SDO reading Object dictionary 0x1200, add nodeId to the value */
  137. if ((ODF_arg->reading) && (ODF_arg->subIndex > 0U)){
  138. CO_setUint32(ODF_arg->data, value + *nodeId);
  139. }
  140. return ret;
  141. }
  142. /******************************************************************************/
  143. CO_ReturnError_t CO_SDO_init(
  144. CO_SDO_t *SDO,
  145. uint32_t COB_IDClientToServer,
  146. uint32_t COB_IDServerToClient,
  147. uint16_t ObjDictIndex_SDOServerParameter,
  148. CO_SDO_t *parentSDO,
  149. const CO_OD_entry_t OD[],
  150. uint16_t ODSize,
  151. CO_OD_extension_t *ODExtensions,
  152. uint8_t nodeId,
  153. uint16_t SDOtimeoutTime_ms,
  154. CO_CANmodule_t *CANdevRx,
  155. uint16_t CANdevRxIdx,
  156. CO_CANmodule_t *CANdevTx,
  157. uint16_t CANdevTxIdx)
  158. {
  159. CO_ReturnError_t ret = CO_ERROR_NO;
  160. /* verify arguments */
  161. if (SDO==NULL || CANdevRx==NULL || CANdevTx==NULL){
  162. return CO_ERROR_ILLEGAL_ARGUMENT;
  163. }
  164. /* configure own object dictionary */
  165. if (parentSDO == NULL){
  166. uint16_t i;
  167. SDO->ownOD = true;
  168. SDO->OD = OD;
  169. SDO->ODSize = ODSize;
  170. SDO->ODExtensions = ODExtensions;
  171. /* clear pointers in ODExtensions */
  172. for(i=0U; i<ODSize; i++){
  173. SDO->ODExtensions[i].pODFunc = NULL;
  174. SDO->ODExtensions[i].object = NULL;
  175. SDO->ODExtensions[i].flags = NULL;
  176. }
  177. }
  178. /* copy object dictionary from parent */
  179. else{
  180. SDO->ownOD = false;
  181. SDO->OD = parentSDO->OD;
  182. SDO->ODSize = parentSDO->ODSize;
  183. SDO->ODExtensions = parentSDO->ODExtensions;
  184. }
  185. /* Configure object variables */
  186. SDO->nodeId = nodeId;
  187. SDO->SDOtimeoutTime_us = (uint32_t)SDOtimeoutTime_ms * 1000;
  188. SDO->state = CO_SDO_ST_IDLE;
  189. uint8_t i;
  190. for(i=0U; i<CO_SDO_RX_DATA_SIZE; i++){
  191. CO_FLAG_CLEAR(SDO->CANrxNew[i]);
  192. }
  193. SDO->CANrxRcv = 0;
  194. SDO->CANrxProc = 0;
  195. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  196. SDO->pFunctSignalPre = NULL;
  197. SDO->functSignalObjectPre = NULL;
  198. #endif
  199. /* Configure Object dictionary entry at index 0x1200 */
  200. if (ObjDictIndex_SDOServerParameter == OD_H1200_SDO_SERVER_PARAM){
  201. CO_OD_configure(SDO, ObjDictIndex_SDOServerParameter, CO_ODF_1200, (void*)&SDO->nodeId, 0U, 0U);
  202. }
  203. if ((COB_IDClientToServer & 0x80000000) != 0 || (COB_IDServerToClient & 0x80000000) != 0 ){
  204. // SDO is invalid
  205. COB_IDClientToServer = 0;
  206. COB_IDServerToClient = 0;
  207. }
  208. /* configure SDO server CAN reception */
  209. ret = CO_CANrxBufferInit(
  210. CANdevRx, /* CAN device */
  211. CANdevRxIdx, /* rx buffer index */
  212. COB_IDClientToServer, /* CAN identifier */
  213. 0x7FF, /* mask */
  214. 0, /* rtr */
  215. (void*)SDO, /* object passed to receive function */
  216. CO_SDO_receive); /* this function will process received message */
  217. /* configure SDO server CAN transmission */
  218. SDO->CANdevTx = CANdevTx;
  219. SDO->CANtxBuff = CO_CANtxBufferInit(
  220. CANdevTx, /* CAN device */
  221. CANdevTxIdx, /* index of specific buffer inside CAN module */
  222. COB_IDServerToClient, /* CAN identifier */
  223. 0, /* rtr */
  224. 8, /* number of data bytes */
  225. 0); /* synchronous message flag bit */
  226. if (SDO->CANtxBuff == NULL) {
  227. ret = CO_ERROR_ILLEGAL_ARGUMENT;
  228. }
  229. return ret;
  230. }
  231. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  232. /******************************************************************************/
  233. void CO_SDO_initCallbackPre(
  234. CO_SDO_t *SDO,
  235. void *object,
  236. void (*pFunctSignalPre)(void *object))
  237. {
  238. if (SDO != NULL){
  239. SDO->functSignalObjectPre = object;
  240. SDO->pFunctSignalPre = pFunctSignalPre;
  241. }
  242. }
  243. #endif
  244. /******************************************************************************/
  245. void CO_OD_configure(
  246. CO_SDO_t *SDO,
  247. uint16_t index,
  248. CO_SDO_abortCode_t (*pODFunc)(CO_ODF_arg_t *ODF_arg),
  249. void *object,
  250. uint8_t *flags,
  251. uint8_t flagsSize)
  252. {
  253. uint16_t entryNo;
  254. entryNo = CO_OD_find(SDO, index);
  255. if (entryNo < 0xFFFFU){
  256. CO_OD_extension_t *ext = &SDO->ODExtensions[entryNo];
  257. uint8_t maxSubIndex = SDO->OD[entryNo].maxSubIndex;
  258. ext->pODFunc = pODFunc;
  259. ext->object = object;
  260. if ((flags != NULL) && (flagsSize != 0U) && (flagsSize == maxSubIndex)){
  261. uint16_t i;
  262. ext->flags = flags;
  263. for(i=0U; i<=maxSubIndex; i++){
  264. ext->flags[i] = 0U;
  265. }
  266. }
  267. else{
  268. ext->flags = NULL;
  269. }
  270. }
  271. }
  272. /******************************************************************************/
  273. uint16_t CO_OD_find(CO_SDO_t *SDO, uint16_t index){
  274. /* Fast search in ordered Object Dictionary. If indexes are mixed, this won't work. */
  275. /* If Object Dictionary has up to 2^N entries, then N is max number of loop passes. */
  276. uint16_t cur, min, max;
  277. const CO_OD_entry_t* object;
  278. min = 0U;
  279. max = SDO->ODSize - 1U;
  280. while(min < max){
  281. cur = (min + max) / 2;
  282. object = &SDO->OD[cur];
  283. /* Is object matched */
  284. if (index == object->index){
  285. return cur;
  286. }
  287. if (index < object->index){
  288. max = cur;
  289. if (max) max--;
  290. }
  291. else
  292. min = cur + 1U;
  293. }
  294. if (min == max){
  295. object = &SDO->OD[min];
  296. /* Is object matched */
  297. if (index == object->index){
  298. return min;
  299. }
  300. }
  301. return 0xFFFFU; /* object does not exist in OD */
  302. }
  303. /******************************************************************************/
  304. uint16_t CO_OD_getLength(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){
  305. const CO_OD_entry_t* object = &SDO->OD[entryNo];
  306. if (entryNo == 0xFFFFU){
  307. return 0U;
  308. }
  309. if (object->maxSubIndex == 0U){ /* Object type is Var */
  310. if (object->pData == 0){ /* data type is domain */
  311. return CO_CONFIG_SDO_BUFFER_SIZE;
  312. }
  313. else{
  314. return object->length;
  315. }
  316. }
  317. else if (object->attribute != 0U){ /* Object type is Array */
  318. if (subIndex == 0U){
  319. return 1U;
  320. }
  321. else if (object->pData == 0){
  322. /* data type is domain */
  323. return CO_CONFIG_SDO_BUFFER_SIZE;
  324. }
  325. else{
  326. return object->length;
  327. }
  328. }
  329. else{ /* Object type is Record */
  330. if (((const CO_OD_entryRecord_t*)(object->pData))[subIndex].pData == 0){
  331. /* data type is domain */
  332. return CO_CONFIG_SDO_BUFFER_SIZE;
  333. }
  334. else{
  335. return ((const CO_OD_entryRecord_t*)(object->pData))[subIndex].length;
  336. }
  337. }
  338. }
  339. /******************************************************************************/
  340. uint16_t CO_OD_getAttribute(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){
  341. const CO_OD_entry_t* object = &SDO->OD[entryNo];
  342. if (entryNo == 0xFFFFU){
  343. return 0U;
  344. }
  345. if (object->maxSubIndex == 0U){ /* Object type is Var */
  346. return object->attribute;
  347. }
  348. else if (object->attribute != 0U){/* Object type is Array */
  349. bool_t exception_1003 = false;
  350. uint16_t attr = object->attribute;
  351. /* Special exception: Object 1003,00 should be writable */
  352. if (object->index == 0x1003 && subIndex == 0) {
  353. exception_1003 = true;
  354. attr |= CO_ODA_WRITEABLE;
  355. }
  356. if (subIndex == 0U && !exception_1003){
  357. /* First subIndex is readonly */
  358. attr &= ~(CO_ODA_WRITEABLE | CO_ODA_RPDO_MAPABLE);
  359. attr |= CO_ODA_READABLE;
  360. }
  361. return attr;
  362. }
  363. else{ /* Object type is Record */
  364. return ((const CO_OD_entryRecord_t*)(object->pData))[subIndex].attribute;
  365. }
  366. }
  367. /******************************************************************************/
  368. void* CO_OD_getDataPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){
  369. const CO_OD_entry_t* object = &SDO->OD[entryNo];
  370. if (entryNo == 0xFFFFU){
  371. return 0;
  372. }
  373. if (object->maxSubIndex == 0U){ /* Object type is Var */
  374. return object->pData;
  375. }
  376. else if (object->maxSubIndex < subIndex){
  377. /* Object type Array/Record, request is out of bounds */
  378. return 0;
  379. }
  380. else if (object->attribute != 0U){/* Object type is Array */
  381. if (subIndex==0){
  382. /* this is the data, for the subIndex 0 in the array */
  383. return (void*) &object->maxSubIndex;
  384. }
  385. else if (object->pData == 0){
  386. /* data type is domain */
  387. return 0;
  388. }
  389. else{
  390. return (void*)(((int8_t*)object->pData) + ((subIndex-1) * object->length));
  391. }
  392. }
  393. else{ /* Object Type is Record */
  394. return ((const CO_OD_entryRecord_t*)(object->pData))[subIndex].pData;
  395. }
  396. }
  397. /******************************************************************************/
  398. uint8_t* CO_OD_getFlagsPointer(CO_SDO_t *SDO, uint16_t entryNo, uint8_t subIndex){
  399. if (entryNo == 0xFFFF || SDO->ODExtensions == NULL){
  400. return NULL;
  401. }
  402. CO_OD_extension_t* ext = &SDO->ODExtensions[entryNo];
  403. if (ext->flags == NULL){
  404. return NULL;
  405. }
  406. return &ext->flags[subIndex];
  407. }
  408. /******************************************************************************/
  409. uint32_t CO_SDO_initTransfer(CO_SDO_t *SDO, uint16_t index, uint8_t subIndex){
  410. SDO->ODF_arg.index = index;
  411. SDO->ODF_arg.subIndex = subIndex;
  412. /* find object in Object Dictionary */
  413. SDO->entryNo = CO_OD_find(SDO, index);
  414. if (SDO->entryNo == 0xFFFFU){
  415. return CO_SDO_AB_NOT_EXIST ; /* object does not exist in OD */
  416. }
  417. /* verify existance of subIndex */
  418. if (subIndex > SDO->OD[SDO->entryNo].maxSubIndex &&
  419. SDO->OD[SDO->entryNo].pData != NULL)
  420. {
  421. return CO_SDO_AB_SUB_UNKNOWN; /* Sub-index does not exist. */
  422. }
  423. /* pointer to data in Object dictionary */
  424. SDO->ODF_arg.ODdataStorage = CO_OD_getDataPointer(SDO, SDO->entryNo, subIndex);
  425. /* fill ODF_arg */
  426. SDO->ODF_arg.object = NULL;
  427. if (SDO->ODExtensions){
  428. CO_OD_extension_t *ext = &SDO->ODExtensions[SDO->entryNo];
  429. SDO->ODF_arg.object = ext->object;
  430. }
  431. SDO->ODF_arg.data = SDO->databuffer;
  432. SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, subIndex);
  433. SDO->ODF_arg.attribute = CO_OD_getAttribute(SDO, SDO->entryNo, subIndex);
  434. SDO->ODF_arg.pFlags = CO_OD_getFlagsPointer(SDO, SDO->entryNo, subIndex);
  435. SDO->ODF_arg.firstSegment = true;
  436. SDO->ODF_arg.lastSegment = true;
  437. /* indicate total data length, if not domain */
  438. SDO->ODF_arg.dataLengthTotal = (SDO->ODF_arg.ODdataStorage) ? SDO->ODF_arg.dataLength : 0U;
  439. SDO->ODF_arg.offset = 0U;
  440. /* verify length */
  441. if (SDO->ODF_arg.dataLength > CO_CONFIG_SDO_BUFFER_SIZE){
  442. return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */
  443. }
  444. return 0U;
  445. }
  446. /******************************************************************************/
  447. uint32_t CO_SDO_readOD(CO_SDO_t *SDO, uint16_t SDOBufferSize){
  448. uint8_t *SDObuffer = SDO->ODF_arg.data;
  449. uint8_t *ODdata = (uint8_t*)SDO->ODF_arg.ODdataStorage;
  450. uint16_t length = SDO->ODF_arg.dataLength;
  451. CO_OD_extension_t *ext = NULL;
  452. /* is object readable? */
  453. if ((SDO->ODF_arg.attribute & CO_ODA_READABLE) == 0)
  454. return CO_SDO_AB_WRITEONLY; /* attempt to read a write-only object */
  455. /* find extension */
  456. if (SDO->ODExtensions != NULL){
  457. ext = &SDO->ODExtensions[SDO->entryNo];
  458. }
  459. CO_LOCK_OD();
  460. /* copy data from OD to SDO buffer if not domain */
  461. if (ODdata != NULL){
  462. while(length--) *(SDObuffer++) = *(ODdata++);
  463. }
  464. /* if domain, Object dictionary function MUST exist */
  465. else{
  466. if (ext && ext->pODFunc == NULL){
  467. CO_UNLOCK_OD();
  468. return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */
  469. }
  470. }
  471. /* call Object dictionary function if registered */
  472. SDO->ODF_arg.reading = true;
  473. if (ext && ext->pODFunc != NULL){
  474. uint32_t abortCode = ext->pODFunc(&SDO->ODF_arg);
  475. if (abortCode != 0U){
  476. CO_UNLOCK_OD();
  477. return abortCode;
  478. }
  479. /* dataLength (upadted by pODFunc) must be inside limits */
  480. if ((SDO->ODF_arg.dataLength == 0U) || (SDO->ODF_arg.dataLength > SDOBufferSize)){
  481. CO_UNLOCK_OD();
  482. return CO_SDO_AB_DEVICE_INCOMPAT; /* general internal incompatibility in the device */
  483. }
  484. }
  485. CO_UNLOCK_OD();
  486. SDO->ODF_arg.offset += SDO->ODF_arg.dataLength;
  487. SDO->ODF_arg.firstSegment = false;
  488. /* swap data if processor is not little endian (CANopen is) */
  489. #ifdef CO_BIG_ENDIAN
  490. if ((SDO->ODF_arg.attribute & CO_ODA_MB_VALUE) != 0){
  491. uint16_t len = SDO->ODF_arg.dataLength;
  492. uint8_t *buf1 = SDO->ODF_arg.data;
  493. uint8_t *buf2 = buf1 + len - 1;
  494. len /= 2;
  495. while(len--){
  496. uint8_t b = *buf1;
  497. *(buf1++) = *buf2;
  498. *(buf2--) = b;
  499. }
  500. }
  501. #endif
  502. return 0U;
  503. }
  504. /******************************************************************************/
  505. uint32_t CO_SDO_writeOD(CO_SDO_t *SDO, uint16_t length){
  506. uint8_t *SDObuffer = SDO->ODF_arg.data;
  507. uint8_t *ODdata = (uint8_t*)SDO->ODF_arg.ODdataStorage;
  508. bool_t exception_1003 = false;
  509. /* is object writeable? */
  510. if ((SDO->ODF_arg.attribute & CO_ODA_WRITEABLE) == 0){
  511. return CO_SDO_AB_READONLY; /* attempt to write a read-only object */
  512. }
  513. /* length of domain data is application specific and not verified */
  514. if (ODdata == 0){
  515. SDO->ODF_arg.dataLength = length;
  516. }
  517. /* verify length except for domain data type */
  518. else if (SDO->ODF_arg.dataLength != length){
  519. return CO_SDO_AB_TYPE_MISMATCH; /* Length of service parameter does not match */
  520. }
  521. /* swap data if processor is not little endian (CANopen is) */
  522. #ifdef CO_BIG_ENDIAN
  523. if ((SDO->ODF_arg.attribute & CO_ODA_MB_VALUE) != 0){
  524. uint16_t len = SDO->ODF_arg.dataLength;
  525. uint8_t *buf1 = SDO->ODF_arg.data;
  526. uint8_t *buf2 = buf1 + len - 1;
  527. len /= 2;
  528. while(len--){
  529. uint8_t b = *buf1;
  530. *(buf1++) = *buf2;
  531. *(buf2--) = b;
  532. }
  533. }
  534. #endif
  535. CO_LOCK_OD();
  536. /* call Object dictionary function if registered */
  537. SDO->ODF_arg.reading = false;
  538. if (SDO->ODExtensions != NULL){
  539. CO_OD_extension_t *ext = &SDO->ODExtensions[SDO->entryNo];
  540. if (ext->pODFunc != NULL){
  541. uint32_t abortCode = ext->pODFunc(&SDO->ODF_arg);
  542. if (abortCode != 0U){
  543. CO_UNLOCK_OD();
  544. return abortCode;
  545. }
  546. }
  547. }
  548. SDO->ODF_arg.offset += SDO->ODF_arg.dataLength;
  549. SDO->ODF_arg.firstSegment = false;
  550. /* Special exception: 1003,00 is writable from network, but not in OD */
  551. if (SDO->ODF_arg.index == 0x1003 && SDO->ODF_arg.subIndex == 0) {
  552. exception_1003 = true;
  553. }
  554. /* copy data from SDO buffer to OD if not domain */
  555. if ((ODdata != NULL) && !exception_1003){
  556. while(length--){
  557. *(ODdata++) = *(SDObuffer++);
  558. }
  559. }
  560. CO_UNLOCK_OD();
  561. return 0;
  562. }
  563. /******************************************************************************/
  564. static void CO_SDO_process_done(CO_SDO_t *SDO, uint32_t *timerNext_us) {
  565. (void)timerNext_us; /* may be unused */
  566. #if CO_SDO_RX_DATA_SIZE > 1
  567. uint8_t proc = SDO->CANrxProc;
  568. uint8_t newProc = proc;
  569. /* check if buffer needs to be free */
  570. if (!CO_FLAG_READ(SDO->CANrxNew[proc])) {
  571. return;
  572. }
  573. if (++newProc >= CO_SDO_RX_DATA_SIZE)
  574. newProc = 0;
  575. SDO->CANrxProc = newProc;
  576. CO_FLAG_CLEAR(SDO->CANrxNew[proc]);
  577. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  578. if ((timerNext_us != NULL) && (CO_FLAG_READ(SDO->CANrxNew[newProc])))
  579. timerNext_us = 0; /* Set timerNext_us to 0 to inform OS to call CO_SDO_process function again without delay. */
  580. #endif
  581. #else
  582. CO_FLAG_CLEAR(SDO->CANrxNew[0]);
  583. #endif
  584. }
  585. /******************************************************************************/
  586. static void CO_SDO_abort(CO_SDO_t *SDO, uint32_t code){
  587. SDO->CANtxBuff->data[0] = 0x80;
  588. SDO->CANtxBuff->data[1] = SDO->ODF_arg.index & 0xFF;
  589. SDO->CANtxBuff->data[2] = (SDO->ODF_arg.index>>8) & 0xFF;
  590. SDO->CANtxBuff->data[3] = SDO->ODF_arg.subIndex;
  591. CO_memcpySwap4(&SDO->CANtxBuff->data[4], &code);
  592. SDO->state = CO_SDO_ST_IDLE;
  593. /* skip all received messages in queue if any */
  594. while (CO_FLAG_READ(SDO->CANrxNew[SDO->CANrxProc]))
  595. CO_SDO_process_done(SDO, NULL);
  596. CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff);
  597. }
  598. /******************************************************************************/
  599. int8_t CO_SDO_process(
  600. CO_SDO_t *SDO,
  601. bool_t NMTisPreOrOperational,
  602. uint32_t timeDifference_us,
  603. uint32_t *timerNext_us)
  604. {
  605. CO_SDO_state_t state = CO_SDO_ST_IDLE;
  606. bool_t sendResponse = false;
  607. uint8_t proc, *CANrxData;
  608. bool_t isNew;
  609. proc = SDO->CANrxProc;
  610. isNew = CO_FLAG_READ(SDO->CANrxNew[proc]);
  611. /* return if idle */
  612. if ((SDO->state == CO_SDO_ST_IDLE) && (!isNew)){
  613. return 0;
  614. }
  615. /* SDO is allowed to work only in operational or pre-operational NMT state */
  616. if (!NMTisPreOrOperational){
  617. SDO->state = CO_SDO_ST_IDLE;
  618. /* free receive buffer if it is not empty */
  619. CO_SDO_process_done(SDO, timerNext_us);
  620. return 0;
  621. }
  622. CANrxData = SDO->CANrxData[proc];
  623. /* Is something new to process? */
  624. if ((!SDO->CANtxBuff->bufferFull) && (isNew || (SDO->state == CO_SDO_ST_UPLOAD_BL_SUBBLOCK))){
  625. /* reset timeout */
  626. if (SDO->state != CO_SDO_ST_UPLOAD_BL_SUBBLOCK) {
  627. SDO->timeoutTimer = 0;
  628. timeDifference_us = 0;
  629. }
  630. /* clear response buffer */
  631. memset(SDO->CANtxBuff->data, 0, sizeof(SDO->CANtxBuff->data));
  632. /* Is abort from client? */
  633. if (isNew && (CANrxData[0] == CCS_ABORT)){
  634. SDO->state = CO_SDO_ST_IDLE;
  635. CO_SDO_process_done(SDO, timerNext_us);
  636. return -1;
  637. }
  638. /* continue with previous SDO communication or start new */
  639. if (SDO->state != CO_SDO_ST_IDLE){
  640. state = SDO->state;
  641. }
  642. else{
  643. uint32_t abortCode;
  644. uint16_t index;
  645. uint8_t CCS = CANrxData[0] >> 5; /* Client command specifier */
  646. /* Is client command specifier valid */
  647. if ((CCS != CCS_DOWNLOAD_INITIATE) && (CCS != CCS_UPLOAD_INITIATE) &&
  648. (CCS != CCS_DOWNLOAD_BLOCK) && (CCS != CCS_UPLOAD_BLOCK)){
  649. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  650. return -1;
  651. }
  652. /* init ODF_arg */
  653. index = CANrxData[2];
  654. index = index << 8 | CANrxData[1];
  655. abortCode = CO_SDO_initTransfer(SDO, index, CANrxData[3]);
  656. if (abortCode != 0U){
  657. CO_SDO_abort(SDO, abortCode);
  658. return -1;
  659. }
  660. /* download */
  661. if ((CCS == CCS_DOWNLOAD_INITIATE) || (CCS == CCS_DOWNLOAD_BLOCK)){
  662. if ((SDO->ODF_arg.attribute & CO_ODA_WRITEABLE) == 0U){
  663. CO_SDO_abort(SDO, CO_SDO_AB_READONLY); /* attempt to write a read-only object */
  664. return -1;
  665. }
  666. /* set state machine to normal or block download */
  667. if (CCS == CCS_DOWNLOAD_INITIATE){
  668. state = CO_SDO_ST_DOWNLOAD_INITIATE;
  669. }
  670. else{
  671. state = CO_SDO_ST_DOWNLOAD_BL_INITIATE;
  672. }
  673. }
  674. /* upload */
  675. else{
  676. abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE);
  677. if (abortCode != 0U){
  678. CO_SDO_abort(SDO, abortCode);
  679. return -1;
  680. }
  681. /* if data size is large enough set state machine to block upload, otherwise set to normal transfer */
  682. if ((CCS == CCS_UPLOAD_BLOCK) && (SDO->ODF_arg.dataLength > CANrxData[5])){
  683. state = CO_SDO_ST_UPLOAD_BL_INITIATE;
  684. }
  685. else{
  686. state = CO_SDO_ST_UPLOAD_INITIATE;
  687. }
  688. }
  689. }
  690. }
  691. /* verify SDO timeout */
  692. if (SDO->timeoutTimer < SDO->SDOtimeoutTime_us) {
  693. SDO->timeoutTimer += timeDifference_us;
  694. }
  695. if (SDO->timeoutTimer >= SDO->SDOtimeoutTime_us) {
  696. if ((SDO->state == CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK) && (!SDO->timeoutSubblockDownolad) && (!SDO->CANtxBuff->bufferFull)){
  697. /* set indication timeout in sub-block transfer and reset timeout */
  698. SDO->timeoutSubblockDownolad = true;
  699. SDO->timeoutTimer = 0;
  700. /* send response without resetting sequence */
  701. state = CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2;
  702. }
  703. else{
  704. CO_SDO_abort(SDO, CO_SDO_AB_TIMEOUT); /* SDO protocol timed out */
  705. return -1;
  706. }
  707. }
  708. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  709. else if (timerNext_us != NULL) {
  710. /* check again after timeout time elapsed */
  711. uint32_t diff = SDO->SDOtimeoutTime_us - SDO->timeoutTimer;
  712. if (*timerNext_us > diff) {
  713. *timerNext_us = diff;
  714. }
  715. }
  716. #endif
  717. /* return immediately if still idle */
  718. if (state == CO_SDO_ST_IDLE){
  719. return 0;
  720. }
  721. /* state machine (buffer is freed with process_done() at the end) */
  722. switch(state){
  723. uint32_t abortCode;
  724. uint16_t len, i;
  725. bool_t lastSegmentInSubblock;
  726. case CO_SDO_ST_DOWNLOAD_INITIATE:{
  727. /* default response */
  728. SDO->CANtxBuff->data[0] = 0x60;
  729. SDO->CANtxBuff->data[1] = CANrxData[1];
  730. SDO->CANtxBuff->data[2] = CANrxData[2];
  731. SDO->CANtxBuff->data[3] = CANrxData[3];
  732. /* Expedited transfer */
  733. if ((CANrxData[0] & 0x02U) != 0U){
  734. /* is size indicated? Get message length */
  735. if ((CANrxData[0] & 0x01U) != 0U){
  736. len = 4U - ((CANrxData[0] >> 2U) & 0x03U);
  737. }
  738. else{
  739. len = SDO->ODF_arg.dataLength;
  740. }
  741. /* copy data to SDO buffer */
  742. SDO->ODF_arg.data[0] = CANrxData[4];
  743. SDO->ODF_arg.data[1] = CANrxData[5];
  744. SDO->ODF_arg.data[2] = CANrxData[6];
  745. SDO->ODF_arg.data[3] = CANrxData[7];
  746. /* write data to the Object dictionary */
  747. abortCode = CO_SDO_writeOD(SDO, len);
  748. if (abortCode != 0U){
  749. CO_SDO_abort(SDO, abortCode);
  750. return -1;
  751. }
  752. /* finish the communication and run mainline processing again */
  753. SDO->state = CO_SDO_ST_IDLE;
  754. sendResponse = true;
  755. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  756. if (timerNext_us != NULL)
  757. *timerNext_us = 0;
  758. #endif
  759. }
  760. /* Segmented transfer */
  761. else{
  762. /* verify length if size is indicated */
  763. if ((CANrxData[0]&0x01) != 0){
  764. uint32_t lenRx;
  765. CO_memcpySwap4(&lenRx, &CANrxData[4]);
  766. SDO->ODF_arg.dataLengthTotal = lenRx;
  767. /* verify length except for domain data type */
  768. if ((lenRx != SDO->ODF_arg.dataLength) && (SDO->ODF_arg.ODdataStorage != 0)){
  769. CO_SDO_abort(SDO, CO_SDO_AB_TYPE_MISMATCH); /* Length of service parameter does not match */
  770. return -1;
  771. }
  772. }
  773. SDO->bufferOffset = 0U;
  774. SDO->sequence = 0U;
  775. SDO->state = CO_SDO_ST_DOWNLOAD_SEGMENTED;
  776. sendResponse = true;
  777. }
  778. break;
  779. }
  780. case CO_SDO_ST_DOWNLOAD_SEGMENTED:{
  781. /* verify client command specifier */
  782. if ((CANrxData[0]&0xE0) != 0x00U){
  783. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  784. return -1;
  785. }
  786. /* verify toggle bit */
  787. i = (CANrxData[0]&0x10U) ? 1U : 0U;
  788. if (i != SDO->sequence){
  789. CO_SDO_abort(SDO, CO_SDO_AB_TOGGLE_BIT);/* toggle bit not alternated */
  790. return -1;
  791. }
  792. /* get size of data in message */
  793. len = 7U - ((CANrxData[0] >> 1U) & 0x07U);
  794. /* verify length. Domain data type enables length larger than SDO buffer size */
  795. if ((SDO->bufferOffset + len) > SDO->ODF_arg.dataLength){
  796. if (SDO->ODF_arg.ODdataStorage != 0){
  797. CO_SDO_abort(SDO, CO_SDO_AB_DATA_LONG); /* Length of service parameter too high */
  798. return -1;
  799. }
  800. else{
  801. /* empty buffer in domain data type */
  802. SDO->ODF_arg.lastSegment = false;
  803. abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset);
  804. if (abortCode != 0U){
  805. CO_SDO_abort(SDO, abortCode);
  806. return -1;
  807. }
  808. SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE;
  809. SDO->bufferOffset = 0U;
  810. }
  811. }
  812. /* copy data to buffer */
  813. for(i=0U; i<len; i++)
  814. SDO->ODF_arg.data[SDO->bufferOffset++] = CANrxData[i+1];
  815. /* If no more segments to be downloaded, write data to the Object dictionary */
  816. if ((CANrxData[0] & 0x01U) != 0U){
  817. SDO->ODF_arg.lastSegment = true;
  818. abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset);
  819. if (abortCode != 0U){
  820. CO_SDO_abort(SDO, abortCode);
  821. return -1;
  822. }
  823. /* finish the communication and run mainline processing again */
  824. SDO->state = CO_SDO_ST_IDLE;
  825. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  826. if (timerNext_us != NULL)
  827. *timerNext_us = 0;
  828. #endif
  829. }
  830. /* download segment response and alternate toggle bit */
  831. SDO->CANtxBuff->data[0] = 0x20 | (SDO->sequence ? 0x10 : 0x00);
  832. SDO->sequence = (SDO->sequence) ? 0 : 1;
  833. sendResponse = true;
  834. break;
  835. }
  836. case CO_SDO_ST_DOWNLOAD_BL_INITIATE:{
  837. /* verify client command specifier and subcommand */
  838. if ((CANrxData[0]&0xE1U) != 0xC0U){
  839. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  840. return -1;
  841. }
  842. /* prepare response */
  843. SDO->CANtxBuff->data[0] = 0xA4;
  844. SDO->CANtxBuff->data[1] = CANrxData[1];
  845. SDO->CANtxBuff->data[2] = CANrxData[2];
  846. SDO->CANtxBuff->data[3] = CANrxData[3];
  847. /* blksize */
  848. SDO->blksize = (CO_CONFIG_SDO_BUFFER_SIZE > (7*127)) ? 127 : (CO_CONFIG_SDO_BUFFER_SIZE / 7);
  849. SDO->CANtxBuff->data[4] = SDO->blksize;
  850. /* is CRC enabled */
  851. SDO->crcEnabled = (CANrxData[0] & 0x04) ? true : false;
  852. SDO->crc = 0;
  853. /* verify length if size is indicated */
  854. if ((CANrxData[0]&0x02) != 0U){
  855. uint32_t lenRx;
  856. CO_memcpySwap4(&lenRx, &CANrxData[4]);
  857. SDO->ODF_arg.dataLengthTotal = lenRx;
  858. /* verify length except for domain data type */
  859. if ((lenRx != SDO->ODF_arg.dataLength) && (SDO->ODF_arg.ODdataStorage != 0)){
  860. CO_SDO_abort(SDO, CO_SDO_AB_TYPE_MISMATCH); /* Length of service parameter does not match */
  861. return -1;
  862. }
  863. }
  864. SDO->bufferOffset = 0U;
  865. SDO->sequence = 0U;
  866. SDO->timeoutSubblockDownolad = false;
  867. SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK;
  868. /* send response */
  869. sendResponse = true;
  870. break;
  871. }
  872. case CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK:{
  873. /* data are copied directly in receive function */
  874. break;
  875. }
  876. case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP:
  877. case CO_SDO_ST_DOWNLOAD_BL_SUB_RESP_2:{
  878. /* check if last segment received */
  879. lastSegmentInSubblock = (!SDO->timeoutSubblockDownolad &&
  880. ((CANrxData[0] & 0x80U) == 0x80U)) ? true : false;
  881. /* prepare response */
  882. SDO->CANtxBuff->data[0] = 0xA2;
  883. SDO->CANtxBuff->data[1] = SDO->sequence;
  884. /* reset sequence on reception break */
  885. if (state == CO_SDO_ST_DOWNLOAD_BL_SUB_RESP) {
  886. SDO->sequence = 0U;
  887. }
  888. /* empty buffer in domain data type if not last segment */
  889. if ((SDO->ODF_arg.ODdataStorage == 0) && (SDO->bufferOffset != 0) && !lastSegmentInSubblock){
  890. /* calculate CRC on next bytes, if enabled */
  891. if (SDO->crcEnabled){
  892. SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->bufferOffset, SDO->crc);
  893. }
  894. /* write data to the Object dictionary */
  895. SDO->ODF_arg.lastSegment = false;
  896. abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset);
  897. if (abortCode != 0U){
  898. CO_SDO_abort(SDO, abortCode);
  899. return -1;
  900. }
  901. SDO->ODF_arg.dataLength = CO_CONFIG_SDO_BUFFER_SIZE;
  902. SDO->bufferOffset = 0U;
  903. }
  904. /* blksize */
  905. len = CO_CONFIG_SDO_BUFFER_SIZE - SDO->bufferOffset;
  906. SDO->blksize = (len > (7*127)) ? 127 : (len / 7);
  907. SDO->CANtxBuff->data[2] = SDO->blksize;
  908. /* set next state */
  909. if (lastSegmentInSubblock) {
  910. SDO->state = CO_SDO_ST_DOWNLOAD_BL_END;
  911. }
  912. else if (SDO->bufferOffset >= CO_CONFIG_SDO_BUFFER_SIZE) {
  913. CO_SDO_abort(SDO, CO_SDO_AB_DEVICE_INCOMPAT);
  914. return -1;
  915. }
  916. else {
  917. SDO->state = CO_SDO_ST_DOWNLOAD_BL_SUBBLOCK;
  918. }
  919. /* send response */
  920. sendResponse = true;
  921. break;
  922. }
  923. case CO_SDO_ST_DOWNLOAD_BL_END:{
  924. /* verify client command specifier and subcommand */
  925. if ((CANrxData[0]&0xE1U) != 0xC1U){
  926. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  927. return -1;
  928. }
  929. /* number of bytes in the last segment of the last block that do not contain data. */
  930. len = (CANrxData[0]>>2U) & 0x07U;
  931. SDO->bufferOffset -= len;
  932. /* calculate and verify CRC, if enabled */
  933. if (SDO->crcEnabled){
  934. uint16_t crc;
  935. SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->bufferOffset, SDO->crc);
  936. CO_memcpySwap2(&crc, &CANrxData[1]);
  937. if (SDO->crc != crc){
  938. CO_SDO_abort(SDO, CO_SDO_AB_CRC); /* CRC error (block mode only). */
  939. return -1;
  940. }
  941. }
  942. /* write data to the Object dictionary */
  943. SDO->ODF_arg.lastSegment = true;
  944. abortCode = CO_SDO_writeOD(SDO, SDO->bufferOffset);
  945. if (abortCode != 0U){
  946. CO_SDO_abort(SDO, abortCode);
  947. return -1;
  948. }
  949. /* finish the communication and run mainline processing again */
  950. SDO->CANtxBuff->data[0] = 0xA1;
  951. SDO->state = CO_SDO_ST_IDLE;
  952. sendResponse = true;
  953. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  954. if (timerNext_us != NULL)
  955. *timerNext_us = 0;
  956. #endif
  957. break;
  958. }
  959. case CO_SDO_ST_UPLOAD_INITIATE:{
  960. /* default response */
  961. SDO->CANtxBuff->data[1] = CANrxData[1];
  962. SDO->CANtxBuff->data[2] = CANrxData[2];
  963. SDO->CANtxBuff->data[3] = CANrxData[3];
  964. /* Expedited transfer */
  965. if (SDO->ODF_arg.dataLength <= 4U){
  966. for(i=0U; i<SDO->ODF_arg.dataLength; i++)
  967. SDO->CANtxBuff->data[4U+i] = SDO->ODF_arg.data[i];
  968. SDO->CANtxBuff->data[0] = 0x43U | ((4U-SDO->ODF_arg.dataLength) << 2U);
  969. /* finish the communication and run mainline processing again */
  970. SDO->state = CO_SDO_ST_IDLE;
  971. sendResponse = true;
  972. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  973. if (timerNext_us != NULL)
  974. *timerNext_us = 0;
  975. #endif
  976. }
  977. /* Segmented transfer */
  978. else{
  979. SDO->bufferOffset = 0U;
  980. SDO->sequence = 0U;
  981. SDO->state = CO_SDO_ST_UPLOAD_SEGMENTED;
  982. /* indicate data size, if known */
  983. if (SDO->ODF_arg.dataLengthTotal != 0U){
  984. uint32_t dlentot = SDO->ODF_arg.dataLengthTotal;
  985. CO_memcpySwap4(&SDO->CANtxBuff->data[4], &dlentot);
  986. SDO->CANtxBuff->data[0] = 0x41U;
  987. }
  988. else{
  989. SDO->CANtxBuff->data[0] = 0x40U;
  990. }
  991. /* send response */
  992. sendResponse = true;
  993. }
  994. break;
  995. }
  996. case CO_SDO_ST_UPLOAD_SEGMENTED:{
  997. /* verify client command specifier */
  998. if ((CANrxData[0]&0xE0U) != 0x60U){
  999. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  1000. return -1;
  1001. }
  1002. /* verify toggle bit */
  1003. i = ((CANrxData[0]&0x10U) != 0) ? 1U : 0U;
  1004. if (i != SDO->sequence){
  1005. CO_SDO_abort(SDO, CO_SDO_AB_TOGGLE_BIT);/* toggle bit not alternated */
  1006. return -1;
  1007. }
  1008. /* calculate length to be sent */
  1009. len = SDO->ODF_arg.dataLength - SDO->bufferOffset;
  1010. if (len > 7U) len = 7U;
  1011. /* If data type is domain, re-fill the data buffer if neccessary and indicated so. */
  1012. if ((SDO->ODF_arg.ODdataStorage == 0) && (len < 7U) && (!SDO->ODF_arg.lastSegment)){
  1013. /* copy previous data to the beginning */
  1014. for(i=0U; i<len; i++){
  1015. SDO->ODF_arg.data[i] = SDO->ODF_arg.data[SDO->bufferOffset+i];
  1016. }
  1017. /* move the beginning of the data buffer */
  1018. SDO->ODF_arg.data += len;
  1019. SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, SDO->ODF_arg.subIndex) - len;
  1020. /* read next data from Object dictionary function */
  1021. abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE);
  1022. if (abortCode != 0U){
  1023. CO_SDO_abort(SDO, abortCode);
  1024. return -1;
  1025. }
  1026. /* return to the original data buffer */
  1027. SDO->ODF_arg.data -= len;
  1028. SDO->ODF_arg.dataLength += len;
  1029. SDO->bufferOffset = 0;
  1030. /* re-calculate the length */
  1031. len = SDO->ODF_arg.dataLength;
  1032. if (len > 7U) len = 7U;
  1033. }
  1034. /* fill response data bytes */
  1035. for(i=0U; i<len; i++)
  1036. SDO->CANtxBuff->data[i+1] = SDO->ODF_arg.data[SDO->bufferOffset++];
  1037. /* first response byte */
  1038. SDO->CANtxBuff->data[0] = 0x00 | (SDO->sequence ? 0x10 : 0x00) | ((7-len)<<1);
  1039. SDO->sequence = (SDO->sequence) ? 0 : 1;
  1040. /* verify end of transfer */
  1041. if ((SDO->bufferOffset == SDO->ODF_arg.dataLength) && (SDO->ODF_arg.lastSegment)){
  1042. SDO->CANtxBuff->data[0] |= 0x01;
  1043. /* finish the communication and run mainline processing again */
  1044. SDO->state = CO_SDO_ST_IDLE;
  1045. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  1046. if (timerNext_us != NULL)
  1047. *timerNext_us = 0;
  1048. #endif
  1049. }
  1050. /* send response */
  1051. sendResponse = true;
  1052. break;
  1053. }
  1054. case CO_SDO_ST_UPLOAD_BL_INITIATE:{
  1055. /* default response */
  1056. SDO->CANtxBuff->data[1] = CANrxData[1];
  1057. SDO->CANtxBuff->data[2] = CANrxData[2];
  1058. SDO->CANtxBuff->data[3] = CANrxData[3];
  1059. /* calculate CRC, if enabled */
  1060. if ((CANrxData[0] & 0x04U) != 0U){
  1061. SDO->crcEnabled = true;
  1062. SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->ODF_arg.dataLength, 0);
  1063. }
  1064. else{
  1065. SDO->crcEnabled = false;
  1066. SDO->crc = 0;
  1067. }
  1068. /* Number of segments per block */
  1069. SDO->blksize = CANrxData[4];
  1070. /* verify client subcommand */
  1071. if ((CANrxData[0]&0x03U) != 0x00U){
  1072. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  1073. return -1;
  1074. }
  1075. /* verify blksize and if SDO data buffer is large enough */
  1076. if ((SDO->blksize < 1U) || (SDO->blksize > 127U) ||
  1077. (((SDO->blksize*7U) > SDO->ODF_arg.dataLength) && (!SDO->ODF_arg.lastSegment))){
  1078. CO_SDO_abort(SDO, CO_SDO_AB_BLOCK_SIZE); /* Invalid block size (block mode only). */
  1079. return -1;
  1080. }
  1081. /* indicate data size, if known */
  1082. if (SDO->ODF_arg.dataLengthTotal != 0U){
  1083. uint32_t dlentot = SDO->ODF_arg.dataLengthTotal;
  1084. CO_memcpySwap4(&SDO->CANtxBuff->data[4], &dlentot);
  1085. SDO->CANtxBuff->data[0] = 0xC6U;
  1086. }
  1087. else{
  1088. SDO->CANtxBuff->data[0] = 0xC4U;
  1089. }
  1090. /* send response */
  1091. SDO->state = CO_SDO_ST_UPLOAD_BL_INITIATE_2;
  1092. sendResponse = true;
  1093. break;
  1094. }
  1095. case CO_SDO_ST_UPLOAD_BL_INITIATE_2:{
  1096. /* verify client command specifier and subcommand */
  1097. if ((CANrxData[0]&0xE3U) != 0xA3U){
  1098. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  1099. return -1;
  1100. }
  1101. SDO->bufferOffset = 0U;
  1102. SDO->sequence = 0U;
  1103. SDO->endOfTransfer = false;
  1104. CO_SDO_process_done(SDO, timerNext_us);
  1105. isNew = false;
  1106. SDO->state = CO_SDO_ST_UPLOAD_BL_SUBBLOCK;
  1107. /* continue in next case */
  1108. }
  1109. // fallthrough
  1110. case CO_SDO_ST_UPLOAD_BL_SUBBLOCK:{
  1111. /* is block confirmation received */
  1112. if (isNew){
  1113. uint8_t ackseq;
  1114. uint16_t j;
  1115. /* verify client command specifier and subcommand */
  1116. if ((CANrxData[0]&0xE3U) != 0xA2U){
  1117. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  1118. return -1;
  1119. }
  1120. ackseq = CANrxData[1]; /* sequence number of the last segment, that was received correctly. */
  1121. /* verify if response is too early */
  1122. if (ackseq > SDO->sequence){
  1123. CO_SDO_abort(SDO, CO_SDO_AB_SEQ_NUM); /* Invalid sequence */
  1124. return -1;
  1125. }
  1126. /* end of transfer */
  1127. if ((SDO->endOfTransfer) && (ackseq == SDO->blksize)){
  1128. /* first response byte */
  1129. SDO->CANtxBuff->data[0] = 0xC1 | ((7 - SDO->lastLen) << 2);
  1130. /* CRC */
  1131. if (SDO->crcEnabled)
  1132. CO_memcpySwap2(&SDO->CANtxBuff->data[1], &SDO->crc);
  1133. SDO->state = CO_SDO_ST_UPLOAD_BL_END;
  1134. /* send response */
  1135. sendResponse = true;
  1136. break;
  1137. }
  1138. /* move remaining data to the beginning */
  1139. for(i=ackseq*7, j=0; i<SDO->ODF_arg.dataLength; i++, j++)
  1140. SDO->ODF_arg.data[j] = SDO->ODF_arg.data[i];
  1141. /* set remaining data length in buffer */
  1142. SDO->ODF_arg.dataLength -= ackseq * 7U;
  1143. /* new block size */
  1144. SDO->blksize = CANrxData[2];
  1145. /* If data type is domain, re-fill the data buffer if necessary and indicated so. */
  1146. if ((SDO->ODF_arg.ODdataStorage == 0) && (SDO->ODF_arg.dataLength < (SDO->blksize*7U)) && (!SDO->ODF_arg.lastSegment)){
  1147. /* move the beginning of the data buffer */
  1148. len = SDO->ODF_arg.dataLength; /* length of valid data in buffer */
  1149. SDO->ODF_arg.data += len;
  1150. SDO->ODF_arg.dataLength = CO_OD_getLength(SDO, SDO->entryNo, SDO->ODF_arg.subIndex) - len;
  1151. /* read next data from Object dictionary function */
  1152. abortCode = CO_SDO_readOD(SDO, CO_CONFIG_SDO_BUFFER_SIZE);
  1153. if (abortCode != 0U){
  1154. CO_SDO_abort(SDO, abortCode);
  1155. return -1;
  1156. }
  1157. /* calculate CRC on next bytes, if enabled */
  1158. if (SDO->crcEnabled){
  1159. SDO->crc = crc16_ccitt(SDO->ODF_arg.data, SDO->ODF_arg.dataLength, SDO->crc);
  1160. }
  1161. /* return to the original data buffer */
  1162. SDO->ODF_arg.data -= len;
  1163. SDO->ODF_arg.dataLength += len;
  1164. }
  1165. /* verify if SDO data buffer is large enough */
  1166. if (((SDO->blksize*7U) > SDO->ODF_arg.dataLength) && (!SDO->ODF_arg.lastSegment)){
  1167. CO_SDO_abort(SDO, CO_SDO_AB_BLOCK_SIZE); /* Invalid block size (block mode only). */
  1168. return -1;
  1169. }
  1170. SDO->bufferOffset = 0U;
  1171. SDO->sequence = 0U;
  1172. SDO->endOfTransfer = false;
  1173. }
  1174. /* return, if all segments was already transfered or on end of transfer */
  1175. if ((SDO->sequence == SDO->blksize) || (SDO->endOfTransfer)){
  1176. break;
  1177. }
  1178. /* reset timeout */
  1179. SDO->timeoutTimer = 0;
  1180. /* calculate length to be sent */
  1181. len = SDO->ODF_arg.dataLength - SDO->bufferOffset;
  1182. if (len > 7U){
  1183. len = 7U;
  1184. }
  1185. /* fill response data bytes */
  1186. for(i=0U; i<len; i++){
  1187. SDO->CANtxBuff->data[i+1] = SDO->ODF_arg.data[SDO->bufferOffset++];
  1188. }
  1189. /* first response byte */
  1190. SDO->CANtxBuff->data[0] = ++SDO->sequence;
  1191. /* verify end of transfer */
  1192. if ((SDO->bufferOffset == SDO->ODF_arg.dataLength) && (SDO->ODF_arg.lastSegment)){
  1193. SDO->CANtxBuff->data[0] |= 0x80;
  1194. SDO->lastLen = len;
  1195. SDO->blksize = SDO->sequence;
  1196. SDO->endOfTransfer = true;
  1197. }
  1198. /* send response */
  1199. sendResponse = true;
  1200. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  1201. /* Inform OS to call this function again without delay. */
  1202. if (timerNext_us != NULL) {
  1203. *timerNext_us = 0;
  1204. }
  1205. #endif
  1206. break;
  1207. }
  1208. case CO_SDO_ST_UPLOAD_BL_END:{
  1209. /* verify client command specifier */
  1210. if ((CANrxData[0]&0xE1U) != 0xA1U){
  1211. CO_SDO_abort(SDO, CO_SDO_AB_CMD);/* Client command specifier not valid or unknown. */
  1212. return -1;
  1213. }
  1214. /* finish the communication and run mainline processing again */
  1215. SDO->state = CO_SDO_ST_IDLE;
  1216. #if (CO_CONFIG_SDO) & CO_CONFIG_FLAG_TIMERNEXT
  1217. if (timerNext_us != NULL)
  1218. *timerNext_us = 0;
  1219. #endif
  1220. break;
  1221. }
  1222. case CO_SDO_ST_IDLE:
  1223. {
  1224. /* Nothing to do, this never happens. */
  1225. break;
  1226. }
  1227. default:{
  1228. CO_SDO_abort(SDO, CO_SDO_AB_DEVICE_INCOMPAT);/* general internal incompatibility in the device */
  1229. return -1;
  1230. }
  1231. }
  1232. /* free receive buffer if it is not empty */
  1233. CO_SDO_process_done(SDO, timerNext_us);
  1234. /* send message */
  1235. if (sendResponse) {
  1236. CO_CANsend(SDO->CANdevTx, SDO->CANtxBuff);
  1237. }
  1238. if (SDO->state != CO_SDO_ST_IDLE){
  1239. return 1;
  1240. }
  1241. return 0;
  1242. }