Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@ pkginclude_HEADERS = \
socanmatic/enum301.h \
socanmatic/enum402.h \
include/socanmatic/ds301.h \
include/socanmatic/ds305.h \
include/socanmatic/emcy.h \
include/socanmatic/ds402.h
include/socanmatic/ds402.h \
include/socanmatic/ds401.h \
include/socanmatic/ds405.h

noinst_HEADERS = include/socanmatic_private.h

Expand All @@ -38,6 +41,7 @@ lib_LTLIBRARIES = libsocanmatic.la
libsocanmatic_la_SOURCES = \
src/sdo.c \
src/ds301.c \
src/ds305.c \
src/error.c \
src/dict.c \
src/util.c \
Expand All @@ -52,6 +56,16 @@ libsocanmatic_la_LIBADD = -ldl
lib_LTLIBRARIES += libsocanmatic402.la
libsocanmatic402_la_SOURCES = dict402.c src/ds402.c

# CiA 401 generic I/O device profile
lib_LTLIBRARIES += libsocanmatic401.la
libsocanmatic401_la_SOURCES = src/ds401.c
libsocanmatic401_la_LIBADD = libsocanmatic.la

# CiA 405 IEC 61131-3 device profile
lib_LTLIBRARIES += libsocanmatic405.la
libsocanmatic405_la_SOURCES = src/ds405.c
libsocanmatic405_la_LIBADD = libsocanmatic.la



# Interfaces
Expand Down
12 changes: 12 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ SoCANmatic

CAN Protocol Library for CANopen.

Supported CANopen Profiles
--------------------------
* DS301 -- Application layer and communication profile (SDO, PDO,
NMT, SYNC, EMCY)
* DS305 -- Layer Setting Services (LSS): configure a node's node-ID
and bit-rate over the bus. Also exposed via `canmat lss ...`.
* DS401 -- Generic I/O device profile: read/write digital and
analogue I/O.
* DS402 -- Drives and motion control device profile.
* DS405 -- Interface and device profile for IEC 61131-3 programmable
devices (network variables).

Electronic Data Sheets (EDS)
----------------------------
The included `canmatc` program translates CiA EDS files to C code. The
Expand Down
22 changes: 15 additions & 7 deletions canmatc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
# NOTE: The ConfigParser module has been renamed to configparser in
# Python 3

import ConfigParser
import configparser
import sys
import re

Expand Down Expand Up @@ -104,7 +104,7 @@ def check_eds_entry(filename, section, params):
# is var type
if 'objecttype' in params:
if 'VAR' != params['objecttype']:
print "%s: section %s, bad ObjectType %s\n" % (filename, section, params['objecttype'])
print("%s: section %s, bad ObjectType %s\n" % (filename, section, params['objecttype']))
exit(-1)
else:
params['objecttype'] = 'VAR'
Expand All @@ -113,9 +113,15 @@ def check_eds_entry(filename, section, params):
def parse_file( obj_dict, enum_dict, name ):
'''Write all object dictaries sectons from file in obj_dict.
Entries are indexed by EDS section.'''
config = ConfigParser.ConfigParser()
# interpolation=None: EDS values may contain a literal '%'
# strict=False: tolerate duplicate options/sections in vendor EDS files
# inline_comment_prefixes=(';',): Python 2's ConfigParser stripped
# inline ';' comments by default; Python 3 does not, so restore it
# (EDS files put ';' comments after values, e.g. "AccessType=rw ; ...")
config = configparser.ConfigParser(interpolation=None, strict=False,
inline_comment_prefixes=(';',))
fp = open(name, "r")
config.readfp( fp )
config.read_file( fp )
for s in config.sections():
if re.match(r'^[0-9a-fA-F]+(sub[0-9a-fA-F]+)?$', s):
obj_dict[s] = config2objdict( config, s )
Expand Down Expand Up @@ -147,7 +153,9 @@ def sect2index( section ):
def map_enum( function, enum_dict, typename ):
def h(elt):
function(elt.name, elt.value, elt.desc)
map( h, enum_dict[typename] )
# map() is lazy in Python 3; consume it so the side effects run
for elt in enum_dict[typename]:
h(elt)

def escape_const(s):
s = re.sub(r' |-',"_", s.upper())
Expand Down Expand Up @@ -225,13 +233,13 @@ def print_dict( name, output, header, namespace, odict, enum_dict ):
(index,subindex) = sect2index( section )
return (index << 8) + subindex

sections = odict.keys()
sections = list(odict.keys())
sections.sort(key=key_index)

def key_name(i):
return odict[ sections[i] ]['parametername'].upper()

btree_name = range(0,len(sections))
btree_name = list(range(0,len(sections)))
btree_name.sort( key=key_name )

# print
Expand Down
3 changes: 3 additions & 0 deletions include/socanmatic.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
#include "socanmatic/sdo.h"
#include "socanmatic/pdo.h"
#include "socanmatic/probe.h"
#include "socanmatic/ds305.h"
#include "socanmatic/ds402.h"
#include "socanmatic/ds401.h"
#include "socanmatic/ds405.h"

#endif //SOCANMATIC_H
194 changes: 194 additions & 0 deletions include/socanmatic/ds305.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/* Copyright (c) 2013-2026, Georgia Tech Research Corporation
* All rights reserved.
*
* Author(s): SoCANmatic contributors
*
* Georgia Tech Humanoid Robotics Lab
* Under Direction of Prof. Mike Stilman <mstilman@cc.gatech.edu>
*
*
* This file is provided under the following "BSD-style" License:
*
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/


#ifndef SOCANMATIC_305_H
#define SOCANMATIC_305_H

/**
* \file ds305.h
*
* \brief CiA 305 Layer Setting Services (LSS)
*
* LSS lets an LSS master configure the node-ID and bit-rate of LSS
* slaves over the CAN bus. This is useful for nodes that have no
* hardware address switches: they power up unconfigured (node-ID
* 0xFF), are placed in configuration mode, assigned an address, and
* told to store it.
*
* All LSS traffic uses two fixed COB-IDs and 8-byte frames whose
* first byte is the command specifier.
*/

#ifdef __cplusplus
extern "C" {
#endif

/** COB-ID for LSS master -> slave requests */
#define CANMAT_LSS_COBID_TX ((canid_t)0x7E5)

/** COB-ID for LSS slave -> master responses */
#define CANMAT_LSS_COBID_RX ((canid_t)0x7E4)

/** Node-ID assigned to an unconfigured LSS slave */
#define CANMAT_LSS_NODE_ID_UNCONFIGURED ((uint8_t)0xFF)

/** LSS command specifiers (byte 0 of an LSS frame) */
typedef enum canmat_lss_cs {
CANMAT_LSS_CS_SWITCH_GLOBAL = 0x04, ///< switch all slaves to a mode
CANMAT_LSS_CS_CONFIGURE_NODE_ID = 0x11, ///< set node-ID of the selected slave
CANMAT_LSS_CS_CONFIGURE_BIT_TIMING = 0x13, ///< set bit-timing of the selected slave
CANMAT_LSS_CS_ACTIVATE_BIT_TIMING = 0x15, ///< activate a previously configured bit-timing
CANMAT_LSS_CS_STORE_CONFIGURATION = 0x17, ///< persist configuration in non-volatile memory

CANMAT_LSS_CS_SWITCH_SEL_VENDOR = 0x40, ///< selective switch, vendor-id sub-command
CANMAT_LSS_CS_SWITCH_SEL_PRODUCT = 0x41, ///< selective switch, product-code sub-command
CANMAT_LSS_CS_SWITCH_SEL_REVISION = 0x42, ///< selective switch, revision sub-command
CANMAT_LSS_CS_SWITCH_SEL_SERIAL = 0x43, ///< selective switch, serial sub-command
CANMAT_LSS_CS_SWITCH_SEL_RESPONSE = 0x44, ///< slave confirms selective switch

CANMAT_LSS_CS_INQUIRE_VENDOR = 0x5A, ///< read the slave's vendor-id
CANMAT_LSS_CS_INQUIRE_PRODUCT = 0x5B, ///< read the slave's product-code
CANMAT_LSS_CS_INQUIRE_REVISION = 0x5C, ///< read the slave's revision
CANMAT_LSS_CS_INQUIRE_SERIAL = 0x5D, ///< read the slave's serial number
CANMAT_LSS_CS_INQUIRE_NODE_ID = 0x5E, ///< read the slave's active node-ID
} canmat_lss_cs_t;

/** LSS mode used with switch-mode-global */
typedef enum canmat_lss_mode {
CANMAT_LSS_MODE_OPERATION = 0x00, ///< normal CANopen operation
CANMAT_LSS_MODE_CONFIGURATION = 0x01, ///< accept LSS configuration commands
} canmat_lss_mode_t;

/** Bit-timing table selector 0: the standard CiA 301 table.
*
* The value is the table index for each supported bit rate. Index 5
* is reserved by the standard and intentionally omitted.
*/
typedef enum canmat_lss_baud {
CANMAT_LSS_BAUD_1000 = 0, ///< 1000 kbit/s
CANMAT_LSS_BAUD_800 = 1, ///< 800 kbit/s
CANMAT_LSS_BAUD_500 = 2, ///< 500 kbit/s
CANMAT_LSS_BAUD_250 = 3, ///< 250 kbit/s
CANMAT_LSS_BAUD_125 = 4, ///< 125 kbit/s
CANMAT_LSS_BAUD_50 = 6, ///< 50 kbit/s
CANMAT_LSS_BAUD_20 = 7, ///< 20 kbit/s
CANMAT_LSS_BAUD_10 = 8, ///< 10 kbit/s
} canmat_lss_baud_t;

/** The four fields of an LSS address, matching identity object 0x1018 */
typedef struct canmat_lss_addr {
uint32_t vendor_id; ///< 0x1018 sub 1
uint32_t product_code; ///< 0x1018 sub 2
uint32_t revision; ///< 0x1018 sub 3
uint32_t serial; ///< 0x1018 sub 4
} canmat_lss_addr_t;


/** Switch all LSS slaves on the bus to the given mode.
*
* Unconfirmed: there is no response frame.
*/
enum canmat_status
canmat_lss_switch_mode_global( canmat_iface_t *cif, enum canmat_lss_mode mode );

/** Switch the single slave matching \a addr into configuration mode.
*
* Confirmed: waits for the slave's 0x44 response. Returns
* CANMAT_ERR_PROTO if no matching slave answered.
*/
enum canmat_status
canmat_lss_switch_mode_selective( canmat_iface_t *cif, const canmat_lss_addr_t *addr );

/** Assign a node-ID to the slave currently in configuration mode.
*
* The slave's error code (0 on success) is stored in \a err if
* non-NULL. Returns CANMAT_ERR_DEV if the slave reported an error.
*/
enum canmat_status
canmat_lss_configure_node_id( canmat_iface_t *cif, uint8_t node_id, uint8_t *err );

/** Configure the bit-timing of the slave in configuration mode.
*
* \a table_selector selects the bit-timing table (0 is the standard
* CiA 301 table); \a table_index is an entry within it (see
* ::canmat_lss_baud). The slave's error code is stored in \a err.
*/
enum canmat_status
canmat_lss_configure_bit_timing( canmat_iface_t *cif, uint8_t table_selector,
uint8_t table_index, uint8_t *err );

/** Activate a previously configured bit-timing after \a switch_delay_ms.
*
* Unconfirmed: there is no response frame.
*/
enum canmat_status
canmat_lss_activate_bit_timing( canmat_iface_t *cif, uint16_t switch_delay_ms );

/** Store the current configuration in the slave's non-volatile memory.
*
* The slave's error code is stored in \a err if non-NULL.
*/
enum canmat_status
canmat_lss_store_configuration( canmat_iface_t *cif, uint8_t *err );

/** Read the active node-ID of the slave in configuration mode. */
enum canmat_status
canmat_lss_inquire_node_id( canmat_iface_t *cif, uint8_t *node_id );

/** Read the full LSS address of the slave in configuration mode. */
enum canmat_status
canmat_lss_inquire_identity( canmat_iface_t *cif, canmat_lss_addr_t *addr );

/** Describe an LSS configuration error code. */
const char *canmat_lss_strerror( uint8_t err );


#ifdef __cplusplus
}
#endif

/* ex: set shiftwidth=4 tabstop=4 expandtab: */
/* Local Variables: */
/* mode: c */
/* c-basic-offset: 4 */
/* indent-tabs-mode: nil */
/* End: */
#endif // SOCANMATIC_305_H
Loading