Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
|
325b118a20 |
13 changed files with 830 additions and 32 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -62,6 +62,7 @@ dependencies = [
|
|||
"esp-hal",
|
||||
"esp-hal-embassy",
|
||||
"esp-println",
|
||||
"heapless",
|
||||
"log",
|
||||
"static_cell",
|
||||
]
|
||||
|
|
|
@ -25,8 +25,10 @@ hal = { package = "esp-hal", version = "0.18.0", features = [
|
|||
esp-hal-embassy = {version= "0.1.0", features = ["esp32", "time-timg0"]}
|
||||
embassy-time = "0.3.1"
|
||||
embassy-sync = "0.6.0"
|
||||
# esp-hal-common = "0.15.0"
|
||||
esp-println = { version = "0.9.1", features = ["esp32", "log"] }
|
||||
log = { version = "0.4.21" }
|
||||
heapless = "0.8.0"
|
||||
esp-alloc = { version = "0.4.0" }
|
||||
static_cell = { version = "2.1.0", features = ["nightly"] }
|
||||
embassy-executor = { version = "0.5.0", features = [
|
||||
|
|
10
README.md
10
README.md
|
@ -11,3 +11,13 @@ git push -u origin main
|
|||
# Pushing an existing repository from the command line
|
||||
git remote add origin https://gitdab.com/andodeki/relay_button.git
|
||||
git push -u origin main
|
||||
|
||||
git add *
|
||||
git commit -m "working button to trigger relay and blinking led code"
|
||||
git push -u origin main
|
||||
|
||||
|
||||
https://wokwi.com/projects/400243028096410625
|
||||
|
||||
easyeda2kicad --full --lcsc_id=C99666
|
||||
easyeda2kicad --full --lcsc_id=C99666 --output ~/libs/my_lib
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![feature(type_alias_impl_trait)]
|
||||
// #![feature(async_fn_in_trait)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
pub mod confg;
|
||||
|
|
66
src/main.rs
66
src/main.rs
|
@ -2,19 +2,26 @@
|
|||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
use button_relay::run::blinky::blink_green;
|
||||
use button_relay::run::button::button_task;
|
||||
use button_relay::run::relay::relay_task;
|
||||
use button_relay::run::shared::{Command, QUEUE_SIZE};
|
||||
// use button_relay::run::blinky::blink_green;
|
||||
// use button_relay::run::button::button_task;
|
||||
// use button_relay::run::relay::relay_task;
|
||||
// use button_relay::run::shared::{Command, PerPins, QUEUE_SIZE};
|
||||
|
||||
use button_relay::run::validate::serial_number_validation_task;
|
||||
use button_relay::singleton;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber};
|
||||
// use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
// use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::println;
|
||||
use hal::gpio::{Input, Io, Level, Output, Pull};
|
||||
// use hal::gpio::{Input, Io, Level, Output, Pull};
|
||||
// use hal::uart::TxRxPins;
|
||||
use hal::{
|
||||
clock::ClockControl, delay::Delay, peripherals::Peripherals, prelude::*, system::SystemControl,
|
||||
clock::{ClockControl, Clocks},
|
||||
delay::Delay,
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
system::SystemControl,
|
||||
};
|
||||
use static_cell::make_static;
|
||||
|
||||
|
@ -36,33 +43,19 @@ fn init_heap() {
|
|||
#[main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let peripherals = Peripherals::take();
|
||||
// let peripherals = singleton!(Peripherals::take(), Peripherals);
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
|
||||
let clocks = ClockControl::max(system.clock_control).freeze();
|
||||
let _delay = Delay::new(&clocks);
|
||||
// let clocks = ClockControl::max(system.clock_control).freeze();
|
||||
let clocks = singleton!(ClockControl::max(system.clock_control).freeze(), Clocks<'_>);
|
||||
|
||||
let delay = Delay::new(&clocks);
|
||||
init_heap();
|
||||
|
||||
esp_println::logger::init_logger_from_env();
|
||||
log::info!("Logger is setup");
|
||||
println!("Hello world!");
|
||||
|
||||
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||
let button_pin = Input::new(io.pins.gpio12, Pull::Down);
|
||||
let led_pin = Output::new(io.pins.gpio2, Level::Low);
|
||||
let relay_pin = Output::new(io.pins.gpio16, Level::Low);
|
||||
|
||||
let channel: &'static mut PubSubChannel<
|
||||
NoopRawMutex,
|
||||
Command,
|
||||
QUEUE_SIZE,
|
||||
QUEUE_SIZE,
|
||||
QUEUE_SIZE,
|
||||
> = make_static!(PubSubChannel::new());
|
||||
|
||||
let publisher = channel.publisher().unwrap();
|
||||
let led_subscriber = channel.subscriber().unwrap();
|
||||
let relay_subscriber = channel.subscriber().unwrap();
|
||||
|
||||
hal::interrupt::enable(
|
||||
hal::peripherals::Interrupt::GPIO,
|
||||
hal::interrupt::Priority::Priority1,
|
||||
|
@ -82,13 +75,24 @@ async fn main(spawner: Spawner) {
|
|||
.unwrap();
|
||||
|
||||
println!("Starting embassy executor ...");
|
||||
|
||||
spawner.spawn(button_task(button_pin, publisher)).unwrap();
|
||||
spawner.spawn(blink_green(led_pin, led_subscriber)).unwrap();
|
||||
// Validate serial number before proceeding with other tasks
|
||||
spawner
|
||||
.spawn(relay_task(relay_pin, relay_subscriber))
|
||||
.spawn(serial_number_validation_task(
|
||||
delay,
|
||||
spawner,
|
||||
peripherals.GPIO,
|
||||
peripherals.IO_MUX,
|
||||
peripherals.UART0,
|
||||
peripherals.UART1,
|
||||
clocks,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// spawner.spawn(button_task(button_pin, publisher)).unwrap();
|
||||
// spawner.spawn(blink_green(led_pin, led_subscriber)).unwrap();
|
||||
// spawner.spawn(relay_task(relay_pin, relay_subscriber)).unwrap();
|
||||
// spawner.spawn(thermal_printer_task(printer_subscriber)).unwrap();
|
||||
|
||||
loop {
|
||||
esp_println::println!("Bing!");
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_millis(5_000)).await;
|
||||
|
|
370
src/main.rs.txt
Normal file
370
src/main.rs.txt
Normal file
|
@ -0,0 +1,370 @@
|
|||
//! Blinks an LED
|
||||
//!
|
||||
//! This assumes that a LED is connected to the pin assigned to `led`. (GPIO4)
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
extern crate embassy_executor;
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_sync::pubsub::{PubSubChannel, Publisher, Subscriber, WaitResult};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use esp_backtrace as _;
|
||||
use esp_println::println;
|
||||
use hal::gpio::{Gpio12, Gpio2, Gpio4, Input, Io, Level, Output, Pull};
|
||||
use hal::{
|
||||
clock::{ClockControl, Clocks},
|
||||
delay::Delay,
|
||||
peripherals::Peripherals,
|
||||
peripherals::{GPIO, IO_MUX, UART0, UART1},
|
||||
prelude::*,
|
||||
system::SystemControl,
|
||||
uart::{TxRxPins, Uart},
|
||||
Async,
|
||||
};
|
||||
use heapless::String;
|
||||
use static_cell::make_static;
|
||||
|
||||
extern crate alloc;
|
||||
use core::cell::RefCell;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
|
||||
|
||||
fn init_heap() {
|
||||
const HEAP_SIZE: usize = 32 * 1024;
|
||||
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, HEAP_SIZE);
|
||||
}
|
||||
}
|
||||
macro_rules! singleton {
|
||||
($val:expr, $T:ty) => {{
|
||||
static STATIC_CELL: ::static_cell::StaticCell<$T> = ::static_cell::StaticCell::new();
|
||||
STATIC_CELL.init($val)
|
||||
}};
|
||||
}
|
||||
|
||||
pub const QUEUE_SIZE: usize = 10;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Command {
|
||||
pub is_on: bool,
|
||||
pub led_state: bool,
|
||||
pub relay_state: bool,
|
||||
pub is_printer_command: bool,
|
||||
}
|
||||
|
||||
const SAFE_MODE: bool = false;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sens<T>(pub T);
|
||||
|
||||
impl<T: core::fmt::Display> core::fmt::Display for Sens<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let Self(inner) = self;
|
||||
if SAFE_MODE {
|
||||
"[REDACTED]".fmt(f)
|
||||
} else {
|
||||
inner.fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let peripherals = Peripherals::take();
|
||||
let system = SystemControl::new(peripherals.SYSTEM);
|
||||
let clocks = singleton!(ClockControl::max(system.clock_control).freeze(), Clocks<'_>);
|
||||
|
||||
let delay = Delay::new(&clocks);
|
||||
init_heap();
|
||||
|
||||
esp_println::logger::init_logger_from_env();
|
||||
log::info!("Logger is setup");
|
||||
println!("Hello world!");
|
||||
|
||||
hal::interrupt::enable(
|
||||
hal::peripherals::Interrupt::GPIO,
|
||||
hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("We are connected!");
|
||||
println!("Start busy loop on main");
|
||||
|
||||
let timer_group0 = hal::timer::timg::TimerGroup::new_async(peripherals.TIMG0, &clocks);
|
||||
esp_hal_embassy::init(&clocks, timer_group0);
|
||||
|
||||
hal::interrupt::enable(
|
||||
hal::peripherals::Interrupt::UART1,
|
||||
hal::interrupt::Priority::Priority1,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("Starting embassy executor ...");
|
||||
// Validate serial number before proceeding with other tasks
|
||||
spawner
|
||||
.spawn(validation_task(
|
||||
delay,
|
||||
spawner,
|
||||
peripherals.GPIO,
|
||||
peripherals.IO_MUX,
|
||||
peripherals.UART0,
|
||||
peripherals.UART1,
|
||||
clocks,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
loop {
|
||||
esp_println::println!("Bing!");
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_millis(5_000)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn button_task(
|
||||
button_pin: Input<'static, Gpio12>,
|
||||
publisher: Publisher<'static, NoopRawMutex, Command, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE>,
|
||||
) {
|
||||
let mut previous_button_state = false;
|
||||
let mut led_state = false;
|
||||
let mut relay_state = false;
|
||||
let mut press_count = 0;
|
||||
let mut last_press_time = embassy_time::Instant::now();
|
||||
loop {
|
||||
let current_button_state = button_pin.is_high();
|
||||
|
||||
if current_button_state && !previous_button_state {
|
||||
// Button was pressed
|
||||
let now = embassy_time::Instant::now();
|
||||
let elapsed = now.duration_since(last_press_time);
|
||||
last_press_time = now;
|
||||
|
||||
if elapsed < Duration::from_millis(500) {
|
||||
press_count += 1;
|
||||
} else {
|
||||
press_count = 1;
|
||||
}
|
||||
|
||||
if press_count == 1 {
|
||||
led_state = !led_state;
|
||||
relay_state = !relay_state;
|
||||
let payload = Command {
|
||||
is_on: true,
|
||||
led_state,
|
||||
relay_state,
|
||||
is_printer_command: false,
|
||||
};
|
||||
publisher.publish(payload).await;
|
||||
esp_println::println!(
|
||||
"Single press: LED State: {}, Relay State: {}",
|
||||
led_state,
|
||||
relay_state
|
||||
);
|
||||
} else if press_count == 2 {
|
||||
let payload = Command {
|
||||
is_on: true,
|
||||
led_state: false,
|
||||
relay_state: false,
|
||||
is_printer_command: true,
|
||||
};
|
||||
publisher.publish(payload).await;
|
||||
esp_println::println!("Double press: Printing from thermal printer...");
|
||||
|
||||
// Insert thermal printer logic here
|
||||
}
|
||||
}
|
||||
|
||||
if current_button_state {
|
||||
let now = embassy_time::Instant::now();
|
||||
let elapsed = now.duration_since(last_press_time);
|
||||
if elapsed >= Duration::from_secs(2) {
|
||||
esp_println::println!("Long press: Rebooting device...");
|
||||
// Insert reboot logic here
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
previous_button_state = current_button_state;
|
||||
Timer::after(Duration::from_millis(50)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn blink_green(
|
||||
mut pin: Output<'static, Gpio2>,
|
||||
mut subscriber: Subscriber<'static, NoopRawMutex, Command, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE>,
|
||||
) {
|
||||
let mut led_state = false;
|
||||
|
||||
loop {
|
||||
match subscriber.try_next_message() {
|
||||
Some(WaitResult::Message(command)) => {
|
||||
led_state = command.led_state;
|
||||
}
|
||||
Some(WaitResult::Lagged(_)) | None => {
|
||||
// No new message, continue with the current state
|
||||
}
|
||||
}
|
||||
if led_state {
|
||||
pin.toggle();
|
||||
Timer::after(Duration::from_millis(200)).await;
|
||||
} else {
|
||||
pin.set_low();
|
||||
Timer::after(Duration::from_millis(50)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type AbrPub = Publisher<'static, NoopRawMutex, Command, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE>;
|
||||
type AbrSub = Subscriber<'static, NoopRawMutex, Command, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE>;
|
||||
|
||||
pub struct ButtonLedPins {
|
||||
pub button_pin: Input<'static, Gpio12>,
|
||||
pub led_pin: Output<'static, Gpio2>,
|
||||
pub button_publisher: AbrPub,
|
||||
pub led_subscriber: AbrSub,
|
||||
}
|
||||
|
||||
impl ButtonLedPins {
|
||||
fn new(
|
||||
button_pin: Input<'static, Gpio12>,
|
||||
led_pin: Output<'static, Gpio2>,
|
||||
button_publisher: AbrPub,
|
||||
led_subscriber: AbrSub,
|
||||
) -> Self {
|
||||
ButtonLedPins {
|
||||
button_pin,
|
||||
led_pin,
|
||||
button_publisher,
|
||||
led_subscriber,
|
||||
}
|
||||
}
|
||||
fn uart_device_setup(
|
||||
&self,
|
||||
delay: Delay,
|
||||
uart0_per: UART0,
|
||||
uart1_per: UART1,
|
||||
clocks: &Clocks<'static>,
|
||||
) -> (Uart<'static, UART0, Async>, Uart<'static, UART1, Async>) {
|
||||
let mut uart0 = Uart::new_async(uart0_per, &clocks);
|
||||
let mut uart1 = Uart::new_async(uart1_per, &clocks);
|
||||
|
||||
(uart0, uart1)
|
||||
}
|
||||
}
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use core::sync::atomic::AtomicBool;
|
||||
pub static SERIAL_NUMBER_VALID: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn validation_task(
|
||||
delay: Delay,
|
||||
spawner: Spawner,
|
||||
peripherals_GPIO: GPIO,
|
||||
peripherals_IO_MUX: IO_MUX,
|
||||
uart0_per: UART0,
|
||||
uart1_per: UART1,
|
||||
clocks: &'static Clocks<'static>,
|
||||
) {
|
||||
let io = Io::new(peripherals_GPIO, peripherals_IO_MUX);
|
||||
let button_pin = Input::new(io.pins.gpio12, Pull::Down);
|
||||
let led_pin = Output::new(io.pins.gpio2, Level::Low);
|
||||
|
||||
let channel: &'static mut PubSubChannel<
|
||||
NoopRawMutex,
|
||||
Command,
|
||||
QUEUE_SIZE,
|
||||
QUEUE_SIZE,
|
||||
QUEUE_SIZE,
|
||||
> = make_static!(PubSubChannel::new());
|
||||
|
||||
let button_publisher = channel.publisher().unwrap();
|
||||
let led_subscriber = channel.subscriber().unwrap();
|
||||
|
||||
// let btnsleds = Rc::new(RefCell::new(ButtonLedPins {
|
||||
// button_pin,
|
||||
// led_pin,
|
||||
// button_publisher,
|
||||
// led_subscriber,
|
||||
// }));
|
||||
let btnsleds = ButtonLedPins {
|
||||
button_pin,
|
||||
led_pin,
|
||||
button_publisher,
|
||||
led_subscriber,
|
||||
};
|
||||
|
||||
let (mut uart0, mut uart1) = btnsleds.uart_device_setup(delay, uart0_per, uart1_per, &clocks);
|
||||
let mut buffer = [0u8; 16];
|
||||
|
||||
loop {
|
||||
if uart0.read_async(&mut buffer).await.is_ok() {
|
||||
match core::str::from_utf8(&buffer) {
|
||||
Ok(serial_number) => {
|
||||
esp_println::println!("Serial number received: {}", serial_number);
|
||||
|
||||
// Validate the serial number with the server
|
||||
if validate_serial_number_with_server(&mut uart1, &buffer).await {
|
||||
esp_println::println!("Serial number is valid!");
|
||||
SERIAL_NUMBER_VALID.store(true, Ordering::SeqCst);
|
||||
|
||||
// Spawn other tasks after successful validation
|
||||
spawner
|
||||
.spawn(button_task(btnsleds.button_pin, btnsleds.button_publisher))
|
||||
.unwrap();
|
||||
spawner
|
||||
.spawn(blink_green(btnsleds.led_pin, btnsleds.led_subscriber))
|
||||
.unwrap();
|
||||
break;
|
||||
} else {
|
||||
esp_println::println!("Serial number is invalid. Please try again.");
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
esp_println::println!(
|
||||
"Received invalid UTF-8 serial number. Please try again."
|
||||
);
|
||||
}
|
||||
}
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn validate_serial_number_with_server(
|
||||
uart: &mut Uart<'static, UART1, Async>,
|
||||
serial_number: &[u8],
|
||||
) -> bool {
|
||||
// Initialize GPRS module
|
||||
send_at_command(uart, b"AT\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Receive validation response from the server
|
||||
let mut response = [0u8; 128];
|
||||
if uart.read_async(&mut response).await.is_ok() {
|
||||
esp_println::println!("Received response from server.");
|
||||
return parse_server_response(&response);
|
||||
}
|
||||
false
|
||||
}
|
||||
fn parse_server_response(response: &[u8]) -> bool {
|
||||
// Parse the HTTP response to check if the serial number is valid
|
||||
// This is a simplified example, you should implement a proper HTTP response parser
|
||||
if let Ok(response_str) = core::str::from_utf8(response) {
|
||||
return response_str.contains("200 OK") && response_str.contains("valid");
|
||||
}
|
||||
false
|
||||
}
|
||||
async fn send_at_command(uart: &mut Uart<'static, UART1, Async>, command: &[u8]) {
|
||||
uart.write_async(command).await.unwrap();
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
extern crate embassy_executor;
|
||||
|
||||
use crate::confg::Sens;
|
||||
// use crate::confg::Sens;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::raw::NoopRawMutex,
|
||||
pubsub::{Subscriber, WaitResult},
|
||||
|
|
|
@ -40,6 +40,7 @@ pub async fn button_task(
|
|||
is_on: true,
|
||||
led_state,
|
||||
relay_state,
|
||||
is_printer_command: false,
|
||||
};
|
||||
publisher.publish(payload).await;
|
||||
esp_println::println!(
|
||||
|
@ -48,7 +49,15 @@ pub async fn button_task(
|
|||
relay_state
|
||||
);
|
||||
} else if press_count == 2 {
|
||||
let payload = Command {
|
||||
is_on: true,
|
||||
led_state: false,
|
||||
relay_state: false,
|
||||
is_printer_command: true,
|
||||
};
|
||||
publisher.publish(payload).await;
|
||||
esp_println::println!("Double press: Printing from thermal printer...");
|
||||
|
||||
// Insert thermal printer logic here
|
||||
}
|
||||
}
|
||||
|
|
36
src/run/isdevicedisconnected.rs
Normal file
36
src/run/isdevicedisconnected.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
//! Connect a potentiometer to PIN25 and see the read values change when
|
||||
//! rotating the shaft. Alternatively you could also connect the PIN to GND or
|
||||
//! 3V3 to see the maximum and minimum raw values read.
|
||||
|
||||
use esp_hal_common::{
|
||||
adc::RegisterAccess,
|
||||
gpio::{Analog, GpioPin},
|
||||
peripheral::Peripheral,
|
||||
};
|
||||
use esp_println::println;
|
||||
use hal::{
|
||||
// adc::{AdcConfig, Attenuation, ADC},
|
||||
analog::adc::{AdcConfig, Attenuation},
|
||||
peripherals::ADC2,
|
||||
prelude::*,
|
||||
Delay,
|
||||
};
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn checkdevice(
|
||||
pin2: GpioPin<Analog, 2>,
|
||||
// adc_instance: impl Peripheral<P = dyn RegisterAccess> + 'static,
|
||||
mut delay: Delay,
|
||||
) {
|
||||
let mut adc2_config = AdcConfig::new();
|
||||
let mut pin2 = adc2_config.enable_pin(pin2, Attenuation::Attenuation11dB);
|
||||
let mut adc2 = ADC::<ADC2>::new(adc_instance.adc2, adc2_config).unwrap();
|
||||
|
||||
// let mut delay = Delay::new(&clocks);
|
||||
|
||||
loop {
|
||||
let pin2_value: u16 = nb::block!(adc2.read(&mut pin2)).unwrap();
|
||||
println!("PIN2 ADC reading = {}", pin2_value);
|
||||
delay.delay_ms(1500u32);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
pub mod blinky;
|
||||
pub mod button;
|
||||
// pub mod isdevicedisconnected;
|
||||
pub mod printing;
|
||||
pub mod relay;
|
||||
pub mod shared;
|
||||
pub mod validate;
|
||||
|
|
28
src/run/printing.rs
Normal file
28
src/run/printing.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
extern crate embassy_executor;
|
||||
|
||||
// use crate::confg::Sens;
|
||||
use embassy_sync::{
|
||||
blocking_mutex::raw::NoopRawMutex,
|
||||
pubsub::{Subscriber, WaitResult},
|
||||
};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use hal::gpio::{Gpio13, Output};
|
||||
|
||||
use super::shared::{Command, QUEUE_SIZE};
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn thermal_printer_task(
|
||||
mut _pin: Output<'static, Gpio13>,
|
||||
mut subscriber: Subscriber<'static, NoopRawMutex, Command, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE>,
|
||||
) {
|
||||
loop {
|
||||
let command = subscriber.next_message_pure().await;
|
||||
if command.is_printer_command {
|
||||
// Mock printing logic
|
||||
esp_println::println!("Thermal Printer: Printing...");
|
||||
// Replace with actual printer command
|
||||
Timer::after(Duration::from_secs(2)).await; // Simulate printing time
|
||||
esp_println::println!("Thermal Printer: Print complete.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,11 +12,127 @@
|
|||
// relay_state: AtomicBool::new(false),
|
||||
// });
|
||||
|
||||
use core::sync::atomic::AtomicBool;
|
||||
|
||||
use embassy_sync::{
|
||||
blocking_mutex::raw::NoopRawMutex,
|
||||
pubsub::{Publisher, Subscriber},
|
||||
};
|
||||
use hal::{
|
||||
clock::Clocks,
|
||||
delay::Delay,
|
||||
gpio::{Gpio12, Gpio13, Gpio16, Gpio2, GpioPin, Input, Output},
|
||||
peripherals::{UART0, UART1},
|
||||
uart::{
|
||||
config::{AtCmdConfig, Config, DataBits, Parity, StopBits},
|
||||
ClockSource, TxRxPins, Uart, UartRx, UartTx,
|
||||
},
|
||||
Async,
|
||||
};
|
||||
|
||||
pub const QUEUE_SIZE: usize = 10;
|
||||
pub static mut SERIAL_NUMBER: [u8; 16] = [0; 16];
|
||||
pub static SERIAL_NUMBER_VALID: AtomicBool = AtomicBool::new(false);
|
||||
// rx_fifo_full_threshold
|
||||
pub const READ_BUF_SIZE: usize = 64;
|
||||
// EOT (CTRL-D)
|
||||
pub const AT_CMD: u8 = 0x04;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! singleton {
|
||||
($val:expr, $T:ty) => {{
|
||||
static STATIC_CELL: ::static_cell::StaticCell<$T> = ::static_cell::StaticCell::new();
|
||||
STATIC_CELL.init($val)
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Command {
|
||||
pub is_on: bool,
|
||||
pub led_state: bool,
|
||||
pub relay_state: bool,
|
||||
pub is_printer_command: bool,
|
||||
}
|
||||
type AbrPubType = Publisher<'static, NoopRawMutex, Command, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE>;
|
||||
type AbrSubType = Subscriber<'static, NoopRawMutex, Command, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE>;
|
||||
|
||||
pub struct PerPins {
|
||||
pub button_pin: Input<'static, Gpio12>,
|
||||
pub led_pin: Output<'static, Gpio2>,
|
||||
pub relay_pin: Output<'static, Gpio16>,
|
||||
pub printer_pin: Output<'static, Gpio13>,
|
||||
pub uart0_pins: TxRxPins<'static, GpioPin<1>, GpioPin<3>>,
|
||||
pub modem_uart_pins: TxRxPins<'static, GpioPin<15>, GpioPin<14>>,
|
||||
pub publisher: AbrPubType,
|
||||
pub led_subscriber: AbrSubType,
|
||||
pub relay_subscriber: AbrSubType,
|
||||
pub printer_subscriber: AbrSubType,
|
||||
}
|
||||
|
||||
impl PerPins {
|
||||
pub fn new(
|
||||
button_pin: Input<'static, Gpio12>,
|
||||
led_pin: Output<'static, Gpio2>,
|
||||
relay_pin: Output<'static, Gpio16>,
|
||||
uart0_pins: TxRxPins<'static, GpioPin<1>, GpioPin<3>>,
|
||||
modem_uart_pins: TxRxPins<'static, GpioPin<15>, GpioPin<14>>,
|
||||
printer_pin: Output<'static, Gpio13>,
|
||||
publisher: AbrPubType,
|
||||
led_subscriber: AbrSubType,
|
||||
relay_subscriber: AbrSubType,
|
||||
printer_subscriber: AbrSubType,
|
||||
) -> Self {
|
||||
Self {
|
||||
button_pin,
|
||||
led_pin,
|
||||
relay_pin,
|
||||
printer_pin,
|
||||
uart0_pins,
|
||||
modem_uart_pins,
|
||||
publisher,
|
||||
led_subscriber,
|
||||
relay_subscriber,
|
||||
printer_subscriber,
|
||||
}
|
||||
}
|
||||
pub fn uart_device_setup(
|
||||
&self,
|
||||
delay: Delay,
|
||||
uart0_per: UART0,
|
||||
uart1_per: UART1,
|
||||
clocks: &Clocks<'static>,
|
||||
) -> (
|
||||
UartTx<'static, UART0, Async>,
|
||||
UartRx<'static, UART0, Async>,
|
||||
UartTx<'static, UART1, Async>,
|
||||
UartRx<'static, UART1, Async>,
|
||||
)
|
||||
// (Uart<'static, UART0, Async>, Uart<'static, UART1, Async>)
|
||||
{
|
||||
let mut uart0 = Uart::new_async(uart0_per, &clocks);
|
||||
|
||||
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
|
||||
uart0
|
||||
.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16)
|
||||
.unwrap();
|
||||
let (tx0, rx0) = uart0.split();
|
||||
|
||||
let config = Config {
|
||||
baudrate: 115200,
|
||||
data_bits: DataBits::DataBits8,
|
||||
parity: Parity::ParityNone,
|
||||
stop_bits: StopBits::STOP1,
|
||||
clock_source: ClockSource::Apb,
|
||||
};
|
||||
// UART interface for the GSM modem
|
||||
let mut uart1 =
|
||||
Uart::new_with_config(uart1_per, config, Some(self.modem_uart_pins), &clocks, None);
|
||||
uart1.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
|
||||
// uart.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16).unwrap();
|
||||
uart1.set_rx_fifo_full_threshold(1).unwrap();
|
||||
let (tx1, rx1) = uart1.split();
|
||||
|
||||
// (uart0, uart1, tx0, rx0)
|
||||
(tx0, rx0, tx1, rx1)
|
||||
}
|
||||
}
|
||||
|
|
218
src/run/validate.rs
Normal file
218
src/run/validate.rs
Normal file
|
@ -0,0 +1,218 @@
|
|||
use core::sync::atomic::Ordering;
|
||||
|
||||
use core::fmt::Write;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_sync::signal::Signal;
|
||||
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, pubsub::PubSubChannel};
|
||||
use embassy_time::{Duration, Timer};
|
||||
use hal::{
|
||||
clock::Clocks,
|
||||
delay::Delay,
|
||||
gpio::{Input, Io, Level, Output, Pull},
|
||||
peripherals::{GPIO, IO_MUX, UART0, UART1},
|
||||
uart::{TxRxPins, Uart},
|
||||
Async,
|
||||
};
|
||||
|
||||
use heapless::String;
|
||||
use static_cell::{make_static, StaticCell};
|
||||
|
||||
use crate::run::{
|
||||
blinky::blink_green, button::button_task, printing::thermal_printer_task, relay::relay_task,
|
||||
shared::SERIAL_NUMBER_VALID,
|
||||
};
|
||||
|
||||
use super::shared::{Command, PerPins, QUEUE_SIZE};
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn serial_number_validation_task(
|
||||
delay: Delay,
|
||||
spawner: Spawner,
|
||||
peripherals_gpio: GPIO,
|
||||
peripherals_io_mux: IO_MUX,
|
||||
uart0_per: UART0,
|
||||
uart1_per: UART1,
|
||||
clocks: &'static Clocks<'static>,
|
||||
) {
|
||||
let io = Io::new(peripherals_gpio, peripherals_io_mux);
|
||||
let button_pin = Input::new(io.pins.gpio12, Pull::Down);
|
||||
let led_pin = Output::new(io.pins.gpio2, Level::Low);
|
||||
let relay_pin = Output::new(io.pins.gpio16, Level::Low);
|
||||
let printer_pin = Output::new(io.pins.gpio13, Level::Low);
|
||||
|
||||
let uart0_pins = TxRxPins::new_tx_rx(io.pins.gpio1, io.pins.gpio3);
|
||||
let uart1_pins = TxRxPins::new_tx_rx(io.pins.gpio15, io.pins.gpio14);
|
||||
|
||||
let channel: &'static mut PubSubChannel<
|
||||
NoopRawMutex,
|
||||
Command,
|
||||
QUEUE_SIZE,
|
||||
QUEUE_SIZE,
|
||||
QUEUE_SIZE,
|
||||
> = make_static!(PubSubChannel::new());
|
||||
|
||||
let publisher = channel.publisher().unwrap();
|
||||
let led_subscriber = channel.subscriber().unwrap();
|
||||
let relay_subscriber = channel.subscriber().unwrap();
|
||||
let printer_subscriber = channel.subscriber().unwrap();
|
||||
|
||||
static SIGNAL: StaticCell<Signal<NoopRawMutex, usize>> = StaticCell::new();
|
||||
let uart_signal = &*SIGNAL.init(Signal::new());
|
||||
|
||||
let per_pins = PerPins {
|
||||
button_pin,
|
||||
led_pin,
|
||||
relay_pin,
|
||||
printer_pin,
|
||||
uart0_pins,
|
||||
modem_uart_pins: uart1_pins,
|
||||
publisher,
|
||||
led_subscriber,
|
||||
relay_subscriber,
|
||||
printer_subscriber,
|
||||
};
|
||||
|
||||
let (_tx0, _rx0, _tx1, _rx1) = per_pins.uart_device_setup(delay, uart0_per, uart1_per, &clocks);
|
||||
let mut buffer = [0u8; 16];
|
||||
|
||||
loop {
|
||||
if uart0.read_async(&mut buffer).await.is_ok() {
|
||||
match core::str::from_utf8(&buffer) {
|
||||
Ok(serial_number) => {
|
||||
esp_println::println!("Serial number received: {}", serial_number);
|
||||
|
||||
// Validate the serial number with the server
|
||||
if validate_serial_number_with_server(&mut uart1, &buffer).await {
|
||||
esp_println::println!("Serial number is valid!");
|
||||
SERIAL_NUMBER_VALID.store(true, Ordering::SeqCst);
|
||||
|
||||
// Spawn other tasks after successful validation
|
||||
spawner
|
||||
.spawn(button_task(per_pins.button_pin, per_pins.publisher))
|
||||
.unwrap();
|
||||
spawner
|
||||
.spawn(blink_green(per_pins.led_pin, per_pins.led_subscriber))
|
||||
.unwrap();
|
||||
spawner
|
||||
.spawn(relay_task(per_pins.relay_pin, per_pins.relay_subscriber))
|
||||
.unwrap();
|
||||
spawner
|
||||
.spawn(thermal_printer_task(
|
||||
per_pins.printer_pin,
|
||||
per_pins.printer_subscriber,
|
||||
))
|
||||
.unwrap();
|
||||
break;
|
||||
} else {
|
||||
esp_println::println!("Serial number is invalid. Please try again.");
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
esp_println::println!(
|
||||
"Received invalid UTF-8 serial number. Please try again."
|
||||
);
|
||||
}
|
||||
}
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn validate_serial_number_with_server(
|
||||
uart: &mut Uart<'static, UART1, Async>,
|
||||
serial_number: &[u8],
|
||||
) -> bool {
|
||||
// Initialize GPRS module
|
||||
send_at_command(uart, b"AT\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Set GPRS connection
|
||||
send_at_command(uart, b"AT+CGATT=1\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Setup PDP context
|
||||
send_at_command(uart, b"AT+CGDCONT=1,\"IP\",\"internet\"\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Activate PDP context
|
||||
send_at_command(uart, b"AT+CGACT=1,1\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Establish TCP connection to the server
|
||||
send_at_command(uart, b"AT+CIPSTART=\"TCP\",\"server_address\",\"port\"\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Prepare HTTP GET request
|
||||
let mut http_request = String::<128>::new();
|
||||
write!(http_request, "GET /validate?serial_number={} HTTP/1.1\r\nHost: server_address\r\nConnection: close\r\n\r\n", core::str::from_utf8(serial_number).unwrap()).unwrap();
|
||||
|
||||
// Send HTTP GET request
|
||||
send_at_command(uart, b"AT+CIPSEND\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
uart.write_async(http_request.as_bytes()).await.unwrap();
|
||||
uart.write_async(b"\x1A").await.unwrap(); // Send Ctrl+Z to indicate the end of the data
|
||||
|
||||
// Receive validation response from the server
|
||||
let mut response = [0u8; 128];
|
||||
if uart.read_async(&mut response).await.is_ok() {
|
||||
esp_println::println!("Received response from server.");
|
||||
return parse_server_response(&response);
|
||||
}
|
||||
false
|
||||
}
|
||||
fn parse_server_response(response: &[u8]) -> bool {
|
||||
// Parse the HTTP response to check if the serial number is valid
|
||||
// This is a simplified example, you should implement a proper HTTP response parser
|
||||
if let Ok(response_str) = core::str::from_utf8(response) {
|
||||
return response_str.contains("200 OK") && response_str.contains("valid");
|
||||
}
|
||||
false
|
||||
}
|
||||
async fn send_at_command(uart: &mut Uart<'static, UART1, Async>, command: &[u8]) {
|
||||
uart.write_async(command).await.unwrap();
|
||||
Timer::after(Duration::from_secs(1)).await;
|
||||
}
|
||||
|
||||
async fn validate_serial_number_with_tcpserver(
|
||||
uart: &mut Uart<'static, UART1, Async>,
|
||||
serial_number: &[u8],
|
||||
) -> bool {
|
||||
// Initialize GPRS module
|
||||
send_at_command(uart, b"AT\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Set GPRS connection
|
||||
send_at_command(uart, b"AT+CGATT=1\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Setup PDP context
|
||||
send_at_command(uart, b"AT+CGDCONT=1,\"IP\",\"internet\"\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Activate PDP context
|
||||
send_at_command(uart, b"AT+CGACT=1,1\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Establish TCP connection to the server
|
||||
send_at_command(uart, b"AT+CIPSTART=\"TCP\",\"server_address\",\"port\"\r\n").await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
// Send serial number to the server
|
||||
// let cmd = format!("AT+CIPSEND={}\r\n", serial_number.len());
|
||||
// Prepare the CIPSEND command
|
||||
let mut cmd = String::<32>::new();
|
||||
write!(cmd, "AT+CIPSEND={}\r\n", serial_number.len()).unwrap();
|
||||
send_at_command(uart, cmd.as_bytes()).await;
|
||||
Timer::after(Duration::from_secs(2)).await;
|
||||
|
||||
uart.write_async(serial_number).await.unwrap();
|
||||
uart.write_async(b"\x1A").await.unwrap(); // Send Ctrl+Z to indicate the end of the data
|
||||
|
||||
// Receive validation response from the server
|
||||
let mut response = [0u8; 1];
|
||||
if uart.read_async(&mut response).await.is_ok() {
|
||||
esp_println::println!("Received response from server.");
|
||||
return response[0] == 1; // Assume server sends 1 for valid and 0 for invalid
|
||||
}
|
||||
false
|
||||
}
|
Loading…
Reference in a new issue