1. 读取并解析SFF-8472 EEPROM基础结构
任务说明
本案例目标为:通过I2C总线读取SFF-8472光模块EEPROM的A0h地址段(0x00~0x7F),解析其中的基础结构字段,包括标识符(Byte 0)、连接器类型(Byte 2)、收发器编码(Byte 3~10)、速率标识(Byte 13~14)以及长度等级(Byte 14~17),并以可读格式输出解析结果。代码将使用Linux用户态I2C设备驱动接口(/dev/i2c-N)实现,适用于带有SFP端口且已加载i2c-dev内核模块的嵌入式Linux平台。
硬件连接与I2C拓扑
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <string.h>
#define EEPROM_ADDR 0x50 /* 7位I2C地址,对应A0h/A1h */
#define EEPROM_SIZE 128 /* A0h段大小 */
#define I2C_DEV "/dev/i2c-0"
/* 读取A0h段全部128字节 */
static int read_eeprom(int fd, uint8_t *buf) {
/* 先写寄存器地址0x00 */
uint8_t reg = 0x00;
if (write(fd, ®, 1) != 1) {
perror("write reg");
return -1;
}
/* 连续读取128字节 */
if (read(fd, buf, EEPROM_SIZE) != EEPROM_SIZE) {
perror("read eeprom");
return -1;
}
return 0;
}
/* 解析并打印基础结构字段 */
static void parse_and_print(const uint8_t *buf) {
const char *id_str;
const char *conn_str;
/* Byte 0: 标识符 */
switch (buf[0]) {
case 0x00: id_str = "Unknown"; break;
case 0x01: id_str = "GBIC"; break;
case 0x02: id_str = "SFP/SFP+/SFP28"; break;
case 0x03: id_str = "XBI"; break;
case 0x04: id_str = "Xenpak"; break;
case 0x08: id_str = "XFP"; break;
case 0x0C: id_str = "QSFP"; break;
case 0x0D: id_str = "QSFP+"; break;
case 0x11: id_str = "QSFP28"; break;
default: id_str = "Reserved"; break;
}
/* Byte 2: 连接器类型 */
switch (buf[2]) {
case 0x00: conn_str = "Unknown"; break;
case 0x01: conn_str = "SC"; break;
case 0x02: conn_str = "FC Style 1"; break;
case 0x03: conn_str = "FC Style 2"; break;
case 0x04: conn_str = "BNC/TNC"; break;
case 0x05: conn_str = "FC Coax"; break;
case 0x06: conn_str = "FiberJack"; break;
case 0x07: conn_str = "LC"; break;
case 0x08: conn_str = "MT-RJ"; break;
case 0x09: conn_str = "MU"; break;
case 0x0A: conn_str = "SG"; break;
case 0x0B: conn_str = "Optical Pigtail"; break;
case 0x0C: conn_str = "MPO"; break;
default: conn_str = "Reserved"; break;
}
printf("=== SFF-8472 A0h 基础结构解析 ===\n");
printf("Byte 0 (标识符) : 0x%02X - %s\n", buf[0], id_str);
printf("Byte 2 (连接器类型) : 0x%02X - %s\n", buf[2], conn_str);
printf("Byte 3 (收发器编码[0]) : 0x%02X\n", buf[3]);
printf("Byte 4 (收发器编码[1]) : 0x%02X\n", buf[4]);
printf("Byte 5 (收发器编码[2]) : 0x%02X\n", buf[5]);
printf("Byte 6 (收发器编码[3]) : 0x%02X\n", buf[6]);
printf("Byte 7 (收发器编码[4]) : 0x%02X\n", buf[7]);
printf("Byte 8 (收发器编码[5]) : 0x%02X\n", buf[8]);
printf("Byte 9 (收发器编码[6]) : 0x%02X\n", buf[9]);
printf("Byte 10 (收发器编码[7]) : 0x%02X\n", buf[10]);
printf("Byte 13 (速率标识[0]) : 0x%02X\n", buf[13]);
printf("Byte 14 (速率标识[1]) : 0x%02X\n", buf[14]);
printf("Byte 14 (长度(SMF),km) : 0x%02X\n", buf[14]);
printf("Byte 15 (长度(OM2),m) : 0x%02X\n", buf[15]);
printf("Byte 16 (长度(OM1),m) : 0x%02X\n", buf[16]);
printf("Byte 17 (长度(铜缆),m) : 0x%02X\n", buf[17]);
}
int main(void) {
int fd;
uint8_t eeprom_data[EEPROM_SIZE];
fd = open(I2C_DEV, O_RDWR);
if (fd < 0) {
perror("open i2c dev");
return 1;
}
if (ioctl(fd, I2C_SLAVE, EEPROM_ADDR) < 0) {
perror("ioctl I2C_SLAVE");
close(fd);
return 1;
}
if (read_eeprom(fd, eeprom_data) < 0) {
close(fd);
return 1;
}
parse_and_print(eeprom_data);
close(fd);
return 0;
}
编译与运行
# 交叉编译(若在目标板上原生编译则直接gcc)
arm-linux-gnueabihf-gcc -o sfp_eeprom sfp_eeprom.c
# 在目标板上运行(需root权限访问I2C设备)
./sfp_eeprom
验证方法与判定标准
将SFP光模块插入笼子后运行程序,观察输出。判定通过的准则为:
- 程序正常退出且无I2C读写错误;
- Byte 0输出为
0x02且标识符显示为SFP/SFP+/SFP28(对于标准SFP模块); - Byte 2输出与模块实际连接器类型一致(如LC连接器输出
0x07 - LC); - Byte 3~10收发器编码与模块规格书标注一致(例如10G SR模块Byte 3为
0x10); - Byte 14~17长度字段与模块标称传输距离对应(如SR模块Byte 14为
0x00,Byte 15为0x64即100m OM2)。
若输出与上述预期不符,首先检查I2C总线号是否正确(可通过i2cdetect -l确认),其次确认模块是否插紧、笼子供电是否正常。