CO_SYNC.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. * CANopen SYNC object.
  3. *
  4. * @file CO_SYNC.c
  5. * @ingroup CO_SYNC
  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_SDOserver.h"
  26. #include "301/CO_Emergency.h"
  27. #include "301/CO_NMT_Heartbeat.h"
  28. #include "301/CO_SYNC.h"
  29. #if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE
  30. /*
  31. * Read received message from CAN module.
  32. *
  33. * Function will be called (by CAN receive interrupt) every time, when CAN
  34. * message with correct identifier will be received. For more information and
  35. * description of parameters see file CO_driver.h.
  36. */
  37. static void CO_SYNC_receive(void *object, void *msg) {
  38. CO_SYNC_t *SYNC;
  39. CO_NMT_internalState_t operState;
  40. SYNC = (CO_SYNC_t*)object; /* this is the correct pointer type of the first argument */
  41. operState = *SYNC->operatingState;
  42. if ((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){
  43. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  44. if (SYNC->counterOverflowValue == 0){
  45. if (DLC == 0U){
  46. CO_FLAG_SET(SYNC->CANrxNew);
  47. }
  48. else{
  49. SYNC->receiveError = (uint16_t)DLC | 0x0100U;
  50. }
  51. }
  52. else{
  53. if (DLC == 1U){
  54. uint8_t *data = CO_CANrxMsg_readData(msg);
  55. SYNC->counter = data[0];
  56. CO_FLAG_SET(SYNC->CANrxNew);
  57. }
  58. else{
  59. SYNC->receiveError = (uint16_t)DLC | 0x0200U;
  60. }
  61. }
  62. if (CO_FLAG_READ(SYNC->CANrxNew)) {
  63. SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true;
  64. #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE
  65. /* Optional signal to RTOS, which can resume task, which handles SYNC. */
  66. if (SYNC->pFunctSignalPre != NULL) {
  67. SYNC->pFunctSignalPre(SYNC->functSignalObjectPre);
  68. }
  69. #endif
  70. }
  71. }
  72. }
  73. /*
  74. * Function for accessing _COB ID SYNC Message_ (index 0x1005) from SDO server.
  75. *
  76. * For more information see file CO_SDOserver.h.
  77. */
  78. static CO_SDO_abortCode_t CO_ODF_1005(CO_ODF_arg_t *ODF_arg){
  79. CO_SYNC_t *SYNC;
  80. uint32_t value;
  81. CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
  82. SYNC = (CO_SYNC_t*) ODF_arg->object;
  83. value = CO_getUint32(ODF_arg->data);
  84. if (!ODF_arg->reading){
  85. uint8_t configureSyncProducer = 0;
  86. /* only 11-bit CAN identifier is supported */
  87. if (value & 0x20000000UL){
  88. ret = CO_SDO_AB_INVALID_VALUE;
  89. }
  90. else{
  91. /* is 'generate Sync messge' bit set? */
  92. if (value & 0x40000000UL){
  93. /* if bit was set before, value can not be changed */
  94. if (SYNC->isProducer){
  95. ret = CO_SDO_AB_DATA_DEV_STATE;
  96. }
  97. else{
  98. configureSyncProducer = 1;
  99. }
  100. }
  101. }
  102. /* configure sync producer */
  103. if (ret == CO_SDO_AB_NONE){
  104. SYNC->COB_ID = (uint16_t)(value & 0x7FFU);
  105. if (configureSyncProducer){
  106. uint8_t len = 0U;
  107. if (SYNC->counterOverflowValue != 0U){
  108. len = 1U;
  109. SYNC->counter = 0U;
  110. SYNC->timer = 0U;
  111. }
  112. SYNC->CANtxBuff = CO_CANtxBufferInit(
  113. SYNC->CANdevTx, /* CAN device */
  114. SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */
  115. SYNC->COB_ID, /* CAN identifier */
  116. 0, /* rtr */
  117. len, /* number of data bytes */
  118. 0); /* synchronous message flag bit */
  119. if (SYNC->CANtxBuff == NULL) {
  120. ret = CO_SDO_AB_DATA_DEV_STATE;
  121. SYNC->isProducer = false;
  122. } else {
  123. SYNC->isProducer = true;
  124. }
  125. }
  126. else{
  127. SYNC->isProducer = false;
  128. }
  129. }
  130. /* configure sync consumer */
  131. if (ret == CO_SDO_AB_NONE) {
  132. CO_ReturnError_t CANret = CO_CANrxBufferInit(
  133. SYNC->CANdevRx, /* CAN device */
  134. SYNC->CANdevRxIdx, /* rx buffer index */
  135. SYNC->COB_ID, /* CAN identifier */
  136. 0x7FF, /* mask */
  137. 0, /* rtr */
  138. (void*)SYNC, /* object passed to receive function */
  139. CO_SYNC_receive); /* this function will process received message */
  140. if (CANret != CO_ERROR_NO) {
  141. ret = CO_SDO_AB_DATA_DEV_STATE;
  142. }
  143. }
  144. }
  145. return ret;
  146. }
  147. /*
  148. * Function for accessing _Communication cycle period_ (index 0x1006) from SDO server.
  149. *
  150. * For more information see file CO_SDOserver.h.
  151. */
  152. static CO_SDO_abortCode_t CO_ODF_1006(CO_ODF_arg_t *ODF_arg){
  153. CO_SYNC_t *SYNC;
  154. uint32_t value;
  155. CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
  156. SYNC = (CO_SYNC_t*) ODF_arg->object;
  157. value = CO_getUint32(ODF_arg->data);
  158. if (!ODF_arg->reading){
  159. /* period transition from 0 to something */
  160. if ((SYNC->periodTime == 0) && (value != 0)){
  161. SYNC->counter = 0;
  162. }
  163. SYNC->periodTime = value;
  164. SYNC->periodTimeoutTime = (value / 2U) * 3U;
  165. /* overflow? */
  166. if (SYNC->periodTimeoutTime < value){
  167. SYNC->periodTimeoutTime = 0xFFFFFFFFUL;
  168. }
  169. SYNC->timer = 0;
  170. }
  171. return ret;
  172. }
  173. /**
  174. * Function for accessing _Synchronous counter overflow value_ (index 0x1019) from SDO server.
  175. *
  176. * For more information see file CO_SDOserver.h.
  177. */
  178. static CO_SDO_abortCode_t CO_ODF_1019(CO_ODF_arg_t *ODF_arg){
  179. CO_SYNC_t *SYNC;
  180. uint8_t value;
  181. CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
  182. SYNC = (CO_SYNC_t*) ODF_arg->object;
  183. value = ODF_arg->data[0];
  184. if (!ODF_arg->reading){
  185. uint8_t len = 0U;
  186. if (SYNC->periodTime){
  187. ret = CO_SDO_AB_DATA_DEV_STATE;
  188. }
  189. else if ((value == 1) || (value > 240)){
  190. ret = CO_SDO_AB_INVALID_VALUE;
  191. }
  192. else{
  193. SYNC->counterOverflowValue = value;
  194. if (value != 0){
  195. len = 1U;
  196. }
  197. SYNC->CANtxBuff = CO_CANtxBufferInit(
  198. SYNC->CANdevTx, /* CAN device */
  199. SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */
  200. SYNC->COB_ID, /* CAN identifier */
  201. 0, /* rtr */
  202. len, /* number of data bytes */
  203. 0); /* synchronous message flag bit */
  204. if (SYNC->CANtxBuff == NULL) {
  205. ret = CO_SDO_AB_DATA_DEV_STATE;
  206. }
  207. }
  208. }
  209. return ret;
  210. }
  211. /******************************************************************************/
  212. CO_ReturnError_t CO_SYNC_init(
  213. CO_SYNC_t *SYNC,
  214. CO_EM_t *em,
  215. CO_SDO_t *SDO,
  216. CO_NMT_internalState_t *operatingState,
  217. uint32_t COB_ID_SYNCMessage,
  218. uint32_t communicationCyclePeriod,
  219. uint8_t synchronousCounterOverflowValue,
  220. CO_CANmodule_t *CANdevRx,
  221. uint16_t CANdevRxIdx,
  222. CO_CANmodule_t *CANdevTx,
  223. uint16_t CANdevTxIdx)
  224. {
  225. uint8_t len = 0;
  226. CO_ReturnError_t ret = CO_ERROR_NO;
  227. /* verify arguments */
  228. if (SYNC==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
  229. CANdevRx==NULL || CANdevTx==NULL){
  230. return CO_ERROR_ILLEGAL_ARGUMENT;
  231. }
  232. /* Configure object variables */
  233. SYNC->isProducer = (COB_ID_SYNCMessage&0x40000000L) ? true : false;
  234. SYNC->COB_ID = COB_ID_SYNCMessage&0x7FF;
  235. SYNC->periodTime = communicationCyclePeriod;
  236. SYNC->periodTimeoutTime = communicationCyclePeriod / 2 * 3;
  237. /* overflow? */
  238. if (SYNC->periodTimeoutTime < communicationCyclePeriod) SYNC->periodTimeoutTime = 0xFFFFFFFFL;
  239. SYNC->counterOverflowValue = synchronousCounterOverflowValue;
  240. if (synchronousCounterOverflowValue) len = 1;
  241. SYNC->curentSyncTimeIsInsideWindow = true;
  242. CO_FLAG_CLEAR(SYNC->CANrxNew);
  243. SYNC->CANrxToggle = false;
  244. SYNC->timer = 0;
  245. SYNC->counter = 0;
  246. SYNC->receiveError = 0U;
  247. SYNC->em = em;
  248. SYNC->operatingState = operatingState;
  249. SYNC->CANdevRx = CANdevRx;
  250. SYNC->CANdevRxIdx = CANdevRxIdx;
  251. #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE
  252. SYNC->pFunctSignalPre = NULL;
  253. SYNC->functSignalObjectPre = NULL;
  254. #endif
  255. /* Configure Object dictionary entry at index 0x1005, 0x1006 and 0x1019 */
  256. CO_OD_configure(SDO, OD_H1005_COBID_SYNC, CO_ODF_1005, (void*)SYNC, 0, 0);
  257. CO_OD_configure(SDO, OD_H1006_COMM_CYCL_PERIOD, CO_ODF_1006, (void*)SYNC, 0, 0);
  258. CO_OD_configure(SDO, OD_H1019_SYNC_CNT_OVERFLOW, CO_ODF_1019, (void*)SYNC, 0, 0);
  259. /* configure SYNC CAN reception */
  260. ret = CO_CANrxBufferInit(
  261. CANdevRx, /* CAN device */
  262. CANdevRxIdx, /* rx buffer index */
  263. SYNC->COB_ID, /* CAN identifier */
  264. 0x7FF, /* mask */
  265. 0, /* rtr */
  266. (void*)SYNC, /* object passed to receive function */
  267. CO_SYNC_receive); /* this function will process received message */
  268. /* configure SYNC CAN transmission */
  269. SYNC->CANdevTx = CANdevTx;
  270. SYNC->CANdevTxIdx = CANdevTxIdx;
  271. SYNC->CANtxBuff = CO_CANtxBufferInit(
  272. CANdevTx, /* CAN device */
  273. CANdevTxIdx, /* index of specific buffer inside CAN module */
  274. SYNC->COB_ID, /* CAN identifier */
  275. 0, /* rtr */
  276. len, /* number of data bytes */
  277. 0); /* synchronous message flag bit */
  278. if (SYNC->CANtxBuff == NULL) {
  279. ret = CO_ERROR_ILLEGAL_ARGUMENT;
  280. }
  281. return ret;
  282. }
  283. #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_CALLBACK_PRE
  284. /******************************************************************************/
  285. void CO_SYNC_initCallbackPre(
  286. CO_SYNC_t *SYNC,
  287. void *object,
  288. void (*pFunctSignalPre)(void *object))
  289. {
  290. if (SYNC != NULL){
  291. SYNC->functSignalObjectPre = object;
  292. SYNC->pFunctSignalPre = pFunctSignalPre;
  293. }
  294. }
  295. #endif
  296. /******************************************************************************/
  297. CO_ReturnError_t CO_SYNCsend(CO_SYNC_t *SYNC){
  298. if (++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1;
  299. SYNC->timer = 0;
  300. SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true;
  301. SYNC->CANtxBuff->data[0] = SYNC->counter;
  302. return CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff);
  303. }
  304. /******************************************************************************/
  305. CO_SYNC_status_t CO_SYNC_process(
  306. CO_SYNC_t *SYNC,
  307. uint32_t timeDifference_us,
  308. uint32_t ObjDict_synchronousWindowLength,
  309. uint32_t *timerNext_us)
  310. {
  311. (void)timerNext_us; /* may be unused */
  312. CO_SYNC_status_t ret = CO_SYNC_NONE;
  313. uint32_t timerNew;
  314. if (*SYNC->operatingState == CO_NMT_OPERATIONAL || *SYNC->operatingState == CO_NMT_PRE_OPERATIONAL){
  315. /* update sync timer, no overflow */
  316. timerNew = SYNC->timer + timeDifference_us;
  317. if (timerNew > SYNC->timer) SYNC->timer = timerNew;
  318. /* was SYNC just received */
  319. if (CO_FLAG_READ(SYNC->CANrxNew)){
  320. SYNC->timer = 0;
  321. ret = CO_SYNC_RECEIVED;
  322. CO_FLAG_CLEAR(SYNC->CANrxNew);
  323. }
  324. /* SYNC producer */
  325. if (SYNC->isProducer && SYNC->periodTime){
  326. if (SYNC->timer >= SYNC->periodTime){
  327. ret = CO_SYNC_RECEIVED;
  328. CO_SYNCsend(SYNC);
  329. }
  330. #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT
  331. /* Calculate when next SYNC needs to be sent */
  332. if (timerNext_us != NULL){
  333. uint32_t diff = SYNC->periodTime - SYNC->timer;
  334. if (*timerNext_us > diff){
  335. *timerNext_us = diff;
  336. }
  337. }
  338. #endif
  339. }
  340. /* Synchronous PDOs are allowed only inside time window */
  341. if (ObjDict_synchronousWindowLength){
  342. if (SYNC->timer > ObjDict_synchronousWindowLength){
  343. if (SYNC->curentSyncTimeIsInsideWindow){
  344. ret = CO_SYNC_OUTSIDE_WINDOW;
  345. }
  346. SYNC->curentSyncTimeIsInsideWindow = false;
  347. }
  348. else{
  349. SYNC->curentSyncTimeIsInsideWindow = true;
  350. }
  351. }
  352. else{
  353. SYNC->curentSyncTimeIsInsideWindow = true;
  354. }
  355. /* Verify timeout of SYNC */
  356. if (SYNC->periodTime && (*SYNC->operatingState == CO_NMT_OPERATIONAL || *SYNC->operatingState == CO_NMT_PRE_OPERATIONAL)){
  357. if (SYNC->timer > SYNC->periodTimeoutTime) {
  358. CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer);
  359. }
  360. else {
  361. CO_errorReset(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION);
  362. #if (CO_CONFIG_SYNC) & CO_CONFIG_FLAG_TIMERNEXT
  363. if (timerNext_us != NULL) {
  364. uint32_t diff = SYNC->periodTimeoutTime - SYNC->timer;
  365. if (*timerNext_us > diff){
  366. *timerNext_us = diff;
  367. }
  368. }
  369. #endif
  370. }
  371. }
  372. }
  373. else {
  374. CO_FLAG_CLEAR(SYNC->CANrxNew);
  375. }
  376. /* verify error from receive function */
  377. if (SYNC->receiveError != 0U){
  378. CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, CO_EMC_SYNC_DATA_LENGTH, (uint32_t)SYNC->receiveError);
  379. SYNC->receiveError = 0U;
  380. }
  381. return ret;
  382. }
  383. #endif /* (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE */