sensor and esp and canable call all communicate with each other.
This commit is contained in:
40
Software/CAN_Sensor/Cargo.lock
generated
40
Software/CAN_Sensor/Cargo.lock
generated
@@ -20,6 +20,25 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"unty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.3"
|
||||
@@ -36,6 +55,7 @@ checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
|
||||
name = "bms"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"canapi",
|
||||
"ch32-hal",
|
||||
"embassy-executor",
|
||||
"embassy-futures",
|
||||
@@ -45,6 +65,7 @@ dependencies = [
|
||||
"embedded-alloc",
|
||||
"embedded-can",
|
||||
"heapless",
|
||||
"log",
|
||||
"panic-halt",
|
||||
"qingke",
|
||||
"qingke-rt",
|
||||
@@ -57,6 +78,13 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "canapi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
@@ -778,6 +806,12 @@ version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
|
||||
|
||||
[[package]]
|
||||
name = "unty"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "usb-device"
|
||||
version = "0.3.2"
|
||||
@@ -837,6 +871,12 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
|
||||
@@ -4,6 +4,8 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# Shared CAN API
|
||||
canapi = { path = "../Shared/canapi" }
|
||||
ch32-hal = { git = "https://github.com/empirephoenix/ch32-hal.git", features = [
|
||||
"ch32v203c8t6",
|
||||
"memory-x",
|
||||
@@ -38,6 +40,7 @@ panic-halt = "1.0"
|
||||
heapless = { version = "0.8.0", features = ["portable-atomic-critical-section"] }
|
||||
embassy-time = { version = "0.4.0" }
|
||||
static_cell = "2.1.1"
|
||||
log = "0.4.28"
|
||||
|
||||
[profile.dev]
|
||||
#lto = true
|
||||
|
||||
@@ -4,13 +4,14 @@ extern crate alloc;
|
||||
|
||||
use crate::hal::peripherals::CAN1;
|
||||
use core::fmt::Write as _;
|
||||
use canapi::id::{classify, plant_id, MessageKind, IDENTIFY_CMD_OFFSET, MOISTURE_DATA_OFFSET};
|
||||
use canapi::SensorSlot;
|
||||
use ch32_hal::gpio::{Level, Output, Speed};
|
||||
use ch32_hal::adc::{Adc, SampleTime, ADC_MAX};
|
||||
use ch32_hal::can;
|
||||
use ch32_hal::can::{Can, CanFifo, CanFilter, CanFrame, CanMode};
|
||||
use ch32_hal::mode::{Blocking};
|
||||
use ch32_hal::mode::{NonBlocking};
|
||||
use ch32_hal::peripherals::USBD;
|
||||
// use ch32_hal::delay::Delay;
|
||||
use embassy_executor::{Spawner, task};
|
||||
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
|
||||
use embassy_usb::{Builder, UsbDevice};
|
||||
@@ -19,9 +20,8 @@ use hal::usbd::{Driver};
|
||||
use hal::{bind_interrupts};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::{Channel};
|
||||
use embassy_time::{Instant, Duration};
|
||||
use embedded_can::blocking::Can as bcan;
|
||||
use embedded_can::StandardId;
|
||||
use embassy_time::{Instant, Duration, Delay, Timer};
|
||||
use embedded_can::{Id, StandardId};
|
||||
use {ch32_hal as hal, panic_halt as _};
|
||||
|
||||
macro_rules! mk_static {
|
||||
@@ -33,12 +33,15 @@ macro_rules! mk_static {
|
||||
}};
|
||||
}
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
USB_LP_CAN1_RX0 => hal::usbd::InterruptHandler<hal::peripherals::USBD>;
|
||||
});
|
||||
bind_interrupts!(struct Irqs {
|
||||
USB_LP_CAN1_RX0 => hal::usbd::InterruptHandler<hal::peripherals::USBD>;
|
||||
});
|
||||
|
||||
|
||||
use embedded_alloc::LlffHeap as Heap;
|
||||
use embedded_alloc::LlffHeap as Heap;
|
||||
use embedded_can::nb::Can as nb_can;
|
||||
use qingke::riscv::asm::delay;
|
||||
use log::log;
|
||||
|
||||
#[global_allocator]
|
||||
static HEAP: Heap = Heap::empty();
|
||||
@@ -49,7 +52,7 @@ static LOG_CH: Channel<CriticalSectionRawMutex, heapless::String<128>, 8> = Chan
|
||||
#[embassy_executor::main(entry = "qingke_rt::entry")]
|
||||
async fn main(spawner: Spawner) {
|
||||
ch32_hal::pac::AFIO.pcfr1().write(|w| w.set_can1_rm(2));
|
||||
|
||||
//
|
||||
unsafe {
|
||||
static mut HEAP_SPACE: [u8; 4096] = [0; 4096]; // 4 KiB heap, adjust as needed
|
||||
HEAP.init(HEAP_SPACE.as_ptr() as usize, HEAP_SPACE.len());
|
||||
@@ -103,20 +106,14 @@ async fn main(spawner: Spawner) {
|
||||
// Built-in LED on PB2 mirrors Q state
|
||||
let led = Output::new(p.PB2, Level::Low, Speed::Low);
|
||||
|
||||
let info = Output::new(p.PA3, Level::Low, Speed::Low);
|
||||
|
||||
// Create ADC on ADC1 and use PA1 as analog input (Threshold/Trigger)
|
||||
let adc = Adc::new(p.ADC1, Default::default());
|
||||
let ain = p.PA1;
|
||||
let config = can::can::Config::default();
|
||||
let can: Can<'static, CAN1 , Blocking> = Can::new_blocking(p.CAN1, p.PB8, p.PB9, CanFifo::Fifo1, CanMode::Normal, 125_000, config).expect("Valid");
|
||||
let mut filter = CanFilter::new_id_list();
|
||||
|
||||
filter
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.set(StandardId::new(0x580 | 0x42).unwrap().into(), Default::default());
|
||||
|
||||
can.add_filter(CanFilter::accept_all());
|
||||
|
||||
let can: Can<CAN1, NonBlocking> = Can::new_nb(p.CAN1, p.PB8, p.PB9, CanFifo::Fifo0, CanMode::Normal, 125_000, config).expect("Valid");
|
||||
ch32_hal::pac::AFIO.pcfr1().write(|w| w.set_can1_rm(2));
|
||||
|
||||
spawner.spawn(usb_task(usb)).unwrap();
|
||||
spawner.spawn(usb_writer(class)).unwrap();
|
||||
@@ -135,13 +132,28 @@ async fn worker(
|
||||
mut led: Output<'static>,
|
||||
mut adc: Adc<'static, hal::peripherals::ADC1>,
|
||||
mut ain: hal::peripherals::PA1,
|
||||
mut can: Can<'static, CAN1, Blocking>,
|
||||
mut can: Can<'static, CAN1, NonBlocking>,
|
||||
) {
|
||||
// 555 emulation state: Q initially Low
|
||||
let mut q_high = false;
|
||||
let low_th: u16 = (ADC_MAX as u16) / 3; // ~1/3 Vref
|
||||
let high_th: u16 = ((ADC_MAX as u32 * 2) / 3) as u16; // ~2/3 Vref
|
||||
|
||||
|
||||
let moisture_address = StandardId::new(plant_id(MOISTURE_DATA_OFFSET, SensorSlot::A, 0)).unwrap();
|
||||
let identity_address = StandardId::new(plant_id(IDENTIFY_CMD_OFFSET, SensorSlot::A, 0)).unwrap();
|
||||
|
||||
let mut filter = CanFilter::new_id_list();
|
||||
|
||||
filter
|
||||
.get(0)
|
||||
.unwrap()
|
||||
.set(identity_address.into(), Default::default());
|
||||
|
||||
can.add_filter(filter);
|
||||
//can.add_filter(CanFilter::accept_all());
|
||||
|
||||
|
||||
loop {
|
||||
// Count rising edges of Q in a 100 ms window
|
||||
let start = Instant::now();
|
||||
@@ -167,10 +179,8 @@ async fn worker(
|
||||
// Drive output pin accordingly
|
||||
if q_high {
|
||||
q.set_high();
|
||||
led.set_high();
|
||||
} else {
|
||||
q.set_low();
|
||||
led.set_low();
|
||||
}
|
||||
|
||||
// Count rising edges
|
||||
@@ -194,9 +204,9 @@ async fn worker(
|
||||
);
|
||||
log(msg);
|
||||
|
||||
let address = StandardId::new(0x580 | 0x42).unwrap();
|
||||
let moisture = CanFrame::new(address, &[freq_hz as u8]).unwrap();
|
||||
match bcan::transmit(&mut can, &moisture) {
|
||||
|
||||
let mut moisture = CanFrame::new(moisture_address, &[freq_hz as u8]).unwrap();
|
||||
match can.transmit(&mut moisture){
|
||||
Ok(..) => {
|
||||
let mut msg: heapless::String<128> = heapless::String::new();
|
||||
let _ = write!(
|
||||
@@ -206,18 +216,48 @@ async fn worker(
|
||||
log(msg);
|
||||
}
|
||||
Err(err) => {
|
||||
|
||||
|
||||
|
||||
let mut msg: heapless::String<128> = heapless::String::new();
|
||||
let _ = write!(
|
||||
&mut msg,
|
||||
"err {}"
|
||||
"err {:?}"
|
||||
,err
|
||||
);
|
||||
log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
yield_now().await;
|
||||
match can.receive() {
|
||||
Ok(frame) => {
|
||||
match frame.id() {
|
||||
Id::Standard(s_frame) => {
|
||||
let mut msg: heapless::String<128> = heapless::String::new();
|
||||
let _ = write!(
|
||||
&mut msg,
|
||||
"Received from canbus: {:?} ident is {:?} \r\n",
|
||||
s_frame.as_raw(),
|
||||
identity_address.as_raw()
|
||||
);
|
||||
log(msg);
|
||||
if s_frame.as_raw() == identity_address.as_raw() {
|
||||
for _ in 0..10 {
|
||||
Timer::after_millis(250).await;
|
||||
led.toggle();
|
||||
}
|
||||
led.set_low();
|
||||
}
|
||||
}
|
||||
Id::Extended(_) => {}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ partition_table = "partitions.csv"
|
||||
|
||||
[dependencies]
|
||||
# Shared CAN API
|
||||
canapi = { path = "canapi" }
|
||||
canapi = { path = "../../Shared/canapi" }
|
||||
#ESP stuff
|
||||
esp-bootloader-esp-idf = { version = "0.2.0", features = ["esp32c6"] }
|
||||
esp-hal = { version = "=1.0.0-rc.0", features = [
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
use crate::hal::Sensor;
|
||||
use bincode::{Decode, Encode};
|
||||
|
||||
pub(crate) const SENSOR_BASE_ADDRESS: u16 = 1000;
|
||||
#[derive(Debug, Clone, Copy, Encode, Decode)]
|
||||
pub(crate) struct AutoDetectRequest {}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Encode, Decode)]
|
||||
pub(crate) struct ResponseMoisture {
|
||||
pub plant: u8,
|
||||
pub sensor: Sensor,
|
||||
pub hz: u32,
|
||||
}
|
||||
@@ -11,13 +11,13 @@ use async_trait::async_trait;
|
||||
use bincode::config;
|
||||
use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_time::{Instant, Timer, WithTimeout};
|
||||
use embassy_time::{Duration, Instant, Timer, WithTimeout};
|
||||
use embedded_can::{Frame, Id};
|
||||
use esp_hal::gpio::Output;
|
||||
use esp_hal::i2c::master::I2c;
|
||||
use esp_hal::pcnt::unit::Unit;
|
||||
use esp_hal::twai::{EspTwaiFrame, StandardId, Twai, TwaiConfiguration};
|
||||
use esp_hal::{Blocking};
|
||||
use esp_hal::{Async, Blocking};
|
||||
use log::{error, info, warn};
|
||||
use pca9535::{GPIOBank, Pca9535Immediate, StandardExpanderInterface};
|
||||
|
||||
@@ -148,52 +148,8 @@ impl SensorImpl {
|
||||
}
|
||||
|
||||
let mut result = DetectionResult::default();
|
||||
loop {
|
||||
match as_async.receive_async().with_deadline(Instant::from_millis(100)).await {
|
||||
Ok(or) => {
|
||||
match or {
|
||||
Ok(can_frame) => {
|
||||
match can_frame.id() {
|
||||
Id::Standard(id) => {
|
||||
let rawid = id.as_raw();
|
||||
match classify(rawid) {
|
||||
None => {}
|
||||
Some(msg) => {
|
||||
if msg.0 == MessageKind::MoistureData {
|
||||
let plant = msg.1 as usize;
|
||||
let sensor = msg.2;
|
||||
match sensor {
|
||||
SensorSlot::A => {
|
||||
result.plant[plant].sensor_a = true;
|
||||
}
|
||||
SensorSlot::B => {
|
||||
result.plant[plant].sensor_b = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Id::Extended(ext) => {
|
||||
warn!("Received extended ID: {:?}", ext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Err(err ) => {
|
||||
error!("Error receiving CAN message: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
info!("Received CAN message: {:?}", or);
|
||||
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Timeout receiving CAN message: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wait for messages to arrive
|
||||
let _ = Self::wait_for_can_measurements(&mut as_async, &mut result).with_timeout(Duration::from_millis(5000)).await;
|
||||
|
||||
let config = as_async.stop().into_blocking();
|
||||
can_power.set_low();
|
||||
@@ -205,6 +161,46 @@ impl SensorImpl {
|
||||
}
|
||||
}
|
||||
|
||||
async fn wait_for_can_measurements(as_async: &mut Twai<'_, Async>, result: &mut DetectionResult) {
|
||||
loop {
|
||||
match as_async.receive_async().await {
|
||||
Ok(can_frame) => {
|
||||
match can_frame.id() {
|
||||
Id::Standard(id) => {
|
||||
info!("Received CAN message: {:?}", id);
|
||||
let rawid = id.as_raw();
|
||||
match classify(rawid) {
|
||||
None => {}
|
||||
Some(msg) => {
|
||||
info!("received message of kind {:?} (plant: {}, sensor: {:?})", msg.0, msg.1, msg.2);
|
||||
if msg.0 == MessageKind::MoistureData {
|
||||
let plant = msg.1 as usize;
|
||||
let sensor = msg.2;
|
||||
match sensor {
|
||||
SensorSlot::A => {
|
||||
result.plant[plant].sensor_a = true;
|
||||
}
|
||||
SensorSlot::B => {
|
||||
result.plant[plant].sensor_b = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Id::Extended(ext) => {
|
||||
warn!("Received extended ID: {:?}", ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error receiving CAN message: {:?}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn inner_pulse(plant: usize, sensor: Sensor, signal_counter: &mut Unit<'_, 0>, sensor_expander: &mut Pca9535Immediate<I2cDevice<'static, CriticalSectionRawMutex, I2c<'static, Blocking>>>) -> FatResult<f32> {
|
||||
|
||||
let mut results = [0_f32; REPEAT_MOIST_MEASURE];
|
||||
|
||||
@@ -38,52 +38,6 @@ use embassy_net::Stack;
|
||||
use embassy_time::Instant;
|
||||
use embedded_io_async::{Read, Write};
|
||||
use log::{error, info};
|
||||
// fn ota(
|
||||
// request: &mut Request<&mut EspHttpConnection>,
|
||||
// ) -> Result<Option<std::string::String>, anyhow::Error> {
|
||||
// let mut board = BOARD_ACCESS.lock().unwrap();
|
||||
// let mut ota = OtaUpdate::begin()?;
|
||||
// log::info!("start ota");
|
||||
//
|
||||
// //having a larger buffer is not really faster, requires more stack and prevents the progress bar from working ;)
|
||||
// const BUFFER_SIZE: usize = 512;
|
||||
// let mut buffer: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
|
||||
// let mut total_read: usize = 0;
|
||||
// let mut lastiter = 0;
|
||||
// loop {
|
||||
// let read = request.read(&mut buffer)?;
|
||||
// total_read += read;
|
||||
// let to_write = &buffer[0..read];
|
||||
// //delay for watchdog and wifi stuff
|
||||
// board.board_hal.get_esp().delay.delay_ms(1);
|
||||
//
|
||||
// let iter = (total_read / 1024) % 8;
|
||||
// if iter != lastiter {
|
||||
// board.board_hal.general_fault(iter % 5 == 0);
|
||||
// for i in 0..PLANT_COUNT {
|
||||
// let _ = board.board_hal.fault(i, iter == i);
|
||||
// }
|
||||
// lastiter = iter;
|
||||
// }
|
||||
//
|
||||
// ota.write(to_write)?;
|
||||
// if read == 0 {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// log::info!("wrote bytes ota {total_read}");
|
||||
// log::info!("finish ota");
|
||||
// let partition = ota.raw_partition();
|
||||
// log::info!("finalizing and changing boot partition to {partition:?}");
|
||||
//
|
||||
// let mut finalizer = ota.finalize()?;
|
||||
// log::info!("changing boot partition");
|
||||
// board.board_hal.get_esp().set_restart_to_conf(true);
|
||||
// drop(board);
|
||||
// finalizer.set_as_boot_partition()?;
|
||||
// anyhow::Ok(None)
|
||||
// }
|
||||
//
|
||||
|
||||
struct HTTPRequestRouter {
|
||||
reboot_now: Arc<AtomicBool>,
|
||||
|
||||
@@ -707,6 +707,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -731,6 +732,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -957,6 +959,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.3",
|
||||
"caniuse-lite": "^1.0.30001741",
|
||||
@@ -2274,6 +2277,7 @@
|
||||
"integrity": "sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/html-minifier-terser": "^6.0.0",
|
||||
"html-minifier-terser": "^6.0.2",
|
||||
@@ -3380,6 +3384,7 @@
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -4338,7 +4343,8 @@
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
@@ -4360,6 +4366,7 @@
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -4508,6 +4515,7 @@
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.3.tgz",
|
||||
"integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.8",
|
||||
|
||||
@@ -44,9 +44,6 @@ pub mod id {
|
||||
pub const MOISTURE_DATA_OFFSET: u16 = 0; // periodic data from sensor (sensor -> controller)
|
||||
pub const IDENTIFY_CMD_OFFSET: u16 = 32; // identify LED command (controller -> sensor)
|
||||
|
||||
// Convenience constants for per-slot base offsets
|
||||
pub const IDENTIFY_CMD_OFFSET_A: u16 = IDENTIFY_CMD_OFFSET + 0;
|
||||
pub const IDENTIFY_CMD_OFFSET_B: u16 = IDENTIFY_CMD_OFFSET + B_OFFSET;
|
||||
|
||||
#[inline]
|
||||
pub const fn plant_id(message_type_offset: u16, sensor: SensorSlot, plant: u16) -> u16 {
|
||||
|
||||
Reference in New Issue
Block a user