WIP ble: Add device information service
TODO: Determine "git describe" size
This commit is contained in:
parent
f42a0d5370
commit
2900f3a8af
4 changed files with 142 additions and 1 deletions
15
build.rs
15
build.rs
|
|
@ -17,6 +17,21 @@ fn main() -> std::io::Result<()> {
|
|||
.compile_well_known_types()
|
||||
.compile_protos(&["docs/c_its-messages.proto"], &["docs/"])?;
|
||||
|
||||
// get git revision
|
||||
println!("cargo:rustc-rerun-if-changed=.git/HEAD");
|
||||
|
||||
println!(
|
||||
"cargo:rustc-env=GIT_REVISION={}",
|
||||
String::from_utf8(
|
||||
std::process::Command::new("git")
|
||||
.args(&["describe", "--always"])
|
||||
.output()
|
||||
.unwrap()
|
||||
.stdout,
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
80
src/ble.rs
80
src/ble.rs
|
|
@ -41,10 +41,55 @@ pub enum BleSendable {
|
|||
SpatemRaw(io::msg::RawMsgRx),
|
||||
}
|
||||
|
||||
pub const DIS_SERIAL_MAX_LEN: usize = 17;
|
||||
pub const DIS_FW_REVISION_MAX_LEN: usize = 16; // TODO: what do we need?
|
||||
pub const DIS_SW_REVISION_MAX_LEN: usize = 66; // max length of get_feature_list, joined with comma
|
||||
|
||||
pub struct DeviceInfo {
|
||||
/// WiFi MAC
|
||||
pub serial_number: [u8; DIS_SERIAL_MAX_LEN],
|
||||
/// git tag/ revision
|
||||
pub fw_revision: [u8; DIS_FW_REVISION_MAX_LEN],
|
||||
/// used for feature flags
|
||||
pub sw_revision: [u8; DIS_SW_REVISION_MAX_LEN],
|
||||
}
|
||||
|
||||
impl DeviceInfo {
|
||||
pub fn new(serial_number: &str, fw_revision: &str, sw_revision: &str) -> Self {
|
||||
Self {
|
||||
serial_number: string_as_padded_buf(serial_number, DIS_SERIAL_MAX_LEN)
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
fw_revision: string_as_padded_buf(fw_revision, DIS_FW_REVISION_MAX_LEN)
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
sw_revision: string_as_padded_buf(sw_revision, DIS_SW_REVISION_MAX_LEN)
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_as_padded_buf(value: &str, length: usize) -> alloc::vec::Vec<u8> {
|
||||
let buf = value.as_bytes();
|
||||
let buf_len = buf.len();
|
||||
|
||||
// cut buffer at maximum length or pad with whitespace
|
||||
if buf_len > length {
|
||||
buf[..length].to_vec()
|
||||
} else {
|
||||
let padding_len = length - buf_len;
|
||||
let padding = alloc::vec![b' '; padding_len];
|
||||
|
||||
[buf, &padding].concat()
|
||||
}
|
||||
}
|
||||
|
||||
#[gatt_server]
|
||||
struct Server {
|
||||
c_its_events: CITSEvents,
|
||||
battery_service: BatteryService,
|
||||
device_info_service: DeviceInfoService,
|
||||
}
|
||||
|
||||
#[gatt_service(uuid = service::BATTERY)]
|
||||
|
|
@ -56,6 +101,25 @@ struct BatteryService {
|
|||
level: u8,
|
||||
}
|
||||
|
||||
#[gatt_service(uuid = service::DEVICE_INFORMATION)]
|
||||
struct DeviceInfoService {
|
||||
/// Manufacturer name
|
||||
#[characteristic(uuid = characteristic::MANUFACTURER_NAME_STRING, read, value = "jtbx")]
|
||||
mfg_name: &'static str,
|
||||
/// Model number
|
||||
#[characteristic(uuid = characteristic::MODEL_NUMBER_STRING, read, value = "ESP32-C5 C-ITS Companion")]
|
||||
model_number: &'static str,
|
||||
// Serial Number String
|
||||
#[characteristic(uuid = characteristic::SERIAL_NUMBER_STRING, read, value = [0u8; DIS_SERIAL_MAX_LEN])]
|
||||
serial_number: [u8; DIS_SERIAL_MAX_LEN],
|
||||
// Firmware Revision String
|
||||
#[characteristic(uuid = characteristic::FIRMWARE_REVISION_STRING, read, value = [0u8; DIS_FW_REVISION_MAX_LEN])]
|
||||
fw_revision: [u8; DIS_FW_REVISION_MAX_LEN],
|
||||
// Software Revision String
|
||||
#[characteristic(uuid = characteristic::SOFTWARE_REVISION_STRING, read, value = [0u8; DIS_SW_REVISION_MAX_LEN])]
|
||||
sw_revision: [u8; DIS_SW_REVISION_MAX_LEN],
|
||||
}
|
||||
|
||||
#[gatt_service(uuid = "c0b70000-d4f4-4000-ada8-f99a02ee315c")]
|
||||
struct CITSEvents {
|
||||
#[descriptor(uuid = descriptors::MEASUREMENT_DESCRIPTION, name = "Position", read, value = "PositionState proto msg", type = &'static str)]
|
||||
|
|
@ -123,6 +187,7 @@ pub async fn run(
|
|||
>,
|
||||
name: alloc::string::String,
|
||||
short_name: alloc::string::String,
|
||||
device_info: DeviceInfo,
|
||||
) {
|
||||
let mut resources: HostResources<DefaultPacketPool, CONNECTIONS_MAX, L2CAP_CHANNELS_MAX> =
|
||||
HostResources::new();
|
||||
|
|
@ -144,6 +209,21 @@ pub async fn run(
|
|||
}))
|
||||
.unwrap();
|
||||
|
||||
// set "dynamic" device info data
|
||||
let _ = server
|
||||
.device_info_service
|
||||
.serial_number
|
||||
.set(&server, &device_info.serial_number);
|
||||
let _ = server
|
||||
.device_info_service
|
||||
.fw_revision
|
||||
.set(&server, &device_info.fw_revision);
|
||||
let _ = server
|
||||
.device_info_service
|
||||
.sw_revision
|
||||
.set(&server, &device_info.sw_revision);
|
||||
|
||||
// advertise and run update logic
|
||||
let _ = embassy_futures::join::join(ble_task(runner), async {
|
||||
loop {
|
||||
// run advertisement and set data until a client connects
|
||||
|
|
|
|||
10
src/main.rs
10
src/main.rs
|
|
@ -234,7 +234,15 @@ async fn main(spawner: Spawner) -> ! {
|
|||
serial[2]
|
||||
);
|
||||
let short_name = alloc::format!("V2X {:02x}{:02x}", serial[1], serial[2]); // max 8 chars!
|
||||
spawner.spawn(ble::run(controller, name, short_name).expect("Failed to spawn BLE task"));
|
||||
|
||||
let fw_revision = env!("GIT_REVISION");
|
||||
let sw_revision = util::get_feature_list().join(",");
|
||||
|
||||
let device_info = ble::DeviceInfo::new(&mac.to_string(), &fw_revision, &sw_revision);
|
||||
|
||||
spawner.spawn(
|
||||
ble::run(controller, name, short_name, device_info).expect("Failed to spawn BLE task"),
|
||||
);
|
||||
}
|
||||
|
||||
// Setup GNSS:
|
||||
|
|
|
|||
38
src/util.rs
38
src/util.rs
|
|
@ -31,3 +31,41 @@ pub(crate) fn get_tx_feature_list() -> Vec<&'static str> {
|
|||
|
||||
features
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn get_feature_list() -> Vec<&'static str> {
|
||||
let mut features = alloc::vec![];
|
||||
|
||||
if cfg!(feature = "gnss_ubx") {
|
||||
features.push("gnss_ubx");
|
||||
}
|
||||
if cfg!(feature = "gnss_l67k") {
|
||||
features.push("gnss_l67k");
|
||||
}
|
||||
if cfg!(feature = "cam_tx") {
|
||||
features.push("cam_tx");
|
||||
}
|
||||
if cfg!(feature = "cam") {
|
||||
features.push("cam");
|
||||
}
|
||||
if cfg!(feature = "denm") {
|
||||
features.push("denm");
|
||||
}
|
||||
if cfg!(feature = "spat") {
|
||||
features.push("spat");
|
||||
}
|
||||
if cfg!(feature = "spat_debug") {
|
||||
features.push("spat_debug");
|
||||
}
|
||||
if cfg!(feature = "screen") {
|
||||
features.push("screen");
|
||||
}
|
||||
if cfg!(feature = "uart") {
|
||||
features.push("uart");
|
||||
}
|
||||
if cfg!(feature = "ble") {
|
||||
features.push("ble");
|
||||
}
|
||||
|
||||
features
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue