4、读取光模块基本信息:厂商名称、PN号、SN号、版本号、日期代码的解析
各位好,我是老张。做光模块固件这么多年,我见过太多人在读取基本信息这一步翻车了。明明I2C通信没问题,读出来的厂商名却是乱码,或者SN号少了一位。今天咱们就把这块彻底讲透。
4.1 这些信息藏在哪?
光模块的EEPROM里,基本信息都放在固定的位置。说白了,这就是一份标准化的“身份证”。SFF-8472规范规定得很清楚,咱们直接看地址映射表:
| 参数 | 字节地址(十进制) | 长度(字节) | 编码格式 |
|---|---|---|---|
| 厂商名称 | 20 - 35 | 16 | ASCII |
| PN号(产品型号) | 40 - 55 | 16 | ASCII |
| SN号(序列号) | 68 - 83 | 16 | ASCII |
| 版本号 | 56 | 1 | 十六进制 |
| 日期代码 | 84 - 89 | 6 | ASCII(YYMMDD格式) |
嗯,这里要注意。厂商名称、PN号、SN号都是16字节的ASCII字符串。但实际生产中,很多厂商不会填满16个字节。空余的位置会用空格(0x20)或者0x00填充。我遇到过最坑的一次,某家厂商用0xFF填充,直接导致解析程序崩溃。
4.2 动手写解析代码
我个人习惯用Python写原型代码,调试起来快。下面这段代码,我在好几个项目里都直接复用:
import struct
def parse_basic_info(eeprom_data):
"""
解析光模块基本信息
:param eeprom_data: 从A0h地址读取的256字节数据
:return: 字典格式的基本信息
"""
info = {}
# 厂商名称:地址20-35,共16字节
vendor_name = eeprom_data[20:36].decode('ascii', errors='ignore').strip('\x00').strip()
info['vendor_name'] = vendor_name
# PN号:地址40-55,共16字节
part_number = eeprom_data[40:56].decode('ascii', errors='ignore').strip('\x00').strip()
info['part_number'] = part_number
# SN号:地址68-83,共16字节
serial_number = eeprom_data[68:84].decode('ascii', errors='ignore').strip('\x00').strip()
info['serial_number'] = serial_number
# 版本号:地址56,1字节
version = eeprom_data[56]
info['version'] = f"V{version}.0"
# 日期代码:地址84-89,6字节,格式YYMMDD
date_str = eeprom_data[84:90].decode('ascii', errors='ignore')
if len(date_str) == 6 and date_str.isdigit():
year = '20' + date_str[0:2]
month = date_str[2:4]
day = date_str[4:6]
info['date_code'] = f"{year}-{month}-{day}"
else:
info['date_code'] = date_str # 原始字符串
return info
# 使用示例
if __name__ == "__main__":
# 模拟从模块读取的256字节数据
raw_data = bytearray(256)
# 填充一些测试数据
raw_data[20:36] = b'FINISAR CORP. '
raw_data[40:56] = b'FTLF8519P3BNL '
raw_data[68:84] = b'ABC12345678901 '
raw_data[56] = 0x01
raw_data[84:90] = b'240315'
result = parse_basic_info(raw_data)
for key, value in result.items():
print(f"{key}: {value}")
核心要点:
- 一定要用
errors='ignore'处理非ASCII字符,否则遇到非法字节会抛异常 - 先去除0x00填充,再去除首尾空格,顺序不能乱
- 版本号通常只占1字节,但有些厂商会扩展成2字节,需要额外判断
4.3 避坑指南:那些年我踩过的雷
我曾经在一个批量测试项目中,发现同一批模块的SN号解析出来总是少一位。排查了半天,原来是厂商在SN号末尾用了0x00填充,而我的strip('\x00')把有效字符也截断了。后来我改成先strip空格,再strip 0x00,问题解决。
还有一次,某个模块的日期代码读出来是"2402A0"。你想想看,这明显不是标准格式。后来查资料才知道,有些厂商在日期代码里混入了生产批次字母。我的建议是:先校验格式,不符合标准就返回原始字符串,别强行解析。
特别注意:
- 日期代码的世纪位:YY是两位年份,2000年后的模块,20要自己补上
- 版本号0x00表示初始版本,0xFF表示未定义,这两种情况要特殊处理
- PN号和SN号中可能出现连字符、斜杠等特殊字符,不要过滤掉
4.4 知识体系梳理
为了让大家更直观地理解整个解析流程,我画了一张图:
实战小技巧:
我在产线测试时,会把解析出来的信息直接和标签上的印刷内容做比对。如果发现不一致,十有八九是EEPROM写入时出了问题。另外,建议在固件里加一个校验函数,定期检查这些基本信息是否被意外篡改。
好了,关于基本信息的解析就讲到这里。其实核心就三点:地址要对、清洗要全、格式要准。把这三点记住,不管遇到什么厂商的模块,你都能轻松搞定。