Python提取Srec或Hex文件数据

1. 解析Srec文件

"""
Parse the SRecord file and return all contiguous data blocks and header record

argument:
    - srec_file_path: path of srecord file to parse

return:
    - title_infor: contains any title information
    - data_blocks: list,Each element is a dictionary,contains 'address' and 'data'
"""
def parse_srec_fragments(srec_file_path):

    with open(srec_file_path, 'r') as f:
        lines = f.readlines()
        f.close()
    
    title_infor = None
    data_blocks = []          # storage all data blocks [{address: int, data: bytes}, ...]
    
    current_address = 0x00000000
    next_address = None
    
    for line in lines:
        line = line.strip()
        if not line.startswith('S'):
            continue
        if len(line) & 1 == 1:
            raise ValueError(f"Invalid line, length error: {line}")
            
        # Extract fields
        record_type = int(line[1:2], 16)
        byte_count = int(line[2:4], 16)
        checksum = int(line[-2:], 16)
        address = None
        data_bytes = None
        
        # Verify length
        if len(line) != 4 + byte_count*2:
            raise ValueError(f"Invalid line, length error: {line}")
            
        # Verify checksum
        computed_sum = sum(bytes.fromhex(line[2:-2])) & 0xFF
        computed_checksum = 0xff - computed_sum
        if checksum != computed_checksum:
            raise ValueError(f"checksum error: {line}")
            
        # Process record type
        if record_type == 0x00:         # S0: Header Record
            if len(line) < 10:
                raise ValueError(f"Invalid line, length error: {line}")
            title_infor = line[8:-2]
            
        elif (record_type == 0x01 or    # S1: Data Record, 16-bit address
              record_type == 0x02 or    # S2: Data Record, 24-bit address
              record_type == 0x03):     # S3: Data Record, 32-bit address
            
            address = int(line[4:6+record_type*2], 16)
            data_bytes = bytes.fromhex(line[6+record_type*2:-2])
            current_address = address
            
            if current_address == next_address:
                # Merge continuous address data together
                temp = bytearray(data_blocks[-1]['data'])
                temp.extend(data_bytes)
                data_blocks[-1]['data'] =  bytes(temp)
            else:
                # Start a new block
                data_blocks.append({
                    'address': current_address,
                    'data': data_bytes
                })
                
            next_address = current_address + byte_count - record_type - 1 - 1

        elif (record_type == 0x04):     # S4: Resverd
            break
            
        elif (record_type == 0x05):     # S5: Count Record, 16-bit counter
            if record_type + byte_count != 8:
                raise ValueError(f"Invalid line, length error: {line}")
                
        elif (record_type == 0x06):     # S6: Count Record, 24-bit counter            
            if record_type + byte_count != 10:
                raise ValueError(f"Invalid line, length error: {line}")            
            
        elif (record_type == 0x07 or    # S7: Termination Record, 16-bit address
              record_type == 0x08 or    # S8: Termination Record, 24-bit address
              record_type == 0x09):     # S9: Termination Record, 32-bit address
            
            if record_type + byte_count != 12:
                raise ValueError(f"Invalid line, length error: {line}")
            
        else:
            raise TypeError(f"Invalid record type!!!")
            
    if len(data_blocks) != 0:
        print(f"Header Record: 0x{title_infor}")
        for idx, block in enumerate(data_blocks):
            print(f"Block {idx + 1}:")
            print(f"  Starts at: 0x{block['address']:08X}")
            print(f"  Length   : 0x{len(block['data']):0X}")
            # print(f"  Data     : {block['data'].hex().upper()}")
    else:
        print("No valid data records found in SRecord files!")
        
    return title_infor, data_blocks

2. 解析Hex文件

"""
Parse the HEX file and return all contiguous data blocks

argument:
    - hex_file_path: path of hex file to parse

return:
    - data_blocks: list,Each element is a dictionary,contains 'address' and 'data'
"""
def parse_hex_fragments(hex_file_path):

    with open(hex_file_path, 'r') as f:
        lines = f.readlines()
        f.close()
    
    data_blocks = []          # storage all data blocks [{address: int, data: bytes}, ...]
    upper_address = 0x0000    # Extended linear address (Type 04)
    current_segment = 0x0000  # Extended segment address (Type 02)
    next_address = None
    
    for line in lines:
        line = line.strip()
        if not line.startswith(':'):
            continue
        if len(line) < 11 or len(line) & 1 == 0:
            raise ValueError(f"Invalid line, length error: {line}")
        
        # Extract fields
        byte_count = int(line[1:3], 16)
        address = int(line[3:7], 16)
        record_type = int(line[7:9], 16)
        data_bytes = bytes.fromhex(line[9:-2])
        checksum = int(line[-2:], 16)
        
        if len(line) != 11 + byte_count*2:
            raise ValueError(f"Invalid line, length error: {line}")
        
        # Verify checksum
        computed_sum = sum(bytes.fromhex(line[1:-2])) & 0xFF
        computed_checksum = (0x100 - computed_sum) & 0xFF
        if checksum != computed_checksum:
            raise ValueError(f"checksum error: {line}")
        
        # Process record type
        if record_type == 0x00:  # Data record
            # Calculate full addresses (support segment addresses and linear addresses)
            if upper_address != 0x0000:
                full_address = (upper_address << 16) + address
            else:
                full_address = (current_segment << 4) + address
            
            if full_address == next_address:
                # Merge continuous address data together
                temp = bytearray(data_blocks[-1]['data'])
                temp.extend(data_bytes)
                data_blocks[-1]['data'] =  bytes(temp)
            else:
                # Start a new block
                data_blocks.append({
                    'address': full_address,
                    'data': data_bytes
                })
                
            next_address = full_address + byte_count
        
        elif record_type == 0x02:  # Extended segment address record
            current_segment = int.from_bytes(data_bytes, byteorder='big')
        
        elif record_type == 0x04:  # Extended linear address record
            upper_address = int.from_bytes(data_bytes, byteorder='big')
        
        elif record_type == 0x01:  # File end record
            break
    
    if len(data_blocks) != 0:
        for idx, block in enumerate(data_blocks):
            print(f"Block {idx + 1}:")
            print(f"  Starts at: 0x{block['address']:08X}")
            print(f"  Length   : 0x{len(block['data']):0X}")
            # print(f"  Data     : {block['data'].hex().upper()}")
    else:
        print("No valid data records found in HEX files!")
        
    return data_blocks

posted @ 2025-08-13 16:41  决云  阅读(16)  评论(0)    收藏  举报