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

Target

Select target project
  • cats/mobile-transceiver-software
  • Reed/mobile-transceiver-software
  • xanarin/mobile-transceiver-software
3 results
Show changes
Commits on Source (3)
......@@ -65,6 +65,15 @@ dependencies = [
"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]]
name = "byteorder"
version = "1.5.0"
......@@ -76,6 +85,7 @@ name = "cats-mobile-transceiver-mainboard"
version = "0.2.1"
dependencies = [
"arrayvec",
"bme280",
"cortex-m",
"cortex-m-rt",
"cortex-m-rtic",
......
......@@ -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"] }
postcard = "1.0.8"
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 }>;
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [USART1, USART6])]
mod app {
use core::fmt::Write;
use arrayvec::ArrayString;
use bme280::i2c::BME280;
use cortex_m::singleton;
use hal::{
adc::{config::AdcConfig, Adc},
......@@ -39,7 +43,12 @@ mod app {
packet::Packet,
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 usb_device::prelude::*;
......@@ -70,6 +79,8 @@ mod app {
#[monotonic(binds = SysTick, default = true)]
type MyMono = Systick<{ SYS_TICK_FREQ }>;
pub type MyBme280 = BME280<I2c<I2C1>, Delay<TIM11, 1000>>;
#[local]
struct Local {
green: gpio::Pin<'B', 15, gpio::Output>,
......@@ -88,6 +99,7 @@ mod app {
radio: Option<RadioManager<'static>>,
gps: GpsModule,
volt_meter: VoltMeter,
bme280: MyBme280,
usb_dev: UsbDevice<'static, UsbBusType>,
shell: Shell,
......@@ -129,8 +141,18 @@ mod app {
// setup volt meter
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 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
let usb_detect = gpioa.pa5.into_pull_down_input();
......@@ -178,6 +200,19 @@ mod app {
.with_u8_data();
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
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
static mut USB_BUS: Option<usb_device::bus::UsbBusAllocator<UsbBusType>> = None;
......@@ -245,6 +280,7 @@ mod app {
radio,
gps: GpsModule::new(),
volt_meter,
bme280,
usb_dev,
shell,
......@@ -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) {
let mut config = ctx.shared.config;
let (black_hole, transmit_period_seconds) =
......@@ -306,7 +342,10 @@ mod app {
let mut buf = [0; MAX_PACKET_LEN];
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
.shared
.radio
......@@ -315,6 +354,14 @@ mod app {
.to_secs()
.try_into()
.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()
.hardware_id(HARDWARE_ID)
......@@ -331,9 +378,14 @@ mod app {
})
.unwrap();
if !config.comment.is_empty() {
cats.add_comment(&config.comment).unwrap();
}
let mut buf: ArrayString<64> = ArrayString::new();
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();
......@@ -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) {
let usb_fs::SharedResources {
mut usb_dev,
mut shell,
mut volt_meter,
mut bme280,
} = cx.shared;
(&mut usb_dev, &mut shell).lock(|usb_dev, shell| {
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;
use ushell::{autocomplete::StaticAutocomplete, history::LRUHistory, Input, ShellError, UShell};
use crate::{
app::MyBme280,
config::{BlackHoleSetting, Config, Frequency, GpsSetting, Maybe, MaybeBlackHole},
voltage::VoltMeter,
};
......@@ -54,7 +55,12 @@ impl Shell {
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 {
let ushell = &mut self.ushell;
match ushell.poll() {
......@@ -256,6 +262,29 @@ impl Shell {
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" => {
write!(ushell, "{}", HELP_TEXT).ok();
}
......
......@@ -8,20 +8,49 @@ const FACTOR: f64 = 1.0 / 0.0757856;
pub struct VoltMeter {
pin: Pin<'C', 0, Analog>,
sensor1: Pin<'C', 2, Analog>,
sensor2: Pin<'C', 3, Analog>,
sensor3: Pin<'C', 4, Analog>,
adc: Adc<ADC1>,
threshold: Option<f32>,
}
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();
Self {
pin,
sensor1,
sensor2,
sensor3,
adc,
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 {
let sample = self.adc.convert(&self.pin, SampleTime::Cycles_480);
let mv = self.adc.sample_to_millivolts(sample);
......