mirror of
https://github.com/ratspeak/rsReticulum
synced 2026-08-12 18:08:29 -04:00
tools: share RNode capability inspection
This commit is contained in:
parent
b1854b62aa
commit
4e1abca4ea
2 changed files with 228 additions and 489 deletions
|
|
@ -12,7 +12,13 @@ use std::process::ExitCode;
|
|||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use clap::{CommandFactory, Parser};
|
||||
use rns_interface::{kiss, rnode, rnode_admin};
|
||||
use rns_interface::{
|
||||
kiss, rnode, rnode_admin,
|
||||
rnode_capabilities::{
|
||||
RNodeCapabilities, RNodeCapabilityParseError, RNodeKnownRadioCapabilities,
|
||||
RNodeRadioCapabilities, RNodeRadioFamily, parse_rnode_capabilities, rnode_product_name,
|
||||
},
|
||||
};
|
||||
use rns_tools::RS_RETICULUM_VERSION;
|
||||
|
||||
// rnodeconf support is staged: safe inspection/config modules are compiled now,
|
||||
|
|
@ -528,36 +534,98 @@ fn print_responses(
|
|||
}
|
||||
|
||||
fn eeprom_summary_lines(image: &eeprom::EepromImage) -> Vec<String> {
|
||||
if !image.info_locked() {
|
||||
return vec!["EEPROM: not provisioned or info lock missing".to_string()];
|
||||
}
|
||||
|
||||
let identity = image.identity();
|
||||
let product = model::product_name(identity.product).unwrap_or("Unknown product");
|
||||
let model_info = model::model_info(identity.model);
|
||||
let model_label = model_info
|
||||
.map(|info| info.band_label)
|
||||
.unwrap_or("unknown band");
|
||||
let radio_label = model_info.map(|info| info.radio).unwrap_or("unknown radio");
|
||||
let checksum_status = if image.checksum_valid() {
|
||||
let capabilities = match parse_rnode_capabilities(image.bytes()) {
|
||||
Ok(capabilities) => capabilities,
|
||||
Err(RNodeCapabilityParseError::InfoNotLocked) => {
|
||||
return vec!["EEPROM: not provisioned or info lock missing".to_string()];
|
||||
}
|
||||
Err(error) => {
|
||||
let mut lines = private_eeprom_identity_lines(&identity, false);
|
||||
lines.push(format!(" Radio capabilities: unavailable ({error})"));
|
||||
append_startup_config_lines(image, &mut lines);
|
||||
return lines;
|
||||
}
|
||||
};
|
||||
|
||||
let mut lines = private_eeprom_identity_lines(&identity, true);
|
||||
append_capability_lines(capabilities, &mut lines);
|
||||
append_startup_config_lines(image, &mut lines);
|
||||
lines
|
||||
}
|
||||
|
||||
fn private_eeprom_identity_lines(
|
||||
identity: &eeprom::IdentityInfo,
|
||||
identity_validated: bool,
|
||||
) -> Vec<String> {
|
||||
let checksum_status = if identity_validated {
|
||||
"valid"
|
||||
} else {
|
||||
"invalid"
|
||||
};
|
||||
let product = if identity_validated {
|
||||
format!(" Product code: 0x{:02x}", identity.product)
|
||||
} else {
|
||||
format!(" Product code: 0x{:02x} (unvalidated)", identity.product)
|
||||
};
|
||||
let model = if identity_validated {
|
||||
format!(" Model: 0x{:02x}", identity.model)
|
||||
} else {
|
||||
format!(" Model code: 0x{:02x} (unvalidated)", identity.model)
|
||||
};
|
||||
|
||||
let mut lines = vec![
|
||||
vec![
|
||||
"EEPROM: provisioned".to_string(),
|
||||
format!(" Product: {product} (0x{:02x})", identity.product),
|
||||
format!(
|
||||
" Model: 0x{:02x} ({model_label}, {radio_label})",
|
||||
identity.model
|
||||
),
|
||||
product,
|
||||
model,
|
||||
format!(" Hardware revision: {}", identity.hw_rev),
|
||||
format!(" Serial: {}", hex::encode(identity.serial.to_be_bytes())),
|
||||
format!(" Manufactured: {}", identity.made),
|
||||
format!(" Identity checksum: {checksum_status}"),
|
||||
];
|
||||
]
|
||||
}
|
||||
|
||||
fn append_capability_lines(capabilities: RNodeCapabilities, lines: &mut Vec<String>) {
|
||||
let product = rnode_product_name(capabilities.product_code()).unwrap_or("Unknown product");
|
||||
lines[1] = format!(
|
||||
" Product: {product} (0x{:02x})",
|
||||
capabilities.product_code()
|
||||
);
|
||||
lines[2] = format!(" Model: 0x{:02x}", capabilities.model_code());
|
||||
|
||||
match capabilities.radio() {
|
||||
RNodeRadioCapabilities::Known(radio) => append_known_radio_lines(radio, lines),
|
||||
_ => {
|
||||
lines.push(" Radio capabilities: unavailable for this model".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn append_known_radio_lines(radio: RNodeKnownRadioCapabilities, lines: &mut Vec<String>) {
|
||||
lines.extend([
|
||||
format!(" Radio family: {}", radio_family_name(radio.family())),
|
||||
format!(
|
||||
" Frequency range: {} - {} Hz",
|
||||
radio.min_frequency_hz(),
|
||||
radio.max_frequency_hz()
|
||||
),
|
||||
format!(" Maximum TX power: {} dBm", radio.max_tx_power_dbm()),
|
||||
]);
|
||||
}
|
||||
|
||||
fn radio_family_name(family: RNodeRadioFamily) -> &'static str {
|
||||
match family {
|
||||
RNodeRadioFamily::Sx1262 => "SX1262",
|
||||
RNodeRadioFamily::Sx1268 => "SX1268",
|
||||
RNodeRadioFamily::Sx1276 => "SX1276",
|
||||
RNodeRadioFamily::Sx1278 => "SX1278",
|
||||
RNodeRadioFamily::Sx1280 => "SX1280",
|
||||
RNodeRadioFamily::Sx1262AndSx1280 => "SX1262 + SX1280",
|
||||
_ => "Unrecognized",
|
||||
}
|
||||
}
|
||||
|
||||
fn append_startup_config_lines(image: &eeprom::EepromImage, lines: &mut Vec<String>) {
|
||||
if let Some(radio) = image.radio_config() {
|
||||
let bitrate =
|
||||
rnode::calculate_bitrate(radio.spreading_factor, radio.coding_rate, radio.bandwidth);
|
||||
|
|
@ -573,8 +641,6 @@ fn eeprom_summary_lines(image: &eeprom::EepromImage) -> Vec<String> {
|
|||
} else {
|
||||
lines.push(" Startup mode: Normal (host-controlled)".to_string());
|
||||
}
|
||||
|
||||
lines
|
||||
}
|
||||
|
||||
fn rnodeconf_cache_paths() -> Result<firmware::CachePaths, String> {
|
||||
|
|
@ -749,6 +815,26 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
fn provisioned_eeprom(model: u8, radio: Option<&eeprom::RadioConfig>) -> eeprom::EepromImage {
|
||||
let identity = eeprom::IdentityInfo {
|
||||
product: model::PRODUCT_RNODE,
|
||||
model,
|
||||
hw_rev: 2,
|
||||
serial: 0x01020304,
|
||||
made: 0x6553F100,
|
||||
};
|
||||
let mut bytes = vec![0xFF; eeprom::EEPROM_SIZE];
|
||||
let mut writes = eeprom::identity_write_frames(&identity);
|
||||
if let Some(radio) = radio {
|
||||
writes.extend(eeprom::radio_config_write_frames(radio));
|
||||
}
|
||||
for frame in writes {
|
||||
let address = frame.payload[0] as usize;
|
||||
bytes[address] = frame.payload[1];
|
||||
}
|
||||
eeprom::EepromImage::new(bytes).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn info_sequence_matches_upstream_probe_order() {
|
||||
assert_eq!(
|
||||
|
|
@ -999,14 +1085,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn eeprom_summary_reports_identity_and_radio_config() {
|
||||
let info = eeprom::IdentityInfo {
|
||||
product: model::PRODUCT_RNODE,
|
||||
model: 0xB4,
|
||||
hw_rev: 2,
|
||||
serial: 0x01020304,
|
||||
made: 0x6553F100,
|
||||
};
|
||||
fn eeprom_summary_reports_validated_identity_capabilities_and_radio_config() {
|
||||
let radio = eeprom::RadioConfig {
|
||||
spreading_factor: 7,
|
||||
coding_rate: 5,
|
||||
|
|
@ -1014,28 +1093,85 @@ mod tests {
|
|||
bandwidth: 125000,
|
||||
frequency: 868000000,
|
||||
};
|
||||
let mut bytes = vec![0xFF; eeprom::EEPROM_SIZE];
|
||||
for frame in eeprom::identity_write_frames(&info)
|
||||
.into_iter()
|
||||
.chain(eeprom::radio_config_write_frames(&radio))
|
||||
{
|
||||
let address = frame.payload[0] as usize;
|
||||
bytes[address] = frame.payload[1];
|
||||
}
|
||||
let image = eeprom::EepromImage::new(bytes).unwrap();
|
||||
let image = provisioned_eeprom(0xB4, Some(&radio));
|
||||
let lines = eeprom_summary_lines(&image);
|
||||
|
||||
assert!(lines.iter().any(|line| line == "EEPROM: provisioned"));
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line.contains("Product: RNode (0x03)"))
|
||||
);
|
||||
assert!(lines.iter().any(|line| line == " Model: 0xb4"));
|
||||
assert!(lines.iter().any(|line| line == " Radio family: SX1278"));
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line == " Frequency range: 420000000 - 520000000 Hz")
|
||||
);
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line == " Maximum TX power: 17 dBm")
|
||||
);
|
||||
assert!(lines.iter().any(|line| line.contains("Startup mode: TNC")));
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line.contains("Frequency: 868000000 Hz"))
|
||||
);
|
||||
assert!(!lines.iter().any(|line| line.contains("420 - 520 MHz")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eeprom_summary_quarantines_ambiguous_model_capabilities() {
|
||||
let image = provisioned_eeprom(0x16, None);
|
||||
let lines = eeprom_summary_lines(&image);
|
||||
|
||||
assert!(lines.iter().any(|line| line == " Model: 0x16"));
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line == " Radio capabilities: unavailable for this model")
|
||||
);
|
||||
assert!(!lines.iter().any(|line| line.contains("Radio family:")));
|
||||
assert!(!lines.iter().any(|line| line.contains("Frequency range:")));
|
||||
assert!(!lines.iter().any(|line| line.contains("Maximum TX power:")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eeprom_summary_does_not_trust_an_invalid_identity_checksum() {
|
||||
let image = provisioned_eeprom(0xB4, None);
|
||||
let mut bytes = image.bytes().to_vec();
|
||||
bytes[eeprom::ADDR_CHKSUM] ^= 0x01;
|
||||
let invalid = eeprom::EepromImage::new(bytes).unwrap();
|
||||
let lines = eeprom_summary_lines(&invalid);
|
||||
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line == " Product code: 0x03 (unvalidated)")
|
||||
);
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line == " Model code: 0xb4 (unvalidated)")
|
||||
);
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line == " Identity checksum: invalid")
|
||||
);
|
||||
assert!(
|
||||
lines
|
||||
.iter()
|
||||
.any(|line| line.contains("Radio capabilities: unavailable"))
|
||||
);
|
||||
assert!(lines.iter().any(|line| line == " Serial: 01020304"));
|
||||
assert!(!lines.iter().any(|line| line.contains("Product: RNode")));
|
||||
assert!(!lines.iter().any(|line| line.contains("Radio family:")));
|
||||
assert!(!lines.iter().any(|line| line.contains("Frequency range:")));
|
||||
assert!(!lines.iter().any(|line| line.contains("Maximum TX power:")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
//! RNode platform, product and firmware model tables.
|
||||
//! RNode platform, product and firmware model metadata.
|
||||
//!
|
||||
//! Radio families and numeric operating limits belong to
|
||||
//! `rns_interface::rnode_capabilities`; this tool-local table contains only
|
||||
//! metadata needed to plan firmware operations.
|
||||
|
||||
pub const PLATFORM_AVR: u8 = 0x90;
|
||||
pub const PLATFORM_ESP32: u8 = 0x80;
|
||||
|
|
@ -32,439 +36,61 @@ pub const MODEL_B9_TCXO: u8 = 0x09;
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ModelInfo {
|
||||
pub model: u8,
|
||||
pub min_frequency: u32,
|
||||
pub max_frequency: u32,
|
||||
pub max_tx_power: u8,
|
||||
pub band_label: &'static str,
|
||||
pub firmware_filename: Option<&'static str>,
|
||||
pub radio: &'static str,
|
||||
}
|
||||
|
||||
pub const MODELS: &[ModelInfo] = &[
|
||||
model(
|
||||
0xA4,
|
||||
410000000,
|
||||
525000000,
|
||||
14,
|
||||
"410 - 525 MHz",
|
||||
Some("rnode_firmware.hex"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xA9,
|
||||
820000000,
|
||||
1020000000,
|
||||
17,
|
||||
"820 - 1020 MHz",
|
||||
Some("rnode_firmware.hex"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xA1,
|
||||
410000000,
|
||||
525000000,
|
||||
22,
|
||||
"410 - 525 MHz",
|
||||
Some("rnode_firmware_t3s3.zip"),
|
||||
"SX1268",
|
||||
),
|
||||
model(
|
||||
0xA6,
|
||||
820000000,
|
||||
1020000000,
|
||||
22,
|
||||
"820 - 960 MHz",
|
||||
Some("rnode_firmware_t3s3.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xA5,
|
||||
410000000,
|
||||
525000000,
|
||||
17,
|
||||
"410 - 525 MHz",
|
||||
Some("rnode_firmware_t3s3_sx127x.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xAA,
|
||||
820000000,
|
||||
1020000000,
|
||||
17,
|
||||
"820 - 960 MHz",
|
||||
Some("rnode_firmware_t3s3_sx127x.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xAC,
|
||||
2400000000,
|
||||
2500000000,
|
||||
20,
|
||||
"2.4 - 2.5 GHz",
|
||||
Some("rnode_firmware_t3s3_sx1280_pa.zip"),
|
||||
"SX1280",
|
||||
),
|
||||
model(
|
||||
0xA2,
|
||||
410000000,
|
||||
525000000,
|
||||
17,
|
||||
"410 - 525 MHz",
|
||||
Some("rnode_firmware_ng21.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xA7,
|
||||
820000000,
|
||||
1020000000,
|
||||
17,
|
||||
"820 - 1020 MHz",
|
||||
Some("rnode_firmware_ng21.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xA3,
|
||||
410000000,
|
||||
525000000,
|
||||
17,
|
||||
"410 - 525 MHz",
|
||||
Some("rnode_firmware_ng20.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xA8,
|
||||
820000000,
|
||||
1020000000,
|
||||
17,
|
||||
"820 - 1020 MHz",
|
||||
Some("rnode_firmware_ng20.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xB3,
|
||||
420000000,
|
||||
520000000,
|
||||
17,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_lora32v20.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xB8,
|
||||
850000000,
|
||||
950000000,
|
||||
17,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_lora32v20.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xB4,
|
||||
420000000,
|
||||
520000000,
|
||||
17,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_lora32v21.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xB9,
|
||||
850000000,
|
||||
950000000,
|
||||
17,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_lora32v21.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
MODEL_B4_TCXO,
|
||||
420000000,
|
||||
520000000,
|
||||
17,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_lora32v21_tcxo.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
MODEL_B9_TCXO,
|
||||
850000000,
|
||||
950000000,
|
||||
17,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_lora32v21_tcxo.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xBA,
|
||||
420000000,
|
||||
520000000,
|
||||
17,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_lora32v10.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xBB,
|
||||
850000000,
|
||||
950000000,
|
||||
17,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_lora32v10.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xC4,
|
||||
420000000,
|
||||
520000000,
|
||||
17,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_heltec32v2.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xC9,
|
||||
850000000,
|
||||
950000000,
|
||||
17,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_heltec32v2.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xC5,
|
||||
420000000,
|
||||
520000000,
|
||||
22,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_heltec32v3.zip"),
|
||||
"SX1268",
|
||||
),
|
||||
model(
|
||||
0xCA,
|
||||
850000000,
|
||||
950000000,
|
||||
22,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_heltec32v3.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xC8,
|
||||
860000000,
|
||||
930000000,
|
||||
28,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_heltec32v4pa.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xC6,
|
||||
420000000,
|
||||
520000000,
|
||||
22,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_heltec_t114.zip"),
|
||||
"SX1268",
|
||||
),
|
||||
model(
|
||||
0xC7,
|
||||
850000000,
|
||||
950000000,
|
||||
22,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_heltec_t114.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xE4,
|
||||
420000000,
|
||||
520000000,
|
||||
17,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_tbeam.zip"),
|
||||
"SX1278",
|
||||
),
|
||||
model(
|
||||
0xE9,
|
||||
850000000,
|
||||
950000000,
|
||||
17,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_tbeam.zip"),
|
||||
"SX1276",
|
||||
),
|
||||
model(
|
||||
0xD4,
|
||||
420000000,
|
||||
520000000,
|
||||
22,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_tdeck.zip"),
|
||||
"SX1268",
|
||||
),
|
||||
model(
|
||||
0xD9,
|
||||
850000000,
|
||||
950000000,
|
||||
22,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_tdeck.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xDB,
|
||||
420000000,
|
||||
520000000,
|
||||
22,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_tbeam_supreme.zip"),
|
||||
"SX1268",
|
||||
),
|
||||
model(
|
||||
0xDC,
|
||||
850000000,
|
||||
950000000,
|
||||
22,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_tbeam_supreme.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xE3,
|
||||
420000000,
|
||||
520000000,
|
||||
22,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_tbeam_sx1262.zip"),
|
||||
"SX1268",
|
||||
),
|
||||
model(
|
||||
0xE8,
|
||||
850000000,
|
||||
950000000,
|
||||
22,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_tbeam_sx1262.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0x11,
|
||||
430000000,
|
||||
510000000,
|
||||
22,
|
||||
"430 - 510 MHz",
|
||||
Some("rnode_firmware_rak4631.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0x12,
|
||||
779000000,
|
||||
928000000,
|
||||
22,
|
||||
"779 - 928 MHz",
|
||||
Some("rnode_firmware_rak4631.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0x13,
|
||||
430000000,
|
||||
510000000,
|
||||
22,
|
||||
"430 - 510 MHz",
|
||||
Some("rnode_firmware_rak4631_sx1280.zip"),
|
||||
"SX1262 + SX1280",
|
||||
),
|
||||
model(
|
||||
0x14,
|
||||
779000000,
|
||||
928000000,
|
||||
22,
|
||||
"779 - 928 MHz",
|
||||
Some("rnode_firmware_rak4631_sx1280.zip"),
|
||||
"SX1262 + SX1280",
|
||||
),
|
||||
model(
|
||||
0x16,
|
||||
779000000,
|
||||
928000000,
|
||||
22,
|
||||
"430 - 510 Mhz",
|
||||
Some("rnode_firmware_techo.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0x17,
|
||||
779000000,
|
||||
928000000,
|
||||
22,
|
||||
"779 - 928 Mhz",
|
||||
Some("rnode_firmware_techo.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0x21,
|
||||
820000000,
|
||||
960000000,
|
||||
22,
|
||||
"820 - 960 MHz",
|
||||
Some("rnode_firmware_opencom_xl.zip"),
|
||||
"SX1262 + SX1280",
|
||||
),
|
||||
model(
|
||||
0xDE,
|
||||
420000000,
|
||||
520000000,
|
||||
22,
|
||||
"420 - 520 MHz",
|
||||
Some("rnode_firmware_xiao_esp32s3.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xDD,
|
||||
850000000,
|
||||
950000000,
|
||||
22,
|
||||
"850 - 950 MHz",
|
||||
Some("rnode_firmware_xiao_esp32s3.zip"),
|
||||
"SX1262",
|
||||
),
|
||||
model(
|
||||
0xFE,
|
||||
100000000,
|
||||
1100000000,
|
||||
17,
|
||||
"(Band capabilities unknown)",
|
||||
None,
|
||||
"Unknown",
|
||||
),
|
||||
model(
|
||||
0xFF,
|
||||
100000000,
|
||||
1100000000,
|
||||
14,
|
||||
"(Band capabilities unknown)",
|
||||
None,
|
||||
"Unknown",
|
||||
),
|
||||
model(0xA4, Some("rnode_firmware.hex")),
|
||||
model(0xA9, Some("rnode_firmware.hex")),
|
||||
model(0xA1, Some("rnode_firmware_t3s3.zip")),
|
||||
model(0xA6, Some("rnode_firmware_t3s3.zip")),
|
||||
model(0xA5, Some("rnode_firmware_t3s3_sx127x.zip")),
|
||||
model(0xAA, Some("rnode_firmware_t3s3_sx127x.zip")),
|
||||
model(0xAC, Some("rnode_firmware_t3s3_sx1280_pa.zip")),
|
||||
model(0xA2, Some("rnode_firmware_ng21.zip")),
|
||||
model(0xA7, Some("rnode_firmware_ng21.zip")),
|
||||
model(0xA3, Some("rnode_firmware_ng20.zip")),
|
||||
model(0xA8, Some("rnode_firmware_ng20.zip")),
|
||||
model(0xB3, Some("rnode_firmware_lora32v20.zip")),
|
||||
model(0xB8, Some("rnode_firmware_lora32v20.zip")),
|
||||
model(0xB4, Some("rnode_firmware_lora32v21.zip")),
|
||||
model(0xB9, Some("rnode_firmware_lora32v21.zip")),
|
||||
model(MODEL_B4_TCXO, Some("rnode_firmware_lora32v21_tcxo.zip")),
|
||||
model(MODEL_B9_TCXO, Some("rnode_firmware_lora32v21_tcxo.zip")),
|
||||
model(0xBA, Some("rnode_firmware_lora32v10.zip")),
|
||||
model(0xBB, Some("rnode_firmware_lora32v10.zip")),
|
||||
model(0xC4, Some("rnode_firmware_heltec32v2.zip")),
|
||||
model(0xC9, Some("rnode_firmware_heltec32v2.zip")),
|
||||
model(0xC5, Some("rnode_firmware_heltec32v3.zip")),
|
||||
model(0xCA, Some("rnode_firmware_heltec32v3.zip")),
|
||||
model(0xC8, Some("rnode_firmware_heltec32v4pa.zip")),
|
||||
model(0xC6, Some("rnode_firmware_heltec_t114.zip")),
|
||||
model(0xC7, Some("rnode_firmware_heltec_t114.zip")),
|
||||
model(0xE4, Some("rnode_firmware_tbeam.zip")),
|
||||
model(0xE9, Some("rnode_firmware_tbeam.zip")),
|
||||
model(0xD4, Some("rnode_firmware_tdeck.zip")),
|
||||
model(0xD9, Some("rnode_firmware_tdeck.zip")),
|
||||
model(0xDB, Some("rnode_firmware_tbeam_supreme.zip")),
|
||||
model(0xDC, Some("rnode_firmware_tbeam_supreme.zip")),
|
||||
model(0xE3, Some("rnode_firmware_tbeam_sx1262.zip")),
|
||||
model(0xE8, Some("rnode_firmware_tbeam_sx1262.zip")),
|
||||
model(0x11, Some("rnode_firmware_rak4631.zip")),
|
||||
model(0x12, Some("rnode_firmware_rak4631.zip")),
|
||||
model(0x13, Some("rnode_firmware_rak4631_sx1280.zip")),
|
||||
model(0x14, Some("rnode_firmware_rak4631_sx1280.zip")),
|
||||
model(0x16, Some("rnode_firmware_techo.zip")),
|
||||
model(0x17, Some("rnode_firmware_techo.zip")),
|
||||
model(0x21, Some("rnode_firmware_opencom_xl.zip")),
|
||||
model(0xDE, Some("rnode_firmware_xiao_esp32s3.zip")),
|
||||
model(0xDD, Some("rnode_firmware_xiao_esp32s3.zip")),
|
||||
model(0xFE, None),
|
||||
model(0xFF, None),
|
||||
];
|
||||
|
||||
const fn model(
|
||||
model: u8,
|
||||
min_frequency: u32,
|
||||
max_frequency: u32,
|
||||
max_tx_power: u8,
|
||||
band_label: &'static str,
|
||||
firmware_filename: Option<&'static str>,
|
||||
radio: &'static str,
|
||||
) -> ModelInfo {
|
||||
const fn model(model: u8, firmware_filename: Option<&'static str>) -> ModelInfo {
|
||||
ModelInfo {
|
||||
model,
|
||||
min_frequency,
|
||||
max_frequency,
|
||||
max_tx_power,
|
||||
band_label,
|
||||
firmware_filename,
|
||||
radio,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -480,28 +106,6 @@ pub fn normalize_eeprom_model(model: u8) -> u8 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn product_name(product: u8) -> Option<&'static str> {
|
||||
Some(match product {
|
||||
PRODUCT_RNODE => "RNode",
|
||||
PRODUCT_HMBRW => "Hombrew RNode",
|
||||
PRODUCT_TBEAM => "LilyGO T-Beam",
|
||||
PRODUCT_TBEAM_S_V1 => "LilyGO T-Beam Supreme",
|
||||
PRODUCT_TDECK => "LilyGO T-Deck",
|
||||
PRODUCT_T32_10 => "LilyGO LoRa32 v1.0",
|
||||
PRODUCT_T32_20 => "LilyGO LoRa32 v2.0",
|
||||
PRODUCT_T32_21 => "LilyGO LoRa32 v2.1",
|
||||
PRODUCT_H32_V2 => "Heltec LoRa32 v2",
|
||||
PRODUCT_H32_V3 => "Heltec LoRa32 v3",
|
||||
PRODUCT_H32_V4 => "Heltec LoRa32 v4",
|
||||
PRODUCT_TECHO => "LilyGO T-Echo",
|
||||
PRODUCT_RAK4631 => "RAK4631",
|
||||
PRODUCT_OPENCOM_XL => "openCom XL",
|
||||
PRODUCT_HELTEC_T114 => "Heltec Mesh Node T114",
|
||||
PRODUCT_XIAO_S3 => "Seeed XIAO ESP32S3 Wio-SX1262",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn platform_name(platform: u8) -> Option<&'static str> {
|
||||
Some(match platform {
|
||||
PLATFORM_AVR => "AVR",
|
||||
|
|
@ -526,7 +130,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn model_table_matches_upstream_shape() {
|
||||
fn model_table_retains_only_firmware_planning_metadata() {
|
||||
assert_eq!(MODELS.len(), 45);
|
||||
assert_eq!(
|
||||
model_info(0xA4).unwrap().firmware_filename,
|
||||
|
|
@ -537,7 +141,7 @@ mod tests {
|
|||
Some("rnode_firmware_t3s3_sx1280_pa.zip")
|
||||
);
|
||||
assert_eq!(model_info(0xFE).unwrap().firmware_filename, None);
|
||||
assert_eq!(model_info(0xFF).unwrap().max_tx_power, 14);
|
||||
assert_eq!(model_info(0xFF).unwrap().firmware_filename, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -548,8 +152,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn names_match_upstream_spellings() {
|
||||
assert_eq!(product_name(PRODUCT_HMBRW), Some("Hombrew RNode"));
|
||||
fn platform_and_mcu_names_match_upstream_spellings() {
|
||||
assert_eq!(platform_name(PLATFORM_ESP32), Some("ESP32"));
|
||||
assert_eq!(mcu_name(MCU_NRF52), Some("Nordic Semiconductor nRF52840"));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue