diff --git a/documentation/graphs/fsm_slave_conf.dot b/documentation/graphs/fsm_slave_conf.dot index cee27683..0d375538 100644 --- a/documentation/graphs/fsm_slave_conf.dot +++ b/documentation/graphs/fsm_slave_conf.dot @@ -55,12 +55,28 @@ digraph slaveconf { enter_sdo_conf [shape=point, label=""] enter_sdo_conf -> enter_pdo_sync [label="No config\nattached"] - enter_sdo_conf -> enter_pdo_conf [label="No SDOs\nconfigured"] + enter_sdo_conf -> enter_soe_conf_preop [label="No SDOs\nconfigured"] enter_sdo_conf -> sdo_conf [weight=10] sdo_conf sdo_conf -> reconfigure - sdo_conf -> enter_pdo_conf [weight=10] + sdo_conf -> enter_soe_conf_preop [weight=10] + + enter_soe_conf_preop [shape=point, label=""] + enter_soe_conf_preop -> enter_pdo_sync [label="No config\nattached"] + enter_soe_conf_preop -> enter_eoe_ip_param [label="No IDNs\nconfigured"] + enter_soe_conf_preop -> soe_conf_preop [weight=10] + + soe_conf_preop + soe_conf_preop -> reconfigure + soe_conf_preop -> enter_eoe_ip_param [weight=10] + + enter_eoe_ip_param [shape=point, label=""] + enter_eoe_ip_param -> enter_pdo_conf [label="No IP parameters"] + enter_eoe_ip_param -> eoe_ip_param [weight=10] + + eoe_ip_param + eoe_ip_param -> enter_pdo_conf [weight=10] enter_pdo_conf [shape=point, label=""] enter_pdo_conf -> pdo_conf [weight=10] diff --git a/include/ecrt.h b/include/ecrt.h index 63ce3fa2..798f884a 100644 --- a/include/ecrt.h +++ b/include/ecrt.h @@ -43,6 +43,12 @@ * - Added the ecrt_master_scan_progress() method, the * ec_master_scan_progress_t structure and the EC_HAVE_SCAN_PROGRESS * definition to check for its existence. + * - Added the EoE configuration methods ecrt_slave_config_eoe_mac_address(), + * ecrt_slave_config_eoe_ip_address(), ecrt_slave_config_eoe_subnet_mask(), + * ecrt_slave_config_eoe_default_gateway(), + * ecrt_slave_config_eoe_dns_address(), + * ecrt_slave_config_eoe_hostname() and the EC_HAVE_SET_IP + * definition to check for its existence. * * Changes since version 1.5.2: * @@ -155,10 +161,12 @@ #include #include #include +#include // struct in_addr #else #include // for size_t #include #include // for struct timeval +#include // struct in_addr #endif /***************************************************************************** @@ -239,6 +247,14 @@ */ #define EC_HAVE_SCAN_PROGRESS +/** Defined, if the methods ecrt_slave_config_eoe_mac_address(), + * ecrt_slave_config_eoe_ip_address(), ecrt_slave_config_eoe_subnet_mask(), + * ecrt_slave_config_eoe_default_gateway(), + * ecrt_slave_config_eoe_dns_address(), ecrt_slave_config_eoe_hostname() are + * available. + */ +#define EC_HAVE_SET_IP + /****************************************************************************/ /** Symbol visibility control macro. @@ -1846,10 +1862,148 @@ EC_PUBLIC_API int ecrt_slave_config_idn( */ EC_PUBLIC_API int ecrt_slave_config_flag( ec_slave_config_t *sc, /**< Slave configuration. */ - const char *key, /**< Key as null-terminated ascii string. */ + const char *key, /**< Key as null-terminated ASCII string. */ int32_t value /**< Value to store. */ ); +/** Sets the link/MAC address for Ethernet-over-EtherCAT (EoE) operation. + * + * This method has to be called in non-realtime context before + * ecrt_master_activate(). + * + * The MAC address is stored in the slave configuration object and will be + * written to the slave during the configuration process. + * + * \retval 0 Success. + * \retval <0 Error code. + */ +EC_PUBLIC_API int ecrt_slave_config_eoe_mac_address( + ec_slave_config_t *sc, /**< Slave configuration. */ + const unsigned char *mac_address /**< MAC address. */ + ); + +/** Sets the IP address for Ethernet-over-EtherCAT (EoE) operation. + * + * This method has to be called in non-realtime context before + * ecrt_master_activate(). + * + * The IP address is stored in the slave configuration object and will be + * written to the slave during the configuration process. + * + * The IP address is passed by-value as a `struct in_addr`. This structure + * contains the 32-bit IPv4 address in network byte order (big endian). + * + * A string-represented IPv4 address can be converted to a `struct in_addr` + * for example via the POSIX function `inet_pton()` (see man 3 inet_pton): + * + * \code{.c} + * #include + * struct in_addr addr; + * if (inet_aton("192.168.0.1", &addr) == 0) { + * fprintf(stderr, "Failed to convert IP address.\n"); + * return -1; + * } + * if (ecrt_slave_config_eoe_ip_address(sc, addr)) { + * fprintf(stderr, "Failed to set IP address.\n"); + * return -1; + * } + * \endcode + * + * + * \retval 0 Success. + * \retval <0 Error code. + */ +EC_PUBLIC_API int ecrt_slave_config_eoe_ip_address( + ec_slave_config_t *sc, /**< Slave configuration. */ + struct in_addr ip_address /**< IPv4 address. */ + ); + +/** Sets the subnet mask for Ethernet-over-EtherCAT (EoE) operation. + * + * This method has to be called in non-realtime context before + * ecrt_master_activate(). + * + * The subnet mask is stored in the slave configuration object and will be + * written to the slave during the configuration process. + * + * The subnet mask is passed by-value as a `struct in_addr`. This structure + * contains the 32-bit mask in network byte order (big endian). + * + * See ecrt_slave_config_eoe_ip_address() on how to convert string-coded masks + * to `struct in_addr`. + * + * \retval 0 Success. + * \retval <0 Error code. + */ +EC_PUBLIC_API int ecrt_slave_config_eoe_subnet_mask( + ec_slave_config_t *sc, /**< Slave configuration. */ + struct in_addr subnet_mask /**< IPv4 subnet mask. */ + ); + +/** Sets the gateway address for Ethernet-over-EtherCAT (EoE) operation. + * + * This method has to be called in non-realtime context before + * ecrt_master_activate(). + * + * The gateway address is stored in the slave configuration object and will be + * written to the slave during the configuration process. + * + * The address is passed by-value as a `struct in_addr`. This structure + * contains the 32-bit IPv4 address in network byte order (big endian). + * + * See ecrt_slave_config_eoe_ip_address() on how to convert string-coded IPv4 + * addresses to `struct in_addr`. + * + * \retval 0 Success. + * \retval <0 Error code. + */ +EC_PUBLIC_API int ecrt_slave_config_eoe_default_gateway( + ec_slave_config_t *sc, /**< Slave configuration. */ + struct in_addr gateway_address /**< Gateway's IPv4 address. */ + ); + +/** Sets the IPv4 address of the DNS server for Ethernet-over-EtherCAT (EoE) + * operation. + * + * This method has to be called in non-realtime context before + * ecrt_master_activate(). + * + * The DNS server address is stored in the slave configuration object and will + * be written to the slave during the configuration process. + * + * The address is passed by-value as a `struct in_addr`. This structure + * contains the 32-bit IPv4 address in network byte order (big endian). + * + * See ecrt_slave_config_eoe_ip_address() on how to convert string-coded IPv4 + * addresses to `struct in_addr`. + * + * \retval 0 Success. + * \retval <0 Error code. + */ +EC_PUBLIC_API int ecrt_slave_config_eoe_dns_address( + ec_slave_config_t *sc, /**< Slave configuration. */ + struct in_addr dns_address /**< IPv4 address of the DNS server. */ + ); + +/** Sets the host name for Ethernet-over-EtherCAT (EoE) operation. + * + * This method has to be called in non-realtime context before + * ecrt_master_activate(). + * + * The host name is stored in the slave configuration object and will + * be written to the slave during the configuration process. + * + * The maximum size of the host name is 32 bytes (including the zero + * terminator). + * + * \retval 0 Success. + * \retval <0 Error code. + */ +EC_PUBLIC_API int ecrt_slave_config_eoe_hostname( + ec_slave_config_t *sc, /**< Slave configuration. */ + const char *name /**< Zero-terminated host name. */ + ); + /***************************************************************************** * Domain methods ****************************************************************************/ diff --git a/lib/Makefile.am b/lib/Makefile.am index e64c7c30..644d4ea8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -44,7 +44,11 @@ noinst_HEADERS = \ soe_request.h \ voe_handler.h -libethercat_la_CFLAGS = -fno-strict-aliasing -Wall -I$(top_srcdir) \ +libethercat_la_CFLAGS = \ + -fno-strict-aliasing \ + -Wall \ + -Wmissing-prototypes \ + -I$(top_srcdir) \ -Dethercat_EXPORTS \ -fvisibility=hidden diff --git a/lib/libethercat.map b/lib/libethercat.map index fb1693f0..7a83f83b 100644 --- a/lib/libethercat.map +++ b/lib/libethercat.map @@ -104,4 +104,10 @@ LIBETHERCAT_1.5.3 { LIBETHERCAT_1.6 { global: ecrt_master_scan_progress; + ecrt_slave_config_eoe_mac_address; + ecrt_slave_config_eoe_ip_address; + ecrt_slave_config_eoe_subnet_mask; + ecrt_slave_config_eoe_default_gateway; + ecrt_slave_config_eoe_dns_address; + ecrt_slave_config_eoe_hostname; } LIBETHERCAT_1.5.3; diff --git a/lib/master.c b/lib/master.c index 59ca10e5..2a9018e5 100644 --- a/lib/master.c +++ b/lib/master.c @@ -34,6 +34,13 @@ /****************************************************************************/ +// prototypes for internal methods (avoid -Wmissing-prototype warning) +void ec_master_clear_config(ec_master_t *); +void ec_master_add_domain(ec_master_t *, ec_domain_t *); +void ec_master_add_slave_config(ec_master_t *, ec_slave_config_t *); + +/****************************************************************************/ + int ecrt_master_reserve(ec_master_t *master) { int ret = ioctl(master->fd, EC_IOCTL_REQUEST, NULL); diff --git a/lib/slave_config.c b/lib/slave_config.c index aa2da090..7c3b8867 100644 --- a/lib/slave_config.c +++ b/lib/slave_config.c @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2019 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT master userspace library. * @@ -36,6 +36,13 @@ /****************************************************************************/ +// prototypes for internal methods (avoid -Wmissing-prototype warning) +void ec_slave_config_add_sdo_request(ec_slave_config_t *, ec_sdo_request_t *); +void ec_slave_config_add_reg_request(ec_slave_config_t *, ec_reg_request_t *); +void ec_slave_config_add_voe_handler(ec_slave_config_t *, ec_voe_handler_t *); + +/****************************************************************************/ + void ec_slave_config_clear(ec_slave_config_t *sc) { ec_sdo_request_t *r, *next_r; @@ -618,7 +625,7 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc, /****************************************************************************/ -void ec_slave_config_add_soe_request(ec_slave_config_t *sc, +inline void ec_slave_config_add_soe_request(ec_slave_config_t *sc, ec_soe_request_t *req) { if (sc->first_soe_request) { @@ -895,3 +902,139 @@ int ecrt_slave_config_flag(ec_slave_config_t *sc, const char *key, } /****************************************************************************/ + +#ifdef EC_EOE + +int ecrt_slave_config_eoe_mac_address(ec_slave_config_t *sc, + const unsigned char *mac_address) +{ + ec_ioctl_eoe_ip_t io = {}; + int ret; + + io.config_index = sc->index; + memcpy(io.mac_address, mac_address, EC_ETH_ALEN); + io.mac_address_included = 1; + + ret = ioctl(sc->master->fd, EC_IOCTL_SC_EOE_IP_PARAM, &io); + if (EC_IOCTL_IS_ERROR(ret)) { + fprintf(stderr, "Failed to configure EoE MAC address: %s\n", + strerror(EC_IOCTL_ERRNO(ret))); + return -EC_IOCTL_ERRNO(ret); + } + + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_ip_address(ec_slave_config_t *sc, + struct in_addr ip_address) +{ + ec_ioctl_eoe_ip_t io = {}; + int ret; + + io.config_index = sc->index; + io.ip_address = ip_address; + io.ip_address_included = 1; + + ret = ioctl(sc->master->fd, EC_IOCTL_SC_EOE_IP_PARAM, &io); + if (EC_IOCTL_IS_ERROR(ret)) { + fprintf(stderr, "Failed to configure EoE IP address: %s\n", + strerror(EC_IOCTL_ERRNO(ret))); + return -EC_IOCTL_ERRNO(ret); + } + + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_subnet_mask(ec_slave_config_t *sc, + struct in_addr subnet_mask) +{ + ec_ioctl_eoe_ip_t io = {}; + int ret; + + io.config_index = sc->index; + io.subnet_mask = subnet_mask; + io.subnet_mask_included = 1; + + ret = ioctl(sc->master->fd, EC_IOCTL_SC_EOE_IP_PARAM, &io); + if (EC_IOCTL_IS_ERROR(ret)) { + fprintf(stderr, "Failed to configure EoE subnet mask: %s\n", + strerror(EC_IOCTL_ERRNO(ret))); + return -EC_IOCTL_ERRNO(ret); + } + + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_default_gateway(ec_slave_config_t *sc, + struct in_addr gateway_address) +{ + ec_ioctl_eoe_ip_t io = {}; + int ret; + + io.config_index = sc->index; + io.gateway = gateway_address; + io.gateway_included = 1; + + ret = ioctl(sc->master->fd, EC_IOCTL_SC_EOE_IP_PARAM, &io); + if (EC_IOCTL_IS_ERROR(ret)) { + fprintf(stderr, "Failed to configure EoE default gateway: %s\n", + strerror(EC_IOCTL_ERRNO(ret))); + return -EC_IOCTL_ERRNO(ret); + } + + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_dns_address(ec_slave_config_t *sc, + struct in_addr dns_address) +{ + ec_ioctl_eoe_ip_t io = {}; + int ret; + + io.config_index = sc->index; + io.dns = dns_address; + io.dns_included = 1; + + ret = ioctl(sc->master->fd, EC_IOCTL_SC_EOE_IP_PARAM, &io); + if (EC_IOCTL_IS_ERROR(ret)) { + fprintf(stderr, "Failed to configure EoE DNS address: %s\n", + strerror(EC_IOCTL_ERRNO(ret))); + return -EC_IOCTL_ERRNO(ret); + } + + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_hostname(ec_slave_config_t *sc, + const char *name) +{ + ec_ioctl_eoe_ip_t io = {}; + int ret; + + io.config_index = sc->index; + strncpy(io.name, (const char *) name, EC_MAX_HOSTNAME_SIZE - 1); + io.name_included = 1; + + ret = ioctl(sc->master->fd, EC_IOCTL_SC_EOE_IP_PARAM, &io); + if (EC_IOCTL_IS_ERROR(ret)) { + fprintf(stderr, "Failed to configure EoE hostname: %s\n", + strerror(EC_IOCTL_ERRNO(ret))); + return -EC_IOCTL_ERRNO(ret); + } + + return 0; +} + +#endif // EC_EOE + +/****************************************************************************/ diff --git a/master/eoe_request.c b/master/eoe_request.c index a33e7c69..f336cf34 100644 --- a/master/eoe_request.c +++ b/master/eoe_request.c @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2014 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -51,13 +51,30 @@ void ec_eoe_request_init( req->name_included = 0; memset(req->mac_address, 0x00, ETH_ALEN); - req->ip_address = 0; - req->subnet_mask = 0; - req->gateway = 0; - req->dns = 0; + req->ip_address.s_addr = 0; + req->subnet_mask.s_addr = 0; + req->gateway.s_addr = 0; + req->dns.s_addr = 0; req->name[0] = 0x00; req->result = 0x0000; } /****************************************************************************/ + +/** Checks if EoE request has something to set. + */ +int ec_eoe_request_valid( + const ec_eoe_request_t *req /**< EoE request. */ + ) +{ + return + req->mac_address_included || + req->ip_address_included || + req->subnet_mask_included || + req->gateway_included || + req->dns_included || + req->name_included; +} + +/****************************************************************************/ diff --git a/master/eoe_request.h b/master/eoe_request.h index 4b9048a4..6751f1f9 100644 --- a/master/eoe_request.h +++ b/master/eoe_request.h @@ -51,10 +51,10 @@ typedef struct { uint8_t name_included; unsigned char mac_address[ETH_ALEN]; - uint32_t ip_address; - uint32_t subnet_mask; - uint32_t gateway; - uint32_t dns; + struct in_addr ip_address; + struct in_addr subnet_mask; + struct in_addr gateway; + struct in_addr dns; char name[EC_MAX_HOSTNAME_SIZE]; uint16_t result; @@ -63,6 +63,7 @@ typedef struct { /****************************************************************************/ void ec_eoe_request_init(ec_eoe_request_t *); +int ec_eoe_request_valid(const ec_eoe_request_t *); /****************************************************************************/ diff --git a/master/ethernet.c b/master/ethernet.c index 76b298df..bd755eb5 100644 --- a/master/ethernet.c +++ b/master/ethernet.c @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -48,6 +48,7 @@ # define SUSE_PATCHLEVEL 0 # endif #endif + /****************************************************************************/ /** Defines the debug level of EoE processing. @@ -526,7 +527,7 @@ void ec_eoe_state_rx_fetch(ec_eoe_t *eoe /**< EoE handler */) #if EOE_DEBUG_LEVEL >= 2 EC_SLAVE_DBG(eoe->slave, 0, "EoE %s RX fragment %u%s, offset %u," - " frame %u%s, %u octets\n", eoe->dev->name, fragment_number, + " frame %u%s, %zu octets\n", eoe->dev->name, fragment_number, last_fragment ? "" : "+", fragment_offset, frame_number, time_appended ? ", + timestamp" : "", time_appended ? rec_size - 8 : rec_size - 4); diff --git a/master/fsm_eoe.c b/master/fsm_eoe.c index 73c2ef56..c061728d 100644 --- a/master/fsm_eoe.c +++ b/master/fsm_eoe.c @@ -33,6 +33,24 @@ /****************************************************************************/ +/** Host-architecture-independent 32-bit swap function. + * + * The internal storage of struct in_addr is always big-endian. + * The mailbox protocol format to supply IPv4 adresses is little-endian + * (Yuck!). So we need a swap function, that is independent of the CPU + * architecture. ntohl()/htonl() can not be used, because they evaluate to + * NOPs if the host architecture matches the target architecture! + */ +void memcpy_swap32(void *dst, const void *src) +{ + int i; + for (i = 0; i < 4; i++) { + ((u8 *) dst)[i] = ((const u8 *) src)[3 - i]; + } +} + +/****************************************************************************/ + /** Maximum time to wait for a set IP parameter response. */ #define EC_EOE_RESPONSE_TIMEOUT 3000 // [ms] @@ -61,6 +79,7 @@ void ec_fsm_eoe_init( fsm->datagram = NULL; fsm->jiffies_start = 0; fsm->request = NULL; + fsm->frame_type_retries = 0; } /****************************************************************************/ @@ -197,26 +216,22 @@ int ec_fsm_eoe_prepare_set( cur += ETH_ALEN; if (req->ip_address_included) { - uint32_t swapped = htonl(req->ip_address); - memcpy(cur, &swapped, 4); + memcpy_swap32(cur, &req->ip_address); } cur += 4; if (req->subnet_mask_included) { - uint32_t swapped = htonl(req->subnet_mask); - memcpy(cur, &swapped, 4); + memcpy_swap32(cur, &req->subnet_mask); } cur += 4; if (req->gateway_included) { - uint32_t swapped = htonl(req->gateway); - memcpy(cur, &swapped, 4); + memcpy_swap32(cur, &req->gateway); } cur += 4; if (req->dns_included) { - uint32_t swapped = htonl(req->dns); - memcpy(cur, &swapped, 4); + memcpy_swap32(cur, &req->dns); } cur += 4; @@ -313,6 +328,7 @@ void ec_fsm_eoe_set_ip_request( ec_slave_mbox_prepare_check(slave, datagram); // can not fail. fsm->retries = EC_FSM_RETRIES; fsm->state = ec_fsm_eoe_set_ip_check; + fsm->frame_type_retries = 10; } /****************************************************************************/ @@ -431,14 +447,28 @@ void ec_fsm_eoe_set_ip_response( frame_type = EC_READ_U8(data) & 0x0f; if (frame_type != EC_EOE_FRAMETYPE_SET_IP_RES) { - EC_SLAVE_ERR(slave, "Received no set IP parameter response" - " (frame type %x).\n", frame_type); - ec_print_data(data, rec_size); - fsm->state = ec_fsm_eoe_error; - return; + if (master->debug_level) { + EC_SLAVE_DBG(slave, 0, "Received no set IP parameter response" + " (frame type %x).\n", frame_type); + ec_print_data(data, rec_size); + } + if (fsm->frame_type_retries--) { + // there may be an EoE segment left in the mailbox. + // discard it and receive again. + fsm->jiffies_start = fsm->datagram->jiffies_sent; + ec_slave_mbox_prepare_check(slave, datagram); // can not fail. + fsm->retries = EC_FSM_RETRIES; + fsm->state = ec_fsm_eoe_set_ip_check; + return; + } + else { + EC_SLAVE_ERR(slave, "Received no set IP parameter response.\n"); + fsm->state = ec_fsm_eoe_error; + return; + } } - req->result = EC_READ_U16(data + 2); + req->result = EC_READ_U16(data + 2); // result code 0x0000 means success if (req->result) { fsm->state = ec_fsm_eoe_error; diff --git a/master/fsm_eoe.h b/master/fsm_eoe.h index 3809a462..7f901bdd 100644 --- a/master/fsm_eoe.h +++ b/master/fsm_eoe.h @@ -48,6 +48,7 @@ struct ec_fsm_eoe { ec_datagram_t *datagram; /**< Datagram used in the previous step. */ unsigned long jiffies_start; /**< Timestamp. */ ec_eoe_request_t *request; /**< EoE request */ + unsigned int frame_type_retries; /**< retries upon wrong frame type. */ }; /****************************************************************************/ diff --git a/master/fsm_master.c b/master/fsm_master.c index 2828239c..3cbe802a 100644 --- a/master/fsm_master.c +++ b/master/fsm_master.c @@ -92,9 +92,11 @@ void ec_fsm_master_init( ec_fsm_coe_init(&fsm->fsm_coe); ec_fsm_soe_init(&fsm->fsm_soe); ec_fsm_pdo_init(&fsm->fsm_pdo, &fsm->fsm_coe); + ec_fsm_eoe_init(&fsm->fsm_eoe); ec_fsm_change_init(&fsm->fsm_change, fsm->datagram); ec_fsm_slave_config_init(&fsm->fsm_slave_config, fsm->datagram, - &fsm->fsm_change, &fsm->fsm_coe, &fsm->fsm_soe, &fsm->fsm_pdo); + &fsm->fsm_change, &fsm->fsm_coe, &fsm->fsm_soe, &fsm->fsm_pdo, + &fsm->fsm_eoe); ec_fsm_slave_scan_init(&fsm->fsm_slave_scan, fsm->datagram, &fsm->fsm_slave_config, &fsm->fsm_pdo); ec_fsm_sii_init(&fsm->fsm_sii, fsm->datagram); @@ -112,6 +114,7 @@ void ec_fsm_master_clear( ec_fsm_coe_clear(&fsm->fsm_coe); ec_fsm_soe_clear(&fsm->fsm_soe); ec_fsm_pdo_clear(&fsm->fsm_pdo); + ec_fsm_eoe_clear(&fsm->fsm_eoe); ec_fsm_change_clear(&fsm->fsm_change); ec_fsm_slave_config_clear(&fsm->fsm_slave_config); ec_fsm_slave_scan_clear(&fsm->fsm_slave_scan); diff --git a/master/fsm_master.h b/master/fsm_master.h index 1ffed862..d6457866 100644 --- a/master/fsm_master.h +++ b/master/fsm_master.h @@ -85,6 +85,7 @@ struct ec_fsm_master { ec_fsm_coe_t fsm_coe; /**< CoE state machine */ ec_fsm_soe_t fsm_soe; /**< SoE state machine */ ec_fsm_pdo_t fsm_pdo; /**< PDO configuration state machine. */ + ec_fsm_eoe_t fsm_eoe; /**< EoE state machine */ ec_fsm_change_t fsm_change; /**< State change state machine */ ec_fsm_slave_config_t fsm_slave_config; /**< slave state machine */ ec_fsm_slave_scan_t fsm_slave_scan; /**< slave state machine */ diff --git a/master/fsm_slave_config.c b/master/fsm_slave_config.c index 6abbd98c..f0f0d250 100644 --- a/master/fsm_slave_config.c +++ b/master/fsm_slave_config.c @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -67,6 +67,7 @@ void ec_fsm_slave_config_state_assign_ethercat(ec_fsm_slave_config_t *); #endif void ec_fsm_slave_config_state_sdo_conf(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_soe_conf_preop(ec_fsm_slave_config_t *); +void ec_fsm_slave_config_state_eoe_ip_param(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_watchdog_divider(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_watchdog(ec_fsm_slave_config_t *); void ec_fsm_slave_config_state_pdo_sync(ec_fsm_slave_config_t *); @@ -91,6 +92,7 @@ void ec_fsm_slave_config_enter_assign_pdi(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_boot_preop(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_sdo_conf(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_soe_conf_preop(ec_fsm_slave_config_t *); +void ec_fsm_slave_config_enter_eoe_ip_param(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_pdo_conf(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_watchdog_divider(ec_fsm_slave_config_t *); void ec_fsm_slave_config_enter_watchdog(ec_fsm_slave_config_t *); @@ -117,7 +119,8 @@ void ec_fsm_slave_config_init( ec_fsm_change_t *fsm_change, /**< State change state machine to use. */ ec_fsm_coe_t *fsm_coe, /**< CoE state machine to use. */ ec_fsm_soe_t *fsm_soe, /**< SoE state machine to use. */ - ec_fsm_pdo_t *fsm_pdo /**< PDO configuration state machine to use. */ + ec_fsm_pdo_t *fsm_pdo, /**< PDO configuration state machine to use. */ + ec_fsm_eoe_t *fsm_eoe /**< EoE state machine to use. */ ) { ec_sdo_request_init(&fsm->request_copy); @@ -128,6 +131,7 @@ void ec_fsm_slave_config_init( fsm->fsm_coe = fsm_coe; fsm->fsm_soe = fsm_soe; fsm->fsm_pdo = fsm_pdo; + fsm->fsm_eoe = fsm_eoe; fsm->wait_ms = 0; } @@ -901,7 +905,7 @@ void ec_fsm_slave_config_enter_soe_conf_preop( } // No SoE configuration to be applied in PREOP - ec_fsm_slave_config_enter_pdo_conf(fsm); + ec_fsm_slave_config_enter_eoe_ip_param(fsm); } /****************************************************************************/ @@ -945,6 +949,56 @@ void ec_fsm_slave_config_state_soe_conf_preop( } // All PREOP IDNs are now configured. + ec_fsm_slave_config_enter_eoe_ip_param(fsm); +} + +/****************************************************************************/ + +/** EOE_IP_PARAM entry function. + */ +void ec_fsm_slave_config_enter_eoe_ip_param( + ec_fsm_slave_config_t *fsm /**< slave state machine */ + ) +{ +#if EC_EOE + ec_slave_t *slave = fsm->slave; + ec_eoe_request_t *request = &slave->config->eoe_ip_param_request; + + if (ec_eoe_request_valid(request)) { + EC_SLAVE_DBG(slave, 1, "Setting EoE IP parameters...\n"); + + // Start EoE command + fsm->state = ec_fsm_slave_config_state_eoe_ip_param; + ec_fsm_eoe_set_ip_param(fsm->fsm_eoe, slave, request); + ec_fsm_eoe_exec(fsm->fsm_eoe, fsm->datagram); // execute immediately + return; + } +#endif + + ec_fsm_slave_config_enter_pdo_conf(fsm); +} + +/****************************************************************************/ + +/** Slave configuration state: EOE_IP_PARAM. + */ +void ec_fsm_slave_config_state_eoe_ip_param( + ec_fsm_slave_config_t *fsm /**< slave state machine */ + ) +{ + ec_slave_t *slave = fsm->slave; + + if (ec_fsm_eoe_exec(fsm->fsm_eoe, fsm->datagram)) { + return; + } + + if (ec_fsm_eoe_success(fsm->fsm_eoe)) { + EC_SLAVE_DBG(slave, 1, "Finished setting EoE IP parameters.\n"); + } + else { + EC_SLAVE_ERR(slave, "Failed to set EoE IP parameters.\n"); + } + ec_fsm_slave_config_enter_pdo_conf(fsm); } diff --git a/master/fsm_slave_config.h b/master/fsm_slave_config.h index bb7566a8..fa33c83b 100644 --- a/master/fsm_slave_config.h +++ b/master/fsm_slave_config.h @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -34,6 +34,7 @@ #include "fsm_change.h" #include "fsm_coe.h" #include "fsm_pdo.h" +#include "fsm_eoe.h" /****************************************************************************/ @@ -49,6 +50,7 @@ struct ec_fsm_slave_config ec_fsm_coe_t *fsm_coe; /**< CoE state machine. */ ec_fsm_soe_t *fsm_soe; /**< SoE state machine. */ ec_fsm_pdo_t *fsm_pdo; /**< PDO configuration state machine. */ + ec_fsm_eoe_t *fsm_eoe; /**< EoE state machine. */ ec_slave_t *slave; /**< Slave the FSM runs on. */ void (*state)(ec_fsm_slave_config_t *); /**< State function. */ @@ -65,7 +67,8 @@ struct ec_fsm_slave_config /****************************************************************************/ void ec_fsm_slave_config_init(ec_fsm_slave_config_t *, ec_datagram_t *, - ec_fsm_change_t *, ec_fsm_coe_t *, ec_fsm_soe_t *, ec_fsm_pdo_t *); + ec_fsm_change_t *, ec_fsm_coe_t *, ec_fsm_soe_t *, ec_fsm_pdo_t *, + ec_fsm_eoe_t *); void ec_fsm_slave_config_clear(ec_fsm_slave_config_t *); void ec_fsm_slave_config_start(ec_fsm_slave_config_t *, ec_slave_t *); diff --git a/master/ioctl.c b/master/ioctl.c index 9361b6b9..a3a7bcf1 100644 --- a/master/ioctl.c +++ b/master/ioctl.c @@ -1584,6 +1584,74 @@ static ATTRIBUTES int ec_ioctl_config_flag( #ifdef EC_EOE +/** Get configured EoE IP parameters for a given slave configuration. + * + * \return Zero on success, otherwise a negative error code. + */ +static ATTRIBUTES int ec_ioctl_config_ip( + ec_master_t *master, /**< EtherCAT master. */ + void *arg /**< ioctl() argument. */ + ) +{ + ec_ioctl_eoe_ip_t *ioctl; + const ec_slave_config_t *sc; + const ec_eoe_request_t *req; + + if (!(ioctl = kmalloc(sizeof(*ioctl), GFP_KERNEL))) { + return -ENOMEM; + } + + if (copy_from_user(ioctl, (void __user *) arg, sizeof(*ioctl))) { + kfree(ioctl); + return -EFAULT; + } + + if (down_interruptible(&master->master_sem)) { + kfree(ioctl); + return -EINTR; + } + + if (!(sc = ec_master_get_config_const(master, ioctl->config_index))) { + up(&master->master_sem); + EC_MASTER_ERR(master, "Slave config %u does not exist!\n", + ioctl->config_index); + kfree(ioctl); + return -EINVAL; + } + + req = &sc->eoe_ip_param_request; + + ioctl->mac_address_included = req->mac_address_included; + ioctl->ip_address_included = req->ip_address_included; + ioctl->subnet_mask_included = req->subnet_mask_included; + ioctl->gateway_included = req->gateway_included; + ioctl->dns_included = req->dns_included; + ioctl->name_included = req->name_included; + + memcpy(ioctl->mac_address, req->mac_address, EC_ETH_ALEN); + ioctl->ip_address = req->ip_address; + ioctl->subnet_mask = req->subnet_mask; + ioctl->gateway = req->gateway; + ioctl->dns = req->dns; + strncpy(ioctl->name, req->name, EC_MAX_HOSTNAME_SIZE); + + up(&master->master_sem); + + if (copy_to_user((void __user *) arg, ioctl, sizeof(*ioctl))) { + kfree(ioctl); + return -EFAULT; + } + + kfree(ioctl); + return 0; +} + +#endif + +/****************************************************************************/ + +#ifdef EC_EOE + /** Get EoE handler information. * * \return Zero on success, otherwise a negative error code. @@ -1646,7 +1714,7 @@ static ATTRIBUTES int ec_ioctl_slave_eoe_ip_param( void *arg /**< ioctl() argument. */ ) { - ec_ioctl_slave_eoe_ip_t io; + ec_ioctl_eoe_ip_t io; ec_eoe_request_t req; ec_slave_t *slave; @@ -1664,7 +1732,7 @@ static ATTRIBUTES int ec_ioctl_slave_eoe_ip_param( req.dns_included = io.dns_included; req.name_included = io.name_included; - memcpy(req.mac_address, io.mac_address, ETH_ALEN); + memcpy(req.mac_address, io.mac_address, EC_ETH_ALEN); req.ip_address = io.ip_address; req.subnet_mask = io.subnet_mask; req.gateway = io.gateway; @@ -3264,6 +3332,70 @@ static ATTRIBUTES int ec_ioctl_sc_flag( /****************************************************************************/ +#ifdef EC_EOE + +/** Configures EoE IP parameters. + * + * \return Zero on success, otherwise a negative error code. + */ +static ATTRIBUTES int ec_ioctl_sc_ip( + ec_master_t *master, /**< EtherCAT master. */ + void *arg, /**< ioctl() argument. */ + ec_ioctl_context_t *ctx /**< Private data structure of file handle. */ + ) +{ + ec_ioctl_eoe_ip_t io; + ec_slave_config_t *sc; + uint8_t *key; + + if (unlikely(!ctx->requested)) { + return -EPERM; + } + + if (copy_from_user(&io, (void __user *) arg, sizeof(io))) { + return -EFAULT; + } + + if (down_interruptible(&master->master_sem)) { + kfree(key); + return -EINTR; + } + + if (!(sc = ec_master_get_config(master, io.config_index))) { + up(&master->master_sem); + kfree(key); + return -ENOENT; + } + + up(&master->master_sem); /** \todo sc could be invalidated */ + + /* the kernel versions of the EoE set IP methods never fail. */ + if (io.mac_address_included) { + ecrt_slave_config_eoe_mac_address(sc, io.mac_address); + } + if (io.ip_address_included) { + ecrt_slave_config_eoe_ip_address(sc, io.ip_address); + } + if (io.subnet_mask_included) { + ecrt_slave_config_eoe_subnet_mask(sc, io.subnet_mask); + } + if (io.gateway_included) { + ecrt_slave_config_eoe_default_gateway(sc, io.gateway); + } + if (io.dns_included) { + ecrt_slave_config_eoe_dns_address(sc, io.dns); + } + if (io.name_included) { + ecrt_slave_config_eoe_hostname(sc, io.name); + } + + return 0; +} + +#endif + +/****************************************************************************/ + /** Gets the domain's data size. * * \return Domain size, or a negative error code. @@ -5190,6 +5322,9 @@ static long ec_ioctl_nrt ret = ec_ioctl_config_flag(master, arg); break; #ifdef EC_EOE + case EC_IOCTL_CONFIG_EOE_IP_PARAM: + ret = ec_ioctl_config_ip(master, arg); + break; case EC_IOCTL_EOE_HANDLER: ret = ec_ioctl_eoe_handler(master, arg); break; @@ -5358,6 +5493,15 @@ static long ec_ioctl_nrt } ret = ec_ioctl_sc_flag(master, arg, ctx); break; +#ifdef EC_EOE + case EC_IOCTL_SC_EOE_IP_PARAM: + if (!ctx->writable) { + ret = -EPERM; + break; + } + ret = ec_ioctl_sc_ip(master, arg, ctx); + break; +#endif case EC_IOCTL_DOMAIN_SIZE: ret = ec_ioctl_domain_size(master, arg, ctx); break; diff --git a/master/ioctl.h b/master/ioctl.h index afaf62c6..2cb90103 100644 --- a/master/ioctl.h +++ b/master/ioctl.h @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2021 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT master. * @@ -47,7 +47,7 @@ * * Increment this when changing the ioctl interface! */ -#define EC_IOCTL_VERSION_MAGIC 35 +#define EC_IOCTL_VERSION_MAGIC 36 // Command-line tool #define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t) @@ -75,7 +75,7 @@ #define EC_IOCTL_SLAVE_SOE_READ EC_IOWR(0x16, ec_ioctl_slave_soe_read_t) #define EC_IOCTL_SLAVE_SOE_WRITE EC_IOWR(0x17, ec_ioctl_slave_soe_write_t) #ifdef EC_EOE -#define EC_IOCTL_SLAVE_EOE_IP_PARAM EC_IOW(0x18, ec_ioctl_slave_eoe_ip_t) +#define EC_IOCTL_SLAVE_EOE_IP_PARAM EC_IOW(0x18, ec_ioctl_eoe_ip_t) #endif #define EC_IOCTL_CONFIG EC_IOWR(0x19, ec_ioctl_config_t) #define EC_IOCTL_CONFIG_PDO EC_IOWR(0x1a, ec_ioctl_config_pdo_t) @@ -84,78 +84,82 @@ #define EC_IOCTL_CONFIG_IDN EC_IOWR(0x1d, ec_ioctl_config_idn_t) #define EC_IOCTL_CONFIG_FLAG EC_IOWR(0x1e, ec_ioctl_config_flag_t) #ifdef EC_EOE -#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x1f, ec_ioctl_eoe_handler_t) +#define EC_IOCTL_CONFIG_EOE_IP_PARAM EC_IOWR(0x1f, ec_ioctl_eoe_ip_t) +#define EC_IOCTL_EOE_HANDLER EC_IOWR(0x20, ec_ioctl_eoe_handler_t) #endif // Application interface -#define EC_IOCTL_REQUEST EC_IO(0x20) -#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x21) -#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x22, ec_ioctl_config_t) -#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x23, uint32_t) -#define EC_IOCTL_ACTIVATE EC_IOR(0x24, ec_ioctl_master_activate_t) -#define EC_IOCTL_DEACTIVATE EC_IO(0x25) -#define EC_IOCTL_SEND EC_IO(0x26) -#define EC_IOCTL_RECEIVE EC_IO(0x27) -#define EC_IOCTL_MASTER_STATE EC_IOR(0x28, ec_master_state_t) -#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x29, ec_ioctl_link_state_t) -#define EC_IOCTL_APP_TIME EC_IOW(0x2a, uint64_t) -#define EC_IOCTL_SYNC_REF EC_IO(0x2b) -#define EC_IOCTL_SYNC_REF_TO EC_IOW(0x2c, uint64_t) -#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2d) -#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2e, uint32_t) -#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x2f) -#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x30, uint32_t) -#define EC_IOCTL_RESET EC_IO(0x31) -#define EC_IOCTL_SC_SYNC EC_IOW(0x32, ec_ioctl_config_t) -#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x33, ec_ioctl_config_t) -#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x34, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x35, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x36, ec_ioctl_add_pdo_entry_t) -#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x37, ec_ioctl_config_pdo_t) -#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x38, ec_ioctl_reg_pdo_entry_t) -#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x39, ec_ioctl_reg_pdo_pos_t) -#define EC_IOCTL_SC_DC EC_IOW(0x3a, ec_ioctl_config_t) -#define EC_IOCTL_SC_SDO EC_IOW(0x3b, ec_ioctl_sc_sdo_t) -#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x3c, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3d, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3e, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3f, ec_ioctl_sc_emerg_t) -#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x40, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SC_SOE_REQUEST EC_IOWR(0x41, ec_ioctl_soe_request_t) -#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x42, ec_ioctl_reg_request_t) -#define EC_IOCTL_SC_VOE EC_IOWR(0x43, ec_ioctl_voe_t) -#define EC_IOCTL_SC_STATE EC_IOWR(0x44, ec_ioctl_sc_state_t) -#define EC_IOCTL_SC_IDN EC_IOW(0x45, ec_ioctl_sc_idn_t) -#define EC_IOCTL_SC_FLAG EC_IOW(0x46, ec_ioctl_sc_flag_t) -#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x47) -#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x48) -#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x49) -#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x4a) -#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4b, ec_ioctl_domain_state_t) -#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4c, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4d, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4e, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4f, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x50, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x51, ec_ioctl_sdo_request_t) -#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x52, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x53, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x54, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x55, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x56, ec_ioctl_soe_request_t) -#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x57, ec_ioctl_soe_request_t) -#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x58, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x59, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x5a, ec_ioctl_reg_request_t) -#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5b, ec_ioctl_reg_request_t) -#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5c, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5d, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ EC_IOW(0x5e, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x5f, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_WRITE EC_IOWR(0x60, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_EXEC EC_IOWR(0x61, ec_ioctl_voe_t) -#define EC_IOCTL_VOE_DATA EC_IOWR(0x62, ec_ioctl_voe_t) -#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x63, size_t) +#define EC_IOCTL_REQUEST EC_IO(0x21) +#define EC_IOCTL_CREATE_DOMAIN EC_IO(0x22) +#define EC_IOCTL_CREATE_SLAVE_CONFIG EC_IOWR(0x23, ec_ioctl_config_t) +#define EC_IOCTL_SELECT_REF_CLOCK EC_IOW(0x24, uint32_t) +#define EC_IOCTL_ACTIVATE EC_IOR(0x25, ec_ioctl_master_activate_t) +#define EC_IOCTL_DEACTIVATE EC_IO(0x26) +#define EC_IOCTL_SEND EC_IO(0x27) +#define EC_IOCTL_RECEIVE EC_IO(0x28) +#define EC_IOCTL_MASTER_STATE EC_IOR(0x29, ec_master_state_t) +#define EC_IOCTL_MASTER_LINK_STATE EC_IOWR(0x2a, ec_ioctl_link_state_t) +#define EC_IOCTL_APP_TIME EC_IOW(0x2b, uint64_t) +#define EC_IOCTL_SYNC_REF EC_IO(0x2c) +#define EC_IOCTL_SYNC_REF_TO EC_IOW(0x2d, uint64_t) +#define EC_IOCTL_SYNC_SLAVES EC_IO(0x2e) +#define EC_IOCTL_REF_CLOCK_TIME EC_IOR(0x2f, uint32_t) +#define EC_IOCTL_SYNC_MON_QUEUE EC_IO(0x30) +#define EC_IOCTL_SYNC_MON_PROCESS EC_IOR(0x31, uint32_t) +#define EC_IOCTL_RESET EC_IO(0x32) +#define EC_IOCTL_SC_SYNC EC_IOW(0x33, ec_ioctl_config_t) +#define EC_IOCTL_SC_WATCHDOG EC_IOW(0x34, ec_ioctl_config_t) +#define EC_IOCTL_SC_ADD_PDO EC_IOW(0x35, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_CLEAR_PDOS EC_IOW(0x36, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_ADD_ENTRY EC_IOW(0x37, ec_ioctl_add_pdo_entry_t) +#define EC_IOCTL_SC_CLEAR_ENTRIES EC_IOW(0x38, ec_ioctl_config_pdo_t) +#define EC_IOCTL_SC_REG_PDO_ENTRY EC_IOWR(0x39, ec_ioctl_reg_pdo_entry_t) +#define EC_IOCTL_SC_REG_PDO_POS EC_IOWR(0x3a, ec_ioctl_reg_pdo_pos_t) +#define EC_IOCTL_SC_DC EC_IOW(0x3b, ec_ioctl_config_t) +#define EC_IOCTL_SC_SDO EC_IOW(0x3c, ec_ioctl_sc_sdo_t) +#define EC_IOCTL_SC_EMERG_SIZE EC_IOW(0x3d, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_POP EC_IOWR(0x3e, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3f, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x40, ec_ioctl_sc_emerg_t) +#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x41, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SC_SOE_REQUEST EC_IOWR(0x42, ec_ioctl_soe_request_t) +#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x43, ec_ioctl_reg_request_t) +#define EC_IOCTL_SC_VOE EC_IOWR(0x44, ec_ioctl_voe_t) +#define EC_IOCTL_SC_STATE EC_IOWR(0x45, ec_ioctl_sc_state_t) +#define EC_IOCTL_SC_IDN EC_IOW(0x46, ec_ioctl_sc_idn_t) +#define EC_IOCTL_SC_FLAG EC_IOW(0x47, ec_ioctl_sc_flag_t) +#ifdef EC_EOE +#define EC_IOCTL_SC_EOE_IP_PARAM EC_IOW(0x48, ec_ioctl_eoe_ip_t) +#endif +#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x49) +#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x4a) +#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x4b) +#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x4c) +#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4d, ec_ioctl_domain_state_t) +#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4e, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4f, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x50, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x51, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x52, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x53, ec_ioctl_sdo_request_t) +#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x54, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x55, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x56, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x57, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x58, ec_ioctl_soe_request_t) +#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x59, ec_ioctl_soe_request_t) +#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x5a, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x5b, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x5c, ec_ioctl_reg_request_t) +#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5d, ec_ioctl_reg_request_t) +#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5e, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5f, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ EC_IOW(0x60, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x61, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_WRITE EC_IOWR(0x62, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_EXEC EC_IOWR(0x63, ec_ioctl_voe_t) +#define EC_IOCTL_VOE_DATA EC_IOWR(0x64, ec_ioctl_voe_t) +#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x65, size_t) /****************************************************************************/ @@ -621,6 +625,7 @@ typedef struct { typedef struct { // input uint16_t slave_position; + uint16_t config_index; // alternatively uint8_t mac_address_included; uint8_t ip_address_included; @@ -630,15 +635,15 @@ typedef struct { uint8_t name_included; unsigned char mac_address[EC_ETH_ALEN]; - uint32_t ip_address; - uint32_t subnet_mask; - uint32_t gateway; - uint32_t dns; + struct in_addr ip_address; + struct in_addr subnet_mask; + struct in_addr gateway; + struct in_addr dns; char name[EC_MAX_HOSTNAME_SIZE]; // output uint16_t result; -} ec_ioctl_slave_eoe_ip_t; +} ec_ioctl_eoe_ip_t; /*****************************************************************************/ diff --git a/master/slave_config.c b/master/slave_config.c index a2cbf2ce..e331aa81 100644 --- a/master/slave_config.c +++ b/master/slave_config.c @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -28,15 +28,20 @@ /****************************************************************************/ -#include -#include +#include "slave_config.h" #include "globals.h" #include "master.h" #include "voe_handler.h" #include "flag.h" +#include "ioctl.h" -#include "slave_config.h" +#ifdef EC_EOE +#include "eoe_request.h" +#endif + +#include +#include /****************************************************************************/ @@ -85,6 +90,10 @@ void ec_slave_config_init( INIT_LIST_HEAD(&sc->soe_configs); INIT_LIST_HEAD(&sc->flags); +#ifdef EC_EOE + ec_eoe_request_init(&sc->eoe_ip_param_request); +#endif + ec_coe_emerg_ring_init(&sc->emerg_ring, sc); } @@ -1431,6 +1440,70 @@ int ecrt_slave_config_flag(ec_slave_config_t *sc, const char *key, /****************************************************************************/ +#ifdef EC_EOE + +int ecrt_slave_config_eoe_mac_address(ec_slave_config_t *sc, + const unsigned char *mac_address) +{ + memcpy(sc->eoe_ip_param_request.mac_address, mac_address, EC_ETH_ALEN); + sc->eoe_ip_param_request.mac_address_included = 1; + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_ip_address(ec_slave_config_t *sc, + struct in_addr ip_address) +{ + sc->eoe_ip_param_request.ip_address = ip_address; + sc->eoe_ip_param_request.ip_address_included = 1; + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_subnet_mask(ec_slave_config_t *sc, + struct in_addr subnet_mask) +{ + sc->eoe_ip_param_request.subnet_mask = subnet_mask; + sc->eoe_ip_param_request.subnet_mask_included = 1; + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_default_gateway(ec_slave_config_t *sc, + struct in_addr gateway_address) +{ + sc->eoe_ip_param_request.gateway = gateway_address; + sc->eoe_ip_param_request.gateway_included = 1; + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_dns_address(ec_slave_config_t *sc, + struct in_addr dns_address) +{ + sc->eoe_ip_param_request.dns = dns_address; + sc->eoe_ip_param_request.dns_included = 1; + return 0; +} + +/****************************************************************************/ + +int ecrt_slave_config_eoe_hostname(ec_slave_config_t *sc, + const char *name) +{ + strncpy(sc->eoe_ip_param_request.name, name, EC_MAX_HOSTNAME_SIZE - 1); + sc->eoe_ip_param_request.name_included = 1; + return 0; +} + +#endif + +/****************************************************************************/ + /** \cond */ EXPORT_SYMBOL(ecrt_slave_config_sync_manager); @@ -1459,6 +1532,14 @@ EXPORT_SYMBOL(ecrt_slave_config_create_reg_request); EXPORT_SYMBOL(ecrt_slave_config_state); EXPORT_SYMBOL(ecrt_slave_config_idn); EXPORT_SYMBOL(ecrt_slave_config_flag); +#ifdef EOE +EXPORT_SYMBOL(ecrt_slave_config_eoe_mac_address); +EXPORT_SYMBOL(ecrt_slave_config_eoe_ip_address); +EXPORT_SYMBOL(ecrt_slave_config_eoe_subnet_mask); +EXPORT_SYMBOL(ecrt_slave_config_eoe_default_gateway); +EXPORT_SYMBOL(ecrt_slave_config_eoe_dns_address); +EXPORT_SYMBOL(ecrt_slave_config_eoe_hostname); +#endif /** \endcond */ diff --git a/master/slave_config.h b/master/slave_config.h index 3ddd8dd8..688156fc 100644 --- a/master/slave_config.h +++ b/master/slave_config.h @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -141,6 +141,10 @@ struct ec_slave_config { struct list_head soe_configs; /**< List of SoE configurations. */ struct list_head flags; /**< List of feature flags. */ +#ifdef EC_EOE + ec_eoe_request_t eoe_ip_param_request; /**< EoE IP parameters. */ +#endif + ec_coe_emerg_ring_t emerg_ring; /**< CoE emergency ring buffer. */ }; diff --git a/tool/CommandConfig.cpp b/tool/CommandConfig.cpp index 55330a4e..cf726faa 100644 --- a/tool/CommandConfig.cpp +++ b/tool/CommandConfig.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -21,14 +21,16 @@ * ****************************************************************************/ +#include "CommandConfig.h" +#include "MasterDevice.h" + #include #include #include #include using namespace std; -#include "CommandConfig.h" -#include "MasterDevice.h" +#include /****************************************************************************/ @@ -147,6 +149,9 @@ void CommandConfig::showDetailedConfigs( ec_ioctl_config_sdo_t sdo; ec_ioctl_config_idn_t idn; ec_ioctl_config_flag_t flag; +#ifdef EC_EOE + ec_ioctl_eoe_ip_t ip; +#endif string indent(doIndent ? " " : ""); for (configIter = configList.begin(); @@ -299,6 +304,45 @@ void CommandConfig::showDetailedConfigs( cout << indent << " None." << endl; } +#ifdef EC_EOE + m.getIpParam(&ip, configIter->config_index); + if (ip.mac_address_included or ip.ip_address_included or + ip.subnet_mask_included or ip.gateway_included or + ip.dns_included or ip.name_included) { + char addr[32]; + cout << indent << "EoE IP parameters:" << endl; + if (ip.mac_address_included) { + cout << indent << " MAC address: " + << hex << setfill('0') << setw(2) + << ip.mac_address[0] << ":" + << ip.mac_address[1] << ":" + << ip.mac_address[2] << ":" + << ip.mac_address[3] << ":" + << ip.mac_address[4] << ":" + << ip.mac_address[5] << dec << endl; + } + if (ip.ip_address_included) { + inet_ntop(AF_INET, &ip.ip_address, addr, sizeof(addr)); + cout << indent << " IP address: " << addr << endl; + } + if (ip.subnet_mask_included) { + inet_ntop(AF_INET, &ip.subnet_mask, addr, sizeof(addr)); + cout << indent << " Subnet mask: " << addr << endl; + } + if (ip.gateway_included) { + inet_ntop(AF_INET, &ip.gateway, addr, sizeof(addr)); + cout << indent << " Default gateway: " << addr << endl; + } + if (ip.dns_included) { + inet_ntop(AF_INET, &ip.dns, addr, sizeof(addr)); + cout << indent << " DNS server address: " << addr << endl; + } + if (ip.name_included) { + cout << indent << " Hostname: " << ip.name << endl; + } + } +#endif + if (configIter->dc_assign_activate) { int i; diff --git a/tool/CommandIp.cpp b/tool/CommandIp.cpp index 09a41597..3c0484a5 100644 --- a/tool/CommandIp.cpp +++ b/tool/CommandIp.cpp @@ -53,13 +53,14 @@ string CommandIp::helpString(const string &binaryBaseName) const << endl << "IP parameters can be appended as argument pairs:" << endl << endl - << " addr [/prefix] IP address (optionally with" << endl - << " decimal subnet prefix)" << endl - << " link Link-layer address (may contain" << endl - << " colons or hyphens)" << endl - << " default Default gateway" << endl - << " dns DNS server" << endl - << " name Host name (max. 32 byte)" << endl + << " ip_address [/prefix] IP address (optionally with" << endl + << " decimal subnet prefix)" << endl + << " mac_address Link-layer address (may contain" + << endl + << " colons or hyphens)" << endl + << " default_gateway Default gateway" << endl + << " dns_address DNS server address" << endl + << " hostname Host name (max. 32 byte)" << endl << endl << "IPv4 adresses can be given either in dot notation or as" << endl << "hostnames, which will be automatically resolved." << endl @@ -88,30 +89,30 @@ void CommandIp::execute(const StringVector &args) throwInvalidUsageException(err); } - ec_ioctl_slave_eoe_ip_t io = {}; + ec_ioctl_eoe_ip_t io = {}; for (unsigned int argIdx = 0; argIdx < args.size(); argIdx += 2) { string arg = args[argIdx]; string val = args[argIdx + 1]; std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower); - if (arg == "link") { + if (arg == "link" or arg == "mac_address") { parseMac(io.mac_address, val); io.mac_address_included = 1; } - else if (arg == "addr") { + else if (arg == "addr" or arg == "ip_address") { parseIpv4Prefix(&io, val); io.ip_address_included = 1; } - else if (arg == "default") { + else if (arg == "default" or arg == "default_gateway") { resolveIpv4(&io.gateway, val); io.gateway_included = 1; } - else if (arg == "dns") { + else if (arg == "dns" or arg == "dns_adress") { resolveIpv4(&io.dns, val); io.dns_included = 1; } - else if (arg == "name") { + else if (arg == "name" or arg == "hostname") { if (val.size() > EC_MAX_HOSTNAME_SIZE - 1) { stringstream err; err << "Name too long!"; @@ -182,7 +183,7 @@ void CommandIp::parseMac(unsigned char mac[EC_ETH_ALEN], const string &str) /****************************************************************************/ -void CommandIp::parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *io, +void CommandIp::parseIpv4Prefix(ec_ioctl_eoe_ip_t *io, const string &str) { size_t pos = str.find('/'); @@ -205,11 +206,8 @@ void CommandIp::parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *io, err << "Invalid prefix '" << prefixStr << "'!"; throwInvalidUsageException(err); } - uint32_t mask = 0; - for (unsigned int bit = 0; bit < prefix; bit++) { - mask |= (1 << (31 - bit)); - } - io->subnet_mask = htonl(mask); + uint32_t mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF; + io->subnet_mask.s_addr = htonl(mask); } resolveIpv4(&io->ip_address, host); @@ -217,7 +215,7 @@ void CommandIp::parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *io, /****************************************************************************/ -void CommandIp::resolveIpv4(uint32_t *addr, const string &str) +void CommandIp::resolveIpv4(struct in_addr *dst, const string &str) { struct addrinfo hints = {}; struct addrinfo *res; @@ -238,12 +236,9 @@ void CommandIp::resolveIpv4(uint32_t *addr, const string &str) throwCommandException(err.str()); } - sockaddr_in *sin = (sockaddr_in *) res->ai_addr; - for (unsigned int i = 0; i < 4; i++) { - ((unsigned char *) addr)[i] = - ((unsigned char *) &sin->sin_addr.s_addr)[i]; - } - + const struct sockaddr_in *in_addr = + (const struct sockaddr_in *) res->ai_addr; + *dst = in_addr->sin_addr; freeaddrinfo(res); } diff --git a/tool/CommandIp.h b/tool/CommandIp.h index da11712b..bc6d9b8c 100644 --- a/tool/CommandIp.h +++ b/tool/CommandIp.h @@ -37,9 +37,8 @@ class CommandIp: protected: void parseMac(unsigned char [6], const string &); - void parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *, - const string &); - void resolveIpv4(uint32_t *, const string &); + void parseIpv4Prefix(ec_ioctl_eoe_ip_t *, const string &); + void resolveIpv4(struct in_addr *, const string &); }; /****************************************************************************/ diff --git a/tool/MasterDevice.cpp b/tool/MasterDevice.cpp index 4d67453f..ac256d88 100644 --- a/tool/MasterDevice.cpp +++ b/tool/MasterDevice.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -553,26 +553,6 @@ void MasterDevice::requestState( /****************************************************************************/ -#ifdef EC_EOE - -void MasterDevice::getEoeHandler( - ec_ioctl_eoe_handler_t *eoe, - uint16_t eoeHandlerIndex - ) -{ - eoe->eoe_index = eoeHandlerIndex; - - if (ioctl(fd, EC_IOCTL_EOE_HANDLER, eoe)) { - stringstream err; - err << "Failed to get EoE handler: " << strerror(errno); - throw MasterDeviceException(err); - } -} - -#endif - -/****************************************************************************/ - void MasterDevice::readSoe(ec_ioctl_slave_soe_read_t *data) { if (ioctl(fd, EC_IOCTL_SLAVE_SOE_READ, data) < 0) { @@ -604,7 +584,49 @@ void MasterDevice::writeSoe(ec_ioctl_slave_soe_write_t *data) /****************************************************************************/ #ifdef EC_EOE -void MasterDevice::setIpParam(ec_ioctl_slave_eoe_ip_t *data) + +void MasterDevice::getEoeHandler( + ec_ioctl_eoe_handler_t *eoe, + uint16_t eoeHandlerIndex + ) +{ + eoe->eoe_index = eoeHandlerIndex; + + if (ioctl(fd, EC_IOCTL_EOE_HANDLER, eoe)) { + stringstream err; + err << "Failed to get EoE handler: " << strerror(errno); + throw MasterDeviceException(err); + } +} + +#endif + +/****************************************************************************/ + +#ifdef EC_EOE + +void MasterDevice::getIpParam(ec_ioctl_eoe_ip_t *data, uint16_t config_index) +{ + data->config_index = config_index; + + if (ioctl(fd, EC_IOCTL_CONFIG_EOE_IP_PARAM, data) < 0) { + if (errno == EIO && data->result) { + throw MasterDeviceEoeException(data->result); + } else { + stringstream err; + err << "Failed to set IP parameters: " << strerror(errno); + throw MasterDeviceException(err); + } + } +} + +#endif + +/****************************************************************************/ + +#ifdef EC_EOE + +void MasterDevice::setIpParam(ec_ioctl_eoe_ip_t *data) { if (ioctl(fd, EC_IOCTL_SLAVE_EOE_IP_PARAM, data) < 0) { if (errno == EIO && data->result) { @@ -616,6 +638,7 @@ void MasterDevice::setIpParam(ec_ioctl_slave_eoe_ip_t *data) } } } + #endif /****************************************************************************/ diff --git a/tool/MasterDevice.h b/tool/MasterDevice.h index 0643eda7..bb6c8a8e 100644 --- a/tool/MasterDevice.h +++ b/tool/MasterDevice.h @@ -1,6 +1,6 @@ /***************************************************************************** * - * Copyright (C) 2006-2009 Florian Pose, Ingenieurgemeinschaft IgH + * Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH * * This file is part of the IgH EtherCAT Master. * @@ -152,12 +152,13 @@ class MasterDevice void requestState(uint16_t, uint8_t); void readFoe(ec_ioctl_slave_foe_t *); void writeFoe(ec_ioctl_slave_foe_t *); -#ifdef EC_EOE - void getEoeHandler(ec_ioctl_eoe_handler_t *, uint16_t); -#endif void readSoe(ec_ioctl_slave_soe_read_t *); void writeSoe(ec_ioctl_slave_soe_write_t *); - void setIpParam(ec_ioctl_slave_eoe_ip_t *); +#ifdef EC_EOE + void getEoeHandler(ec_ioctl_eoe_handler_t *, uint16_t); + void getIpParam(ec_ioctl_eoe_ip_t *, uint16_t); + void setIpParam(ec_ioctl_eoe_ip_t *); +#endif unsigned int getMasterCount() const {return masterCount;}