SOEM裸机移植

源码地址

https://gitee.com/rathon/apollof429-v2.git
还有一些移植细节可以参考我之前写的一些博客

硬件平台:

正点原子APOLLOF429V2开发板

开发环境

stm32cubemx6.2.0版本,用的库为STM32Cube_FW_F4_V1.26.2,开发软件为STM32cubeide
在这里插入图片描述

时钟配置

在这里插入图片描述

串口配置

非gnu版串口重定向


在main.c或者.h中添加以下代码进行重定向

#include <stdio.h>/* USER CODE BEGIN PFP */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);return ch;
}

gnu版串口重定向

当配置了–gnu时,需要用以下的重定向代码
在这里插入图片描述

#ifdef __GNUC__/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printfset to 'Yes') calls __io_putchar() *///#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)//comment_20190422: soem needs --gnu compile option,  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/*** @brief  Retargets the C library printf function to the USART.* @param  None* @retval None*/
PUTCHAR_PROTOTYPE
{/* Place your implementation of fputc here *//* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);return ch;
}

定时器配置

主站系统时钟

将TIM2定时器配置成1s周期中断,主频1Mhz,这样CNT对应的单位刚好是1us。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
打开定时器中断

HAL_TIM_Base_Start_IT(&htim2);

配置一个IO用于示波器抓取定时器时钟是否准确,这里选用PB0。(非必须)

uint32_t time_s ,time_ms, time_us;
extern int dorun;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM2){time_s++;}
}
uint32_t GetSec(void)
{return time_s;
}uint32_t GetUSec(void)
{time_us = (TIM2->CNT)%1000000;return time_us;
}

主站DC定时器中断函数

将TIM5定时器配置成1ms周期中断,主频1Mhz,这样CNT对应的单位刚好是1us。
在这里插入图片描述
打开定时器中断

HAL_TIM_Base_Start_IT(&htim5);

配置一个IO用于示波器抓取定时器时钟是否准确,这里选用PB0。(非必须)

uint32_t time_s ,time_ms, time_us;
extern int dorun;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM2){time_s++;}else if (htim->Instance == TIM5){HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);if(dorun==1){ecat_loop();}}else{}
}
uint32_t GetSec(void)
{return time_s;
}uint32_t GetUSec(void)
{time_us = (TIM2->CNT)%1000000;return time_us;
}

osal相关文件

osal是soem里的文件,里面有个延时相关的函数(因为我不喜欢正点原子提供的SYSTEM/delay文件夹里的函数),由于后面的PCF8574和IIC驱动里有延时调用,因此在这里我就先移植“osal”。

osal_def.h

/** Licensed under the GNU General Public License version 2 with exceptions. See* LICENSE file in the project root for full license information*/#ifndef _osal_defs_
#define _osal_defs_#ifdef __cplusplus
extern "C"
{
#endif// define if debug printf is needed
//#define EC_DEBUG#ifdef EC_DEBUG
#define EC_PRINT printf
#else
#define EC_PRINT(...) do {} while (0)
#endif#ifndef PACKED
#define PACKED_BEGIN
#define PACKED  __attribute__((__packed__))
#define PACKED_END
#endif#define OSAL_THREAD_HANDLE task_t *
#define OSAL_THREAD_FUNC void
#define OSAL_THREAD_FUNC_RT void#ifdef __cplusplus
}
#endif#endif

osal.h

/** Licensed under the GNU General Public License version 2 with exceptions. See* LICENSE file in the project root for full license information*/#ifndef _osal_
#define _osal_#ifdef __cplusplus
extern "C"
{
#endif#include "osal_defs.h"
#include <stdint.h>
#include <stdbool.h>
/* General types */
#ifndef TRUE
#define TRUE                1
#endif
#ifndef FALSE
#define FALSE               0
#endif
typedef uint8_t             boolean;
typedef int8_t              int8;
typedef int16_t             int16;
typedef int32_t             int32;
typedef uint8_t             uint8;
typedef uint16_t            uint16;
typedef uint32_t            uint32;
typedef int64_t             int64;
typedef uint64_t            uint64;
typedef float               float32;
typedef double              float64;typedef struct
{uint32 sec;     /*< Seconds elapsed since the Epoch (Jan 1, 1970) */uint32 usec;    /*< Microseconds elapsed since last second boundary */
} ec_timet;typedef struct
{uint32 tv_sec;uint32 tv_usec;
}timeval;typedef struct
{int tz_minuteswest; /* 格林尼治时间往西方的时差,以分钟为单位 */int tz_dsttime; /* 日光节约时间的修正方式 */
}timezone;typedef struct osal_timer
{ec_timet stop_time;
} osal_timert;void osal_timer_start(osal_timert * self, uint32 timeout_us);
boolean osal_timer_is_expired(osal_timert * self);
int osal_usleep(uint32 usec);
ec_timet osal_current_time(void);
void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff);
int osal_thread_create(void *thandle, int stacksize, void *func, void *param);
int osal_thread_create_rt(void *thandle, int stacksize, void *func, void *param);#ifdef __cplusplus
}
#endif#endif

osal.c

/** Licensed under the GNU General Public License version 2 with exceptions. See* LICENSE file in the project root for full license information*/
#include "osal.h"
#include "tim.h"
#include <stdlib.h>#define  timercmp(a, b, CMP)                                \(((a)->tv_sec == (b)->tv_sec) ?                           \((a)->tv_usec CMP (b)->tv_usec) :                        \((a)->tv_sec CMP (b)->tv_sec))
#define  timeradd(a, b, result)                             \do {                                                      \(result)->tv_sec = (a)->tv_sec + (b)->tv_sec;           \(result)->tv_usec = (a)->tv_usec + (b)->tv_usec;        \if ((result)->tv_usec >= 1000000)                       \{                                                       \++(result)->tv_sec;                                  \(result)->tv_usec -= 1000000;                        \}                                                       \} while (0)
#define  timersub(a, b, result)                             \do {                                                      \(result)->tv_sec = (a)->tv_sec - (b)->tv_sec;           \(result)->tv_usec = (a)->tv_usec - (b)->tv_usec;        \if ((result)->tv_usec < 0) {                            \--(result)->tv_sec;                                   \(result)->tv_usec += 1000000;                         \}                                                       \} while (0)#define USECS_PER_SEC   1000000
#define USECS_PER_TICK  (USECS_PER_SEC / CFG_TICKS_PER_SECOND)/* Workaround for rt-labs defect 776.* Default implementation of udelay() didn't work correctly when tick was* shorter than one millisecond.*/
void udelay (uint32_t us)
{osal_timert qtime;osal_timer_start(&qtime, us);while(!osal_timer_is_expired(&qtime));
}int gettimeofday(timeval *tp, void *tzp)
{uint32_t sec = GetSec();uint32_t us = GetUSec();tp->tv_usec = us;tp->tv_sec = sec;return 0;
}int osal_usleep (uint32 usec)
{udelay(usec);return 0;
}int osal_gettimeofday(timeval *tv, timezone *tz)
{return gettimeofday(tv, tz);
}ec_timet osal_current_time (void)
{timeval current_time;ec_timet return_value;gettimeofday (&current_time, 0);return_value.sec = current_time.tv_sec;return_value.usec = current_time.tv_usec;return return_value;
}void osal_timer_start (osal_timert * self, uint32 timeout_usec)
{timeval start_time;timeval timeout;timeval stop_time;gettimeofday (&start_time, 0);timeout.tv_sec = timeout_usec / USECS_PER_SEC;timeout.tv_usec = timeout_usec % USECS_PER_SEC;timeradd (&start_time, &timeout, &stop_time);self->stop_time.sec = stop_time.tv_sec;self->stop_time.usec = stop_time.tv_usec;
}boolean osal_timer_is_expired (osal_timert * self)
{timeval current_time;timeval stop_time;int is_not_yet_expired;gettimeofday (&current_time, 0);stop_time.tv_sec = self->stop_time.sec;stop_time.tv_usec = self->stop_time.usec;is_not_yet_expired = timercmp (&current_time, &stop_time, <);return is_not_yet_expired == false;
}void *osal_malloc(size_t size)
{return malloc(size);
}void osal_free(void *ptr)
{free(ptr);
}int osal_thread_create(void *thandle, int stacksize, void *func, void *param)
{
//   thandle = task_spawn ("worker", func, 6,stacksize, param);
//   if(!thandle)
//   {
//      return 0;
//   }return 1;
}int osal_thread_create_rt(void *thandle, int stacksize, void *func, void *param)
{
//   thandle = task_spawn ("worker_rt", func, 15 ,stacksize, param);
//   if(!thandle)
//   {
//      return 0;
//   }return 1;
}

添加PCF8574和IIC驱动在这里插入图片描述

在这里插入图片描述
由于正点原子的阿波罗开发板中,phy芯片的ETH_RESET引脚由PCF8574芯片控制,因此得从正点原子的代码中copy来以下驱动文件。
在这里插入图片描述
由于正点原子这种独特的设计,导致phy的复位引脚的代码变得很复杂。

myiic.h

/******************************************************************************************************* @file        myiic.h* @author      正点原子团队(ALIENTEK)* @version     V1.0* @date        2022-04-20* @brief       IIC 驱动代码* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 阿波罗 F429开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com** 修改说明* V1.0 20220420* 第一次发布******************************************************************************************************/#ifndef __MYIIC_H
#define __MYIIC_H
#include "stm32f4xx_hal.h"
#include "osal.h"
/******************************************************************************************/
/* 引脚 定义 */#define IIC_SCL_GPIO_PORT               GPIOH
#define IIC_SCL_GPIO_PIN                GPIO_PIN_4
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0)   /* PH口时钟使能 */#define IIC_SDA_GPIO_PORT               GPIOH
#define IIC_SDA_GPIO_PIN                GPIO_PIN_5
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0)   /* PH口时钟使能 *//******************************************************************************************/
/* IO操作 */#define IIC_SCL(x)        do{ x ? \HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* SCL */#define IIC_SDA(x)        do{ x ? \HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* SDA */#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN)        /* 读取SDA *//******************************************************************************************/
/* IIC所有操作函数 */void iic_init(void);                        /* 初始化IIC的IO口 */
void iic_start(void);                       /* 发送IIC开始信号 */
void iic_stop(void);                        /* 发送IIC停止信号 */
void iic_ack(void);                         /* IIC发送ACK信号 */
void iic_nack(void);                        /* IIC不发送ACK信号 */
uint8_t iic_wait_ack(void);                 /* IIC等待ACK信号 */
void iic_send_byte(uint8_t data);           /* IIC发送一个字节 */
uint8_t iic_read_byte(unsigned char ack);   /* IIC读取一个字节 */#endif

myiic.c

/******************************************************************************************************* @file        myiic.c* @author      正点原子团队(ALIENTEK)* @version     V1.0* @date        2022-04-20* @brief       IIC 驱动代码* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 阿波罗 F429开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com** 修改说明* V1.0 20220420* 第一次发布******************************************************************************************************/#include "myiic.h"/*** @brief       初始化IIC* @param       无* @retval      无*/
void iic_init(void)
{GPIO_InitTypeDef gpio_init_struct;IIC_SCL_GPIO_CLK_ENABLE();                              /* SCL引脚时钟使能 */IIC_SDA_GPIO_CLK_ENABLE();                              /* SDA引脚时钟使能 */gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;     /* 快速 */HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);    /* SCL引脚初始化 *//* SDA引脚开漏输出,上拉, 这样就不用再设置IO方向了,开漏输出的时候(=1), 也可以读取外部信号的高低电平 */gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;            /* 开漏输出 */HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);    /* SDA引脚初始化 */iic_stop();                                             /* 停止总线上所有设备 */
}/*** @brief       IIC延时函数,用于控制IIC读写速度* @param       无* @retval      无*/
static void iic_delay(void)
{osal_usleep(2);            /* 2us的延时, 读写速度在250Khz以内 */
}/*** @brief       产生IIC起始信号* @param       无* @retval      无*/
void iic_start(void)
{IIC_SDA(1);IIC_SCL(1);iic_delay();IIC_SDA(0);             /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */iic_delay();IIC_SCL(0);             /* 钳住I2C总线,准备发送或接收数据 */iic_delay();
}/*** @brief       产生IIC停止信号* @param       无* @retval      无*/
void iic_stop(void)
{IIC_SDA(0);             /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */iic_delay();IIC_SCL(1);iic_delay();IIC_SDA(1);             /* 发送I2C总线结束信号 */iic_delay();
}/*** @brief       等待应答信号到来* @param       无* @retval      1,接收应答失败*              0,接收应答成功*/
uint8_t iic_wait_ack(void)
{uint8_t waittime = 0;uint8_t rack = 0;IIC_SDA(1);             /* 主机释放SDA线(此时外部器件可以拉低SDA线) */iic_delay();IIC_SCL(1);             /* SCL=1, 此时从机可以返回ACK */iic_delay();while (IIC_READ_SDA)    /* 等待应答 */{waittime++;if (waittime > 250){iic_stop();rack = 1;break;}}IIC_SCL(0);             /* SCL=0, 结束ACK检查 */iic_delay();return rack;
}/*** @brief       产生ACK应答* @param       无* @retval      无*/
void iic_ack(void)
{IIC_SDA(0);             /* SCL 0 -> 1 时 SDA = 0,表示应答 */iic_delay();IIC_SCL(1);             /* 产生一个时钟 */iic_delay();IIC_SCL(0);iic_delay();IIC_SDA(1);             /* 主机释放SDA线 */iic_delay();
}/*** @brief       不产生ACK应答* @param       无* @retval      无*/
void iic_nack(void)
{IIC_SDA(1);             /* SCL 0 -> 1  时 SDA = 1,表示不应答 */iic_delay();IIC_SCL(1);             /* 产生一个时钟 */iic_delay();IIC_SCL(0);iic_delay();
}/*** @brief       IIC发送一个字节* @param       data: 要发送的数据* @retval      无*/
void iic_send_byte(uint8_t data)
{uint8_t t;for (t = 0; t < 8; t++){IIC_SDA((data & 0x80) >> 7);    /* 高位先发送 */iic_delay();IIC_SCL(1);iic_delay();IIC_SCL(0);data <<= 1;             /* 左移1位,用于下一次发送 */}IIC_SDA(1);                 /* 发送完成, 主机释放SDA线 */
}/*** @brief       IIC读取一个字节* @param       ack:  ack=1时,发送ack; ack=0时,发送nack* @retval      接收到的数据*/
uint8_t iic_read_byte(uint8_t ack)
{uint8_t i, receive = 0;for (i = 0; i < 8; i++ )    /* 接收1个字节数据 */{receive <<= 1;          /* 高位先输出,所以先收到的数据位要左移 */IIC_SCL(1);iic_delay();if (IIC_READ_SDA){receive++;}IIC_SCL(0);iic_delay();}if (!ack){iic_nack();             /* 发送nACK */}else{iic_ack();              /* 发送ACK */}return receive;
}

pcf8574.h

/******************************************************************************************************* @file        pcf8574.h* @author      正点原子团队(ALIENTEK)* @version     V1.0* @date        2022-04-20* @brief       PCF8574 驱动代码* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 阿波罗 F429开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com** 修改说明* V1.0 20220420* 第一次发布******************************************************************************************************/#ifndef __PCF8574_H
#define __PCF8574_H#include "myiic.h"/******************************************************************************************/
/* 引脚 定义 */#define PCF8574_GPIO_PORT                  GPIOB
#define PCF8574_GPIO_PIN                   GPIO_PIN_12
#define PCF8574_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)  /* PB口时钟使能 *//******************************************************************************************/#define PCF8574_INT  HAL_GPIO_ReadPin(PCF8574_GPIO_PORT, PCF8574_GPIO_PIN)              /* PCF8574 INT脚 */#define PCF8574_ADDR  0X40      /* PCF8574地址(左移了一位) *//* PCF8574各个IO的功能 */
#define BEEP_IO         0       /* 蜂鸣器控制引脚        P0 */
#define AP_INT_IO       1       /* AP3216C中断引脚       P1 */
#define DCMI_PWDN_IO    2       /* DCMI的电源控制引脚    P2 */
#define USB_PWR_IO      3       /* USB电源控制引脚       P3 */
#define EX_IO           4       /* 扩展IO,自定义使用     P4 */
#define MPU_INT_IO      5       /* SH3001中断引脚        P5 */
#define RS485_RE_IO     6       /* RS485_RE引脚          P6 */
#define ETH_RESET_IO    7       /* 以太网复位引脚        P7 *//******************************************************************************************/uint8_t pcf8574_init(void); 
uint8_t pcf8574_read_byte(void); 
void pcf8574_write_byte(uint8_t data);
void pcf8574_write_bit(uint8_t bit, uint8_t sta);
uint8_t pcf8574_read_bit(uint8_t bit);#endif

pcf8574.c

/******************************************************************************************************* @file        pcf8574.c* @author      正点原子团队(ALIENTEK)* @version     V1.0* @date        2022-04-20* @brief       PCF8574 驱动代码* @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司***************************************************************************************************** @attention** 实验平台:正点原子 阿波罗 F429开发板* 在线视频:www.yuanzige.com* 技术论坛:www.openedv.com* 公司网址:www.alientek.com* 购买地址:openedv.taobao.com** 修改说明* V1.0 20220420* 第一次发布******************************************************************************************************/#include "pcf8574.h"/*** @brief       初始化PCF8574* @param       无* @retval      0, 成功;1, 失败;*/
uint8_t pcf8574_init(void)
{uint8_t temp = 0;GPIO_InitTypeDef gpio_init_struct;PCF8574_GPIO_CLK_ENABLE();                               /* 使能GPIOB时钟 */gpio_init_struct.Pin = PCF8574_GPIO_PIN;                 /* PB12 */gpio_init_struct.Mode = GPIO_MODE_INPUT;                 /* 输入 */gpio_init_struct.Pull = GPIO_PULLUP;                     /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_HIGH;                /* 高速 */HAL_GPIO_Init(PCF8574_GPIO_PORT, &gpio_init_struct);     /* 初始化IO */iic_init();                                              /* IIC初始化 *//* 检查PCF8574是否在位 */iic_start();iic_send_byte(PCF8574_ADDR);                             /* 写地址 */temp = iic_wait_ack();                                   /* 等待应答,通过判断是否有ACK应答,来判断PCF8574的状态 */iic_stop();                                              /* 产生一个停止条件 */pcf8574_write_byte(0XFF);                                /* 默认情况下所有IO输出高电平 */return temp;
}/*** @brief       读取PCF8574的8位IO值* @param       无* @retval      读到的数据*/
uint8_t pcf8574_read_byte(void)
{ uint8_t temp = 0;iic_start();iic_send_byte(PCF8574_ADDR | 0X01);   /* 进入接收模式 */iic_wait_ack();temp = iic_read_byte(0);iic_stop();                           /* 产生一个停止条件 */return temp;
}/*** @brief       向PCF8574写入8位IO值* @param       data   : 要写入的数据* @retval      无*/
void pcf8574_write_byte(uint8_t data)
{iic_start();  iic_send_byte(PCF8574_ADDR | 0X00);   /* 发送器件地址0X40,写数据 */iic_wait_ack();iic_send_byte(data);                  /* 发送字节 */iic_wait_ack();iic_stop();                           /* 产生一个停止条件  */osal_usleep(10000); 
}/*** @brief       设置PCF8574某个IO的高低电平* @param       bit    : 要设置的IO编号,0~7* @param       sta    : IO的状态;0或1* @retval      无*/
void pcf8574_write_bit(uint8_t bit, uint8_t sta)
{uint8_t data;data = pcf8574_read_byte();          /* 先读出原来的设置 */if (sta == 0){data &= ~(1 << bit);}else{data |= 1 << bit;}pcf8574_write_byte(data);            /* 写入新的数据 */
}/*** @brief       读取PCF8574的某个IO的值* @param       bit     : 要读取的IO编号, 0~7* @retval      此IO口的值(状态, 0/1)*/
uint8_t pcf8574_read_bit(uint8_t bit)
{uint8_t data;data = pcf8574_read_byte();          /* 先读取这个8位IO的值  */if (data & (1 << bit)){return 1;}else {return 0; }
}  

以太网外设

STM32CUBEMX配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此时会自动生成eth.c文件
在这里插入图片描述

eth.h

/********************************************************************************* @file    eth.h* @brief   This file contains all the function prototypes for*          the eth.c file******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __ETH_H__
#define __ETH_H__#ifdef __cplusplus
extern "C" {
#endif/* Includes ------------------------------------------------------------------*/
#include "main.h"/* USER CODE BEGIN Includes *//* USER CODE END Includes */extern ETH_HandleTypeDef heth;/* USER CODE BEGIN Private defines *//* USER CODE END Private defines */void MX_ETH_Init(void);/* USER CODE BEGIN Prototypes */
/* PHY芯片寄存器映射表 */ 
#define ETH_CHIP_BCR                            ((uint16_t)0x0000U)
#define ETH_CHIP_BSR                            ((uint16_t)0x0001U)
#define PHY_REGISTER2                           ((uint16_t)0x0002U)
#define PHY_REGISTER3                           ((uint16_t)0x0003U)/* 操作SCR寄存器的值(一般不需要修改) */
#define ETH_CHIP_BCR_SOFT_RESET                 ((uint16_t)0x8000U)
#define ETH_CHIP_BCR_LOOPBACK                   ((uint16_t)0x4000U)
#define ETH_CHIP_BCR_SPEED_SELECT               ((uint16_t)0x2000U)
#define ETH_CHIP_BCR_AUTONEGO_EN                ((uint16_t)0x1000U)
#define ETH_CHIP_BCR_POWER_DOWN                 ((uint16_t)0x0800U)
#define ETH_CHIP_BCR_ISOLATE                    ((uint16_t)0x0400U)
#define ETH_CHIP_BCR_RESTART_AUTONEGO           ((uint16_t)0x0200U)
#define ETH_CHIP_BCR_DUPLEX_MODE                ((uint16_t)0x0100U) /* 操作BSR寄存器的值(一般不需要修改) */   
#define ETH_CHIP_BSR_100BASE_T4                 ((uint16_t)0x8000U)
#define ETH_CHIP_BSR_100BASE_TX_FD              ((uint16_t)0x4000U)
#define ETH_CHIP_BSR_100BASE_TX_HD              ((uint16_t)0x2000U)
#define ETH_CHIP_BSR_10BASE_T_FD                ((uint16_t)0x1000U)
#define ETH_CHIP_BSR_10BASE_T_HD                ((uint16_t)0x0800U)
#define ETH_CHIP_BSR_100BASE_T2_FD              ((uint16_t)0x0400U)
#define ETH_CHIP_BSR_100BASE_T2_HD              ((uint16_t)0x0200U)
#define ETH_CHIP_BSR_EXTENDED_STATUS            ((uint16_t)0x0100U)
#define ETH_CHIP_BSR_AUTONEGO_CPLT              ((uint16_t)0x0020U)
#define ETH_CHIP_BSR_REMOTE_FAULT               ((uint16_t)0x0010U)
#define ETH_CHIP_BSR_AUTONEGO_ABILITY           ((uint16_t)0x0008U)
#define ETH_CHIP_BSR_LINK_STATUS                ((uint16_t)0x0004U)
#define ETH_CHIP_BSR_JABBER_DETECT              ((uint16_t)0x0002U)
#define ETH_CHIP_BSR_EXTENDED_CAP               ((uint16_t)0x0001U)
/* PHY芯片进程状态 */
#define  ETH_CHIP_STATUS_READ_ERROR             ((int32_t)-5)
#define  ETH_CHIP_STATUS_WRITE_ERROR            ((int32_t)-4)
#define  ETH_CHIP_STATUS_ADDRESS_ERROR          ((int32_t)-3)
#define  ETH_CHIP_STATUS_RESET_TIMEOUT          ((int32_t)-2)
#define  ETH_CHIP_STATUS_ERROR                  ((int32_t)-1)
#define  ETH_CHIP_STATUS_OK                     ((int32_t) 0)
#define  ETH_CHIP_STATUS_LINK_DOWN              ((int32_t) 1)
#define  ETH_CHIP_STATUS_100MBITS_FULLDUPLEX    ((int32_t) 2)
#define  ETH_CHIP_STATUS_100MBITS_HALFDUPLEX    ((int32_t) 3)
#define  ETH_CHIP_STATUS_10MBITS_FULLDUPLEX     ((int32_t) 4)
#define  ETH_CHIP_STATUS_10MBITS_HALFDUPLEX     ((int32_t) 5)
#define  ETH_CHIP_STATUS_AUTONEGO_NOTDONE       ((int32_t) 6)void PhyReset(void);
void PhyEventHandler(void);
void PhyTick(void);
#define LAN8720                                 0
#define SR8201F                                 1
#define YT8512C                                 2
#define RTL8201                                 3int EthRdPacket(void* pBuff);
int EthWrPacket(void* pBuff, int Len);
/* USER CODE END Prototypes */#ifdef __cplusplus
}
#endif#endif /* __ETH_H__ *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

eth.c

/********************************************************************************* @file    eth.c* @brief   This file provides code for the configuration*          of the ETH instances.******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2024 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************//* Includes ------------------------------------------------------------------*/
#include "eth.h"/* USER CODE BEGIN 0 */
#include <stdio.h>
#include <string.h>
#include "osal.h"
#include "pcf8574.h"
#if defined ( __ICCARM__ ) /*!< IAR Compiler */#pragma data_alignment=4
#endif
__ALIGN_BEGIN ETH_DMADescTypeDef  DMARxDscrTab[ETH_RXBUFNB] __ALIGN_END;/* Ethernet Rx MA Descriptor */#if defined ( __ICCARM__ ) /*!< IAR Compiler */#pragma data_alignment=4
#endif
__ALIGN_BEGIN ETH_DMADescTypeDef  DMATxDscrTab[ETH_TXBUFNB] __ALIGN_END;/* Ethernet Tx DMA Descriptor */#if defined ( __ICCARM__ ) /*!< IAR Compiler */#pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __ALIGN_END; /* Ethernet Receive Buffer */#if defined ( __ICCARM__ ) /*!< IAR Compiler */#pragma data_alignment=4
#endif
__ALIGN_BEGIN uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __ALIGN_END; /* Ethernet Transmit Buffer */#define YT8512C_AND_RTL8201BL_PHYREGISTER2      0x0000
#define SR8201F_PHYREGISTER2                    0x001C
#define LAN8720A_PHYREGISTER2                   0x0007
uint32_t PHY_TYPE;
uint16_t ETH_CHIP_PHYSCSR;
uint16_t ETH_CHIP_SPEED_STATUS;
uint16_t ETH_CHIP_DUPLEX_STATUS;
/* USER CODE END 0 */ETH_HandleTypeDef heth;/* ETH init function */
void MX_ETH_Init(void)
{/* USER CODE BEGIN ETH_Init 0 *//* USER CODE END ETH_Init 0 *//* USER CODE BEGIN ETH_Init 1 *//* USER CODE END ETH_Init 1 */heth.Instance = ETH;heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;heth.Init.Speed = ETH_SPEED_100M;heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;heth.Init.PhyAddress = LAN8742A_PHY_ADDRESS;heth.Init.MACAddr[0] =   0x00;heth.Init.MACAddr[1] =   0x80;heth.Init.MACAddr[2] =   0xE1;heth.Init.MACAddr[3] =   0x00;heth.Init.MACAddr[4] =   0x00;heth.Init.MACAddr[5] =   0x00;heth.Init.RxMode = ETH_RXPOLLING_MODE;heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;/* USER CODE BEGIN MACADDRESS */heth.Init.PhyAddress = 0U;/* USER CODE END MACADDRESS */if (HAL_ETH_Init(&heth) != HAL_OK){Error_Handler();}/* USER CODE BEGIN ETH_Init 2 *//* Initialize Tx Descriptors list: Chain Mode */HAL_ETH_DMATxDescListInit(&heth, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);/* Initialize Rx Descriptors list: Chain Mode  */HAL_ETH_DMARxDescListInit(&heth, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);/* Enable MAC and DMA transmission and reception */HAL_ETH_Start(&heth);/* USER CODE END ETH_Init 2 */}void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(ethHandle->Instance==ETH){/* USER CODE BEGIN ETH_MspInit 0 *//* USER CODE END ETH_MspInit 0 *//* ETH clock enable */__HAL_RCC_ETH_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOG_CLK_ENABLE();/**ETH GPIO ConfigurationPC1     ------> ETH_MDCPA1     ------> ETH_REF_CLKPA2     ------> ETH_MDIOPA7     ------> ETH_CRS_DVPC4     ------> ETH_RXD0PC5     ------> ETH_RXD1PB11     ------> ETH_TX_ENPG13     ------> ETH_TXD0PG14     ------> ETH_TXD1*/GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_11;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF11_ETH;HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);/* USER CODE BEGIN ETH_MspInit 1 */PhyReset();/* USER CODE END ETH_MspInit 1 */}
}void HAL_ETH_MspDeInit(ETH_HandleTypeDef* ethHandle)
{if(ethHandle->Instance==ETH){/* USER CODE BEGIN ETH_MspDeInit 0 *//* USER CODE END ETH_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_ETH_CLK_DISABLE();/**ETH GPIO ConfigurationPC1     ------> ETH_MDCPA1     ------> ETH_REF_CLKPA2     ------> ETH_MDIOPA7     ------> ETH_CRS_DVPC4     ------> ETH_RXD0PC5     ------> ETH_RXD1PB11     ------> ETH_TX_ENPG13     ------> ETH_TXD0PG14     ------> ETH_TXD1*/HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5);HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7);HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11);HAL_GPIO_DeInit(GPIOG, GPIO_PIN_13|GPIO_PIN_14);/* USER CODE BEGIN ETH_MspDeInit 1 *//* USER CODE END ETH_MspDeInit 1 */}
}/* USER CODE BEGIN 1 */
/*  SR8201F     Register 2    0x001CRegister 3    0xC016YT8512C     Register 2    0x0000Register 3    0x0128LAN8720A    Register 2    0x0007Register 3    0xC0F0RTL8201BL   Register 2    0x0000Register 3    0x8201 */
void PhyReset(void)
{uint32_t regvalue;HAL_ETH_ReadPHYRegister(&heth,PHY_REGISTER2, &regvalue);//get phy idPHY_TYPE = regvalue;printf("phy id is %d\n",PHY_TYPE);if (PHY_TYPE && 0xFFF == 0xFFF)                           /*LAN8720A*/{pcf8574_write_bit(ETH_RESET_IO,1);osal_usleep(10000);pcf8574_write_bit(ETH_RESET_IO,0);osal_usleep(10000);}else                                                    /*YT8512C*/{pcf8574_write_bit(ETH_RESET_IO,0);osal_usleep(10000);pcf8574_write_bit(ETH_RESET_IO,1);osal_usleep(10000);}HAL_ETH_ReadPHYRegister(&heth,PHY_REGISTER2, &regvalue);//get phy idswitch (regvalue){case YT8512C_AND_RTL8201BL_PHYREGISTER2:HAL_ETH_ReadPHYRegister(&heth,PHY_REGISTER3, &regvalue);if (regvalue == 0x128){ETH_CHIP_PHYSCSR  = ((uint16_t)0x11);ETH_CHIP_SPEED_STATUS = ((uint16_t)0x4010);ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x2000);PHY_TYPE = YT8512C;}else{ETH_CHIP_PHYSCSR  = ((uint16_t)0x10);ETH_CHIP_SPEED_STATUS = ((uint16_t)0x0022);ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x0004);PHY_TYPE = RTL8201;}break;case SR8201F_PHYREGISTER2:ETH_CHIP_PHYSCSR  = ((uint16_t)0x00);ETH_CHIP_SPEED_STATUS = ((uint16_t)0x2020);ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x0100);PHY_TYPE = SR8201F;break;case LAN8720A_PHYREGISTER2:ETH_CHIP_PHYSCSR  = ((uint16_t)0x1F);ETH_CHIP_SPEED_STATUS = ((uint16_t)0x0004);ETH_CHIP_DUPLEX_STATUS = ((uint16_t)0x0010);PHY_TYPE = LAN8720;break;}
}int32_t eth_chip_get_link_state(void)
{uint32_t readval = 0;if (HAL_ETH_ReadPHYRegister(&heth,ETH_CHIP_PHYSCSR, &readval) != HAL_OK){return ETH_CHIP_STATUS_READ_ERROR;}if (((readval & ETH_CHIP_SPEED_STATUS) != ETH_CHIP_SPEED_STATUS) && ((readval & ETH_CHIP_DUPLEX_STATUS) != 0)){return ETH_CHIP_STATUS_100MBITS_FULLDUPLEX;}else if (((readval & ETH_CHIP_SPEED_STATUS) != ETH_CHIP_SPEED_STATUS)){return ETH_CHIP_STATUS_100MBITS_HALFDUPLEX;}else if (((readval & ETH_CHIP_BCR_DUPLEX_MODE) != ETH_CHIP_BCR_DUPLEX_MODE)){return ETH_CHIP_STATUS_10MBITS_FULLDUPLEX;}else{return ETH_CHIP_STATUS_10MBITS_HALFDUPLEX;}
}int linkState;
int phyEvent;
void PhyEventHandler(void)
{uint32_t value;//Any link failure condition is latched in the BMSR register. Reading//the register twice will always return the actual link statusHAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*/HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*///Link is up?if((value & PHY_LINKED_STATUS) != 0){int32_t readval = 0;uint32_t duplex = 0;uint32_t speed = 0;readval = eth_chip_get_link_state();if (readval == ETH_CHIP_STATUS_READ_ERROR){//Update link statelinkState = FALSE;}else{switch (readval){case ETH_CHIP_STATUS_100MBITS_FULLDUPLEX:duplex = ETH_MODE_FULLDUPLEX;speed = ETH_SPEED_100M;printf("ETH_CHIP_STATUS_100MBITS_FULLDUPLEX\n");break;case ETH_CHIP_STATUS_100MBITS_HALFDUPLEX:duplex = ETH_MODE_HALFDUPLEX;speed = ETH_SPEED_100M;printf("ETH_CHIP_STATUS_100MBITS_HALFDUPLEX\n");break;case ETH_CHIP_STATUS_10MBITS_FULLDUPLEX:duplex = ETH_MODE_FULLDUPLEX;speed = ETH_SPEED_10M;printf("ETH_CHIP_STATUS_10MBITS_FULLDUPLEX\n");break;case ETH_CHIP_STATUS_10MBITS_HALFDUPLEX:duplex = ETH_MODE_HALFDUPLEX;speed = ETH_SPEED_10M;printf("ETH_CHIP_STATUS_10MBITS_HALFDUPLEX\n");break;default:duplex = ETH_MODE_FULLDUPLEX;speed = ETH_SPEED_100M;printf("ETH_CHIP_STATUS_100MBITS_FULLDUPLEX\n");break;}heth.Init.Speed = speed;heth.Init.DuplexMode = duplex;//Update link statelinkState = TRUE;/* ETHERNET MAC Re-Configuration */HAL_ETH_ConfigMAC(&heth, (ETH_MACInitTypeDef *) NULL);/* Restart MAC interface */HAL_ETH_Start(&heth);}}else{//Update link statelinkState = FALSE;}}
extern int dorun;
void PhyTick(void)
{uint32_t value;int link;//Any link failure condition is latched in the BMSR register. Reading//the register twice will always return the actual link statusHAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*/HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &value);/* Read PHY_BSR*///Retrieve current link statelink= (value & PHY_LINKED_STATUS) ? TRUE : FALSE;//Link up event?if(link && !linkState){//Set event flagphyEvent = TRUE;printf("Link up event\n");}//Link down event?else if(!link && linkState){//Set event flagphyEvent = TRUE;dorun = 0;printf("Link down event\n");}
}int EthRdPacket(void* pBuff)
{int Len;uint8_t* pDmaBuff;HAL_StatusTypeDef HalStatus;__IO ETH_DMADescTypeDef *dmarxdesc;HalStatus = HAL_ETH_GetReceivedFrame(&heth);            // check if a packet has been received/* Clean and Invalidate data cache *///SCB_CleanInvalidateDCache();if (HalStatus == HAL_OK)                                // packet received{Len = heth.RxFrameInfos.length;                     // packet lenghtpDmaBuff = (uint8_t*)heth.RxFrameInfos.buffer;      // DMA buffer pointememcpy (pBuff, pDmaBuff, Len);                      // read the data/* Release descriptors to DMA *//* Point to first descriptor */dmarxdesc = heth.RxFrameInfos.FSRxDesc;/* Set Own bit in Rx descriptors: gives the buffers back to DMA */for (int i=0; i< heth.RxFrameInfos.SegCount; i++){dmarxdesc->Status |= ETH_DMARXDESC_OWN;dmarxdesc = (ETH_DMADescTypeDef *)(dmarxdesc->Buffer2NextDescAddr);}/* Clear Segment_Count */heth.RxFrameInfos.SegCount =0;return Len;                                         // return the number of bytes read}else{return 0;                                        // no packet received}
}int EthWrPacket(void* pBuff, int Len)
{uint8_t* pDmaBuff;HAL_StatusTypeDef HalStatus;/* Clean and Invalidate data cache *///SCB_CleanInvalidateDCache();if ((heth.TxDesc->Status & ETH_DMATXDESC_OWN) == (uint32_t)RESET){pDmaBuff = (uint8_t*)(heth.TxDesc->Buffer1Addr);memcpy (pDmaBuff, pBuff, Len);HalStatus = HAL_ETH_TransmitFrame(&heth, Len);if (HalStatus != HAL_OK){printf ("HAL_ETH_TransmitFrame err %d\n", HalStatus);return 0;}return Len;}else{return 0;}
}
/* USER CODE END 1 *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

SOEM例程

main.c

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init */time_s = 0;time_ms = 0;time_us = 0;/* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_TIM2_Init();MX_TIM5_Init();MX_USART1_UART_Init();//MX_ETH_Init();/* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(&htim2);HAL_TIM_Base_Start_IT(&htim5);while (pcf8574_init())                      /* ��ⲻ��PCF8574 */{printf("PCF8574 Check Failed!\n");osal_usleep(1000);printf("Please Check!      \n");}printf("PCF8574 Check Success!\n");MX_ETH_Init();linkState = FALSE;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */PhyTick();if(phyEvent){phyEvent = FALSE;PhyEventHandler();simpletest("hello");//slaveinfo("hello");//servotest("hello");}else{if(time_us%100000 == 0){//ecatcheck();}}}/* USER CODE END 3 */
}

slaveinfo.c

/** \file* \brief Example code for Simple Open EtherCAT master** Usage : slaveinfo [ifname] [-sdo] [-map]* Ifname is NIC interface, f.e. eth0.* Optional -sdo to display CoE object dictionary.* Optional -map to display slave PDO mapping** This shows the configured slave data.** (c)Arthur Ketels 2010 - 2011*/#include <stdio.h>
#include <string.h>
#include <inttypes.h>#include "ethercat.h"
#include "slaveinfo.h"extern char IOmap[4096];
ec_ODlistt ODlist;
ec_OElistt OElist;
boolean printSDO = FALSE;
boolean printMAP = FALSE;
char usdo[128];
char hstr[1024];char* dtype2string(uint16 dtype)
{switch(dtype){case ECT_BOOLEAN:sprintf(hstr, "BOOLEAN");break;case ECT_INTEGER8:sprintf(hstr, "INTEGER8");break;case ECT_INTEGER16:sprintf(hstr, "INTEGER16");break;case ECT_INTEGER32:sprintf(hstr, "INTEGER32");break;case ECT_INTEGER24:sprintf(hstr, "INTEGER24");break;case ECT_INTEGER64:sprintf(hstr, "INTEGER64");break;case ECT_UNSIGNED8:sprintf(hstr, "UNSIGNED8");break;case ECT_UNSIGNED16:sprintf(hstr, "UNSIGNED16");break;case ECT_UNSIGNED32:sprintf(hstr, "UNSIGNED32");break;case ECT_UNSIGNED24:sprintf(hstr, "UNSIGNED24");break;case ECT_UNSIGNED64:sprintf(hstr, "UNSIGNED64");break;case ECT_REAL32:sprintf(hstr, "REAL32");break;case ECT_REAL64:sprintf(hstr, "REAL64");break;case ECT_BIT1:sprintf(hstr, "BIT1");break;case ECT_BIT2:sprintf(hstr, "BIT2");break;case ECT_BIT3:sprintf(hstr, "BIT3");break;case ECT_BIT4:sprintf(hstr, "BIT4");break;case ECT_BIT5:sprintf(hstr, "BIT5");break;case ECT_BIT6:sprintf(hstr, "BIT6");break;case ECT_BIT7:sprintf(hstr, "BIT7");break;case ECT_BIT8:sprintf(hstr, "BIT8");break;case ECT_VISIBLE_STRING:sprintf(hstr, "VISIBLE_STRING");break;case ECT_OCTET_STRING:sprintf(hstr, "OCTET_STRING");break;default:sprintf(hstr, "Type 0x%4.4X", dtype);}return hstr;
}char* SDO2string(uint16 slave, uint16 index, uint8 subidx, uint16 dtype)
{int l = sizeof(usdo) - 1, i;uint8 *u8;int8 *i8;uint16 *u16;int16 *i16;uint32 *u32;int32 *i32;uint64 *u64;int64 *i64;float *sr;double *dr;char es[32];memset(&usdo, 0, 128);ec_SDOread(slave, index, subidx, FALSE, &l, &usdo, EC_TIMEOUTRXM);if (EcatError){return ec_elist2string();}else{switch(dtype){case ECT_BOOLEAN:u8 = (uint8*) &usdo[0];if (*u8) sprintf(hstr, "TRUE");else sprintf(hstr, "FALSE");break;case ECT_INTEGER8:i8 = (int8*) &usdo[0];sprintf(hstr, "0x%2.2x %d", *i8, *i8);break;case ECT_INTEGER16:i16 = (int16*) &usdo[0];sprintf(hstr, "0x%4.4x %d", *i16, *i16);break;case ECT_INTEGER32:case ECT_INTEGER24:i32 = (int32*) &usdo[0];sprintf(hstr, "0x%8.8x %d", *i32, *i32);break;case ECT_INTEGER64:i64 = (int64*) &usdo[0];sprintf(hstr, "0x%16.16"PRIx64" %"PRId64, *i64, *i64);break;case ECT_UNSIGNED8:u8 = (uint8*) &usdo[0];sprintf(hstr, "0x%2.2x %u", *u8, *u8);break;case ECT_UNSIGNED16:u16 = (uint16*) &usdo[0];sprintf(hstr, "0x%4.4x %u", *u16, *u16);break;case ECT_UNSIGNED32:case ECT_UNSIGNED24:u32 = (uint32*) &usdo[0];sprintf(hstr, "0x%8.8x %u", *u32, *u32);break;case ECT_UNSIGNED64:u64 = (uint64*) &usdo[0];sprintf(hstr, "0x%16.16"PRIx64" %"PRIu64, *u64, *u64);break;case ECT_REAL32:sr = (float*) &usdo[0];sprintf(hstr, "%f", *sr);break;case ECT_REAL64:dr = (double*) &usdo[0];sprintf(hstr, "%f", *dr);break;case ECT_BIT1:case ECT_BIT2:case ECT_BIT3:case ECT_BIT4:case ECT_BIT5:case ECT_BIT6:case ECT_BIT7:case ECT_BIT8:u8 = (uint8*) &usdo[0];sprintf(hstr, "0x%x", *u8);break;case ECT_VISIBLE_STRING:strcpy(hstr, usdo);break;case ECT_OCTET_STRING:hstr[0] = 0x00;for (i = 0 ; i < l ; i++){sprintf(es, "0x%2.2x ", usdo[i]);strcat( hstr, es);}break;default:sprintf(hstr, "Unknown type");}return hstr;}
}/** Read PDO assign structure */
int si_PDOassign(uint16 slave, uint16 PDOassign, int mapoffset, int bitoffset)
{uint16 idxloop, nidx, subidxloop, rdat, idx, subidx;uint8 subcnt;int wkc, bsize = 0, rdl;int32 rdat2;uint8 bitlen, obj_subidx;uint16 obj_idx;int abs_offset, abs_bit;rdl = sizeof(rdat); rdat = 0;/* read PDO assign subindex 0 ( = number of PDO's) */wkc = ec_SDOread(slave, PDOassign, 0x00, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);rdat = etohs(rdat);/* positive result from slave ? */if ((wkc > 0) && (rdat > 0)){/* number of available sub indexes */nidx = rdat;bsize = 0;/* read all PDO's */for (idxloop = 1; idxloop <= nidx; idxloop++){rdl = sizeof(rdat); rdat = 0;/* read PDO assign */wkc = ec_SDOread(slave, PDOassign, (uint8)idxloop, FALSE, &rdl, &rdat, EC_TIMEOUTRXM);/* result is index of PDO */idx = etohs(rdat);if (idx > 0){rdl = sizeof(subcnt); subcnt = 0;/* read number of subindexes of PDO */wkc = ec_SDOread(slave,idx, 0x00, FALSE, &rdl, &subcnt, EC_TIMEOUTRXM);subidx = subcnt;/* for each subindex */for (subidxloop = 1; subidxloop <= subidx; subidxloop++){rdl = sizeof(rdat2); rdat2 = 0;/* read SDO that is mapped in PDO */wkc = ec_SDOread(slave, idx, (uint8)subidxloop, FALSE, &rdl, &rdat2, EC_TIMEOUTRXM);rdat2 = etohl(rdat2);/* extract bitlength of SDO */bitlen = LO_BYTE(rdat2);bsize += bitlen;obj_idx = (uint16)(rdat2 >> 16);obj_subidx = (uint8)((rdat2 >> 8) & 0x000000ff);abs_offset = mapoffset + (bitoffset / 8);abs_bit = bitoffset % 8;ODlist.Slave = slave;ODlist.Index[0] = obj_idx;OElist.Entries = 0;wkc = 0;/* read object entry from dictionary if not a filler (0x0000:0x00) */if(obj_idx || obj_subidx)wkc = ec_readOEsingle(0, obj_subidx, &ODlist, &OElist);printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);if((wkc > 0) && OElist.Entries){printf(" %-12s %s\n", dtype2string(OElist.DataType[obj_subidx]), OElist.Name[obj_subidx]);}elseprintf("\n");bitoffset += bitlen;};};};};/* return total found bitlength (PDO) */return bsize;
}int si_map_sdo(int slave)
{int wkc, rdl;int retVal = 0;uint8 nSM, iSM, tSM;int Tsize, outputs_bo, inputs_bo;uint8 SMt_bug_add;printf("PDO mapping according to CoE :\n");SMt_bug_add = 0;outputs_bo = 0;inputs_bo = 0;rdl = sizeof(nSM); nSM = 0;/* read SyncManager Communication Type object count */wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, 0x00, FALSE, &rdl, &nSM, EC_TIMEOUTRXM);/* positive result from slave ? */if ((wkc > 0) && (nSM > 2)){/* make nSM equal to number of defined SM */nSM--;/* limit to maximum number of SM defined, if true the slave can't be configured */if (nSM > EC_MAXSM)nSM = EC_MAXSM;/* iterate for every SM type defined */for (iSM = 2 ; iSM <= nSM ; iSM++){rdl = sizeof(tSM); tSM = 0;/* read SyncManager Communication Type */wkc = ec_SDOread(slave, ECT_SDO_SMCOMMTYPE, iSM + 1, FALSE, &rdl, &tSM, EC_TIMEOUTRXM);if (wkc > 0){if((iSM == 2) && (tSM == 2)) // SM2 has type 2 == mailbox out, this is a bug in the slave!{SMt_bug_add = 1; // try to correct, this works if the types are 0 1 2 3 and should be 1 2 3 4printf("Activated SM type workaround, possible incorrect mapping.\n");}if(tSM)tSM += SMt_bug_add; // only add if SMt > 0if (tSM == 3) // outputs{/* read the assign RXPDO */printf("  SM%1d outputs\n     addr b   index: sub bitl data_type    name\n", iSM);Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].outputs - (uint8 *)&IOmap[0]), outputs_bo );outputs_bo += Tsize;}if (tSM == 4) // inputs{/* read the assign TXPDO */printf("  SM%1d inputs\n     addr b   index: sub bitl data_type    name\n", iSM);Tsize = si_PDOassign(slave, ECT_SDO_PDOASSIGN + iSM, (int)(ec_slave[slave].inputs - (uint8 *)&IOmap[0]), inputs_bo );inputs_bo += Tsize;}}}}/* found some I/O bits ? */if ((outputs_bo > 0) || (inputs_bo > 0))retVal = 1;return retVal;
}int si_siiPDO(uint16 slave, uint8 t, int mapoffset, int bitoffset)
{uint16 a , w, c, e, er, Size;uint8 eectl;uint16 obj_idx;uint8 obj_subidx;uint8 obj_name;uint8 obj_datatype;uint8 bitlen;int totalsize;ec_eepromPDOt eepPDO;ec_eepromPDOt *PDO;int abs_offset, abs_bit;char str_name[EC_MAXNAME + 1];eectl = ec_slave[slave].eep_pdi;Size = 0;totalsize = 0;PDO = &eepPDO;PDO->nPDO = 0;PDO->Length = 0;PDO->Index[1] = 0;for (c = 0 ; c < EC_MAXSM ; c++) PDO->SMbitsize[c] = 0;if (t > 1)t = 1;PDO->Startpos = ec_siifind(slave, ECT_SII_PDO + t);if (PDO->Startpos > 0){a = PDO->Startpos;w = ec_siigetbyte(slave, a++);w += (ec_siigetbyte(slave, a++) << 8);PDO->Length = w;c = 1;/* traverse through all PDOs */do{PDO->nPDO++;PDO->Index[PDO->nPDO] = ec_siigetbyte(slave, a++);PDO->Index[PDO->nPDO] += (ec_siigetbyte(slave, a++) << 8);PDO->BitSize[PDO->nPDO] = 0;c++;/* number of entries in PDO */e = ec_siigetbyte(slave, a++);PDO->SyncM[PDO->nPDO] = ec_siigetbyte(slave, a++);a++;obj_name = ec_siigetbyte(slave, a++);a += 2;c += 2;if (PDO->SyncM[PDO->nPDO] < EC_MAXSM) /* active and in range SM? */{str_name[0] = 0;if(obj_name)ec_siistring(str_name, slave, obj_name);if (t)printf("  SM%1d RXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);elseprintf("  SM%1d TXPDO 0x%4.4X %s\n", PDO->SyncM[PDO->nPDO], PDO->Index[PDO->nPDO], str_name);printf("     addr b   index: sub bitl data_type    name\n");/* read all entries defined in PDO */for (er = 1; er <= e; er++){c += 4;obj_idx = ec_siigetbyte(slave, a++);obj_idx += (ec_siigetbyte(slave, a++) << 8);obj_subidx = ec_siigetbyte(slave, a++);obj_name = ec_siigetbyte(slave, a++);obj_datatype = ec_siigetbyte(slave, a++);bitlen = ec_siigetbyte(slave, a++);abs_offset = mapoffset + (bitoffset / 8);abs_bit = bitoffset % 8;PDO->BitSize[PDO->nPDO] += bitlen;a += 2;/* skip entry if filler (0x0000:0x00) */if(obj_idx || obj_subidx){str_name[0] = 0;if(obj_name)ec_siistring(str_name, slave, obj_name);printf("  [0x%4.4X.%1d] 0x%4.4X:0x%2.2X 0x%2.2X", abs_offset, abs_bit, obj_idx, obj_subidx, bitlen);printf(" %-12s %s\n", dtype2string(obj_datatype), str_name);}bitoffset += bitlen;totalsize += bitlen;}PDO->SMbitsize[ PDO->SyncM[PDO->nPDO] ] += PDO->BitSize[PDO->nPDO];Size += PDO->BitSize[PDO->nPDO];c++;}else /* PDO deactivated because SM is 0xff or > EC_MAXSM */{c += 4 * e;a += 8 * e;c++;}if (PDO->nPDO >= (EC_MAXEEPDO - 1)) c = PDO->Length; /* limit number of PDO entries in buffer */}while (c < PDO->Length);}if (eectl) ec_eeprom2pdi(slave); /* if eeprom control was previously pdi then restore */return totalsize;
}int si_map_sii(int slave)
{int retVal = 0;int Tsize, outputs_bo, inputs_bo;printf("PDO mapping according to SII :\n");outputs_bo = 0;inputs_bo = 0;/* read the assign RXPDOs */Tsize = si_siiPDO(slave, 1, (int)(ec_slave[slave].outputs - (uint8*)&IOmap), outputs_bo );outputs_bo += Tsize;/* read the assign TXPDOs */Tsize = si_siiPDO(slave, 0, (int)(ec_slave[slave].inputs - (uint8*)&IOmap), inputs_bo );inputs_bo += Tsize;/* found some I/O bits ? */if ((outputs_bo > 0) || (inputs_bo > 0))retVal = 1;return retVal;
}void si_sdo(int cnt)
{int i, j;ODlist.Entries = 0;memset(&ODlist, 0, sizeof(ODlist));if( ec_readODlist(cnt, &ODlist)){printf(" CoE Object Description found, %d entries.\n",ODlist.Entries);for( i = 0 ; i < ODlist.Entries ; i++){ec_readODdescription(i, &ODlist);while(EcatError) printf("%s", ec_elist2string());printf(" Index: %4.4x Datatype: %4.4x Objectcode: %2.2x Name: %s\n",ODlist.Index[i], ODlist.DataType[i], ODlist.ObjectCode[i], ODlist.Name[i]);memset(&OElist, 0, sizeof(OElist));ec_readOE(i, &ODlist, &OElist);while(EcatError) printf("%s", ec_elist2string());for( j = 0 ; j < ODlist.MaxSub[i]+1 ; j++){if ((OElist.DataType[j] > 0) && (OElist.BitLength[j] > 0)){printf("  Sub: %2.2x Datatype: %4.4x Bitlength: %4.4x Obj.access: %4.4x Name: %s\n",j, OElist.DataType[j], OElist.BitLength[j], OElist.ObjAccess[j], OElist.Name[j]);if ((OElist.ObjAccess[j] & 0x0007)){printf("          Value :%s\n", SDO2string(cnt, ODlist.Index[i], j, OElist.DataType[j]));}}}}}else{while(EcatError) printf("%s", ec_elist2string());}
}void slaveinfo(char *ifname)
{printSDO = TRUE;printMAP = TRUE;int cnt, i, j, nSM;uint16 ssigen;int expectedWKC;printf("Starting slaveinfo\n");/* initialise SOEM, bind socket to ifname */if (ec_init(ifname)){printf("ec_init on %s succeeded.\n",ifname);/* find and auto-config slaves */if ( ec_config_init(FALSE) > 0 ){printf("%d slaves found and configured.\n",ec_slavecount);ec_config_map(&IOmap);ec_configdc();while(EcatError) printf("%s", ec_elist2string());printf("%d slaves found and configured.\n",ec_slavecount);expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;printf("Calculated workcounter %d\n", expectedWKC);/* wait for all slaves to reach SAFE_OP state */ec_statecheck(0, EC_STATE_SAFE_OP,  EC_TIMEOUTSTATE * 3);if (ec_slave[0].state != EC_STATE_SAFE_OP ){printf("Not all slaves reached safe operational state.\n");ec_readstate();for(i = 1; i<=ec_slavecount ; i++){if(ec_slave[i].state != EC_STATE_SAFE_OP){printf("Slave %d State=%2x StatusCode=%4x : %s\n",i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));}}}ec_readstate();for( cnt = 1 ; cnt <= ec_slavecount ; cnt++){printf("\nSlave:%d\n Name:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d[ns]\n Has DC: %d\n",cnt, ec_slave[cnt].name, ec_slave[cnt].Obits, ec_slave[cnt].Ibits,ec_slave[cnt].state, ec_slave[cnt].pdelay, ec_slave[cnt].hasdc);if (ec_slave[cnt].hasdc) printf(" DCParentport:%d\n", ec_slave[cnt].parentport);printf(" Activeports:%d.%d.%d.%d\n", (ec_slave[cnt].activeports & 0x01) > 0 ,(ec_slave[cnt].activeports & 0x02) > 0 ,(ec_slave[cnt].activeports & 0x04) > 0 ,(ec_slave[cnt].activeports & 0x08) > 0 );printf(" Configured address: %4.4x\n", ec_slave[cnt].configadr);printf(" Man: %8.8x ID: %8.8x Rev: %8.8x\n", (int)ec_slave[cnt].eep_man, (int)ec_slave[cnt].eep_id, (int)ec_slave[cnt].eep_rev);for(nSM = 0 ; nSM < EC_MAXSM ; nSM++){if(ec_slave[cnt].SM[nSM].StartAddr > 0)printf(" SM%1d A:%4.4x L:%4d F:%8.8x Type:%d\n",nSM, etohs(ec_slave[cnt].SM[nSM].StartAddr), etohs(ec_slave[cnt].SM[nSM].SMlength),etohl(ec_slave[cnt].SM[nSM].SMflags), ec_slave[cnt].SMtype[nSM]);}for(j = 0 ; j < ec_slave[cnt].FMMUunused ; j++){printf(" FMMU%1d Ls:%8.8x Ll:%4d Lsb:%d Leb:%d Ps:%4.4x Psb:%d Ty:%2.2x Act:%2.2x\n", j,etohl(ec_slave[cnt].FMMU[j].LogStart), etohs(ec_slave[cnt].FMMU[j].LogLength), ec_slave[cnt].FMMU[j].LogStartbit,ec_slave[cnt].FMMU[j].LogEndbit, etohs(ec_slave[cnt].FMMU[j].PhysStart), ec_slave[cnt].FMMU[j].PhysStartBit,ec_slave[cnt].FMMU[j].FMMUtype, ec_slave[cnt].FMMU[j].FMMUactive);}printf(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n",ec_slave[cnt].FMMU0func, ec_slave[cnt].FMMU1func, ec_slave[cnt].FMMU2func, ec_slave[cnt].FMMU3func);printf(" MBX length wr: %d rd: %d MBX protocols : %2.2x\n", ec_slave[cnt].mbx_l, ec_slave[cnt].mbx_rl, ec_slave[cnt].mbx_proto);ssigen = ec_siifind(cnt, ECT_SII_GENERAL);/* SII general section */if (ssigen){ec_slave[cnt].CoEdetails = ec_siigetbyte(cnt, ssigen + 0x07);ec_slave[cnt].FoEdetails = ec_siigetbyte(cnt, ssigen + 0x08);ec_slave[cnt].EoEdetails = ec_siigetbyte(cnt, ssigen + 0x09);ec_slave[cnt].SoEdetails = ec_siigetbyte(cnt, ssigen + 0x0a);if((ec_siigetbyte(cnt, ssigen + 0x0d) & 0x02) > 0){ec_slave[cnt].blockLRW = 1;ec_slave[0].blockLRW++;}ec_slave[cnt].Ebuscurrent = ec_siigetbyte(cnt, ssigen + 0x0e);ec_slave[cnt].Ebuscurrent += ec_siigetbyte(cnt, ssigen + 0x0f) << 8;ec_slave[0].Ebuscurrent += ec_slave[cnt].Ebuscurrent;}printf(" CoE details: %2.2x FoE details: %2.2x EoE details: %2.2x SoE details: %2.2x\n",ec_slave[cnt].CoEdetails, ec_slave[cnt].FoEdetails, ec_slave[cnt].EoEdetails, ec_slave[cnt].SoEdetails);printf(" Ebus current: %d[mA]\n only LRD/LWR:%d\n",ec_slave[cnt].Ebuscurrent, ec_slave[cnt].blockLRW);if ((ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE) && printSDO)si_sdo(cnt);if(printMAP){if (ec_slave[cnt].mbx_proto & ECT_MBXPROT_COE)si_map_sdo(cnt);elsesi_map_sii(cnt);}}}else{printf("No slaves found!\n");}printf("End slaveinfo, close socket\n");/* stop SOEM, close socket */ec_close();}else{printf("No socket connection on %s\nExcecute as root\n",ifname);}
}

simpletest.c

#include "simpletest.h"
#include "ethercat.h"
#include <stdio.h>#define EC_TIMEOUTMON 500extern char IOmap[4096];
boolean needlf;
boolean inOP;
int wkc;
int expectedWKC;
uint8 currentgroup = 0;void simpletest(char *ifname)
{int i, j, oloop, iloop, chk;needlf = FALSE;inOP = FALSE;printf("Starting simple test\n");/* initialise SOEM, bind socket to ifname */if (ec_init(ifname)){printf("ec_init on %s succeeded.\n",ifname);/* find and auto-config slaves */if ( ec_config_init(FALSE) > 0 ){printf("%d slaves found and configured.\n",ec_slavecount);ec_config_map(&IOmap);ec_configdc();printf("Slaves mapped, state to SAFE_OP.\n");/* wait for all slaves to reach SAFE_OP state */ec_statecheck(0, EC_STATE_SAFE_OP,  EC_TIMEOUTSTATE * 4);oloop = ec_slave[0].Obytes;if ((oloop == 0) && (ec_slave[0].Obits > 0)) oloop = 1;if (oloop > 8) oloop = 8;iloop = ec_slave[0].Ibytes;if ((iloop == 0) && (ec_slave[0].Ibits > 0)) iloop = 1;if (iloop > 8) iloop = 8;printf("segments : %d : %d %d %d %d\n",ec_group[0].nsegments ,ec_group[0].IOsegment[0],ec_group[0].IOsegment[1],ec_group[0].IOsegment[2],ec_group[0].IOsegment[3]);printf("Request operational state for all slaves\n");expectedWKC = (ec_group[0].outputsWKC * 2) + ec_group[0].inputsWKC;printf("Calculated workcounter %d\n", expectedWKC);ec_slave[0].state = EC_STATE_OPERATIONAL;/* send one valid process data to make outputs in slaves happy*/ec_send_processdata();ec_receive_processdata(EC_TIMEOUTRET);/* request OP state for all slaves */ec_writestate(0);chk = 200;/* wait for all slaves to reach OP state */do{ec_send_processdata();ec_receive_processdata(EC_TIMEOUTRET);ec_statecheck(0, EC_STATE_OPERATIONAL, 50000);}while (chk-- && (ec_slave[0].state != EC_STATE_OPERATIONAL));if (ec_slave[0].state == EC_STATE_OPERATIONAL ){printf("Operational state reached for all slaves.\n");inOP = TRUE;/* cyclic loop */for(i = 1; i <= 1000; i++){ec_send_processdata();wkc = ec_receive_processdata(EC_TIMEOUTRET);if(wkc >= expectedWKC){printf("Processdata cycle %4d, WKC %d , O:", i, wkc);for(j = 0 ; j < oloop; j++){printf(" %2.2x", *(ec_slave[0].outputs + j));}printf(" I:");for(j = 0 ; j < iloop; j++){printf(" %2.2x", *(ec_slave[0].inputs + j));}printf(" T:%lld\n",ec_DCtime);needlf = TRUE;}osal_usleep(5000);}inOP = FALSE;}else{printf("Not all slaves reached operational state.\n");ec_readstate();for(i = 1; i<=ec_slavecount ; i++){if(ec_slave[i].state != EC_STATE_OPERATIONAL){printf("Slave %d State=0x%2.2x StatusCode=0x%4.4x : %s\n",i, ec_slave[i].state, ec_slave[i].ALstatuscode, ec_ALstatuscode2string(ec_slave[i].ALstatuscode));}}}printf("\nRequest init state for all slaves\n");ec_slave[0].state = EC_STATE_INIT;/* request INIT state for all slaves */ec_writestate(0);}else{printf("No slaves found!\n");}printf("End simple test, close socket\n");}else{printf("No socket connection on %s\nExcecute as root\n",ifname);}
}void ecatcheck(void)
{int slave;if( inOP && ((wkc < expectedWKC) || ec_group[currentgroup].docheckstate)){if (needlf){needlf = FALSE;printf("\n");}/* one ore more slaves are not responding */ec_group[currentgroup].docheckstate = FALSE;ec_readstate();for (slave = 1; slave <= ec_slavecount; slave++){if ((ec_slave[slave].group == currentgroup) && (ec_slave[slave].state != EC_STATE_OPERATIONAL)){ec_group[currentgroup].docheckstate = TRUE;if (ec_slave[slave].state == (EC_STATE_SAFE_OP + EC_STATE_ERROR)){printf("ERROR : slave %d is in SAFE_OP + ERROR, attempting ack.\n", slave);ec_slave[slave].state = (EC_STATE_SAFE_OP + EC_STATE_ACK);ec_writestate(slave);}else if(ec_slave[slave].state == EC_STATE_SAFE_OP){printf("WARNING : slave %d is in SAFE_OP, change to OPERATIONAL.\n", slave);ec_slave[slave].state = EC_STATE_OPERATIONAL;ec_writestate(slave);}else if(ec_slave[slave].state > EC_STATE_NONE){if (ec_reconfig_slave(slave, EC_TIMEOUTMON)){ec_slave[slave].islost = FALSE;printf("MESSAGE : slave %d reconfigured\n",slave);}}else if(!ec_slave[slave].islost){/* re-check state */ec_statecheck(slave, EC_STATE_OPERATIONAL, EC_TIMEOUTRET);if (ec_slave[slave].state == EC_STATE_NONE){ec_slave[slave].islost = TRUE;printf("ERROR : slave %d lost\n",slave);}}}if (ec_slave[slave].islost){if(ec_slave[slave].state == EC_STATE_NONE){if (ec_recover_slave(slave, EC_TIMEOUTMON)){ec_slave[slave].islost = FALSE;printf("MESSAGE : slave %d recovered\n",slave);}}else{ec_slave[slave].islost = FALSE;printf("MESSAGE : slave %d found\n",slave);}}}if(!ec_group[currentgroup].docheckstate)printf("OK : all slaves resumed OPERATIONAL.\n");}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/497653.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智慧地下采矿:可视化引领未来矿业管理

图扑智慧地下采矿可视化平台通过整合多源数据&#xff0c;提供实时 3D 矿井地图及分析&#xff0c;提升了矿产开采的安全性与效率&#xff0c;为矿业管理提供数据驱动的智能决策支持&#xff0c;推动行业数字化转型。

基于Docker+模拟器的Appium自动化测试(二)

模拟器的设置 打开“夜神模拟器”的系统设置&#xff0c;切换到“手机与网络”页&#xff0c;选中网络设置下的“开启网络连接”和“开启网络桥接模式”复选框&#xff0c;而后选择“静态IP”单选框&#xff0c;在IP地址中输入“192.168.0.105”&#xff0c;网关等内容不再赘述…

紫光同创-盘古200pro+开发板

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 一、开发系统介绍 开发系统概述 MES2L676-200HP 开发板采用紫光同创 logos2 系列 FPGA&#xff0c;型号&#xff1a;…

Rofin罗芬激光Principle and Advantages原理讲解PPT软件使用

Rofin罗芬激光Principle and Advantages原理讲解PPT软件使用

import org.springframework.data.jpa.repository.JpaRepository<T, ID>;

org.springframework.data.jpa.repository.JpaRepository<T, ID> 接口中的 ID 类型参数。 理解 JpaRepository<T, ID> 中的 T 和 ID&#xff1a; T (Type): T 代表的是你想要操作的 实体类 的类型。例如&#xff0c;如果你有一个名为 User 的实体类&#xff0c;那…

docker项目部署流程(Vue+Spingboot)

文章目录 1.docker安装(Ubuntu)1.卸载原有的docker引擎和旧版本软件包(第一次使用跳过)2.使用存储库安装apt 2.安装nginx并运行3.安装Mysql4.构建jdk镜像1.准备条件(3样东西)拉取ubuntu镜像DockerfileDockerfile简洁版 2.构建java镜像3.创建并运行java容器 5.网络配置1.自定义网…

《童年-高尔基》阅读笔记

《童年-高尔基》阅读笔记 2024-12-29日读完&#xff0c;在图书馆的书架上&#xff0c;大批的厚厚的外国文学书&#xff0c;只有这本薄薄的&#xff0c;我就拿下来看了一下&#xff0c;发现这本书就是初中就在语文课本中提到的自传体三部曲之一&#xff0c;其他两本是《在人间》…

fpga系列 HDL:ModelSim显示模拟波形以及十进制格式数值

FPGA中使用数字滤波器时&#xff0c;可通过观察模拟波形更好地查看滤波效果。可以通过ModelSim中的波形格式设置来实现更直观的波形显示。 右键波形->Format-> Analog 效果 不同的数值格式显示&#xff1a;右键波形->Radix-> Decimal 效果 示例代码 ver…

AI大模型语音识别转文字

提取音频 本项目作用在于将常见的会议录音文件、各种语种音频文件进行转录成相应的文字&#xff0c;也可从特定视频中提取对应音频进行转录程文字保存在本地。最原始的从所给网址下载对应视频和音频进行处理。下载ffmpeg(https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-…

《计算机组成及汇编语言原理》阅读笔记:p128-p132

《计算机组成及汇编语言原理》学习第 10 天&#xff0c;p128-p132 总结&#xff0c;总计 5 页。 一、技术总结 1.8088 organization and architecture 8088处理器是16位电脑&#xff0c;寄存器是16位&#xff0c;数据总线(data bus)是8位&#xff0c;地址总线是20位。 (1)g…

【ArcGIS Pro】完整的nc文件整理表格模型构建流程及工具练习数据分享

学术科研啥的要用到很多数据&#xff0c;nc文件融合了时间空间数据是科研重要文件。之前分享过怎样将nc文件处理成栅格后整理成表格。小编的读者还是有跑不通整个流程的&#xff0c;再来做一篇总结篇&#xff0c;也分享下练习数据跟工具&#xff0c;如果还是弄不了的&#xff0…

安装了python,环境变量也设置了,但是输入python不报错也没反应是为什么?window的锅!

目录 问题 结论总结 衍生问题 1 第1步&#xff1a;小白python安装&#xff0c;不要埋头一直点下一步&#xff01;&#xff01;&#xff01; 2 第2步&#xff1a;可以选择删了之前的&#xff0c;重新安装python 3 第3步&#xff1a;如果你不想或不能删了重装python&#…

图像处理-Ch7-快速小波变换和小波包

个人博客&#xff01;无广告观看&#xff0c;因为这节内容太多了&#xff0c;有点放不下&#xff0c;分了三节 文章目录 快速小波变换(The Fast Wavelet Transform)与两频段子带编译码系统的关系例&#xff1a;计算一维小波变换 一维快速小波反变换例&#xff1a;计算一维小波…

【从零开始】11. LLaMA-Factory 微调 Qwen 模型(番外篇)

书接上回&#xff0c;在完成了 RAGChecker 测试后&#xff0c;离 RAG 应用真正发布还差最后一步 - 基础信息指令微调。考虑到模型还是需要具备一定程度的“自我认知”&#xff0c;因此需要将公司信息“嵌入”到模型里面的。为此&#xff0c;我选择了 LLaMA-Factory&#xff08;…

小程序配置文件 —— 15 页面配置

页面配置 小程序的页面配置&#xff0c;也称为局部配置&#xff0c;每一个小程序页面也可以使用自己的 .json 文件来对页面的窗口表现进行配置&#xff1b; 需要注意的是&#xff1a;页面配置文件的属性和全局配置文件中的 window 属性几乎一致&#xff0c;只不过这里不需要额…

Linux高级--2.4.5 靠协议头保证传输的 MAC/IP/TCP/UDP---协议帧格式

任何网络协议&#xff0c;都必须要用包头里面设置写特殊字段来标识自己&#xff0c;传输越复杂&#xff0c;越稳定&#xff0c;越高性能的协议&#xff0c;包头越复杂。我们理解这些包头中每个字段的作用要站在它们解决什么问题的角度来理解。因为没人愿意让包头那么复杂。 本…

算法基础一:冒泡排序

一、冒泡排序 1、定义 冒泡排序&#xff08;英语&#xff1a;Bubble Sort&#xff09;是一种简单的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序&#xff08;如从大到小、首字母从A到Z&#xff09;错误就把他们交换过来。 …

Spring Cloud LoadBalancer (负载均衡)

目录 什么是负载均衡 服务端负载均衡 客户端负载均衡 Spring Cloud LoadBalancer快速上手 启动多个product-service实例 测试负载均衡 负载均衡策略 自定义负载均衡策略 什么是负载均衡 负载均衡(Load Balance&#xff0c;简称 LB) , 是高并发, 高可用系统必不可少的关…

OneNet平台2024版MQTT协议完整开发案例教程【MQTT数据流模式】

一、前言 此篇文章是以智慧路灯项目为例&#xff0c;完整的演示介绍 OneNet平台的开发。 OneNet平台 是2024年的新版本&#xff0c;采用数据流模版为例。 方便大家&#xff0c;腾讯云IOT 转 OneNet平台。 因为目前腾讯云IOT平台无法白嫖了&#xff0c;新用户已经无法免费使用…

一起学Git【第六节:查看版本差异】

git diff是 Git 版本控制系统中用于展示差异的强大工具。他可以用于查看文件在工作区、暂存区和版本库之间的差异、任意两个指定版本之间的差异和两个分支之间的差异等,接下来进行详细的介绍。 1.显示工作区与暂存区之间的差异 # 显示工作区和暂存区之间的差异,后面不加参数…