aboutsummaryrefslogtreecommitdiff
path: root/node_id.go
diff options
context:
space:
mode:
authorNoah Stride <[email protected]>2024-02-02 19:51:25 +0000
committerGitHub <[email protected]>2024-02-02 09:51:25 -1000
commitffcb5db042e1f74b93020a9e840704eb9984913c (patch)
tree2ee157217aa958ff6195a6aaa3e4ec968e8c62d9 /node_id.go
parent463760ccf1cb99f387f5bf99ed83e31772744671 (diff)
Support for generating random NodeIDs and deriving Short/Long names (#2)
* Super rough initial subscription to channels and sending node info * Very ugly hacky FromRadio subscription * Add more TODOs :weary: * Add log message before we try to broadcast NodeInfo * Add basic positioning broadcasting * demo sending message from consumer * Use const for BroadcastNodeID * Config validation and defaults * Tidy up examples/TODOs * Tidy up example * Handle position and devicetelemetry updates * Fix dodgy merge * Allow configuring interval for nodeinfo/position seperately * Make broadcasted position configurable * Add MQTTProtoTopic constant rather than modifying topic root * Add Long/Short generation from NodeID * Mimic Meshtastic source more closely * Use generated Long/Short when not specified * Add TestRandomNodeID * Generate NodeID above the threshold
Diffstat (limited to 'node_id.go')
-rw-r--r--node_id.go77
1 files changed, 77 insertions, 0 deletions
diff --git a/node_id.go b/node_id.go
new file mode 100644
index 0000000..5e89145
--- /dev/null
+++ b/node_id.go
@@ -0,0 +1,77 @@
+package meshtastic
+
+import (
+ "crypto/rand"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "math/big"
+)
+
+// NodeID holds the node identifier. This is a uint32 value which uniquely identifies a node within a mesh.
+type NodeID uint32
+
+const (
+ // BroadcastNodeID is the special NodeID used when broadcasting a packet to a channel.
+ BroadcastNodeID NodeID = math.MaxUint32
+ // ReservedNodeIDThreshold is the threshold at which NodeIDs are considered reserved. Random NodeIDs should not
+ // be generated below this threshold.
+ // Source: https://github.com/meshtastic/firmware/blob/d1ea58975755e146457a8345065e4ca357555275/src/mesh/NodeDB.cpp#L461
+ reservedNodeIDThreshold NodeID = 4
+)
+
+// Uint32 returns the underlying uint32 value of the NodeID.
+func (n NodeID) Uint32() uint32 {
+ return uint32(n)
+}
+
+// String converts the NodeID to a hex formatted string.
+// This is typically how NodeIDs are displayed in Meshtastic UIs.
+func (n NodeID) String() string {
+ return fmt.Sprintf("!%08x", uint32(n))
+}
+
+// Bytes converts the NodeID to a byte slice
+func (n NodeID) Bytes() []byte {
+ bytes := make([]byte, 4) // uint32 is 4 bytes
+ binary.BigEndian.PutUint32(bytes, n.Uint32())
+ return bytes
+}
+
+// DefaultLongName returns the default long node name based on the NodeID.
+// Source: https://github.com/meshtastic/firmware/blob/d1ea58975755e146457a8345065e4ca357555275/src/mesh/NodeDB.cpp#L382
+func (n NodeID) DefaultLongName() string {
+ bytes := make([]byte, 4) // uint32 is 4 bytes
+ binary.BigEndian.PutUint32(bytes, n.Uint32())
+ return fmt.Sprintf("Meshtastic %04x", bytes[2:])
+}
+
+// DefaultShortName returns the default short node name based on the NodeID.
+// Last two bytes of the NodeID represented in hex.
+// Source: https://github.com/meshtastic/firmware/blob/d1ea58975755e146457a8345065e4ca357555275/src/mesh/NodeDB.cpp#L382
+func (n NodeID) DefaultShortName() string {
+ bytes := make([]byte, 4) // uint32 is 4 bytes
+ binary.BigEndian.PutUint32(bytes, n.Uint32())
+ return fmt.Sprintf("%04x", bytes[2:])
+}
+
+// RandomNodeID returns a randomised NodeID.
+// It's recommended to call this the first time a node is started and persist the result.
+//
+// Hardware meshtastic nodes first try a NodeID of the last four bytes of the BLE MAC address. If that ID is already in
+// use or invalid, a random NodeID is generated.
+// Source: https://github.com/meshtastic/firmware/blob/d1ea58975755e146457a8345065e4ca357555275/src/mesh/NodeDB.cpp#L466
+func RandomNodeID() (NodeID, error) {
+ // Generates a random uint32 between reservedNodeIDThreshold and math.MaxUint32
+ randomInt, err := rand.Int(
+ rand.Reader,
+ big.NewInt(
+ int64(math.MaxUint32-reservedNodeIDThreshold.Uint32()),
+ ),
+ )
+ if err != nil {
+ return NodeID(0), fmt.Errorf("reading entropy: %w", err)
+ }
+ r := uint32(randomInt.Uint64()) + reservedNodeIDThreshold.Uint32()
+ return NodeID(r), nil
+}