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 知识体系梳理

为了让大家更直观地理解整个解析流程,我画了一张图:

光模块基本信息解析流程 Step 1: 读取EEPROM Step 2: 按地址分段提取 厂商名(20-35) | PN号(40-55) | SN号(68-83) 版本号(56) | 日期代码(84-89) Step 3: 数据清洗 去除0x00/0xFF填充 → 去除首尾空格 Step 4: 格式化输出 版本号→Vx.0 | 日期代码→YYYY-MM-DD ⚠️ 常见陷阱 • 填充字符不统一 • 日期格式不规范 • 版本号扩展字节 • 特殊字符未处理 • 世纪位缺失 • 非法ASCII字节

实战小技巧:

我在产线测试时,会把解析出来的信息直接和标签上的印刷内容做比对。如果发现不一致,十有八九是EEPROM写入时出了问题。另外,建议在固件里加一个校验函数,定期检查这些基本信息是否被意外篡改。

好了,关于基本信息的解析就讲到这里。其实核心就三点:地址要对、清洗要全、格式要准。把这三点记住,不管遇到什么厂商的模块,你都能轻松搞定。

专注资料整理