evan suggested that computers have two cores, which I had neglected up until now bitbanging is way easier than figuring out how to use pin interrupts in embassy, mA be damned
252 lines
8.1 KiB
Rust
252 lines
8.1 KiB
Rust
//! This example uses the RP Pico W board Wifi chip (cyw43).
|
|
//! Creates an Access point Wifi network and creates a TCP endpoint on port 1234.
|
|
|
|
#![no_std]
|
|
#![no_main]
|
|
#![allow(async_fn_in_trait)]
|
|
|
|
use core::array;
|
|
use core::borrow::BorrowMut;
|
|
use core::cell::RefCell;
|
|
use core::fmt::Formatter;
|
|
use core::marker::PhantomData;
|
|
use core::panic::PanicInfo;
|
|
use core::str::from_utf8;
|
|
use core::sync::atomic::{AtomicU8};
|
|
|
|
use bt_hci::cmd::info;
|
|
use critical_section::Mutex;
|
|
use cyw43_pio::PioSpi;
|
|
use embassy_futures::join::join;
|
|
use embassy_futures::yield_now;
|
|
use embassy_rp::interrupt::typelevel::{Handler, Interrupt, IO_IRQ_BANK0};
|
|
use embassy_rp::multicore::{spawn_core1, Stack};
|
|
use embassy_rp::pwm::{self, Pwm};
|
|
use fixed::FixedU16;
|
|
use log::*;
|
|
//use embassy_rp::i2c::InterruptHandler;
|
|
use embassy_executor::{InterruptExecutor, Spawner};
|
|
use embassy_net::tcp::TcpSocket;
|
|
use embassy_net::{Config, StackResources};
|
|
use embassy_rp::{bind_interrupts, interrupt};
|
|
use embassy_rp::clocks::RoscRng;
|
|
use embassy_rp::gpio::{AnyPin, Input, InterruptTrigger, Level, Output};
|
|
use embassy_rp::peripherals::{DMA_CH0, PIN_21, PIO0, USB};
|
|
use embassy_rp::pio::{InterruptHandler, Pio};
|
|
use embassy_rp::usb::Driver;
|
|
use embassy_time::{Duration, Timer};
|
|
use embedded_io_async::Write;
|
|
use rand::RngCore;
|
|
use reqwless::response;
|
|
use static_cell::StaticCell;
|
|
use defmt_rtt as _;
|
|
|
|
bind_interrupts!(struct Irqs {
|
|
PIO0_IRQ_0 => InterruptHandler<PIO0>;
|
|
USBCTRL_IRQ => embassy_rp::usb::InterruptHandler<USB>;
|
|
|
|
});
|
|
|
|
static READ_CARD: Mutex<RefCell<u64>> =
|
|
Mutex::new(RefCell::new(0));
|
|
static BIT: AtomicU8 = AtomicU8::new(0);
|
|
static DATA_IN: Mutex<RefCell<Option<(Input, Input)>>> =
|
|
Mutex::new(RefCell::new(None));
|
|
|
|
#[embassy_executor::task]
|
|
async fn logger_task(driver: Driver<'static, USB>) {
|
|
embassy_usb_logger::run!(1024, log::LevelFilter::Debug, driver);
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! {
|
|
runner.run().await
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! {
|
|
runner.run().await
|
|
}
|
|
|
|
static LAST_BIT: AtomicU8 = AtomicU8::new(0);
|
|
#[embassy_executor::task]
|
|
async fn print_task() -> ! {
|
|
let mut last_bit = 0;
|
|
loop {
|
|
Timer::after_millis(250).await;
|
|
let card = critical_section::with(|cs| {
|
|
READ_CARD.borrow(cs).clone().into_inner()
|
|
});
|
|
let bit = BIT.load(core::sync::atomic::Ordering::SeqCst);
|
|
if bit == last_bit {
|
|
if card !=0 {
|
|
info!("thi ting: {card:#x}");
|
|
}
|
|
critical_section::with(|cs| {
|
|
READ_CARD.replace(cs, 0);
|
|
});
|
|
BIT.store(0, core::sync::atomic::Ordering::SeqCst);
|
|
}
|
|
last_bit = bit;
|
|
info!("ro: {card:#x}, bit: {bit}");
|
|
}
|
|
}
|
|
|
|
#[panic_handler]
|
|
fn panic( info: &PanicInfo) -> ! {
|
|
error!("{}", info);
|
|
loop { }
|
|
}
|
|
|
|
#[embassy_executor::main]
|
|
async fn main(spawner: Spawner) {
|
|
let p = embassy_rp::init(Default::default());
|
|
let data_0= Input::new(p.PIN_21, embassy_rp::gpio::Pull::None);
|
|
let data_1= Input::new(p.PIN_16, embassy_rp::gpio::Pull::None);
|
|
|
|
let mut rng = RoscRng;
|
|
|
|
let driver = Driver::new(p.USB, Irqs);
|
|
spawner.spawn(logger_task(driver)).unwrap();
|
|
|
|
|
|
let fw = include_bytes!("../../cyw43-firmware/43439A0.bin");
|
|
let clm = include_bytes!("../../cyw43-firmware/43439A0_clm.bin");
|
|
|
|
// To make flashing faster for development, you may want to flash the firmwares independently
|
|
// at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
|
|
// probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000
|
|
// probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000
|
|
//let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) };
|
|
//let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
|
|
|
|
let pwr = Output::new(p.PIN_23, Level::Low);
|
|
let cs = Output::new(p.PIN_25, Level::High);
|
|
let mut pio = Pio::new(p.PIO0, Irqs);
|
|
let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
|
|
|
|
static STATE: StaticCell<cyw43::State> = StaticCell::new();
|
|
let state = STATE.init(cyw43::State::new());
|
|
let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
|
|
defmt::unwrap!(spawner.spawn(cyw43_task(runner)));
|
|
|
|
control.init(clm).await;
|
|
control
|
|
.set_power_management(cyw43::PowerManagementMode::PowerSave)
|
|
.await;
|
|
|
|
// Use a link-local address for communication without DHCP server
|
|
let config = Config::ipv4_static(embassy_net::StaticConfigV4 {
|
|
address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16),
|
|
dns_servers: heapless::Vec::new(),
|
|
gateway: None,
|
|
});
|
|
|
|
// Generate random seed
|
|
let seed = rng.next_u64();
|
|
|
|
// Init network stack
|
|
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
|
|
let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed);
|
|
|
|
defmt::unwrap!(spawner.spawn(net_task(runner)));
|
|
|
|
//control.start_ap_open("door409", 5).await;
|
|
control.start_ap_wpa2("door409-outside", "outerbabes", 5).await;
|
|
|
|
let mut rx_buffer = [0; 4096];
|
|
let mut tx_buffer = [0; 4096];
|
|
let mut buf = [0; 4096];
|
|
|
|
spawner.spawn(print_task()).unwrap();
|
|
|
|
let mut partial: u64 = 0;
|
|
let mut bit: u8 = 0;
|
|
let mut prev: (bool,bool) = (false,false);
|
|
|
|
static mut CORE1_STACK: Stack<4096> = Stack::new();
|
|
spawn_core1(p.CORE1, unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, move || {
|
|
loop {
|
|
let current = (data_0.is_low(), data_1.is_low());
|
|
if current.1 && !prev.1 {
|
|
partial |= 1 << bit;
|
|
bit += 1;
|
|
}
|
|
if current.0 && !prev.0 {
|
|
partial &= !(1u64).rotate_left(bit as u32);
|
|
bit += 1;
|
|
}
|
|
prev=current;
|
|
|
|
critical_section::with(|cs| {
|
|
let mut foreign_partial = READ_CARD.borrow_ref_mut(cs);
|
|
|
|
// may or may not be sound, should work fine given no noise on the signal
|
|
if *foreign_partial != partial && !current.0 && !current.1 {
|
|
bit = 0;
|
|
partial = *foreign_partial;
|
|
}
|
|
|
|
*foreign_partial = partial;
|
|
});
|
|
|
|
BIT.store(bit, core::sync::atomic::Ordering::SeqCst);
|
|
}
|
|
});
|
|
|
|
|
|
loop {
|
|
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
|
socket.set_timeout(Some(Duration::from_secs(3)));
|
|
|
|
control.gpio_set(0, false).await;
|
|
info!("Listening on TCP:1234...");
|
|
if let Err(e) = socket.accept(1234).await {
|
|
warn!("accept error: {:?}", e);
|
|
continue;
|
|
}
|
|
|
|
info!("Received connection from {:?}", socket.remote_endpoint());
|
|
control.gpio_set(0, true).await;
|
|
|
|
loop {
|
|
let mut n = match socket.read(&mut buf).await {
|
|
Ok(0) => {
|
|
warn!("read EOF");
|
|
break;
|
|
}
|
|
Ok(n) => n,
|
|
Err(e) => {
|
|
warn!("read error: {:?}", e);
|
|
break;
|
|
}
|
|
};
|
|
|
|
|
|
info!("rxd {}", from_utf8(&buf[..n]).unwrap());
|
|
Timer::after_millis(30).await;
|
|
|
|
let mut segs = buf[..n].trim_ascii().split(|c| *c == ' ' as u8);
|
|
|
|
match char::from_u32(segs.next().unwrap()[0] as u32).unwrap() {
|
|
'D' => {
|
|
},
|
|
_ => {}
|
|
|
|
}
|
|
|
|
//let mut response: [u8;2] = [0;2];
|
|
|
|
//let _ = bus.read_async(0xC0u16, &mut response).await;
|
|
//let _ = hex::encode_to_slice(response, &mut buf);
|
|
|
|
match socket.write_all(&buf[..n]).await {
|
|
Ok(()) => {}
|
|
Err(e) => {
|
|
warn!("write error: {:?}", e);
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|