CO_TIME.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * CANopen TIME object.
  3. *
  4. * @file CO_TIME.c
  5. * @ingroup CO_TIME
  6. * @author Julien PEYREGNE
  7. * @copyright 2019 - 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_SDOserver.h"
  27. #include "301/CO_Emergency.h"
  28. #include "301/CO_NMT_Heartbeat.h"
  29. #include "301/CO_TIME.h"
  30. #if (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE
  31. #define DIV_ROUND_UP(_n, _d) (((_n) + (_d) - 1) / (_d))
  32. /*
  33. * Read received message from CAN module.
  34. *
  35. * Function will be called (by CAN receive interrupt) every time, when CAN
  36. * message with correct identifier will be received.
  37. */
  38. static void CO_TIME_receive(void *object, void *msg){
  39. CO_TIME_t *TIME;
  40. CO_NMT_internalState_t operState;
  41. uint8_t DLC = CO_CANrxMsg_readDLC(msg);
  42. uint8_t *data = CO_CANrxMsg_readData(msg);
  43. TIME = (CO_TIME_t*)object; /* this is the correct pointer type of the first argument */
  44. operState = *TIME->operatingState;
  45. if ((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){
  46. // Process Time from msg buffer
  47. memcpy(&TIME->Time.ullValue, data, DLC);
  48. CO_FLAG_SET(TIME->CANrxNew);
  49. #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE
  50. /* Optional signal to RTOS, which can resume task, which handles TIME. */
  51. if (TIME->pFunctSignalPre != NULL) {
  52. TIME->pFunctSignalPre(TIME->functSignalObjectPre);
  53. }
  54. #endif
  55. }
  56. else{
  57. TIME->receiveError = (uint16_t)DLC;
  58. }
  59. }
  60. /******************************************************************************/
  61. CO_ReturnError_t CO_TIME_init(
  62. CO_TIME_t *TIME,
  63. CO_EM_t *em,
  64. CO_SDO_t *SDO,
  65. CO_NMT_internalState_t *operatingState,
  66. uint32_t COB_ID_TIMEMessage,
  67. uint32_t TIMECyclePeriod,
  68. CO_CANmodule_t *CANdevRx,
  69. uint16_t CANdevRxIdx,
  70. CO_CANmodule_t *CANdevTx,
  71. uint16_t CANdevTxIdx)
  72. {
  73. CO_ReturnError_t ret = CO_ERROR_NO;
  74. /* verify arguments */
  75. if (TIME==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
  76. CANdevRx==NULL || CANdevTx==NULL){
  77. return CO_ERROR_ILLEGAL_ARGUMENT;
  78. }
  79. /* Configure object variables */
  80. TIME->isConsumer = (COB_ID_TIMEMessage&0x80000000L) ? true : false;
  81. TIME->isProducer = (COB_ID_TIMEMessage&0x40000000L) ? true : false;
  82. TIME->COB_ID = COB_ID_TIMEMessage&0x7FF; // 11 bit ID
  83. TIME->periodTime = TIMECyclePeriod;
  84. TIME->periodTimeoutTime = TIMECyclePeriod / 2 * 3;
  85. /* overflow? */
  86. if (TIME->periodTimeoutTime < TIMECyclePeriod)
  87. TIME->periodTimeoutTime = 0xFFFFFFFFL;
  88. CO_FLAG_CLEAR(TIME->CANrxNew);
  89. TIME->timer = 0;
  90. TIME->receiveError = 0U;
  91. TIME->em = em;
  92. TIME->operatingState = operatingState;
  93. #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE
  94. TIME->pFunctSignalPre = NULL;
  95. TIME->functSignalObjectPre = NULL;
  96. #endif
  97. /* configure TIME consumer message reception */
  98. TIME->CANdevRx = CANdevRx;
  99. TIME->CANdevRxIdx = CANdevRxIdx;
  100. if (TIME->isConsumer) {
  101. ret = CO_CANrxBufferInit(
  102. CANdevRx, /* CAN device */
  103. CANdevRxIdx, /* rx buffer index */
  104. TIME->COB_ID, /* CAN identifier */
  105. 0x7FF, /* mask */
  106. 0, /* rtr */
  107. (void*)TIME, /* object passed to receive function */
  108. CO_TIME_receive); /* this function will process received message */
  109. }
  110. /* configure TIME producer message transmission */
  111. TIME->CANdevTx = CANdevTx;
  112. TIME->CANdevTxIdx = CANdevTxIdx;
  113. if (TIME->isProducer) {
  114. TIME->TXbuff = CO_CANtxBufferInit(
  115. CANdevTx, /* CAN device */
  116. CANdevTxIdx, /* index of specific buffer inside CAN module */
  117. TIME->COB_ID, /* CAN identifier */
  118. 0, /* rtr */
  119. TIME_MSG_LENGTH, /* number of data bytes */
  120. 0); /* synchronous message flag bit */
  121. if (TIME->TXbuff == NULL) {
  122. ret = CO_ERROR_ILLEGAL_ARGUMENT;
  123. }
  124. }
  125. return ret;
  126. }
  127. #if (CO_CONFIG_TIME) & CO_CONFIG_FLAG_CALLBACK_PRE
  128. /******************************************************************************/
  129. void CO_TIME_initCallbackPre(
  130. CO_TIME_t *TIME,
  131. void *object,
  132. void (*pFunctSignalPre)(void *object))
  133. {
  134. if (TIME != NULL){
  135. TIME->functSignalObjectPre = object;
  136. TIME->pFunctSignalPre = pFunctSignalPre;
  137. }
  138. }
  139. #endif
  140. /******************************************************************************/
  141. uint8_t CO_TIME_process(
  142. CO_TIME_t *TIME,
  143. uint32_t timeDifference_us)
  144. {
  145. uint8_t ret = 0;
  146. uint32_t timerNew;
  147. if (*TIME->operatingState == CO_NMT_OPERATIONAL || *TIME->operatingState == CO_NMT_PRE_OPERATIONAL){
  148. /* update TIME timer, no overflow */
  149. uint32_t timeDifference_ms = DIV_ROUND_UP(timeDifference_us, 1000);
  150. timerNew = TIME->timer + timeDifference_ms;
  151. if (timerNew > TIME->timer)
  152. TIME->timer = timerNew;
  153. /* was TIME just received */
  154. if (CO_FLAG_READ(TIME->CANrxNew)){
  155. TIME->timer = 0;
  156. ret = 1;
  157. CO_FLAG_CLEAR(TIME->CANrxNew);
  158. }
  159. /* TIME producer */
  160. if (TIME->isProducer && TIME->periodTime){
  161. if (TIME->timer >= TIME->periodTime){
  162. TIME->timer = 0;
  163. ret = 1;
  164. memcpy(TIME->TXbuff->data, &TIME->Time.ullValue, TIME_MSG_LENGTH);
  165. CO_CANsend(TIME->CANdevTx, TIME->TXbuff);
  166. }
  167. }
  168. /* Verify TIME timeout if node is consumer */
  169. if (TIME->isConsumer && TIME->periodTime && TIME->timer > TIME->periodTimeoutTime
  170. && *TIME->operatingState == CO_NMT_OPERATIONAL)
  171. CO_errorReport(TIME->em, CO_EM_TIME_TIMEOUT, CO_EMC_COMMUNICATION, TIME->timer);
  172. }
  173. else {
  174. CO_FLAG_CLEAR(TIME->CANrxNew);
  175. }
  176. /* verify error from receive function */
  177. if (TIME->receiveError != 0U){
  178. CO_errorReport(TIME->em, CO_EM_TIME_LENGTH, CO_EMC_TIME_DATA_LENGTH, (uint32_t)TIME->receiveError);
  179. TIME->receiveError = 0U;
  180. }
  181. return ret;
  182. }
  183. #endif /* (CO_CONFIG_TIME) & CO_CONFIG_TIME_ENABLE */