Skip to content

Instantly share code, notes, and snippets.

@spbnick
Created November 16, 2023 13:18
Show Gist options
  • Save spbnick/54230e7a7a2c163929d6418180159e15 to your computer and use it in GitHub Desktop.
Save spbnick/54230e7a7a2c163929d6418180159e15 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import knob
graph = knob.Graph()
e = graph.entities
n = e[""]
r = graph.relations
s = e.ll_state
t = r.ll_state_transition
s.Advertising(
implementation_required=True,
comment="Device in this state is an \"advertiser\", and is "
"transmitting advertising physical channel packets, "
"and listening and responding to responses."
) >> e.role.Advertiser << n.Device
s.Scanning(
implementation_required=True,
comment="Device in this state is a \"scanner\", and is listening for "
"advertising physical channel packets from devices that are "
"advertising. This state can be entered from the Standby state."
) >> e.role.Scanner << n.Device
s.Standby(
comment="The Link Layer in the Standby state does not transmit or "
"receive any packets. The Standby state can be entered from "
"any other state."
)
s.Initiating(
comment="The Link Layer in the Initiating state will be listening for "
"advertising physical channel packets from a specific device(s) "
"and responding to these packets to initiate a connection with "
"another device. A device in the Initiating state is known as an "
"initiator. The Initiating state can be entered from the Standby "
"state."
) >> e.role.Initiator << n.Device
s.Connection(
comment="The Connection state can be entered either from the Initiating "
"state or the Advertising state. A device in the Connection "
"state is known as being in a connection."
) >> e.role["In a Connection"] << n.Device
s.Synchronization(
comment="The Link Layer in the Synchronization State will be listening "
"for periodic physical channel packets forming a specific "
"periodic advertising train, coming from a specified device that "
"is transmitting periodic advertising. The Synchronization State "
"can be entered from the Standby State. While in this State, the "
"Host may direct the Link Layer to listen for isochronous data "
"packets coming from a specified device that is transmitting a "
"Broadcast Isochronous Group (BIG). A device that is in the "
"Synchronization State and is receiving isochronous data packets "
"is referred to as a Synchronized Receiver."
) >> e.role["Synchronized Receiver"] << n.Device
s["Isochronous Broadcasting"](
comment="The Link Layer in the Isochronous Broadcasting State will "
"transmit isochronous data packets on an isochronous physical "
"channel. The Isochronous Broadcasting State can be entered from "
"the Standby State. A device that is in the Isochronous "
"Broadcasting State is referred to as an Isochronous Broadcaster."
) >> e.role["Isochronous Broadcaster"] << n.Device
s.Advertising >> t >> s.Standby
s.Advertising << t << s.Standby
s.Advertising >> t >> e.role.Peripheral
s["Isochronous Broadcasting"] >> t >> s.Standby
s["Isochronous Broadcasting"] << t << s.Standby
s.Scanning >> t >> s.Standby
s.Scanning << t << s.Standby
s.Synchronization >> t >> s.Standby
s.Synchronization << t << s.Standby
s.Initiating >> t >> s.Standby
s.Initiating << t << s.Standby
s.Initiating >> t >> e.role.Central
s.Connection >> e.role.Central >> t >> s.Standby
s.Connection >> e.role.Peripheral >> t >> s.Standby
e.role.Central(
comment="The Link Layer in the Central Role will communicate with a "
"device in the Peripheral Role and define the timings of "
"transmissions."
) << n.Device
e.role.Peripheral(
comment="The Link Layer in the Peripheral Role will communicate with a "
"single device in the Central Role."
) << n.Device
n.Device >> r.identified_by >> [
n["Device Address Type"],
n["Device Address"]
]
n["Device Address"] << r.type_of(
identified_by=n["Device Address Type"]
) << [
n["Public Device Address"](
length_bits=48,
created_according_to="[Vol 2] Part B, Section 1.2",
),
n["Random Device Address"](
length_bits=48
),
]
n.Device >> n["Identity Address"] << r.type_of << [
n["Public Device Address"],
n["Random Static Device Address"],
]
n["Random Device Address"] << r.type_of << [
e.bitfield_value["Static device address"] << \
r.identified_by << \
n["Random Static Device Address"](
comment="Shall meet the following requirements:\n"
"• At least one bit of the random part of the address "
"shall be 0\n"
"• At least one bit of the random part of the address "
"shall be 1\n"
"\n"
"A device may choose to initialize its static address to "
"a new value after each power cycle. A device shall not "
"change its static address value once initialized "
"until the device is power cycled.\n"
"\n"
"Note: If the static address of a device is changed, "
"then the address stored in peer devices will not be "
"valid and the ability to reconnect using the old "
"address will be lost."
),
[
e.bitfield_value["Non-resolvable private address"] << \
r.identified_by << \
n["Random Non-Resolvable Private Device Address"](
comment="Requirements:\n"
"• At least one bit of the random part of the "
"address shall be 1\n"
"• At least one bit of the random part of the "
"address shall be 0\n"
"• The address shall not be equal to the public "
"address"
) >> r.type_of,
e.bitfield_value["Resolvable private address"] << \
r.identified_by << \
n["Random Resolvable Private Device Address"](
comment="To generate a resolvable private address, the "
"device must have either the Local Identity "
"Resolving Key (IRK) or the Peer Identity Resolving "
"Key (IRK). The resolvable private address shall be "
"generated with the IRK and a randomly generated "
"24-bit number."
) >> r.type_of,
] >> n["Random Private Device Address"]
]
n["Random Device Address"] >> r.bitfields >> \
e.bitfield["Random Device Address Random Part"](len=46) >> r.followed_by >> \
(
[
e.bitfield_value["Non-resolvable private address"](value=0),
e.bitfield_value["Resolvable private address"](value=1),
e.bitfield_value["Reserved for future use"](value=2),
e.bitfield_value["Static device address"](value=3),
] << r.value << e.bitfield["Random Device Address Sub-Type"](len=2)
)
e.bitfield["Random Device Address Random Part"] >> \
r.bitfields(
selected_by=e.bitfield_value["Resolvable private address"]
) >> \
e.bitfield["Random Device Resolvable Private Address Hash"](len=24) >> \
r.followed_by >> \
e.bitfield["Random Device Resolvable Private "
"Address, Random Part of Prand"](
len=22,
comment="Requirements: at least one bit shall be 0, "
"at least one bit shall be 1"
)
print(graph.render_graphviz())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment