CO_PDO.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. /*
  2. * CANopen Process Data Object.
  3. *
  4. * @file CO_PDO.c
  5. * @ingroup CO_PDO
  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 <string.h>
  26. #include "301/CO_PDO.h"
  27. /*
  28. * Read received message from CAN module.
  29. *
  30. * Function will be called (by CAN receive interrupt) every time, when CAN
  31. * message with correct identifier will be received. For more information and
  32. * description of parameters see file CO_driver.h.
  33. * If new message arrives and previous message wasn't processed yet, then
  34. * previous message will be lost and overwritten by new message. That's OK with PDOs.
  35. */
  36. static void CO_PDO_receive(void *object, void *msg){
  37. CO_RPDO_t *RPDO;
  38. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  39. uint8_t *data = CO_CANrxMsg_readData(msg);
  40. RPDO = (CO_RPDO_t*)object; /* this is the correct pointer type of the first argument */
  41. if ( (RPDO->valid) &&
  42. (*RPDO->operatingState == CO_NMT_OPERATIONAL) &&
  43. (DLC >= RPDO->dataLength))
  44. {
  45. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  46. const size_t index = RPDO->SYNC && RPDO->synchronous && RPDO->SYNC->CANrxToggle;
  47. #else
  48. const size_t index = 0;
  49. #endif
  50. /* copy data into appropriate buffer and set 'new message' flag */
  51. memcpy(RPDO->CANrxData[index], data, sizeof(RPDO->CANrxData[index]));
  52. CO_FLAG_SET(RPDO->CANrxNew[index]);
  53. #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  54. /* Optional signal to RTOS, which can resume task, which handles RPDO. */
  55. if (RPDO->pFunctSignalPre != NULL) {
  56. RPDO->pFunctSignalPre(RPDO->functSignalObjectPre);
  57. }
  58. #endif
  59. }
  60. }
  61. /*
  62. * Configure RPDO Communication parameter.
  63. *
  64. * Function is called from commuincation reset or when parameter changes.
  65. *
  66. * Function configures following variable from CO_RPDO_t: _valid_. It also
  67. * configures CAN rx buffer. If configuration fails, emergency message is send
  68. * and device is not able to enter NMT operational.
  69. *
  70. * @param RPDO RPDO object.
  71. * @param COB_IDUsedByRPDO _RPDO communication parameter_, _COB-ID for PDO_ variable
  72. * from Object dictionary (index 0x1400+, subindex 1).
  73. */
  74. static void CO_RPDOconfigCom(CO_RPDO_t* RPDO, uint32_t COB_IDUsedByRPDO){
  75. uint16_t ID;
  76. CO_ReturnError_t r;
  77. ID = (uint16_t)COB_IDUsedByRPDO;
  78. /* is RPDO used? */
  79. if ((COB_IDUsedByRPDO & 0xBFFFF800L) == 0 && RPDO->dataLength && ID){
  80. /* is used default COB-ID? */
  81. if (ID == RPDO->defaultCOB_ID) ID += RPDO->nodeId;
  82. RPDO->valid = true;
  83. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  84. RPDO->synchronous = (RPDO->RPDOCommPar->transmissionType <= 240) ? true : false;
  85. #endif
  86. }
  87. else{
  88. ID = 0;
  89. RPDO->valid = false;
  90. CO_FLAG_CLEAR(RPDO->CANrxNew[0]);
  91. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  92. CO_FLAG_CLEAR(RPDO->CANrxNew[1]);
  93. #endif
  94. }
  95. r = CO_CANrxBufferInit(
  96. RPDO->CANdevRx, /* CAN device */
  97. RPDO->CANdevRxIdx, /* rx buffer index */
  98. ID, /* CAN identifier */
  99. 0x7FF, /* mask */
  100. 0, /* rtr */
  101. (void*)RPDO, /* object passed to receive function */
  102. CO_PDO_receive); /* this function will process received message */
  103. if (r != CO_ERROR_NO){
  104. RPDO->valid = false;
  105. CO_FLAG_CLEAR(RPDO->CANrxNew[0]);
  106. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  107. CO_FLAG_CLEAR(RPDO->CANrxNew[1]);
  108. #endif
  109. }
  110. }
  111. /*
  112. * Configure TPDO Communication parameter.
  113. *
  114. * Function is called from commuincation reset or when parameter changes.
  115. *
  116. * Function configures following variable from CO_TPDO_t: _valid_. It also
  117. * configures CAN tx buffer. If configuration fails, emergency message is send
  118. * and device is not able to enter NMT operational.
  119. *
  120. * @param TPDO TPDO object.
  121. * @param COB_IDUsedByTPDO _TPDO communication parameter_, _COB-ID for PDO_ variable
  122. * from Object dictionary (index 0x1400+, subindex 1).
  123. * @param syncFlag Indicate, if TPDO is synchronous.
  124. */
  125. static void CO_TPDOconfigCom(CO_TPDO_t* TPDO, uint32_t COB_IDUsedByTPDO, uint8_t syncFlag){
  126. uint16_t ID;
  127. ID = (uint16_t)COB_IDUsedByTPDO;
  128. /* is TPDO used? */
  129. if ((COB_IDUsedByTPDO & 0xBFFFF800L) == 0 && TPDO->dataLength && ID){
  130. /* is used default COB-ID? */
  131. if (ID == TPDO->defaultCOB_ID) ID += TPDO->nodeId;
  132. TPDO->valid = true;
  133. }
  134. else{
  135. ID = 0;
  136. TPDO->valid = false;
  137. }
  138. TPDO->CANtxBuff = CO_CANtxBufferInit(
  139. TPDO->CANdevTx, /* CAN device */
  140. TPDO->CANdevTxIdx, /* index of specific buffer inside CAN module */
  141. ID, /* CAN identifier */
  142. 0, /* rtr */
  143. TPDO->dataLength, /* number of data bytes */
  144. syncFlag); /* synchronous message flag bit */
  145. if (TPDO->CANtxBuff == 0){
  146. TPDO->valid = false;
  147. }
  148. }
  149. /*
  150. * Find mapped variable in Object Dictionary.
  151. *
  152. * Function is called from CO_R(T)PDOconfigMap or when mapping parameter changes.
  153. *
  154. * @param SDO SDO object.
  155. * @param map PDO mapping parameter.
  156. * @param R_T 0 for RPDO map, 1 for TPDO map.
  157. * @param ppData Pointer to returning parameter: pointer to data of mapped variable.
  158. * @param pLength Pointer to returning parameter: *add* length of mapped variable.
  159. * @param pSendIfCOSFlags Pointer to returning parameter: sendIfCOSFlags variable.
  160. * @param pIsMultibyteVar Pointer to returning parameter: true for multibyte variable.
  161. *
  162. * @return 0 on success, otherwise SDO abort code.
  163. */
  164. static uint32_t CO_PDOfindMap(
  165. CO_SDO_t *SDO,
  166. uint32_t map,
  167. uint8_t R_T,
  168. uint8_t **ppData,
  169. uint8_t *pLength,
  170. uint8_t *pSendIfCOSFlags,
  171. uint8_t *pIsMultibyteVar)
  172. {
  173. uint16_t entryNo;
  174. uint16_t index;
  175. uint8_t subIndex;
  176. uint8_t dataLen;
  177. uint8_t objectLen;
  178. uint8_t attr;
  179. index = (uint16_t)(map>>16);
  180. subIndex = (uint8_t)(map>>8);
  181. dataLen = (uint8_t) map; /* data length in bits */
  182. /* data length must be byte aligned */
  183. if (dataLen&0x07) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  184. dataLen >>= 3; /* new data length is in bytes */
  185. *pLength += dataLen;
  186. /* total PDO length can not be more than 8 bytes */
  187. if (*pLength > 8) return CO_SDO_AB_MAP_LEN; /* The number and length of the objects to be mapped would exceed PDO length. */
  188. /* is there a reference to dummy entries */
  189. if (index <=7 && subIndex == 0){
  190. static uint32_t dummyTX = 0;
  191. static uint32_t dummyRX;
  192. uint8_t dummySize = 4;
  193. if (index<2) dummySize = 0;
  194. else if (index==2 || index==5) dummySize = 1;
  195. else if (index==3 || index==6) dummySize = 2;
  196. /* is size of variable big enough for map */
  197. if (dummySize < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  198. /* Data and ODE pointer */
  199. if (R_T == 0) *ppData = (uint8_t*) &dummyRX;
  200. else *ppData = (uint8_t*) &dummyTX;
  201. return 0;
  202. }
  203. /* find object in Object Dictionary */
  204. entryNo = CO_OD_find(SDO, index);
  205. /* Does object exist in OD? */
  206. if (entryNo == 0xFFFF || subIndex > SDO->OD[entryNo].maxSubIndex)
  207. return CO_SDO_AB_NOT_EXIST; /* Object does not exist in the object dictionary. */
  208. attr = CO_OD_getAttribute(SDO, entryNo, subIndex);
  209. /* Is object Mappable for RPDO? */
  210. 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. */
  211. /* Is object Mappable for TPDO? */
  212. 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. */
  213. /* is size of variable big enough for map */
  214. objectLen = CO_OD_getLength(SDO, entryNo, subIndex);
  215. if (objectLen < dataLen) return CO_SDO_AB_NO_MAP; /* Object cannot be mapped to the PDO. */
  216. /* mark multibyte variable */
  217. *pIsMultibyteVar = (attr&CO_ODA_MB_VALUE) ? 1 : 0;
  218. /* pointer to data */
  219. *ppData = (uint8_t*) CO_OD_getDataPointer(SDO, entryNo, subIndex);
  220. #ifdef CO_BIG_ENDIAN
  221. /* skip unused MSB bytes */
  222. if (*pIsMultibyteVar){
  223. *ppData += objectLen - dataLen;
  224. }
  225. #endif
  226. /* setup change of state flags */
  227. if (attr&CO_ODA_TPDO_DETECT_COS){
  228. int16_t i;
  229. for(i=*pLength-dataLen; i<*pLength; i++){
  230. *pSendIfCOSFlags |= 1<<i;
  231. }
  232. }
  233. return 0;
  234. }
  235. /*
  236. * Configure RPDO Mapping parameter.
  237. *
  238. * Function is called from communication reset or when parameter changes.
  239. *
  240. * Function configures following variables from CO_RPDO_t: _dataLength_ and
  241. * _mapPointer_.
  242. *
  243. * @param RPDO RPDO object.
  244. * @param noOfMappedObjects Number of mapped object (from OD).
  245. *
  246. * @return 0 on success, otherwise SDO abort code.
  247. */
  248. static uint32_t CO_RPDOconfigMap(CO_RPDO_t* RPDO, uint8_t noOfMappedObjects){
  249. int16_t i;
  250. uint8_t length = 0;
  251. uint32_t ret = 0;
  252. const uint32_t* pMap = &RPDO->RPDOMapPar->mappedObject1;
  253. for(i=noOfMappedObjects; i>0; i--){
  254. int16_t j;
  255. uint8_t* pData;
  256. uint8_t dummy = 0;
  257. uint8_t prevLength = length;
  258. uint8_t MBvar;
  259. uint32_t map = *(pMap++);
  260. /* function do much checking of errors in map */
  261. ret = CO_PDOfindMap(
  262. RPDO->SDO,
  263. map,
  264. 0,
  265. &pData,
  266. &length,
  267. &dummy,
  268. &MBvar);
  269. if (ret){
  270. length = 0;
  271. CO_errorReport(RPDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, map);
  272. break;
  273. }
  274. /* write PDO data pointers */
  275. #ifdef CO_BIG_ENDIAN
  276. if (MBvar){
  277. for(j=length-1; j>=prevLength; j--)
  278. RPDO->mapPointer[j] = pData++;
  279. }
  280. else{
  281. for(j=prevLength; j<length; j++)
  282. RPDO->mapPointer[j] = pData++;
  283. }
  284. #else
  285. for(j=prevLength; j<length; j++){
  286. RPDO->mapPointer[j] = pData++;
  287. }
  288. #endif
  289. }
  290. RPDO->dataLength = length;
  291. return ret;
  292. }
  293. uint32_t debug_map =0;
  294. /*
  295. * Configure TPDO Mapping parameter.
  296. *
  297. * Function is called from communication reset or when parameter changes.
  298. *
  299. * Function configures following variables from CO_TPDO_t: _dataLength_,
  300. * _mapPointer_ and _sendIfCOSFlags_.
  301. *
  302. * @param TPDO TPDO object.
  303. * @param noOfMappedObjects Number of mapped object (from OD).
  304. *
  305. * @return 0 on success, otherwise SDO abort code.
  306. */
  307. static uint32_t CO_TPDOconfigMap(CO_TPDO_t* TPDO, uint8_t noOfMappedObjects){
  308. int16_t i;
  309. uint8_t length = 0;
  310. uint32_t ret = 0;
  311. const uint32_t* pMap = &TPDO->TPDOMapPar->mappedObject1;
  312. TPDO->sendIfCOSFlags = 0;
  313. for(i=noOfMappedObjects; i>0; i--){
  314. int16_t j;
  315. uint8_t* pData;
  316. uint8_t prevLength = length;
  317. uint8_t MBvar;
  318. uint32_t map = *(pMap++);
  319. debug_map = map;
  320. /* function do much checking of errors in map */
  321. ret = CO_PDOfindMap(
  322. TPDO->SDO,
  323. map,
  324. 1,
  325. &pData,
  326. &length,
  327. &TPDO->sendIfCOSFlags,
  328. &MBvar);
  329. if (ret){
  330. length = 0;
  331. CO_errorReport(TPDO->em, CO_EM_PDO_WRONG_MAPPING, CO_EMC_PROTOCOL_ERROR, map);
  332. break;
  333. }
  334. /* write PDO data pointers */
  335. #ifdef CO_BIG_ENDIAN
  336. if (MBvar){
  337. for(j=length-1; j>=prevLength; j--)
  338. TPDO->mapPointer[j] = pData++;
  339. }
  340. else{
  341. for(j=prevLength; j<length; j++)
  342. TPDO->mapPointer[j] = pData++;
  343. }
  344. #else
  345. for(j=prevLength; j<length; j++){
  346. TPDO->mapPointer[j] = pData++;
  347. }
  348. #endif
  349. }
  350. TPDO->dataLength = length;
  351. return ret;
  352. }
  353. /*
  354. * Function for accessing _RPDO communication parameter_ (index 0x1400+) from SDO server.
  355. *
  356. * For more information see file CO_SDOserver.h.
  357. */
  358. static CO_SDO_abortCode_t CO_ODF_RPDOcom(CO_ODF_arg_t *ODF_arg){
  359. CO_RPDO_t *RPDO;
  360. RPDO = (CO_RPDO_t*) ODF_arg->object;
  361. /* Reading Object Dictionary variable */
  362. if (ODF_arg->reading){
  363. if (ODF_arg->subIndex == 1){
  364. uint32_t value = CO_getUint32(ODF_arg->data);
  365. /* if default COB ID is used, write default value here */
  366. if (((value)&0xFFFF) == RPDO->defaultCOB_ID && RPDO->defaultCOB_ID)
  367. value += RPDO->nodeId;
  368. /* If PDO is not valid, set bit 31 */
  369. if (!RPDO->valid) value |= 0x80000000L;
  370. CO_setUint32(ODF_arg->data, value);
  371. }
  372. return CO_SDO_AB_NONE;
  373. }
  374. /* Writing Object Dictionary variable */
  375. if (RPDO->restrictionFlags & 0x04)
  376. return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */
  377. if (*RPDO->operatingState == CO_NMT_OPERATIONAL && (RPDO->restrictionFlags & 0x01))
  378. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  379. if (ODF_arg->subIndex == 1){ /* COB_ID */
  380. uint32_t value = CO_getUint32(ODF_arg->data);
  381. /* bits 11...29 must be zero */
  382. if (value & 0x3FFF8000L)
  383. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  384. /* if default COB-ID is being written, write defaultCOB_ID without nodeId */
  385. if (((value)&0xFFFF) == (RPDO->defaultCOB_ID + RPDO->nodeId)){
  386. value &= 0xC0000000L;
  387. value += RPDO->defaultCOB_ID;
  388. CO_setUint32(ODF_arg->data, value);
  389. }
  390. /* if PDO is valid, bits 0..29 can not be changed */
  391. if (RPDO->valid && ((value ^ RPDO->RPDOCommPar->COB_IDUsedByRPDO) & 0x3FFFFFFFL))
  392. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  393. /* configure RPDO */
  394. CO_RPDOconfigCom(RPDO, value);
  395. }
  396. else if (ODF_arg->subIndex == 2){ /* Transmission_type */
  397. uint8_t *value = (uint8_t*) ODF_arg->data;
  398. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  399. bool_t synchronousPrev = RPDO->synchronous;
  400. /* values from 241...253 are not valid */
  401. if (*value >= 241 && *value <= 253)
  402. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  403. RPDO->synchronous = (*value <= 240) ? true : false;
  404. /* Remove old message from second buffer. */
  405. if (RPDO->synchronous != synchronousPrev) {
  406. CO_FLAG_CLEAR(RPDO->CANrxNew[1]);
  407. }
  408. #else
  409. /* values from 0...253 are not valid */
  410. if (*value <= 253)
  411. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  412. #endif
  413. }
  414. return CO_SDO_AB_NONE;
  415. }
  416. /*
  417. * Function for accessing _TPDO communication parameter_ (index 0x1800+) from SDO server.
  418. *
  419. * For more information see file CO_SDOserver.h.
  420. */
  421. static CO_SDO_abortCode_t CO_ODF_TPDOcom(CO_ODF_arg_t *ODF_arg){
  422. CO_TPDO_t *TPDO;
  423. TPDO = (CO_TPDO_t*) ODF_arg->object;
  424. if (ODF_arg->subIndex == 4) return CO_SDO_AB_SUB_UNKNOWN; /* Sub-index does not exist. */
  425. /* Reading Object Dictionary variable */
  426. if (ODF_arg->reading){
  427. if (ODF_arg->subIndex == 1){ /* COB_ID */
  428. uint32_t value = CO_getUint32(ODF_arg->data);
  429. /* if default COB ID is used, write default value here */
  430. if (((value)&0xFFFF) == TPDO->defaultCOB_ID && TPDO->defaultCOB_ID)
  431. value += TPDO->nodeId;
  432. /* If PDO is not valid, set bit 31 */
  433. if (!TPDO->valid) value |= 0x80000000L;
  434. CO_setUint32(ODF_arg->data, value);
  435. }
  436. return CO_SDO_AB_NONE;
  437. }
  438. /* Writing Object Dictionary variable */
  439. if (TPDO->restrictionFlags & 0x04)
  440. return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */
  441. if (*TPDO->operatingState == CO_NMT_OPERATIONAL && (TPDO->restrictionFlags & 0x01))
  442. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  443. if (ODF_arg->subIndex == 1){ /* COB_ID */
  444. uint32_t value = CO_getUint32(ODF_arg->data);
  445. /* bits 11...29 must be zero */
  446. if (value & 0x3FFF8000L)
  447. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  448. /* if default COB-ID is being written, write defaultCOB_ID without nodeId */
  449. if (((value)&0xFFFF) == (TPDO->defaultCOB_ID + TPDO->nodeId)){
  450. value &= 0xC0000000L;
  451. value += TPDO->defaultCOB_ID;
  452. CO_setUint32(ODF_arg->data, value);
  453. }
  454. /* if PDO is valid, bits 0..29 can not be changed */
  455. if (TPDO->valid && ((value ^ TPDO->TPDOCommPar->COB_IDUsedByTPDO) & 0x3FFFFFFFL))
  456. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  457. /* configure TPDO */
  458. CO_TPDOconfigCom(TPDO, value, TPDO->CANtxBuff->syncFlag);
  459. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  460. TPDO->syncCounter = 255;
  461. #endif
  462. }
  463. else if (ODF_arg->subIndex == 2){ /* Transmission_type */
  464. uint8_t *value = (uint8_t*) ODF_arg->data;
  465. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  466. /* values from 241...253 are not valid */
  467. if (*value >= 241 && *value <= 253)
  468. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  469. TPDO->CANtxBuff->syncFlag = (*value <= 240) ? 1 : 0;
  470. TPDO->syncCounter = 255;
  471. #else
  472. /* values from 0...253 are not valid */
  473. if (*value <= 253)
  474. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  475. #endif
  476. }
  477. else if (ODF_arg->subIndex == 3){ /* Inhibit_Time */
  478. /* if PDO is valid, value can not be changed */
  479. if (TPDO->valid)
  480. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  481. TPDO->inhibitTimer = 0;
  482. }
  483. else if (ODF_arg->subIndex == 5){ /* Event_Timer */
  484. uint16_t value = CO_getUint16(ODF_arg->data);
  485. TPDO->eventTimer = ((uint32_t) value) * 1000;
  486. }
  487. else if (ODF_arg->subIndex == 6){ /* SYNC start value */
  488. uint8_t *value = (uint8_t*) ODF_arg->data;
  489. /* if PDO is valid, value can not be changed */
  490. if (TPDO->valid)
  491. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  492. /* values from 240...255 are not valid */
  493. if (*value > 240)
  494. return CO_SDO_AB_INVALID_VALUE; /* Invalid value for parameter (download only). */
  495. }
  496. return CO_SDO_AB_NONE;
  497. }
  498. /*
  499. * Function for accessing _RPDO mapping parameter_ (index 0x1600+) from SDO server.
  500. *
  501. * For more information see file CO_SDOserver.h.
  502. */
  503. static CO_SDO_abortCode_t CO_ODF_RPDOmap(CO_ODF_arg_t *ODF_arg){
  504. CO_RPDO_t *RPDO;
  505. RPDO = (CO_RPDO_t*) ODF_arg->object;
  506. /* Reading Object Dictionary variable */
  507. if (ODF_arg->reading){
  508. uint8_t *value = (uint8_t*) ODF_arg->data;
  509. if (ODF_arg->subIndex == 0){
  510. /* If there is error in mapping, dataLength is 0, so numberOfMappedObjects is 0. */
  511. if (!RPDO->dataLength) *value = 0;
  512. }
  513. return CO_SDO_AB_NONE;
  514. }
  515. /* Writing Object Dictionary variable */
  516. if (RPDO->restrictionFlags & 0x08)
  517. return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */
  518. if (*RPDO->operatingState == CO_NMT_OPERATIONAL && (RPDO->restrictionFlags & 0x02))
  519. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  520. if (RPDO->valid)
  521. return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */
  522. /* numberOfMappedObjects */
  523. if (ODF_arg->subIndex == 0){
  524. uint8_t *value = (uint8_t*) ODF_arg->data;
  525. if (*value > 8)
  526. return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */
  527. /* configure mapping */
  528. return (CO_SDO_abortCode_t) CO_RPDOconfigMap(RPDO, *value);
  529. }
  530. /* mappedObject */
  531. else{
  532. uint32_t value = CO_getUint32(ODF_arg->data);
  533. uint8_t* pData;
  534. uint8_t length = 0;
  535. uint8_t dummy = 0;
  536. uint8_t MBvar;
  537. if (RPDO->dataLength)
  538. return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */
  539. /* verify if mapping is correct */
  540. return (CO_SDO_abortCode_t) CO_PDOfindMap(
  541. RPDO->SDO,
  542. value,
  543. 0,
  544. &pData,
  545. &length,
  546. &dummy,
  547. &MBvar);
  548. }
  549. return CO_SDO_AB_NONE;
  550. }
  551. /*
  552. * Function for accessing _TPDO mapping parameter_ (index 0x1A00+) from SDO server.
  553. *
  554. * For more information see file CO_SDOserver.h.
  555. */
  556. static CO_SDO_abortCode_t CO_ODF_TPDOmap(CO_ODF_arg_t *ODF_arg){
  557. CO_TPDO_t *TPDO;
  558. TPDO = (CO_TPDO_t*) ODF_arg->object;
  559. /* Reading Object Dictionary variable */
  560. if (ODF_arg->reading){
  561. uint8_t *value = (uint8_t*) ODF_arg->data;
  562. if (ODF_arg->subIndex == 0){
  563. /* If there is error in mapping, dataLength is 0, so numberOfMappedObjects is 0. */
  564. if (!TPDO->dataLength) *value = 0;
  565. }
  566. return CO_SDO_AB_NONE;
  567. }
  568. /* Writing Object Dictionary variable */
  569. if (TPDO->restrictionFlags & 0x08)
  570. return CO_SDO_AB_READONLY; /* Attempt to write a read only object. */
  571. if (*TPDO->operatingState == CO_NMT_OPERATIONAL && (TPDO->restrictionFlags & 0x02))
  572. return CO_SDO_AB_DATA_DEV_STATE; /* Data cannot be transferred or stored to the application because of the present device state. */
  573. if (TPDO->valid)
  574. return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */
  575. /* numberOfMappedObjects */
  576. if (ODF_arg->subIndex == 0){
  577. uint8_t *value = (uint8_t*) ODF_arg->data;
  578. if (*value > 8)
  579. return CO_SDO_AB_MAP_LEN; /* Number and length of object to be mapped exceeds PDO length. */
  580. /* configure mapping */
  581. return (CO_SDO_abortCode_t) CO_TPDOconfigMap(TPDO, *value);
  582. }
  583. /* mappedObject */
  584. else{
  585. uint32_t value = CO_getUint32(ODF_arg->data);
  586. uint8_t* pData;
  587. uint8_t length = 0;
  588. uint8_t dummy = 0;
  589. uint8_t MBvar;
  590. if (TPDO->dataLength)
  591. return CO_SDO_AB_UNSUPPORTED_ACCESS; /* Unsupported access to an object. */
  592. /* verify if mapping is correct */
  593. return (CO_SDO_abortCode_t) CO_PDOfindMap(
  594. TPDO->SDO,
  595. value,
  596. 1,
  597. &pData,
  598. &length,
  599. &dummy,
  600. &MBvar);
  601. }
  602. return CO_SDO_AB_NONE;
  603. }
  604. /******************************************************************************/
  605. CO_ReturnError_t CO_RPDO_init(
  606. CO_RPDO_t *RPDO,
  607. CO_EM_t *em,
  608. CO_SDO_t *SDO,
  609. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  610. CO_SYNC_t *SYNC,
  611. #endif
  612. CO_NMT_internalState_t *operatingState,
  613. uint8_t nodeId,
  614. uint16_t defaultCOB_ID,
  615. uint8_t restrictionFlags,
  616. const CO_RPDOCommPar_t *RPDOCommPar,
  617. const CO_RPDOMapPar_t *RPDOMapPar,
  618. uint16_t idx_RPDOCommPar,
  619. uint16_t idx_RPDOMapPar,
  620. CO_CANmodule_t *CANdevRx,
  621. uint16_t CANdevRxIdx)
  622. {
  623. /* verify arguments */
  624. if (RPDO==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
  625. RPDOCommPar==NULL || RPDOMapPar==NULL || CANdevRx==NULL){
  626. return CO_ERROR_ILLEGAL_ARGUMENT;
  627. }
  628. /* Configure object variables */
  629. RPDO->em = em;
  630. RPDO->SDO = SDO;
  631. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  632. RPDO->SYNC = SYNC;
  633. #endif
  634. RPDO->RPDOCommPar = RPDOCommPar;
  635. RPDO->RPDOMapPar = RPDOMapPar;
  636. RPDO->operatingState = operatingState;
  637. RPDO->nodeId = nodeId;
  638. RPDO->defaultCOB_ID = defaultCOB_ID;
  639. RPDO->restrictionFlags = restrictionFlags;
  640. #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  641. RPDO->pFunctSignalPre = NULL;
  642. RPDO->functSignalObjectPre = NULL;
  643. #endif
  644. /* Configure Object dictionary entry at index 0x1400+ and 0x1600+ */
  645. CO_OD_configure(SDO, idx_RPDOCommPar, CO_ODF_RPDOcom, (void*)RPDO, 0, 0);
  646. CO_OD_configure(SDO, idx_RPDOMapPar, CO_ODF_RPDOmap, (void*)RPDO, 0, 0);
  647. /* configure communication and mapping */
  648. CO_FLAG_CLEAR(RPDO->CANrxNew[0]);
  649. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  650. CO_FLAG_CLEAR(RPDO->CANrxNew[1]);
  651. #endif
  652. RPDO->CANdevRx = CANdevRx;
  653. RPDO->CANdevRxIdx = CANdevRxIdx;
  654. CO_RPDOconfigMap(RPDO, RPDOMapPar->numberOfMappedObjects);
  655. CO_RPDOconfigCom(RPDO, RPDOCommPar->COB_IDUsedByRPDO);
  656. return CO_ERROR_NO;
  657. }
  658. #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_CALLBACK_PRE
  659. /******************************************************************************/
  660. void CO_RPDO_initCallbackPre(
  661. CO_RPDO_t *RPDO,
  662. void *object,
  663. void (*pFunctSignalPre)(void *object))
  664. {
  665. if (RPDO != NULL){
  666. RPDO->functSignalObjectPre = object;
  667. RPDO->pFunctSignalPre = pFunctSignalPre;
  668. }
  669. }
  670. #endif
  671. /******************************************************************************/
  672. CO_ReturnError_t CO_TPDO_init(
  673. CO_TPDO_t *TPDO,
  674. CO_EM_t *em,
  675. CO_SDO_t *SDO,
  676. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  677. CO_SYNC_t *SYNC,
  678. #endif
  679. CO_NMT_internalState_t *operatingState,
  680. uint8_t nodeId,
  681. uint16_t defaultCOB_ID,
  682. uint8_t restrictionFlags,
  683. const CO_TPDOCommPar_t *TPDOCommPar,
  684. const CO_TPDOMapPar_t *TPDOMapPar,
  685. uint16_t idx_TPDOCommPar,
  686. uint16_t idx_TPDOMapPar,
  687. CO_CANmodule_t *CANdevTx,
  688. uint16_t CANdevTxIdx)
  689. {
  690. /* verify arguments */
  691. if (TPDO==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
  692. TPDOCommPar==NULL || TPDOMapPar==NULL || CANdevTx==NULL){
  693. return CO_ERROR_ILLEGAL_ARGUMENT;
  694. }
  695. /* Configure object variables */
  696. TPDO->em = em;
  697. TPDO->SDO = SDO;
  698. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  699. TPDO->SYNC = SYNC;
  700. #endif
  701. TPDO->TPDOCommPar = TPDOCommPar;
  702. TPDO->TPDOMapPar = TPDOMapPar;
  703. TPDO->operatingState = operatingState;
  704. TPDO->nodeId = nodeId;
  705. TPDO->defaultCOB_ID = defaultCOB_ID;
  706. TPDO->restrictionFlags = restrictionFlags;
  707. /* Configure Object dictionary entry at index 0x1800+ and 0x1A00+ */
  708. CO_OD_configure(SDO, idx_TPDOCommPar, CO_ODF_TPDOcom, (void*)TPDO, 0, 0);
  709. CO_OD_configure(SDO, idx_TPDOMapPar, CO_ODF_TPDOmap, (void*)TPDO, 0, 0);
  710. /* configure communication and mapping */
  711. TPDO->CANdevTx = CANdevTx;
  712. TPDO->CANdevTxIdx = CANdevTxIdx;
  713. TPDO->inhibitTimer = 0;
  714. TPDO->eventTimer = ((uint32_t) TPDOCommPar->eventTimer) * 1000;
  715. if (TPDOCommPar->transmissionType>=254) TPDO->sendRequest = 1;
  716. CO_TPDOconfigMap(TPDO, TPDOMapPar->numberOfMappedObjects);
  717. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  718. TPDO->syncCounter = 255;
  719. CO_TPDOconfigCom(TPDO, TPDOCommPar->COB_IDUsedByTPDO, ((TPDOCommPar->transmissionType<=240) ? 1 : 0));
  720. if ((TPDOCommPar->transmissionType>240 &&
  721. TPDOCommPar->transmissionType<254) ||
  722. TPDOCommPar->SYNCStartValue>240){
  723. TPDO->valid = false;
  724. }
  725. #else
  726. CO_TPDOconfigCom(TPDO, TPDOCommPar->COB_IDUsedByTPDO, 0);
  727. if (TPDOCommPar->transmissionType<254)
  728. TPDO->valid = false;
  729. #endif
  730. return CO_ERROR_NO;
  731. }
  732. /******************************************************************************/
  733. uint8_t CO_TPDOisCOS(CO_TPDO_t *TPDO){
  734. /* Prepare TPDO data automatically from Object Dictionary variables */
  735. uint8_t* pPDOdataByte;
  736. uint8_t** ppODdataByte;
  737. pPDOdataByte = &TPDO->CANtxBuff->data[TPDO->dataLength];
  738. ppODdataByte = &TPDO->mapPointer[TPDO->dataLength];
  739. switch(TPDO->dataLength){
  740. case 8: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x80)) return 1; // fallthrough
  741. case 7: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x40)) return 1; // fallthrough
  742. case 6: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x20)) return 1; // fallthrough
  743. case 5: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x10)) return 1; // fallthrough
  744. case 4: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x08)) return 1; // fallthrough
  745. case 3: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x04)) return 1; // fallthrough
  746. case 2: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x02)) return 1; // fallthrough
  747. case 1: if (*(--pPDOdataByte) != **(--ppODdataByte) && (TPDO->sendIfCOSFlags&0x01)) return 1; // fallthrough
  748. }
  749. return 0;
  750. }
  751. /******************************************************************************/
  752. CO_ReturnError_t CO_TPDOsend(CO_TPDO_t *TPDO){
  753. int16_t i;
  754. uint8_t* pPDOdataByte;
  755. uint8_t** ppODdataByte;
  756. #if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_CALLS_EXTENSION
  757. if (TPDO->SDO->ODExtensions){
  758. /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */
  759. const uint32_t* pMap = &TPDO->TPDOMapPar->mappedObject1;
  760. CO_SDO_t *pSDO = TPDO->SDO;
  761. for(i=TPDO->TPDOMapPar->numberOfMappedObjects; i>0; i--){
  762. uint32_t map = *(pMap++);
  763. uint16_t index = (uint16_t)(map>>16);
  764. uint8_t subIndex = (uint8_t)(map>>8);
  765. uint16_t entryNo = CO_OD_find(pSDO, index);
  766. if ( entryNo == 0xFFFF ) continue;
  767. CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo];
  768. if ( ext->pODFunc == NULL) continue;
  769. CO_ODF_arg_t ODF_arg;
  770. memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t));
  771. ODF_arg.reading = true;
  772. ODF_arg.index = index;
  773. ODF_arg.subIndex = subIndex;
  774. ODF_arg.object = ext->object;
  775. ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex);
  776. ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex);
  777. ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); //https://github.com/CANopenNode/CANopenNode/issues/100
  778. ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex);
  779. ext->pODFunc(&ODF_arg);
  780. }
  781. }
  782. #endif
  783. i = TPDO->dataLength;
  784. pPDOdataByte = &TPDO->CANtxBuff->data[0];
  785. ppODdataByte = &TPDO->mapPointer[0];
  786. /* Copy data from Object dictionary. */
  787. for(; i>0; i--) {
  788. *(pPDOdataByte++) = **(ppODdataByte++);
  789. }
  790. TPDO->sendRequest = 0;
  791. return CO_CANsend(TPDO->CANdevTx, TPDO->CANtxBuff);
  792. }
  793. /******************************************************************************/
  794. void CO_RPDO_process(CO_RPDO_t *RPDO, bool_t syncWas){
  795. bool_t process_rpdo = true;
  796. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  797. if (RPDO->synchronous && !syncWas)
  798. process_rpdo = false;
  799. #endif
  800. if (!RPDO->valid || !(*RPDO->operatingState == CO_NMT_OPERATIONAL))
  801. {
  802. CO_FLAG_CLEAR(RPDO->CANrxNew[0]);
  803. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  804. CO_FLAG_CLEAR(RPDO->CANrxNew[1]);
  805. #endif
  806. }
  807. else if (process_rpdo)
  808. {
  809. #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION
  810. bool_t update = false;
  811. #endif
  812. uint8_t bufNo = 0;
  813. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  814. /* Determine, which of the two rx buffers, contains relevant message. */
  815. if (RPDO->SYNC && RPDO->synchronous && !RPDO->SYNC->CANrxToggle) {
  816. bufNo = 1;
  817. }
  818. #endif
  819. while(CO_FLAG_READ(RPDO->CANrxNew[bufNo])){
  820. int16_t i;
  821. uint8_t* pPDOdataByte;
  822. uint8_t** ppODdataByte;
  823. i = RPDO->dataLength;
  824. pPDOdataByte = &RPDO->CANrxData[bufNo][0];
  825. ppODdataByte = &RPDO->mapPointer[0];
  826. /* Copy data to Object dictionary. If between the copy operation CANrxNew
  827. * is set to true by receive thread, then copy the latest data again. */
  828. CO_FLAG_CLEAR(RPDO->CANrxNew[bufNo]);
  829. for(; i>0; i--) {
  830. **(ppODdataByte++) = *(pPDOdataByte++);
  831. }
  832. #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION
  833. update = true;
  834. #endif
  835. }
  836. #if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_CALLS_EXTENSION
  837. if (update && RPDO->SDO->ODExtensions){
  838. int16_t i;
  839. /* for each mapped OD, check mapping to see if an OD extension is available, and call it if it is */
  840. const uint32_t* pMap = &RPDO->RPDOMapPar->mappedObject1;
  841. CO_SDO_t *pSDO = RPDO->SDO;
  842. for(i=RPDO->RPDOMapPar->numberOfMappedObjects; i>0; i--){
  843. uint32_t map = *(pMap++);
  844. uint16_t index = (uint16_t)(map>>16);
  845. uint8_t subIndex = (uint8_t)(map>>8);
  846. uint16_t entryNo = CO_OD_find(pSDO, index);
  847. if ( entryNo == 0xFFFF ) continue;
  848. CO_OD_extension_t *ext = &pSDO->ODExtensions[entryNo];
  849. if ( ext->pODFunc == NULL) continue;
  850. CO_ODF_arg_t ODF_arg;
  851. memset((void*)&ODF_arg, 0, sizeof(CO_ODF_arg_t));
  852. ODF_arg.reading = false;
  853. ODF_arg.index = index;
  854. ODF_arg.subIndex = subIndex;
  855. ODF_arg.object = ext->object;
  856. ODF_arg.attribute = CO_OD_getAttribute(pSDO, entryNo, subIndex);
  857. ODF_arg.pFlags = CO_OD_getFlagsPointer(pSDO, entryNo, subIndex);
  858. ODF_arg.data = CO_OD_getDataPointer(pSDO, entryNo, subIndex); //https://github.com/CANopenNode/CANopenNode/issues/100
  859. ODF_arg.dataLength = CO_OD_getLength(pSDO, entryNo, subIndex);
  860. ext->pODFunc(&ODF_arg);
  861. }
  862. }
  863. #endif
  864. }
  865. }
  866. /******************************************************************************/
  867. void CO_TPDO_process(
  868. CO_TPDO_t *TPDO,
  869. bool_t syncWas,
  870. uint32_t timeDifference_us,
  871. uint32_t *timerNext_us)
  872. {
  873. (void)timerNext_us; /* may be unused */
  874. /* update timers */
  875. TPDO->inhibitTimer = (TPDO->inhibitTimer > timeDifference_us) ? (TPDO->inhibitTimer - timeDifference_us) : 0;
  876. TPDO->eventTimer = (TPDO->eventTimer > timeDifference_us) ? (TPDO->eventTimer - timeDifference_us) : 0;
  877. if (TPDO->valid && *TPDO->operatingState == CO_NMT_OPERATIONAL){
  878. /* Send PDO by application request or by Event timer */
  879. if (TPDO->TPDOCommPar->transmissionType >= 253){
  880. if (TPDO->inhibitTimer == 0 && (TPDO->sendRequest || (TPDO->TPDOCommPar->eventTimer && TPDO->eventTimer == 0))){
  881. if (CO_TPDOsend(TPDO) == CO_ERROR_NO){
  882. /* successfully sent */
  883. TPDO->inhibitTimer = ((uint32_t) TPDO->TPDOCommPar->inhibitTime) * 100;
  884. TPDO->eventTimer = ((uint32_t) TPDO->TPDOCommPar->eventTimer) * 1000;
  885. }
  886. }
  887. #if (CO_CONFIG_PDO) & CO_CONFIG_FLAG_TIMERNEXT
  888. if (timerNext_us != NULL){
  889. if (TPDO->sendRequest && *timerNext_us > TPDO->inhibitTimer){
  890. *timerNext_us = TPDO->inhibitTimer; /* Schedule for just beyond inhibit window */
  891. }else if (TPDO->TPDOCommPar->eventTimer && *timerNext_us > TPDO->eventTimer){
  892. *timerNext_us = TPDO->eventTimer; /* Schedule for next maximum event time */
  893. }
  894. }
  895. #endif
  896. }
  897. #if (CO_CONFIG_PDO) & CO_CONFIG_PDO_SYNC_ENABLE
  898. /* Synchronous PDOs */
  899. else if (TPDO->SYNC && syncWas){
  900. /* send synchronous acyclic PDO */
  901. if (TPDO->TPDOCommPar->transmissionType == 0){
  902. if (TPDO->sendRequest) CO_TPDOsend(TPDO);
  903. }
  904. /* send synchronous cyclic PDO */
  905. else{
  906. /* is the start of synchronous TPDO transmission */
  907. if (TPDO->syncCounter == 255){
  908. if (TPDO->SYNC->counterOverflowValue && TPDO->TPDOCommPar->SYNCStartValue)
  909. TPDO->syncCounter = 254; /* SYNCStartValue is in use */
  910. else
  911. TPDO->syncCounter = TPDO->TPDOCommPar->transmissionType;
  912. }
  913. /* if the SYNCStartValue is in use, start first TPDO after SYNC with matched SYNCStartValue. */
  914. if (TPDO->syncCounter == 254){
  915. if (TPDO->SYNC->counter == TPDO->TPDOCommPar->SYNCStartValue){
  916. TPDO->syncCounter = TPDO->TPDOCommPar->transmissionType;
  917. CO_TPDOsend(TPDO);
  918. }
  919. }
  920. /* Send PDO after every N-th Sync */
  921. else if (--TPDO->syncCounter == 0){
  922. TPDO->syncCounter = TPDO->TPDOCommPar->transmissionType;
  923. CO_TPDOsend(TPDO);
  924. }
  925. }
  926. }
  927. #endif
  928. }
  929. else{
  930. /* Not operational or valid. Force TPDO first send after operational or valid. */
  931. if (TPDO->TPDOCommPar->transmissionType>=254) TPDO->sendRequest = 1;
  932. else TPDO->sendRequest = 0;
  933. }
  934. }