Browse Source

support for fixed packet length mode

Fabian Peter Hammerle 3 years ago
parent
commit
a104791ee7
5 changed files with 106 additions and 19 deletions
  1. 9 0
      CHANGELOG.md
  2. 71 19
      cc1101/__init__.py
  3. 10 0
      cc1101/options.py
  4. 16 0
      examples/transmit_fixed_length.py
  5. 0 0
      examples/transmit_variable_length.py

+ 9 - 0
CHANGELOG.md

@@ -5,6 +5,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Unreleased]
+### Added
+- support for fixed packet length mode
+  via new method `set_packet_length_mode(PacketLengthMode.FIXED)`
+- new enum `options.PacketLengthMode`
+- new method `get_packet_length_mode()`
+- method `get_packet_length()` is now public
+- new method `set_packet_length()`
+- added configured packet length to `CC1101`'s string representation
+  (`≤n` indicates variable length mode, `=n` fixed length mode)
 
 ## [1.1.0] - 2020-12-01
 ### Added

+ 71 - 19
cc1101/__init__.py

@@ -29,7 +29,7 @@ from cc1101.addresses import (
     StatusRegisterAddress,
     FIFORegisterAddress,
 )
-from cc1101.options import SyncMode, ModulationFormat
+from cc1101.options import PacketLengthMode, SyncMode, ModulationFormat
 
 
 _LOGGER = logging.getLogger(__name__)
@@ -385,16 +385,15 @@ class CC1101:
             "symbol_rate={:.2f}kBaud".format(self.get_symbol_rate_baud() / 1000),
             "modulation_format={}".format(self.get_modulation_format().name),
             "sync_mode={}".format(self.get_sync_mode().name),
+            "packet_length{}{}".format(
+                "≤"
+                if self.get_packet_length_mode() == PacketLengthMode.VARIABLE
+                else "=",
+                self.get_packet_length(),
+            ),
         )
         return "CC1101({})".format(", ".join(attrs))
 
-    def _get_packet_length(self) -> int:
-        """
-        packet length in fixed packet length mode,
-        maximum packet length in variable packet length mode.
-        """
-        return self._read_single_byte(ConfigurationRegisterAddress.PKTLEN)
-
     def get_configuration_register_values(
         self,
         start_register: ConfigurationRegisterAddress = min(
@@ -411,6 +410,30 @@ class CC1101:
             for i, v in enumerate(values)
         }
 
+    def get_packet_length(self) -> int:
+        """
+        PKTLEN
+
+        Packet length in fixed packet length mode,
+        maximum packet length in variable packet length mode.
+
+        > In variable packet length mode, [...]
+        > any packet received with a length byte
+        > with a value greater than PKTLEN will be discarded.
+        """
+        return self._read_single_byte(ConfigurationRegisterAddress.PKTLEN)
+
+    def set_packet_length(self, packet_length: int) -> None:
+        """
+        see get_packet_length()
+        """
+        assert 1 <= packet_length <= 255, "unsupported packet length {}".format(
+            packet_length
+        )
+        self._write_burst(
+            start_register=ConfigurationRegisterAddress.PKTLEN, values=[packet_length]
+        )
+
     def _disable_data_whitening(self):
         """
         PKTCTRL0.WHITE_DATA
@@ -456,6 +479,18 @@ class CC1101:
             start_register=ConfigurationRegisterAddress.PKTCTRL0, values=[pktctrl0]
         )
 
+    def get_packet_length_mode(self) -> PacketLengthMode:
+        pktctrl0 = self._read_single_byte(ConfigurationRegisterAddress.PKTCTRL0)
+        return PacketLengthMode(pktctrl0 & 0b11)
+
+    def set_packet_length_mode(self, mode: PacketLengthMode) -> None:
+        pktctrl0 = self._read_single_byte(ConfigurationRegisterAddress.PKTCTRL0)
+        pktctrl0 &= 0b11111100
+        pktctrl0 |= mode
+        self._write_burst(
+            start_register=ConfigurationRegisterAddress.PKTCTRL0, values=[pktctrl0]
+        )
+
     def _flush_tx_fifo_buffer(self) -> None:
         # > Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states.
         _LOGGER.debug("flushing tx fifo buffer")
@@ -463,7 +498,8 @@ class CC1101:
 
     def transmit(self, payload: bytes) -> None:
         """
-        > [...], the packet length is configured by the first byte [...].
+        > In variable packet length mode [.set/get_packet_length_mode()],
+        > the packet length is configured by the first byte [...].
         > The packet length is defined as the payload data,
         > excluding the length byte and the optional CRC.
         from "15.2 Packet Format"
@@ -473,9 +509,33 @@ class CC1101:
         # see "15.2 Packet Format"
         # > In variable packet length mode, [...]
         # > The first byte written to the TXFIFO must be different from 0.
-        if payload[0] == 0:
+        packet_length_mode = self.get_packet_length_mode()
+        packet_length = self.get_packet_length()
+        if packet_length_mode == PacketLengthMode.VARIABLE:
+            if not payload:
+                raise ValueError("empty payload {!r}".format(payload))
+            if payload[0] == 0:
+                raise ValueError(
+                    "in variable packet length mode the first byte of the payload must not be null"
+                    + "\npayload: {!r}".format(payload)
+                )
+            if len(payload) > packet_length:
+                raise ValueError(
+                    "payload exceeds maximum payload length of {} bytes".format(
+                        packet_length
+                    )
+                    + "\nsee .get_packet_length()"
+                    + "\npayload: {!r}".format(payload)
+                )
+        elif (
+            packet_length_mode == PacketLengthMode.FIXED
+            and len(payload) != packet_length
+        ):
             raise ValueError(
-                "in variable packet length mode the first byte of payload must not be null"
+                "expected payload length of {} bytes, got {}".format(
+                    packet_length, len(payload)
+                )
+                + "\nsee .set_packet_length_mode() and .get_packet_length()"
                 + "\npayload: {!r}".format(payload)
             )
         marcstate = self.get_main_radio_control_state_machine_state()
@@ -485,14 +545,6 @@ class CC1101:
                     marcstate.name
                 )
             )
-        max_packet_length = self._get_packet_length()
-        if len(payload) > max_packet_length:
-            raise ValueError(
-                "payload exceeds maximum payload length of {} bytes".format(
-                    max_packet_length
-                )
-                + "\npayload: {!r}".format(payload)
-            )
         self._flush_tx_fifo_buffer()
         self._write_burst(FIFORegisterAddress.TX, list(payload))
         _LOGGER.info(

+ 10 - 0
cc1101/options.py

@@ -18,6 +18,16 @@
 import enum
 
 
+class PacketLengthMode(enum.IntEnum):
+    """
+    PKTCTRL0.LENGTH_CONFIG
+    """
+
+    FIXED = 0b00
+    VARIABLE = 0b01
+    # INFINITE = 0b10
+
+
 class ModulationFormat(enum.IntEnum):
     """
     MDMCFG2.MOD_FORMAT

+ 16 - 0
examples/transmit_fixed_length.py

@@ -0,0 +1,16 @@
+import logging
+
+import cc1101
+
+
+logging.basicConfig(level=logging.INFO)
+
+with cc1101.CC1101() as transceiver:
+    transceiver.set_base_frequency_hertz(433.5e6)
+    transceiver.set_symbol_rate_baud(600)
+    transceiver.set_sync_mode(cc1101.SyncMode.NO_PREAMBLE_AND_SYNC_WORD)
+    transceiver.set_packet_length_mode(cc1101.PacketLengthMode.FIXED)
+    transceiver.set_packet_length(4)
+    transceiver.disable_checksum()
+    print(transceiver)
+    transceiver.transmit(b"\xff\x00\xaa\xff")

+ 0 - 0
examples/transmit.py → examples/transmit_variable_length.py