CO_SRDO.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /**
  2. * CANopen Safety Related Data Object protocol.
  3. *
  4. * @file CO_SRDO.c
  5. * @ingroup CO_SRDO
  6. * @author Robert Grüning
  7. * @copyright 2020 - 2020 Robert Grüning
  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 "304/CO_SRDO.h"
  26. #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE
  27. #include "301/crc16-ccitt.h"
  28. /* verify configuration */
  29. #if !((CO_CONFIG_CRC16) & CO_CONFIG_CRC16_ENABLE)
  30. #error CO_CONFIG_CRC16_ENABLE must be enabled.
  31. #endif
  32. #define CO_SRDO_INVALID (0U)
  33. #define CO_SRDO_TX (1U)
  34. #define CO_SRDO_RX (2U)
  35. #define CO_SRDO_VALID_MAGIC (0xA5)
  36. static void CO_SRDO_receive_normal(void *object, void *msg){
  37. CO_SRDO_t *SRDO;
  38. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  39. uint8_t *data = CO_CANrxMsg_readData(msg);
  40. SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */
  41. if ( (SRDO->valid == CO_SRDO_RX) &&
  42. (DLC >= SRDO->dataLength) && !CO_FLAG_READ(SRDO->CANrxNew[1]))
  43. {
  44. /* copy data into appropriate buffer and set 'new message' flag */
  45. memcpy(SRDO->CANrxData[0], data, sizeof(SRDO->CANrxData[0]));
  46. CO_FLAG_SET(SRDO->CANrxNew[0]);
  47. #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  48. /* Optional signal to RTOS, which can resume task, which handles SRDO. */
  49. if (SRDO->pFunctSignalPre != NULL) {
  50. SRDO->pFunctSignalPre(SRDO->functSignalObjectPre);
  51. }
  52. #endif
  53. }
  54. }
  55. static void CO_SRDO_receive_inverted(void *object, void *msg){
  56. CO_SRDO_t *SRDO;
  57. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  58. uint8_t *data = CO_CANrxMsg_readData(msg);
  59. SRDO = (CO_SRDO_t*)object; /* this is the correct pointer type of the first argument */
  60. if ( (SRDO->valid == CO_SRDO_RX) &&
  61. (DLC >= SRDO->dataLength) && CO_FLAG_READ(SRDO->CANrxNew[0]))
  62. {
  63. /* copy data into appropriate buffer and set 'new message' flag */
  64. memcpy(SRDO->CANrxData[1], data, sizeof(SRDO->CANrxData[1]));
  65. CO_FLAG_SET(SRDO->CANrxNew[1]);
  66. #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  67. /* Optional signal to RTOS, which can resume task, which handles SRDO. */
  68. if (SRDO->pFunctSignalPre != NULL) {
  69. SRDO->pFunctSignalPre(SRDO->functSignalObjectPre);
  70. }
  71. #endif
  72. }
  73. }
  74. static void CO_SRDOconfigCom(CO_SRDO_t* SRDO, uint32_t COB_IDnormal, uint32_t COB_IDinverted){
  75. uint16_t IDs[2][2] = {0};
  76. uint16_t* ID;
  77. uint16_t successCount = 0;
  78. int16_t i;
  79. uint32_t COB_ID[2];
  80. COB_ID[0] = COB_IDnormal;
  81. COB_ID[1] = COB_IDinverted;
  82. SRDO->valid = CO_SRDO_INVALID;
  83. /* is SRDO used? */
  84. if (*SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC && (SRDO->SRDOCommPar->informationDirection == CO_SRDO_TX || SRDO->SRDOCommPar->informationDirection == CO_SRDO_RX) &&
  85. SRDO->dataLength){
  86. ID = &IDs[SRDO->SRDOCommPar->informationDirection - 1][0];
  87. /* is used default COB-ID? */
  88. for(i = 0; i < 2; i++){
  89. if (!(COB_ID[i] & 0xBFFFF800L)){
  90. ID[i] = (uint16_t)COB_ID[i] & 0x7FF;
  91. if (ID[i] == SRDO->defaultCOB_ID[i] && SRDO->nodeId <= 64){
  92. ID[i] += 2*SRDO->nodeId;
  93. }
  94. if (0x101 <= ID[i] && ID[i] <= 0x180 && ((ID[i] & 1) != i )){
  95. successCount++;
  96. }
  97. }
  98. }
  99. }
  100. /* all ids are ok*/
  101. if (successCount == 2){
  102. SRDO->valid = SRDO->SRDOCommPar->informationDirection;
  103. if (SRDO->valid == CO_SRDO_TX){
  104. SRDO->timer = 500 * SRDO->nodeId; /* 0.5ms * node-ID delay*/
  105. }
  106. else if (SRDO->valid == CO_SRDO_RX){
  107. SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U;
  108. }
  109. }
  110. else{
  111. memset(IDs, 0, sizeof(IDs));
  112. CO_FLAG_CLEAR(SRDO->CANrxNew[0]);
  113. CO_FLAG_CLEAR(SRDO->CANrxNew[1]);
  114. SRDO->valid = CO_SRDO_INVALID;
  115. }
  116. for(i = 0; i < 2; i++){
  117. CO_ReturnError_t r;
  118. SRDO->CANtxBuff[i] = CO_CANtxBufferInit(
  119. SRDO->CANdevTx, /* CAN device */
  120. SRDO->CANdevTxIdx[i], /* index of specific buffer inside CAN module */
  121. IDs[0][i], /* CAN identifier */
  122. 0, /* rtr */
  123. SRDO->dataLength, /* number of data bytes */
  124. 0); /* synchronous message flag bit */
  125. if (SRDO->CANtxBuff[i] == 0){
  126. SRDO->valid = CO_SRDO_INVALID;
  127. }
  128. r = CO_CANrxBufferInit(
  129. SRDO->CANdevRx, /* CAN device */
  130. SRDO->CANdevRxIdx[i], /* rx buffer index */
  131. IDs[1][i], /* CAN identifier */
  132. 0x7FF, /* mask */
  133. 0, /* rtr */
  134. (void*)SRDO, /* object passed to receive function */
  135. i ? CO_SRDO_receive_inverted : CO_SRDO_receive_normal); /* this function will process received message */
  136. if (r != CO_ERROR_NO){
  137. SRDO->valid = CO_SRDO_INVALID;
  138. CO_FLAG_CLEAR(SRDO->CANrxNew[i]);
  139. }
  140. }
  141. }
  142. static uint32_t CO_SRDOfindMap(
  143. CO_SDO_t *SDO,
  144. uint32_t map,
  145. uint8_t R_T,
  146. uint8_t **ppData,
  147. uint8_t *pLength,
  148. uint8_t *pSendIfCOSFlags,
  149. uint8_t *pIsMultibyteVar)
  150. {
  151. uint16_t entryNo;
  152. uint16_t index;
  153. uint8_t subIndex;
  154. uint8_t dataLen;
  155. uint8_t objectLen;
  156. uint8_t attr;
  157. index = (uint16_t)(map>>16);
  158. subIndex = (uint8_t)(map>>8);
  159. dataLen = (uint8_t) map; /* data length in bits */
  160. /* data length must be byte aligned */
  161. if (dataLen&0x07) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  162. dataLen >>= 3; /* new data length is in bytes */
  163. *pLength += dataLen;
  164. /* total PDO length can not be more than 8 bytes */
  165. if (*pLength > 8) return CO_SDO_AB_MAP_LEN; /* The number and length of the objects to be mapped would exceed PDO length. */
  166. /* is there a reference to dummy entries */
  167. if (index <=7 && subIndex == 0){
  168. static uint32_t dummyTX = 0;
  169. static uint32_t dummyRX;
  170. uint8_t dummySize = 4;
  171. if (index<2) dummySize = 0;
  172. else if (index==2 || index==5) dummySize = 1;
  173. else if (index==3 || index==6) dummySize = 2;
  174. /* is size of variable big enough for map */
  175. if (dummySize < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  176. /* Data and ODE pointer */
  177. if (R_T == 0) *ppData = (uint8_t*) &dummyRX;
  178. else *ppData = (uint8_t*) &dummyTX;
  179. return 0;
  180. }
  181. /* find object in Object Dictionary */
  182. entryNo = CO_OD_find(SDO, index);
  183. /* Does object exist in OD? */
  184. if (entryNo == 0xFFFF || subIndex > SDO->OD[entryNo].maxSubIndex)
  185. return CO_SDO_AB_NOT_EXIST; /* Object does not exist in the object dictionary. */
  186. attr = CO_OD_getAttribute(SDO, entryNo, subIndex);
  187. /* Is object Mappable for RPDO? */
  188. if (R_T==0 && !((attr&CO_ODA_RPDO_MAPABLE) && (attr&CO_ODA_WRITEABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  189. /* Is object Mappable for TPDO? */
  190. if (R_T!=0 && !((attr&CO_ODA_TPDO_MAPABLE) && (attr&CO_ODA_READABLE))) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  191. /* is size of variable big enough for map */
  192. objectLen = CO_OD_getLength(SDO, entryNo, subIndex);
  193. if (objectLen < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  194. /* mark multibyte variable */
  195. *pIsMultibyteVar = (attr&CO_ODA_MB_VALUE) ? 1 : 0;
  196. /* pointer to data */
  197. *ppData = (uint8_t*) CO_OD_getDataPointer(SDO, entryNo, subIndex);
  198. #ifdef CO_BIG_ENDIAN
  199. /* skip unused MSB bytes */
  200. if (*pIsMultibyteVar){
  201. *ppData += objectLen - dataLen;
  202. }
  203. #endif
  204. /* setup change of state flags */
  205. if (attr&CO_ODA_TPDO_DETECT_COS){
  206. int16_t i;
  207. for(i=*pLength-dataLen; i<*pLength; i++){
  208. *pSendIfCOSFlags |= 1<<i;
  209. }
  210. }
  211. return 0;
  212. }
  213. static uint32_t CO_SRDOconfigMap(CO_SRDO_t* SRDO, uint8_t noOfMappedObjects){
  214. int16_t i;
  215. uint8_t lengths[2] = {0};
  216. uint32_t ret = 0;
  217. const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0];
  218. for(i=noOfMappedObjects; i>0; i--){
  219. int16_t j;
  220. uint8_t* pData;
  221. uint8_t dummy = 0;
  222. uint8_t* length = &lengths[i%2];
  223. uint8_t** mapPointer = SRDO->mapPointer[i%2];
  224. uint8_t prevLength = *length;
  225. uint8_t MBvar;
  226. uint32_t map = *(pMap++);
  227. /* function do much checking of errors in map */
  228. ret = CO_SRDOfindMap(
  229. SRDO->SDO,
  230. map,
  231. SRDO->SRDOCommPar->informationDirection == CO_SRDO_TX,
  232. &pData,
  233. length,
  234. &dummy,
  235. &MBvar);
  236. if (ret){
  237. *length = 0;
  238. CO_errorReport(SRDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, map);
  239. break;
  240. }
  241. /* write SRDO data pointers */
  242. #ifdef CO_BIG_ENDIAN
  243. if (MBvar){
  244. for(j=*length-1; j>=prevLength; j--)
  245. mapPointer[j] = pData++;
  246. }
  247. else{
  248. for(j=prevLength; j<*length; j++)
  249. mapPointer[j] = pData++;
  250. }
  251. #else
  252. for(j=prevLength; j<*length; j++){
  253. mapPointer[j] = pData++;
  254. }
  255. #endif
  256. }
  257. if (lengths[0] == lengths[1])
  258. SRDO->dataLength = lengths[0];
  259. else{
  260. SRDO->dataLength = 0;
  261. CO_errorReport(SRDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, 0);
  262. ret = CO_SDO_AB_MAP_LEN;
  263. }
  264. return ret;
  265. }
  266. static uint16_t CO_SRDOcalcCrc(const CO_SRDO_t *SRDO){
  267. uint16_t i;
  268. uint16_t result = 0x0000;
  269. uint8_t buffer[4];
  270. uint32_t cob;
  271. const CO_SRDOCommPar_t *com = SRDO->SRDOCommPar;
  272. const CO_SRDOMapPar_t *map = SRDO->SRDOMapPar;
  273. result = crc16_ccitt(&com->informationDirection, 1, result);
  274. CO_memcpySwap2(&buffer[0], &com->safetyCycleTime);
  275. result = crc16_ccitt(&buffer[0], 2, result);
  276. result = crc16_ccitt(&com->safetyRelatedValidationTime, 1, result);
  277. /* adjust COB-ID if the default is used
  278. Caution: if the node id changes and you are using the default COB-ID you have to recalculate the checksum
  279. This behaviour is controversial and could be changed or made optional.
  280. */
  281. cob = com->COB_ID1_normal;
  282. if (((cob)&0x7FF) == SRDO->defaultCOB_ID[0] && SRDO->nodeId <= 64)
  283. cob += SRDO->nodeId;
  284. CO_memcpySwap4(&buffer[0], &cob);
  285. result = crc16_ccitt(&buffer[0], 4, result);
  286. cob = com->COB_ID2_inverted;
  287. if (((cob)&0x7FF) == SRDO->defaultCOB_ID[1] && SRDO->nodeId <= 64)
  288. cob += SRDO->nodeId;
  289. CO_memcpySwap4(&buffer[0], &cob);
  290. result = crc16_ccitt(&buffer[0], 4, result);
  291. result = crc16_ccitt(&map->numberOfMappedObjects, 1, result);
  292. for(i = 0; i < map->numberOfMappedObjects;){
  293. uint8_t subindex = i + 1;
  294. result = crc16_ccitt(&subindex, 1, result);
  295. CO_memcpySwap4(&buffer[0], &map->mappedObjects[i]);
  296. result = crc16_ccitt(&buffer[0], 4, result);
  297. i = subindex;
  298. }
  299. return result;
  300. }
  301. static CO_SDO_abortCode_t CO_ODF_SRDOcom(CO_ODF_arg_t *ODF_arg){
  302. CO_SRDO_t *SRDO;
  303. SRDO = (CO_SRDO_t*) ODF_arg->object;
  304. /* Reading Object Dictionary variable */
  305. if (ODF_arg->reading){
  306. if (ODF_arg->subIndex == 5 || ODF_arg->subIndex == 6){
  307. uint32_t value = CO_getUint32(ODF_arg->data);
  308. uint16_t index = ODF_arg->subIndex - 5;
  309. /* if default COB ID is used, write default value here */
  310. if (((value)&0x7FF) == SRDO->defaultCOB_ID[index] && SRDO->nodeId <= 64)
  311. value += SRDO->nodeId;
  312. /* If SRDO is not valid, set bit 31. but I do not think this applies to SRDO ?! */
  313. /* if (!SRDO->valid) value |= 0x80000000L; */
  314. CO_setUint32(ODF_arg->data, value);
  315. }
  316. return CO_SDO_AB_NONE;
  317. }
  318. /* Writing Object Dictionary variable */
  319. if (*SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL)
  320. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  321. if (ODF_arg->subIndex == 1){
  322. uint8_t value = ODF_arg->data[0];
  323. if (value > 2)
  324. return CO_SDO_AB_INVALID_VALUE;
  325. }
  326. else if (ODF_arg->subIndex == 2){
  327. uint16_t value = CO_getUint16(ODF_arg->data);
  328. if (value == 0)
  329. return CO_SDO_AB_INVALID_VALUE;
  330. }
  331. else if (ODF_arg->subIndex == 3){
  332. uint8_t value = ODF_arg->data[0];
  333. if (value == 0)
  334. return CO_SDO_AB_INVALID_VALUE;
  335. }
  336. else if (ODF_arg->subIndex == 4){ /* Transmission_type */
  337. uint8_t *value = (uint8_t*) ODF_arg->data;
  338. if (*value != 254)
  339. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  340. }
  341. else if (ODF_arg->subIndex == 5 || ODF_arg->subIndex == 6){ /* COB_ID */
  342. uint32_t value = CO_getUint32(ODF_arg->data);
  343. uint16_t index = ODF_arg->subIndex - 5;
  344. /* check value range, the spec does not specify if COB-ID flags are allowed */
  345. if (value < 0x101 || value > 0x180 || (value & 1) == index)
  346. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  347. /* if default COB-ID is being written, write defaultCOB_ID without nodeId */
  348. if (SRDO->nodeId <= 64 && value == (SRDO->defaultCOB_ID[index] + SRDO->nodeId)){
  349. value = SRDO->defaultCOB_ID[index];
  350. CO_setUint32(ODF_arg->data, value);
  351. }
  352. }
  353. *SRDO->SRDOGuard->configurationValid = CO_SRDO_INVALID;
  354. return CO_SDO_AB_NONE;
  355. }
  356. static CO_SDO_abortCode_t CO_ODF_SRDOmap(CO_ODF_arg_t *ODF_arg){
  357. CO_SRDO_t *SRDO;
  358. SRDO = (CO_SRDO_t*) ODF_arg->object;
  359. if (ODF_arg->reading)
  360. return CO_SDO_AB_NONE;
  361. /* Writing Object Dictionary variable */
  362. if (*SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL)
  363. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  364. if (SRDO->SRDOCommPar->informationDirection) /* SRDO must be deleted */
  365. return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */
  366. /* numberOfMappedObjects */
  367. if (ODF_arg->subIndex == 0){
  368. uint8_t *value = (uint8_t*) ODF_arg->data;
  369. if (*value > 16 || *value & 1) /*only odd numbers are allowed*/
  370. return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds SRDO length. */
  371. }
  372. else{
  373. if (SRDO->SRDOMapPar->numberOfMappedObjects != 0)
  374. return CO_SDO_AB_UNSUPPORTED_ACCESS;
  375. }
  376. *SRDO->SRDOGuard->configurationValid = CO_SRDO_INVALID;
  377. return CO_SDO_AB_NONE;
  378. }
  379. static CO_SDO_abortCode_t CO_ODF_SRDOcrc(CO_ODF_arg_t *ODF_arg){
  380. CO_SRDOGuard_t *SRDOGuard;
  381. SRDOGuard = (CO_SRDOGuard_t*) ODF_arg->object;
  382. if (!ODF_arg->reading){
  383. if (*SRDOGuard->operatingState == CO_NMT_OPERATIONAL)
  384. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  385. *SRDOGuard->configurationValid = CO_SRDO_INVALID;
  386. }
  387. return CO_SDO_AB_NONE;
  388. }
  389. static CO_SDO_abortCode_t CO_ODF_SRDOvalid(CO_ODF_arg_t *ODF_arg){
  390. CO_SRDOGuard_t *SRDOGuard;
  391. SRDOGuard = (CO_SRDOGuard_t*) ODF_arg->object;
  392. if (!ODF_arg->reading){
  393. if (*SRDOGuard->operatingState == CO_NMT_OPERATIONAL)
  394. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  395. SRDOGuard->checkCRC = ODF_arg->data[0] == CO_SRDO_VALID_MAGIC;
  396. }
  397. return CO_SDO_AB_NONE;
  398. }
  399. CO_ReturnError_t CO_SRDOGuard_init(
  400. CO_SRDOGuard_t *SRDOGuard,
  401. CO_SDO_t *SDO,
  402. CO_NMT_internalState_t *operatingState,
  403. uint8_t *configurationValid,
  404. uint16_t idx_SRDOvalid,
  405. uint16_t idx_SRDOcrc)
  406. {
  407. /* verify arguments */
  408. if (SRDOGuard==NULL || SDO==NULL || operatingState==NULL || configurationValid==NULL){
  409. return CO_ERROR_ILLEGAL_ARGUMENT;
  410. }
  411. SRDOGuard->operatingState = operatingState;
  412. SRDOGuard->operatingStatePrev = CO_NMT_INITIALIZING;
  413. SRDOGuard->configurationValid = configurationValid;
  414. SRDOGuard->checkCRC = *configurationValid == CO_SRDO_VALID_MAGIC;
  415. /* Configure Object dictionary entry at index 0x13FE and 0x13FF */
  416. CO_OD_configure(SDO, idx_SRDOvalid, CO_ODF_SRDOvalid, (void*)SRDOGuard, 0, 0);
  417. CO_OD_configure(SDO, idx_SRDOcrc, CO_ODF_SRDOcrc, (void*)SRDOGuard, 0, 0);
  418. return CO_ERROR_NO;
  419. }
  420. uint8_t CO_SRDOGuard_process(
  421. CO_SRDOGuard_t *SRDOGuard)
  422. {
  423. uint8_t result = 0;
  424. CO_NMT_internalState_t operatingState = *SRDOGuard->operatingState;
  425. if (operatingState != SRDOGuard->operatingStatePrev){
  426. SRDOGuard->operatingStatePrev = operatingState;
  427. if (operatingState == CO_NMT_OPERATIONAL)
  428. result |= 1 << 0;
  429. }
  430. if (SRDOGuard->checkCRC){
  431. result |= 1 << 1;
  432. SRDOGuard->checkCRC = 0;
  433. }
  434. return result;
  435. }
  436. #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  437. /******************************************************************************/
  438. void CO_SRDO_initCallbackPre(
  439. CO_SRDO_t *SRDO,
  440. void *object,
  441. void (*pFunctSignalPre)(void *object))
  442. {
  443. if (SRDO != NULL){
  444. SRDO->functSignalObjectPre = object;
  445. SRDO->pFunctSignalPre = pFunctSignalPre;
  446. }
  447. }
  448. #endif
  449. /******************************************************************************/
  450. void CO_SRDO_initCallbackEnterSafeState(
  451. CO_SRDO_t *SRDO,
  452. void *object,
  453. void (*pFunctSignalSafe)(void *object))
  454. {
  455. if (SRDO != NULL){
  456. SRDO->functSignalObjectSafe = object;
  457. SRDO->pFunctSignalSafe = pFunctSignalSafe;
  458. }
  459. }
  460. CO_ReturnError_t CO_SRDO_init(
  461. CO_SRDO_t *SRDO,
  462. CO_SRDOGuard_t *SRDOGuard,
  463. CO_EM_t *em,
  464. CO_SDO_t *SDO,
  465. uint8_t nodeId,
  466. uint16_t defaultCOB_ID,
  467. const CO_SRDOCommPar_t *SRDOCommPar,
  468. const CO_SRDOMapPar_t *SRDOMapPar,
  469. const uint16_t *checksum,
  470. uint16_t idx_SRDOCommPar,
  471. uint16_t idx_SRDOMapPar,
  472. CO_CANmodule_t *CANdevRx,
  473. uint16_t CANdevRxIdxNormal,
  474. uint16_t CANdevRxIdxInverted,
  475. CO_CANmodule_t *CANdevTx,
  476. uint16_t CANdevTxIdxNormal,
  477. uint16_t CANdevTxIdxInverted)
  478. {
  479. /* verify arguments */
  480. if (SRDO==NULL || SRDOGuard==NULL || em==NULL || SDO==NULL || checksum==NULL ||
  481. SRDOCommPar==NULL || SRDOMapPar==NULL || CANdevRx==NULL || CANdevTx==NULL){
  482. return CO_ERROR_ILLEGAL_ARGUMENT;
  483. }
  484. SRDO->SRDOGuard = SRDOGuard;
  485. SRDO->em = em;
  486. SRDO->SDO = SDO;
  487. SRDO->SRDOCommPar = SRDOCommPar;
  488. SRDO->SRDOMapPar = SRDOMapPar;
  489. SRDO->checksum = checksum;
  490. SRDO->CANdevRx = CANdevRx;
  491. SRDO->CANdevRxIdx[0] = CANdevRxIdxNormal;
  492. SRDO->CANdevRxIdx[1] = CANdevRxIdxInverted;
  493. SRDO->CANdevTx = CANdevTx;
  494. SRDO->CANdevTxIdx[0] = CANdevTxIdxNormal;
  495. SRDO->CANdevTxIdx[1] = CANdevTxIdxInverted;
  496. SRDO->nodeId = nodeId;
  497. SRDO->defaultCOB_ID[0] = defaultCOB_ID;
  498. SRDO->defaultCOB_ID[1] = defaultCOB_ID + 1;
  499. SRDO->valid = CO_SRDO_INVALID;
  500. SRDO->toogle = 0;
  501. SRDO->timer = 0;
  502. SRDO->pFunctSignalSafe = NULL;
  503. SRDO->functSignalObjectSafe = NULL;
  504. #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  505. SRDO->pFunctSignalPre = NULL;
  506. SRDO->functSignalObjectPre = NULL;
  507. #endif
  508. /* Configure Object dictionary entry at index 0x1301+ and 0x1381+ */
  509. CO_OD_configure(SDO, idx_SRDOCommPar, CO_ODF_SRDOcom, (void*)SRDO, 0, 0);
  510. CO_OD_configure(SDO, idx_SRDOMapPar, CO_ODF_SRDOmap, (void*)SRDO, 0, 0);
  511. return CO_ERROR_NO;
  512. }
  513. CO_ReturnError_t CO_SRDO_requestSend(
  514. CO_SRDO_t *SRDO)
  515. {
  516. if (*SRDO->SRDOGuard->operatingState != CO_NMT_OPERATIONAL)
  517. return CO_ERROR_WRONG_NMT_STATE;
  518. if (SRDO->valid != CO_SRDO_TX)
  519. return CO_ERROR_TX_UNCONFIGURED;
  520. if (SRDO->toogle != 0)
  521. return CO_ERROR_TX_BUSY;
  522. SRDO->timer = 0;
  523. return CO_ERROR_NO;
  524. }
  525. void CO_SRDO_process(
  526. CO_SRDO_t *SRDO,
  527. uint8_t commands,
  528. uint32_t timeDifference_us,
  529. uint32_t *timerNext_us)
  530. {
  531. (void)timerNext_us; /* may be unused */
  532. if (commands & (1<<1)){
  533. uint16_t crcValue = CO_SRDOcalcCrc(SRDO);
  534. if (*SRDO->checksum != crcValue)
  535. *SRDO->SRDOGuard->configurationValid = 0;
  536. }
  537. if ((commands & (1<<0)) && *SRDO->SRDOGuard->configurationValid == CO_SRDO_VALID_MAGIC){
  538. if (CO_SRDOconfigMap(SRDO, SRDO->SRDOMapPar->numberOfMappedObjects) == 0){
  539. CO_SRDOconfigCom(SRDO, SRDO->SRDOCommPar->COB_ID1_normal, SRDO->SRDOCommPar->COB_ID2_inverted);
  540. }
  541. else{
  542. SRDO->valid = CO_SRDO_INVALID;
  543. }
  544. }
  545. if (SRDO->valid && *SRDO->SRDOGuard->operatingState == CO_NMT_OPERATIONAL){
  546. SRDO->timer = (SRDO->timer > timeDifference_us) ? (SRDO->timer - timeDifference_us) : 0;
  547. if (SRDO->valid == CO_SRDO_TX){
  548. if (SRDO->timer == 0){
  549. if (SRDO->toogle){
  550. CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[1]);
  551. SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U - CO_CONFIG_SRDO_MINIMUM_DELAY;
  552. }
  553. else{
  554. int16_t i;
  555. uint8_t* pSRDOdataByte_normal;
  556. uint8_t* pSRDOdataByte_inverted;
  557. uint8_t** ppODdataByte_normal;
  558. uint8_t** ppODdataByte_inverted;
  559. bool_t data_ok = true;
  560. #if (CO_CONFIG_SRDO) & CO_CONFIG_TSRDO_CALLS_EXTENSION
  561. if (SRDO->SDO->ODExtensions){
  562. /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */
  563. const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0];
  564. CO_SDO_t *pSDO = SRDO->SDO;
  565. for(i=SRDO->SRDOMapPar->numberOfMappedObjects; i>0; i--){
  566. uint32_t map = *(pMap++);
  567. uint16_t index = (uint16_t)(map>>16);
  568. uint8_t subIndex = (uint8_t)(map>>8);
  569. uint16_t entryNo = CO_OD_find(pSDO, index);
  570. if ( entryNo != 0xFFFF )
  571. {
  572. CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo];
  573. if ( ext->pODFunc != NULL)
  574. {
  575. CO_ODF_arg_t ODF_arg;
  576. memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t));
  577. ODF_arg.reading = true;
  578. ODF_arg.index = index;
  579. ODF_arg.subIndex = subIndex;
  580. ODF_arg.object = ext->object;
  581. ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex);
  582. ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex);
  583. ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); /* https://github.com/CANopenNode/CANopenNode/issues/100 */
  584. ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex);
  585. ext->pODFunc(&ODF_arg);
  586. }
  587. }
  588. }
  589. }
  590. #endif
  591. pSRDOdataByte_normal = &SRDO->CANtxBuff[0]->data[0];
  592. ppODdataByte_normal = &SRDO->mapPointer[0][0];
  593. pSRDOdataByte_inverted = &SRDO->CANtxBuff[1]->data[0];
  594. ppODdataByte_inverted = &SRDO->mapPointer[1][0];
  595. #if (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_CHECK_TX
  596. /* check data before sending (optional) */
  597. for(i = 0; i<SRDO->dataLength; i++){
  598. uint8_t invert = ~*(ppODdataByte_inverted[i]);
  599. if (*(ppODdataByte_normal[i]) != invert)
  600. {
  601. data_ok = false;
  602. break;
  603. }
  604. }
  605. #endif
  606. if (data_ok){
  607. /* Copy data from Object dictionary. */
  608. for(i = 0; i<SRDO->dataLength; i++){
  609. pSRDOdataByte_normal[i] = *(ppODdataByte_normal[i]);
  610. pSRDOdataByte_inverted[i] = *(ppODdataByte_inverted[i]);
  611. }
  612. CO_CANsend(SRDO->CANdevTx, SRDO->CANtxBuff[0]);
  613. SRDO->timer = CO_CONFIG_SRDO_MINIMUM_DELAY;
  614. }
  615. else{
  616. SRDO->toogle = 1;
  617. /* save state */
  618. if (SRDO->pFunctSignalSafe != NULL){
  619. SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe);
  620. }
  621. }
  622. }
  623. SRDO->toogle = !SRDO->toogle;
  624. }
  625. #if (CO_CONFIG_SRDO) & CO_CONFIG_FLAG_TIMERNEXT
  626. if (timerNext_us != NULL){
  627. if (*timerNext_us > SRDO->timer){
  628. *timerNext_us = SRDO->timer; /* Schedule for next message timer */
  629. }
  630. }
  631. #endif
  632. }
  633. else if (SRDO->valid == CO_SRDO_RX){
  634. if (CO_FLAG_READ(SRDO->CANrxNew[SRDO->toogle])){
  635. if (SRDO->toogle){
  636. int16_t i;
  637. uint8_t* pSRDOdataByte_normal;
  638. uint8_t* pSRDOdataByte_inverted;
  639. uint8_t** ppODdataByte_normal;
  640. uint8_t** ppODdataByte_inverted;
  641. bool_t data_ok = true;
  642. pSRDOdataByte_normal = &SRDO->CANrxData[0][0];
  643. pSRDOdataByte_inverted = &SRDO->CANrxData[1][0];
  644. for(i = 0; i<SRDO->dataLength; i++){
  645. uint8_t invert = ~pSRDOdataByte_inverted[i];
  646. if (pSRDOdataByte_normal[i] != invert){
  647. data_ok = false;
  648. break;
  649. }
  650. }
  651. if (data_ok){
  652. ppODdataByte_normal = &SRDO->mapPointer[0][0];
  653. ppODdataByte_inverted = &SRDO->mapPointer[1][0];
  654. /* Copy data to Object dictionary. If between the copy operation CANrxNew
  655. * is set to true by receive thread, then copy the latest data again. */
  656. for(i = 0; i<SRDO->dataLength; i++){
  657. *(ppODdataByte_normal[i]) = pSRDOdataByte_normal[i];
  658. *(ppODdataByte_inverted[i]) = pSRDOdataByte_inverted[i];
  659. }
  660. CO_FLAG_CLEAR(SRDO->CANrxNew[0]);
  661. CO_FLAG_CLEAR(SRDO->CANrxNew[1]);
  662. #if (CO_CONFIG_SRDO) & CO_CONFIG_RSRDO_CALLS_EXTENSION
  663. if (SRDO->SDO->ODExtensions){
  664. int16_t i;
  665. /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */
  666. const uint32_t* pMap = &SRDO->SRDOMapPar->mappedObjects[0];
  667. CO_SDO_t *pSDO = SRDO->SDO;
  668. for(i=SRDO->SRDOMapPar->numberOfMappedObjects; i>0; i--){
  669. uint32_t map = *(pMap++);
  670. uint16_t index = (uint16_t)(map>>16);
  671. uint8_t subIndex = (uint8_t)(map>>8);
  672. uint16_t entryNo = CO_OD_find(pSDO, index);
  673. if ( entryNo != 0xFFFF )
  674. {
  675. CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo];
  676. if ( ext->pODFunc != NULL)
  677. {
  678. CO_ODF_arg_t ODF_arg;
  679. memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t));
  680. ODF_arg.reading = false;
  681. ODF_arg.index = index;
  682. ODF_arg.subIndex = subIndex;
  683. ODF_arg.object = ext->object;
  684. ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex);
  685. ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex);
  686. ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); /* https://github.com/CANopenNode/CANopenNode/issues/100 */
  687. ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex);
  688. ext->pODFunc(&ODF_arg);
  689. }
  690. }
  691. }
  692. }
  693. #endif
  694. }
  695. else{
  696. CO_FLAG_CLEAR(SRDO->CANrxNew[0]);
  697. CO_FLAG_CLEAR(SRDO->CANrxNew[1]);
  698. /* save state */
  699. if (SRDO->pFunctSignalSafe != NULL){
  700. SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe);
  701. }
  702. }
  703. SRDO->timer = SRDO->SRDOCommPar->safetyCycleTime * 1000U;
  704. }
  705. else{
  706. SRDO->timer = SRDO->SRDOCommPar->safetyRelatedValidationTime * 1000U;
  707. }
  708. SRDO->toogle = !SRDO->toogle;
  709. }
  710. if (SRDO->timer == 0){
  711. SRDO->toogle = 0;
  712. SRDO->timer = SRDO->SRDOCommPar->safetyRelatedValidationTime * 1000U;
  713. CO_FLAG_CLEAR(SRDO->CANrxNew[0]);
  714. CO_FLAG_CLEAR(SRDO->CANrxNew[1]);
  715. /* save state */
  716. if (SRDO->pFunctSignalSafe != NULL){
  717. SRDO->pFunctSignalSafe(SRDO->functSignalObjectSafe);
  718. }
  719. }
  720. }
  721. }
  722. else{
  723. SRDO->valid = CO_SRDO_INVALID;
  724. CO_FLAG_CLEAR(SRDO->CANrxNew[0]);
  725. CO_FLAG_CLEAR(SRDO->CANrxNew[1]);
  726. }
  727. }
  728. #endif /* (CO_CONFIG_SRDO) & CO_CONFIG_SRDO_ENABLE */