Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • cats/mobile-transceiver-software
  • Reed/mobile-transceiver-software
  • xanarin/mobile-transceiver-software
3 results
Select Git revision
Show changes
Commits on Source (3)
...@@ -65,6 +65,15 @@ dependencies = [ ...@@ -65,6 +65,15 @@ dependencies = [
"wyz", "wyz",
] ]
[[package]]
name = "bme280"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32c139eaf2284d0c91a25f61d84dd326444cace86cb0371f45d71d2d055ba432"
dependencies = [
"embedded-hal 0.2.7",
]
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.5.0" version = "1.5.0"
...@@ -76,6 +85,7 @@ name = "cats-mobile-transceiver-mainboard" ...@@ -76,6 +85,7 @@ name = "cats-mobile-transceiver-mainboard"
version = "0.2.1" version = "0.2.1"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bme280",
"cortex-m", "cortex-m",
"cortex-m-rt", "cortex-m-rt",
"cortex-m-rtic", "cortex-m-rtic",
......
...@@ -36,3 +36,4 @@ num-traits = { version = "0.2.17", default-features = false, features = ["libm"] ...@@ -36,3 +36,4 @@ num-traits = { version = "0.2.17", default-features = false, features = ["libm"]
rand = { version = "0.8", default-features = false, features = ["small_rng"] } rand = { version = "0.8", default-features = false, features = ["small_rng"] }
postcard = "1.0.8" postcard = "1.0.8"
serde = { version = "1.0.196", default-features = false, features = ["derive"] } serde = { version = "1.0.196", default-features = false, features = ["derive"] }
bme280 = { version = "0.3", default-features = false }
...@@ -21,6 +21,10 @@ pub type MyInstant = Instant<u64, 1, { SYS_TICK_FREQ }>; ...@@ -21,6 +21,10 @@ pub type MyInstant = Instant<u64, 1, { SYS_TICK_FREQ }>;
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [USART1, USART6])] #[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [USART1, USART6])]
mod app { mod app {
use core::fmt::Write;
use arrayvec::ArrayString;
use bme280::i2c::BME280;
use cortex_m::singleton; use cortex_m::singleton;
use hal::{ use hal::{
adc::{config::AdcConfig, Adc}, adc::{config::AdcConfig, Adc},
...@@ -39,7 +43,12 @@ mod app { ...@@ -39,7 +43,12 @@ mod app {
packet::Packet, packet::Packet,
whisker::{Gps, NodeInfoBuilder, Route}, whisker::{Gps, NodeInfoBuilder, Route},
}; };
use stm32f4xx_hal as hal; use stm32f4xx_hal::{
self as hal,
i2c::I2c,
pac::{I2C1, TIM11},
timer::Delay,
};
use systick_monotonic::{fugit::Instant, ExtU64, Systick}; use systick_monotonic::{fugit::Instant, ExtU64, Systick};
use usb_device::prelude::*; use usb_device::prelude::*;
...@@ -70,6 +79,8 @@ mod app { ...@@ -70,6 +79,8 @@ mod app {
#[monotonic(binds = SysTick, default = true)] #[monotonic(binds = SysTick, default = true)]
type MyMono = Systick<{ SYS_TICK_FREQ }>; type MyMono = Systick<{ SYS_TICK_FREQ }>;
pub type MyBme280 = BME280<I2c<I2C1>, Delay<TIM11, 1000>>;
#[local] #[local]
struct Local { struct Local {
green: gpio::Pin<'B', 15, gpio::Output>, green: gpio::Pin<'B', 15, gpio::Output>,
...@@ -88,6 +99,7 @@ mod app { ...@@ -88,6 +99,7 @@ mod app {
radio: Option<RadioManager<'static>>, radio: Option<RadioManager<'static>>,
gps: GpsModule, gps: GpsModule,
volt_meter: VoltMeter, volt_meter: VoltMeter,
bme280: MyBme280,
usb_dev: UsbDevice<'static, UsbBusType>, usb_dev: UsbDevice<'static, UsbBusType>,
shell: Shell, shell: Shell,
...@@ -129,8 +141,18 @@ mod app { ...@@ -129,8 +141,18 @@ mod app {
// setup volt meter // setup volt meter
let volt_pin = gpioc.pc0.into_analog(); let volt_pin = gpioc.pc0.into_analog();
let sensor1 = gpioc.pc2.into_analog();
let sensor2 = gpioc.pc3.into_analog();
let sensor3 = gpioc.pc4.into_analog();
let volt_adc = Adc::adc1(dp.ADC1, true, AdcConfig::default()); let volt_adc = Adc::adc1(dp.ADC1, true, AdcConfig::default());
let mut volt_meter = VoltMeter::new(volt_pin, volt_adc, config.min_voltage.into()); let mut volt_meter = VoltMeter::new(
volt_pin,
sensor1,
sensor2,
sensor3,
volt_adc,
config.min_voltage.into(),
);
// Detect if we're connected to USB or not // Detect if we're connected to USB or not
let usb_detect = gpioa.pa5.into_pull_down_input(); let usb_detect = gpioa.pa5.into_pull_down_input();
...@@ -178,6 +200,19 @@ mod app { ...@@ -178,6 +200,19 @@ mod app {
.with_u8_data(); .with_u8_data();
gps_serial.listen(serial::Event::Rxne); gps_serial.listen(serial::Event::Rxne);
// Set up BME280
let scl = gpiob.pb8;
let sda = gpiob.pb9;
let i2c = I2c::new(
dp.I2C1,
(scl, sda),
hal::i2c::Mode::standard(100.kHz()),
&clocks,
);
let mut bme280 = BME280::new_primary(i2c, dp.TIM11.delay_ms(&clocks));
let _ = bme280.init();
// Setup USB // Setup USB
static mut EP_MEMORY: [u32; 1024] = [0; 1024]; static mut EP_MEMORY: [u32; 1024] = [0; 1024];
static mut USB_BUS: Option<usb_device::bus::UsbBusAllocator<UsbBusType>> = None; static mut USB_BUS: Option<usb_device::bus::UsbBusAllocator<UsbBusType>> = None;
...@@ -245,6 +280,7 @@ mod app { ...@@ -245,6 +280,7 @@ mod app {
radio, radio,
gps: GpsModule::new(), gps: GpsModule::new(),
volt_meter, volt_meter,
bme280,
usb_dev, usb_dev,
shell, shell,
...@@ -279,7 +315,7 @@ mod app { ...@@ -279,7 +315,7 @@ mod app {
} }
} }
#[task(priority = 2, local = [buf, bootup_time], shared = [red, radio, gps, config, status, volt_meter])] #[task(priority = 2, local = [buf, bootup_time], shared = [red, radio, gps, config, status, volt_meter, bme280])]
fn transmit_position(mut ctx: transmit_position::Context) { fn transmit_position(mut ctx: transmit_position::Context) {
let mut config = ctx.shared.config; let mut config = ctx.shared.config;
let (black_hole, transmit_period_seconds) = let (black_hole, transmit_period_seconds) =
...@@ -306,7 +342,10 @@ mod app { ...@@ -306,7 +342,10 @@ mod app {
let mut buf = [0; MAX_PACKET_LEN]; let mut buf = [0; MAX_PACKET_LEN];
let mut cats = Packet::new(&mut buf); let mut cats = Packet::new(&mut buf);
let voltage = ctx.shared.volt_meter.lock(|vm| vm.voltage()); let (sensors, voltage) = ctx
.shared
.volt_meter
.lock(|vm| (vm.sensors(), vm.voltage()));
let temp = ctx let temp = ctx
.shared .shared
.radio .radio
...@@ -315,6 +354,14 @@ mod app { ...@@ -315,6 +354,14 @@ mod app {
.to_secs() .to_secs()
.try_into() .try_into()
.unwrap_or(0); .unwrap_or(0);
let (temperature, pressure, humidity) = ctx.shared.bme280.lock(|b| match b.measure() {
Ok(o) => (o.temperature, o.pressure, o.humidity),
Err(_) => {
let _ = b.init(); // hail mary attempt
(0.0, 0.0, 0.0)
}
});
let mut info_builder = NodeInfoBuilder::default() let mut info_builder = NodeInfoBuilder::default()
.hardware_id(HARDWARE_ID) .hardware_id(HARDWARE_ID)
...@@ -331,9 +378,14 @@ mod app { ...@@ -331,9 +378,14 @@ mod app {
}) })
.unwrap(); .unwrap();
if !config.comment.is_empty() { let mut buf: ArrayString<64> = ArrayString::new();
cats.add_comment(&config.comment).unwrap(); write!(
} &mut buf,
"{} {} {} {} {} {}",
sensors[0], sensors[1], sensors[2], temperature, pressure, humidity
)
.unwrap();
cats.add_comment(&buf).unwrap();
cats.add_route(Route::new(config.max_hops)).unwrap(); cats.add_route(Route::new(config.max_hops)).unwrap();
...@@ -451,17 +503,18 @@ mod app { ...@@ -451,17 +503,18 @@ mod app {
} }
} }
#[task(binds=OTG_FS, priority = 2, local=[flash], shared=[usb_dev, shell, volt_meter])] #[task(binds=OTG_FS, priority = 2, local=[flash], shared=[usb_dev, shell, volt_meter,bme280])]
fn usb_fs(cx: usb_fs::Context) { fn usb_fs(cx: usb_fs::Context) {
let usb_fs::SharedResources { let usb_fs::SharedResources {
mut usb_dev, mut usb_dev,
mut shell, mut shell,
mut volt_meter, mut volt_meter,
mut bme280,
} = cx.shared; } = cx.shared;
(&mut usb_dev, &mut shell).lock(|usb_dev, shell| { (&mut usb_dev, &mut shell).lock(|usb_dev, shell| {
while usb_dev.poll(&mut [shell.ushell.get_serial_mut()]) { while usb_dev.poll(&mut [shell.ushell.get_serial_mut()]) {
shell.poll(cx.local.flash, &mut volt_meter); shell.poll(cx.local.flash, &mut volt_meter, &mut bme280);
} }
}); });
} }
......
...@@ -10,6 +10,7 @@ use usbd_serial::SerialPort; ...@@ -10,6 +10,7 @@ use usbd_serial::SerialPort;
use ushell::{autocomplete::StaticAutocomplete, history::LRUHistory, Input, ShellError, UShell}; use ushell::{autocomplete::StaticAutocomplete, history::LRUHistory, Input, ShellError, UShell};
use crate::{ use crate::{
app::MyBme280,
config::{BlackHoleSetting, Config, Frequency, GpsSetting, Maybe, MaybeBlackHole}, config::{BlackHoleSetting, Config, Frequency, GpsSetting, Maybe, MaybeBlackHole},
voltage::VoltMeter, voltage::VoltMeter,
}; };
...@@ -54,7 +55,12 @@ impl Shell { ...@@ -54,7 +55,12 @@ impl Shell {
Self { ushell, config } Self { ushell, config }
} }
pub fn poll<V: Mutex<T = VoltMeter>>(&mut self, flash: &mut LockedFlash, volt_meter: &mut V) { pub fn poll<V: Mutex<T = VoltMeter>, B: Mutex<T = MyBme280>>(
&mut self,
flash: &mut LockedFlash,
volt_meter: &mut V,
bme280: &mut B,
) {
loop { loop {
let ushell = &mut self.ushell; let ushell = &mut self.ushell;
match ushell.poll() { match ushell.poll() {
...@@ -256,6 +262,29 @@ impl Shell { ...@@ -256,6 +262,29 @@ impl Shell {
write!(ushell, "\r\n{volts:.2} V\r\n").ok(); write!(ushell, "\r\n{volts:.2} V\r\n").ok();
} }
"sensors" => {
let sensors = volt_meter.lock(|vm| vm.sensors());
write!(
ushell,
"\r\nS1: {} mV\r\nS2: {} mV\r\nS3: {} mV\r\n",
sensors[0], sensors[1], sensors[2]
)
.ok();
}
"bme280" => match bme280.lock(|b| b.measure()) {
Ok(m) => {
write!(
ushell,
"\r\nTemperature: {} deg C\r\nPressure: {} pascals\r\nHumidity: {}%\r\n",
m.temperature, m.pressure, m.humidity
).ok();
}
Err(e) => {
write!(ushell, "Could not communicate with the bme280: {:?}", e)
.ok();
}
},
"help" => { "help" => {
write!(ushell, "{}", HELP_TEXT).ok(); write!(ushell, "{}", HELP_TEXT).ok();
} }
......
...@@ -8,20 +8,49 @@ const FACTOR: f64 = 1.0 / 0.0757856; ...@@ -8,20 +8,49 @@ const FACTOR: f64 = 1.0 / 0.0757856;
pub struct VoltMeter { pub struct VoltMeter {
pin: Pin<'C', 0, Analog>, pin: Pin<'C', 0, Analog>,
sensor1: Pin<'C', 2, Analog>,
sensor2: Pin<'C', 3, Analog>,
sensor3: Pin<'C', 4, Analog>,
adc: Adc<ADC1>, adc: Adc<ADC1>,
threshold: Option<f32>, threshold: Option<f32>,
} }
impl VoltMeter { impl VoltMeter {
pub fn new(pin: Pin<'C', 0, Analog>, mut adc: Adc<ADC1>, threshold: Option<f32>) -> Self { pub fn new(
pin: Pin<'C', 0, Analog>,
sensor1: Pin<'C', 2, Analog>,
sensor2: Pin<'C', 3, Analog>,
sensor3: Pin<'C', 4, Analog>,
mut adc: Adc<ADC1>,
threshold: Option<f32>,
) -> Self {
adc.calibrate(); adc.calibrate();
Self { Self {
pin, pin,
sensor1,
sensor2,
sensor3,
adc, adc,
threshold, threshold,
} }
} }
pub fn sensors(&mut self) -> [u16; 3] {
let samples = [
self.adc.convert(&self.sensor1, SampleTime::Cycles_480),
self.adc.convert(&self.sensor2, SampleTime::Cycles_480),
self.adc.convert(&self.sensor3, SampleTime::Cycles_480),
];
let mut out = [0; 3];
for (i, s) in samples.iter().enumerate() {
out[i] = self.adc.sample_to_millivolts(*s);
}
out
}
pub fn voltage(&mut self) -> f64 { pub fn voltage(&mut self) -> f64 {
let sample = self.adc.convert(&self.pin, SampleTime::Cycles_480); let sample = self.adc.convert(&self.pin, SampleTime::Cycles_480);
let mv = self.adc.sample_to_millivolts(sample); let mv = self.adc.sample_to_millivolts(sample);
......