Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
7635c3659b |
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -712,6 +712,7 @@ dependencies = [
|
|||||||
"embedded-hal 1.0.0",
|
"embedded-hal 1.0.0",
|
||||||
"fugit",
|
"fugit",
|
||||||
"heapless 0.8.0",
|
"heapless 0.8.0",
|
||||||
|
"log",
|
||||||
"panic-halt",
|
"panic-halt",
|
||||||
"rp2040-boot2",
|
"rp2040-boot2",
|
||||||
"rp2040-hal",
|
"rp2040-hal",
|
||||||
|
@ -17,9 +17,8 @@ cortex-m-rt = "0.7"
|
|||||||
rp2040-boot2 = { version = "0.3.0", optional = true }
|
rp2040-boot2 = { version = "0.3.0", optional = true }
|
||||||
rp2040-hal = {version = "0.10.2", features = ["rtic-monotonic"]}
|
rp2040-hal = {version = "0.10.2", features = ["rtic-monotonic"]}
|
||||||
waveshare-rp2040-zero = { version = "0.8.0", features = ["rt"] }
|
waveshare-rp2040-zero = { version = "0.8.0", features = ["rt"] }
|
||||||
|
cortex-m-rtic = { version = "1", features = [] }
|
||||||
cortex-m-rtic = "1"
|
embedded-hal = {version = "1.0.0", features = []}
|
||||||
embedded-hal = "1.0.0"
|
|
||||||
|
|
||||||
usb-device = "0.3.2"
|
usb-device = "0.3.2"
|
||||||
|
|
||||||
@ -31,6 +30,8 @@ usbd-serial = "0.2.2"
|
|||||||
|
|
||||||
smart-leds = "0.3.0"
|
smart-leds = "0.3.0"
|
||||||
ws2812-pio = "0.8.0"
|
ws2812-pio = "0.8.0"
|
||||||
|
|
||||||
w5500-dhcp = { version = "0.7", features = ["eh0", "log"] }
|
w5500-dhcp = { version = "0.7", features = ["eh0", "log"] }
|
||||||
w5500-mqtt = { version = "0.4", features = ["eh0", "log"] }
|
w5500-mqtt = { version = "0.4", features = ["eh0", "log"] }
|
||||||
heapless = "0.8.0"
|
log = "0.4.22"
|
||||||
|
heapless = "0.8"
|
441
src/main.rs
441
src/main.rs
@ -1,15 +1,15 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use panic_halt as _;
|
use panic_halt as _;
|
||||||
|
|
||||||
#[rtic::app(device = waveshare_rp2040_zero::hal::pac, peripherals = true, dispatchers = [I2C0_IRQ])]
|
#[rtic::app(device = waveshare_rp2040_zero::hal::pac, peripherals = true, dispatchers = [I2C0_IRQ])]
|
||||||
mod app {
|
mod app {
|
||||||
|
use core::convert::TryInto;
|
||||||
use core::iter::once;
|
use core::iter::once;
|
||||||
use cortex_m::delay::Delay;
|
use cortex_m::delay::Delay;
|
||||||
use fugit::MicrosDurationU32;
|
use fugit::MicrosDurationU32;
|
||||||
use fugit::RateExtU32;
|
use fugit::RateExtU32;
|
||||||
use rp2040_hal::gpio::bank0::{Gpio16, Gpio2, Gpio3, Gpio4, Gpio5, Gpio7};
|
use rp2040_hal::gpio::bank0::{Gpio16, Gpio2, Gpio3, Gpio4, Gpio5};
|
||||||
use rp2040_hal::gpio::{
|
use rp2040_hal::gpio::{
|
||||||
FunctionPio0, FunctionSio, FunctionSpi, Pin, PullDown, PullNone, PullUp, SioOutput,
|
FunctionPio0, FunctionSio, FunctionSpi, Pin, PullDown, PullNone, PullUp, SioOutput,
|
||||||
};
|
};
|
||||||
@ -18,6 +18,7 @@ mod app {
|
|||||||
use rp2040_hal::{Clock, Spi};
|
use rp2040_hal::{Clock, Spi};
|
||||||
use smart_leds::{brightness, SmartLedsWrite};
|
use smart_leds::{brightness, SmartLedsWrite};
|
||||||
use usbd_serial::SerialPort;
|
use usbd_serial::SerialPort;
|
||||||
|
use waveshare_rp2040_zero::hal::prelude::*;
|
||||||
use waveshare_rp2040_zero::hal::spi::Enabled;
|
use waveshare_rp2040_zero::hal::spi::Enabled;
|
||||||
use waveshare_rp2040_zero::{
|
use waveshare_rp2040_zero::{
|
||||||
hal::{
|
hal::{
|
||||||
@ -32,6 +33,7 @@ mod app {
|
|||||||
use waveshare_rp2040_zero::hal::pio::PIOExt;
|
use waveshare_rp2040_zero::hal::pio::PIOExt;
|
||||||
use ws2812_pio::Ws2812;
|
use ws2812_pio::Ws2812;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use embedded_hal::digital::OutputPin;
|
use embedded_hal::digital::OutputPin;
|
||||||
use fugit::ExtU32;
|
use fugit::ExtU32;
|
||||||
@ -70,16 +72,15 @@ mod app {
|
|||||||
cortex_m::asm::delay(CYCLES_PER_MILLIS.saturating_mul(ms));
|
cortex_m::asm::delay(CYCLES_PER_MILLIS.saturating_mul(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BlinkState {
|
fn monotonic_secs() -> u32 {
|
||||||
GOOD,
|
app::monotonics::now()
|
||||||
Init,
|
.duration_since_epoch()
|
||||||
EthernetError,
|
.to_secs()
|
||||||
OtherError,
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {
|
struct Shared {
|
||||||
timer: hal::Timer,
|
|
||||||
usb_dev: UsbDevice<'static, hal::usb::UsbBus>,
|
usb_dev: UsbDevice<'static, hal::usb::UsbBus>,
|
||||||
serial: SerialPort<'static, hal::usb::UsbBus>,
|
serial: SerialPort<'static, hal::usb::UsbBus>,
|
||||||
ws: Ws2812<PIO0, SM0, CountDown<'static>, hal::gpio::Pin<Gpio16, FunctionPio0, PullDown>>,
|
ws: Ws2812<PIO0, SM0, CountDown<'static>, hal::gpio::Pin<Gpio16, FunctionPio0, PullDown>>,
|
||||||
@ -95,8 +96,10 @@ mod app {
|
|||||||
>,
|
>,
|
||||||
Pin<Gpio5, FunctionSio<SioOutput>, PullDown>,
|
Pin<Gpio5, FunctionSio<SioOutput>, PullDown>,
|
||||||
>,
|
>,
|
||||||
spi_reset: Pin<Gpio7, FunctionSio<SioOutput>, PullDown>,
|
dhcp: DhcpClient<'static>,
|
||||||
blink_state: BlinkState,
|
mqtt: MqttClient<'static>,
|
||||||
|
dhcp_spawn_at: Option<u32>,
|
||||||
|
mqtt_spawn_at: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
@ -120,8 +123,8 @@ mod app {
|
|||||||
&mut resets,
|
&mut resets,
|
||||||
&mut watchdog,
|
&mut watchdog,
|
||||||
)
|
)
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let sio = Sio::new(c.device.SIO);
|
let sio = Sio::new(c.device.SIO);
|
||||||
let pins = waveshare_rp2040_zero::Pins::new(
|
let pins = waveshare_rp2040_zero::Pins::new(
|
||||||
@ -131,29 +134,53 @@ mod app {
|
|||||||
&mut resets,
|
&mut resets,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Set up our SPI pins into the correct mode
|
||||||
|
let spi_sclk: hal::gpio::Pin<_, hal::gpio::FunctionSpi, hal::gpio::PullNone> =
|
||||||
|
pins.gp2.reconfigure();
|
||||||
|
let spi_mosi: hal::gpio::Pin<_, hal::gpio::FunctionSpi, hal::gpio::PullNone> =
|
||||||
|
pins.gp3.reconfigure();
|
||||||
|
let spi_miso: hal::gpio::Pin<_, hal::gpio::FunctionSpi, hal::gpio::PullUp> =
|
||||||
|
pins.gp4.reconfigure();
|
||||||
|
let spi_cs = pins.gp5.into_push_pull_output();
|
||||||
|
let mut spi_reset = pins.gp7.into_push_pull_output();
|
||||||
|
|
||||||
|
// Create the SPI driver instance for the SPI0 device
|
||||||
|
let spi = hal::spi::Spi::<_, _, _, 8>::new(c.device.SPI0, (spi_mosi, spi_miso, spi_sclk));
|
||||||
|
// Exchange the uninitialised SPI driver for an initialised one
|
||||||
|
let spi = spi.init(
|
||||||
|
&mut resets,
|
||||||
|
clocks.peripheral_clock.freq(),
|
||||||
|
1.MHz(),
|
||||||
|
W5500_MODE,
|
||||||
|
);
|
||||||
|
let mut w5500 = W5500::new(spi, spi_cs);
|
||||||
|
|
||||||
|
w5500_dhcp::ll::eh0::reset(&mut spi_reset, &mut Delay::new(c.core.SYST, SYSCLK_HZ))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
//let timer = Timer::new(c.device.TIMER, &mut c.device.RESETS, &clocks);
|
//let timer = Timer::new(c.device.TIMER, &mut c.device.RESETS, &clocks);
|
||||||
let dTIMER = c.device.TIMER;
|
let dTIMER = c.device.TIMER;
|
||||||
let timer = cortex_m::singleton!(: hal::Timer = hal::Timer::new(dTIMER, &mut resets, &clocks)).unwrap();
|
let timer =
|
||||||
|
cortex_m::singleton!(: hal::Timer = hal::Timer::new(dTIMER, &mut resets, &clocks))
|
||||||
|
.unwrap();
|
||||||
let mut alarm = timer.alarm_0().unwrap();
|
let mut alarm = timer.alarm_0().unwrap();
|
||||||
|
|
||||||
let count_down: CountDown<'static> = timer.count_down();
|
let count_down: CountDown<'static> = timer.count_down();
|
||||||
|
|
||||||
let (mut pio, sm0, _, _, _) = c.device.PIO0.split(&mut resets);
|
|
||||||
let ws: Ws2812<PIO0, SM0, CountDown<'static>, hal::gpio::Pin<Gpio16, FunctionPio0, PullDown>> = Ws2812::new(
|
|
||||||
// The onboard NeoPixel is attached to GPIO pin #16 on the Waveshare RP2040-Zero.
|
|
||||||
pins.neopixel.into_function(),
|
|
||||||
&mut pio,
|
|
||||||
sm0,
|
|
||||||
clocks.peripheral_clock.freq(),
|
|
||||||
count_down,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let (mut pio, sm0, _, _, _) = c.device.PIO0.split(&mut resets);
|
||||||
|
let ws: Ws2812<
|
||||||
|
PIO0,
|
||||||
|
SM0,
|
||||||
|
CountDown<'static>,
|
||||||
|
hal::gpio::Pin<Gpio16, FunctionPio0, PullDown>,
|
||||||
|
> = Ws2812::new(
|
||||||
|
// The onboard NeoPixel is attached to GPIO pin #16 on the Waveshare RP2040-Zero.
|
||||||
|
pins.neopixel.into_function(),
|
||||||
|
&mut pio,
|
||||||
|
sm0,
|
||||||
|
clocks.peripheral_clock.freq(),
|
||||||
|
count_down,
|
||||||
|
);
|
||||||
|
|
||||||
// Set up the USB driver
|
// Set up the USB driver
|
||||||
let USBCTRL_REGS = c.device.USBCTRL_REGS;
|
let USBCTRL_REGS = c.device.USBCTRL_REGS;
|
||||||
@ -183,176 +210,210 @@ mod app {
|
|||||||
|
|
||||||
let _ = serial.write(b"Hello, World!\r\n");
|
let _ = serial.write(b"Hello, World!\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let _ = alarm.schedule(SCAN_TIME_US);
|
let _ = alarm.schedule(SCAN_TIME_US);
|
||||||
alarm.enable_interrupt();
|
alarm.enable_interrupt();
|
||||||
|
|
||||||
timer_irq::spawn_after(500_u32.millis().into()).unwrap();
|
let mac: Eui48Addr = Eui48Addr::new(0x00, 0x08, 0xDC, 0x00, 0x00, 0x00);
|
||||||
|
|
||||||
// init ethernet stuff
|
timer_irq::spawn().unwrap();
|
||||||
|
|
||||||
// Set up our SPI pins into the correct mode
|
// continually initialize the W5500 until we link up
|
||||||
let spi_sclk: hal::gpio::Pin<_, hal::gpio::FunctionSpi, hal::gpio::PullNone> =
|
// since we are using power over Ethernet we know that if the device
|
||||||
pins.gp2.reconfigure();
|
// has power it also has an Ethernet cable connected.
|
||||||
let spi_mosi: hal::gpio::Pin<_, hal::gpio::FunctionSpi, hal::gpio::PullNone> =
|
let _phy_cfg: PhyCfg = 'outer: loop {
|
||||||
pins.gp3.reconfigure();
|
// sanity check W5500 communications
|
||||||
let spi_miso: hal::gpio::Pin<_, hal::gpio::FunctionSpi, hal::gpio::PullUp> =
|
assert_eq!(w5500.version().unwrap(), w5500_dhcp::ll::VERSION);
|
||||||
pins.gp4.reconfigure();
|
|
||||||
let spi_cs = pins.gp5.into_push_pull_output();
|
|
||||||
let mut spi_reset = pins.gp7.into_push_pull_output();
|
|
||||||
|
|
||||||
// Create the SPI driver instance for the SPI0 device
|
// load the MAC address we got from EEPROM
|
||||||
let spi = hal::spi::Spi::<_, _, _, 8>::new(c.device.SPI0, (spi_mosi, spi_miso, spi_sclk));
|
w5500.set_shar(&mac).unwrap();
|
||||||
// Exchange the uninitialised SPI driver for an initialised one
|
debug_assert_eq!(w5500.shar().unwrap(), mac);
|
||||||
let spi = spi.init(
|
|
||||||
&mut resets,
|
// wait for the PHY to indicate the Ethernet link is up
|
||||||
clocks.peripheral_clock.freq(),
|
let mut attempts: u32 = 0;
|
||||||
400.kHz(),
|
serial.write(b"Polling for link up\r\n");
|
||||||
W5500_MODE,
|
const PHY_CFG: PhyCfg = PhyCfg::DEFAULT.set_opmdc(OperationMode::FullDuplex10bt);
|
||||||
|
w5500.set_phycfgr(PHY_CFG).unwrap();
|
||||||
|
|
||||||
|
const LINK_UP_POLL_PERIOD_MILLIS: u32 = 100;
|
||||||
|
const LINK_UP_POLL_ATTEMPTS: u32 = 50;
|
||||||
|
loop {
|
||||||
|
let phy_cfg: PhyCfg = w5500.phycfgr().unwrap();
|
||||||
|
if phy_cfg.lnk() == LinkStatus::Up {
|
||||||
|
break 'outer phy_cfg;
|
||||||
|
}
|
||||||
|
if attempts >= LINK_UP_POLL_ATTEMPTS {
|
||||||
|
let mut data: heapless::String<16> = heapless::String::new();
|
||||||
|
write!(
|
||||||
|
&mut data,
|
||||||
|
"Failed to link up in {} ms\r\n",
|
||||||
|
attempts * LINK_UP_POLL_PERIOD_MILLIS
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
serial.write(data.as_bytes());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delay_ms(LINK_UP_POLL_PERIOD_MILLIS);
|
||||||
|
attempts += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_reset.set_low().unwrap();
|
||||||
|
delay_ms(1);
|
||||||
|
spi_reset.set_high().unwrap();
|
||||||
|
delay_ms(3);
|
||||||
|
};
|
||||||
|
let mut data: heapless::String<16> = heapless::String::new();
|
||||||
|
write!(&mut data, "Done link up\n{}", _phy_cfg).unwrap();
|
||||||
|
|
||||||
|
serial.write(data.as_bytes());
|
||||||
|
|
||||||
|
let mut mqtt: MqttClient = MqttClient::new(MQTT_SN, MQTT_SRC_PORT, MQTT_SERVER);
|
||||||
|
mqtt.set_client_id(CLIENT_ID);
|
||||||
|
|
||||||
|
let seed: u64 = u64::from(cortex_m::peripheral::SYST::get_current()) << 32
|
||||||
|
| u64::from(cortex_m::peripheral::SYST::get_current());
|
||||||
|
|
||||||
|
let dhcp = DhcpClient::new(DHCP_SN, seed, mac, HOSTNAME);
|
||||||
|
dhcp.setup_socket(&mut w5500).unwrap();
|
||||||
|
|
||||||
|
// start the DHCP client
|
||||||
|
//dhcp_sn::spawn().unwrap();
|
||||||
|
|
||||||
|
// start the timeout tracker
|
||||||
|
//timeout_tracker::spawn().unwrap();
|
||||||
|
|
||||||
|
(
|
||||||
|
Shared {
|
||||||
|
usb_dev,
|
||||||
|
serial,
|
||||||
|
ws,
|
||||||
|
w5500,
|
||||||
|
dhcp,
|
||||||
|
mqtt,
|
||||||
|
dhcp_spawn_at: None,
|
||||||
|
mqtt_spawn_at: None,
|
||||||
|
},
|
||||||
|
Local {},
|
||||||
|
init::Monotonics(Monotonic::new(*timer, alarm)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(shared = [dhcp_spawn_at, mqtt_spawn_at])]
|
||||||
|
fn timeout_tracker(mut cx: timeout_tracker::Context) {
|
||||||
|
timeout_tracker::spawn_after(1_u32.secs().into()).unwrap();
|
||||||
|
|
||||||
|
let now: u32 = monotonic_secs();
|
||||||
|
|
||||||
|
cx.shared.dhcp_spawn_at.lock(|dhcp_spawn_at| {
|
||||||
|
if let Some(then) = dhcp_spawn_at {
|
||||||
|
if now >= *then {
|
||||||
|
if dhcp_sn::spawn().is_err() {
|
||||||
|
log::error!("DHCP task is already spawned")
|
||||||
|
}
|
||||||
|
*dhcp_spawn_at = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.shared.mqtt_spawn_at.lock(|mqtt_spawn_at| {
|
||||||
|
if let Some(then) = mqtt_spawn_at {
|
||||||
|
if now >= *then {
|
||||||
|
if mqtt_sn::spawn().is_err() {
|
||||||
|
log::error!("MQTT task is already spawned")
|
||||||
|
}
|
||||||
|
*mqtt_spawn_at = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[task(shared = [w5500, mqtt, mqtt_spawn_at], local = [])]
|
||||||
|
fn mqtt_sn(cx: mqtt_sn::Context) {
|
||||||
|
log::info!("[TASK] mqtt_sn");
|
||||||
|
|
||||||
|
(cx.shared.w5500, cx.shared.mqtt, cx.shared.mqtt_spawn_at).lock(
|
||||||
|
|w5500, mqtt, mqtt_spawn_at| {
|
||||||
|
loop {
|
||||||
|
let now: u32 = monotonic_secs();
|
||||||
|
match mqtt.process(w5500, now) {
|
||||||
|
Ok(MqttEvent::CallAfter(secs)) => {
|
||||||
|
*mqtt_spawn_at = Some(now + secs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ok(MqttEvent::ConnAck) => {
|
||||||
|
log::info!("[MQTT] ConnAck");
|
||||||
|
// can subscribe to topics here
|
||||||
|
// not needed for this
|
||||||
|
}
|
||||||
|
Ok(MqttEvent::Publish(reader)) => {
|
||||||
|
log::warn!("should not get Publish never subscribed");
|
||||||
|
reader.done().unwrap();
|
||||||
|
}
|
||||||
|
Ok(MqttEvent::SubAck(_) | MqttEvent::UnSubAck(_)) => {
|
||||||
|
log::warn!("should not get (Un)SubAck, never (un)subscribed");
|
||||||
|
}
|
||||||
|
Ok(MqttEvent::None) => {
|
||||||
|
{
|
||||||
|
let mut data: heapless::String<16> = heapless::String::new();
|
||||||
|
write!(&mut data, "{:.1}", 42).unwrap();
|
||||||
|
mqtt.publish(w5500, "test", data.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
*mqtt_spawn_at = Some(now + 5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("[MQTT] {e:?}");
|
||||||
|
*mqtt_spawn_at = Some(now + 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
let w5500 = W5500::new(spi, spi_cs);
|
}
|
||||||
|
|
||||||
w5500_dhcp::ll::eh0::reset(&mut spi_reset, &mut Delay::new(c.core.SYST, SYSCLK_HZ))
|
#[task(shared = [w5500, dhcp, dhcp_spawn_at])]
|
||||||
.unwrap();
|
fn dhcp_sn(cx: dhcp_sn::Context) {
|
||||||
|
log::info!("[TASK] dhcp_sn");
|
||||||
|
|
||||||
init_ethernet::spawn_after(5000_u32.millis().into()).unwrap();
|
(cx.shared.w5500, cx.shared.dhcp, cx.shared.dhcp_spawn_at).lock(
|
||||||
|
|w5500, dhcp, dhcp_spawn_at| {
|
||||||
|
let leased_before: bool = dhcp.has_lease();
|
||||||
|
let now: u32 = monotonic_secs();
|
||||||
|
let spawn_after_secs: u32 = dhcp.process(w5500, now).unwrap();
|
||||||
|
|
||||||
(Shared { timer: *timer, usb_dev, serial, ws, w5500,spi_reset, blink_state: BlinkState::Init}, Local {}, init::Monotonics(Monotonic::new(*timer, alarm)))
|
let spawn_at: u32 = now + spawn_after_secs;
|
||||||
|
*dhcp_spawn_at = Some(spawn_at);
|
||||||
|
log::info!("[DHCP] spawning after {spawn_after_secs} seconds, at {spawn_at}");
|
||||||
|
|
||||||
|
// spawn MQTT task if bound
|
||||||
|
if dhcp.has_lease() && !leased_before && mqtt_sn::spawn().is_err() {
|
||||||
|
log::error!("MQTT task is already spawned")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(
|
#[task(
|
||||||
priority = 1,
|
priority = 1,
|
||||||
shared = [serial, ws, blink_state],
|
shared = [serial, ws],
|
||||||
local = [tog: bool = true],
|
local = [tog: bool = true],
|
||||||
)]
|
)]
|
||||||
fn timer_irq(c: timer_irq::Context) {
|
fn timer_irq(mut c: timer_irq::Context) {
|
||||||
let blink_state = c.shared.blink_state;
|
if *c.local.tog {
|
||||||
let ws = c.shared.ws;
|
c.shared
|
||||||
let serial = c.shared.serial;
|
.ws
|
||||||
let tog = c.local.tog;
|
.lock(|ws| ws.write(brightness(once((255, 0, 0).into()), 32)).unwrap());
|
||||||
|
c.shared.serial.lock(|serial| _ = serial.write(b"High\r\n"));
|
||||||
(blink_state, ws, serial).lock(|blink_state, ws, serial| {
|
} else {
|
||||||
if *tog {
|
c.shared
|
||||||
match blink_state {
|
.ws
|
||||||
BlinkState::GOOD => {
|
.lock(|ws| ws.write(brightness(once((0, 0, 0).into()), 32)).unwrap());
|
||||||
ws.write(brightness(once((0, 255, 0).into()), 25)).unwrap();
|
c.shared.serial.lock(|serial| _ = serial.write(b"LOW\r\n"));
|
||||||
_ = serial.write(b"High\r\n");
|
}
|
||||||
}
|
*c.local.tog = !*c.local.tog;
|
||||||
BlinkState::Init => {
|
|
||||||
ws.write(brightness(once((0, 0, 255).into()), 25)).unwrap();
|
|
||||||
_ = serial.write(b"Init\r\n");
|
|
||||||
}
|
|
||||||
BlinkState::EthernetError => {
|
|
||||||
ws.write(brightness(once((255, 255, 0).into()), 25)).unwrap();
|
|
||||||
_ = serial.write(b"Ethernet error error\r\n");
|
|
||||||
}
|
|
||||||
BlinkState::OtherError => {
|
|
||||||
ws.write(brightness(once((255, 0, 0).into()), 25)).unwrap();
|
|
||||||
_ = serial.write(b"Other error\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ws.write(brightness(once((0, 0, 0).into()), 32)).unwrap();
|
|
||||||
}
|
|
||||||
*tog = !*tog;
|
|
||||||
});
|
|
||||||
|
|
||||||
timer_irq::spawn_after(250.millis().into()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task(
|
|
||||||
shared = [w5500, serial,spi_reset, blink_state],)
|
|
||||||
]
|
|
||||||
fn init_ethernet(c: init_ethernet::Context) {
|
|
||||||
let mac: Eui48Addr = Eui48Addr::new(0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED );
|
|
||||||
|
|
||||||
let w5500 = c.shared.w5500;
|
|
||||||
let serial = c.shared.serial;
|
|
||||||
let spi_reset = c.shared.spi_reset;
|
|
||||||
let blink_state = c.shared.blink_state;
|
|
||||||
|
|
||||||
(w5500, serial,spi_reset, blink_state).lock(|w5500, serial, spi_reset, blink_state| {
|
|
||||||
// continually initialize the W5500 until we link up
|
|
||||||
// since we are using power over Ethernet we know that if the device
|
|
||||||
// has power it also has an Ethernet cable connected.
|
|
||||||
let _phy_cfg: PhyCfg = 'outer: loop {
|
|
||||||
// sanity check W5500 communications
|
|
||||||
_ = serial.write(b"Sanity checks\r\n");
|
|
||||||
let version = w5500.version();
|
|
||||||
match version {
|
|
||||||
Ok(v) => {
|
|
||||||
let mut data: heapless::String<16> = heapless::String::new();
|
|
||||||
write!(
|
|
||||||
&mut data,
|
|
||||||
"Read version of w5500 {}\r\n",
|
|
||||||
v
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
_ = serial.write(data.as_bytes());
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
_ = serial.write(b"Failed to read W5500 version\r\n");
|
|
||||||
*blink_state = BlinkState::EthernetError;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ = serial.write(b"Sanity checks passed\r\n");
|
|
||||||
|
|
||||||
// load the MAC address we got from EEPROM
|
|
||||||
w5500.set_shar(&mac).unwrap();
|
|
||||||
debug_assert_eq!(w5500.shar().unwrap(), mac);
|
|
||||||
|
|
||||||
// wait for the PHY to indicate the Ethernet link is up
|
|
||||||
let mut attempts: u32 = 0;
|
|
||||||
_ = serial.write(b"Polling for link up\r\n");
|
|
||||||
const PHY_CFG: PhyCfg = PhyCfg::DEFAULT.set_opmdc(OperationMode::FullDuplex10bt);
|
|
||||||
w5500.set_phycfgr(PHY_CFG).unwrap();
|
|
||||||
|
|
||||||
const LINK_UP_POLL_PERIOD_MILLIS: u32 = 100;
|
|
||||||
const LINK_UP_POLL_ATTEMPTS: u32 = 50;
|
|
||||||
loop {
|
|
||||||
let phy_cfg: PhyCfg = w5500.phycfgr().unwrap();
|
|
||||||
if phy_cfg.lnk() == LinkStatus::Up {
|
|
||||||
break 'outer phy_cfg;
|
|
||||||
}
|
|
||||||
if attempts >= LINK_UP_POLL_ATTEMPTS {
|
|
||||||
let mut data: heapless::String<16> = heapless::String::new();
|
|
||||||
write!(
|
|
||||||
&mut data,
|
|
||||||
"Failed to link up in {} ms\r\n",
|
|
||||||
attempts * LINK_UP_POLL_PERIOD_MILLIS
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
_ = serial.write(data.as_bytes());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
delay_ms(LINK_UP_POLL_PERIOD_MILLIS);
|
|
||||||
attempts += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
spi_reset.set_low().unwrap();
|
|
||||||
delay_ms(1);
|
|
||||||
spi_reset.set_high().unwrap();
|
|
||||||
delay_ms(3);
|
|
||||||
};
|
|
||||||
let mut data: heapless::String<16> = heapless::String::new();
|
|
||||||
write!(&mut data, "Done link up\n{}", _phy_cfg).unwrap();
|
|
||||||
|
|
||||||
_ = serial.write(data.as_bytes());
|
|
||||||
|
|
||||||
let mut mqtt: MqttClient = MqttClient::new(MQTT_SN, MQTT_SRC_PORT, MQTT_SERVER);
|
|
||||||
mqtt.set_client_id(CLIENT_ID);
|
|
||||||
|
|
||||||
let seed: u64 = u64::from(cortex_m::peripheral::SYST::get_current()) << 32
|
|
||||||
| u64::from(cortex_m::peripheral::SYST::get_current());
|
|
||||||
|
|
||||||
let dhcp = DhcpClient::new(DHCP_SN, seed, mac, HOSTNAME);
|
|
||||||
dhcp.setup_socket(w5500).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
timer_irq::spawn_after(500.millis().into()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(
|
#[task(
|
||||||
@ -394,6 +455,14 @@ mod app {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// This is the W5500 interrupt.
|
||||||
|
///
|
||||||
|
/// The only interrupts we should get are for the DHCP & MQTT sockets.
|
||||||
|
#[task(binds = SPI0_IRQ, local = [], shared = [w5500])]
|
||||||
|
#[allow(clippy::collapsible_if)]
|
||||||
|
fn exti0(mut cx: exti0::Context) {
|
||||||
|
log::info!("[TASK] exti0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user