Compare commits

...

1 commit
main ... dev

Author SHA1 Message Date
aOK
325b118a20 added uart: work in progress 2024-06-12 17:14:10 +03:00
13 changed files with 830 additions and 32 deletions

1
Cargo.lock generated
View file

@ -62,6 +62,7 @@ dependencies = [
"esp-hal",
"esp-hal-embassy",
"esp-println",
"heapless",
"log",
"static_cell",
]

View file

@ -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 = [

View file

@ -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

View file

@ -3,6 +3,7 @@
#![feature(type_alias_impl_trait)]
// #![feature(async_fn_in_trait)]
#[macro_use]
extern crate alloc;
pub mod confg;

View file

@ -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
View 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;
}

View file

@ -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},

View file

@ -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
}
}

View 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);
}
}

View file

@ -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
View 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.");
}
}
}

View file

@ -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
View 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
}