0
0
Fork 0

feat: Add L76K GNSS

This commit is contained in:
Jannik Beyerstedt 2026-05-11 23:52:35 +02:00
commit 919065f377
3 changed files with 205 additions and 8 deletions

69
Cargo.lock generated
View file

@ -17,6 +17,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c583acf993cf4245c4acb0a2cc2ab1f9cc097de73411bb6d3647ff6af2b1013d" checksum = "c583acf993cf4245c4acb0a2cc2ab1f9cc097de73411bb6d3647ff6af2b1013d"
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.5.0" version = "1.5.0"
@ -92,6 +98,15 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chrono"
version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "const-default" name = "const-default"
version = "1.0.0" version = "1.0.0"
@ -425,6 +440,21 @@ dependencies = [
"heapless 0.9.2", "heapless 0.9.2",
] ]
[[package]]
name = "embassy_gps"
version = "0.1.0"
source = "git+https://github.com/jbeyerstedt/embassy_gps.git?branch=feat%2Frework-gpsfix#75f1a67a69372234330c0c9618a953c415380b99"
dependencies = [
"chrono",
"embassy-futures",
"embassy-time",
"embedded-io-async 0.7.0",
"esp-hal",
"heapless 0.9.2",
"log",
"nmea",
]
[[package]] [[package]]
name = "embedded-can" name = "embedded-can"
version = "0.4.1" version = "0.4.1"
@ -903,9 +933,11 @@ dependencies = [
name = "esp32-c_its-companion" name = "esp32-c_its-companion"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono",
"critical-section", "critical-section",
"embassy-executor", "embassy-executor",
"embassy-time", "embassy-time",
"embassy_gps",
"embedded-io 0.7.1", "embedded-io 0.7.1",
"embedded-io-async 0.7.0", "embedded-io-async 0.7.0",
"esp-alloc", "esp-alloc",
@ -1183,6 +1215,12 @@ version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "libm"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]] [[package]]
name = "linked_list_allocator" name = "linked_list_allocator"
version = "0.10.6" version = "0.10.6"
@ -1229,6 +1267,12 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "nb" name = "nb"
version = "0.1.3" version = "0.1.3"
@ -1244,6 +1288,30 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
[[package]]
name = "nmea"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2086c773d18da556c05ca235596d163c00379027189bafe2209ae40ebd19717c"
dependencies = [
"arrayvec",
"cfg-if",
"chrono",
"heapless 0.8.0",
"nom",
"num-traits",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.50.3" version = "0.50.3"
@ -1271,6 +1339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"libm",
] ]
[[package]] [[package]]

View file

@ -43,6 +43,8 @@ esp-radio = { version = "0.18.0", features = [
"sniffer", "sniffer",
] } ] }
embassy_gps = { version = "0.1.0", default-features = false, features = ["esp", "log-04"], git = "https://github.com/jbeyerstedt/embassy_gps.git", branch = "feat/rework-gpsfix" }
chrono = { version = "0.4.44", default-features = false, features = ["alloc"] }
# For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html # For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html
[profile.dev] [profile.dev]

View file

@ -5,10 +5,13 @@
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \ reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer." holding buffers for the duration of a data transfer."
)] )]
#![deny(clippy::large_stack_frames)] // #![deny(clippy::large_stack_frames)]
use core::cell::RefCell;
use critical_section::Mutex;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_time::{Duration, Timer}; use embassy_gps::gps::l76k;
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal::clock::CpuClock; use esp_hal::clock::CpuClock;
use esp_hal::timer::timg::TimerGroup; use esp_hal::timer::timg::TimerGroup;
@ -21,10 +24,68 @@ mod radio;
const WIFI_CHANNEL: radio::Channel = 180; const WIFI_CHANNEL: radio::Channel = 180;
#[derive(Debug, Default)]
struct State {
initialized: bool,
time: chrono::NaiveDateTime,
lat_deg: f32,
lon_deg: f32,
heading_deg: Option<f32>,
speed_mps: Option<f32>,
}
impl State {
fn update_with_gpsfix(&mut self, fix: &embassy_gps::types::GpsFix) {
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
let lat_deg = fix.latitude_deg as f32;
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
let lon_deg = fix.longitude_deg as f32;
self.lat_deg = lat_deg;
self.lon_deg = lon_deg;
if let Some(heading) = fix.true_course_deg {
self.heading_deg = Some(heading);
} else {
warn!("State: Course missing from GpsFix");
}
if let Some(speed) = fix.speed_over_ground {
self.speed_mps = Some(speed);
} else {
warn!("State: Speed missing from GpsFix");
}
if let Some(time) = fix.get_timestamp() {
self.time = time;
if !self.initialized {
info!("GNSS fix: {}", self.print_fix());
}
self.initialized = true;
}
}
fn print_fix(&self) -> alloc::string::String {
alloc::format!(
"{:?}, {:.4} N, {:.4} E, {:.0}°, {:.2} m/s",
self.time,
self.lat_deg,
self.lon_deg,
self.heading_deg.unwrap_or_default(),
self.speed_mps.unwrap_or_default(),
)
}
}
// This creates a default app-descriptor required by the esp-idf bootloader. // This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description> // For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
esp_bootloader_esp_idf::esp_app_desc!(); esp_bootloader_esp_idf::esp_app_desc!();
static GNSS_UPDATE: Mutex<RefCell<Option<embassy_gps::types::GpsFix>>> =
Mutex::new(RefCell::new(None));
#[allow( #[allow(
clippy::large_stack_frames, clippy::large_stack_frames,
reason = "it's not unusual to allocate larger buffers etc. in main" reason = "it's not unusual to allocate larger buffers etc. in main"
@ -70,13 +131,39 @@ async fn main(spawner: Spawner) -> ! {
info!("WiFi promiscuous mode on channel {WIFI_CHANNEL} running"); info!("WiFi promiscuous mode on channel {WIFI_CHANNEL} running");
// TODO: Spawn some tasks // Seeed XIAO L67K:
let _ = spawner; // RX: D7/ GPIO12
// TX: D6/ GPIO11
// WAKEUP: D0/ GPIO1 -> HIGH for active, LOW for Sleep
// RESET: D2/ GPIO25 -> HIGH for normal, LOW for Reset
spawner.spawn(
gnss_task(
peripherals.GPIO1,
peripherals.GPIO25,
peripherals.UART0,
peripherals.GPIO12,
peripherals.GPIO11,
)
.expect("Failed to spawn GNSS task"),
);
info!("GNSS task started, waiting for GNSS fix...");
let mut state = State::default();
loop { loop {
// nothing to do here, all data is handled in RX callback for now embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await;
// but use a timer so that this is yields to other tasks
Timer::after(Duration::from_secs(1)).await; critical_section::with(|cs| {
let gnss_update_ref = GNSS_UPDATE.borrow(cs);
if let Some(fix) = gnss_update_ref.replace(None) {
state.update_with_gpsfix(&fix);
if let Some(time) = fix.get_timestamp() {
state.time = time;
info!("{}", state.print_fix()); // TODO: degrate to debug later?
}
}
});
} }
} }
@ -99,3 +186,42 @@ fn handle_frame(frame: wifi::sniffer::PromiscuousPkt<'_>) {
// TODO: handle 802.11 frame // TODO: handle 802.11 frame
info!("Received frame with {} bytes", frame.len); info!("Received frame with {} bytes", frame.len);
} }
#[allow(clippy::large_stack_frames, reason = "GNSS driver needs some space")]
#[embassy_executor::task]
async fn gnss_task(
gps_wakeup: esp_hal::peripherals::GPIO1<'static>,
gps_reset: esp_hal::peripherals::GPIO25<'static>,
uart: esp_hal::peripherals::UART0<'static>,
uart_rx: esp_hal::peripherals::GPIO12<'static>,
uart_tx: esp_hal::peripherals::GPIO11<'static>,
) {
use embassy_gps::gps::GpsFsm;
let mut gps = l76k::esp::L76kFsm::new_sep(
l76k::esp::GpsHw {
reinit: gps_reset,
standby: gps_wakeup,
},
|| {
esp_hal::uart::Uart::new(uart, esp_hal::uart::Config::default().with_baudrate(9600))
.expect("Failed to create UART for GNSS")
.with_rx(uart_rx)
.with_tx(uart_tx)
.into_async()
},
)
.await;
loop {
if let Ok(Some(embassy_gps::types::GpsEvent::Fix(fix))) = gps.step().await {
// send to main thread
critical_section::with(|cs| {
let gnss_update_ref = GNSS_UPDATE.borrow(cs);
gnss_update_ref.replace(Some(fix));
});
} else {
// FSM will recover automatically from errors and ignore other event types
}
}
}