1
0
Fork 0

Add LSS master into gateway-ascii (CiA309).

- Rename local variable 'token' into 'tok' in CO_GTWA_process().
- CO_LSSmaster: replace CO_LSSmaster_InquireNodeId() with more generic
  CO_LSSmaster_Inquire(). CiA309-3 command 'lss_inquire_addr' now works
  also according to standard.
- CANopen.h: fix doxygen.
- gettingStarted.md: Change example "master" device from node-Id=3 to 1...
This commit is contained in:
Janez 2020-05-31 13:08:35 +02:00
parent ae220f9115
commit 92a803f169
6 changed files with 806 additions and 130 deletions

View file

@ -54,7 +54,7 @@ typedef enum {
CO_LSSmaster_COMMAND_INQUIRE_PRODUCT,
CO_LSSmaster_COMMAND_INQUIRE_REV,
CO_LSSmaster_COMMAND_INQUIRE_SERIAL,
CO_LSSmaster_COMMAND_INQUIRE_NODE_ID,
CO_LSSmaster_COMMAND_INQUIRE,
CO_LSSmaster_COMMAND_IDENTIFY_FASTSCAN,
} CO_LSSmaster_command_t;
@ -107,7 +107,7 @@ static void CO_LSSmaster_receive(void *object, void *msg)
* or after the timeout expired. Only if no message has been received we have
* to check for timeouts
*/
static CO_LSSmaster_return_t CO_LSSmaster_check_timeout(
static inline CO_LSSmaster_return_t CO_LSSmaster_check_timeout(
CO_LSSmaster_t *LSSmaster,
uint32_t timeDifference_us)
{
@ -709,14 +709,15 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(
/******************************************************************************/
CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId(
CO_LSSmaster_return_t CO_LSSmaster_Inquire(
CO_LSSmaster_t *LSSmaster,
uint32_t timeDifference_us,
uint8_t *nodeId)
CO_LSS_cs_t lssInquireCs,
uint32_t *value)
{
CO_LSSmaster_return_t ret = CO_LSSmaster_INVALID_STATE;
if (LSSmaster==NULL || nodeId==NULL){
if (LSSmaster==NULL || value==NULL){
return CO_LSSmaster_ILLEGAL_ARGUMENT;
}
@ -725,19 +726,15 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId(
LSSmaster->state==CO_LSSmaster_STATE_CFG_GLOBAL) &&
LSSmaster->command == CO_LSSmaster_COMMAND_WAITING) {
LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE_NODE_ID;
LSSmaster->command = CO_LSSmaster_COMMAND_INQUIRE;
LSSmaster->timeoutTimer = 0;
ret = CO_LSSmaster_inquireInitiate(LSSmaster, CO_LSS_INQUIRE_NODE_ID);
ret = CO_LSSmaster_inquireInitiate(LSSmaster, lssInquireCs);
}
/* Check for reply */
else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE_NODE_ID) {
uint32_t tmp = 0;
else if (LSSmaster->command == CO_LSSmaster_COMMAND_INQUIRE) {
ret = CO_LSSmaster_inquireCheckWait(LSSmaster, timeDifference_us,
CO_LSS_INQUIRE_NODE_ID, &tmp);
*nodeId = tmp & 0xff;
lssInquireCs, value);
}
if (ret != CO_LSSmaster_WAIT_SLAVE) {

View file

@ -131,7 +131,9 @@ typedef struct{
* Default timeout for LSS slave in ms. This is the same as for SDO. For more
* info about LSS timeout see #CO_LSSmaster_changeTimeout()
*/
#ifndef CO_LSSmaster_DEFAULT_TIMEOUT
#define CO_LSSmaster_DEFAULT_TIMEOUT 1000U /* ms */
#endif
/**
@ -364,9 +366,10 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(
/**
* Request LSS inquire node ID
* Request LSS inquire node ID or part of LSS address
*
* The node ID value is read from the node.
* The node-ID, identity vendor-ID, product-code, revision-number or
* serial-number value is read from the node.
*
* This function needs one specific node to be selected.
*
@ -376,14 +379,16 @@ CO_LSSmaster_return_t CO_LSSmaster_InquireLssAddress(
* @param LSSmaster This object.
* @param timeDifference_us Time difference from previous function call in
* [microseconds]. Zero when request is started.
* @param [out] nodeId read result when function returns successfully
* @param lssInquireCs One of CO_LSS_INQUIRE_xx commands from #CO_LSS_cs_t.
* @param [out] value read result when function returns successfully
* @return #CO_LSSmaster_ILLEGAL_ARGUMENT, #CO_LSSmaster_INVALID_STATE,
* #CO_LSSmaster_WAIT_SLAVE, #CO_LSSmaster_OK, #CO_LSSmaster_TIMEOUT
*/
CO_LSSmaster_return_t CO_LSSmaster_InquireNodeId(
CO_LSSmaster_return_t CO_LSSmaster_Inquire(
CO_LSSmaster_t *LSSmaster,
uint32_t timeDifference_us,
uint8_t *nodeId);
CO_LSS_cs_t lssInquireCs,
uint32_t *value);
/**

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,10 @@
/**
* CANopen access from other networks - ASCII mapping (CiA 309-3 DS v2.1.0)
* CANopen access from other networks - ASCII mapping (CiA 309-3 DS v3.0.0)
*
* @file CO_gateway_ascii.h
* @ingroup CO_CANopen_309_3
* @author Janez Paternoster
* @author Martin Wagner
* @copyright 2020 Janez Paternoster
*
* This file is part of CANopenNode, an opensource CANopen Stack.
@ -212,6 +213,24 @@ typedef enum {
CO_GTWA_ST_READ = 0x10U,
/** SDO 'write' (download) */
CO_GTWA_ST_WRITE = 0x11U,
/** LSS 'lss_switch_glob' */
CO_GTWA_ST_LSS_SWITCH_GLOB = 0x20U,
/** LSS 'lss_switch_sel' */
CO_GTWA_ST_LSS_SWITCH_SEL = 0x21U,
/** LSS 'lss_set_node' */
CO_GTWA_ST_LSS_SET_NODE = 0x22U,
/** LSS 'lss_conf_bitrate' */
CO_GTWA_ST_LSS_CONF_BITRATE = 0x23U,
/** LSS 'lss_store' */
CO_GTWA_ST_LSS_STORE = 0x24U,
/** LSS 'lss_inquire_addr' or 'lss_get_node' */
CO_GTWA_ST_LSS_INQUIRE = 0x25U,
/** LSS 'lss_inquire_addr', all parameters */
CO_GTWA_ST_LSS_INQUIRE_ADDR_ALL = 0x26U,
/** LSS '_lss_fastscan' */
CO_GTWA_ST__LSS_FASTSCAN = 0x30U,
/** LSS 'lss_allnodes' */
CO_GTWA_ST_LSS_ALLNODES = 0x31U,
/** print message log */
CO_GTWA_ST_LOG = 0x80U,
/** print 'help' text */
@ -312,8 +331,26 @@ typedef struct {
CO_NMT_t *NMT;
#endif
#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LSS) || defined CO_DOXYGEN
/** LSS object from CO_GTWA_init() */
CO_LSSmaster_t *LSS;
/** LSSmaster object from CO_GTWA_init() */
CO_LSSmaster_t *LSSmaster;
/** 128 bit number, uniquely identifying each node */
CO_LSS_address_t lssAddress;
/** LSS Node-ID parameter */
uint8_t lssNID;
/** LSS bitrate parameter */
uint16_t lssBitrate;
/** LSS inquire parameter */
CO_LSS_cs_t lssInquireCs;
/** LSS fastscan parameter */
CO_LSSmaster_fastscan_t lssFastscan;
/** LSS allnodes sub state parameter */
uint8_t lssSubState;
/** LSS allnodes node count parameter */
uint8_t lssNodeCount;
/** LSS allnodes store parameter */
bool_t lssStore;
/** LSS allnodes timeout parameter */
uint16_t lssTimeout_ms;
#endif
#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII_LOG) || defined CO_DOXYGEN
/** Message log buffer of usable size @ref CO_CONFIG_GTWA_LOG_BUF_SIZE */
@ -336,7 +373,7 @@ typedef struct {
* @param SDOtimeoutTimeDefault in milliseconds, 500 typically
* @param SDOblockTransferEnableDefault true or false
* @param NMT NMT object
* @param LSS LSS master object
* @param LSSmaster LSS master object
*
* @return #CO_ReturnError_t: CO_ERROR_NO or CO_ERROR_ILLEGAL_ARGUMENT
*/
@ -345,7 +382,7 @@ CO_ReturnError_t CO_GTWA_init(CO_GTWA_t* gtwa,
uint16_t SDOtimeoutTimeDefault,
bool_t SDOblockTransferEnableDefault,
void *NMT,
void *LSS);
void *LSSmaster);
/**

View file

@ -144,36 +144,36 @@ extern "C" {
#define CO_NO_NMT (1)
/** Number of NMT master objects, 0 or 1 master(CANtx). It depends on
* @ref CO_CONFIG_NMT setting. */
#define CO_NO_NMT_MST (0...1)
#define CO_NO_NMT_MST (0 - 1)
/** Number of SYNC objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */
#define CO_NO_SYNC (0...1)
#define CO_NO_SYNC (0 - 1)
/** Number of Emergency producer objects, fixed to 1 producer(CANtx) */
#define CO_NO_EMERGENCY (1)
/** Number of Emergency consumer objects, 0 or 1 consumer(CANrx). It depends on
* @ref CO_CONFIG_EM setting. */
#define CO_NO_EM_CONS (0...1)
#define CO_NO_EM_CONS (0 - 1)
/** Number of Time-stamp objects, 0 or 1 (consumer(CANrx) + producer(CANtx)) */
#define CO_NO_TIME (0...1)
#define CO_NO_TIME (0 - 1)
/** Number of RPDO objects, 1 to 512 consumers (CANrx) */
#define CO_NO_RPDO (1...512)
#define CO_NO_RPDO (1 - 512)
/** Number of TPDO objects, 1 to 512 producers (CANtx) */
#define CO_NO_TPDO (1...512)
#define CO_NO_TPDO (1 - 512)
/** Number of SDO server objects, from 1 to 128 (CANrx + CANtx) */
#define CO_NO_SDO_SERVER (1...128)
#define CO_NO_SDO_SERVER (1 - 128)
/** Number of SDO client objects, from 0 to 128 (CANrx + CANtx) */
#define CO_NO_SDO_CLIENT (0...128)
#define CO_NO_SDO_CLIENT (0 - 128)
/** Number of HB producer objects, fixed to 1 producer(CANtx) */
#define CO_NO_HB_PROD (1)
/** Number of HB consumer objects, from 0 to 127 consumers(CANrx) */
#define CO_NO_HB_CONS (0...127)
#define CO_NO_HB_CONS (0 - 127)
/** Number of LSS slave objects, 0 or 1 (CANrx + CANtx). It depends on
* @ref CO_CONFIG_LSS setting. */
#define CO_NO_LSS_SLAVE (0...1)
#define CO_NO_LSS_SLAVE (0 - 1)
/** Number of LSS master objects, 0 or 1 (CANrx + CANtx). It depends on
* @ref CO_CONFIG_LSS setting. */
#define CO_NO_LSS_MASTER (0...1)
#define CO_NO_LSS_MASTER (0 - 1)
/** Number of Trace objects, 0 to many */
#define CO_NO_TRACE (0...)
#define CO_NO_TRACE (0 - )
/** @} */
#else /* CO_DOXYGEN */
@ -222,19 +222,19 @@ extern "C" {
#endif /* CO_DOXYGEN */
#if CO_NO_SDO_CLIENT != 0
#if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN
#include "301/CO_SDOclient.h"
#endif
#if CO_NO_LSS_SLAVE != 0
#if CO_NO_LSS_SLAVE != 0 || defined CO_DOXYGEN
#include "305/CO_LSSslave.h"
#endif
#if CO_NO_LSS_MASTER != 0
#if CO_NO_LSS_MASTER != 0 || defined CO_DOXYGEN
#include "305/CO_LSSmaster.h"
#endif
#if (CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII
#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN
#include "309/CO_gateway_ascii.h"
#endif
#if CO_NO_TRACE != 0
#if CO_NO_TRACE != 0 || defined CO_DOXYGEN
#include "extra/CO_trace.h"
#endif
@ -253,19 +253,19 @@ typedef struct {
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*/
#if CO_NO_SDO_CLIENT != 0
#if CO_NO_SDO_CLIENT != 0 || defined CO_DOXYGEN
CO_SDOclient_t *SDOclient[CO_NO_SDO_CLIENT]; /**< SDO client object */
#endif
#if CO_NO_LSS_SLAVE == 1
#if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN
CO_LSSslave_t *LSSslave; /**< LSS slave object */
#endif
#if CO_NO_LSS_MASTER == 1
#if CO_NO_LSS_MASTER == 1 || defined CO_DOXYGEN
CO_LSSmaster_t *LSSmaster; /**< LSS master object */
#endif
#if ((CO_CONFIG_GTW) & CO_CONFIG_GTW_ASCII) || defined CO_DOXYGEN
CO_GTWA_t *gtwa; /**< Gateway-ascii object (CiA309-3) */
#endif
#if CO_NO_TRACE > 0
#if CO_NO_TRACE > 0 || defined CO_DOXYGEN
CO_trace_t *trace[CO_NO_TRACE]; /**< Trace object for recording variables */
#endif
} CO_t;
@ -317,7 +317,7 @@ CO_ReturnError_t CO_CANinit(void *CANptr,
uint16_t bitRate);
#if CO_NO_LSS_SLAVE == 1
#if CO_NO_LSS_SLAVE == 1 || defined CO_DOXYGEN
/**
* Initialize CANopen LSS slave
*
@ -370,7 +370,7 @@ CO_NMT_reset_cmd_t CO_process(CO_t *co,
uint32_t *timerNext_us);
#if CO_NO_SYNC == 1
#if CO_NO_SYNC == 1 || defined CO_DOXYGEN
/**
* Process CANopen SYNC objects.
*

View file

@ -78,13 +78,13 @@ Second terminal now shows operational state (0x05) and one pre-defined PDO messa
### Second CANopen device
Open the third terminal and cd to the same directory as is in the first terminal. First generate default storage files. Then start second instance of _canopend_ with NodeID = 3. Use default od_storage files and enable command interface on standard IO (terminal).
Open the third terminal and cd to the same directory as is in the first terminal. First generate default storage files. Then start second instance of _canopend_ with NodeID = 1. Use default od_storage files and enable command interface on standard IO (terminal).
echo "-" > od_storage
echo "-" > od_storage_auto
./canopend vcan0 -i3 -c "stdio"
./canopend vcan0 -i1 -c "stdio"
Now you should see in second terminal (_candump_) two CANopen devices sending heartbeats in one second interval each. One with node-ID = 4 and one with node-ID = 3. Both should be operational.
Now you should see in second terminal (_candump_) two CANopen devices sending heartbeats in one second interval each. One with node-ID = 4 and one with node-ID = 1. Both should be operational.
### CANopen command interface
@ -106,9 +106,9 @@ In CAN dump you can see some SDO communication. SDO communication can be quite c
[2] 4 write 0x1017 0 u16 5000
[2] OK #response
In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. You can do the same also for node 3, but you won't see anything on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier.
In _candump_ you will notice, that heartbeats from node 4 are coming in 5 second interval now. You can do the same also for node 1, but you won't see anything on _candump_, because data are written into itself directly. In "stdio" you can omit sequence number, to make typing easier.
3 w 0x1017 0 u16 2500
1 w 0x1017 0 u16 2500
[0] OK
Now store Object dictionary on node-ID 4, so it will preserve variables on next start of the program.
@ -143,10 +143,10 @@ If node is operational (started), it can exchange all objects, including PDO, SD
reset node
[0] OK
3 reset communication
1 reset communication
[0] OK
3 reset node
1 reset node
[0] OK
@ -159,15 +159,19 @@ Please be careful when exposing your CANopen network to the outside world, it is
### Next steps
Now you can enter the big world of [CANopen devices](http://can-newsletter.org/hardware).
Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native integrated into Linux kernel are:
You can also build your own CANopen device with your favourite microcontroller, see *deviceSupport.md*. There is also a bare-metal demo for [PIC microcontrollers](https://github.com/CANopenNode/CANopenPIC), most complete example is for PIC32.
Assigning Node-ID or CAN bitrate to unconfigured nodes, which support LSS configuration, is described in *LSSusage.md*.
Some further CANopenNode related Linux tools are available in [CANopenSocket](https://github.com/CANopenNode/CANopenSocket).
Accessing real CANopen devices is the same as described above for virtual CAN interface. Some tested USB to CAN interfaces, which are native in Linux kernel are:
- Simple serial [USBtin](http://www.fischl.de/usbtin/) - Start with: `sudo slcand -f -o -c -s8 /dev/ttyACM0 can0; sudo ip link set up can0`
- [EMS CPC-USB](https://www.ems-wuensche.com/?post_type=product&p=746) or [PCAN-USB FD](http://www.peak-system.com/PCAN-USB-FD.365.0.html?&L=1) - Start with: `sudo ip link set up can0 type can bitrate 250000`
- You can get the idea of other supported CAN interfaces in [Linux kernel source](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/net/can) (Kconfig files).
- Beaglebone or Paspberry PI or similar has CAN capes available. On RPI worked also the above USB interfaces, but it was necessary to compile the kernel.
- Raspberry PI or similar has CAN capes available.
With [CANopenNode](https://github.com/CANopenNode/CANopenNode) you can also design your own device. There are many very useful and high quality specifications for different [device profiles](http://www.can-cia.org/standardization/specifications/), some of them are public and free to download.
Here we played with virtual CAN interface and result shows as pixels on screen. If you connect real CAN interface to your computer, things may
become dangerous. Keep control and safety on your machines!