Coverage for ccsds124/bitbuffer.py: 100%
40 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-29 15:01 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-06-29 15:01 +0000
1"""
2Variable-length bit buffer for building compressed output.
4This module provides a dynamically-growing bit buffer for constructing
5compressed output streams. Bits are appended sequentially using MSB-first
6ordering as required by CCSDS 124.0-B-1.
8Bit Ordering:
9Bits are appended MSB-first within each byte:
10- First bit appended goes to bit position 7
11- Second bit goes to position 6, etc.
13MicroPython compatible - no typing module imports.
14"""
16# Import for type hints only - works at runtime
17if False: # noqa: SIM108
18 from ccsds124.bitvector import BitVector
21class BitBuffer:
22 """Variable-length bit buffer for building compressed output."""
24 def __init__(self) -> None:
25 """Initialize an empty bit buffer."""
26 self._data = bytearray()
27 self.num_bits = 0
29 def clear(self) -> None:
30 """Clear the buffer."""
31 self._data = bytearray()
32 self.num_bits = 0
34 def append_bit(self, bit: int) -> None:
35 """
36 Append a single bit to the buffer.
38 Args:
39 bit: Bit value (0 or non-zero for 1)
40 """
41 byte_index = self.num_bits // 8
42 bit_index = self.num_bits % 8
44 # Extend buffer if needed
45 while byte_index >= len(self._data):
46 self._data.append(0)
48 # CCSDS uses MSB-first bit ordering: first bit goes to position 7
49 if bit:
50 self._data[byte_index] |= 1 << (7 - bit_index)
52 self.num_bits += 1
54 def append_bits(self, data: bytes, num_bits: int) -> None:
55 """
56 Append multiple bits from bytes.
58 Args:
59 data: Source bytes
60 num_bits: Number of bits to append (MSB-first)
61 """
62 for i in range(num_bits):
63 byte_index = i // 8
64 bit_index = i % 8
66 # Extract bits MSB-first (bit 7, 6, 5, ..., 0)
67 bit = (data[byte_index] >> (7 - bit_index)) & 1
68 self.append_bit(bit)
70 def append_bitvector(self, bv: "BitVector") -> None:
71 """
72 Append all bits from a BitVector.
74 Args:
75 bv: BitVector to append
76 """
77 # Calculate number of bytes from bit length
78 num_bytes = (bv.length + 7) // 8
80 # CCSDS MSB-first: bytes in order, bits within each byte from MSB to LSB
81 for byte_idx in range(num_bytes):
82 bits_in_this_byte = 8
84 # Last byte may have fewer than 8 bits
85 if byte_idx == num_bytes - 1:
86 remainder = bv.length % 8
87 if remainder != 0:
88 bits_in_this_byte = remainder
90 # With MSB-first bitvector indexing: bit 0 is MSB, bit 7 is LSB
91 # We want to append bits in order: MSB first, LSB last
92 start_bit = byte_idx * 8
93 for bit_offset in range(bits_in_this_byte):
94 pos = start_bit + bit_offset
95 bit = bv.get_bit(pos)
96 self.append_bit(bit)
98 def to_bytes(self) -> bytes:
99 """
100 Convert buffer contents to bytes.
102 Returns:
103 Bytes representation of the buffer
104 """
105 if self.num_bits == 0:
106 return b""
108 # Calculate number of bytes needed
109 num_bytes = (self.num_bits + 7) // 8
110 return bytes(self._data[:num_bytes])