pamoja.mesh

Idiomatic mesh-framing facade.

When the fixed infrastructure is gone or was never there, devices carry each other's traffic: every node relays what it hears, so a message crosses an area no single node can reach. This is the packet half of that, addressing and integrity over radios that give you neither.

  1"""Idiomatic mesh-framing facade.
  2
  3When the fixed infrastructure is gone or was never there, devices carry each
  4other's traffic: every node relays what it hears, so a message crosses an area no
  5single node can reach. This is the packet half of that, addressing and integrity
  6over radios that give you neither.
  7"""
  8
  9from __future__ import annotations
 10
 11from pamoja._native import MeshFrame, SeenPackets
 12from pamoja._native import mesh_broadcast_frame as _broadcast_frame
 13from pamoja._native import mesh_crc16 as _crc16
 14from pamoja._native import mesh_frame as _frame
 15from pamoja._native import mesh_limits as _limits
 16from pamoja._native import mesh_parse_frame as _parse_frame
 17from pamoja._native import mesh_relayed as _relayed
 18
 19__all__ = [
 20    "BROADCAST",
 21    "DEFAULT_HOP_LIMIT",
 22    "MAX_FRAME",
 23    "MAX_PAYLOAD",
 24    "HEADER_LEN",
 25    "SEEN_DEFAULT_CAPACITY",
 26    "MeshFrame",
 27    "SeenPackets",
 28    "broadcast",
 29    "crc16",
 30    "frame",
 31    "parse",
 32    "relayed",
 33]
 34
 35_MAX_FRAME, _MAX_PAYLOAD, _BROADCAST, _HOP_LIMIT, _SEEN, _HEADER = _limits()
 36
 37#: How many bytes of a frame are header, so where its payload starts.
 38HEADER_LEN = _HEADER
 39#: The largest frame, in bytes, including its header and checksum.
 40MAX_FRAME = _MAX_FRAME
 41#: The largest payload a single frame can carry, in bytes.
 42MAX_PAYLOAD = _MAX_PAYLOAD
 43#: The destination address that means every node.
 44BROADCAST = _BROADCAST
 45#: The hop limit a frame starts with unless one is given.
 46DEFAULT_HOP_LIMIT = _HOP_LIMIT
 47#: A duplicate-cache size for a caller with no reason to choose one.
 48SEEN_DEFAULT_CAPACITY = _SEEN
 49
 50
 51def frame(
 52    src: int,
 53    dst: int,
 54    id: int,
 55    payload: bytes,
 56    hop_limit: int | None = None,
 57) -> MeshFrame:
 58    """Build a frame addressed to one node.
 59
 60    :param src: The address of this node.
 61    :param dst: The address the frame is for, or :data:`BROADCAST`.
 62    :param id: The sequence number identifying this packet from this source.
 63    :param payload: The bytes to carry.
 64    :param hop_limit: How many relays the frame may take, defaulting to
 65        :data:`DEFAULT_HOP_LIMIT`.
 66    :returns: The frame, with the bytes to transmit on its ``bytes`` attribute.
 67    :raises PamojaError: If the payload is larger than :data:`MAX_PAYLOAD`.
 68    """
 69    return _frame(src, dst, id, bytes(payload), hop_limit)
 70
 71
 72def broadcast(
 73    src: int, id: int, payload: bytes, hop_limit: int | None = None
 74) -> MeshFrame:
 75    """Build a frame addressed to every node.
 76
 77    :param src: The address of this node.
 78    :param id: The sequence number identifying this packet from this source.
 79    :param payload: The bytes to carry.
 80    :param hop_limit: How many relays the frame may take, defaulting to
 81        :data:`DEFAULT_HOP_LIMIT`.
 82    :returns: The frame, with the bytes to transmit on its ``bytes`` attribute.
 83    :raises PamojaError: If the payload is larger than :data:`MAX_PAYLOAD`.
 84    """
 85    return _broadcast_frame(src, id, bytes(payload), hop_limit)
 86
 87
 88def parse(data: bytes) -> MeshFrame:
 89    """Parse a frame received off a radio.
 90
 91    :param data: The frame exactly as it arrived.
 92    :returns: The parsed frame.
 93    :raises PamojaError: If the frame is truncated, of an unknown version, or
 94        fails its checksum, which is what a noisy radio produces.
 95    """
 96    return _parse_frame(bytes(data))
 97
 98
 99def relayed(data: bytes) -> MeshFrame | None:
100    """Return the same frame with one hop spent, ready to forward.
101
102    :param data: The frame exactly as it arrived.
103    :returns: The frame to forward, or ``None`` once its hops have run out,
104        which is what stops a flood from circulating forever.
105    :raises PamojaError: If the frame cannot be parsed.
106    """
107    return _relayed(bytes(data))
108
109
110def crc16(data: bytes) -> int:
111    """Compute the CRC-16 a frame carries.
112
113    :param data: The bytes the checksum covers.
114    :returns: The checksum.
115    """
116    return _crc16(bytes(data))
BROADCAST = 4294967295
DEFAULT_HOP_LIMIT = 3
MAX_FRAME = 250
MAX_PAYLOAD = 236
HEADER_LEN = 12
SEEN_DEFAULT_CAPACITY = 64
class MeshFrame:

A mesh packet: its addressing, its payload, and the bytes to transmit.

dst

The address the frame is addressed to.

id

The sequence number identifying this packet from this source.

hop_limit

How many further relays the frame may take.

broadcast

Whether the frame is addressed to every node.

version

The protocol version the frame declares.

payload

The payload the frame carries.

src

The address of the node the frame came from.

bytes

The whole frame as it goes on the air.

class SeenPackets:

A memory of recently seen packets, so a node relays each one only once.

def contains(self, /, src, id):

Reports whether a packet is currently remembered, without recording it.

def record(self, /, src, id):

Records a packet and reports whether it was new.

A true answer is when a node should act on the packet and relay it; a false one means another copy already arrived by a different path.

capacity

How many packets this cache remembers.

def broadcast( src: int, id: int, payload: bytes, hop_limit: int | None = None) -> MeshFrame:
73def broadcast(
74    src: int, id: int, payload: bytes, hop_limit: int | None = None
75) -> MeshFrame:
76    """Build a frame addressed to every node.
77
78    :param src: The address of this node.
79    :param id: The sequence number identifying this packet from this source.
80    :param payload: The bytes to carry.
81    :param hop_limit: How many relays the frame may take, defaulting to
82        :data:`DEFAULT_HOP_LIMIT`.
83    :returns: The frame, with the bytes to transmit on its ``bytes`` attribute.
84    :raises PamojaError: If the payload is larger than :data:`MAX_PAYLOAD`.
85    """
86    return _broadcast_frame(src, id, bytes(payload), hop_limit)

Build a frame addressed to every node.

Parameters
  • src: The address of this node.
  • id: The sequence number identifying this packet from this source.
  • payload: The bytes to carry.
  • hop_limit: How many relays the frame may take, defaulting to DEFAULT_HOP_LIMIT. :returns: The frame, with the bytes to transmit on its bytes attribute.
Raises
  • PamojaError: If the payload is larger than MAX_PAYLOAD.
def crc16(data: bytes) -> int:
111def crc16(data: bytes) -> int:
112    """Compute the CRC-16 a frame carries.
113
114    :param data: The bytes the checksum covers.
115    :returns: The checksum.
116    """
117    return _crc16(bytes(data))

Compute the CRC-16 a frame carries.

Parameters
  • data: The bytes the checksum covers. :returns: The checksum.
def frame( src: int, dst: int, id: int, payload: bytes, hop_limit: int | None = None) -> MeshFrame:
52def frame(
53    src: int,
54    dst: int,
55    id: int,
56    payload: bytes,
57    hop_limit: int | None = None,
58) -> MeshFrame:
59    """Build a frame addressed to one node.
60
61    :param src: The address of this node.
62    :param dst: The address the frame is for, or :data:`BROADCAST`.
63    :param id: The sequence number identifying this packet from this source.
64    :param payload: The bytes to carry.
65    :param hop_limit: How many relays the frame may take, defaulting to
66        :data:`DEFAULT_HOP_LIMIT`.
67    :returns: The frame, with the bytes to transmit on its ``bytes`` attribute.
68    :raises PamojaError: If the payload is larger than :data:`MAX_PAYLOAD`.
69    """
70    return _frame(src, dst, id, bytes(payload), hop_limit)

Build a frame addressed to one node.

Parameters
  • src: The address of this node.
  • dst: The address the frame is for, or BROADCAST.
  • id: The sequence number identifying this packet from this source.
  • payload: The bytes to carry.
  • hop_limit: How many relays the frame may take, defaulting to DEFAULT_HOP_LIMIT. :returns: The frame, with the bytes to transmit on its bytes attribute.
Raises
  • PamojaError: If the payload is larger than MAX_PAYLOAD.
def parse(data: bytes) -> MeshFrame:
89def parse(data: bytes) -> MeshFrame:
90    """Parse a frame received off a radio.
91
92    :param data: The frame exactly as it arrived.
93    :returns: The parsed frame.
94    :raises PamojaError: If the frame is truncated, of an unknown version, or
95        fails its checksum, which is what a noisy radio produces.
96    """
97    return _parse_frame(bytes(data))

Parse a frame received off a radio.

Parameters
  • data: The frame exactly as it arrived. :returns: The parsed frame.
Raises
  • PamojaError: If the frame is truncated, of an unknown version, or fails its checksum, which is what a noisy radio produces.
def relayed(data: bytes) -> MeshFrame | None:
100def relayed(data: bytes) -> MeshFrame | None:
101    """Return the same frame with one hop spent, ready to forward.
102
103    :param data: The frame exactly as it arrived.
104    :returns: The frame to forward, or ``None`` once its hops have run out,
105        which is what stops a flood from circulating forever.
106    :raises PamojaError: If the frame cannot be parsed.
107    """
108    return _relayed(bytes(data))

Return the same frame with one hop spent, ready to forward.

Parameters
  • data: The frame exactly as it arrived. :returns: The frame to forward, or None once its hops have run out, which is what stops a flood from circulating forever.
Raises
  • PamojaError: If the frame cannot be parsed.