feagi_hal/bluetooth/nus.rs
1// Copyright 2025 Neuraville Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Nordic UART Service (NUS) and FEAGI Service UUID Definitions
5//!
6//! This module defines the BLE service and characteristic UUIDs used for
7//! FEAGI communication. We use both the standard Nordic UART Service (NUS)
8//! for simple bidirectional communication and custom FEAGI service UUIDs
9//! for structured data.
10//!
11//! ## Nordic UART Service (NUS)
12//!
13//! NUS is a simple, widely-supported BLE service that mimics a UART interface:
14//!
15//! - **Service UUID**: `6E400001-B5A3-F393-E0A9-E50E24DCCA9E`
16//! - **TX Characteristic**: `6E400003-B5A3-F393-E0A9-E50E24DCCA9E` (Notify)
17//! - Device → Client (micro:bit sends sensor data)
18//! - **RX Characteristic**: `6E400002-B5A3-F393-E0A9-E50E24DCCA9E` (Write)
19//! - Client → Device (FEAGI sends commands)
20//!
21//! ## FEAGI Custom Service (Alternative)
22//!
23//! For more structured communication, FEAGI defines custom characteristics:
24//!
25//! - **Service UUID**: `E95D0753-251D-470A-A062-FA1922DFA9A8`
26//! - **Sensor Data** (Notify): `E95D0754-251D-470A-A062-FA1922DFA9A8`
27//! - **Neuron Data** (Write): `E95D0755-251D-470A-A062-FA1922DFA9A8`
28//! - **GPIO Control** (Write): `E95D0756-251D-470A-A062-FA1922DFA9A8`
29//! - **LED Matrix** (Write): `E95D0757-251D-470A-A062-FA1922DFA9A8`
30//! - **Capabilities** (Read): `E95D0758-251D-470A-A062-FA1922DFA9A8`
31//!
32//! ## Usage
33//!
34//! ```rust
35//! use feagi_hal::bluetooth::nus::*;
36//!
37//! // Use NUS for simple communication
38//! let service_uuid = NUS_SERVICE_UUID;
39//! let rx_uuid = NUS_RX_CHAR_UUID; // Client writes here
40//! let tx_uuid = NUS_TX_CHAR_UUID; // Client reads/subscribes here
41//!
42//! // Or use FEAGI service for structured data
43//! let service_uuid = FEAGI_SERVICE_UUID;
44//! let neuron_uuid = NEURON_DATA_CHAR_UUID;
45//! ```
46
47// Note: This module is part of a no_std crate
48
49// ============================================================================
50// Nordic UART Service (NUS) - Standard BLE service for serial-like communication
51// ============================================================================
52
53/// Nordic UART Service UUID: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
54///
55/// This is the primary service UUID for NUS.
56pub const NUS_SERVICE_UUID: [u8; 16] = [
57 0x6e, 0x40, 0x00, 0x01, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e,
58];
59
60/// NUS TX Characteristic UUID: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
61///
62/// **Direction**: Device → Client (Notify)
63/// **Purpose**: Device sends sensor data or status updates to client
64pub const NUS_TX_CHAR_UUID: [u8; 16] = [
65 0x6e, 0x40, 0x00, 0x03, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e,
66];
67
68/// NUS RX Characteristic UUID: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E
69///
70/// **Direction**: Client → Device (Write)
71/// **Purpose**: Client sends commands or motor data to device
72pub const NUS_RX_CHAR_UUID: [u8; 16] = [
73 0x6e, 0x40, 0x00, 0x02, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e,
74];
75
76// ============================================================================
77// FEAGI Custom Service - Structured characteristics for different data types
78// ============================================================================
79
80/// FEAGI BLE Service UUID: E95D0753-251D-470A-A062-FA1922DFA9A8
81pub const FEAGI_SERVICE_UUID: [u8; 16] = [
82 0xe9, 0x5d, 0x07, 0x53, 0x25, 0x1d, 0x47, 0x0a, 0xa0, 0x62, 0xfa, 0x19, 0x22, 0xdf, 0xa9, 0xa8,
83];
84
85/// Sensor Data Characteristic UUID: E95D0754-251D-470A-A062-FA1922DFA9A8
86///
87/// **Direction**: Device → Client (Notify)
88/// **Purpose**: Periodic sensor readings (accel, mag, temp, buttons)
89/// **Format**: JSON string
90pub const SENSOR_DATA_CHAR_UUID: [u8; 16] = [
91 0xe9, 0x5d, 0x07, 0x54, 0x25, 0x1d, 0x47, 0x0a, 0xa0, 0x62, 0xfa, 0x19, 0x22, 0xdf, 0xa9, 0xa8,
92];
93
94/// Neuron Data Characteristic UUID: E95D0755-251D-470A-A062-FA1922DFA9A8
95///
96/// **Direction**: Client → Device (Write)
97/// **Purpose**: Neuron firing coordinates for LED matrix visualization
98/// **Format**: Binary packet (see protocol.rs)
99pub const NEURON_DATA_CHAR_UUID: [u8; 16] = [
100 0xe9, 0x5d, 0x07, 0x55, 0x25, 0x1d, 0x47, 0x0a, 0xa0, 0x62, 0xfa, 0x19, 0x22, 0xdf, 0xa9, 0xa8,
101];
102
103/// GPIO Control Characteristic UUID: E95D0756-251D-470A-A062-FA1922DFA9A8
104///
105/// **Direction**: Client → Device (Write)
106/// **Purpose**: Digital I/O and PWM control
107/// **Format**: Binary packet (see protocol.rs)
108pub const GPIO_CONTROL_CHAR_UUID: [u8; 16] = [
109 0xe9, 0x5d, 0x07, 0x56, 0x25, 0x1d, 0x47, 0x0a, 0xa0, 0x62, 0xfa, 0x19, 0x22, 0xdf, 0xa9, 0xa8,
110];
111
112/// LED Matrix Characteristic UUID: E95D0757-251D-470A-A062-FA1922DFA9A8
113///
114/// **Direction**: Client → Device (Write)
115/// **Purpose**: Full 5×5 LED matrix update
116/// **Format**: 25 bytes (brightness values 0-255)
117pub const LED_MATRIX_CHAR_UUID: [u8; 16] = [
118 0xe9, 0x5d, 0x07, 0x57, 0x25, 0x1d, 0x47, 0x0a, 0xa0, 0x62, 0xfa, 0x19, 0x22, 0xdf, 0xa9, 0xa8,
119];
120
121/// Capabilities Characteristic UUID: E95D0758-251D-470A-A062-FA1922DFA9A8
122///
123/// **Direction**: Device → Client (Read)
124/// **Purpose**: Device capabilities JSON (sensors, GPIO, display)
125/// **Format**: JSON string
126pub const CAPABILITIES_CHAR_UUID: [u8; 16] = [
127 0xe9, 0x5d, 0x07, 0x58, 0x25, 0x1d, 0x47, 0x0a, 0xa0, 0x62, 0xfa, 0x19, 0x22, 0xdf, 0xa9, 0xa8,
128];
129
130// ============================================================================
131// Default Device Names
132// ============================================================================
133
134/// Default device name for FEAGI-enabled micro:bit
135pub const FEAGI_MICROBIT_NAME: &str = "FEAGI-microbit";
136
137/// Default device name for FEAGI-enabled ESP32
138pub const FEAGI_ESP32_NAME: &str = "FEAGI-esp32";
139
140/// Default device name for generic FEAGI robot
141pub const FEAGI_ROBOT_NAME: &str = "FEAGI-robot";
142
143// ============================================================================
144// Helper Functions
145// ============================================================================
146
147/// Convert UUID byte array to standard UUID string format
148///
149/// Example: `[0x6e, 0x40, ...]` → `"6e400001-b5a3-f393-e0a9-e50e24dcca9e"`
150#[cfg(feature = "alloc")]
151pub fn uuid_to_string(uuid: &[u8; 16]) -> alloc::string::String {
152 use alloc::format;
153 format!(
154 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
155 uuid[0], uuid[1], uuid[2], uuid[3],
156 uuid[4], uuid[5],
157 uuid[6], uuid[7],
158 uuid[8], uuid[9],
159 uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]
160 )
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_nus_uuids_are_unique() {
169 assert_ne!(NUS_SERVICE_UUID, NUS_TX_CHAR_UUID);
170 assert_ne!(NUS_SERVICE_UUID, NUS_RX_CHAR_UUID);
171 assert_ne!(NUS_TX_CHAR_UUID, NUS_RX_CHAR_UUID);
172 }
173
174 #[test]
175 fn test_feagi_uuids_are_unique() {
176 let uuids = [
177 FEAGI_SERVICE_UUID,
178 SENSOR_DATA_CHAR_UUID,
179 NEURON_DATA_CHAR_UUID,
180 GPIO_CONTROL_CHAR_UUID,
181 LED_MATRIX_CHAR_UUID,
182 CAPABILITIES_CHAR_UUID,
183 ];
184
185 // Check all pairs are different
186 for i in 0..uuids.len() {
187 for j in (i + 1)..uuids.len() {
188 assert_ne!(uuids[i], uuids[j], "UUIDs at {} and {} are identical", i, j);
189 }
190 }
191 }
192
193 #[test]
194 fn test_uuid_byte_order() {
195 // NUS service UUID should start with 6E40
196 assert_eq!(NUS_SERVICE_UUID[0], 0x6e);
197 assert_eq!(NUS_SERVICE_UUID[1], 0x40);
198
199 // FEAGI service UUID should start with E95D
200 assert_eq!(FEAGI_SERVICE_UUID[0], 0xe9);
201 assert_eq!(FEAGI_SERVICE_UUID[1], 0x5d);
202 }
203}