Python API
The AtPack Parser provides a comprehensive Python API for programmatic access to AtPack file contents.
Basic Usage
Importing the Library
from atpack_parser import AtPackParser
from atpack_parser.models import Device, Register, MemorySegment
Creating a Parser Instance
# Parse an AtPack file
parser = AtPackParser("path/to/atpack.atpack")
# Or use pathlib.Path
from pathlib import Path
parser = AtPackParser(Path("path/to/atpack.atpack"))
Getting Device Information
# List all devices in the AtPack
devices = parser.get_devices()
print(f"Found {len(devices)} devices")
# Get a specific device
device = parser.get_device("PIC16F877")
if device:
print(f"Device: {device.name}")
print(f"Family: {device.family}")
print(f"Architecture: {device.architecture}")
# Access memory segments instead of direct flash/ram/eeprom properties
for segment in device.memory_segments:
print(f"{segment.name}: {segment.size} bytes at 0x{segment.start:04X}")
Working with Device Data
Device Properties
The Device
model provides access to all device information:
device = parser.get_device("ATmega16")
# Basic information
print(f"Name: {device.name}")
print(f"Family: {device.family}")
print(f"Architecture: {device.architecture}")
print(f"Package: {device.package}")
# Memory information
print(f"Flash: {device.flash_size} bytes")
print(f"RAM: {device.ram_size} bytes")
print(f"EEPROM: {device.eeprom_size} bytes")
# Additional properties
print(f"Max frequency: {device.max_frequency} Hz")
print(f"Operating voltage: {device.voltage_min}V - {device.voltage_max}V")
print(f"Temperature range: {device.temp_min}°C - {device.temp_max}°C")
Memory Layout
# Get memory segments
memory_segments = parser.get_memory_layout("ATmega16")
for segment in memory_segments:
print(f"Segment: {segment.name}")
print(f" Start: 0x{segment.start_address:04X}")
print(f" Size: {segment.size} bytes")
print(f" Type: {segment.type}")
print(f" Access: {segment.access}")
Registers and Peripherals
# Get all registers for a device
registers = parser.get_device_registers("ATmega16")
# Filter by peripheral
usart_registers = [r for r in registers if r.peripheral == "USART"]
for register in usart_registers:
print(f"Register: {register.name}")
print(f" Address: 0x{register.address:04X}")
print(f" Size: {register.size} bytes")
print(f" Description: {register.description}")
# Access bit fields
for bitfield in register.bitfields:
print(f" Bit {bitfield.bit_range}: {bitfield.name}")
print(f" Description: {bitfield.description}")
Fuse Bits
# Get fuse information
fuses = parser.get_device_fuses("ATmega16")
for fuse in fuses:
print(f"Fuse: {fuse.name}")
print(f" Address: 0x{fuse.address:04X}")
print(f" Default: 0x{fuse.default_value:02X}")
# Fuse bit fields
for field in fuse.bitfields:
print(f" Bits {field.bit_range}: {field.name}")
print(f" Values: {field.values}")
Advanced Usage
Error Handling
from atpack_parser.exceptions import AtPackParseError, DeviceNotFoundError
try:
parser = AtPackParser("invalid.atpack")
except AtPackParseError as e:
print(f"Failed to parse AtPack: {e}")
try:
device = parser.get_device("NonExistentDevice")
except DeviceNotFoundError as e:
print(f"Device not found: {e}")
Working with Multiple AtPacks
# Parse multiple AtPack files
atmel_parser = AtPackParser("Atmel.ATmega_DFP.2.2.509.atpack")
pic_parser = AtPackParser("Microchip.PIC16Fxxx_DFP.1.7.162.atpack")
# Get all devices from both
all_devices = []
all_devices.extend(atmel_parser.get_devices())
all_devices.extend(pic_parser.get_devices())
print(f"Total devices: {len(all_devices)}")
Device Search and Filtering
# Search devices by name pattern
import re
devices = parser.get_devices()
# Find all ATmega devices
atmega_devices = [d for d in devices if d.name.startswith("ATmega")]
# Find devices with specific flash size
flash_16k_devices = [d for d in devices if d.flash_size == 16384]
# Find devices by regex pattern
pattern = re.compile(r"ATmega\d{2}A?$")
matched_devices = [d for d in devices if pattern.match(d.name)]
Data Export
import json
from pathlib import Path
# Export device data to JSON
devices = parser.get_devices()
device_data = [
{
"name": d.name,
"family": d.family,
"flash_size": d.flash_size,
"ram_size": d.ram_size,
}
for d in devices
]
with open("devices.json", "w") as f:
json.dump(device_data, f, indent=2)
# Export register definitions
device = parser.get_device("ATmega16")
registers = parser.get_device_registers("ATmega16")
register_data = [
{
"name": r.name,
"address": r.address,
"size": r.size,
"peripheral": r.peripheral,
"bitfields": [
{
"name": bf.name,
"bit_range": bf.bit_range,
"description": bf.description
}
for bf in r.bitfields
]
}
for r in registers
]
with open(f"{device.name}_registers.json", "w") as f:
json.dump(register_data, f, indent=2)
Custom Processing
# Create a device comparison report
def compare_devices(parser, device_names):
comparison = {}
for name in device_names:
device = parser.get_device(name)
if device:
comparison[name] = {
"flash": device.flash_size,
"ram": device.ram_size,
"eeprom": device.eeprom_size,
"max_freq": device.max_frequency,
"package": device.package
}
return comparison
# Compare ATmega devices
atmega_comparison = compare_devices(parser, ["ATmega16", "ATmega32", "ATmega64"])
for name, specs in atmega_comparison.items():
print(f"{name}: Flash={specs['flash']}, RAM={specs['ram']}")
Integration with Other Tools
# Generate PlatformIO board definitions
def generate_platformio_board(device):
board_config = {
"build": {
"mcu": device.name.lower(),
"f_cpu": device.max_frequency,
"core": "arduino"
},
"upload": {
"maximum_size": device.flash_size,
"maximum_ram_size": device.ram_size,
"protocol": "avrisp"
},
"name": device.name
}
return board_config
# Generate board configs for all devices
devices = parser.get_devices()
board_configs = {d.name.lower(): generate_platformio_board(d) for d in devices}
Performance Tips
Lazy Loading
The parser uses lazy loading to improve performance:
# This is fast - doesn't parse everything
parser = AtPackParser("large.atpack")
# This triggers parsing only when needed
devices = parser.get_devices() # Parses device list
registers = parser.get_device_registers("ATmega16") # Parses registers for this device
Caching Results
# Cache frequently accessed data
device_cache = {}
def get_cached_device(parser, name):
if name not in device_cache:
device_cache[name] = parser.get_device(name)
return device_cache[name]
Memory Management
# For processing many AtPacks, consider memory usage
import gc
atpack_files = ["file1.atpack", "file2.atpack", "file3.atpack"]
all_devices = []
for file in atpack_files:
parser = AtPackParser(file)
devices = parser.get_devices()
all_devices.extend(devices)
# Clean up parser to free memory
del parser
gc.collect()