feat: Add L76K GNSS
This commit is contained in:
parent
c589605407
commit
919065f377
3 changed files with 205 additions and 8 deletions
140
src/main.rs
140
src/main.rs
|
|
@ -5,10 +5,13 @@
|
|||
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
|
||||
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_time::{Duration, Timer};
|
||||
use embassy_gps::gps::l76k;
|
||||
use esp_backtrace as _;
|
||||
use esp_hal::clock::CpuClock;
|
||||
use esp_hal::timer::timg::TimerGroup;
|
||||
|
|
@ -21,10 +24,68 @@ mod radio;
|
|||
|
||||
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.
|
||||
// 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!();
|
||||
|
||||
static GNSS_UPDATE: Mutex<RefCell<Option<embassy_gps::types::GpsFix>>> =
|
||||
Mutex::new(RefCell::new(None));
|
||||
|
||||
#[allow(
|
||||
clippy::large_stack_frames,
|
||||
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");
|
||||
|
||||
// TODO: Spawn some tasks
|
||||
let _ = spawner;
|
||||
// Seeed XIAO L67K:
|
||||
// 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 {
|
||||
// nothing to do here, all data is handled in RX callback for now
|
||||
// but use a timer so that this is yields to other tasks
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).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
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue