MindSDK_MM32F5270/components/canopen/CO_SYNC.c

362 lines
12 KiB
C

/*
* CANopen SYNC object.
*
* @file CO_SYNC.c
* @ingroup CO_SYNC
* @author Janez Paternoster
* @copyright 2004 - 2020 Janez Paternoster
*
* This file is part of CANopenNode, an opensource CANopen Stack.
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
* For more information on CANopen see <http://www.can-cia.org/>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "CO_driver.h"
#include "CO_SDO.h"
#include "CO_Emergency.h"
#include "CO_NMT_Heartbeat.h"
#include "CO_SYNC.h"
/*
* Read received message from CAN module.
*
* Function will be called (by CAN receive interrupt) every time, when CAN
* message with correct identifier will be received. For more information and
* description of parameters see file CO_driver.h.
*/
static void CO_SYNC_receive(void *object, const CO_CANrxMsg_t *msg){
CO_SYNC_t *SYNC;
uint8_t operState;
SYNC = (CO_SYNC_t*)object; /* this is the correct pointer type of the first argument */
operState = *SYNC->operatingState;
if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){
if(SYNC->counterOverflowValue == 0){
if(msg->DLC == 0U){
SET_CANrxNew(SYNC->CANrxNew);
}
else{
SYNC->receiveError = (uint16_t)msg->DLC | 0x0100U;
}
}
else{
if(msg->DLC == 1U){
SYNC->counter = msg->data[0];
SET_CANrxNew(SYNC->CANrxNew);
}
else{
SYNC->receiveError = (uint16_t)msg->DLC | 0x0200U;
}
}
if(IS_CANrxNew(SYNC->CANrxNew)) {
SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true;
}
}
}
/*
* Function for accessing _COB ID SYNC Message_ (index 0x1005) from SDO server.
*
* For more information see file CO_SDO.h.
*/
static CO_SDO_abortCode_t CO_ODF_1005(CO_ODF_arg_t *ODF_arg){
CO_SYNC_t *SYNC;
uint32_t value;
CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
SYNC = (CO_SYNC_t*) ODF_arg->object;
value = CO_getUint32(ODF_arg->data);
if(!ODF_arg->reading){
uint8_t configureSyncProducer = 0;
/* only 11-bit CAN identifier is supported */
if(value & 0x20000000UL){
ret = CO_SDO_AB_INVALID_VALUE;
}
else{
/* is 'generate Sync messge' bit set? */
if(value & 0x40000000UL){
/* if bit was set before, value can not be changed */
if(SYNC->isProducer){
ret = CO_SDO_AB_DATA_DEV_STATE;
}
else{
configureSyncProducer = 1;
}
}
}
/* configure sync producer and consumer */
if(ret == CO_SDO_AB_NONE){
SYNC->COB_ID = (uint16_t)(value & 0x7FFU);
if(configureSyncProducer){
uint8_t len = 0U;
if(SYNC->counterOverflowValue != 0U){
len = 1U;
SYNC->counter = 0U;
SYNC->timer = 0U;
}
SYNC->CANtxBuff = CO_CANtxBufferInit(
SYNC->CANdevTx, /* CAN device */
SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */
SYNC->COB_ID, /* CAN identifier */
0, /* rtr */
len, /* number of data bytes */
0); /* synchronous message flag bit */
SYNC->isProducer = true;
}
else{
SYNC->isProducer = false;
}
CO_CANrxBufferInit(
SYNC->CANdevRx, /* CAN device */
SYNC->CANdevRxIdx, /* rx buffer index */
SYNC->COB_ID, /* CAN identifier */
0x7FF, /* mask */
0, /* rtr */
(void*)SYNC, /* object passed to receive function */
CO_SYNC_receive); /* this function will process received message */
}
}
return ret;
}
/*
* Function for accessing _Communication cycle period_ (index 0x1006) from SDO server.
*
* For more information see file CO_SDO.h.
*/
static CO_SDO_abortCode_t CO_ODF_1006(CO_ODF_arg_t *ODF_arg){
CO_SYNC_t *SYNC;
uint32_t value;
CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
SYNC = (CO_SYNC_t*) ODF_arg->object;
value = CO_getUint32(ODF_arg->data);
if(!ODF_arg->reading){
/* period transition from 0 to something */
if((SYNC->periodTime == 0) && (value != 0)){
SYNC->counter = 0;
}
SYNC->periodTime = value;
SYNC->periodTimeoutTime = (value / 2U) * 3U;
/* overflow? */
if(SYNC->periodTimeoutTime < value){
SYNC->periodTimeoutTime = 0xFFFFFFFFUL;
}
SYNC->timer = 0;
}
return ret;
}
/**
* Function for accessing _Synchronous counter overflow value_ (index 0x1019) from SDO server.
*
* For more information see file CO_SDO.h.
*/
static CO_SDO_abortCode_t CO_ODF_1019(CO_ODF_arg_t *ODF_arg){
CO_SYNC_t *SYNC;
uint8_t value;
CO_SDO_abortCode_t ret = CO_SDO_AB_NONE;
SYNC = (CO_SYNC_t*) ODF_arg->object;
value = ODF_arg->data[0];
if(!ODF_arg->reading){
uint8_t len = 0U;
if(SYNC->periodTime){
ret = CO_SDO_AB_DATA_DEV_STATE;
}
else if((value == 1) || (value > 240)){
ret = CO_SDO_AB_INVALID_VALUE;
}
else{
SYNC->counterOverflowValue = value;
if(value != 0){
len = 1U;
}
SYNC->CANtxBuff = CO_CANtxBufferInit(
SYNC->CANdevTx, /* CAN device */
SYNC->CANdevTxIdx, /* index of specific buffer inside CAN module */
SYNC->COB_ID, /* CAN identifier */
0, /* rtr */
len, /* number of data bytes */
0); /* synchronous message flag bit */
}
}
return ret;
}
/******************************************************************************/
CO_ReturnError_t CO_SYNC_init(
CO_SYNC_t *SYNC,
CO_EM_t *em,
CO_SDO_t *SDO,
uint8_t *operatingState,
uint32_t COB_ID_SYNCMessage,
uint32_t communicationCyclePeriod,
uint8_t synchronousCounterOverflowValue,
CO_CANmodule_t *CANdevRx,
uint16_t CANdevRxIdx,
CO_CANmodule_t *CANdevTx,
uint16_t CANdevTxIdx)
{
uint8_t len = 0;
/* verify arguments */
if(SYNC==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
CANdevRx==NULL || CANdevTx==NULL){
return CO_ERROR_ILLEGAL_ARGUMENT;
}
/* Configure object variables */
SYNC->isProducer = (COB_ID_SYNCMessage&0x40000000L) ? true : false;
SYNC->COB_ID = COB_ID_SYNCMessage&0x7FF;
SYNC->periodTime = communicationCyclePeriod;
SYNC->periodTimeoutTime = communicationCyclePeriod / 2 * 3;
/* overflow? */
if(SYNC->periodTimeoutTime < communicationCyclePeriod) SYNC->periodTimeoutTime = 0xFFFFFFFFL;
SYNC->counterOverflowValue = synchronousCounterOverflowValue;
if(synchronousCounterOverflowValue) len = 1;
SYNC->curentSyncTimeIsInsideWindow = true;
CLEAR_CANrxNew(SYNC->CANrxNew);
SYNC->CANrxToggle = false;
SYNC->timer = 0;
SYNC->counter = 0;
SYNC->receiveError = 0U;
SYNC->em = em;
SYNC->operatingState = operatingState;
SYNC->CANdevRx = CANdevRx;
SYNC->CANdevRxIdx = CANdevRxIdx;
/* Configure Object dictionary entry at index 0x1005, 0x1006 and 0x1019 */
CO_OD_configure(SDO, OD_H1005_COBID_SYNC, CO_ODF_1005, (void*)SYNC, 0, 0);
CO_OD_configure(SDO, OD_H1006_COMM_CYCL_PERIOD, CO_ODF_1006, (void*)SYNC, 0, 0);
CO_OD_configure(SDO, OD_H1019_SYNC_CNT_OVERFLOW, CO_ODF_1019, (void*)SYNC, 0, 0);
/* configure SYNC CAN reception */
CO_CANrxBufferInit(
CANdevRx, /* CAN device */
CANdevRxIdx, /* rx buffer index */
SYNC->COB_ID, /* CAN identifier */
0x7FF, /* mask */
0, /* rtr */
(void*)SYNC, /* object passed to receive function */
CO_SYNC_receive); /* this function will process received message */
/* configure SYNC CAN transmission */
SYNC->CANdevTx = CANdevTx;
SYNC->CANdevTxIdx = CANdevTxIdx;
SYNC->CANtxBuff = CO_CANtxBufferInit(
CANdevTx, /* CAN device */
CANdevTxIdx, /* index of specific buffer inside CAN module */
SYNC->COB_ID, /* CAN identifier */
0, /* rtr */
len, /* number of data bytes */
0); /* synchronous message flag bit */
return CO_ERROR_NO;
}
/******************************************************************************/
uint8_t CO_SYNC_process(
CO_SYNC_t *SYNC,
uint32_t timeDifference_us,
uint32_t ObjDict_synchronousWindowLength)
{
uint8_t ret = 0;
uint32_t timerNew;
if(*SYNC->operatingState == CO_NMT_OPERATIONAL || *SYNC->operatingState == CO_NMT_PRE_OPERATIONAL){
/* update sync timer, no overflow */
timerNew = SYNC->timer + timeDifference_us;
if(timerNew > SYNC->timer) SYNC->timer = timerNew;
/* was SYNC just received */
if(IS_CANrxNew(SYNC->CANrxNew)){
SYNC->timer = 0;
ret = 1;
CLEAR_CANrxNew(SYNC->CANrxNew);
}
/* SYNC producer */
if(SYNC->isProducer && SYNC->periodTime){
if(SYNC->timer >= SYNC->periodTime){
if(++SYNC->counter > SYNC->counterOverflowValue) SYNC->counter = 1;
SYNC->timer = 0;
ret = 1;
SYNC->CANrxToggle = SYNC->CANrxToggle ? false : true;
SYNC->CANtxBuff->data[0] = SYNC->counter;
CO_CANsend(SYNC->CANdevTx, SYNC->CANtxBuff);
}
}
/* Synchronous PDOs are allowed only inside time window */
if(ObjDict_synchronousWindowLength){
if(SYNC->timer > ObjDict_synchronousWindowLength){
if(SYNC->curentSyncTimeIsInsideWindow){
ret = 2;
}
SYNC->curentSyncTimeIsInsideWindow = false;
}
else{
SYNC->curentSyncTimeIsInsideWindow = true;
}
}
else{
SYNC->curentSyncTimeIsInsideWindow = true;
}
/* Verify timeout of SYNC */
if(SYNC->periodTime && SYNC->timer > SYNC->periodTimeoutTime && *SYNC->operatingState == CO_NMT_OPERATIONAL)
CO_errorReport(SYNC->em, CO_EM_SYNC_TIME_OUT, CO_EMC_COMMUNICATION, SYNC->timer);
}
else {
CLEAR_CANrxNew(SYNC->CANrxNew);
}
/* verify error from receive function */
if(SYNC->receiveError != 0U){
CO_errorReport(SYNC->em, CO_EM_SYNC_LENGTH, CO_EMC_SYNC_DATA_LENGTH, (uint32_t)SYNC->receiveError);
SYNC->receiveError = 0U;
}
return ret;
}