From 4bd7f23da8a903ddd667ace0029d121cb9704677 Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Wed, 24 Jul 2024 06:40:03 +0200 Subject: [PATCH 01/10] add: hardware layer rework --- include/libethercat/ec.h | 8 +- include/libethercat/hw.h | 57 ++++------ include/libethercat/hw_file.h | 18 ++- include/libethercat/hw_sock_raw.h | 20 +++- include/libethercat/hw_sock_raw_mmaped.h | 27 ++++- src/dc.c | 4 +- src/ec.c | 52 ++++----- src/hw.c | 134 ++--------------------- src/hw_file.c | 124 +++++++++++++++------ src/hw_sock_raw.c | 80 ++++++++------ src/hw_sock_raw_mmaped.c | 103 +++++++++-------- tools/eepromtool/eepromtool.c | 8 +- tools/ethercatdiag/ethercatdiag.c | 8 +- tools/example_with_dc/example_with_dc.c | 10 +- tools/foe_tool/foe_tool.c | 7 +- 15 files changed, 332 insertions(+), 328 deletions(-) diff --git a/include/libethercat/ec.h b/include/libethercat/ec.h index dffbeeb4..e45fc263 100644 --- a/include/libethercat/ec.h +++ b/include/libethercat/ec.h @@ -177,7 +177,7 @@ typedef struct ec_pd_group { //! ethercat master structure typedef struct ec { - hw_t hw; //!< pointer to hardware interface + struct hw_common *phw; //!< pointer to hardware interface pool_entry_t dg_entries[LEC_MAX_DATAGRAMS]; //!< static datagrams for datagram pool. pool_t pool; //!< datagram pool @@ -266,13 +266,11 @@ void ec_log(int lvl, const osal_char_t *pre, const osal_char_t *format, ...) __a * a initial scan of the bus. * * \param[out] pec Ethercat master instance pointer. - * \param[in] ifname Ethercat master interface name. - * \param[in] prio Receive thread priority. - * \param[in] cpumask Receive thread cpumask. + * \param[in] phw Ethercat master network device access. * \param[in] eeprom_log Log eeprom to stdout. * \return 0 on succes, otherwise error code */ -int ec_open(ec_t *pec, const osal_char_t *ifname, int prio, int cpumask, int eeprom_log); +int ec_open(ec_t *pec, struct hw_common *phw, int eeprom_log); //! \brief Closes ethercat master. /*! diff --git a/include/libethercat/hw.h b/include/libethercat/hw.h index a377344c..5bf80eeb 100644 --- a/include/libethercat/hw.h +++ b/include/libethercat/hw.h @@ -53,6 +53,10 @@ #include #endif +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (void *)(ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + /** \defgroup hardware_group HW * * This modules contains main EtherCAT hardware functions. @@ -64,7 +68,7 @@ // forward decl struct ec; -struct hw; +struct hw_common; //! Receive a frame from an EtherCAT hw device. /*! @@ -72,7 +76,7 @@ struct hw; * * \return 0 or negative error code */ -typedef int (*hw_device_recv_t)(struct hw *phw); +typedef int (*hw_device_recv_t)(struct hw_common *phw); //! Send a frame from an EtherCAT hw device. /*! @@ -81,13 +85,13 @@ typedef int (*hw_device_recv_t)(struct hw *phw); * * \return 0 or negative error code */ -typedef int (*hw_device_send_t)(struct hw *phw, ec_frame_t *pframe); +typedef int (*hw_device_send_t)(struct hw_common *phw, ec_frame_t *pframe); //! Doing internal stuff when finished sending frames /*! * \param[in] phw Pointer to hw handle. */ -typedef void (*hw_device_send_finished_t)(struct hw *phw); +typedef void (*hw_device_send_finished_t)(struct hw_common *phw); //! Get a free tx buffer from underlying hw device. /*! @@ -96,19 +100,15 @@ typedef void (*hw_device_send_finished_t)(struct hw *phw); * * \return 0 or negative error code */ -typedef int (*hw_device_get_tx_buffer_t)(struct hw *phw, ec_frame_t **ppframe); +typedef int (*hw_device_get_tx_buffer_t)(struct hw_common *phw, ec_frame_t **ppframe); + +#define ETH_FRAME_LEN 0x1518 //! hardware structure -typedef struct hw { +typedef struct hw_common { struct ec *pec; //!< Pointer to EtherCAT master structure. - int sockfd; //!< raw socket file descriptor osal_uint32_t mtu_size; //!< mtu size - - // receiver thread settings - osal_task_t rxthread; //!< receiver thread handle - int rxthreadrunning; //!< receiver thread running flag - osal_mutex_t hw_lock; //!< transmit lock pool_t tx_high; //!< high priority datagrams @@ -125,27 +125,13 @@ typedef struct hw { hw_device_send_finished_t send_finished; //!< \brief Function to be called after frames were sent. hw_device_get_tx_buffer_t get_tx_buffer; //!< \brief Function to retreave next TX buffer. -#define ETH_FRAME_LEN 0x1518 - osal_uint8_t send_frame[ETH_FRAME_LEN]; //!< \brief Static send frame. - osal_uint8_t recv_frame[ETH_FRAME_LEN]; //!< \brief Static receive frame. - osal_bool_t polling_mode; //!< \brief Special interrupt-less polling-mode flag. - -#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 - int mmap_packets; //!< \brief Doing mmap packets. - osal_char_t *rx_ring; //!< kernel mmap receive buffers - osal_char_t *tx_ring; //!< kernel mmap send buffers - - osal_off_t rx_ring_offset; //!< \brief Offset in RX ring. - osal_off_t tx_ring_offset; //!< \brief Offset in TX ring. -#endif - #if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 osal_bool_t use_sbuf; vm_file_desc_t fd; //!< \brief Driver file descriptor. drv_sbuf_desc_t sbuf; //!< \brief Driver SBUF descriptor. #endif -} hw_t; //!< \brief Hardware struct type. +} hw_common_t; //!< \brief Hardware struct type. #ifdef __cplusplus extern "C" { @@ -153,41 +139,40 @@ extern "C" { //! open a new hw /*! - * \param phw return hw - * \param devname ethernet device name - * \param prio receive thread prio - * \param cpumask receive thread cpumask + * \param[in] phw Pointer to hw structure. + * \param[in] pec Pointer to master structure. + * * \return 0 or negative error code */ -int hw_open(hw_t *phw, struct ec *pec, const osal_char_t *devname, int prio, int cpumask); +int hw_open(struct hw_common *phw, struct ec *pec); //! destroys a hw /*! * \param phw hw handle * \return 0 or negative error code */ -int hw_close(hw_t *phw); +int hw_close(struct hw_common *phw); //! start sending queued ethercat datagrams /*! * \param phw hardware handle * \return 0 or error code */ -int hw_tx_low(hw_t *phw); +int hw_tx_low(struct hw_common *phw); //! start sending queued ethercat datagrams /*! * \param phw hardware handle * \return 0 or error code */ -int hw_tx(hw_t *phw); +int hw_tx(struct hw_common *phw); //! Process a received EtherCAT frame /*! * \param[in] phw Pointer to hw handle. * \param[in] pframe Pointer to received EtherCAT frame. */ -void hw_process_rx_frame(hw_t *phw, ec_frame_t *pframe); +void hw_process_rx_frame(struct hw_common *phw, ec_frame_t *pframe); #ifdef __cplusplus } diff --git a/include/libethercat/hw_file.h b/include/libethercat/hw_file.h index 1a2d14ab..a661c51e 100644 --- a/include/libethercat/hw_file.h +++ b/include/libethercat/hw_file.h @@ -42,14 +42,30 @@ #include +typedef struct hw_file { + struct hw_common common; + + int fd; //!< \brief file descriptor + + osal_uint8_t send_frame[ETH_FRAME_LEN]; //!< \brief Static send frame. + osal_uint8_t recv_frame[ETH_FRAME_LEN]; //!< \brief Static receive frame. + osal_bool_t polling_mode; //!< \brief Special interrupt-less polling-mode flag. + + // receiver thread settings in non-polling mode + osal_task_t rxthread; //!< receiver thread handle + int rxthreadrunning; //!< receiver thread running flag +} hw_file_t; + //! Opens EtherCAT hw device. /*! * \param[in] phw Pointer to hw handle. * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] prio Priority for receiver thread. + * \param[in] cpu_mask CPU mask for receiver thread. * * \return 0 or negative error code */ -int hw_device_file_open(hw_t *phw, const osal_char_t *devname); +int hw_device_file_open(struct hw_file *phw, struct ec *pec, const osal_char_t *devname, int prio, int cpu_mask); #endif // LIBETHERCAT_HW_FILE_H diff --git a/include/libethercat/hw_sock_raw.h b/include/libethercat/hw_sock_raw.h index b40f9333..14d2f02a 100644 --- a/include/libethercat/hw_sock_raw.h +++ b/include/libethercat/hw_sock_raw.h @@ -41,15 +41,33 @@ #define LIBETHERCAT_HW_SOCK_RAW_H #include +#include +#include + +typedef struct hw_sock_raw { + struct hw_common common; + + int sockfd; //!< raw socket file descriptor + + osal_uint8_t send_frame[ETH_FRAME_LEN]; //!< \brief Static send frame. + osal_uint8_t recv_frame[ETH_FRAME_LEN]; //!< \brief Static receive frame. + + // receiver thread settings + osal_task_t rxthread; //!< receiver thread handle + int rxthreadrunning; //!< receiver thread running flag +} hw_sock_raw_t; //! Opens EtherCAT hw device. /*! * \param[in] phw Pointer to hw handle. + * \param[in] pec Pointer to master structure. * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] prio Priority for receiver thread. + * \param[in] cpu_mask CPU mask for receiver thread. * * \return 0 or negative error code */ -int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname); +int hw_device_sock_raw_open(struct hw_sock_raw *phw, struct ec *pec, const osal_char_t *devname, int prio, int cpu_mask); #endif // LIBETHERCAT_HW_SOCK_RAW_H diff --git a/include/libethercat/hw_sock_raw_mmaped.h b/include/libethercat/hw_sock_raw_mmaped.h index 1d996f15..77f22e1a 100644 --- a/include/libethercat/hw_sock_raw_mmaped.h +++ b/include/libethercat/hw_sock_raw_mmaped.h @@ -41,15 +41,36 @@ #define LIBETHERCAT_HW_SOCK_RAW_MMAPED_H #include +#include + +typedef struct hw_sock_raw_mmaped { + struct hw_common common; + + int sockfd; //!< raw socket file descriptor + + osal_uint8_t send_frame[ETH_FRAME_LEN]; //!< \brief Static send frame. + osal_uint8_t recv_frame[ETH_FRAME_LEN]; //!< \brief Static receive frame. + + int mmap_packets; //!< \brief Doing mmap packets. + osal_char_t *rx_ring; //!< kernel mmap receive buffers + osal_char_t *tx_ring; //!< kernel mmap send buffers + + osal_off_t rx_ring_offset; //!< \brief Offset in RX ring. + osal_off_t tx_ring_offset; //!< \brief Offset in TX ring. + + // receiver thread settings + osal_task_t rxthread; //!< receiver thread handle + int rxthreadrunning; //!< receiver thread running flag +} hw_sock_raw_mmaped_t; //! Opens EtherCAT hw device. /*! - * \param[in] phw Pointer to hw handle. - * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] phw_sock_raw_mmaped Pointer to sock_raw_mmmaped hw handle. + * \param[in] devname Null-terminated string to EtherCAT hw device name. * * \return 0 or negative error code */ -int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname); +int hw_device_sock_raw_mmaped_open(struct hw_sock_raw_mmaped *phw_sock_raw_mmaped, const osal_char_t *devname); #endif // LIBETHERCAT_HW_SOCK_RAW_MMAPED_H diff --git a/src/dc.c b/src/dc.c index 344f9111..662524dc 100644 --- a/src/dc.c +++ b/src/dc.c @@ -94,10 +94,10 @@ static inline osal_uint64_t get_packet_duration(ec_t *pec) { } &anon_cb; }); // queue frame and trigger tx - pool_put(&pec->hw.tx_high, p_entry); + pool_put(&pec->phw->tx_high, p_entry); osal_uint64_t start = osal_timer_gettime_nsec(); - hw_tx(&pec->hw); + hw_tx(pec->phw); // wait for completion osal_timer_t to; diff --git a/src/ec.c b/src/ec.c index 358c7b64..30c4a9e1 100644 --- a/src/ec.c +++ b/src/ec.c @@ -993,7 +993,7 @@ int ec_set_state(ec_t *pec, ec_state_t state) { ec_pd_group_t *pd = &pec->pd_groups[i]; if (pd->cdg.p_idx != NULL) { - pec->hw.tx_send[pd->cdg.p_idx->idx] = NULL; + pec->phw->tx_send[pd->cdg.p_idx->idx] = NULL; ec_index_put(&pec->idx_q, pd->cdg.p_idx); pd->cdg.p_idx = NULL; } @@ -1006,7 +1006,7 @@ int ec_set_state(ec_t *pec, ec_state_t state) { // return distributed clocks datagram if (pec->dc.cdg.p_idx != NULL) { - pec->hw.tx_send[pec->dc.cdg.p_idx->idx] = NULL; + pec->phw->tx_send[pec->dc.cdg.p_idx->idx] = NULL; ec_index_put(&pec->idx_q, pec->dc.cdg.p_idx); pec->dc.cdg.p_idx = NULL; } @@ -1018,7 +1018,7 @@ int ec_set_state(ec_t *pec, ec_state_t state) { // return broadcast state datagram if (pec->cdg_state.p_idx != NULL) { - pec->hw.tx_send[pec->cdg_state.p_idx->idx] = NULL; + pec->phw->tx_send[pec->cdg_state.p_idx->idx] = NULL; ec_index_put(&pec->idx_q, pec->cdg_state.p_idx); pec->cdg_state.p_idx = NULL; } @@ -1065,15 +1065,13 @@ int ec_set_state(ec_t *pec, ec_state_t state) { //! open ethercat master /*! * \param ppec return value for ethercat master pointer - * \param ifname ethercat master interface name - * \param prio receive thread priority - * \param cpumask receive thread cpumask + * \param phw ethercat master network device access * \param eeprom_log log eeprom to stdout * \return 0 on succes, otherwise error code */ -int ec_open(ec_t *pec, const osal_char_t *ifname, int prio, int cpumask, int eeprom_log) { +int ec_open(ec_t *pec, struct hw_common *phw, int eeprom_log) { assert(pec != NULL); - assert(ifname != NULL); + assert(phw != NULL); // reset data structure (void)memset(pec, 0, sizeof(ec_t)); @@ -1120,10 +1118,8 @@ int ec_open(ec_t *pec, const osal_char_t *ifname, int prio, int cpumask, int eep (void)pool_open(&pec->mbx_message_pool_recv_free, LEC_MAX_MBX_ENTRIES, &pec->mbx_mp_recv_free_entries[0]); (void)pool_open(&pec->mbx_message_pool_send_free, LEC_MAX_MBX_ENTRIES, &pec->mbx_mp_send_free_entries[0]); - if (ret == EC_OK) { - ret = hw_open(&pec->hw, pec, ifname, prio, cpumask); - } - + pec->phw = phw; + if (ret == EC_OK) { ret = ec_async_loop_create(&pec->async_loop, pec); } @@ -1154,7 +1150,7 @@ int ec_open(ec_t *pec, const osal_char_t *ifname, int prio, int cpumask, int eep if (pec != NULL) { ec_log(1, "MASTER_OPEN", "error occured, closing EtherCAT!\n"); - int local_ret = hw_close(&pec->hw); + int local_ret = hw_close(pec->phw); if (local_ret != EC_OK) { ec_log(1, "MASTER_OPEN", "hw_close failed with %d\n", local_ret); } @@ -1186,7 +1182,7 @@ int ec_close(ec_t *pec) { ec_log(10, "MASTER_CLOSE", "destroying async loop\n"); (void)ec_async_loop_destroy(&pec->async_loop); ec_log(10, "MASTER_CLOSE", "closing hardware handle\n"); - (void)hw_close(&pec->hw); + (void)hw_close(pec->phw); ec_log(10, "MASTER_CLOSE", "freeing frame pool\n"); (void)pool_close(&pec->pool); @@ -1267,20 +1263,20 @@ int ec_transceive(ec_t *pec, osal_uint8_t cmd, osal_uint32_t adr, p_entry->user_cb = cb_block; // queue frame and trigger tx - pool_put(&pec->hw.tx_low, p_entry); + pool_put(&pec->phw->tx_low, p_entry); // send frame immediately if in sync mode if ( (pec->master_state != EC_STATE_SAFEOP) && (pec->master_state != EC_STATE_OP)) { - if (hw_tx_low(&pec->hw) != EC_OK) { + if (hw_tx_low(pec->phw) != EC_OK) { ec_log(1, "MASTER_TRANSCEIVE", "hw_tx failed!\n"); } } else { osal_timer_t test; // max mtu frame, 10 [ns] per bit on 100 Mbit/s, 150% threshold - osal_timer_init(&test, (10 * 8 * pec->hw.mtu_size) * 1.5); - if (osal_timer_cmp(&test, &pec->hw.next_cylce_start, <)) { - if (hw_tx_low(&pec->hw) != EC_OK) { + osal_timer_init(&test, (10 * 8 * pec->phw->mtu_size) * 1.5); + if (osal_timer_cmp(&test, &pec->phw->next_cylce_start, <)) { + if (hw_tx_low(pec->phw) != EC_OK) { ec_log(1, "MASTER_TRANSCEIVE", "hw_tx_low failed!\n"); } } @@ -1364,12 +1360,12 @@ int ec_transmit_no_reply(ec_t *pec, osal_uint8_t cmd, osal_uint32_t adr, p_entry->user_cb = cb_no_reply; // queue frame and return, we don't care about an answer - pool_put(&pec->hw.tx_low, p_entry); + pool_put(&pec->phw->tx_low, p_entry); // send frame immediately if in sync mode if ( (pec->master_state != EC_STATE_SAFEOP) && (pec->master_state != EC_STATE_OP) ) { - if (hw_tx_low(&pec->hw) != EC_OK) { + if (hw_tx_low(pec->phw) != EC_OK) { ec_log(1, "MASTER_TRANSMIT_NO_REPLY", "hw_tx_low failed!\n"); } } @@ -1581,7 +1577,7 @@ static int ec_send_process_data_group(ec_t *pec, int group) { } // queue frame and trigger tx - pool_put(&pec->hw.tx_high, pd->cdg.p_entry); + pool_put(&pec->phw->tx_high, pd->cdg.p_entry); } } @@ -1624,7 +1620,7 @@ static int ec_send_process_data_group(ec_t *pec, int group) { } // queue frame and trigger tx - pool_put(&pec->hw.tx_high, pd->cdg_lwr.p_entry); + pool_put(&pec->phw->tx_high, pd->cdg_lwr.p_entry); } } @@ -1663,7 +1659,7 @@ static int ec_send_process_data_group(ec_t *pec, int group) { p_dg->len = pd->pdin_len; // queue frame and trigger tx - pool_put(&pec->hw.tx_high, pd->cdg_lrd.p_entry); + pool_put(&pec->phw->tx_high, pd->cdg_lrd.p_entry); } } @@ -1703,7 +1699,7 @@ static int ec_send_process_data_group(ec_t *pec, int group) { p_dg->len = pd->log_mbx_state_len; // queue frame and trigger tx - pool_put(&pec->hw.tx_high, pd->cdg_lrd_mbx_state.p_entry); + pool_put(&pec->phw->tx_high, pd->cdg_lrd_mbx_state.p_entry); } } @@ -1809,7 +1805,7 @@ static void cb_distributed_clocks(struct ec *pec, pool_entry_t *p_entry, ec_data p_entry_dc_sto->user_cb = cb_no_reply; // queue frame and trigger tx - pool_put(&pec->hw.tx_low, p_entry_dc_sto); + pool_put(&pec->phw->tx_low, p_entry_dc_sto); } } else {} } @@ -1891,7 +1887,7 @@ int ec_send_distributed_clocks_sync(ec_t *pec) { } // queue frame and trigger tx - pool_put(&pec->hw.tx_high, pec->dc.cdg.p_entry); + pool_put(&pec->phw->tx_high, pec->dc.cdg.p_entry); pec->dc.sent_time_nsec = act_rtc_time; } @@ -1992,7 +1988,7 @@ int ec_send_brd_ec_state(ec_t *pec) { p_dg->len = 2; // queue frame and trigger tx - pool_put(&pec->hw.tx_high, pec->cdg_state.p_entry); + pool_put(&pec->phw->tx_high, pec->cdg_state.p_entry); osal_timer_init(&pec->cdg_state.timeout, 10000000); } diff --git a/src/hw.c b/src/hw.c index 667db88b..c941b1c0 100644 --- a/src/hw.c +++ b/src/hw.c @@ -39,27 +39,6 @@ #include #include - -#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 -#include -#endif - -#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 -#include -#endif - -#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 -#include -#endif - -#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 -#include -#endif - -#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 -#include -#endif - #include #include #include @@ -88,21 +67,17 @@ #include #endif -//! receiver thread forward declaration -void *hw_rx_thread(void *arg); - //! open a new hw /*! - * \param pphw return hw - * \param devname ethernet device name - * \param prio receive thread prio - * \param cpumask receive thread cpumask + * \param[in] phw Pointer to hw structure. + * \param[in] pec Pointer to master structure. + * * \return 0 or negative error code */ -int hw_open(hw_t *phw, struct ec *pec, const osal_char_t *devname, int prio, int cpumask) { +int hw_open(struct hw_common *phw, struct ec *pec) { assert(phw != NULL); - int ret = EC_ERROR_HW_NOT_SUPPORTED; + int ret = EC_OK; phw->pec = pec; phw->bytes_last_sent = 0; @@ -112,66 +87,6 @@ int hw_open(hw_t *phw, struct ec *pec, const osal_char_t *devname, int prio, int osal_mutex_init(&phw->hw_lock, NULL); - const osal_char_t *ifname = devname; - -#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 - if ((ifname[0] == '/') || (strncmp(ifname, "file:", 5) == 0)) { - // assume char device -> hw_file - if (strncmp(ifname, "file:", 5) == 0) { - ifname = &ifname[5]; - } - - ec_log(10, "HW_OPEN", "Opening interface as device file: %s\n", ifname); - ret = hw_device_file_open(phw, ifname); - } else -#endif - { -#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 - if (strncmp(ifname, "bpf:", 4) == 0) { - ifname = &ifname[4]; - - ec_log(10, "HW_OPEN", "Opening interface as BPF: %s\n", ifname); - ret = hw_device_bpf_open(phw, ifname); - } else -#endif -#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 - if (strncmp(ifname, "pikeos:", 7) == 0) { - ifname = &ifname[7]; - - ec_log(10, "HW_OPEN", "Opening interface as pikeos: %s\n", ifname); - ret = hw_device_pikeos_open(phw, ifname); - } else -#endif -#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 - if (strncmp(ifname, "sock-raw-mmaped:", 16) == 0) { - ifname = &ifname[16]; - - ec_log(10, "HW_OPEN", "Opening interface as mmaped SOCK_RAW: %s\n", ifname); - ret = hw_device_sock_raw_mmaped_open(phw, ifname); - } else -#endif - { -#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 - if (strncmp(ifname, "sock-raw:", 9) == 0) { - ifname = &ifname[9]; - } - - ec_log(10, "HW_OPEN", "Opening interface as SOCK_RAW: %s\n", ifname); - ret = hw_device_sock_raw_open(phw, ifname); -#endif - } - } - - if (ret == EC_OK) { - phw->rxthreadrunning = 1; - osal_task_attr_t attr; - attr.policy = OSAL_SCHED_POLICY_FIFO; - attr.priority = prio; - attr.affinity = cpumask; - (void)strcpy(&attr.task_name[0], "ecat.rx"); - osal_task_create(&phw->rxthread, &attr, hw_rx_thread, phw); - } - return ret; } @@ -180,13 +95,9 @@ int hw_open(hw_t *phw, struct ec *pec, const osal_char_t *devname, int prio, int * \param phw hw handle * \return 0 or negative error code */ -int hw_close(hw_t *phw) { +int hw_close(struct hw_common *phw) { assert(phw != NULL); - // stop receiver thread - phw->rxthreadrunning = 0; - osal_task_join(&phw->rxthread, NULL); - osal_mutex_lock(&phw->hw_lock); (void)pool_close(&phw->tx_high); (void)pool_close(&phw->tx_low); @@ -202,7 +113,7 @@ int hw_close(hw_t *phw) { * \param[in] phw Pointer to hw handle. * \param[in] pframe Pointer to received EtherCAT frame. */ -void hw_process_rx_frame(hw_t *phw, ec_frame_t *pframe) { +void hw_process_rx_frame(struct hw_common *phw, ec_frame_t *pframe) { assert(phw != NULL); assert(pframe != NULL); @@ -228,33 +139,8 @@ void hw_process_rx_frame(hw_t *phw, ec_frame_t *pframe) { } } -//! receiver thread -void *hw_rx_thread(void *arg) { - // cppcheck-suppress misra-c2012-11.5 - hw_t *phw = (hw_t *) arg; - - assert(phw != NULL); - - osal_task_sched_priority_t rx_prio; - if (osal_task_get_priority(&phw->rxthread, &rx_prio) != OSAL_OK) { - rx_prio = 0; - } - - ec_log(10, "HW_RX", "receive thread running (prio %d)\n", rx_prio); - - while (phw->rxthreadrunning != 0) { - if (phw->recv(phw) != EC_OK) { - break; - } - } - - ec_log(10, "HW_RX", "receive thread stopped\n"); - - return NULL; -} - //! internal tx func -static void hw_tx_pool(hw_t *phw, pool_t *pool) { +static void hw_tx_pool(struct hw_common *phw, pool_t *pool) { assert(phw != NULL); osal_bool_t sent = OSAL_FALSE; @@ -314,7 +200,7 @@ static void hw_tx_pool(hw_t *phw, pool_t *pool) { * \param phw hardware handle * \return 0 or error code */ -int hw_tx_low(hw_t *phw) { +int hw_tx_low(struct hw_common *phw) { assert(phw != NULL); int ret = EC_OK; @@ -331,7 +217,7 @@ int hw_tx_low(hw_t *phw) { * \param phw hardware handle * \return 0 or error code */ -int hw_tx(hw_t *phw) { +int hw_tx(struct hw_common *phw) { assert(phw != NULL); int ret = EC_OK; diff --git a/src/hw_file.c b/src/hw_file.c index f8b56c86..010017f3 100644 --- a/src/hw_file.c +++ b/src/hw_file.c @@ -38,7 +38,7 @@ */ #include -#include +#include #include #include #include @@ -73,73 +73,115 @@ #define ETHERCAT_DEVICE_GET_POLLING _IOR (ETHERCAT_DEVICE_MAGIC, 2, unsigned int) // forward declarations -int hw_device_file_send(hw_t *phw, ec_frame_t *pframe); -int hw_device_file_recv(hw_t *phw); -void hw_device_file_send_finished(hw_t *phw); -int hw_device_file_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe); +int hw_device_file_send(struct hw_common *phw, ec_frame_t *pframe); +int hw_device_file_recv(struct hw_common *phw); +void hw_device_file_send_finished(struct hw_common *phw); +int hw_device_file_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe); + +static void hw_device_file_recv_internal(struct hw_file *phw_file); +static void *hw_device_file_rx_thread(void *arg); //! Opens EtherCAT hw device. /*! * \param[in] phw Pointer to hw handle. * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] prio Priority for receiver thread. + * \param[in] cpu_mask CPU mask for receiver thread. * * \return 0 or negative error code */ -int hw_device_file_open(hw_t *phw, const osal_char_t *devname) { +int hw_device_file_open(struct hw_file *phw_file, struct ec *pec, const osal_char_t *devname, int prio, int cpumask) { int ret = EC_OK; ec_frame_t *pframe = NULL; static const osal_uint8_t mac_dest[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const osal_uint8_t mac_src[] = {0x00, 0x30, 0x64, 0x0f, 0x83, 0x35}; - phw->send = hw_device_file_send; - phw->recv = hw_device_file_recv; - phw->send_finished = hw_device_file_send_finished; - phw->get_tx_buffer = hw_device_file_get_tx_buffer; + hw_open(&phw_file->common, pec); + + phw_file->common.send = hw_device_file_send; + phw_file->common.recv = hw_device_file_recv; + phw_file->common.send_finished = hw_device_file_send_finished; + phw_file->common.get_tx_buffer = hw_device_file_get_tx_buffer; /* we use file link layer device driver */ // cppcheck-suppress misra-c2012-7.1 - phw->sockfd = open(devname, O_RDWR, 0644); - if (phw->sockfd <= 0) { + phw_file->fd = open(devname, O_RDWR, 0644); + if (phw_file->fd <= 0) { ec_log(1, "HW_OPEN", "error opening %s: %s\n", devname, strerror(errno)); ret = EC_ERROR_HW_NO_INTERFACE; } else { - phw->mtu_size = 1480; + phw_file->common.mtu_size = 1480; // cppcheck-suppress misra-c2012-11.3 - pframe = (ec_frame_t *)phw->send_frame; + pframe = (ec_frame_t *)phw_file->send_frame; (void)memcpy(pframe->mac_dest, mac_dest, 6); (void)memcpy(pframe->mac_src, mac_src, 6); // check polling mode - phw->polling_mode = OSAL_FALSE; + phw_file->polling_mode = OSAL_FALSE; #if LIBETHERCAT_HAVE_SYS_IOCTL_H == 1 unsigned int pollval = 0; - if (ioctl(phw->sockfd, ETHERCAT_DEVICE_GET_POLLING, &pollval) >= 0) { - phw->polling_mode = pollval == 0 ? OSAL_FALSE : OSAL_TRUE; + if (ioctl(phw_file->fd, ETHERCAT_DEVICE_GET_POLLING, &pollval) >= 0) { + phw_file->polling_mode = pollval == 0 ? OSAL_FALSE : OSAL_TRUE; } unsigned int monitor = 0; - (void)ioctl(phw->sockfd, ETHERCAT_DEVICE_MONITOR_ENABLE, &monitor); + (void)ioctl(phw_file->fd, ETHERCAT_DEVICE_MONITOR_ENABLE, &monitor); #endif - ec_log(10, "HW_OPEN", "%s polling mode\n", phw->polling_mode == OSAL_FALSE ? "not using" : "using"); + ec_log(10, "HW_OPEN", "%s polling mode\n", phw_file->polling_mode == OSAL_FALSE ? "not using" : "using"); + } + + if (ret == EC_OK) { + if (phw_file->polling_mode == OSAL_FALSE) { + phw_file->rxthreadrunning = 1; + osal_task_attr_t attr; + attr.policy = OSAL_SCHED_POLICY_FIFO; + attr.priority = prio; + attr.affinity = cpumask; + (void)strcpy(&attr.task_name[0], "ecat.rx"); + osal_task_create(&phw_file->rxthread, &attr, hw_device_file_rx_thread, phw_file); + } } return ret; } -static void hw_device_file_recv_internal(hw_t *phw) { +void hw_device_file_recv_internal(struct hw_file *phw_file) { // cppcheck-suppress misra-c2012-11.3 - ec_frame_t *pframe = (ec_frame_t *) &phw->recv_frame; + ec_frame_t *pframe = (ec_frame_t *) &phw_file->recv_frame; // using tradional recv function - osal_ssize_t bytesrx = read(phw->sockfd, pframe, ETH_FRAME_LEN); + osal_ssize_t bytesrx = read(phw_file->fd, pframe, ETH_FRAME_LEN); if (bytesrx > 0) { - hw_process_rx_frame(phw, pframe); + hw_process_rx_frame(&phw_file->common, pframe); } } +//! receiver thread +void *hw_device_file_rx_thread(void *arg) { + // cppcheck-suppress misra-c2012-11.5 + struct hw_file *phw_file = (struct hw_file *) arg; + + assert(phw_file != NULL); + + osal_task_sched_priority_t rx_prio; + if (osal_task_get_priority(&phw_file->rxthread, &rx_prio) != OSAL_OK) { + rx_prio = 0; + } + + ec_log(10, "HW_FILE_RX", "receive thread running (prio %d)\n", rx_prio); + + while (phw_file->rxthreadrunning != 0) { + hw_device_file_recv_internal(phw_file); + } + + ec_log(10, "HW_FILE_RX", "receive thread stopped\n"); + + return NULL; +} + //! Receive a frame from an EtherCAT hw device. /*! * \param[in] phw Pointer to hw handle. @@ -147,12 +189,16 @@ static void hw_device_file_recv_internal(hw_t *phw) { * * \return 0 or negative error code */ -int hw_device_file_recv(hw_t *phw) { - if (phw->polling_mode == OSAL_TRUE) { +int hw_device_file_recv(struct hw_common *phw) { + assert(phw != NULL); + + struct hw_file *phw_file = container_of(phw, struct hw_file, common); + + if (phw_file->polling_mode == OSAL_TRUE) { return EC_ERROR_HW_NOT_SUPPORTED; } - hw_device_file_recv_internal(phw); + hw_device_file_recv_internal(phw_file); return EC_OK; } @@ -164,15 +210,16 @@ int hw_device_file_recv(hw_t *phw) { * * \return 0 or negative error code */ -int hw_device_file_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { +int hw_device_file_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe) { assert(phw != NULL); assert(ppframe != NULL); int ret = EC_OK; ec_frame_t *pframe = NULL; + struct hw_file *phw_file = container_of(phw, struct hw_file, common); // cppcheck-suppress misra-c2012-11.3 - pframe = (ec_frame_t *)phw->send_frame; + pframe = (ec_frame_t *)phw_file->send_frame; // reset length to send new frame pframe->ethertype = htons(ETH_P_ECAT); @@ -191,14 +238,15 @@ int hw_device_file_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { * * \return 0 or negative error code */ -int hw_device_file_send(hw_t *phw, ec_frame_t *pframe) { +int hw_device_file_send(struct hw_common *phw, ec_frame_t *pframe) { assert(phw != NULL); assert(pframe != NULL); int ret = EC_OK; + struct hw_file *phw_file = container_of(phw, struct hw_file, common); // no more datagrams need to be sent or no more space in frame - osal_ssize_t bytestx = write(phw->sockfd, pframe, pframe->len); + osal_ssize_t bytestx = write(phw_file->fd, pframe, pframe->len); if ((osal_ssize_t)pframe->len != bytestx) { ec_log(1, "HW_TX", "got only %" PRId64 " bytes out of %d bytes " @@ -211,7 +259,7 @@ int hw_device_file_send(hw_t *phw, ec_frame_t *pframe) { ret = EC_ERROR_HW_SEND; } - phw->bytes_sent += bytestx; + phw_file->common.bytes_sent += bytestx; return ret; } @@ -220,17 +268,21 @@ int hw_device_file_send(hw_t *phw, ec_frame_t *pframe) { /*! * \param[in] phw Pointer to hw handle. */ -void hw_device_file_send_finished(hw_t *phw) { +void hw_device_file_send_finished(struct hw_common *phw) { + assert(phw != NULL); + + struct hw_file *phw_file = container_of(phw, struct hw_file, common); + // in case of polling do receive now - if (phw->polling_mode == OSAL_TRUE) { + if (phw_file->polling_mode == OSAL_TRUE) { // sleep a little bit (at least packet-on-wire-duration) // 10 [ns] per bit on 100 Mbit/s Ethernet. //uint64_t packet_time = 10 * 8 * phw->bytes_sent; //osal_sleep(packet_time * 0.4); - phw->bytes_last_sent = phw->bytes_sent; - phw->bytes_sent = 0; + phw_file->common.bytes_last_sent = phw_file->common.bytes_sent; + phw_file->common.bytes_sent = 0; - hw_device_file_recv_internal(phw); + hw_device_file_recv_internal(phw_file); } } diff --git a/src/hw_sock_raw.c b/src/hw_sock_raw.c index b83bee0b..843593c0 100644 --- a/src/hw_sock_raw.c +++ b/src/hw_sock_raw.c @@ -38,7 +38,7 @@ */ #include -#include +#include #include #include #include @@ -65,10 +65,10 @@ #include // forward declarations -int hw_device_sock_raw_send(hw_t *phw, ec_frame_t *pframe); -int hw_device_sock_raw_recv(hw_t *phw); -void hw_device_sock_raw_send_finished(hw_t *phw); -int hw_device_sock_raw_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe); +int hw_device_sock_raw_send(struct hw_common *phw, ec_frame_t *pframe); +int hw_device_sock_raw_recv(struct hw_common *phw); +void hw_device_sock_raw_send_finished(struct hw_common *phw); +int hw_device_sock_raw_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe); // this need the grant_cap_net_raw kernel module // see https://gitlab.com/fastflo/open_ethercat @@ -100,12 +100,15 @@ static int try_grant_cap_net_raw_init(void) { //! Opens EtherCAT hw device. /*! - * \param[in] phw Pointer to hw handle. - * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] phw_sock_raw Pointer to sock raw hw handle. + * \param[in] pec Pointer to master structure. + * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] prio Priority for receiver thread. + * \param[in] cpu_mask CPU mask for receiver thread. * * \return 0 or negative error code */ -int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { +int hw_device_sock_raw_open(struct hw_sock_raw *phw_sock_raw, struct ec *pec, const osal_char_t *devname, int prio, int cpumask) { int ret = EC_OK; struct ifreq ifr; int ifindex; @@ -114,15 +117,17 @@ int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { ec_log(10, "hw_open", "grant_cap_net_raw unsuccessfull, maybe we are " "not allowed to open a raw socket\n"); } + + hw_open(&phw_sock_raw->common, pec); - phw->send = hw_device_sock_raw_send; - phw->recv = hw_device_sock_raw_recv; - phw->send_finished = hw_device_sock_raw_send_finished; - phw->get_tx_buffer = hw_device_sock_raw_get_tx_buffer; + phw_sock_raw->common.send = hw_device_sock_raw_send; + phw_sock_raw->common.recv = hw_device_sock_raw_recv; + phw_sock_raw->common.send_finished = hw_device_sock_raw_send_finished; + phw_sock_raw->common.get_tx_buffer = hw_device_sock_raw_get_tx_buffer; // create raw socket connection - phw->sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ECAT)); - if (phw->sockfd <= 0) { + phw_sock_raw->sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ECAT)); + if (phw_sock_raw->sockfd <= 0) { ec_log(1, "HW_OPEN", "socket error on opening SOCK_RAW: %s\n", strerror(errno)); ret = EC_ERROR_UNAVAILABLE; } @@ -134,24 +139,24 @@ int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 1; - setsockopt(phw->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - setsockopt(phw->sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + setsockopt(phw_sock_raw->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + setsockopt(phw_sock_raw->sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); // do not route our frames i = 1; - setsockopt(phw->sockfd, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i)); + setsockopt(phw_sock_raw->sockfd, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i)); // attach to out network interface (void)strcpy(ifr.ifr_name, devname); - ioctl(phw->sockfd, SIOCGIFINDEX, &ifr); + ioctl(phw_sock_raw->sockfd, SIOCGIFINDEX, &ifr); ifindex = ifr.ifr_ifindex; (void)strcpy(ifr.ifr_name, devname); ifr.ifr_flags = 0; - ioctl(phw->sockfd, SIOCGIFFLAGS, &ifr); + ioctl(phw_sock_raw->sockfd, SIOCGIFFLAGS, &ifr); osal_bool_t iff_running = (ifr.ifr_flags & IFF_RUNNING) == 0 ? OSAL_FALSE : OSAL_TRUE; ifr.ifr_flags = ifr.ifr_flags | IFF_PROMISC | IFF_BROADCAST | IFF_UP; - /*int ret =*/ ioctl(phw->sockfd, SIOCSIFFLAGS, &ifr); + /*int ret =*/ ioctl(phw_sock_raw->sockfd, SIOCSIFFLAGS, &ifr); // if (ret != 0) { // ec_log(1, "HW_OPEN", "error setting interface %s: %s\n", devname, strerror(errno)); // goto error_exit; @@ -160,7 +165,7 @@ int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { osal_timer_t up_timeout; osal_timer_init(&up_timeout, 10000000000); while (iff_running == OSAL_FALSE) { - ioctl(phw->sockfd, SIOCGIFFLAGS, &ifr); + ioctl(phw_sock_raw->sockfd, SIOCGIFFLAGS, &ifr); iff_running = (ifr.ifr_flags & IFF_RUNNING) == 0 ? OSAL_FALSE : OSAL_TRUE; if (iff_running == OSAL_TRUE) { ec_log(10, "HW_OPEN", "interface %s is RUNNING now, wait additional 2 sec for link to be established!\n", devname); @@ -179,8 +184,8 @@ int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { if (iff_running == OSAL_FALSE) { ec_log(1, "HW_OPEN", "unable to bring interface %s UP!\n", devname); ret = EC_ERROR_UNAVAILABLE; - close(phw->sockfd); - phw->sockfd = 0; + close(phw_sock_raw->sockfd); + phw_sock_raw->sockfd = 0; } } @@ -189,9 +194,9 @@ int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { (void)memset(&ifr, 0, sizeof(ifr)); (void)strncpy(ifr.ifr_name, devname, IFNAMSIZ); - ioctl(phw->sockfd, SIOCGIFMTU, &ifr); - phw->mtu_size = ifr.ifr_mtu; - ec_log(10, "hw_open", "got mtu size %d\n", phw->mtu_size); + ioctl(phw_sock_raw->sockfd, SIOCGIFMTU, &ifr); + phw_sock_raw->common.mtu_size = ifr.ifr_mtu; + ec_log(10, "hw_open", "got mtu size %d\n", phw_sock_raw->common.mtu_size); // bind socket to protocol, in this case RAW EtherCAT */ struct sockaddr_ll sll; @@ -199,7 +204,7 @@ int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; sll.sll_protocol = htons(ETH_P_ECAT); - bind(phw->sockfd, (struct sockaddr *) &sll, sizeof(sll)); + bind(phw_sock_raw->sockfd, (struct sockaddr *) &sll, sizeof(sll)); } return ret; @@ -212,12 +217,15 @@ int hw_device_sock_raw_open(hw_t *phw, const osal_char_t *devname) { * * \return 0 or negative error code */ -int hw_device_sock_raw_recv(hw_t *phw) { +int hw_device_sock_raw_recv(struct hw_common *phw) { + assert(phw != NULL); + // cppcheck-suppress misra-c2012-11.3 - ec_frame_t *pframe = (ec_frame_t *) &phw->recv_frame; + struct hw_sock_raw *phw_sock_raw = container_of(phw, struct hw_sock_raw, common); + ec_frame_t *pframe = (ec_frame_t *) &phw_sock_raw->recv_frame; // using tradional recv function - osal_ssize_t bytesrx = recv(phw->sockfd, pframe, ETH_FRAME_LEN, 0); + osal_ssize_t bytesrx = recv(phw_sock_raw->sockfd, pframe, ETH_FRAME_LEN, 0); if (bytesrx > 0) { hw_process_rx_frame(phw, pframe); @@ -233,18 +241,19 @@ int hw_device_sock_raw_recv(hw_t *phw) { * * \return 0 or negative error code */ -int hw_device_sock_raw_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { +int hw_device_sock_raw_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe) { assert(phw != NULL); assert(ppframe != NULL); int ret = EC_OK; ec_frame_t *pframe = NULL; + struct hw_sock_raw *phw_sock_raw = container_of(phw, struct hw_sock_raw, common); static const osal_uint8_t mac_dest[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const osal_uint8_t mac_src[] = {0x00, 0x30, 0x64, 0x0f, 0x83, 0x35}; // cppcheck-suppress misra-c2012-11.3 - pframe = (ec_frame_t *)phw->send_frame; + pframe = (ec_frame_t *)phw_sock_raw->send_frame; // reset length to send new frame (void)memcpy(pframe->mac_dest, mac_dest, 6); @@ -265,14 +274,15 @@ int hw_device_sock_raw_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { * * \return 0 or negative error code */ -int hw_device_sock_raw_send(hw_t *phw, ec_frame_t *pframe) { +int hw_device_sock_raw_send(struct hw_common *phw, ec_frame_t *pframe) { assert(phw != NULL); assert(pframe != NULL); int ret = EC_OK; + struct hw_sock_raw *phw_sock_raw = container_of(phw, struct hw_sock_raw, common); // no more datagrams need to be sent or no more space in frame - osal_ssize_t bytestx = send(phw->sockfd, pframe, pframe->len, 0); + osal_ssize_t bytestx = send(phw_sock_raw->sockfd, pframe, pframe->len, 0); if ((osal_ssize_t)pframe->len != bytestx) { ec_log(1, "HW_TX", "got only %ld bytes out of %d bytes " @@ -292,7 +302,7 @@ int hw_device_sock_raw_send(hw_t *phw, ec_frame_t *pframe) { /*! * \param[in] phw Pointer to hw handle. */ -void hw_device_sock_raw_send_finished(hw_t *phw) { +void hw_device_sock_raw_send_finished(struct hw_common *phw) { } diff --git a/src/hw_sock_raw_mmaped.c b/src/hw_sock_raw_mmaped.c index 003ff49c..1a9d01a8 100644 --- a/src/hw_sock_raw_mmaped.c +++ b/src/hw_sock_raw_mmaped.c @@ -38,7 +38,7 @@ */ #include -#include +#include #include #include #include @@ -65,10 +65,10 @@ #include // forward declarations -int hw_device_sock_raw_mmaped_send(hw_t *phw, ec_frame_t *pframe); -int hw_device_sock_raw_mmaped_recv(hw_t *phw); -void hw_device_sock_raw_mmaped_send_finished(hw_t *phw); -int hw_device_sock_raw_mmaped_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe); +int hw_device_sock_raw_mmaped_send(struct hw_common *phw, ec_frame_t *pframe); +int hw_device_sock_raw_mmaped_recv(struct hw_common *phw); +void hw_device_sock_raw_mmaped_send_finished(struct hw_common *phw); +int hw_device_sock_raw_mmaped_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe); // this need the grant_cap_net_raw kernel module // see https://gitlab.com/fastflo/open_ethercat @@ -105,7 +105,7 @@ static int try_grant_cap_net_raw_init(void) { * * \return 0 or negative error code */ -int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { +int hw_device_sock_raw_mmaped_open(struct hw_sock_raw_mmaped *phw_sock_raw_mmaped, const osal_char_t *devname) { int ret = EC_OK; struct ifreq ifr; int ifindex; @@ -115,19 +115,19 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { "not allowed to open a raw socket\n"); } - phw->send = hw_device_sock_raw_mmaped_send; - phw->recv = hw_device_sock_raw_mmaped_recv; - phw->send_finished = hw_device_sock_raw_mmaped_send_finished; - phw->get_tx_buffer = hw_device_sock_raw_mmaped_get_tx_buffer; + phw_sock_raw_mmaped->common.send = hw_device_sock_raw_mmaped_send; + phw_sock_raw_mmaped->common.recv = hw_device_sock_raw_mmaped_recv; + phw_sock_raw_mmaped->common.send_finished = hw_device_sock_raw_mmaped_send_finished; + phw_sock_raw_mmaped->common.get_tx_buffer = hw_device_sock_raw_mmaped_get_tx_buffer; // create raw socket connection - phw->sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ECAT)); - if (phw->sockfd <= 0) { + phw_sock_raw_mmaped->sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ECAT)); + if (phw_sock_raw_mmaped->sockfd <= 0) { ec_log(1, "HW_OPEN", "socket error on opening SOCK_RAW: %s\n", strerror(errno)); ret = EC_ERROR_UNAVAILABLE; } - phw->mmap_packets = 100; + phw_sock_raw_mmaped->mmap_packets = 100; if (ret == EC_OK) { int pagesize = getpagesize(); @@ -136,25 +136,25 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { struct tpacket_req tp; // tell kernel to export data through mmap()ped ring - tp.tp_block_size = phw->mmap_packets * pagesize; + tp.tp_block_size = phw_sock_raw_mmaped->mmap_packets * pagesize; tp.tp_block_nr = 1; tp.tp_frame_size = pagesize; - tp.tp_frame_nr = phw->mmap_packets; - if (setsockopt(phw->sockfd, SOL_PACKET, PACKET_RX_RING, (void*)&tp, sizeof(tp)) != 0) { + tp.tp_frame_nr = phw_sock_raw_mmaped->mmap_packets; + if (setsockopt(phw_sock_raw_mmaped->sockfd, SOL_PACKET, PACKET_RX_RING, (void*)&tp, sizeof(tp)) != 0) { ec_log(1, "HW_OPEN", "setsockopt() rx ring: %s\n", strerror(errno)); ret = EC_ERROR_UNAVAILABLE; - } else if (setsockopt(phw->sockfd, SOL_PACKET, PACKET_TX_RING, (void*)&tp, sizeof(tp)) != 0) { + } else if (setsockopt(phw_sock_raw_mmaped->sockfd, SOL_PACKET, PACKET_TX_RING, (void*)&tp, sizeof(tp)) != 0) { ec_log(1, "HW_OPEN", "setsockopt() tx ring: %s\n", strerror(errno)); ret = EC_ERROR_UNAVAILABLE; } else {} if (ret == EC_OK) { // TODO unmap anywhere - phw->rx_ring = mmap(0, phw->mmap_packets * pagesize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, phw->sockfd, 0); - phw->tx_ring = &phw->rx_ring[(phw->mmap_packets * pagesize)]; + phw_sock_raw_mmaped->rx_ring = mmap(0, phw_sock_raw_mmaped->mmap_packets * pagesize * 2, PROT_READ | PROT_WRITE, MAP_SHARED, phw_sock_raw_mmaped->sockfd, 0); + phw_sock_raw_mmaped->tx_ring = &phw_sock_raw_mmaped->rx_ring[(phw_sock_raw_mmaped->mmap_packets * pagesize)]; - phw->rx_ring_offset = 0; - phw->tx_ring_offset = 0; + phw_sock_raw_mmaped->rx_ring_offset = 0; + phw_sock_raw_mmaped->tx_ring_offset = 0; } } @@ -165,24 +165,24 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 1; - setsockopt(phw->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); - setsockopt(phw->sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + setsockopt(phw_sock_raw_mmaped->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + setsockopt(phw_sock_raw_mmaped->sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); // do not route our frames i = 1; - setsockopt(phw->sockfd, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i)); + setsockopt(phw_sock_raw_mmaped->sockfd, SOL_SOCKET, SO_DONTROUTE, &i, sizeof(i)); // attach to out network interface (void)strcpy(ifr.ifr_name, devname); - ioctl(phw->sockfd, SIOCGIFINDEX, &ifr); + ioctl(phw_sock_raw_mmaped->sockfd, SIOCGIFINDEX, &ifr); ifindex = ifr.ifr_ifindex; (void)strcpy(ifr.ifr_name, devname); ifr.ifr_flags = 0; - ioctl(phw->sockfd, SIOCGIFFLAGS, &ifr); + ioctl(phw_sock_raw_mmaped->sockfd, SIOCGIFFLAGS, &ifr); osal_bool_t iff_running = (ifr.ifr_flags & IFF_RUNNING) == 0 ? OSAL_FALSE : OSAL_TRUE; ifr.ifr_flags = ifr.ifr_flags | IFF_PROMISC | IFF_BROADCAST | IFF_UP; - /*int ret =*/ ioctl(phw->sockfd, SIOCSIFFLAGS, &ifr); + /*int ret =*/ ioctl(phw_sock_raw_mmaped->sockfd, SIOCSIFFLAGS, &ifr); // if (ret != 0) { // ec_log(1, "HW_OPEN", "error setting interface %s: %s\n", devname, strerror(errno)); // goto error_exit; @@ -191,7 +191,7 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { osal_timer_t up_timeout; osal_timer_init(&up_timeout, 10000000000); while (iff_running == OSAL_FALSE) { - ioctl(phw->sockfd, SIOCGIFFLAGS, &ifr); + ioctl(phw_sock_raw_mmaped->sockfd, SIOCGIFFLAGS, &ifr); iff_running = (ifr.ifr_flags & IFF_RUNNING) == 0 ? OSAL_FALSE : OSAL_TRUE; if (iff_running == OSAL_TRUE) { ec_log(10, "HW_OPEN", "interface %s is RUNNING now, wait additional 2 sec for link to be established!\n", devname); @@ -210,8 +210,8 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { if (iff_running == OSAL_FALSE) { ec_log(1, "HW_OPEN", "unable to bring interface %s UP!\n", devname); ret = EC_ERROR_UNAVAILABLE; - close(phw->sockfd); - phw->sockfd = 0; + close(phw_sock_raw_mmaped->sockfd); + phw_sock_raw_mmaped->sockfd = 0; } } @@ -220,9 +220,9 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { (void)memset(&ifr, 0, sizeof(ifr)); (void)strncpy(ifr.ifr_name, devname, IFNAMSIZ); - ioctl(phw->sockfd, SIOCGIFMTU, &ifr); - phw->mtu_size = ifr.ifr_mtu; - ec_log(10, "hw_open", "got mtu size %d\n", phw->mtu_size); + ioctl(phw_sock_raw_mmaped->sockfd, SIOCGIFMTU, &ifr); + phw_sock_raw_mmaped->common.mtu_size = ifr.ifr_mtu; + ec_log(10, "hw_open", "got mtu size %d\n", phw_sock_raw_mmaped->common.mtu_size); // bind socket to protocol, in this case RAW EtherCAT */ struct sockaddr_ll sll; @@ -230,7 +230,7 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; sll.sll_protocol = htons(ETH_P_ECAT); - bind(phw->sockfd, (struct sockaddr *) &sll, sizeof(sll)); + bind(phw_sock_raw_mmaped->sockfd, (struct sockaddr *) &sll, sizeof(sll)); } return ret; @@ -243,11 +243,15 @@ int hw_device_sock_raw_mmaped_open(hw_t *phw, const osal_char_t *devname) { * * \return 0 or negative error code */ -int hw_device_sock_raw_mmaped_recv(hw_t *phw) { +int hw_device_sock_raw_mmaped_recv(struct hw_common *phw) { + assert(phw != NULL); + + struct hw_sock_raw_mmaped *phw_sock_raw_mmaped = container_of(phw, struct hw_sock_raw_mmaped, common); + // using kernel mapped receive buffers // wait for received, non-processed packet struct pollfd pollset; - pollset.fd = phw->sockfd; + pollset.fd = phw_sock_raw_mmaped->sockfd; pollset.events = POLLIN; pollset.revents = 0; int ret = poll(&pollset, 1, 1); @@ -257,40 +261,42 @@ int hw_device_sock_raw_mmaped_recv(hw_t *phw) { struct tpacket_hdr *header; for ( // cppcheck-suppress misra-c2012-11.3 - header = (struct tpacket_hdr *)(&phw->rx_ring[(phw->rx_ring_offset * pagesize)]); + header = (struct tpacket_hdr *)(&phw_sock_raw_mmaped->rx_ring[(phw_sock_raw_mmaped->rx_ring_offset * pagesize)]); header->tp_status & TP_STATUS_USER; // cppcheck-suppress misra-c2012-11.3 - header = (struct tpacket_hdr *)(&phw->rx_ring[(phw->rx_ring_offset * pagesize)])) + header = (struct tpacket_hdr *)(&phw_sock_raw_mmaped->rx_ring[(phw_sock_raw_mmaped->rx_ring_offset * pagesize)])) { // cppcheck-suppress misra-c2012-11.3 ec_frame_t *real_frame = (ec_frame_t *)(&((osal_char_t *)header)[header->tp_mac]); hw_process_rx_frame(phw, real_frame); header->tp_status = 0; - phw->rx_ring_offset = (phw->rx_ring_offset + 1) % phw->mmap_packets; + phw_sock_raw_mmaped->rx_ring_offset = (phw_sock_raw_mmaped->rx_ring_offset + 1) % phw_sock_raw_mmaped->mmap_packets; } } return EC_OK; } -static struct tpacket_hdr *hw_get_next_tx_buffer(hw_t *phw) { +static struct tpacket_hdr *hw_get_next_tx_buffer(struct hw_common *phw) { struct tpacket_hdr *header; struct pollfd pollset; assert(phw != NULL); + + struct hw_sock_raw_mmaped *phw_sock_raw_mmaped = container_of(phw, struct hw_sock_raw_mmaped, common); // cppcheck-suppress misra-c2012-11.3 - header = (struct tpacket_hdr *)(&phw->tx_ring[(phw->tx_ring_offset * getpagesize())]); + header = (struct tpacket_hdr *)(&phw_sock_raw_mmaped->tx_ring[(phw_sock_raw_mmaped->tx_ring_offset * getpagesize())]); while (header->tp_status != TP_STATUS_AVAILABLE) { // notify kernel - if (send(phw->sockfd, NULL, 0, 0) < 0) { + if (send(phw_sock_raw_mmaped->sockfd, NULL, 0, 0) < 0) { ec_log(1, "HW_TX", "error on send: %s\n", strerror(errno)); } // buffer not available, wait here... - pollset.fd = phw->sockfd; + pollset.fd = phw_sock_raw_mmaped->sockfd; pollset.events = POLLOUT; pollset.revents = 0; int ret = poll(&pollset, 1, 1000); @@ -310,7 +316,7 @@ static struct tpacket_hdr *hw_get_next_tx_buffer(hw_t *phw) { * * \return 0 or negative error code */ -int hw_device_sock_raw_mmaped_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { +int hw_device_sock_raw_mmaped_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe) { assert(phw != NULL); assert(ppframe != NULL); @@ -344,11 +350,12 @@ int hw_device_sock_raw_mmaped_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { * * \return 0 or negative error code */ -int hw_device_sock_raw_mmaped_send(hw_t *phw, ec_frame_t *pframe) { +int hw_device_sock_raw_mmaped_send(struct hw_common *phw, ec_frame_t *pframe) { assert(phw != NULL); assert(pframe != NULL); int ret = EC_OK; + struct hw_sock_raw_mmaped *phw_sock_raw_mmaped = container_of(phw, struct hw_sock_raw_mmaped, common); // fill header struct tpacket_hdr *header = NULL; @@ -357,13 +364,13 @@ int hw_device_sock_raw_mmaped_send(hw_t *phw, ec_frame_t *pframe) { header->tp_status = TP_STATUS_SEND_REQUEST; // notify kernel - if (send(phw->sockfd, NULL, 0, 0) < 0) { + if (send(phw_sock_raw_mmaped->sockfd, NULL, 0, 0) < 0) { ec_log(1, "HW_TX", "error on sendto: %s\n", strerror(errno)); ret = EC_ERROR_HW_SEND; } // increase consumer ring pointer - phw->tx_ring_offset = (phw->tx_ring_offset + 1) % phw->mmap_packets; + phw_sock_raw_mmaped->tx_ring_offset = (phw_sock_raw_mmaped->tx_ring_offset + 1) % phw_sock_raw_mmaped->mmap_packets; return ret; } @@ -372,7 +379,7 @@ int hw_device_sock_raw_mmaped_send(hw_t *phw, ec_frame_t *pframe) { /*! * \param[in] phw Pointer to hw handle. */ -void hw_device_sock_raw_mmaped_send_finished(hw_t *phw) { +void hw_device_sock_raw_mmaped_send_finished(struct hw_common *phw) { } diff --git a/tools/eepromtool/eepromtool.c b/tools/eepromtool/eepromtool.c index 258712f3..1f000ad7 100644 --- a/tools/eepromtool/eepromtool.c +++ b/tools/eepromtool/eepromtool.c @@ -6,6 +6,7 @@ #include #include #include "libethercat/ec.h" +#include "libethercat/hw_file.h" #include int usage(int argc, char **argv) { @@ -30,7 +31,8 @@ enum tool_mode { mode_write }; -ec_t ec; +struct hw_file hw_file; +struct ec ec; int main(int argc, char **argv) { int ret, slave = -1, i; @@ -70,7 +72,9 @@ int main(int argc, char **argv) { ec_log_func_user = NULL; ec_log_func = &no_verbose_log; - ret = ec_open(&ec, intf, 90, 1, 1); + hw_device_file_open(&hw_file, &ec, intf, 90, 1); + struct hw_common *phw = &hw_file.common; + ret = ec_open(&ec, phw, 1); ec_set_state(&ec, EC_STATE_INIT); switch (mode) { diff --git a/tools/ethercatdiag/ethercatdiag.c b/tools/ethercatdiag/ethercatdiag.c index 18d59e47..aca8cc03 100644 --- a/tools/ethercatdiag/ethercatdiag.c +++ b/tools/ethercatdiag/ethercatdiag.c @@ -19,6 +19,7 @@ #include +#include "libethercat/hw_file.h" #include "libethercat/ec.h" #include "libethercat/mii.h" @@ -133,10 +134,12 @@ enum tool_mode { }; ec_t ec; +struct hw_file hw_file; int main(int argc, char **argv) { int ret, slave, i, phy = 0; + struct hw_common *phw; char *intf = NULL, *fn = NULL; int show_propagation_delays = 0; @@ -194,8 +197,9 @@ int main(int argc, char **argv) { ec_log_func_user = NULL; ec_log_func = &no_verbose_log; - - ret = ec_open(&ec, intf, 90, 1, 1); + hw_device_file_open(&hw_file, &ec, intf, 90, 1); + phw = &hw_file.common; + ret = ec_open(&ec, phw, 1); if (show_propagation_delays) diff --git a/tools/example_with_dc/example_with_dc.c b/tools/example_with_dc/example_with_dc.c index 58e217a0..f39d5599 100644 --- a/tools/example_with_dc/example_with_dc.c +++ b/tools/example_with_dc/example_with_dc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,7 @@ void no_verbose_log(int lvl, void *user, const char *format, ...) { }; static ec_t ec; +static struct hw_file hw_file; static osal_uint64_t cycle_rate = 1000000; static ec_dc_mode_t dc_mode = dc_mode_master_as_ref_clock; @@ -96,7 +98,7 @@ static osal_void_t* cyclic_task(osal_void_t* param) { ec_send_process_data(pec); // transmit cyclic packets (and also acyclic if there are any) - hw_tx(&pec->hw); + hw_tx(pec->phw); osal_trace_time(tx_duration, osal_timer_gettime_nsec() - time_start); } @@ -200,7 +202,9 @@ int main(int argc, char **argv) { ec_log_func_user = NULL; ec_log_func = &no_verbose_log; - ret = ec_open(&ec, intf, base_prio - 1, base_affinity, 1); + hw_device_file_open(&hw_file, &ec, intf, base_prio - 1, base_affinity); + struct hw_common *phw = &hw_file.common; + ret = ec_open(&ec, phw, 1); if (ret != EC_OK) { goto exit; } @@ -292,7 +296,7 @@ int main(int argc, char **argv) { "Frame len %" PRIu64 " bytes/%7.1fus, Timer %+7.1fus (jitter avg %+5.1fus, max %+5.1fus), " "Duration %+5.1fus (jitter avg %+5.1fus, max %+5.1fus), " "Round trip %+5.1fus (jitter avg %+5.1fus, max %+5.1fus)\n", - ec.hw.bytes_last_sent, (10 * 8 * ec.hw.bytes_last_sent) / 1000., + ec.phw->bytes_last_sent, (10 * 8 * ec.phw->bytes_last_sent) / 1000., to_us(tx_timer_med), to_us(tx_timer_avg_jit), to_us(tx_timer_max_jit), to_us(tx_duration_med), to_us(tx_duration_avg_jit), to_us(tx_duration_max_jit), to_us(roundtrip_duration_med), to_us(roundtrip_duration_avg_jit), to_us(roundtrip_duration_max_jit)); diff --git a/tools/foe_tool/foe_tool.c b/tools/foe_tool/foe_tool.c index 6cb55a95..15e67c23 100644 --- a/tools/foe_tool/foe_tool.c +++ b/tools/foe_tool/foe_tool.c @@ -22,6 +22,7 @@ #include "libethercat/ec.h" #include "libethercat/mii.h" +#include "libethercat/hw_file.h" void no_log(int lvl, void *user, const char *format, ...) {}; @@ -75,6 +76,7 @@ enum tool_mode { mode_write, }; +struct hw_file hw_file; ec_t ec; #include #include @@ -129,8 +131,9 @@ int main(int argc, char **argv) { ec_log_func_user = NULL; ec_log_func = &no_verbose_log; - - ret = ec_open(&ec, intf, 90, 1, 1); + hw_device_file_open(&hw_file, &ec, intf, 90, 1); + struct hw_common *phw = &hw_file.common; + ret = ec_open(&ec, phw, 1); ec_set_state(&ec, EC_STATE_INIT); ec_set_state(&ec, EC_STATE_BOOT); From 0bea5c41fae5091a3b8eac03f4a40905cb8412da Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Wed, 24 Jul 2024 08:41:21 +0200 Subject: [PATCH 02/10] change: reworked pikeos stuff --- include/libethercat/hw.h | 9 +---- include/libethercat/hw_pikeos.h | 14 +++++++- src/hw.c | 2 +- src/hw_pikeos.c | 63 ++++++++++++++++++--------------- 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/include/libethercat/hw.h b/include/libethercat/hw.h index 5bf80eeb..3a1375f6 100644 --- a/include/libethercat/hw.h +++ b/include/libethercat/hw.h @@ -54,7 +54,7 @@ #endif #define container_of(ptr, type, member) ({ \ - const __typeof__( ((type *)0)->member ) *__mptr = (void *)(ptr); \ + __typeof__( ((type *)0)->member ) *__mptr = (void *)(ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) /** \defgroup hardware_group HW @@ -124,13 +124,6 @@ typedef struct hw_common { hw_device_send_t send; //!< \brief Function to send frames via device. hw_device_send_finished_t send_finished; //!< \brief Function to be called after frames were sent. hw_device_get_tx_buffer_t get_tx_buffer; //!< \brief Function to retreave next TX buffer. - -#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 - osal_bool_t use_sbuf; - - vm_file_desc_t fd; //!< \brief Driver file descriptor. - drv_sbuf_desc_t sbuf; //!< \brief Driver SBUF descriptor. -#endif } hw_common_t; //!< \brief Hardware struct type. #ifdef __cplusplus diff --git a/include/libethercat/hw_pikeos.h b/include/libethercat/hw_pikeos.h index d2198226..7e1b05de 100644 --- a/include/libethercat/hw_pikeos.h +++ b/include/libethercat/hw_pikeos.h @@ -42,6 +42,18 @@ #include +typedef struct hw_pikeos { + struct hw_common common; + + osal_bool_t use_sbuf; + + vm_file_desc_t fd; //!< \brief Driver file descriptor. + drv_sbuf_desc_t sbuf; //!< \brief Driver SBUF descriptor. + + osal_uint8_t send_frame[ETH_FRAME_LEN]; //!< \brief Static send frame. + osal_uint8_t recv_frame[ETH_FRAME_LEN]; //!< \brief Static receive frame. +} hw_pikeos_t; + //! Opens EtherCAT hw device. /*! * \param[in] phw Pointer to hw handle. @@ -49,7 +61,7 @@ * * \return 0 or negative error code */ -int hw_device_pikeos_open(hw_t *phw, const osal_char_t *devname); +int hw_device_pikeos_open(struct hw_pikeos *phw, const osal_char_t *devname); #endif // LIBETHERCAT_HW_PIKEOS_H diff --git a/src/hw.c b/src/hw.c index c941b1c0..75880e5f 100644 --- a/src/hw.c +++ b/src/hw.c @@ -133,7 +133,7 @@ void hw_process_rx_frame(struct hw_common *phw, ec_frame_t *pframe) { (*entry->user_cb)(phw->pec, entry, d); } } - + d = ec_datagram_next(d); } } diff --git a/src/hw_pikeos.c b/src/hw_pikeos.c index 52c89b1a..a2641080 100644 --- a/src/hw_pikeos.c +++ b/src/hw_pikeos.c @@ -61,10 +61,10 @@ #include // forward declarations -int hw_device_pikeos_send(hw_t *phw, ec_frame_t *pframe); -int hw_device_pikeos_recv(hw_t *phw); -void hw_device_pikeos_send_finished(hw_t *phw); -int hw_device_pikeos_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe); +int hw_device_pikeos_send(struct hw_common *phw, ec_frame_t *pframe); +int hw_device_pikeos_recv(struct hw_common *phw); +void hw_device_pikeos_send_finished(struct hw_common *phw); +int hw_device_pikeos_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe); //! Opens EtherCAT hw device. /*! @@ -73,7 +73,7 @@ int hw_device_pikeos_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe); * * \return 0 or negative error code */ -int hw_device_pikeos_open(hw_t *phw, const osal_char_t *devname) { +int hw_device_pikeos_open(struct hw_pikeos *phw, const osal_char_t *devname) { assert(phw != NULL); assert(devname != NULL); @@ -83,11 +83,12 @@ int hw_device_pikeos_open(hw_t *phw, const osal_char_t *devname) { P4_e_t local_retval; P4_address_t vaddr; - phw->send = hw_device_pikeos_send; - phw->recv = hw_device_pikeos_recv; - phw->send_finished = hw_device_pikeos_send_finished; - phw->get_tx_buffer = hw_device_pikeos_get_tx_buffer; - phw->use_sbuf = OSAL_TRUE; + phw->common.send = hw_device_pikeos_send; + phw->common.recv = hw_device_pikeos_recv; + phw->common.send_finished = hw_device_pikeos_send_finished; + phw->common.get_tx_buffer = hw_device_pikeos_get_tx_buffer; + phw->common.mtu_size = 1480; + phw->use_sbuf = OSAL_TRUE; char *tmp; if ((tmp = strchr(devname, '/')) != NULL) { @@ -170,8 +171,6 @@ int hw_device_pikeos_open(hw_t *phw, const osal_char_t *devname) { ec_log(10, "HW_OPEN", "using vmread/vmwrite\n"); } - phw->mtu_size = 1480; - return ret; } @@ -182,22 +181,24 @@ int hw_device_pikeos_open(hw_t *phw, const osal_char_t *devname) { * * \return 0 or negative error code */ -int hw_device_pikeos_recv(hw_t *phw) { +int hw_device_pikeos_recv(struct hw_common *phw) { assert(phw != NULL); + + struct hw_pikeos *phw_pikeos = container_of(phw, struct hw_pikeos, common); int ret = EC_OK; ec_frame_t *pframe = NULL; - if (phw->use_sbuf == OSAL_TRUE) { + if (phw_pikeos->use_sbuf == OSAL_TRUE) { // get a full rxbuffer from RX ring (dontwait=0 -> WAITING) - vm_io_buf_id_t rxbuf = vm_io_sbuf_rx_get(&phw->sbuf, 0); + vm_io_buf_id_t rxbuf = vm_io_sbuf_rx_get(&phw_pikeos->sbuf, 0); if (rxbuf == VM_IO_BUF_ID_INVALID) { p4_sleep(P4_NSEC(1000000)); ret = EC_ERROR_UNAVAILABLE; } if (ret == EC_OK) { - pframe = (ec_frame_t *)vm_io_sbuf_rx_buf_addr(&phw->sbuf, rxbuf); + pframe = (ec_frame_t *)vm_io_sbuf_rx_buf_addr(&phw_pikeos->sbuf, rxbuf); if (pframe == NULL) { ret = EC_ERROR_UNAVAILABLE; @@ -205,17 +206,17 @@ int hw_device_pikeos_recv(hw_t *phw) { } if (ret == EC_OK) { - int32_t bytesrx = vm_io_sbuf_rx_buf_size(&phw->sbuf, rxbuf); + int32_t bytesrx = vm_io_sbuf_rx_buf_size(&phw_pikeos->sbuf, rxbuf); if (bytesrx > 0) { hw_process_rx_frame(phw, pframe); } - vm_io_sbuf_rx_free(&phw->sbuf, rxbuf); + vm_io_sbuf_rx_free(&phw_pikeos->sbuf, rxbuf); } } else { /* use_sbuf == OSAL_FALSE */ - pframe = (ec_frame_t *)&phw->recv_frame[0]; + pframe = (ec_frame_t *)&phw_pikeos->recv_frame[0]; P4_size_t read_size; - P4_e_t localret = vm_read(&phw->fd, pframe, ETH_FRAME_LEN, &read_size); + P4_e_t localret = vm_read(&phw_pikeos->fd, pframe, ETH_FRAME_LEN, &read_size); if (localret != P4_E_OK) { ret = EC_ERROR_UNAVAILABLE; @@ -236,10 +237,12 @@ int hw_device_pikeos_recv(hw_t *phw) { * * \return 0 or negative error code */ -int hw_device_pikeos_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { +int hw_device_pikeos_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe) { assert(phw != NULL); assert(ppframe != NULL); + struct hw_pikeos *phw_pikeos = container_of(phw, struct hw_pikeos, common); + int ret = EC_ERROR_UNAVAILABLE; ec_frame_t *pframe = NULL; @@ -247,7 +250,7 @@ int hw_device_pikeos_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { static const osal_uint8_t mac_src[] = {0x00, 0x30, 0x64, 0x0f, 0x83, 0x35}; // cppcheck-suppress misra-c2012-11.3 - pframe = (ec_frame_t *)phw->send_frame; + pframe = (ec_frame_t *)phw_pikeos->send_frame; // reset length to send new frame (void)memcpy(pframe->mac_dest, mac_dest, 6); @@ -268,22 +271,24 @@ int hw_device_pikeos_get_tx_buffer(hw_t *phw, ec_frame_t **ppframe) { * * \return 0 or negative error code */ -int hw_device_pikeos_send(hw_t *phw, ec_frame_t *pframe) { +int hw_device_pikeos_send(struct hw_common *phw, ec_frame_t *pframe) { assert(phw != NULL); assert(pframe != NULL); + struct hw_pikeos *phw_pikeos = container_of(phw, struct hw_pikeos, common); + int ret = EC_OK; void* txbuf = NULL; - if (phw->use_sbuf == OSAL_TRUE) { + if (phw_pikeos->use_sbuf == OSAL_TRUE) { // get an empty tx buffer from TX ring (dontwait) - vm_io_buf_id_t sbuftx = vm_io_sbuf_tx_alloc(&phw->sbuf, 1); + vm_io_buf_id_t sbuftx = vm_io_sbuf_tx_alloc(&phw_pikeos->sbuf, 1); if (sbuftx == VM_IO_BUF_ID_INVALID) { ret = EC_ERROR_UNAVAILABLE; } if (ret == EC_OK) { - txbuf = (void*)vm_io_sbuf_tx_buf_addr(&phw->sbuf, sbuftx); + txbuf = (void*)vm_io_sbuf_tx_buf_addr(&phw_pikeos->sbuf, sbuftx); if (txbuf == NULL) { ret = EC_ERROR_UNAVAILABLE; @@ -292,11 +297,11 @@ int hw_device_pikeos_send(hw_t *phw, ec_frame_t *pframe) { if (ret == EC_OK) { (void)memcpy(txbuf, pframe, pframe->len); - vm_io_sbuf_tx_ready(&phw->sbuf, sbuftx, pframe->len); + vm_io_sbuf_tx_ready(&phw_pikeos->sbuf, sbuftx, pframe->len); } } else { /* use_sbuf == OSAL_FALSE */ P4_size_t written_size; - P4_e_t localret = vm_write(&phw->fd, pframe, pframe->len, &written_size); + P4_e_t localret = vm_write(&phw_pikeos->fd, pframe, pframe->len, &written_size); if (localret != P4_E_OK) { ret = EC_ERROR_UNAVAILABLE; @@ -311,7 +316,7 @@ int hw_device_pikeos_send(hw_t *phw, ec_frame_t *pframe) { /*! * \param[in] phw Pointer to hw handle. */ -void hw_device_pikeos_send_finished(hw_t *phw) { +void hw_device_pikeos_send_finished(struct hw_common *phw) { (void)phw; } From f9d3f13bab6b94bb47baf0bc2cbdaaf03af1deb3 Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Wed, 24 Jul 2024 10:02:48 +0200 Subject: [PATCH 03/10] add: rx thread for pikeos --- include/libethercat/hw_file.h | 4 ++-- include/libethercat/hw_pikeos.h | 9 +++++++- src/hw_pikeos.c | 39 ++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/include/libethercat/hw_file.h b/include/libethercat/hw_file.h index a661c51e..22879ee3 100644 --- a/include/libethercat/hw_file.h +++ b/include/libethercat/hw_file.h @@ -52,8 +52,8 @@ typedef struct hw_file { osal_bool_t polling_mode; //!< \brief Special interrupt-less polling-mode flag. // receiver thread settings in non-polling mode - osal_task_t rxthread; //!< receiver thread handle - int rxthreadrunning; //!< receiver thread running flag + osal_task_t rxthread; //!< receiver thread handle + int rxthreadrunning; //!< receiver thread running flag } hw_file_t; //! Opens EtherCAT hw device. diff --git a/include/libethercat/hw_pikeos.h b/include/libethercat/hw_pikeos.h index 7e1b05de..0fb5461a 100644 --- a/include/libethercat/hw_pikeos.h +++ b/include/libethercat/hw_pikeos.h @@ -52,16 +52,23 @@ typedef struct hw_pikeos { osal_uint8_t send_frame[ETH_FRAME_LEN]; //!< \brief Static send frame. osal_uint8_t recv_frame[ETH_FRAME_LEN]; //!< \brief Static receive frame. + + // receiver thread + osal_task_t rxthread; //!< receiver thread handle + int rxthreadrunning; //!< receiver thread running flag } hw_pikeos_t; //! Opens EtherCAT hw device. /*! * \param[in] phw Pointer to hw handle. * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] prio Priority for receiver thread. + * \param[in] cpu_mask CPU mask for receiver thread. * * \return 0 or negative error code */ -int hw_device_pikeos_open(struct hw_pikeos *phw, const osal_char_t *devname); +int hw_device_pikeos_open(struct hw_pikeos *phw, const osal_char_t *devname, + int prio, int cpumask); #endif // LIBETHERCAT_HW_PIKEOS_H diff --git a/src/hw_pikeos.c b/src/hw_pikeos.c index a2641080..f6be3854 100644 --- a/src/hw_pikeos.c +++ b/src/hw_pikeos.c @@ -66,14 +66,18 @@ int hw_device_pikeos_recv(struct hw_common *phw); void hw_device_pikeos_send_finished(struct hw_common *phw); int hw_device_pikeos_get_tx_buffer(struct hw_common *phw, ec_frame_t **ppframe); +void *hw_device_pikeos_rx_thread(void *arg); + //! Opens EtherCAT hw device. /*! * \param[in] phw Pointer to hw handle. * \param[in] devname Null-terminated string to EtherCAT hw device name. + * \param[in] prio Priority for receiver thread. + * \param[in] cpu_mask CPU mask for receiver thread. * * \return 0 or negative error code */ -int hw_device_pikeos_open(struct hw_pikeos *phw, const osal_char_t *devname) { +int hw_device_pikeos_open(struct hw_pikeos *phw, const osal_char_t *devname, int prio, int cpumask) { assert(phw != NULL); assert(devname != NULL); @@ -171,9 +175,42 @@ int hw_device_pikeos_open(struct hw_pikeos *phw, const osal_char_t *devname) { ec_log(10, "HW_OPEN", "using vmread/vmwrite\n"); } + if (ret == EC_OK) { + phw->rxthreadrunning = 1; + osal_task_attr_t attr; + attr.policy = OSAL_SCHED_POLICY_FIFO; + attr.priority = prio; + attr.affinity = cpumask; + (void)strcpy(&attr.task_name[0], "ecat.rx"); + osal_task_create(&phw->rxthread, &attr, hw_device_pikeos_rx_thread, phw); + } + return ret; } +//! receiver thread +void *hw_device_pikeos_rx_thread(void *arg) { + // cppcheck-suppress misra-c2012-11.5 + struct hw_pikeos *phw_pikeos = (struct hw_pikeos *) arg; + + assert(phw_pikeos != NULL); + + osal_task_sched_priority_t rx_prio; + if (osal_task_get_priority(&phw_pikeos->rxthread, &rx_prio) != OSAL_OK) { + rx_prio = 0; + } + + ec_log(10, "HW_PIKEOS_RX", "receive thread running (prio %d)\n", rx_prio); + + while (phw_pikeos->rxthreadrunning != 0) { + hw_device_pikeos_recv(&phw_pikeos->common); + } + + ec_log(10, "HW_PIKEOS_RX", "receive thread stopped\n"); + + return NULL; +} + //! Receive a frame from an EtherCAT hw device. /*! From f802b4897f26263584f68eda4d4d87c8b66ff55f Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Wed, 31 Jul 2024 12:48:22 +0200 Subject: [PATCH 04/10] fix: examples using hw devices --- tools/eepromtool/eepromtool.c | 115 ++++++++++++++++++++++-- tools/ethercatdiag/ethercatdiag.c | 100 +++++++++++++++++++-- tools/example_with_dc/example_with_dc.c | 94 ++++++++++++++++++- tools/foe_tool/foe_tool.c | 95 ++++++++++++++++++-- 4 files changed, 381 insertions(+), 23 deletions(-) diff --git a/tools/eepromtool/eepromtool.c b/tools/eepromtool/eepromtool.c index 1f000ad7..06ba297e 100644 --- a/tools/eepromtool/eepromtool.c +++ b/tools/eepromtool/eepromtool.c @@ -1,14 +1,55 @@ +//! ethercat example eeprom tool +/*! + * author: Robert Burger + * + * $Id$ + */ + #include +#include +#include + +#include "libethercat/config.h" +#include "libethercat/ec.h" + +#if LIBETHERCAT_HAVE_UNISTD_H == 1 #include +#endif + #include #include +#if LIBETHERCAT_HAVE_SYS_STAT_H == 1 #include +#endif + +#if LIBETHERCAT_HAVE_FCNTL_H == 1 #include -#include "libethercat/ec.h" -#include "libethercat/hw_file.h" +#endif + #include +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 +#include +static struct hw_file hw_file; +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 +#include +static struct hw_bpf hw_bpf; +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 +#include +static struct hw_pikeos hw_pikeos; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 +#include +static struct hw_sock_raw hw_sock_raw; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 +#include +static struct hw_sock_raw_mmaped hw_sock_raw_mmaped; +#endif + int usage(int argc, char **argv) { printf("%s -i|--interface -s|--slave [-r|--read] [-w|--write] [-f|--file ]\n", argv[0]); return 0; @@ -31,11 +72,12 @@ enum tool_mode { mode_write }; -struct hw_file hw_file; struct ec ec; int main(int argc, char **argv) { int ret, slave = -1, i; + int base_prio = 0; + int base_affinity = 0xF; char *intf = NULL, *fn = NULL; enum tool_mode mode = mode_undefined; @@ -71,9 +113,72 @@ int main(int argc, char **argv) { // use our log function ec_log_func_user = NULL; ec_log_func = &no_verbose_log; + struct hw_common *phw = NULL; + +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 + if ((intf[0] == '/') || (strncmp(intf, "file:", 5) == 0)) { + // assume char device -> hw_file + if (strncmp(intf, "file:", 5) == 0) { + intf = &intf[5]; + } + + ec_log(10, "HW_OPEN", "Opening interface as device file: %s\n", intf); + ret = hw_device_file_open(&hw_file, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_file.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 + if (strncmp(intf, "bpf:", 4) == 0) { + intf = &intf[4]; + + ec_log(10, "HW_OPEN", "Opening interface as BPF: %s\n", intf); + ret = hw_device_bpf_open(&hw_bpf, intf); + + if (ret == 0) { + phw = &hw_bpf.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 + if (strncmp(intf, "pikeos:", 7) == 0) { + intf = &intf[7]; + + ec_log(10, "HW_OPEN", "Opening interface as pikeos: %s\n", intf); + ret = hw_device_pikeos_open(&hw_pikeos, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_pikeos.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 + if (strncmp(intf, "sock-raw:", 9) == 0) { + intf = &intf[9]; + + ec_log(10, "HW_OPEN", "Opening interface as SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_open(&hw_sock_raw, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_sock_raw.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 + if (strncmp(intf, "sock-raw-mmaped:", 16) == 0) { + intf = &intf[16]; + + ec_log(10, "HW_OPEN", "Opening interface as mmaped SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_mmaped_open(&hw_sock_raw_mmaped, intf); + + if (ret == 0) { + phw = &hw_sock_raw_mmaped.common; + } + } +#endif - hw_device_file_open(&hw_file, &ec, intf, 90, 1); - struct hw_common *phw = &hw_file.common; ret = ec_open(&ec, phw, 1); ec_set_state(&ec, EC_STATE_INIT); diff --git a/tools/ethercatdiag/ethercatdiag.c b/tools/ethercatdiag/ethercatdiag.c index aca8cc03..5aded370 100644 --- a/tools/ethercatdiag/ethercatdiag.c +++ b/tools/ethercatdiag/ethercatdiag.c @@ -1,4 +1,6 @@ -#include +#include "libethercat/config.h" +#include "libethercat/ec.h" +#include "libethercat/mii.h" #include @@ -19,9 +21,27 @@ #include -#include "libethercat/hw_file.h" -#include "libethercat/ec.h" -#include "libethercat/mii.h" +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 +#include +static struct hw_file hw_file; +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 +#include +static struct hw_bpf hw_bpf; +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 +#include +static struct hw_pikeos hw_pikeos; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 +#include +static struct hw_sock_raw hw_sock_raw; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 +#include +static struct hw_sock_raw_mmaped hw_sock_raw_mmaped; +#endif + void no_log(int lvl, void *user, const char *format, ...) {}; @@ -134,12 +154,12 @@ enum tool_mode { }; ec_t ec; -struct hw_file hw_file; int main(int argc, char **argv) { int ret, slave, i, phy = 0; + int base_prio = 60; + int base_affinity = 0x8; - struct hw_common *phw; char *intf = NULL, *fn = NULL; int show_propagation_delays = 0; @@ -196,9 +216,73 @@ int main(int argc, char **argv) { // use our log function ec_log_func_user = NULL; ec_log_func = &no_verbose_log; + struct hw_common *phw = NULL; + +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 + if ((intf[0] == '/') || (strncmp(intf, "file:", 5) == 0)) { + // assume char device -> hw_file + if (strncmp(intf, "file:", 5) == 0) { + intf = &intf[5]; + } + + ec_log(10, "HW_OPEN", "Opening interface as device file: %s\n", intf); + ret = hw_device_file_open(&hw_file, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_file.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 + if (strncmp(intf, "bpf:", 4) == 0) { + intf = &intf[4]; + + ec_log(10, "HW_OPEN", "Opening interface as BPF: %s\n", intf); + ret = hw_device_bpf_open(&hw_bpf, intf); + + if (ret == 0) { + phw = &hw_bpf.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 + if (strncmp(intf, "pikeos:", 7) == 0) { + intf = &intf[7]; + + ec_log(10, "HW_OPEN", "Opening interface as pikeos: %s\n", intf); + ret = hw_device_pikeos_open(&hw_pikeos, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_pikeos.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 + if (strncmp(intf, "sock-raw:", 9) == 0) { + intf = &intf[9]; + + ec_log(10, "HW_OPEN", "Opening interface as SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_open(&hw_sock_raw, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_sock_raw.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 + if (strncmp(intf, "sock-raw-mmaped:", 16) == 0) { + intf = &intf[16]; + + ec_log(10, "HW_OPEN", "Opening interface as mmaped SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_mmaped_open(&hw_sock_raw_mmaped, intf); + + if (ret == 0) { + phw = &hw_sock_raw_mmaped.common; + } + } +#endif + - hw_device_file_open(&hw_file, &ec, intf, 90, 1); - phw = &hw_file.common; ret = ec_open(&ec, phw, 1); diff --git a/tools/example_with_dc/example_with_dc.c b/tools/example_with_dc/example_with_dc.c index f39d5599..0d8ef6a1 100644 --- a/tools/example_with_dc/example_with_dc.c +++ b/tools/example_with_dc/example_with_dc.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -33,6 +32,26 @@ #include +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 +#include +static struct hw_file hw_file; +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 +#include +static struct hw_bpf hw_bpf; +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 +#include +static struct hw_pikeos hw_pikeos; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 +#include +static struct hw_sock_raw hw_sock_raw; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 +#include +static struct hw_sock_raw_mmaped hw_sock_raw_mmaped; +#endif void no_log(int lvl, void *user, const char *format, ...) {}; @@ -68,7 +87,6 @@ void no_verbose_log(int lvl, void *user, const char *format, ...) { }; static ec_t ec; -static struct hw_file hw_file; static osal_uint64_t cycle_rate = 1000000; static ec_dc_mode_t dc_mode = dc_mode_master_as_ref_clock; @@ -201,9 +219,77 @@ int main(int argc, char **argv) { // use our log function ec_log_func_user = NULL; ec_log_func = &no_verbose_log; + struct hw_common *phw = NULL; - hw_device_file_open(&hw_file, &ec, intf, base_prio - 1, base_affinity); - struct hw_common *phw = &hw_file.common; +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 + if ((intf[0] == '/') || (strncmp(intf, "file:", 5) == 0)) { + // assume char device -> hw_file + if (strncmp(intf, "file:", 5) == 0) { + intf = &intf[5]; + } + + ec_log(10, "HW_OPEN", "Opening interface as device file: %s\n", intf); + ret = hw_device_file_open(&hw_file, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_file.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 + if (strncmp(intf, "bpf:", 4) == 0) { + intf = &intf[4]; + + ec_log(10, "HW_OPEN", "Opening interface as BPF: %s\n", intf); + ret = hw_device_bpf_open(&hw_bpf, intf); + + if (ret == 0) { + phw = &hw_bpf.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 + if (strncmp(intf, "pikeos:", 7) == 0) { + intf = &intf[7]; + + ec_log(10, "HW_OPEN", "Opening interface as pikeos: %s\n", intf); + ret = hw_device_pikeos_open(&hw_pikeos, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_pikeos.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 + if (strncmp(intf, "sock-raw:", 9) == 0) { + intf = &intf[9]; + + ec_log(10, "HW_OPEN", "Opening interface as SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_open(&hw_sock_raw, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_sock_raw.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 + if (strncmp(intf, "sock-raw-mmaped:", 16) == 0) { + intf = &intf[16]; + + ec_log(10, "HW_OPEN", "Opening interface as mmaped SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_mmaped_open(&hw_sock_raw_mmaped, intf); + + if (ret == 0) { + phw = &hw_sock_raw_mmaped.common; + } + } +#endif + + if (phw == NULL) { + ec_log(10, "HW_OPEN", "Hardware device layer failure!\n"); + goto exit; + } + ret = ec_open(&ec, phw, 1); if (ret != EC_OK) { goto exit; diff --git a/tools/foe_tool/foe_tool.c b/tools/foe_tool/foe_tool.c index 15e67c23..f9fa000d 100644 --- a/tools/foe_tool/foe_tool.c +++ b/tools/foe_tool/foe_tool.c @@ -9,6 +9,7 @@ #include #include +#include #if LIBETHERCAT_HAVE_SYS_STAT_H == 1 #include @@ -22,7 +23,27 @@ #include "libethercat/ec.h" #include "libethercat/mii.h" -#include "libethercat/hw_file.h" + +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 +#include +static struct hw_file hw_file; +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 +#include +static struct hw_bpf hw_bpf; +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 +#include +static struct hw_pikeos hw_pikeos; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 +#include +static struct hw_sock_raw hw_sock_raw; +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 +#include +static struct hw_sock_raw_mmaped hw_sock_raw_mmaped; +#endif void no_log(int lvl, void *user, const char *format, ...) {}; @@ -76,13 +97,12 @@ enum tool_mode { mode_write, }; -struct hw_file hw_file; ec_t ec; -#include -#include int main(int argc, char **argv) { int ret, slave, i, phy = 0; + int base_prio = 0; + int base_affinity = 0xF; char *intf = NULL, *first_fn = NULL, *second_fn = NULL; uint32_t password = 0; @@ -130,9 +150,72 @@ int main(int argc, char **argv) { // use our log function ec_log_func_user = NULL; ec_log_func = &no_verbose_log; + struct hw_common *phw = NULL; + +#if LIBETHERCAT_BUILD_DEVICE_FILE == 1 + if ((intf[0] == '/') || (strncmp(intf, "file:", 5) == 0)) { + // assume char device -> hw_file + if (strncmp(intf, "file:", 5) == 0) { + intf = &intf[5]; + } + + ec_log(10, "HW_OPEN", "Opening interface as device file: %s\n", intf); + ret = hw_device_file_open(&hw_file, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_file.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_BPF == 1 + if (strncmp(intf, "bpf:", 4) == 0) { + intf = &intf[4]; + + ec_log(10, "HW_OPEN", "Opening interface as BPF: %s\n", intf); + ret = hw_device_bpf_open(&hw_bpf, intf); + + if (ret == 0) { + phw = &hw_bpf.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_PIKEOS == 1 + if (strncmp(intf, "pikeos:", 7) == 0) { + intf = &intf[7]; + + ec_log(10, "HW_OPEN", "Opening interface as pikeos: %s\n", intf); + ret = hw_device_pikeos_open(&hw_pikeos, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_pikeos.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_LEGACY == 1 + if (strncmp(intf, "sock-raw:", 9) == 0) { + intf = &intf[9]; + + ec_log(10, "HW_OPEN", "Opening interface as SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_open(&hw_sock_raw, &ec, intf, base_prio - 1, base_affinity); + + if (ret == 0) { + phw = &hw_sock_raw.common; + } + } +#endif +#if LIBETHERCAT_BUILD_DEVICE_SOCK_RAW_MMAPED == 1 + if (strncmp(intf, "sock-raw-mmaped:", 16) == 0) { + intf = &intf[16]; + + ec_log(10, "HW_OPEN", "Opening interface as mmaped SOCK_RAW: %s\n", intf); + ret = hw_device_sock_raw_mmaped_open(&hw_sock_raw_mmaped, intf); + + if (ret == 0) { + phw = &hw_sock_raw_mmaped.common; + } + } +#endif - hw_device_file_open(&hw_file, &ec, intf, 90, 1); - struct hw_common *phw = &hw_file.common; ret = ec_open(&ec, phw, 1); ec_set_state(&ec, EC_STATE_INIT); From 176e5e142efdc5410f2cfaffc75f6a706d064d20 Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Wed, 31 Jul 2024 15:00:52 +0200 Subject: [PATCH 05/10] fix: distributing headers --- src/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index e0127f0e..8dec3012 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,22 +28,27 @@ libethercat_la_SOURCES = coe.c coe_master.c slave.c datagram.c pool.c async_loop hw.c soe.c foe.c mbx.c eeprom.c dc.c idx.c mii.c eoe.c if BUILD_DEVICE_SOCK_RAW_LEGACY +include_HEADERS += $(top_srcdir)/include/libethercat/hw_sock_raw.h libethercat_la_SOURCES += hw_sock_raw.c endif if BUILD_DEVICE_SOCK_RAW_MMAPED +include_HEADERS += $(top_srcdir)/include/libethercat/hw_sock_raw_mmaped.h libethercat_la_SOURCES += hw_sock_raw_mmaped.c endif if BUILD_DEVICE_FILE +include_HEADERS += $(top_srcdir)/include/libethercat/hw_file.h libethercat_la_SOURCES += hw_file.c endif if BUILD_DEVICE_BPF +include_HEADERS += $(top_srcdir)/include/libethercat/hw_bpf.h libethercat_la_SOURCES += hw_bpf.c endif if BUILD_PIKEOS +include_HEADERS += $(top_srcdir)/include/libethercat/hw_pikeos.h libethercat_la_SOURCES += hw_pikeos.c endif From 8bd80e90d3f8d1705c486e103c334042fdbf8ffd Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Wed, 31 Jul 2024 15:01:08 +0200 Subject: [PATCH 06/10] fix: printf format attribute --- include/libethercat/ec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libethercat/ec.h b/include/libethercat/ec.h index e45fc263..8da2e305 100644 --- a/include/libethercat/ec.h +++ b/include/libethercat/ec.h @@ -242,7 +242,7 @@ extern "C" { #endif extern void *ec_log_func_user; -extern void (*ec_log_func)(int lvl, void *user, const osal_char_t *format, ...); +extern void (*ec_log_func)(int lvl, void *user, const osal_char_t *format, ...) __attribute__ ((format (printf, 3, 4))); //! \brief EtherCAT logging function /*! From 74349a6ab89451c1dfc8075f4aacfdb4cbc3bccd Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Thu, 1 Aug 2024 06:02:09 +0200 Subject: [PATCH 07/10] fix: returning in foe_tool if hw layer failed! --- tools/foe_tool/foe_tool.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/foe_tool/foe_tool.c b/tools/foe_tool/foe_tool.c index c40d9421..5d76d7bc 100644 --- a/tools/foe_tool/foe_tool.c +++ b/tools/foe_tool/foe_tool.c @@ -218,6 +218,11 @@ int main(int argc, char **argv) { } } #endif + + if (!phw) { + printf("Error opening hw device \"%s\"\n", intf); + return -1; + } ret = ec_open(&ec, phw, 1); From 5fb735938fd502a12ad0769e48e9e4402002fa4f Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Thu, 1 Aug 2024 06:19:11 +0200 Subject: [PATCH 08/10] add: settling mode for dc ref_clock mode --- include/libethercat/dc.h | 12 ++++++++++++ src/ec.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/libethercat/dc.h b/include/libethercat/dc.h index 0cce47f2..1ccdfc33 100644 --- a/include/libethercat/dc.h +++ b/include/libethercat/dc.h @@ -107,6 +107,18 @@ typedef struct ec_dc_info { double kp; double ki; + double settling_time; //!< \brief Settling time in [ns] + double settling_threshold; //!< \brief Settling threshold in [ns] + double settling_threshold_cycles; //!< \brief Settling cycles below threshold. + double settling_threshold_cnt; //!< \brief Current cycles below threshold. + osal_bool_t settling_done; //!< \brief Settling done. + + enum { + settling_mode_none, //!< \brief No settling mode, keep kp active + settling_mode_time, //!< \brief Settling time mode + settling_mode_threshold //!< \brief Settling threshold mode + } settling_mode; + double v_part_old; } control; //!< \brief PI-controller to adjust EtherCAT master timer value. diff --git a/src/ec.c b/src/ec.c index 358c7b64..c533233f 100644 --- a/src/ec.c +++ b/src/ec.c @@ -1101,6 +1101,12 @@ int ec_open(ec_t *pec, const osal_char_t *ifname, int prio, int cpumask, int eep pec->dc.control.diffsum_limit = 10.; pec->dc.control.kp = 1; pec->dc.control.ki = 0.1; + pec->dc.control.settling_time = 1000000000; // 1 sec + pec->dc.control.settling_threshold = 10000; // 10 usec + pec->dc.control.settling_threshold_cycles = 100; + pec->dc.control.settling_threshold_cnt = 0; + pec->dc.control.settling_done = OSAL_FALSE; + pec->dc.control.settling_mode = settling_mode_none; pec->dc.control.v_part_old = 0.0; pec->tun_fd = 0; @@ -1769,6 +1775,39 @@ static void cb_distributed_clocks(struct ec *pec, pool_entry_t *p_entry, ec_data double p_part = pec->dc.control.kp * pec->dc.act_diff; pec->dc.control.v_part_old = p_part; + switch (pec->dc.control.settling_mode) { + case settling_mode_none: + break; + case settling_mode_time: + if ( (pec->dc.control.settling_done == OSAL_FALSE) && + (pec->dc.control.settling_time > pec->dc.dc_time) ) + { + pec->dc.control.settling_done = OSAL_TRUE; + } + + if (pec->dc.control.settling_done == OSAL_TRUE) { + p_part = 0; + } + break; + case settling_mode_threshold: + if (pec->dc.control.settling_done == OSAL_FALSE) { + if (pec->dc.act_diff < pec->dc.control.settling_threshold) { + pec->dc.control.settling_threshold_cnt++; + } else { + pec->dc.control.settling_threshold_cnt = 0; + } + + if (pec->dc.control.settling_threshold_cnt >= pec->dc.control.settling_threshold_cycles) { + pec->dc.control.settling_done = OSAL_TRUE; + } + } + + if (pec->dc.control.settling_done == OSAL_TRUE) { + p_part = 0; + } + break; + } + // sum it up for integral part pec->dc.control.diffsum += pec->dc.control.ki * pec->dc.act_diff; From 36b774484de946b62c24d2f21d5a549660768743 Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Thu, 1 Aug 2024 06:30:36 +0200 Subject: [PATCH 09/10] chore: some dc settling mode improvements and setters --- include/libethercat/dc.h | 10 +++++----- include/libethercat/ec.h | 17 +++++++++++++++++ src/ec.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/include/libethercat/dc.h b/include/libethercat/dc.h index 1ccdfc33..530f9851 100644 --- a/include/libethercat/dc.h +++ b/include/libethercat/dc.h @@ -107,11 +107,11 @@ typedef struct ec_dc_info { double kp; double ki; - double settling_time; //!< \brief Settling time in [ns] - double settling_threshold; //!< \brief Settling threshold in [ns] - double settling_threshold_cycles; //!< \brief Settling cycles below threshold. - double settling_threshold_cnt; //!< \brief Current cycles below threshold. - osal_bool_t settling_done; //!< \brief Settling done. + double settling_time; //!< \brief Settling time in [ns] + double settling_threshold; //!< \brief Settling threshold in [ns] + osal_uint32_t settling_threshold_cycles;//!< \brief Settling cycles below threshold. + osal_uint32_t settling_threshold_cnt; //!< \brief Current cycles below threshold. + osal_bool_t settling_done; //!< \brief Settling done. enum { settling_mode_none, //!< \brief No settling mode, keep kp active diff --git a/include/libethercat/ec.h b/include/libethercat/ec.h index dffbeeb4..1f20216c 100644 --- a/include/libethercat/ec.h +++ b/include/libethercat/ec.h @@ -301,6 +301,23 @@ void ec_configure_tun(ec_t *pec, osal_uint8_t ip_address[4]); void ec_configure_dc(ec_t *pec, osal_uint64_t timer, ec_dc_mode_t mode, void (*user_cb)(void *arg, int num), void *user_cb_arg); +//! \brief Configures distributed clocks settling to time mode in +// dc ref_clock mode. In other modes this setting has no effect. +/*! + * \param[in] pec Pointer to EtherCAT master structure. + * \param[in] settling_time Settling time to be set. + */ +void ec_configure_dc_settling_time(ec_t *pec, double settling_time); + +//! \brief Configures distributed clocks settling to threshold mode in +// dc ref_clock mode. In other modes this setting has no effect. +/*! + * \param[in] pec Pointer to EtherCAT master structure. + * \param[in] threshold Settling threshold to be set in [ns]. + * \param[in] cycles Cycles below threshold. + */ +void ec_configure_dc_settling_threshold(ec_t *pec, double threshold, osal_uint32_t cycles); + //! \brief Create process data groups. /*! * \param[in] pec Pointer to ethercat master structure, diff --git a/src/ec.c b/src/ec.c index c533233f..d6bcedf5 100644 --- a/src/ec.c +++ b/src/ec.c @@ -2074,6 +2074,35 @@ void ec_configure_dc(ec_t *pec, osal_uint64_t timer, ec_dc_mode_t mode, pec->dc.cdg.user_cb_arg = user_cb_arg; } +//! \brief Configures distributed clocks settling to time mode in +// dc ref_clock mode. In other modes this setting has no effect. +/*! + * \param[in] pec Pointer to EtherCAT master structure. + * \param[in] settling_time Settling time to be set. + */ +void ec_configure_dc_settling_time(ec_t *pec, double settling_time) { + assert(pec != NULL); + + pec->dc.control.settling_mode = settling_mode_time; + pec->dc.control.settling_time = settling_time; +} + +//! \brief Configures distributed clocks settling to threshold mode in +// dc ref_clock mode. In other modes this setting has no effect. +/*! + * \param[in] pec Pointer to EtherCAT master structure. + * \param[in] threshold Settling threshold to be set in [ns]. + * \param[in] cycles Cycles below threshold. + */ +void ec_configure_dc_settling_threshold(ec_t *pec, double threshold, osal_uint32_t cycles) { + assert(pec != NULL); + + pec->dc.control.settling_mode = settling_mode_threshold; + pec->dc.control.settling_threshold = threshold; + pec->dc.control.settling_threshold_cycles = cycles; + pec->dc.control.settling_threshold_cnt = 0; +} + //! \brief Return current slave count. /*! * \param[in] pec Pointer to ethercat master structure. From 2e6df94721e88fdbcd9c0d978840959c2fd097db Mon Sep 17 00:00:00 2001 From: Robert Burger Date: Wed, 21 Aug 2024 08:33:39 +0200 Subject: [PATCH 10/10] Revert "Merge remote-tracking branch 'origin/feat/dc-pi-control-enhancement' into feat/hw_rework" This reverts commit bc01c76e5824d63d81c87bfa44f0b7b0571853d1, reversing changes made to 74349a6ab89451c1dfc8075f4aacfdb4cbc3bccd. --- include/libethercat/dc.h | 12 ------- include/libethercat/ec.h | 17 ---------- src/ec.c | 68 ---------------------------------------- 3 files changed, 97 deletions(-) diff --git a/include/libethercat/dc.h b/include/libethercat/dc.h index 530f9851..0cce47f2 100644 --- a/include/libethercat/dc.h +++ b/include/libethercat/dc.h @@ -107,18 +107,6 @@ typedef struct ec_dc_info { double kp; double ki; - double settling_time; //!< \brief Settling time in [ns] - double settling_threshold; //!< \brief Settling threshold in [ns] - osal_uint32_t settling_threshold_cycles;//!< \brief Settling cycles below threshold. - osal_uint32_t settling_threshold_cnt; //!< \brief Current cycles below threshold. - osal_bool_t settling_done; //!< \brief Settling done. - - enum { - settling_mode_none, //!< \brief No settling mode, keep kp active - settling_mode_time, //!< \brief Settling time mode - settling_mode_threshold //!< \brief Settling threshold mode - } settling_mode; - double v_part_old; } control; //!< \brief PI-controller to adjust EtherCAT master timer value. diff --git a/include/libethercat/ec.h b/include/libethercat/ec.h index 5e3d2416..8da2e305 100644 --- a/include/libethercat/ec.h +++ b/include/libethercat/ec.h @@ -299,23 +299,6 @@ void ec_configure_tun(ec_t *pec, osal_uint8_t ip_address[4]); void ec_configure_dc(ec_t *pec, osal_uint64_t timer, ec_dc_mode_t mode, void (*user_cb)(void *arg, int num), void *user_cb_arg); -//! \brief Configures distributed clocks settling to time mode in -// dc ref_clock mode. In other modes this setting has no effect. -/*! - * \param[in] pec Pointer to EtherCAT master structure. - * \param[in] settling_time Settling time to be set. - */ -void ec_configure_dc_settling_time(ec_t *pec, double settling_time); - -//! \brief Configures distributed clocks settling to threshold mode in -// dc ref_clock mode. In other modes this setting has no effect. -/*! - * \param[in] pec Pointer to EtherCAT master structure. - * \param[in] threshold Settling threshold to be set in [ns]. - * \param[in] cycles Cycles below threshold. - */ -void ec_configure_dc_settling_threshold(ec_t *pec, double threshold, osal_uint32_t cycles); - //! \brief Create process data groups. /*! * \param[in] pec Pointer to ethercat master structure, diff --git a/src/ec.c b/src/ec.c index 5a17b78b..30c4a9e1 100644 --- a/src/ec.c +++ b/src/ec.c @@ -1099,12 +1099,6 @@ int ec_open(ec_t *pec, struct hw_common *phw, int eeprom_log) { pec->dc.control.diffsum_limit = 10.; pec->dc.control.kp = 1; pec->dc.control.ki = 0.1; - pec->dc.control.settling_time = 1000000000; // 1 sec - pec->dc.control.settling_threshold = 10000; // 10 usec - pec->dc.control.settling_threshold_cycles = 100; - pec->dc.control.settling_threshold_cnt = 0; - pec->dc.control.settling_done = OSAL_FALSE; - pec->dc.control.settling_mode = settling_mode_none; pec->dc.control.v_part_old = 0.0; pec->tun_fd = 0; @@ -1771,39 +1765,6 @@ static void cb_distributed_clocks(struct ec *pec, pool_entry_t *p_entry, ec_data double p_part = pec->dc.control.kp * pec->dc.act_diff; pec->dc.control.v_part_old = p_part; - switch (pec->dc.control.settling_mode) { - case settling_mode_none: - break; - case settling_mode_time: - if ( (pec->dc.control.settling_done == OSAL_FALSE) && - (pec->dc.control.settling_time > pec->dc.dc_time) ) - { - pec->dc.control.settling_done = OSAL_TRUE; - } - - if (pec->dc.control.settling_done == OSAL_TRUE) { - p_part = 0; - } - break; - case settling_mode_threshold: - if (pec->dc.control.settling_done == OSAL_FALSE) { - if (pec->dc.act_diff < pec->dc.control.settling_threshold) { - pec->dc.control.settling_threshold_cnt++; - } else { - pec->dc.control.settling_threshold_cnt = 0; - } - - if (pec->dc.control.settling_threshold_cnt >= pec->dc.control.settling_threshold_cycles) { - pec->dc.control.settling_done = OSAL_TRUE; - } - } - - if (pec->dc.control.settling_done == OSAL_TRUE) { - p_part = 0; - } - break; - } - // sum it up for integral part pec->dc.control.diffsum += pec->dc.control.ki * pec->dc.act_diff; @@ -2070,35 +2031,6 @@ void ec_configure_dc(ec_t *pec, osal_uint64_t timer, ec_dc_mode_t mode, pec->dc.cdg.user_cb_arg = user_cb_arg; } -//! \brief Configures distributed clocks settling to time mode in -// dc ref_clock mode. In other modes this setting has no effect. -/*! - * \param[in] pec Pointer to EtherCAT master structure. - * \param[in] settling_time Settling time to be set. - */ -void ec_configure_dc_settling_time(ec_t *pec, double settling_time) { - assert(pec != NULL); - - pec->dc.control.settling_mode = settling_mode_time; - pec->dc.control.settling_time = settling_time; -} - -//! \brief Configures distributed clocks settling to threshold mode in -// dc ref_clock mode. In other modes this setting has no effect. -/*! - * \param[in] pec Pointer to EtherCAT master structure. - * \param[in] threshold Settling threshold to be set in [ns]. - * \param[in] cycles Cycles below threshold. - */ -void ec_configure_dc_settling_threshold(ec_t *pec, double threshold, osal_uint32_t cycles) { - assert(pec != NULL); - - pec->dc.control.settling_mode = settling_mode_threshold; - pec->dc.control.settling_threshold = threshold; - pec->dc.control.settling_threshold_cycles = cycles; - pec->dc.control.settling_threshold_cnt = 0; -} - //! \brief Return current slave count. /*! * \param[in] pec Pointer to ethercat master structure.