Skip to main content

pygbl

A parser for the EBL and GBL (v3 and v4) firmware image formats used by the Silicon Labs Gecko bootloader.

Images are parsed into structured tags and round-trip byte-for-byte, with anything following the end tag handed back separately rather than folded into the image.

Installation

pip install pygbl

The base install is pure Python and covers parsing, serializing, building images from ELFs, and LZMA. Signing, encryption and LZ4 need optional dependencies:

pip install pygbl[crypto]  # signing and encryption
pip install pygbl[lz4]     # LZ4 compression
pip install pygbl[all]

Calling those features without their dependency raises MissingDependencyError.

Usage

Parse an image and inspect its tags:

import pathlib

from pygbl import GBL3ApplicationInfo, parse_firmware_image

data = pathlib.Path("ncp-uart-hw.gbl").read_bytes()
image = parse_firmware_image(data)

for tag in image.tags:
    print(tag)

print(image.get_first_tag(GBL3ApplicationInfo).version)
print(image.get_metadata())  # opaque bytes, the schema is vendor defined

serialize pads up to a word boundary, as commander does. parse_firmware_image discards anything after the end tag; deserialize hands it back:

image, trailing = GBL3Image.deserialize(data)

assert image.serialize(block_size=1) + trailing == data

Modify an image. Tags are frozen dataclasses, so dataclasses.replace works, and regenerate_crc fixes up the end tag afterwards:

import dataclasses

from pygbl import GBL3End, GBL3Metadata

modified = dataclasses.replace(
    image,
    tags=[t for t in image.tags if not isinstance(t, GBL3End)]
    + [GBL3Metadata(metadata=b'{"fw_type": "zigbee_ncp"}')],
).regenerate_crc()

Compress, encrypt and sign, in the order the bootloader expects:

from cryptography.hazmat.primitives.serialization import load_pem_private_key

from pygbl import GBL3Compression

private_key = load_pem_private_key(
    pathlib.Path("vendor_sign.key").read_bytes(), password=None
)
key = bytes.fromhex("7F8FE53979B31BC556FCB131AFF42414")

sealed = image.compress(GBL3Compression.LZMA).encrypt(key).sign(private_key)
pathlib.Path("signed.gbl").write_bytes(sealed.serialize())

The bootloader decompresses into fixed buffers, so compress uses the only LZMA parameters it can accept. Overriding them past what it can allocate raises ValueError.

And unwrap it again:

assert sealed.verify_signature(private_key.public_key())
assert sealed.decrypt(key).decompress().serialize() == image.serialize()

Building images from an ELF

Images can be built straight from a linked ELF, without commander. Program data comes from the loadable segments (keyed by physical address, since initialized data is stored in flash but linked at its RAM address) and the application info tag is read from the SDK's application_properties_t struct:

from pygbl import build_application_gbl3, build_bootloader_gbl3

with open("zigbee_ncp.out", "rb") as f:
    image = build_application_gbl3(f, metadata=b'{"fw_type": "zigbee_ncp"}')

with open("bootloader.out", "rb") as f:
    bootloader = build_bootloader_gbl3(f)

GBLv4

Series 3 parts use GBLv4, a different format that nests tags inside a signed manifest and can bundle several updates in one file.

from pygbl import GBL4Image, GBL4MemorySectionInfo, GBL4UpdateMemorySection

data = pathlib.Path("light-simg301.gbl4").read_bytes()
image, trailing = GBL4Image.deserialize(data)

assert image.serialize() + trailing == data

# `get_tags` searches the whole tree, at any depth
for update in image.get_tags(GBL4UpdateMemorySection):
    print(f"{update.target_address:#010x} {update.plain_image_size} bytes")

for info in image.get_tags(GBL4MemorySectionInfo):
    print(info.compression_scheme, info.encryption_scheme, info.nonce.hex())

Reading and writing are supported; building a v4 image from an ELF is not, the ELF helpers are GBLv3 only.

EBL

EBL images, used by older EM3xx parts, work the same way:

from pygbl import EBLEraseProgram, parse_firmware_image

image = parse_firmware_image(pathlib.Path("ncp-uart-sw.ebl").read_bytes())

for tag in image.get_tags(EBLEraseProgram):
    print(f"{tag.address:#010x} {len(tag.data)} bytes")

Bootloader and application images

A GBL can contain a bootloader, an application, or both. Combined images can be split apart and recombined, which is useful because some bootloaders cannot flash a combined image in one pass:

bootloader, application = combined.split_bootloader_app()
recombined = application.combine_bootloader_app(bootloader)

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pygbl-1.1.0.tar.gz (8.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pygbl-1.1.0-py3-none-any.whl (29.7 kB view details)

Uploaded Python 3

File details

Details for the file pygbl-1.1.0.tar.gz.

File metadata

  • Download URL: pygbl-1.1.0.tar.gz
  • Upload date:
  • Size: 8.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pygbl-1.1.0.tar.gz
Algorithm Hash digest
SHA256 83cee49e964264281902a3bc134d81fbad5bf295d275e580319328c9af60fadc
MD5 46cbd9a32959ccf971a9e91ccb8998bc
BLAKE2b-256 d0a73627bb98b916f2f151656929aba524a2ab91bc7ece96281e8f7876da4df8

See more details on using hashes here.

Provenance

The following attestation bundles were made for pygbl-1.1.0.tar.gz:

Publisher: publish-to-pypi.yml on zigpy/pygbl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pygbl-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: pygbl-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 29.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pygbl-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 629e5625518c044ab10716dddcc6b6972aa5f83ffb8ad6fd7e42a2f4cf3e7b3c
MD5 e3030b538a8e0e71b5bf79306e5a4f47
BLAKE2b-256 efe97df6628852fdf18a66507daa71cf7f771a718338c3eff99a446423b3dfd3

See more details on using hashes here.

Provenance

The following attestation bundles were made for pygbl-1.1.0-py3-none-any.whl:

Publisher: publish-to-pypi.yml on zigpy/pygbl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page