diff --git a/Cargo.lock b/Cargo.lock index bce6cde..7eba5e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "az" version = "1.2.1" @@ -136,6 +142,19 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "embedded-graphics" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd2a8e0250a7e1212828166b01eed0219e488ebb2599f44624a29c9bd249f397" +dependencies = [ + "az", + "byteorder", + "embedded-graphics-core", + "float-cmp", + "micromath", +] + [[package]] name = "embedded-graphics-core" version = "0.4.0" @@ -156,6 +175,15 @@ dependencies = [ "void", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fugit" version = "0.3.7" @@ -180,6 +208,12 @@ dependencies = [ "either", ] +[[package]] +name = "micromath" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39617bc909d64b068dcffd0e3e31679195b5576d0c83fadc52690268cc2b2b55" + [[package]] name = "nb" version = "0.1.3" @@ -195,6 +229,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "num_enum" version = "0.5.11" @@ -359,11 +402,17 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" name = "soldering-iron" version = "0.1.0" dependencies = [ + "cortex-m", "cortex-m-rt", + "display-interface", + "embedded-graphics", + "embedded-hal", "fugit", "panic-halt", "rp-pico", "ssd1306", + "usb-device", + "usbd-serial", ] [[package]] @@ -408,6 +457,17 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" +[[package]] +name = "usbd-serial" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db75519b86287f12dcf0d171c7cf4ecc839149fe9f3b720ac4cfce52959e1dfe" +dependencies = [ + "embedded-hal", + "nb 0.1.3", + "usb-device", +] + [[package]] name = "vcell" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index 0a5adc2..c118b48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +cortex-m = "0.7.7" cortex-m-rt = "0.7.3" +display-interface = "0.4.1" +embedded-graphics = "0.8.0" +embedded-hal = "0.2.7" fugit = "0.3.7" panic-halt = "0.2.0" rp-pico = "0.7.0" ssd1306 = "0.8.0" +usb-device = "0.2.9" +usbd-serial = "0.1.1" diff --git a/src/main.rs b/src/main.rs index c3f7e09..9f7d5fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,80 @@ #![no_std] #![no_main] +use cortex_m::delay::Delay; + +use display_interface::DisplayError; + +use embedded_graphics::{ + mono_font::{ascii::FONT_6X10, MonoTextStyleBuilder}, + pixelcolor::BinaryColor, + prelude::*, + text::{Baseline, Text}, +}; + +use embedded_hal::digital::v2::{InputPin, ToggleableOutputPin}; + use fugit::RateExtU32; use panic_halt as _; -use rp_pico::entry; -use rp_pico::hal::clocks::{self, Clock}; -use rp_pico::hal::i2c::I2C; -use rp_pico::hal::{Sio, Watchdog}; -use rp_pico::pac::Peripherals; -use rp_pico::Pins; +use rp_pico::{ + entry, + hal::{ + clocks::{self, Clock}, + gpio::PinState, + i2c::I2C, + usb::UsbBus, + Sio, Watchdog, + }, + pac::{CorePeripherals, Peripherals}, + Pins, +}; -use ssd1306::prelude::*; -use ssd1306::{I2CDisplayInterface, Ssd1306}; +use ssd1306::{prelude::*, I2CDisplayInterface, Ssd1306}; + +use usb_device::{bus::UsbBus as UsbBusTrait, bus::UsbBusAllocator, prelude::*}; + +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +fn print_serial<'a, B: UsbBusTrait>( + serial: &mut SerialPort<'a, B>, + msg: &str, +) -> Result<(), UsbError> { + let buf = msg.as_bytes(); + let mut pos = 0; + + while pos < buf.len() { + match serial.write(&buf[pos..]) { + Ok(count) => { + pos += count; + continue; + } + Err(UsbError::WouldBlock) => continue, + Err(err) => return Err(err), + } + } + + Ok(()) +} + +fn stringify_display_error(err: DisplayError) -> &'static str { + match err { + DisplayError::InvalidFormatError => "invalid format", + DisplayError::BusWriteError => "bus write error", + DisplayError::DCError => "dc error", + DisplayError::CSError => "cs error", + DisplayError::DataFormatNotImplemented => "data format not implemented", + DisplayError::RSError => "rs error", + DisplayError::OutOfBoundsError => "out of bounds", + _ => "unknown error", + } +} #[entry] fn main() -> ! { let mut p = Peripherals::take().unwrap(); + let cp = CorePeripherals::take().unwrap(); let mut watchdog = Watchdog::new(p.WATCHDOG); let clocks = clocks::init_clocks_and_plls( @@ -32,25 +89,114 @@ fn main() -> ! { .ok() .unwrap(); + let mut delay = Delay::new(cp.SYST, clocks.system_clock.freq().to_Hz()); + let sio = Sio::new(p.SIO); let pins = Pins::new(p.IO_BANK0, p.PADS_BANK0, sio.gpio_bank0, &mut p.RESETS); + let usb_bus = UsbBusAllocator::new(UsbBus::new( + p.USBCTRL_REGS, + p.USBCTRL_DPRAM, + clocks.usb_clock, + true, + &mut p.RESETS, + )); + + let mut serial = SerialPort::new(&usb_bus); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x2342, 0x1337)) + .manufacturer("lujoga") + .product("Soldering Iron") + .device_class(USB_CLASS_CDC) + .build(); + + for _ in 0..2000 { + delay.delay_ms(5); + + if !usb_dev.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8]; + match serial.read(&mut buf[..]) { + Ok(_) => break, + _ => (), + } + } + + let _ = print_serial(&mut serial, "Hello, world!\r\n"); + let i2c = I2C::i2c0( p.I2C0, - pins.gpio16.into_mode(), - pins.gpio17.into_mode(), + pins.gpio0.into_mode(), + pins.gpio1.into_mode(), 400.kHz(), &mut p.RESETS, clocks.peripheral_clock.freq(), ); + let mut display = Ssd1306::new( - I2CDisplayInterface::new_custom_address(i2c, 0x78), + I2CDisplayInterface::new_custom_address(i2c, 0x3c), DisplaySize128x64, DisplayRotation::Rotate0, ) .into_buffered_graphics_mode(); - display.init().unwrap(); + let result = display.init().map_err(stringify_display_error); + if let Err(msg) = result { + let _ = print_serial(&mut serial, msg); + panic!(); + } - loop {} + let text_style = MonoTextStyleBuilder::new() + .font(&FONT_6X10) + .text_color(BinaryColor::On) + .build(); + + let result = Text::with_baseline("Hello, world!", Point::zero(), text_style, Baseline::Top) + .draw(&mut display) + .map_err(stringify_display_error); + if let Err(msg) = result { + let _ = print_serial(&mut serial, msg); + panic!(); + } + + let result = display.flush().map_err(stringify_display_error); + if let Err(msg) = result { + let _ = print_serial(&mut serial, msg); + } + + let mut relay = pins.gpio14.into_push_pull_output_in_state(PinState::Low); + let tmp_button = pins.gpio15.into_pull_up_input(); + + let mut led = pins.led.into_push_pull_output_in_state(PinState::Low); + + let mut counter = 0; + loop { + delay.delay_ms(5); + counter = (counter + 1) % 100; + + if counter == 0 { + led.toggle().unwrap(); + + let _ = print_serial(&mut serial, "ping\r\n"); + } + + if tmp_button.is_low().unwrap() { + relay.toggle().unwrap(); + delay.delay_ms(1000); + } + + if !usb_dev.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8; 64]; + match serial.read(&mut buf[..]) { + Ok(count) => { + let _ = serial.write(&buf[..count]); + } + _ => (), + } + } }