From 528d734dd049a7fea49dd88f6bb50d1d04a08a74 Mon Sep 17 00:00:00 2001 From: wormuz Date: Tue, 18 Aug 2026 03:47:12 +0300 Subject: [PATCH] Update format enum for libbladeRF 2.6.0 and fix bytes-per-sample libbladeRF 2.6.0 inserted BLADERF_FORMAT_SC16_Q11_PACKED right after BLADERF_FORMAT_SC16_Q11, shifting every value after it. Since the .pxd declares the enum without explicit values, Cython numbers it positionally and PYBLADERF_FORMAT_SC16_Q11_META silently became 1 - which is now SC16_Q11_PACKED, a format without metadata. The failure is silent: bladerf_sync_config() accepts the value, sync_rx() returns samples, and only the metadata timestamps give it away by never advancing. Verified on a bladeRF 2.0 micro xA4 (FX3 2.6.0, FPGA 0.16.0): format 1 (PACKED) ac=32768, ts stuck at 133592988592904 format 2 (META) ac=32768, ts=[61, 32829, 65597], step exactly 32768 Also adds the missing BLADERF_IMAGE_TYPE_GAIN_CAL, and exposes SC16_Q11_PACKED and PACKET_META. Separately, bytes_per_sample treated every format except SC16_Q11 as 2 bytes, which is wrong for SC16_Q11_META: it carries 16-bit I and Q like SC16_Q11. Only the SC8_Q7 formats are 2 bytes. --- python_bladerf/pylibbladerf/cbladerf.pxd | 2 ++ python_bladerf/pylibbladerf/pybladerf.pyx | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/python_bladerf/pylibbladerf/cbladerf.pxd b/python_bladerf/pylibbladerf/cbladerf.pxd index bf8cc0b..68fb871 100644 --- a/python_bladerf/pylibbladerf/cbladerf.pxd +++ b/python_bladerf/pylibbladerf/cbladerf.pxd @@ -326,6 +326,7 @@ cdef extern from 'libbladeRF.h' nogil: ctypedef enum bladerf_format: BLADERF_FORMAT_SC16_Q11 + BLADERF_FORMAT_SC16_Q11_PACKED BLADERF_FORMAT_SC16_Q11_META BLADERF_FORMAT_PACKET_META BLADERF_FORMAT_SC8_Q7 @@ -402,6 +403,7 @@ cdef extern from 'libbladeRF.h' nogil: BLADERF_IMAGE_TYPE_RX_IQ_CAL BLADERF_IMAGE_TYPE_TX_IQ_CAL BLADERF_IMAGE_TYPE_FPGA_A5 + BLADERF_IMAGE_TYPE_GAIN_CAL const int BLADERF_IMAGE_MAGIC_LEN diff --git a/python_bladerf/pylibbladerf/pybladerf.pyx b/python_bladerf/pylibbladerf/pybladerf.pyx index e815966..850be1d 100644 --- a/python_bladerf/pylibbladerf/pybladerf.pyx +++ b/python_bladerf/pylibbladerf/pybladerf.pyx @@ -316,7 +316,9 @@ class pybladerf_correction(IntEnum): class pybladerf_format(IntEnum): PYBLADERF_FORMAT_SC16_Q11 = cbladerf.BLADERF_FORMAT_SC16_Q11 + PYBLADERF_FORMAT_SC16_Q11_PACKED = cbladerf.BLADERF_FORMAT_SC16_Q11_PACKED PYBLADERF_FORMAT_SC16_Q11_META = cbladerf.BLADERF_FORMAT_SC16_Q11_META + PYBLADERF_FORMAT_PACKET_META = cbladerf.BLADERF_FORMAT_PACKET_META PYBLADERF_FORMAT_SC8_Q7 = cbladerf.BLADERF_FORMAT_SC8_Q7 PYBLADERF_FORMAT_SC8_Q7_META = cbladerf.BLADERF_FORMAT_SC8_Q7_META @@ -1709,7 +1711,12 @@ cdef class PyBladerfDevice: cdef void **buffers cdef int result = -1 - async_data.bytes_per_sample = 4 if data_format == pybladerf_format.PYBLADERF_FORMAT_SC16_Q11 else 2 + # SC16_Q11 and SC16_Q11_META carry 16-bit I and Q, so 4 bytes per + # sample; the SC8_Q7 formats carry 8-bit I and Q, so 2 bytes. + async_data.bytes_per_sample = 2 if data_format in ( + pybladerf_format.PYBLADERF_FORMAT_SC8_Q7, + pybladerf_format.PYBLADERF_FORMAT_SC8_Q7_META, + ) else 4 async_data.package_size = USB_PACKAGE_SIZE_SS if self.pybladerf_device_speed() == pybladerf_dev_speed.PYBLADERF_DEVICE_SPEED_SUPER else USB_PACKAGE_SIZE_HS async_data.packages_per_buffer = samples_per_buffer // (async_data.package_size // async_data.bytes_per_sample) async_data.samples_per_package = (samples_per_buffer - PYMETADATA_HEADER_SIZE) // async_data.bytes_per_sample @@ -1737,7 +1744,12 @@ cdef class PyBladerfDevice: cdef void **buffers cdef int result = -1 - async_data.bytes_per_sample = 4 if data_format == pybladerf_format.PYBLADERF_FORMAT_SC16_Q11 else 2 + # SC16_Q11 and SC16_Q11_META carry 16-bit I and Q, so 4 bytes per + # sample; the SC8_Q7 formats carry 8-bit I and Q, so 2 bytes. + async_data.bytes_per_sample = 2 if data_format in ( + pybladerf_format.PYBLADERF_FORMAT_SC8_Q7, + pybladerf_format.PYBLADERF_FORMAT_SC8_Q7_META, + ) else 4 async_data.package_size = USB_PACKAGE_SIZE_SS if self.pybladerf_device_speed() == pybladerf_dev_speed.PYBLADERF_DEVICE_SPEED_SUPER else USB_PACKAGE_SIZE_HS async_data.packages_per_buffer = samples_per_buffer // (async_data.package_size // async_data.bytes_per_sample) async_data.samples_per_package = (samples_per_buffer - PYMETADATA_HEADER_SIZE) // async_data.bytes_per_sample