feat: Add TIME producer and refactor TIME consumer
This commit is contained in:
parent
8bd037bb1b
commit
bba140f943
9 changed files with 290 additions and 229 deletions
37
CANopen.c
37
CANopen.c
|
|
@ -88,7 +88,7 @@
|
|||
|| CO_NO_SYNC != 1 \
|
||||
|| CO_NO_EMERGENCY != 1 \
|
||||
|| CO_NO_SDO_SERVER == 0 \
|
||||
|| CO_NO_TS > 1 \
|
||||
|| CO_NO_TIME > 1 \
|
||||
|| CO_NO_SDO_CLIENT > 128 \
|
||||
|| (CO_NO_RPDO < 1 || CO_NO_RPDO > 0x200) \
|
||||
|| (CO_NO_TPDO < 1 || CO_NO_TPDO > 0x200) \
|
||||
|
|
@ -112,25 +112,26 @@
|
|||
#define CO_RXCAN_NMT 0 /* index for NMT message */
|
||||
#define CO_RXCAN_SYNC 1 /* index for SYNC message */
|
||||
#define CO_RXCAN_EMERG (CO_RXCAN_SYNC+CO_NO_SYNC) /* index for Emergency message */
|
||||
#define CO_RXCAN_TS (CO_RXCAN_EMERG+CO_NO_EMERGENCY) /* index for TS message */
|
||||
#define CO_RXCAN_RPDO (CO_RXCAN_TS+CO_NO_TS) /* start index for RPDO messages */
|
||||
#define CO_RXCAN_TIME (CO_RXCAN_EMERG+CO_NO_EMERGENCY) /* index for TIME message */
|
||||
#define CO_RXCAN_RPDO (CO_RXCAN_TIME+CO_NO_TIME) /* start index for RPDO messages */
|
||||
#define CO_RXCAN_SDO_SRV (CO_RXCAN_RPDO+CO_NO_RPDO) /* start index for SDO server message (request) */
|
||||
#define CO_RXCAN_SDO_CLI (CO_RXCAN_SDO_SRV+CO_NO_SDO_SERVER) /* start index for SDO client message (response) */
|
||||
#define CO_RXCAN_CONS_HB (CO_RXCAN_SDO_CLI+CO_NO_SDO_CLIENT) /* start index for Heartbeat Consumer messages */
|
||||
#define CO_RXCAN_LSS (CO_RXCAN_CONS_HB+CO_NO_HB_CONS) /* index for LSS rx message */
|
||||
/* total number of received CAN messages */
|
||||
#define CO_RXCAN_NO_MSGS (1+CO_NO_SYNC+CO_NO_EMERGENCY+CO_NO_TS+CO_NO_RPDO+CO_NO_SDO_SERVER+CO_NO_SDO_CLIENT+CO_NO_HB_CONS)
|
||||
#define CO_RXCAN_NO_MSGS (1+CO_NO_SYNC+CO_NO_EMERGENCY+CO_NO_TIME+CO_NO_RPDO+CO_NO_SDO_SERVER+CO_NO_SDO_CLIENT+CO_NO_HB_CONS)
|
||||
|
||||
#define CO_TXCAN_NMT 0 /* index for NMT master message */
|
||||
#define CO_TXCAN_SYNC CO_TXCAN_NMT+CO_NO_NMT_MASTER /* index for SYNC message */
|
||||
#define CO_TXCAN_EMERG (CO_TXCAN_SYNC+CO_NO_SYNC) /* index for Emergency message */
|
||||
#define CO_TXCAN_TPDO (CO_TXCAN_EMERG+CO_NO_EMERGENCY) /* start index for TPDO messages */
|
||||
#define CO_TXCAN_TIME (CO_TXCAN_EMERG+CO_NO_EMERGENCY) /* index for TIME message */
|
||||
#define CO_TXCAN_TPDO (CO_TXCAN_TIME+CO_NO_TIME) /* start index for TPDO messages */
|
||||
#define CO_TXCAN_SDO_SRV (CO_TXCAN_TPDO+CO_NO_TPDO) /* start index for SDO server message (response) */
|
||||
#define CO_TXCAN_SDO_CLI (CO_TXCAN_SDO_SRV+CO_NO_SDO_SERVER) /* start index for SDO client message (request) */
|
||||
#define CO_TXCAN_HB (CO_TXCAN_SDO_CLI+CO_NO_SDO_CLIENT) /* index for Heartbeat message */
|
||||
#define CO_TXCAN_LSS (CO_TXCAN_HB+CO_NO_HB_PROD) /* index for LSS tx message */
|
||||
/* total number of transmitted CAN messages */
|
||||
#define CO_TXCAN_NO_MSGS (CO_NO_NMT_MASTER+CO_NO_SYNC+CO_NO_EMERGENCY+CO_NO_TPDO+CO_NO_SDO_SERVER+CO_NO_SDO_CLIENT+CO_NO_HB_PROD+CO_NO_LSS_SERVER+CO_NO_LSS_CLIENT)
|
||||
#define CO_TXCAN_NO_MSGS (CO_NO_NMT_MASTER+CO_NO_SYNC+CO_NO_EMERGENCY+CO_NO_TIME+CO_NO_TPDO+CO_NO_SDO_SERVER+CO_NO_SDO_CLIENT+CO_NO_HB_PROD+CO_NO_LSS_SERVER+CO_NO_LSS_CLIENT)
|
||||
|
||||
|
||||
#ifdef CO_USE_GLOBALS
|
||||
|
|
@ -143,7 +144,7 @@
|
|||
static CO_EMpr_t COO_EMpr;
|
||||
static CO_NMT_t COO_NMT;
|
||||
static CO_SYNC_t COO_SYNC;
|
||||
static CO_TS_t COO_TS;
|
||||
static CO_TIME_t COO_TIME;
|
||||
static CO_RPDO_t COO_RPDO[CO_NO_RPDO];
|
||||
static CO_TPDO_t COO_TPDO[CO_NO_TPDO];
|
||||
static CO_HBconsumer_t COO_HBcons;
|
||||
|
|
@ -247,7 +248,7 @@ CO_ReturnError_t CO_new(void)
|
|||
CO->emPr = &COO_EMpr;
|
||||
CO->NMT = &COO_NMT;
|
||||
CO->SYNC = &COO_SYNC;
|
||||
CO->TS = &COO_TS;
|
||||
CO->TIME = &COO_TIME;
|
||||
for(i=0; i<CO_NO_RPDO; i++)
|
||||
CO->RPDO[i] = &COO_RPDO[i];
|
||||
for(i=0; i<CO_NO_TPDO; i++)
|
||||
|
|
@ -287,7 +288,7 @@ CO_ReturnError_t CO_new(void)
|
|||
CO->emPr = (CO_EMpr_t *) calloc(1, sizeof(CO_EMpr_t));
|
||||
CO->NMT = (CO_NMT_t *) calloc(1, sizeof(CO_NMT_t));
|
||||
CO->SYNC = (CO_SYNC_t *) calloc(1, sizeof(CO_SYNC_t));
|
||||
CO->TS = (CO_TS_t *) calloc(1, sizeof(CO_TS_t));
|
||||
CO->TIME = (CO_TIME_t *) calloc(1, sizeof(CO_TIME_t));
|
||||
for(i=0; i<CO_NO_RPDO; i++){
|
||||
CO->RPDO[i] = (CO_RPDO_t *) calloc(1, sizeof(CO_RPDO_t));
|
||||
}
|
||||
|
|
@ -330,7 +331,7 @@ CO_ReturnError_t CO_new(void)
|
|||
+ sizeof(CO_EMpr_t)
|
||||
+ sizeof(CO_NMT_t)
|
||||
+ sizeof(CO_SYNC_t)
|
||||
+ sizeof(CO_TS_t)
|
||||
+ sizeof(CO_TIME_t)
|
||||
+ sizeof(CO_RPDO_t) * CO_NO_RPDO
|
||||
+ sizeof(CO_TPDO_t) * CO_NO_TPDO
|
||||
+ sizeof(CO_HBconsumer_t)
|
||||
|
|
@ -364,7 +365,7 @@ CO_ReturnError_t CO_new(void)
|
|||
if(CO->emPr == NULL) errCnt++;
|
||||
if(CO->NMT == NULL) errCnt++;
|
||||
if(CO->SYNC == NULL) errCnt++;
|
||||
if(CO->TS == NULL) errCnt++;
|
||||
if(CO->TIME == NULL) errCnt++;
|
||||
for(i=0; i<CO_NO_RPDO; i++){
|
||||
if(CO->RPDO[i] == NULL) errCnt++;
|
||||
}
|
||||
|
|
@ -565,15 +566,17 @@ CO_ReturnError_t CO_CANopenInit(
|
|||
|
||||
if(err){return err;}
|
||||
|
||||
err = CO_TS_init(
|
||||
CO->TS,
|
||||
err = CO_TIME_init(
|
||||
CO->TIME,
|
||||
CO->em,
|
||||
CO->SDO[0],
|
||||
&CO->NMT->operatingState,
|
||||
CO_CAN_ID_TIME_STAMP,
|
||||
OD_COB_ID_TIME,
|
||||
0,
|
||||
CO->CANmodule[0],
|
||||
CO_RXCAN_TS);
|
||||
CO_RXCAN_TIME,
|
||||
CO->CANmodule[0],
|
||||
CO_TXCAN_TIME);
|
||||
|
||||
if(err){return err;}
|
||||
|
||||
|
|
@ -819,8 +822,8 @@ CO_NMT_reset_cmd_t CO_process(
|
|||
timeDifference_ms);
|
||||
|
||||
|
||||
CO_TS_process(
|
||||
CO->TS,
|
||||
CO_TIME_process(
|
||||
CO->TIME,
|
||||
timeDifference_ms);
|
||||
|
||||
return reset;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ extern "C" {
|
|||
#include "CO_Emergency.h"
|
||||
#include "CO_NMT_Heartbeat.h"
|
||||
#include "CO_SYNC.h"
|
||||
#include "CO_TimeStamp.h"
|
||||
#include "CO_TIME.h"
|
||||
#include "CO_PDO.h"
|
||||
#include "CO_HBconsumer.h"
|
||||
#if CO_NO_SDO_CLIENT != 0
|
||||
|
|
@ -109,7 +109,7 @@ typedef enum{
|
|||
CO_CAN_ID_NMT_SERVICE = 0x000, /**< 0x000, Network management */
|
||||
CO_CAN_ID_SYNC = 0x080, /**< 0x080, Synchronous message */
|
||||
CO_CAN_ID_EMERGENCY = 0x080, /**< 0x080, Emergency messages (+nodeID) */
|
||||
CO_CAN_ID_TIME_STAMP = 0x100, /**< 0x100, Time stamp message */
|
||||
CO_CAN_ID_TIME = 0x100, /**< 0x100, Time message */
|
||||
CO_CAN_ID_TPDO_1 = 0x180, /**< 0x180, Default TPDO1 (+nodeID) */
|
||||
CO_CAN_ID_RPDO_1 = 0x200, /**< 0x200, Default RPDO1 (+nodeID) */
|
||||
CO_CAN_ID_TPDO_2 = 0x280, /**< 0x280, Default TPDO2 (+nodeID) */
|
||||
|
|
@ -136,7 +136,7 @@ typedef struct{
|
|||
CO_EMpr_t *emPr; /**< Emergency process object */
|
||||
CO_NMT_t *NMT; /**< NMT object */
|
||||
CO_SYNC_t *SYNC; /**< SYNC object */
|
||||
CO_TS_t *TS; /**< TS object */
|
||||
CO_TIME_t *TIME; /**< TIME object */
|
||||
CO_RPDO_t *RPDO[CO_NO_RPDO];/**< RPDO objects */
|
||||
CO_TPDO_t *TPDO[CO_NO_TPDO];/**< TPDO objects */
|
||||
CO_HBconsumer_t *HBcons; /**< Heartbeat consumer object*/
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ CANopen Features
|
|||
- SDO master.
|
||||
- Emergency message.
|
||||
- Sync producer/consumer.
|
||||
- Time protocol (Time stamp).
|
||||
- Time protocol (producer/consumer).
|
||||
- Non-volatile storage.
|
||||
- LSS master and slave, LSS fastscan
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ File structure
|
|||
- **CO_LSSmaster.h/.c** - CANopen LSS master functionality.
|
||||
- **CO_LSSslave.h/.c** - CANopen LSS slave functionality.
|
||||
- **CO_SYNC.h/.c** - CANopen SYNC producer and consumer object.
|
||||
- **CO_TimeStamp.h/.c** - CANopen TIME protocol object.
|
||||
- **CO_TIME.h/.c** - CANopen TIME protocol object.
|
||||
- **CO_SDO.h/.c** - CANopen SDO server object. It serves data from Object dictionary.
|
||||
- **CO_PDO.h/.c** - CANopen PDO object. It configures, receives and transmits CANopen process data.
|
||||
- **CO_SDOmaster.h/.c** - CANopen SDO client object (master functionality).
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ struct sCO_OD_EEPROM CO_OD_EEPROM = {
|
|||
/*1008*/ {'C', 'A', 'N', 'o', 'p', 'e', 'n', 'N', 'o', 'd', 'e'},
|
||||
/*1009*/ {'3', '.', '0', '0'},
|
||||
/*100A*/ {'3', '.', '0', '0'},
|
||||
/*1012*/ 0x80000100L,
|
||||
/*1014*/ 0x80L,
|
||||
/*1015*/ 0x64,
|
||||
/*1016*/ {0x0L, 0x0L, 0x0L, 0x0L},
|
||||
|
|
@ -312,6 +313,7 @@ const CO_OD_entry_t CO_OD[CO_OD_NoOfElements] = {
|
|||
{0x100A, 0x00, 0x05, 4, (void*)&CO_OD_ROM.manufacturerSoftwareVersion[0]},
|
||||
{0x1010, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.storeParameters[0]},
|
||||
{0x1011, 0x01, 0x8E, 4, (void*)&CO_OD_RAM.restoreDefaultParameters[0]},
|
||||
{0x1012, 0x00, 0x85, 4, (void*)&CO_OD_ROM.COB_ID_TIME},
|
||||
{0x1014, 0x00, 0x85, 4, (void*)&CO_OD_ROM.COB_ID_EMCY},
|
||||
{0x1015, 0x00, 0x8D, 2, (void*)&CO_OD_ROM.inhibitTimeEMCY},
|
||||
{0x1016, 0x04, 0x8D, 4, (void*)&CO_OD_ROM.consumerHeartbeatTime[0]},
|
||||
|
|
|
|||
|
|
@ -70,6 +70,21 @@
|
|||
typedef char_t VISIBLE_STRING;
|
||||
typedef oChar_t OCTET_STRING;
|
||||
typedef domain_t DOMAIN;
|
||||
|
||||
#ifndef timeOfDay_t
|
||||
typedef union {
|
||||
unsigned long long ullValue;
|
||||
struct {
|
||||
unsigned long ms:28;
|
||||
unsigned reserved:4;
|
||||
unsigned days:16;
|
||||
unsigned reserved2:16;
|
||||
};
|
||||
}timeOfDay_t;
|
||||
#endif
|
||||
|
||||
typedef timeOfDay_t TIME_OF_DAY;
|
||||
typedef timeOfDay_t TIME_DIFFERENCE;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
@ -95,7 +110,7 @@
|
|||
FEATURES
|
||||
*******************************************************************************/
|
||||
#define CO_NO_SYNC 1 //Associated objects: 1005, 1006, 1007, 2103, 2104
|
||||
#define CO_NO_TS 1 //Associated objects: 1012-1013
|
||||
#define CO_NO_TIME 1 //Associated objects: 1012-1013
|
||||
#define CO_NO_EMERGENCY 1 //Associated objects: 1014, 1015
|
||||
#define CO_NO_SDO_SERVER 1 //Associated objects: 1200
|
||||
#define CO_NO_SDO_CLIENT 0
|
||||
|
|
@ -239,6 +254,7 @@ struct sCO_OD_ROM{
|
|||
/*1008 */ VISIBLE_STRING manufacturerDeviceName[11];
|
||||
/*1009 */ VISIBLE_STRING manufacturerHardwareVersion[4];
|
||||
/*100A */ VISIBLE_STRING manufacturerSoftwareVersion[4];
|
||||
/*1012 */ UNSIGNED32 COB_ID_TIME;
|
||||
/*1014 */ UNSIGNED32 COB_ID_EMCY;
|
||||
/*1015 */ UNSIGNED16 inhibitTimeEMCY;
|
||||
/*1016 */ UNSIGNED32 consumerHeartbeatTime[4];
|
||||
|
|
@ -315,6 +331,9 @@ extern struct sCO_OD_ROM CO_OD_ROM;
|
|||
#define ODL_restoreDefaultParameters_arrayLength 1
|
||||
#define ODA_restoreDefaultParameters_restoreAllDefaultParameters 0
|
||||
|
||||
/*1012, Data Type: UNSIGNED32 */
|
||||
#define OD_COB_ID_TIME CO_OD_ROM.COB_ID_TIME
|
||||
|
||||
/*1014, Data Type: UNSIGNED32 */
|
||||
#define OD_COB_ID_EMCY CO_OD_ROM.COB_ID_EMCY
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ typedef enum{
|
|||
#define CO_EMC_DAM_MPDO 0x8230U /**< 0x8230, DAM MPDO not processed, destination object not available */
|
||||
#define CO_EMC_SYNC_DATA_LENGTH 0x8240U /**< 0x8240, Unexpected SYNC data length */
|
||||
#define CO_EMC_RPDO_TIMEOUT 0x8250U /**< 0x8250, RPDO timeout */
|
||||
#define CO_EMC_TS_DATA_LENGTH 0x8260U /**< 0x8260, Unexpected TS data length */
|
||||
#define CO_EMC_TIME_DATA_LENGTH 0x8260U /**< 0x8260, Unexpected TIME data length */
|
||||
#define CO_EMC_EXTERNAL_ERROR 0x9000U /**< 0x90xx, External Error */
|
||||
#define CO_EMC_ADDITIONAL_FUNC 0xF000U /**< 0xF0xx, Additional Functions */
|
||||
#define CO_EMC_DEVICE_SPECIFIC 0xFF00U /**< 0xFFxx, Device specific */
|
||||
|
|
@ -211,8 +211,8 @@ typedef enum{
|
|||
#define CO_EM_CAN_RX_BUS_PASSIVE 0x06U /**< 0x06, communication, info, CAN receive bus is passive */
|
||||
#define CO_EM_CAN_TX_BUS_PASSIVE 0x07U /**< 0x07, communication, info, CAN transmit bus is passive */
|
||||
#define CO_EM_NMT_WRONG_COMMAND 0x08U /**< 0x08, communication, info, Wrong NMT command received */
|
||||
#define CO_EM_TS_TIME_OUT 0x09U /**< 0x09, communication, info, Time stamp message timeout */
|
||||
#define CO_EM_TS_LENGTH 0x0AU /**< 0x0A, communication, info, Unexpected Time stamp data length */
|
||||
#define CO_EM_TIME_TIMEOUT 0x09U /**< 0x09, communication, info, TIME message timeout */
|
||||
#define CO_EM_TIME_LENGTH 0x0AU /**< 0x0A, communication, info, Unexpected TIME data length */
|
||||
#define CO_EM_0B_unused 0x0BU /**< 0x0B, (unused) */
|
||||
#define CO_EM_0C_unused 0x0CU /**< 0x0C, (unused) */
|
||||
#define CO_EM_0D_unused 0x0DU /**< 0x0D, (unused) */
|
||||
|
|
|
|||
185
stack/CO_TIME.c
Normal file
185
stack/CO_TIME.c
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* CANopen TIME object.
|
||||
*
|
||||
* @file CO_TIME.c
|
||||
* @ingroup CO_TIME
|
||||
* @author Julien PEYREGNE
|
||||
* @copyright
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* CANopenNode is free and open source software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Following clarification and special exception to the GNU General Public
|
||||
* License is included to the distribution terms of CANopenNode:
|
||||
*
|
||||
* Linking this library statically or dynamically with other modules is
|
||||
* making a combined work based on this library. Thus, the terms and
|
||||
* conditions of the GNU General Public License cover the whole combination.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give
|
||||
* you permission to link this library with independent modules to
|
||||
* produce an executable, regardless of the license terms of these
|
||||
* independent modules, and to copy and distribute the resulting
|
||||
* executable under terms of your choice, provided that you also meet,
|
||||
* for each linked independent module, the terms and conditions of the
|
||||
* license of that module. An independent module is a module which is
|
||||
* not derived from or based on this library. If you modify this
|
||||
* library, you may extend this exception to your version of the
|
||||
* library, but you are not obliged to do so. If you do not wish
|
||||
* to do so, delete this exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "CANopen.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.
|
||||
*/
|
||||
static void CO_TIME_receive(void *object, const CO_CANrxMsg_t *msg){
|
||||
CO_TIME_t *TIME;
|
||||
uint8_t operState;
|
||||
|
||||
TIME = (CO_TIME_t*)object; /* this is the correct pointer type of the first argument */
|
||||
operState = *TIME->operatingState;
|
||||
|
||||
if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){
|
||||
SET_CANrxNew(TIME->CANrxNew);
|
||||
// Process Time from msg buffer
|
||||
CO_memcpy((uint8_t*)&TIME->Time.ullValue, msg->data, msg->DLC);
|
||||
}
|
||||
else{
|
||||
TIME->receiveError = (uint16_t)msg->DLC;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
CO_ReturnError_t CO_TIME_init(
|
||||
CO_TIME_t *TIME,
|
||||
CO_EM_t *em,
|
||||
CO_SDO_t *SDO,
|
||||
uint8_t *operatingState,
|
||||
uint32_t COB_ID_TIMEMessage,
|
||||
uint32_t TIMECyclePeriod,
|
||||
CO_CANmodule_t *CANdevRx,
|
||||
uint16_t CANdevRxIdx,
|
||||
CO_CANmodule_t *CANdevTx,
|
||||
uint16_t CANdevTxIdx)
|
||||
{
|
||||
/* verify arguments */
|
||||
if(TIME==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
|
||||
CANdevRx==NULL || CANdevTx==NULL){
|
||||
return CO_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
/* Configure object variables */
|
||||
TIME->isConsumer = (COB_ID_TIMEMessage&0x80000000L) ? true : false;
|
||||
TIME->isProducer = (COB_ID_TIMEMessage&0x40000000L) ? true : false;
|
||||
TIME->COB_ID = COB_ID_TIMEMessage&0x7FF; // 11 bit ID
|
||||
|
||||
TIME->periodTime = TIMECyclePeriod;
|
||||
TIME->periodTimeoutTime = TIMECyclePeriod / 2 * 3;
|
||||
/* overflow? */
|
||||
if(TIME->periodTimeoutTime < TIMECyclePeriod)
|
||||
TIME->periodTimeoutTime = 0xFFFFFFFFL;
|
||||
|
||||
CLEAR_CANrxNew(TIME->CANrxNew);
|
||||
TIME->timer = 0;
|
||||
TIME->receiveError = 0U;
|
||||
|
||||
TIME->em = em;
|
||||
TIME->operatingState = operatingState;
|
||||
|
||||
|
||||
/* configure TIME consumer message reception */
|
||||
TIME->CANdevRx = CANdevRx;
|
||||
TIME->CANdevRxIdx = CANdevRxIdx;
|
||||
if(TIME->isConsumer)
|
||||
CO_CANrxBufferInit(
|
||||
CANdevRx, /* CAN device */
|
||||
CANdevRxIdx, /* rx buffer index */
|
||||
TIME->COB_ID, /* CAN identifier */
|
||||
0x7FF, /* mask */
|
||||
0, /* rtr */
|
||||
(void*)TIME, /* object passed to receive function */
|
||||
CO_TIME_receive); /* this function will process received message */
|
||||
|
||||
|
||||
/* configure TIME producer message transmission */
|
||||
TIME->CANdevTx = CANdevTx;
|
||||
TIME->CANdevTxIdx = CANdevTxIdx;
|
||||
if(TIME->isProducer)
|
||||
TIME->TXbuff = CO_CANtxBufferInit(
|
||||
CANdevTx, /* CAN device */
|
||||
CANdevTxIdx, /* index of specific buffer inside CAN module */
|
||||
TIME->COB_ID, /* CAN identifier */
|
||||
0, /* rtr */
|
||||
TIME_MSG_LENGTH, /* number of data bytes */
|
||||
0); /* synchronous message flag bit */
|
||||
|
||||
return CO_ERROR_NO;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
uint8_t CO_TIME_process(
|
||||
CO_TIME_t *TIME,
|
||||
uint32_t timeDifference_ms)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
uint32_t timerNew;
|
||||
|
||||
if(*TIME->operatingState == CO_NMT_OPERATIONAL || *TIME->operatingState == CO_NMT_PRE_OPERATIONAL){
|
||||
/* update TIME timer, no overflow */
|
||||
timerNew = TIME->timer + timeDifference_ms;
|
||||
if(timerNew > TIME->timer)
|
||||
TIME->timer = timerNew;
|
||||
|
||||
/* was TIME just received */
|
||||
if(TIME->CANrxNew){
|
||||
TIME->timer = 0;
|
||||
ret = 1;
|
||||
TIME->CANrxNew = false;
|
||||
}
|
||||
|
||||
/* TIME producer */
|
||||
if(TIME->isProducer && TIME->periodTime){
|
||||
if(TIME->timer >= TIME->periodTime){
|
||||
TIME->timer = 0;
|
||||
ret = 1;
|
||||
CO_memcpy(TIME->TXbuff->data, (const uint8_t*)&TIME->Time.ullValue, TIME_MSG_LENGTH);
|
||||
CO_CANsend(TIME->CANdevTx, TIME->TXbuff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify TIME timeout if node is consumer */
|
||||
if(TIME->isConsumer && TIME->periodTime && TIME->timer > TIME->periodTimeoutTime
|
||||
&& *TIME->operatingState == CO_NMT_OPERATIONAL)
|
||||
CO_errorReport(TIME->em, CO_EM_TIME_TIMEOUT, CO_EMC_COMMUNICATION, TIME->timer);
|
||||
}
|
||||
else {
|
||||
CLEAR_CANrxNew(TIME->CANrxNew);
|
||||
}
|
||||
|
||||
/* verify error from receive function */
|
||||
if(TIME->receiveError != 0U){
|
||||
CO_errorReport(TIME->em, CO_EM_TIME_LENGTH, CO_EMC_TIME_DATA_LENGTH, (uint32_t)TIME->receiveError);
|
||||
TIME->receiveError = 0U;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* CANopen TimeStamp object protocol.
|
||||
* CANopen TIME object protocol.
|
||||
*
|
||||
* @file CO_TimeStamp.c
|
||||
* @ingroup CO_TimeStamp
|
||||
* @file CO_TIME.c
|
||||
* @ingroup CO_TIME
|
||||
* @author Julien PEYREGNE
|
||||
* @copyright
|
||||
*
|
||||
|
|
@ -44,8 +44,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef CO_TS_H
|
||||
#define CO_TS_H
|
||||
#ifndef CO_TIME_H
|
||||
#define CO_TIME_H
|
||||
|
||||
#include "CO_OD.h"
|
||||
|
||||
|
|
@ -55,84 +55,100 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup CO_TS TS
|
||||
* @defgroup CO_TIME TIME
|
||||
* @ingroup CO_CANopen
|
||||
* @{
|
||||
*
|
||||
* CANopen TimeStamp object protocol.
|
||||
* CANopen TIME object protocol.
|
||||
*
|
||||
* For CAN identifier see #CO_Default_CAN_ID_t
|
||||
*
|
||||
* TIME message is used for time synchronization of the nodes on network. One node
|
||||
* should be TIME producer, others can be TIME consumers. This is configured with
|
||||
* COB_ID_TIME object 0x1012 :
|
||||
*
|
||||
* - bit 31 should be set for a consumer
|
||||
* - bit 30 should be set for a producer
|
||||
*
|
||||
* TS message is used for time synchronization of the nodes on network. One node
|
||||
* should be TS producer, others can be TS consumers.
|
||||
*/
|
||||
|
||||
#define EMCY_MSG_LENGTH 6U
|
||||
#define TIME_MSG_LENGTH 6U
|
||||
|
||||
/**
|
||||
* TS producer and consumer object.
|
||||
* TIME producer and consumer object.
|
||||
*/
|
||||
typedef struct{
|
||||
CO_EM_t *em; /**< From CO_TS_init() */
|
||||
uint8_t *operatingState; /**< From CO_TS_init() */
|
||||
uint16_t COB_ID; /**< From CO_TS_init() */
|
||||
/** TS period time in [milliseconds]. Set to TS period to enable
|
||||
CO_EM_t *em; /**< From CO_TIME_init() */
|
||||
uint8_t *operatingState; /**< From CO_TIME_init() */
|
||||
/** True, if device is TIME consumer. Calculated from _COB ID TIME Message_
|
||||
variable from Object dictionary (index 0x1012). */
|
||||
bool_t isConsumer;
|
||||
/** True, if device is TIME producer. Calculated from _COB ID TIME Message_
|
||||
variable from Object dictionary (index 0x1012). */
|
||||
bool_t isProducer;
|
||||
uint16_t COB_ID; /**< From CO_TIME_init() */
|
||||
/** TIME period time in [milliseconds]. Set to TIME period to enable
|
||||
timeout detection */
|
||||
uint32_t periodTime;
|
||||
/** TS period timeout time in [milliseconds].
|
||||
/** TIME period timeout time in [milliseconds].
|
||||
(periodTimeoutTime = periodTime * 1,5) */
|
||||
uint32_t periodTimeoutTime;
|
||||
/** Variable indicates, if new TS message received from CAN bus */
|
||||
bool_t CANrxNew;
|
||||
/** Timer for the TS message in [microseconds].
|
||||
Set to zero after received or transmitted TS message */
|
||||
/** Variable indicates, if new TIME message received from CAN bus */
|
||||
volatile void *CANrxNew;
|
||||
/** Timer for the TIME message in [microseconds].
|
||||
Set to zero after received or transmitted TIME message */
|
||||
uint32_t timer;
|
||||
/** Set to nonzero value, if TS with wrong data length is received from CAN */
|
||||
/** Set to nonzero value, if TIME with wrong data length is received from CAN */
|
||||
uint16_t receiveError;
|
||||
CO_CANmodule_t *CANdevRx; /**< From CO_TS_init() */
|
||||
uint16_t CANdevRxIdx; /**< From CO_TS_init() */
|
||||
CO_CANmodule_t *CANdevRx; /**< From CO_TIME_init() */
|
||||
uint16_t CANdevRxIdx; /**< From CO_TIME_init() */
|
||||
CO_CANmodule_t *CANdevTx; /**< From CO_TIME_init() */
|
||||
uint16_t CANdevTxIdx; /**< From CO_TIME_init() */
|
||||
CO_CANtx_t *TXbuff; /**< CAN transmit buffer */
|
||||
TIME_OF_DAY Time;
|
||||
}CO_TS_t;
|
||||
}CO_TIME_t;
|
||||
|
||||
/**
|
||||
* Initialize TS object.
|
||||
* Initialize TIME object.
|
||||
*
|
||||
* Function must be called in the communication reset section.
|
||||
*
|
||||
* @param TS This object will be initialized.
|
||||
* @param TIME This object will be initialized.
|
||||
* @param em Emergency object.
|
||||
* @param SDO SDO server object.
|
||||
* @param operatingState Pointer to variable indicating CANopen device NMT internal state.
|
||||
* @param COB_ID_TSMessage Should be intialized with CO_CAN_ID_TIME_STAMP
|
||||
* @param TSCyclePeriod Set to TS period to enable timeout detection (1,5x period) or 0.
|
||||
* @param CANdevRx CAN device for TS reception.
|
||||
* @param COB_ID_TIMEMessage Should be intialized with CO_CAN_ID_TIME_STAMP
|
||||
* @param TIMECyclePeriod Set to TIME period to enable timeout detection (1,5x period) or 0.
|
||||
* @param CANdevRx CAN device for TIME reception.
|
||||
* @param CANdevRxIdx Index of receive buffer in the above CAN device.
|
||||
*
|
||||
* @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT.
|
||||
*/
|
||||
CO_ReturnError_t CO_TS_init(
|
||||
CO_TS_t *TS,
|
||||
CO_ReturnError_t CO_TIME_init(
|
||||
CO_TIME_t *TIME,
|
||||
CO_EM_t *em,
|
||||
CO_SDO_t *SDO,
|
||||
uint8_t *operatingState,
|
||||
uint32_t COB_ID_TSMessage,
|
||||
uint32_t TSCyclePeriod,
|
||||
uint32_t COB_ID_TIMEMessage,
|
||||
uint32_t TIMECyclePeriod,
|
||||
CO_CANmodule_t *CANdevRx,
|
||||
uint16_t CANdevRxIdx);
|
||||
uint16_t CANdevRxIdx,
|
||||
CO_CANmodule_t *CANdevTx,
|
||||
uint16_t CANdevTxIdx);
|
||||
|
||||
/**
|
||||
* Process Timestamp communication.
|
||||
* Process TIME communication.
|
||||
*
|
||||
* Function must be called cyclically.
|
||||
*
|
||||
* @param TS This object.
|
||||
* @param TIME This object.
|
||||
* @param timeDifference_ms Time difference from previous function call in [milliseconds].
|
||||
*
|
||||
* @return 0: No special meaning.
|
||||
* @return 1: New TS message recently received.
|
||||
* @return 1: New TIME message recently received.
|
||||
*/
|
||||
uint8_t CO_TS_process(
|
||||
CO_TS_t *TS,
|
||||
uint8_t CO_TIME_process(
|
||||
CO_TIME_t *TIME,
|
||||
uint32_t timeDifference_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* CANopen TimeStamp object.
|
||||
*
|
||||
* @file CO_TimeStamp.c
|
||||
* @ingroup CO_TimeStamp
|
||||
* @author Julien PEYREGNE
|
||||
* @copyright
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* CANopenNode is free and open source software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation, either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Following clarification and special exception to the GNU General Public
|
||||
* License is included to the distribution terms of CANopenNode:
|
||||
*
|
||||
* Linking this library statically or dynamically with other modules is
|
||||
* making a combined work based on this library. Thus, the terms and
|
||||
* conditions of the GNU General Public License cover the whole combination.
|
||||
*
|
||||
* As a special exception, the copyright holders of this library give
|
||||
* you permission to link this library with independent modules to
|
||||
* produce an executable, regardless of the license terms of these
|
||||
* independent modules, and to copy and distribute the resulting
|
||||
* executable under terms of your choice, provided that you also meet,
|
||||
* for each linked independent module, the terms and conditions of the
|
||||
* license of that module. An independent module is a module which is
|
||||
* not derived from or based on this library. If you modify this
|
||||
* library, you may extend this exception to your version of the
|
||||
* library, but you are not obliged to do so. If you do not wish
|
||||
* to do so, delete this exception statement from your version.
|
||||
*/
|
||||
|
||||
#include "CANopen.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_TS_receive(void *object, const CO_CANrxMsg_t *msg){
|
||||
CO_TS_t *TS;
|
||||
uint8_t operState;
|
||||
int i = 0;
|
||||
TIME_OF_DAY TempTime;
|
||||
|
||||
TS = (CO_TS_t*)object; /* this is the correct pointer type of the first argument */
|
||||
operState = *TS->operatingState;
|
||||
|
||||
if((operState == CO_NMT_OPERATIONAL) || (operState == CO_NMT_PRE_OPERATIONAL)){
|
||||
if(msg->DLC == EMCY_MSG_LENGTH){
|
||||
TS->CANrxNew = true;
|
||||
// Process Time from msg buffer
|
||||
TempTime.ullValue = 0;
|
||||
for(i=0; i<msg->DLC; i++)
|
||||
TempTime.ullValue += (unsigned long long)msg->data[i] << 8*i;
|
||||
TS->Time.ullValue = TempTime.ullValue;
|
||||
}
|
||||
else{
|
||||
TS->receiveError = (uint16_t)msg->DLC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
CO_ReturnError_t CO_TS_init(
|
||||
CO_TS_t *TS,
|
||||
CO_EM_t *em,
|
||||
CO_SDO_t *SDO,
|
||||
uint8_t *operatingState,
|
||||
uint32_t COB_ID_TSMessage,
|
||||
uint32_t TSCyclePeriod,
|
||||
CO_CANmodule_t *CANdevRx,
|
||||
uint16_t CANdevRxIdx)
|
||||
{
|
||||
/* verify arguments */
|
||||
if(TS==NULL || em==NULL || SDO==NULL || operatingState==NULL ||
|
||||
CANdevRx==NULL){
|
||||
return CO_ERROR_ILLEGAL_ARGUMENT;
|
||||
}
|
||||
|
||||
/* Configure object variables */
|
||||
TS->COB_ID = COB_ID_TSMessage&0x7FF;
|
||||
|
||||
TS->periodTime = TSCyclePeriod;
|
||||
TS->periodTimeoutTime = TSCyclePeriod / 2 * 3;
|
||||
/* overflow? */
|
||||
if(TS->periodTimeoutTime < TSCyclePeriod)
|
||||
TS->periodTimeoutTime = 0xFFFFFFFFL;
|
||||
|
||||
TS->CANrxNew = false;
|
||||
TS->timer = 0;
|
||||
TS->receiveError = 0U;
|
||||
|
||||
TS->em = em;
|
||||
TS->operatingState = operatingState;
|
||||
|
||||
TS->CANdevRx = CANdevRx;
|
||||
TS->CANdevRxIdx = CANdevRxIdx;
|
||||
|
||||
/* configure TS CAN reception */
|
||||
CO_CANrxBufferInit(
|
||||
CANdevRx, /* CAN device */
|
||||
CANdevRxIdx, /* rx buffer index */
|
||||
TS->COB_ID, /* CAN identifier */
|
||||
0x7FF, /* mask */
|
||||
0, /* rtr */
|
||||
(void*)TS, /* object passed to receive function */
|
||||
CO_TS_receive); /* this function will process received message */
|
||||
|
||||
return CO_ERROR_NO;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
uint8_t CO_TS_process(
|
||||
CO_TS_t *TS,
|
||||
uint32_t timeDifference_ms)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
uint32_t timerNew;
|
||||
|
||||
if(*TS->operatingState == CO_NMT_OPERATIONAL || *TS->operatingState == CO_NMT_PRE_OPERATIONAL){
|
||||
/* update timestamp timer, no overflow */
|
||||
timerNew = TS->timer + timeDifference_ms;
|
||||
if(timerNew > TS->timer)
|
||||
TS->timer = timerNew;
|
||||
|
||||
/* was TS just received */
|
||||
if(TS->CANrxNew){
|
||||
TS->timer = 0;
|
||||
ret = 1;
|
||||
TS->CANrxNew = false;
|
||||
}
|
||||
|
||||
/* Verify timeout of TS */
|
||||
if(TS->periodTime && TS->timer > TS->periodTimeoutTime && *TS->operatingState == CO_NMT_OPERATIONAL)
|
||||
CO_errorReport(TS->em, CO_EM_TS_TIME_OUT, CO_EMC_COMMUNICATION, TS->timer);
|
||||
}
|
||||
else {
|
||||
TS->CANrxNew = false;
|
||||
}
|
||||
|
||||
/* verify error from receive function */
|
||||
if(TS->receiveError != 0U){
|
||||
CO_errorReport(TS->em, CO_EM_TS_LENGTH, CO_EMC_TS_DATA_LENGTH, (uint32_t)TS->receiveError);
|
||||
TS->receiveError = 0U;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
Loading…
Reference in a new issue