From 15d5c8576b4a34ff757737dc72670590695dc9af Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 22 Jan 2023 12:22:05 -0800 Subject: [PATCH 01/45] Working copy pasted base code. --- boards/neo_trinkey/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/neo_trinkey/Cargo.toml b/boards/neo_trinkey/Cargo.toml index 743d465d4107..be08832124b9 100644 --- a/boards/neo_trinkey/Cargo.toml +++ b/boards/neo_trinkey/Cargo.toml @@ -15,6 +15,7 @@ cortex-m-rt = { version = "0.7", optional = true } usb-device = { version = "0.2", optional = true } smart-leds = { version = "0.3.0", optional = true } ws2812-timer-delay = { version = "0.3.0", features = ["slow"], optional = true } +cargo-hf2 = "0.3.3" [dependencies.atsamd-hal] version = "0.14" From b16e31052992b0d7a12dd1748c67533168544be4 Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 22 Jan 2023 12:22:52 -0800 Subject: [PATCH 02/45] Adding so far unused import --- .../examples/blinky_usb_morse_out.rs | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 boards/neo_trinkey/examples/blinky_usb_morse_out.rs diff --git a/boards/neo_trinkey/examples/blinky_usb_morse_out.rs b/boards/neo_trinkey/examples/blinky_usb_morse_out.rs new file mode 100644 index 000000000000..19b324bcdacf --- /dev/null +++ b/boards/neo_trinkey/examples/blinky_usb_morse_out.rs @@ -0,0 +1,109 @@ +#![no_std] +#![no_main] +use panic_halt as _; + +use cortex_m::asm::delay as cycle_delay; +use cortex_m::peripheral::NVIC; +use usb_device::bus::UsbBusAllocator; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use neo_trinkey as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use hal::clock::GenericClockController; +use hal::usb::UsbBus; +use pac::{interrupt, CorePeripherals, Peripherals}; + +// Added +use hal::delay::Delay; +// use hal::pac::{CorePeripherals, Peripherals}; +// use hal::prelude::*; +// use hal::timer::TimerCounter; + +// use smart_leds::{hsv::RGB8, SmartLedsWrite}; +// use ws2812_timer_delay::Ws2812; +// End Added + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + unsafe { + USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TRINKEY_ACK") + .device_class(USB_CLASS_CDC) + .build(), + ); + } + + unsafe { + core.NVIC.set_priority(interrupt::USB, 1); + NVIC::unmask(interrupt::USB); + } + + loop { + cycle_delay(15 * 1024 * 1024); + } +} + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; + +fn poll_usb() { + unsafe { + USB_BUS.as_mut().map(|usb_dev| { + USB_SERIAL.as_mut().map(|serial| { + usb_dev.poll(&mut [serial]); + let mut buf = [0u8; 64]; + + if let Ok(count) = serial.read(&mut buf) { + for (i, c) in buf.iter().enumerate() { + if i >= count { + break; + } + serial.write("Received: ".as_bytes()).ok(); + serial.write(&[c.clone()]).ok(); + serial.write("\r\n".as_bytes()).ok(); + } + }; + }); + }); + }; +} + +#[interrupt] +fn USB() { + // Note: USB is the name of the interrupt, you can not attach the #[interrupt] + // tag to poll_usb. Although you could add the contents of poll_usb into + // this function, separating them allows you to add more functions to run on + // the USB interrupt in the future. + poll_usb(); +} From ba13a1a0fc339545d741e39e53a13c3d0699d40e Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 22 Jan 2023 12:27:13 -0800 Subject: [PATCH 03/45] Run with cargo hf2 --release --example blinky_usb_morse_out --features usb,leds --- boards/neo_trinkey/examples/blinky_usb_morse_out.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boards/neo_trinkey/examples/blinky_usb_morse_out.rs b/boards/neo_trinkey/examples/blinky_usb_morse_out.rs index 19b324bcdacf..eec49c0a0afe 100644 --- a/boards/neo_trinkey/examples/blinky_usb_morse_out.rs +++ b/boards/neo_trinkey/examples/blinky_usb_morse_out.rs @@ -21,11 +21,11 @@ use pac::{interrupt, CorePeripherals, Peripherals}; // Added use hal::delay::Delay; // use hal::pac::{CorePeripherals, Peripherals}; -// use hal::prelude::*; -// use hal::timer::TimerCounter; +use hal::prelude::*; +use hal::timer::TimerCounter; -// use smart_leds::{hsv::RGB8, SmartLedsWrite}; -// use ws2812_timer_delay::Ws2812; +use smart_leds::{hsv::RGB8, SmartLedsWrite}; +use ws2812_timer_delay::Ws2812; // End Added #[entry] From 226ed1bf2757a23d3853fc85491eeba0c840f77c Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 22 Jan 2023 12:28:12 -0800 Subject: [PATCH 04/45] Modify (inelegantly) the readme --- boards/neo_trinkey/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/neo_trinkey/README.md b/boards/neo_trinkey/README.md index a91d7965b62e..8c3a722ff939 100644 --- a/boards/neo_trinkey/README.md +++ b/boards/neo_trinkey/README.md @@ -1,3 +1,9 @@ +### How to run our first example: + +``` +cargo hf2 --release --example blinky_usb_morse_out --features usb,leds +``` + # Adafruit Neo Trinkey Board Support Crate This crate provides a type-safe API for working with the [Adafruit Neo Trinkey From 375ee5941df132762120b9266c112e24e68acd36 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 22 Jan 2023 13:36:40 -0800 Subject: [PATCH 05/45] Starting to build morse output... I am definitely struggling a bit with what's coming back from the USB calls, and I don't know yet how really to initialize the neopixel There's a bunch of commented out code that is in the direction of what I mean to do. --- .../examples/blinky_usb_morse_out.rs | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/blinky_usb_morse_out.rs b/boards/neo_trinkey/examples/blinky_usb_morse_out.rs index eec49c0a0afe..86ebc4f8113e 100644 --- a/boards/neo_trinkey/examples/blinky_usb_morse_out.rs +++ b/boards/neo_trinkey/examples/blinky_usb_morse_out.rs @@ -16,7 +16,6 @@ use bsp::pac; use hal::clock::GenericClockController; use hal::usb::UsbBus; -use pac::{interrupt, CorePeripherals, Peripherals}; // Added use hal::delay::Delay; @@ -27,6 +26,7 @@ use hal::timer::TimerCounter; use smart_leds::{hsv::RGB8, SmartLedsWrite}; use ws2812_timer_delay::Ws2812; // End Added +use pac::{interrupt, CorePeripherals, Peripherals}; #[entry] fn main() -> ! { @@ -92,6 +92,8 @@ fn poll_usb() { serial.write("Received: ".as_bytes()).ok(); serial.write(&[c.clone()]).ok(); serial.write("\r\n".as_bytes()).ok(); + emit_morse_letter('e'); + // emit_morse_letter(&[c.clone()].as_char()); } }; }); @@ -99,6 +101,82 @@ fn poll_usb() { }; } +fn emit_morse_letter(letter: char) { + match letter { + 'a' => { + emit_morse_dot(); + emit_morse_dash(); + } + 'b' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + } + 'c' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + } + 'd' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + } + 'e' => emit_morse_dot(), + // 'f' => emit_morse_dot_dot_dash_dot(), + // 'g' => emit_morse_dash_dash_dot(), + // 'h' => emit_morse_dot_dot_dot_dot(), + // 'i' => emit_morse_dot_dot(), + // 'j' => emit_morse_dot_dash_dash_dash(), + // 'k' => emit_morse_dash_dot_dash(), + // 'l' => emit_morse_dot_dash_dot_dot(), + // 'm' => emit_morse_dash_dash(), + // 'n' => emit_morse_dash_dot(), + // 'o' => emit_morse_dash_dash_dash(), + // 'p' => emit_morse_dot_dash_dash_dot(), + // 'q' => emit_morse_dash_dash_dot_dash(), + // 'r' => emit_morse_dot_dash_dot(), + // 's' => emit_morse_dot_dot_dot(), + // 't' => emit_morse_dash(), + // 'u' => emit_morse_dot_dot_dash(), + // 'v' => emit_morse_dot_dot_dot_dash(), + // 'w' => emit_morse_dot_dash_dash(), + // 'x' => emit_morse_dash_dot_dot_dash(), + // 'y' => emit_morse_dash_dot_dash_dash(), + // 'z' => emit_morse_dash_dash_dot_dot(), + _ => { + emit_morse_space(); + } + } +} + +const INTERVAL: u16 = 500u16; + +fn emit_morse_dot() { + // let neo_pixel = pins.neo_pixel.into_push_pull_output(); + // let mut ws2812 = Ws2812::new(timer, neo_pixel); + // ws2812.write(on.iter().cloned()).unwrap(); + // delay.delay_ms(INTERVAL); + // ws2812.write(off.iter().cloned()).unwrap(); + // delay.delay_ms(INTERVAL); +} +fn emit_morse_dash() { + // let neo_pixel = pins.neo_pixel.into_push_pull_output(); + // let mut ws2812 = Ws2812::new(timer, neo_pixel); + // ws2812.write(on.iter().cloned()).unwrap(); + // delay.delay_ms(3 * INTERVAL); + // ws2812.write(off.iter().cloned()).unwrap(); + // delay.delay_ms(INTERVAL); +} +fn emit_morse_space() { + // let neo_pixel = pins.neo_pixel.into_push_pull_output(); + // let mut ws2812 = Ws2812::new(timer, neo_pixel); + // ws2812.write(off.iter().cloned()).unwrap(); + // delay.delay_ms(7 * INTERVAL); +} + #[interrupt] fn USB() { // Note: USB is the name of the interrupt, you can not attach the #[interrupt] From 7adafe3bc0f6d7dd42e3dbf33fd7701e1b52a872 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 22 Jan 2023 13:40:42 -0800 Subject: [PATCH 06/45] Renamed example to usb_morse for a little less typing. --- boards/neo_trinkey/README.md | 2 +- .../examples/{blinky_usb_morse_out.rs => usb_morse.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename boards/neo_trinkey/examples/{blinky_usb_morse_out.rs => usb_morse.rs} (100%) diff --git a/boards/neo_trinkey/README.md b/boards/neo_trinkey/README.md index 8c3a722ff939..df2a64e68921 100644 --- a/boards/neo_trinkey/README.md +++ b/boards/neo_trinkey/README.md @@ -1,7 +1,7 @@ ### How to run our first example: ``` -cargo hf2 --release --example blinky_usb_morse_out --features usb,leds +cargo hf2 --release --example usb_morse --features usb,leds ``` # Adafruit Neo Trinkey Board Support Crate diff --git a/boards/neo_trinkey/examples/blinky_usb_morse_out.rs b/boards/neo_trinkey/examples/usb_morse.rs similarity index 100% rename from boards/neo_trinkey/examples/blinky_usb_morse_out.rs rename to boards/neo_trinkey/examples/usb_morse.rs From 466a02d37b01749c0024d560c2dc3b8934eb8575 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 22 Jan 2023 13:49:50 -0800 Subject: [PATCH 07/45] Finish the morse letter to dot/dash conversion switch case. --- boards/neo_trinkey/examples/usb_morse.rs | 129 +++++++++++++++++++---- 1 file changed, 108 insertions(+), 21 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 86ebc4f8113e..4430509bb059 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -125,27 +125,114 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); } 'e' => emit_morse_dot(), - // 'f' => emit_morse_dot_dot_dash_dot(), - // 'g' => emit_morse_dash_dash_dot(), - // 'h' => emit_morse_dot_dot_dot_dot(), - // 'i' => emit_morse_dot_dot(), - // 'j' => emit_morse_dot_dash_dash_dash(), - // 'k' => emit_morse_dash_dot_dash(), - // 'l' => emit_morse_dot_dash_dot_dot(), - // 'm' => emit_morse_dash_dash(), - // 'n' => emit_morse_dash_dot(), - // 'o' => emit_morse_dash_dash_dash(), - // 'p' => emit_morse_dot_dash_dash_dot(), - // 'q' => emit_morse_dash_dash_dot_dash(), - // 'r' => emit_morse_dot_dash_dot(), - // 's' => emit_morse_dot_dot_dot(), - // 't' => emit_morse_dash(), - // 'u' => emit_morse_dot_dot_dash(), - // 'v' => emit_morse_dot_dot_dot_dash(), - // 'w' => emit_morse_dot_dash_dash(), - // 'x' => emit_morse_dash_dot_dot_dash(), - // 'y' => emit_morse_dash_dot_dash_dash(), - // 'z' => emit_morse_dash_dash_dot_dot(), + 'f' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + } + 'g' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + } + 'h' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + } + 'i' => { + emit_morse_dot(); + emit_morse_dot(); + } + 'j' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + } + 'k' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + } + 'l' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + } + 'm' => { + emit_morse_dash(); + emit_morse_dash(); + } + 'n' => { + emit_morse_dash(); + emit_morse_dash(); + } + 'o' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + } + 'p' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + } + 'q' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + } + 'r' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + } + 's' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + } + 't' => emit_morse_dash(), + 'u' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + } + 'v' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + } + 'w' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + } + 'x' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + } + 'y' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + } + 'z' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + } _ => { emit_morse_space(); } From c7d6419812b251fcebef0799df5ffe5971dcc283 Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 22 Jan 2023 19:07:01 -0800 Subject: [PATCH 08/45] add blinking led to usb example --- boards/neo_trinkey/examples/usb_morse.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 4430509bb059..c13a3da3fc93 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -68,7 +68,30 @@ fn main() -> ! { NVIC::unmask(interrupt::USB); } + let gclk0 = clocks.gclk0(); + let timer_clock = clocks.tcc2_tc3(&gclk0).unwrap(); + let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.TC3, &mut peripherals.PM); + timer.start(3.mhz()); + let neo_pixel = pins.neo_pixel.into_push_pull_output(); + let mut ws2812 = Ws2812::new(timer, neo_pixel); + + let mut delay = Delay::new(core.SYST, &mut clocks); + + const NUM_LEDS: usize = 4; + let off = [RGB8::default(); NUM_LEDS]; + let on = [ + RGB8::new(5, 5, 0), + RGB8::new(0, 5, 5), + RGB8::new(5, 0, 5), + RGB8::new(2, 2, 2), + ]; + loop { + ws2812.write(off.iter().cloned()).unwrap(); + delay.delay_ms(500u16); + ws2812.write(on.iter().cloned()).unwrap(); + delay.delay_ms(500u16); + cycle_delay(15 * 1024 * 1024); } } From c293f33203e80b85a26574d03f17046f8fb368b0 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 29 Jan 2023 19:20:24 -0800 Subject: [PATCH 09/45] Made the Xiao blink with the milspec preferred blink style of 3 on, 1 off. --- boards/xiao_m0/examples/milspec_blink.rs | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 boards/xiao_m0/examples/milspec_blink.rs diff --git a/boards/xiao_m0/examples/milspec_blink.rs b/boards/xiao_m0/examples/milspec_blink.rs new file mode 100644 index 000000000000..a779a5ed5b14 --- /dev/null +++ b/boards/xiao_m0/examples/milspec_blink.rs @@ -0,0 +1,34 @@ +#![no_main] +#![no_std] + +extern crate panic_halt; + +use hal::{clock::GenericClockController, delay::Delay, prelude::*}; +use pac::{CorePeripherals, Peripherals}; + +use bsp::{entry, hal, pac, Led0}; +use xiao_m0 as bsp; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_external_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + + let mut delay = Delay::new(core.SYST, &mut clocks); + let mut led0: Led0 = pins.led0.into_push_pull_output(); + + loop { + delay.delay_ms(100u8); + led0.toggle().unwrap(); + delay.delay_ms(200u8); + delay.delay_ms(100u8); + led0.toggle().unwrap(); + } +} From 6986c209df8100334423c9259e2326d442214f93 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Tue, 31 Jan 2023 10:33:11 -0800 Subject: [PATCH 10/45] Rename board interface. WIP: trying to have the morse code generation at least emit .__. to the serial port, but reinitializing the interface doesn't make sense. Need to refactor so that the global abstraction for the hardware we've configured is more globally accessible (or easier to pass around.) --- boards/neo_trinkey/README.md | 7 +++++++ boards/neo_trinkey/examples/usb_morse.rs | 19 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/boards/neo_trinkey/README.md b/boards/neo_trinkey/README.md index df2a64e68921..95abd98cd9f4 100644 --- a/boards/neo_trinkey/README.md +++ b/boards/neo_trinkey/README.md @@ -2,6 +2,13 @@ ``` cargo hf2 --release --example usb_morse --features usb,leds +``` +Connect to the device at /dev/cu.usbmodemTRINKEY_MORSE1 +```bash +$ screen /dev/cu.usbmodemTRINKEY_MORSE1 9600 +``` + + ``` # Adafruit Neo Trinkey Board Support Crate diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index c13a3da3fc93..d824b3419bac 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -55,9 +55,9 @@ fn main() -> ! { USB_SERIAL = Some(SerialPort::new(&bus_allocator)); USB_BUS = Some( UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) - .manufacturer("Fake company") + .manufacturer("Agilistas!") .product("Serial port") - .serial_number("TRINKEY_ACK") + .serial_number("TRINKEY_MORSE") .device_class(USB_CLASS_CDC) .build(), ); @@ -124,8 +124,19 @@ fn poll_usb() { }; } +fn print_to_serial(message: &str) { + unsafe { + USB_BUS.as_mut().map(|usb_dev| { + USB_SERIAL.as_mut().map(|serial| { + serial.write(message.as_bytes()).ok(); + }); + }); + }; +} + fn emit_morse_letter(letter: char) { - match letter { + let downcased_letter = letter.to_ascii_lowercase(); // Add support for Latin 1 later. + match downcased_letter { 'a' => { emit_morse_dot(); emit_morse_dash(); @@ -265,6 +276,7 @@ fn emit_morse_letter(letter: char) { const INTERVAL: u16 = 500u16; fn emit_morse_dot() { + print_to_serial("."); // let neo_pixel = pins.neo_pixel.into_push_pull_output(); // let mut ws2812 = Ws2812::new(timer, neo_pixel); // ws2812.write(on.iter().cloned()).unwrap(); @@ -273,6 +285,7 @@ fn emit_morse_dot() { // delay.delay_ms(INTERVAL); } fn emit_morse_dash() { + print_to_serial("_"); // let neo_pixel = pins.neo_pixel.into_push_pull_output(); // let mut ws2812 = Ws2812::new(timer, neo_pixel); // ws2812.write(on.iter().cloned()).unwrap(); From 3edb47ef38d324f06544324ef766f29a4181622c Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 11:07:25 -0800 Subject: [PATCH 11/45] Add (partially implemented) example. --- boards/xiao_m0/examples/usb_morse.rs | 99 ++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 boards/xiao_m0/examples/usb_morse.rs diff --git a/boards/xiao_m0/examples/usb_morse.rs b/boards/xiao_m0/examples/usb_morse.rs new file mode 100644 index 000000000000..aab32641f4e1 --- /dev/null +++ b/boards/xiao_m0/examples/usb_morse.rs @@ -0,0 +1,99 @@ +#![no_std] +#![no_main] + +extern crate panic_halt; + +use cortex_m::{asm::delay as asm_delay, peripheral::NVIC}; +use hal::{clock::GenericClockController, prelude::*, usb::UsbBus}; +use pac::{interrupt, CorePeripherals, Peripherals}; +use usb_device::{bus::UsbBusAllocator, prelude::*}; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use bsp::{entry, hal, pac, Led0, Led1}; +use xiao_m0 as bsp; + +struct UsbSerial { + usb_bus: UsbBusAllocator, + serial: SerialPort<'static, UsbBus>, + led_data: Led1, +} + +struct Environment { + usb_serial: Option, + led0: Led0, + peripherals: Peripherals, + core: CorePeripherals, + clocks: GenericClockController, + pins: bsp::Pins, + bus_allocator: UsbBusAllocator, +} + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; +static mut LED_DATA: Option = None; + +fn init() -> Environment { + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + let usb_serial = unsafe { + USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0xdead, 0xbeef)) + .manufacturer("Agilistas!") + .product("xiao_usb_morse") + .serial_number("1") + .device_class(USB_CLASS_CDC) + .build(), + ); + LED_DATA = Some(pins.led1.into_mode()); + UsbSerial { + usb_bus: USB_ALLOCATOR.as_ref().unwrap(), + serial: USB_SERIAL.as_ref().unwrap(), + led_data: LED_DATA.as_ref().unwrap(), + } + }; + + Environment { + usb_serial: Some(usb_serial), + led0: pins.led0.into_push_pull_output(), + peripherals, + core, + clocks, + pins, + bus_allocator, + } +} + +#[entry] +fn main() -> ! { + let mut environment: Environment = init(); + let mut led0: Led0 = environment.pins.led0.into_push_pull_output(); + let mut delay = hal::delay::Delay::new(environment.core.SYST, &mut environment.clocks); + + loop { + delay.delay_ms(200u8); + led0.toggle().unwrap(); + delay.delay_ms(600u16); + led0.toggle().unwrap(); + } +} From 5981dfb010b4d22418c5c13e9bf98fd2632c69d1 Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 5 Feb 2023 11:27:42 -0800 Subject: [PATCH 12/45] Start extracing env. --- boards/neo_trinkey/examples/usb_morse-xiao.rs | 99 +++++ .../examples/usb_morse_abstracted.rs | 356 ++++++++++++++++++ 2 files changed, 455 insertions(+) create mode 100644 boards/neo_trinkey/examples/usb_morse-xiao.rs create mode 100644 boards/neo_trinkey/examples/usb_morse_abstracted.rs diff --git a/boards/neo_trinkey/examples/usb_morse-xiao.rs b/boards/neo_trinkey/examples/usb_morse-xiao.rs new file mode 100644 index 000000000000..96a8ba60adb3 --- /dev/null +++ b/boards/neo_trinkey/examples/usb_morse-xiao.rs @@ -0,0 +1,99 @@ +#![no_std] +#![no_main] + +extern crate panic_halt; + +use cortex_m::{asm::delay as asm_delay, peripheral::NVIC}; +use hal::{clock::GenericClockController, prelude::*, usb::UsbBus}; +use pac::{interrupt, CorePeripherals, Peripherals}; +use usb_device::{bus::UsbBusAllocator, prelude::*}; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use bsp::{entry, hal, pac, Led0, Led1}; +use neo_trinkey as bsp; + +struct UsbSerial { + usb_bus: UsbBusAllocator, + serial: SerialPort<'static, UsbBus>, + led_data: Led1, +} + +struct Environment { + usb_serial: Option, + led0: Led0, + peripherals: Peripherals, + core: CorePeripherals, + clocks: GenericClockController, + pins: bsp::Pins, + bus_allocator: UsbBusAllocator, +} + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; +static mut LED_DATA: Option = None; + +fn init() -> Environment { + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + let usb_serial = unsafe { + USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0xdead, 0xbeef)) + .manufacturer("Agilistas!") + .product("xiao_usb_morse") + .serial_number("1") + .device_class(USB_CLASS_CDC) + .build(), + ); + LED_DATA = Some(pins.led1.into_mode()); + UsbSerial { + usb_bus: USB_ALLOCATOR.as_ref().unwrap(), + serial: USB_SERIAL.as_ref().unwrap(), + led_data: LED_DATA.as_ref().unwrap(), + } + }; + + Environment { + usb_serial: Some(usb_serial), + led0: pins.led0.into_push_pull_output(), + peripherals, + core, + clocks, + pins, + bus_allocator, + } +} + +#[entry] +fn main() -> ! { + let mut environment: Environment = init(); + let mut led0: Led0 = environment.pins.led0.into_push_pull_output(); + let mut delay = hal::delay::Delay::new(environment.core.SYST, &mut environment.clocks); + + loop { + delay.delay_ms(200u8); + led0.toggle().unwrap(); + delay.delay_ms(600u16); + led0.toggle().unwrap(); + } +} diff --git a/boards/neo_trinkey/examples/usb_morse_abstracted.rs b/boards/neo_trinkey/examples/usb_morse_abstracted.rs new file mode 100644 index 000000000000..145c14c10623 --- /dev/null +++ b/boards/neo_trinkey/examples/usb_morse_abstracted.rs @@ -0,0 +1,356 @@ +#![no_std] +#![no_main] +use panic_halt as _; + +use cortex_m::asm::delay as cycle_delay; +use cortex_m::peripheral::NVIC; +use usb_device::bus::UsbBusAllocator; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use neo_trinkey as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use hal::clock::GenericClockController; +use hal::usb::UsbBus; + +// Added +use hal::delay::Delay; +// use hal::pac::{CorePeripherals, Peripherals}; +use hal::prelude::*; +use hal::timer::TimerCounter; + +use smart_leds::{hsv::RGB8, SmartLedsWrite}; +use ws2812_timer_delay::Ws2812; +// End Added +use pac::{interrupt, CorePeripherals, Peripherals}; + +struct Environment { + // usb_serial: Option, + // led0: Led0, + peripherals: Peripherals, + // core: CorePeripherals, + // clocks: GenericClockController, + // pins: bsp::Pins, + // bus_allocator: UsbBusAllocator, +} + +#[entry] +fn main() -> ! { + let mut env = init(); + legacy(env) +} + +fn init() -> Environment { + let mut peripherals = Peripherals::take().unwrap(); + + + // Environment { + // usb_serial: Some(usb_serial), + // led0: pins.led0.into_push_pull_output(), + // peripherals, + // core, + // clocks, + // pins, + // bus_allocator, + // } + Environment { + peripherals + } +} + +fn legacy(env: Environment) -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + unsafe { + USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Agilistas!") + .product("Serial port") + .serial_number("TRINKEY_MORSE") + .device_class(USB_CLASS_CDC) + .build(), + ); + } + + unsafe { + core.NVIC.set_priority(interrupt::USB, 1); + NVIC::unmask(interrupt::USB); + } + + let gclk0 = clocks.gclk0(); + let timer_clock = clocks.tcc2_tc3(&gclk0).unwrap(); + let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.TC3, &mut peripherals.PM); + timer.start(3.mhz()); + let neo_pixel = pins.neo_pixel.into_push_pull_output(); + let mut ws2812 = Ws2812::new(timer, neo_pixel); + + let mut delay = Delay::new(core.SYST, &mut clocks); + + const NUM_LEDS: usize = 4; + let off = [RGB8::default(); NUM_LEDS]; + let on = [ + RGB8::new(5, 5, 0), + RGB8::new(0, 5, 5), + RGB8::new(5, 0, 5), + RGB8::new(2, 2, 2), + ]; + + // runTheLoop(); + loop { + ws2812.write(off.iter().cloned()).unwrap(); + delay.delay_ms(500u16); + ws2812.write(on.iter().cloned()).unwrap(); + delay.delay_ms(500u16); + + cycle_delay(15 * 1024 * 1024); + } + +} + +fn runTheLoop(env: Environment) -> ! { + loop { + // ws2812.write(off.iter().cloned()).unwrap(); + // delay.delay_ms(500u16); + // ws2812.write(on.iter().cloned()).unwrap(); + // delay.delay_ms(500u16); + + // cycle_delay(15 * 1024 * 1024); + } +} + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; + +fn poll_usb() { + unsafe { + USB_BUS.as_mut().map(|usb_dev| { + USB_SERIAL.as_mut().map(|serial| { + usb_dev.poll(&mut [serial]); + let mut buf = [0u8; 64]; + + if let Ok(count) = serial.read(&mut buf) { + for (i, c) in buf.iter().enumerate() { + if i >= count { + break; + } + serial.write("Received: ".as_bytes()).ok(); + serial.write(&[c.clone()]).ok(); + serial.write("\r\n".as_bytes()).ok(); + emit_morse_letter('e'); + // emit_morse_letter(&[c.clone()].as_char()); + } + }; + }); + }); + }; +} + +fn print_to_serial(message: &str) { + unsafe { + USB_BUS.as_mut().map(|usb_dev| { + USB_SERIAL.as_mut().map(|serial| { + serial.write(message.as_bytes()).ok(); + }); + }); + }; +} + +fn emit_morse_letter(letter: char) { + let downcased_letter = letter.to_ascii_lowercase(); // Add support for Latin 1 later. + match downcased_letter { + 'a' => { + emit_morse_dot(); + emit_morse_dash(); + } + 'b' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + } + 'c' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + } + 'd' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + } + 'e' => emit_morse_dot(), + 'f' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + } + 'g' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + } + 'h' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + } + 'i' => { + emit_morse_dot(); + emit_morse_dot(); + } + 'j' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + } + 'k' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + } + 'l' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + } + 'm' => { + emit_morse_dash(); + emit_morse_dash(); + } + 'n' => { + emit_morse_dash(); + emit_morse_dash(); + } + 'o' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + } + 'p' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + } + 'q' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + } + 'r' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + } + 's' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + } + 't' => emit_morse_dash(), + 'u' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + } + 'v' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + } + 'w' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + } + 'x' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + } + 'y' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + } + 'z' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + } + _ => { + emit_morse_space(); + } + } +} + +const INTERVAL: u16 = 500u16; + +fn emit_morse_dot() { + print_to_serial("."); + // let neo_pixel = pins.neo_pixel.into_push_pull_output(); + // let mut ws2812 = Ws2812::new(timer, neo_pixel); + // ws2812.write(on.iter().cloned()).unwrap(); + // delay.delay_ms(INTERVAL); + // ws2812.write(off.iter().cloned()).unwrap(); + // delay.delay_ms(INTERVAL); +} +fn emit_morse_dash() { + print_to_serial("_"); + // let neo_pixel = pins.neo_pixel.into_push_pull_output(); + // let mut ws2812 = Ws2812::new(timer, neo_pixel); + // ws2812.write(on.iter().cloned()).unwrap(); + // delay.delay_ms(3 * INTERVAL); + // ws2812.write(off.iter().cloned()).unwrap(); + // delay.delay_ms(INTERVAL); +} +fn emit_morse_space() { + // let neo_pixel = pins.neo_pixel.into_push_pull_output(); + // let mut ws2812 = Ws2812::new(timer, neo_pixel); + // ws2812.write(off.iter().cloned()).unwrap(); + // delay.delay_ms(7 * INTERVAL); +} + +#[interrupt] +fn USB() { + // Note: USB is the name of the interrupt, you can not attach the #[interrupt] + // tag to poll_usb. Although you could add the contents of poll_usb into + // this function, separating them allows you to add more functions to run on + // the USB interrupt in the future. + poll_usb(); +} From 16119c471942374ae961a8ed933f0fadc785ec21 Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 5 Feb 2023 11:28:48 -0800 Subject: [PATCH 13/45] Get peripherals from environment. --- boards/neo_trinkey/examples/usb_morse_abstracted.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse_abstracted.rs b/boards/neo_trinkey/examples/usb_morse_abstracted.rs index 145c14c10623..2a886f554891 100644 --- a/boards/neo_trinkey/examples/usb_morse_abstracted.rs +++ b/boards/neo_trinkey/examples/usb_morse_abstracted.rs @@ -63,7 +63,7 @@ fn init() -> Environment { } fn legacy(env: Environment) -> ! { - let mut peripherals = Peripherals::take().unwrap(); + let mut peripherals = env.peripherals; let mut core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_internal_32kosc( peripherals.GCLK, From cb8c4c13742f8fcadbe0c832e656523e6ee244e3 Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 5 Feb 2023 11:30:25 -0800 Subject: [PATCH 14/45] Extract core. --- boards/neo_trinkey/examples/usb_morse_abstracted.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse_abstracted.rs b/boards/neo_trinkey/examples/usb_morse_abstracted.rs index 2a886f554891..519ea7da13a4 100644 --- a/boards/neo_trinkey/examples/usb_morse_abstracted.rs +++ b/boards/neo_trinkey/examples/usb_morse_abstracted.rs @@ -32,7 +32,7 @@ struct Environment { // usb_serial: Option, // led0: Led0, peripherals: Peripherals, - // core: CorePeripherals, + core: CorePeripherals, // clocks: GenericClockController, // pins: bsp::Pins, // bus_allocator: UsbBusAllocator, @@ -46,6 +46,7 @@ fn main() -> ! { fn init() -> Environment { let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); // Environment { @@ -58,7 +59,8 @@ fn init() -> Environment { // bus_allocator, // } Environment { - peripherals + peripherals, + core, } } From b3209a988681d784dba152cd3972107fd5d86aa3 Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 5 Feb 2023 11:31:13 -0800 Subject: [PATCH 15/45] Use core. --- boards/neo_trinkey/examples/usb_morse_abstracted.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse_abstracted.rs b/boards/neo_trinkey/examples/usb_morse_abstracted.rs index 519ea7da13a4..64f32a4f31d1 100644 --- a/boards/neo_trinkey/examples/usb_morse_abstracted.rs +++ b/boards/neo_trinkey/examples/usb_morse_abstracted.rs @@ -66,7 +66,7 @@ fn init() -> Environment { fn legacy(env: Environment) -> ! { let mut peripherals = env.peripherals; - let mut core = CorePeripherals::take().unwrap(); + let mut core = env.core; let mut clocks = GenericClockController::with_internal_32kosc( peripherals.GCLK, &mut peripherals.PM, From cdef9dd237b5dcb313408065c026e65adf3378ca Mon Sep 17 00:00:00 2001 From: Paul Zabelin Date: Sun, 5 Feb 2023 13:27:58 -0800 Subject: [PATCH 16/45] use morse code to display some LED color --- boards/neo_trinkey/examples/usb_morse.rs | 25 +++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index d824b3419bac..788251575a53 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -87,15 +87,32 @@ fn main() -> ! { ]; loop { + let letter = pop(); + emit_morse_letter(letter); + ws2812.write(off.iter().cloned()).unwrap(); delay.delay_ms(500u16); - ws2812.write(on.iter().cloned()).unwrap(); + + unsafe { + let colors: [RGB8; 4] = [ + RGB8::new(MORSE_QUEUE[0], 5, 0), + RGB8::new(MORSE_QUEUE[1], 5, 0), + RGB8::new(MORSE_QUEUE[2], 5, 0), + RGB8::new(MORSE_QUEUE[3], 5, 0), + ]; + ws2812.write(colors.iter().cloned()).unwrap(); + } delay.delay_ms(500u16); cycle_delay(15 * 1024 * 1024); } } +fn pop() -> char { + return 's'; +} + +static mut MORSE_QUEUE: [u8; 4] = [1, 2, 3, 4]; static mut USB_ALLOCATOR: Option> = None; static mut USB_BUS: Option> = None; static mut USB_SERIAL: Option> = None; @@ -283,9 +300,15 @@ fn emit_morse_dot() { // delay.delay_ms(INTERVAL); // ws2812.write(off.iter().cloned()).unwrap(); // delay.delay_ms(INTERVAL); + unsafe { + MORSE_QUEUE = [2, 3, 4, 1]; + } } fn emit_morse_dash() { print_to_serial("_"); + unsafe { + MORSE_QUEUE = [8, 7, 6, 5]; + } // let neo_pixel = pins.neo_pixel.into_push_pull_output(); // let mut ws2812 = Ws2812::new(timer, neo_pixel); // ws2812.write(on.iter().cloned()).unwrap(); From 82c1043f330ababc728118528b5300be2ae4d18a Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 13:28:25 -0800 Subject: [PATCH 17/45] Put our command line in the readme. --- boards/xiao_m0/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/xiao_m0/README.md b/boards/xiao_m0/README.md index 8df3577410a4..5fc79bf84fff 100644 --- a/boards/xiao_m0/README.md +++ b/boards/xiao_m0/README.md @@ -3,6 +3,10 @@ This crate provides a type-safe API for working with the [Seeed Studio Seeeduino XIAO](http://wiki.seeedstudio.com/Seeeduino-XIAO/). +## FORK NOTES: + +cargo hf2 --release --example usb_morse --features="unproven" + ## Prerequisites * Install the cross compile toolchain `rustup target add thumbv6m-none-eabi` From a64cd926f1720050155e250eb57b0bef3a1931e8 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 13:51:53 -0800 Subject: [PATCH 18/45] Add a character queue. --- boards/neo_trinkey/examples/usb_morse.rs | 43 +++++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 788251575a53..bc828c1e89a7 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -28,6 +28,39 @@ use ws2812_timer_delay::Ws2812; // End Added use pac::{interrupt, CorePeripherals, Peripherals}; +struct CharQueue { + queue: [char; 32], +} + +static mut CHAR_QUEUE: Option = None; + +fn push(c: char) { + unsafe { + let queue = CHAR_QUEUE.as_mut().unwrap(); + for i in 0..queue.queue.len() { + if queue.queue[i] == '\0' { + queue.queue[i] = c; + return; + } + } + } +} + +fn pop() -> Option { + unsafe { + let queue = CHAR_QUEUE.as_mut().unwrap(); + let c = queue.queue[0]; + if c == '\0' { + return None; + } + for i in 0..queue.queue.len() - 1 { + queue.queue[i] = queue.queue[i + 1]; + } + queue.queue[queue.queue.len() - 1] = '\0'; + Some(c) + } +} + #[entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); @@ -87,8 +120,8 @@ fn main() -> ! { ]; loop { - let letter = pop(); - emit_morse_letter(letter); + // let letter = pop(); + // emit_morse_letter(letter); ws2812.write(off.iter().cloned()).unwrap(); delay.delay_ms(500u16); @@ -108,9 +141,9 @@ fn main() -> ! { } } -fn pop() -> char { - return 's'; -} +// fn pop() -> char { +// return 's'; +// } static mut MORSE_QUEUE: [u8; 4] = [1, 2, 3, 4]; static mut USB_ALLOCATOR: Option> = None; From 5c8449108967d46ff8ecf854fdb796b777548263 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 17:19:03 -0800 Subject: [PATCH 19/45] There's a thing to poll to see what state to set the LEDs to for this iteration. --- boards/neo_trinkey/examples/usb_morse.rs | 163 ++++++++++++++++++----- 1 file changed, 132 insertions(+), 31 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index bc828c1e89a7..0c619ea4762d 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -32,21 +32,115 @@ struct CharQueue { queue: [char; 32], } -static mut CHAR_QUEUE: Option = None; +struct PinControlQueue { + queue: [Option; 32], + length: u8, +} + +struct PinControlDescriptor { + pinState: bool, + duration: u8, +} + +fn pushDot() { + let dot = PinControlDescriptor { + pinState: true, + duration: 1, + }; + let interval = PinControlDescriptor { + pinState: false, + duration: 1, + }; + pushState(dot); + pushState(interval); +} -fn push(c: char) { +fn pushDash() { + let dash = PinControlDescriptor { + pinState: true, + duration: 3, + }; + let interval = PinControlDescriptor { + pinState: false, + duration: 1, + }; + pushState(dash); + pushState(interval); +} + +fn pushSpace() { + let space = PinControlDescriptor { + pinState: false, + duration: 7, + }; + pushState(space); +} + +static mut countDown: u8 = 0; + +static mut haxTempState: bool = false; +fn getNextState() -> bool { unsafe { - let queue = CHAR_QUEUE.as_mut().unwrap(); - for i in 0..queue.queue.len() { - if queue.queue[i] == '\0' { - queue.queue[i] = c; - return; - } + haxTempState = !haxTempState; + // return haxTempState; + if (countDown == 0) { + countDown = 3; + return false; + } else { + countDown -= 1; + return true; } } } -fn pop() -> Option { +static mut CHAR_QUEUE: Option = None; +static mut PIN_QUEUE: Option = None; +// { +// queue: [None; 32], +// length: 0, +// }; +// static mut PIN_QUEUE: PinControlQueue = PinControlQueue { +// queue: [Option PinControlDescriptor { + return PinControlDescriptor { + pinState: true, + duration: 1, + }; +} + +// fn push(c: char) { +// unsafe { +// let queue = CHAR_QUEUE.as_mut().unwrap(); +// for i in 0..queue.queue.len() { +// if queue.queue[i] == '\0' { +// queue.queue[i] = c; +// return; +// } +// } +// } +// } + +fn pop() -> char { + return 's'; +} +fn real_pop() -> Option { unsafe { let queue = CHAR_QUEUE.as_mut().unwrap(); let c = queue.queue[0]; @@ -122,29 +216,33 @@ fn main() -> ! { loop { // let letter = pop(); // emit_morse_letter(letter); + let mut state = getNextState(); + if state { + // turn on + ws2812.write(on.iter().cloned()).unwrap(); + } else { + // turn off + ws2812.write(off.iter().cloned()).unwrap(); + } - ws2812.write(off.iter().cloned()).unwrap(); + // ws2812.write(off.iter().cloned()).unwrap(); delay.delay_ms(500u16); - unsafe { - let colors: [RGB8; 4] = [ - RGB8::new(MORSE_QUEUE[0], 5, 0), - RGB8::new(MORSE_QUEUE[1], 5, 0), - RGB8::new(MORSE_QUEUE[2], 5, 0), - RGB8::new(MORSE_QUEUE[3], 5, 0), - ]; - ws2812.write(colors.iter().cloned()).unwrap(); - } - delay.delay_ms(500u16); + // unsafe { + // let colors: [RGB8; 4] = [ + // RGB8::new(MORSE_QUEUE[0], 5, 0), + // RGB8::new(MORSE_QUEUE[1], 5, 0), + // RGB8::new(MORSE_QUEUE[2], 5, 0), + // RGB8::new(MORSE_QUEUE[3], 5, 0), + // ]; + // ws2812.write(colors.iter().cloned()).unwrap(); + // } + // delay.delay_ms(500u16); cycle_delay(15 * 1024 * 1024); } } -// fn pop() -> char { -// return 's'; -// } - static mut MORSE_QUEUE: [u8; 4] = [1, 2, 3, 4]; static mut USB_ALLOCATOR: Option> = None; static mut USB_BUS: Option> = None; @@ -326,6 +424,7 @@ fn emit_morse_letter(letter: char) { const INTERVAL: u16 = 500u16; fn emit_morse_dot() { + pushDot(); print_to_serial("."); // let neo_pixel = pins.neo_pixel.into_push_pull_output(); // let mut ws2812 = Ws2812::new(timer, neo_pixel); @@ -333,15 +432,16 @@ fn emit_morse_dot() { // delay.delay_ms(INTERVAL); // ws2812.write(off.iter().cloned()).unwrap(); // delay.delay_ms(INTERVAL); - unsafe { - MORSE_QUEUE = [2, 3, 4, 1]; - } + // unsafe { + // MORSE_QUEUE = [2, 3, 4, 1]; + // } } fn emit_morse_dash() { - print_to_serial("_"); - unsafe { - MORSE_QUEUE = [8, 7, 6, 5]; - } + pushDash(); + // print_to_serial("_"); + // unsafe { + // MORSE_QUEUE = [8, 7, 6, 5]; + // } // let neo_pixel = pins.neo_pixel.into_push_pull_output(); // let mut ws2812 = Ws2812::new(timer, neo_pixel); // ws2812.write(on.iter().cloned()).unwrap(); @@ -350,6 +450,7 @@ fn emit_morse_dash() { // delay.delay_ms(INTERVAL); } fn emit_morse_space() { + pushSpace(); // let neo_pixel = pins.neo_pixel.into_push_pull_output(); // let mut ws2812 = Ws2812::new(timer, neo_pixel); // ws2812.write(off.iter().cloned()).unwrap(); From 98bb0444f42fb59f4166a9dc80775974a5d5a0c1 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 17:23:37 -0800 Subject: [PATCH 20/45] Add FixedSliceVec to project to support embedded Vec (for queues) --- boards/neo_trinkey/Cargo.toml | 1 + boards/neo_trinkey/examples/usb_morse.rs | 3 +++ 2 files changed, 4 insertions(+) diff --git a/boards/neo_trinkey/Cargo.toml b/boards/neo_trinkey/Cargo.toml index be08832124b9..fbf454b22cf2 100644 --- a/boards/neo_trinkey/Cargo.toml +++ b/boards/neo_trinkey/Cargo.toml @@ -16,6 +16,7 @@ usb-device = { version = "0.2", optional = true } smart-leds = { version = "0.3.0", optional = true } ws2812-timer-delay = { version = "0.3.0", features = ["slow"], optional = true } cargo-hf2 = "0.3.3" +fixed-slice-vec = "0.10.0" [dependencies.atsamd-hal] version = "0.14" diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 0c619ea4762d..ec922c684ce4 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -2,6 +2,9 @@ #![no_main] use panic_halt as _; +use core::mem::MaybeUninit; +use fixed_slice_vec::FixedSliceVec; + use cortex_m::asm::delay as cycle_delay; use cortex_m::peripheral::NVIC; use usb_device::bus::UsbBusAllocator; From a9dfe17f78d826b84d6fd8d050a13697fd295563 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:02:28 -0800 Subject: [PATCH 21/45] I can dequeue a pin control state. (But I don't in the right place yet.) --- boards/neo_trinkey/examples/usb_morse.rs | 173 +++++++++++++++++++++-- 1 file changed, 165 insertions(+), 8 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index ec922c684ce4..89340dd7809f 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -1,5 +1,6 @@ #![no_std] #![no_main] +use bsp::pac::dsu::length; use panic_halt as _; use core::mem::MaybeUninit; @@ -36,10 +37,144 @@ struct CharQueue { } struct PinControlQueue { - queue: [Option; 32], - length: u8, + queue: [PinControlDescriptor; 32], + length: usize, } +static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { + queue: [ + PinControlDescriptor { + pinState: true, + duration: 3, + }, + PinControlDescriptor { + pinState: false, + duration: 1, + }, + PinControlDescriptor { + pinState: true, + duration: 3, + }, + PinControlDescriptor { + pinState: false, + duration: 1, + }, + PinControlDescriptor { + pinState: true, + duration: 3, + }, + PinControlDescriptor { + pinState: false, + duration: 3, + }, + PinControlDescriptor { + pinState: true, + duration: 1, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: true, + duration: 1, + }, + PinControlDescriptor { + pinState: false, + duration: 3, + }, + PinControlDescriptor { + pinState: true, + duration: 3, + }, + PinControlDescriptor { + pinState: false, + duration: 1, + }, + PinControlDescriptor { + pinState: true, + duration: 3, + }, + PinControlDescriptor { + pinState: false, + duration: 1, + }, + PinControlDescriptor { + pinState: true, + duration: 1, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + PinControlDescriptor { + pinState: false, + duration: 0, + }, + ], + length: 14, +}; + struct PinControlDescriptor { pinState: bool, duration: u8, @@ -79,6 +214,14 @@ fn pushSpace() { pushState(space); } +fn pushLetterInterval() { + let space = PinControlDescriptor { + pinState: false, + duration: 3, + }; + pushState(space); +} + static mut countDown: u8 = 0; static mut haxTempState: bool = false; @@ -107,7 +250,13 @@ static mut PIN_QUEUE: Option = None; // length: 0, // }; -fn pushState(state: PinControlDescriptor) {} +fn pushState(state: PinControlDescriptor) { + // unsafe { + // let queue: PinControlQueue = PIN_CONTROL_QUEUE.as_mut().unwrap(); + // queue.queue[usize * queue.length] = state; + // queue.length += 1; + // } +} // fn pushState(state: PinControlDescriptor) { // unsafe { @@ -122,10 +271,18 @@ fn pushState(state: PinControlDescriptor) {} // } fn popState() -> PinControlDescriptor { - return PinControlDescriptor { - pinState: true, - duration: 1, - }; + unsafe { + let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.length]; + PIN_CONTROL_QUEUE.length -= 1; + return PinControlDescriptor { + pinState: returnValue.pinState, + duration: returnValue.duration, + }; + } + // return PinControlDescriptor { + // pinState: true, + // duration: 1, + // }; } // fn push(c: char) { @@ -219,7 +376,7 @@ fn main() -> ! { loop { // let letter = pop(); // emit_morse_letter(letter); - let mut state = getNextState(); + let state = getNextState(); if state { // turn on ws2812.write(on.iter().cloned()).unwrap(); From 4a7cf1ad93e0a1461e4ccfe338e0172436cde355 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:03:47 -0800 Subject: [PATCH 22/45] Remove commented code. --- boards/neo_trinkey/examples/usb_morse.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 89340dd7809f..ef825b62c8bc 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -279,10 +279,6 @@ fn popState() -> PinControlDescriptor { duration: returnValue.duration, }; } - // return PinControlDescriptor { - // pinState: true, - // duration: 1, - // }; } // fn push(c: char) { From bd63fc88884ff5f27a21e38cf02895985bb443a0 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:05:17 -0800 Subject: [PATCH 23/45] Speed up loop. --- boards/neo_trinkey/examples/usb_morse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index ef825b62c8bc..966d945c3787 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -395,7 +395,7 @@ fn main() -> ! { // } // delay.delay_ms(500u16); - cycle_delay(15 * 1024 * 1024); + // cycle_delay(15 * 1024 * 1024); } } From 5d6de9ec93e33a5fec473826e1dc2f2f73b93457 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:06:39 -0800 Subject: [PATCH 24/45] When the pin state queue is empty, return an low voltage request with a duration of 1. --- boards/neo_trinkey/examples/usb_morse.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 966d945c3787..a897eabb2c34 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -272,6 +272,12 @@ fn pushState(state: PinControlDescriptor) { fn popState() -> PinControlDescriptor { unsafe { + if (PIN_CONTROL_QUEUE.length == 0) { + return PinControlDescriptor { + pinState: false, + duration: 1, + }; + } let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.length]; PIN_CONTROL_QUEUE.length -= 1; return PinControlDescriptor { From bd786981c43ac7924756b5a9d1e63b251ab8280a Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:13:49 -0800 Subject: [PATCH 25/45] We drain the queue of pin states. We don't refill it yet, but we do handle an empty queue. Next, make the queue into a circular buffer, and push stuff into it. It would sure be nice to have some tests. --- boards/neo_trinkey/examples/usb_morse.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index a897eabb2c34..ae0ef0836981 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -223,19 +223,18 @@ fn pushLetterInterval() { } static mut countDown: u8 = 0; +static mut currentPinState: bool = false; -static mut haxTempState: bool = false; fn getNextState() -> bool { + let mut pinState: bool; unsafe { - haxTempState = !haxTempState; - // return haxTempState; - if (countDown == 0) { - countDown = 3; - return false; - } else { - countDown -= 1; - return true; + if countDown == 0 { + let pinStateDescriptor = popState(); + countDown = pinStateDescriptor.duration; + currentPinState = pinStateDescriptor.pinState; } + countDown -= 1; + return currentPinState; } } From 14add25e45c24fa15aac950522e5fdedd5676566 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:19:03 -0800 Subject: [PATCH 26/45] Adjust fake data. --- boards/neo_trinkey/examples/usb_morse.rs | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index ae0ef0836981..5dae11c1a6b3 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -73,7 +73,7 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { }, PinControlDescriptor { pinState: false, - duration: 0, + duration: 1, }, PinControlDescriptor { pinState: true, @@ -105,39 +105,39 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { }, PinControlDescriptor { pinState: false, - duration: 0, + duration: 3, }, PinControlDescriptor { - pinState: false, - duration: 0, + pinState: true, + duration: 3, }, PinControlDescriptor { pinState: false, - duration: 0, + duration: 1, }, PinControlDescriptor { - pinState: false, - duration: 0, + pinState: true, + duration: 3, }, PinControlDescriptor { pinState: false, - duration: 0, + duration: 1, }, PinControlDescriptor { - pinState: false, - duration: 0, + pinState: true, + duration: 3, }, PinControlDescriptor { pinState: false, - duration: 0, + duration: 1, }, PinControlDescriptor { pinState: false, - duration: 0, + duration: 1, }, PinControlDescriptor { pinState: false, - duration: 0, + duration: 1, }, PinControlDescriptor { pinState: false, @@ -172,7 +172,7 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { duration: 0, }, ], - length: 14, + length: 21, }; struct PinControlDescriptor { From 11ed14346a0b3be7af3908df34cd4f3000bb3ce8 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:20:46 -0800 Subject: [PATCH 27/45] Fix case where counter decrements below zero (because of a zero interval.) --- boards/neo_trinkey/examples/usb_morse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 5dae11c1a6b3..c24bb0e0f20c 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -228,7 +228,7 @@ static mut currentPinState: bool = false; fn getNextState() -> bool { let mut pinState: bool; unsafe { - if countDown == 0 { + if countDown <= 0 { let pinStateDescriptor = popState(); countDown = pinStateDescriptor.duration; currentPinState = pinStateDescriptor.pinState; From 8d30654f2e86dd5be89e6207dc17669ecfa387ed Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:25:17 -0800 Subject: [PATCH 28/45] Correct fake data to send S-M-S. --- boards/neo_trinkey/examples/usb_morse.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index c24bb0e0f20c..da4f670c4112 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -39,37 +39,38 @@ struct CharQueue { struct PinControlQueue { queue: [PinControlDescriptor; 32], length: usize, + position: usize, } static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { queue: [ PinControlDescriptor { pinState: true, - duration: 3, + duration: 10, }, PinControlDescriptor { pinState: false, duration: 1, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 1, }, PinControlDescriptor { pinState: false, duration: 1, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 1, }, PinControlDescriptor { pinState: false, - duration: 3, + duration: 1, }, PinControlDescriptor { pinState: true, - duration: 1, + duration: 3, }, PinControlDescriptor { pinState: false, @@ -77,11 +78,11 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { }, PinControlDescriptor { pinState: true, - duration: 1, + duration: 3, }, PinControlDescriptor { pinState: false, - duration: 3, + duration: 1, }, PinControlDescriptor { pinState: true, @@ -89,11 +90,11 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 3, }, PinControlDescriptor { pinState: true, - duration: 3, + duration: 1, }, PinControlDescriptor { pinState: false, @@ -173,6 +174,7 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { }, ], length: 21, + position: 0, }; struct PinControlDescriptor { From c42e7723fe1dc77ddb7af33e01bfb5c245cc7479 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:27:10 -0800 Subject: [PATCH 29/45] Fix off by one error in next state queue drain. (It would never drain the last state.) Board now blinks S-N-S, followed after an interval with a 10 unit long ON pulse. --- boards/neo_trinkey/examples/usb_morse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index da4f670c4112..0965a56b3145 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -279,8 +279,8 @@ fn popState() -> PinControlDescriptor { duration: 1, }; } - let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.length]; PIN_CONTROL_QUEUE.length -= 1; + let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.length]; return PinControlDescriptor { pinState: returnValue.pinState, duration: returnValue.duration, From 21db3f9af47c2068a54d337cbfe4b1eeca9cb312 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:48:44 -0800 Subject: [PATCH 30/45] Make the queue into a circular queue to push into... (But the pop doesn't honor this yet.) --- boards/neo_trinkey/examples/usb_morse.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 0965a56b3145..ef5de3705045 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -251,14 +251,6 @@ static mut PIN_QUEUE: Option = None; // length: 0, // }; -fn pushState(state: PinControlDescriptor) { - // unsafe { - // let queue: PinControlQueue = PIN_CONTROL_QUEUE.as_mut().unwrap(); - // queue.queue[usize * queue.length] = state; - // queue.length += 1; - // } -} - // fn pushState(state: PinControlDescriptor) { // unsafe { // let queue: PinControlQueue = PIN_QUEUE.as_mut().unwrap(); @@ -271,6 +263,22 @@ fn pushState(state: PinControlDescriptor) { // } // } +const QUEUE_LENGTH: usize = 32; +fn pushState(state: PinControlDescriptor) { + unsafe { + let index = PIN_CONTROL_QUEUE.position as usize; + let length: usize = PIN_CONTROL_QUEUE.length as usize; + let queue = &mut PIN_CONTROL_QUEUE; + queue.queue[index] = state; + if index == QUEUE_LENGTH { + queue.position = 0; + } else { + queue.position = index + 1; + } + queue.length += 1; + } +} + fn popState() -> PinControlDescriptor { unsafe { if (PIN_CONTROL_QUEUE.length == 0) { From c699856ffa7a7b5f92af2be1a40b8913e5271adb Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 18:54:07 -0800 Subject: [PATCH 31/45] Convert popState() to treat PIN_CONTROL_QUEUE as a circular queue. --- boards/neo_trinkey/examples/usb_morse.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index ef5de3705045..828a2ea62287 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -174,7 +174,7 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { }, ], length: 21, - position: 0, + position: 21, }; struct PinControlDescriptor { @@ -270,11 +270,7 @@ fn pushState(state: PinControlDescriptor) { let length: usize = PIN_CONTROL_QUEUE.length as usize; let queue = &mut PIN_CONTROL_QUEUE; queue.queue[index] = state; - if index == QUEUE_LENGTH { - queue.position = 0; - } else { - queue.position = index + 1; - } + PIN_CONTROL_QUEUE.position = (PIN_CONTROL_QUEUE.position + 1) % QUEUE_LENGTH; queue.length += 1; } } @@ -287,8 +283,9 @@ fn popState() -> PinControlDescriptor { duration: 1, }; } + let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.position]; PIN_CONTROL_QUEUE.length -= 1; - let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.length]; + PIN_CONTROL_QUEUE.position = (PIN_CONTROL_QUEUE.position - 1) % QUEUE_LENGTH; return PinControlDescriptor { pinState: returnValue.pinState, duration: returnValue.duration, From 3c6369c6bdeac78e93799f3a7c5dd2b0423440c4 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 19:08:34 -0800 Subject: [PATCH 32/45] Make the read and writ heads on the pin control queue move independently. Note that the queue doesn't (currently) worry about overflow. It CAN and WILL overflow if it's filled faster than it drains. That said, all that results is some states not being rendered to the pins. --- boards/neo_trinkey/examples/usb_morse.rs | 97 ++++++++++++++---------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 828a2ea62287..5f89e0534fa5 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -39,106 +39,107 @@ struct CharQueue { struct PinControlQueue { queue: [PinControlDescriptor; 32], length: usize, - position: usize, + writePosition: usize, + readPosition: usize, } static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { queue: [ PinControlDescriptor { - pinState: true, - duration: 10, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 3, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 1, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 1, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 3, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { - pinState: true, - duration: 3, + pinState: false, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { pinState: false, - duration: 1, + duration: 0, }, PinControlDescriptor { pinState: false, @@ -173,8 +174,9 @@ static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { duration: 0, }, ], - length: 21, - position: 21, + length: 0, + writePosition: 0, + readPosition: 0, }; struct PinControlDescriptor { @@ -266,11 +268,11 @@ static mut PIN_QUEUE: Option = None; const QUEUE_LENGTH: usize = 32; fn pushState(state: PinControlDescriptor) { unsafe { - let index = PIN_CONTROL_QUEUE.position as usize; + let index = PIN_CONTROL_QUEUE.writePosition as usize; let length: usize = PIN_CONTROL_QUEUE.length as usize; let queue = &mut PIN_CONTROL_QUEUE; queue.queue[index] = state; - PIN_CONTROL_QUEUE.position = (PIN_CONTROL_QUEUE.position + 1) % QUEUE_LENGTH; + PIN_CONTROL_QUEUE.writePosition = (PIN_CONTROL_QUEUE.writePosition + 1) % QUEUE_LENGTH; queue.length += 1; } } @@ -283,9 +285,9 @@ fn popState() -> PinControlDescriptor { duration: 1, }; } - let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.position]; + let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.readPosition]; PIN_CONTROL_QUEUE.length -= 1; - PIN_CONTROL_QUEUE.position = (PIN_CONTROL_QUEUE.position - 1) % QUEUE_LENGTH; + PIN_CONTROL_QUEUE.readPosition = (PIN_CONTROL_QUEUE.readPosition + 1) % QUEUE_LENGTH; return PinControlDescriptor { pinState: returnValue.pinState, duration: returnValue.duration, @@ -381,6 +383,19 @@ fn main() -> ! { RGB8::new(2, 2, 2), ]; + pushDash(); + pushDash(); + pushDash(); + pushLetterInterval(); + pushDot(); + pushDot(); + pushDot(); + pushLetterInterval(); + pushDash(); + pushDash(); + pushDash(); + pushLetterInterval(); + loop { // let letter = pop(); // emit_morse_letter(letter); @@ -394,7 +409,7 @@ fn main() -> ! { } // ws2812.write(off.iter().cloned()).unwrap(); - delay.delay_ms(500u16); + delay.delay_ms(100u16); // unsafe { // let colors: [RGB8; 4] = [ From 6a0d04d18afdade7238fc4903a30f278d9ad0d21 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 22:22:31 -0800 Subject: [PATCH 33/45] Working morse emitter. It still would benefit from a letter queue, but this works as long as you don't type too fast. Needs some cleanup though. --- boards/neo_trinkey/examples/usb_morse.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 5f89e0534fa5..22b278a45abb 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -446,8 +446,10 @@ fn poll_usb() { serial.write("Received: ".as_bytes()).ok(); serial.write(&[c.clone()]).ok(); serial.write("\r\n".as_bytes()).ok(); - emit_morse_letter('e'); - // emit_morse_letter(&[c.clone()].as_char()); + // emit_morse_letter('e'); + + let letter = char::from_u32([c.clone()][0] as u32).unwrap(); + emit_morse_letter(letter); } }; }); From 2a229ed5a9b1228fee7b1f7c8821b0bbf7bd5817 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 5 Feb 2023 22:35:59 -0800 Subject: [PATCH 34/45] Clean up some cruft. Conform to more rust standard naming. I left the stubs of the character queue in place, so I can finish that out, but this is way shorter now. I wish I had a way to generate the initial queue state, but iterators are part of std, which we don't have access to. --- boards/neo_trinkey/examples/usb_morse.rs | 287 +++++++++-------------- 1 file changed, 111 insertions(+), 176 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 22b278a45abb..1d816841ffb8 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -39,274 +39,240 @@ struct CharQueue { struct PinControlQueue { queue: [PinControlDescriptor; 32], length: usize, - writePosition: usize, - readPosition: usize, + write_position: usize, + read_position: usize, } static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { queue: [ PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, PinControlDescriptor { - pinState: false, + pin_state: false, duration: 0, }, ], length: 0, - writePosition: 0, - readPosition: 0, + write_position: 0, + read_position: 0, }; struct PinControlDescriptor { - pinState: bool, + pin_state: bool, duration: u8, } -fn pushDot() { +fn push_dot() { let dot = PinControlDescriptor { - pinState: true, + pin_state: true, duration: 1, }; let interval = PinControlDescriptor { - pinState: false, + pin_state: false, duration: 1, }; - pushState(dot); - pushState(interval); + push_state(dot); + push_state(interval); } -fn pushDash() { +fn push_dash() { let dash = PinControlDescriptor { - pinState: true, + pin_state: true, duration: 3, }; let interval = PinControlDescriptor { - pinState: false, + pin_state: false, duration: 1, }; - pushState(dash); - pushState(interval); + push_state(dash); + push_state(interval); } -fn pushSpace() { +fn push_space() { let space = PinControlDescriptor { - pinState: false, + pin_state: false, duration: 7, }; - pushState(space); + push_state(space); } -fn pushLetterInterval() { +fn push_letter_interval() { let space = PinControlDescriptor { - pinState: false, + pin_state: false, duration: 3, }; - pushState(space); + push_state(space); } -static mut countDown: u8 = 0; -static mut currentPinState: bool = false; +static mut COUNT_DOWN: u8 = 0; +static mut CURRENT_PIN_STATE: bool = false; -fn getNextState() -> bool { - let mut pinState: bool; +fn get_next_state() -> bool { + let mut pin_state: bool; unsafe { - if countDown <= 0 { - let pinStateDescriptor = popState(); - countDown = pinStateDescriptor.duration; - currentPinState = pinStateDescriptor.pinState; + if COUNT_DOWN <= 0 { + let pin_state_descriptor = pop_state(); + COUNT_DOWN = pin_state_descriptor.duration; + CURRENT_PIN_STATE = pin_state_descriptor.pin_state; } - countDown -= 1; - return currentPinState; + COUNT_DOWN -= 1; + return CURRENT_PIN_STATE; } } static mut CHAR_QUEUE: Option = None; -static mut PIN_QUEUE: Option = None; -// { -// queue: [None; 32], -// length: 0, -// }; -// static mut PIN_QUEUE: PinControlQueue = PinControlQueue { -// queue: [Option PinControlDescriptor { +fn pop_state() -> PinControlDescriptor { unsafe { - if (PIN_CONTROL_QUEUE.length == 0) { + if PIN_CONTROL_QUEUE.length == 0 { return PinControlDescriptor { - pinState: false, + pin_state: false, duration: 1, }; } - let returnValue = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.readPosition]; + let return_value = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.read_position]; PIN_CONTROL_QUEUE.length -= 1; - PIN_CONTROL_QUEUE.readPosition = (PIN_CONTROL_QUEUE.readPosition + 1) % QUEUE_LENGTH; + PIN_CONTROL_QUEUE.read_position = (PIN_CONTROL_QUEUE.read_position + 1) % QUEUE_LENGTH; return PinControlDescriptor { - pinState: returnValue.pinState, - duration: returnValue.duration, + pin_state: return_value.pin_state, + duration: return_value.duration, }; } } -// fn push(c: char) { -// unsafe { -// let queue = CHAR_QUEUE.as_mut().unwrap(); -// for i in 0..queue.queue.len() { -// if queue.queue[i] == '\0' { -// queue.queue[i] = c; -// return; -// } -// } -// } -// } - fn pop() -> char { return 's'; } @@ -383,23 +349,10 @@ fn main() -> ! { RGB8::new(2, 2, 2), ]; - pushDash(); - pushDash(); - pushDash(); - pushLetterInterval(); - pushDot(); - pushDot(); - pushDot(); - pushLetterInterval(); - pushDash(); - pushDash(); - pushDash(); - pushLetterInterval(); - loop { // let letter = pop(); // emit_morse_letter(letter); - let state = getNextState(); + let state = get_next_state(); if state { // turn on ws2812.write(on.iter().cloned()).unwrap(); @@ -409,24 +362,10 @@ fn main() -> ! { } // ws2812.write(off.iter().cloned()).unwrap(); - delay.delay_ms(100u16); - - // unsafe { - // let colors: [RGB8; 4] = [ - // RGB8::new(MORSE_QUEUE[0], 5, 0), - // RGB8::new(MORSE_QUEUE[1], 5, 0), - // RGB8::new(MORSE_QUEUE[2], 5, 0), - // RGB8::new(MORSE_QUEUE[3], 5, 0), - // ]; - // ws2812.write(colors.iter().cloned()).unwrap(); - // } - // delay.delay_ms(500u16); - - // cycle_delay(15 * 1024 * 1024); + delay.delay_ms(INTERVAL); } } -static mut MORSE_QUEUE: [u8; 4] = [1, 2, 3, 4]; static mut USB_ALLOCATOR: Option> = None; static mut USB_BUS: Option> = None; static mut USB_SERIAL: Option> = None; @@ -457,148 +396,168 @@ fn poll_usb() { }; } -fn print_to_serial(message: &str) { - unsafe { - USB_BUS.as_mut().map(|usb_dev| { - USB_SERIAL.as_mut().map(|serial| { - serial.write(message.as_bytes()).ok(); - }); - }); - }; -} - fn emit_morse_letter(letter: char) { let downcased_letter = letter.to_ascii_lowercase(); // Add support for Latin 1 later. match downcased_letter { 'a' => { emit_morse_dot(); emit_morse_dash(); + push_letter_interval(); } 'b' => { emit_morse_dash(); emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); + push_letter_interval(); } 'c' => { emit_morse_dash(); emit_morse_dot(); emit_morse_dash(); emit_morse_dot(); + push_letter_interval(); } 'd' => { emit_morse_dash(); emit_morse_dot(); emit_morse_dot(); + push_letter_interval(); + } + 'e' => { + emit_morse_dot(); + push_letter_interval(); } - 'e' => emit_morse_dot(), 'f' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dash(); emit_morse_dot(); + push_letter_interval(); } 'g' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dot(); + push_letter_interval(); } 'h' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); + push_letter_interval(); } 'i' => { emit_morse_dot(); emit_morse_dot(); + push_letter_interval(); } 'j' => { emit_morse_dot(); emit_morse_dash(); emit_morse_dash(); emit_morse_dash(); + push_letter_interval(); } 'k' => { emit_morse_dash(); emit_morse_dot(); emit_morse_dash(); + push_letter_interval(); } 'l' => { emit_morse_dot(); emit_morse_dash(); emit_morse_dot(); emit_morse_dot(); + push_letter_interval(); } 'm' => { emit_morse_dash(); emit_morse_dash(); + push_letter_interval(); } 'n' => { emit_morse_dash(); emit_morse_dash(); + push_letter_interval(); } 'o' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dash(); + push_letter_interval(); } 'p' => { emit_morse_dot(); emit_morse_dash(); emit_morse_dash(); emit_morse_dot(); + push_letter_interval(); } 'q' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dot(); emit_morse_dash(); + push_letter_interval(); } 'r' => { emit_morse_dot(); emit_morse_dash(); emit_morse_dot(); + push_letter_interval(); } 's' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); + push_letter_interval(); + } + 't' => { + emit_morse_dash(); + push_letter_interval(); } - 't' => emit_morse_dash(), 'u' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dash(); + push_letter_interval(); } 'v' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); emit_morse_dash(); + push_letter_interval(); } 'w' => { emit_morse_dot(); emit_morse_dash(); emit_morse_dash(); + push_letter_interval(); } 'x' => { emit_morse_dash(); emit_morse_dot(); emit_morse_dot(); emit_morse_dash(); + push_letter_interval(); } 'y' => { emit_morse_dash(); emit_morse_dot(); emit_morse_dash(); emit_morse_dash(); + push_letter_interval(); } 'z' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dot(); emit_morse_dot(); + push_letter_interval(); } _ => { emit_morse_space(); @@ -606,40 +565,16 @@ fn emit_morse_letter(letter: char) { } } -const INTERVAL: u16 = 500u16; +const INTERVAL: u16 = 100u16; fn emit_morse_dot() { - pushDot(); - print_to_serial("."); - // let neo_pixel = pins.neo_pixel.into_push_pull_output(); - // let mut ws2812 = Ws2812::new(timer, neo_pixel); - // ws2812.write(on.iter().cloned()).unwrap(); - // delay.delay_ms(INTERVAL); - // ws2812.write(off.iter().cloned()).unwrap(); - // delay.delay_ms(INTERVAL); - // unsafe { - // MORSE_QUEUE = [2, 3, 4, 1]; - // } + push_dot(); } fn emit_morse_dash() { - pushDash(); - // print_to_serial("_"); - // unsafe { - // MORSE_QUEUE = [8, 7, 6, 5]; - // } - // let neo_pixel = pins.neo_pixel.into_push_pull_output(); - // let mut ws2812 = Ws2812::new(timer, neo_pixel); - // ws2812.write(on.iter().cloned()).unwrap(); - // delay.delay_ms(3 * INTERVAL); - // ws2812.write(off.iter().cloned()).unwrap(); - // delay.delay_ms(INTERVAL); + push_dash(); } fn emit_morse_space() { - pushSpace(); - // let neo_pixel = pins.neo_pixel.into_push_pull_output(); - // let mut ws2812 = Ws2812::new(timer, neo_pixel); - // ws2812.write(off.iter().cloned()).unwrap(); - // delay.delay_ms(7 * INTERVAL); + push_space(); } #[interrupt] From 8913d3a987cf1026930757664e04e0c1d8aed28c Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Mon, 6 Feb 2023 22:43:38 -0800 Subject: [PATCH 35/45] Implenent a char queue. Next we should use it. --- boards/neo_trinkey/examples/usb_morse.rs | 71 +++++++++++++++--------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 1d816841ffb8..0619dd2b677c 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -32,17 +32,31 @@ use ws2812_timer_delay::Ws2812; // End Added use pac::{interrupt, CorePeripherals, Peripherals}; +const INTERVAL: u16 = 100u16; // Controls the speed of morse code generation +const CHAR_QUEUE_LENTGH: usize = 32; +const STATE_QUEUE_LENGTH: usize = 32; + struct CharQueue { - queue: [char; 32], + queue: [char; CHAR_QUEUE_LENTGH], + length: usize, + write_position: usize, + read_position: usize, } struct PinControlQueue { - queue: [PinControlDescriptor; 32], + queue: [PinControlDescriptor; STATE_QUEUE_LENGTH], length: usize, write_position: usize, read_position: usize, } +static mut CHAR_QUEUE: CharQueue = CharQueue { + queue: ['\r'; CHAR_QUEUE_LENTGH], + length: 0, + write_position: 0, + read_position: 0, +}; + static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { queue: [ PinControlDescriptor { @@ -242,15 +256,35 @@ fn get_next_state() -> bool { } } -static mut CHAR_QUEUE: Option = None; +fn push_char(letter: char) { + unsafe { + let index = CHAR_QUEUE.write_position as usize; + let queue = &mut CHAR_QUEUE; + queue.queue[index] = letter; + CHAR_QUEUE.write_position = (CHAR_QUEUE.write_position + 1) % CHAR_QUEUE_LENTGH; + queue.length += 1; + } +} + +fn pop_char() -> char { + unsafe { + if CHAR_QUEUE.length == 0 { + return '\r'; // Use CR to indicate empty queue + } + let return_value = CHAR_QUEUE.queue[CHAR_QUEUE.read_position]; + CHAR_QUEUE.read_position = (CHAR_QUEUE.read_position + 1) % CHAR_QUEUE_LENTGH; + CHAR_QUEUE.length -= 1; + return return_value; + } +} -const QUEUE_LENGTH: usize = 32; fn push_state(state: PinControlDescriptor) { unsafe { let index = PIN_CONTROL_QUEUE.write_position as usize; let queue = &mut PIN_CONTROL_QUEUE; queue.queue[index] = state; - PIN_CONTROL_QUEUE.write_position = (PIN_CONTROL_QUEUE.write_position + 1) % QUEUE_LENGTH; + PIN_CONTROL_QUEUE.write_position = + (PIN_CONTROL_QUEUE.write_position + 1) % STATE_QUEUE_LENGTH; queue.length += 1; } } @@ -265,7 +299,8 @@ fn pop_state() -> PinControlDescriptor { } let return_value = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.read_position]; PIN_CONTROL_QUEUE.length -= 1; - PIN_CONTROL_QUEUE.read_position = (PIN_CONTROL_QUEUE.read_position + 1) % QUEUE_LENGTH; + PIN_CONTROL_QUEUE.read_position = + (PIN_CONTROL_QUEUE.read_position + 1) % STATE_QUEUE_LENGTH; return PinControlDescriptor { pin_state: return_value.pin_state, duration: return_value.duration, @@ -273,24 +308,6 @@ fn pop_state() -> PinControlDescriptor { } } -fn pop() -> char { - return 's'; -} -fn real_pop() -> Option { - unsafe { - let queue = CHAR_QUEUE.as_mut().unwrap(); - let c = queue.queue[0]; - if c == '\0' { - return None; - } - for i in 0..queue.queue.len() - 1 { - queue.queue[i] = queue.queue[i + 1]; - } - queue.queue[queue.queue.len() - 1] = '\0'; - Some(c) - } -} - #[entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); @@ -559,14 +576,16 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); push_letter_interval(); } + '\r' => { + // We use CR to indicate the quueue is empty, so we make it phs only one blank cycle. + push_letter_interval(); + } _ => { emit_morse_space(); } } } -const INTERVAL: u16 = 100u16; - fn emit_morse_dot() { push_dot(); } From 3c30b80ffd1470c4fa0e23860489efbe04f30f3b Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Tue, 7 Feb 2023 16:40:43 -0800 Subject: [PATCH 36/45] Use new char buffer, for more compact representation. --- boards/neo_trinkey/examples/usb_morse.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 0619dd2b677c..5990e3137f54 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -247,6 +247,7 @@ fn get_next_state() -> bool { let mut pin_state: bool; unsafe { if COUNT_DOWN <= 0 { + emit_morse_letter(pop_char()); let pin_state_descriptor = pop_state(); COUNT_DOWN = pin_state_descriptor.duration; CURRENT_PIN_STATE = pin_state_descriptor.pin_state; @@ -405,7 +406,8 @@ fn poll_usb() { // emit_morse_letter('e'); let letter = char::from_u32([c.clone()][0] as u32).unwrap(); - emit_morse_letter(letter); + push_char(letter); + // emit_morse_letter(letter); // TODO: Move this to next state)_ } }; }); From 85332afbda5e22a3d7d1f5a17742c369d1dc1a87 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Tue, 7 Feb 2023 16:45:57 -0800 Subject: [PATCH 37/45] Only push new chars into the pin buffer when it's been drained. --- boards/neo_trinkey/examples/usb_morse.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 5990e3137f54..336dfe13196d 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -247,7 +247,10 @@ fn get_next_state() -> bool { let mut pin_state: bool; unsafe { if COUNT_DOWN <= 0 { - emit_morse_letter(pop_char()); + if PIN_CONTROL_QUEUE.length == 0 { + // Only push a new character into our que if we've drained it fully + emit_morse_letter(pop_char()); + } let pin_state_descriptor = pop_state(); COUNT_DOWN = pin_state_descriptor.duration; CURRENT_PIN_STATE = pin_state_descriptor.pin_state; From 958d4e172b96df5bb5037cefd4a1678b746c6494 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Tue, 7 Feb 2023 22:41:18 -0800 Subject: [PATCH 38/45] Add numbers, space and punctuation. --- boards/neo_trinkey/examples/usb_morse.rs | 241 +++++++++++++++++++++++ 1 file changed, 241 insertions(+) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 336dfe13196d..2e3e9704ce5d 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -581,6 +581,247 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); push_letter_interval(); } + "0" => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + "1" => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + "2" => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + "3" => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + "4" => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + "5" => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + "6" => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + "7" => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + "8" => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + "9" => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + ' ' => { + push_word_interval(); + } + ',' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '.' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '?' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '\'' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '!' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '/' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '(' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + ')' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '&' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + ':' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + ';' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '=' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '+' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '-' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '_' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '"' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '$' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '@' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } '\r' => { // We use CR to indicate the quueue is empty, so we make it phs only one blank cycle. push_letter_interval(); From 6ea95d58978138e02bad41f4e766ededf68ac418 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Tue, 7 Feb 2023 22:42:51 -0800 Subject: [PATCH 39/45] Fix word_interval -> space. CHatGPT assumed I'd called it something else. --- boards/neo_trinkey/examples/usb_morse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index 2e3e9704ce5d..c69819c19a69 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -662,7 +662,7 @@ fn emit_morse_letter(letter: char) { push_letter_interval(); } ' ' => { - push_word_interval(); + push_space(); } ',' => { emit_morse_dash(); From 3509349d2bc41f003f97c208e901af970ae068e9 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Tue, 7 Feb 2023 22:44:43 -0800 Subject: [PATCH 40/45] Also fix where copilot thought I wanted a " instead of a ' --- boards/neo_trinkey/examples/usb_morse.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index c69819c19a69..d34c1c2f4709 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -581,7 +581,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); push_letter_interval(); } - "0" => { + '0' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dash(); @@ -589,7 +589,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dash(); push_letter_interval(); } - "1" => { + '1' => { emit_morse_dot(); emit_morse_dash(); emit_morse_dash(); @@ -597,7 +597,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dash(); push_letter_interval(); } - "2" => { + '2' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dash(); @@ -605,7 +605,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dash(); push_letter_interval(); } - "3" => { + '3' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); @@ -613,7 +613,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dash(); push_letter_interval(); } - "4" => { + '4' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); @@ -621,7 +621,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dash(); push_letter_interval(); } - "5" => { + '5' => { emit_morse_dot(); emit_morse_dot(); emit_morse_dot(); @@ -629,7 +629,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); push_letter_interval(); } - "6" => { + '6' => { emit_morse_dash(); emit_morse_dot(); emit_morse_dot(); @@ -637,7 +637,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); push_letter_interval(); } - "7" => { + '7' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dot(); @@ -645,7 +645,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); push_letter_interval(); } - "8" => { + '8' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dash(); @@ -653,7 +653,7 @@ fn emit_morse_letter(letter: char) { emit_morse_dot(); push_letter_interval(); } - "9" => { + '9' => { emit_morse_dash(); emit_morse_dash(); emit_morse_dash(); From 8e93323dc952b62ff91a958b4011b3c5e4451818 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Wed, 8 Feb 2023 02:52:48 -0800 Subject: [PATCH 41/45] Increased char buffer size to 1K. Tried to make the USB loop provide queue length stats, but not having std in embedded rust meant I wasn't sure how to convert my usize into a string. (I made it a u32 at least.) --- boards/neo_trinkey/examples/usb_morse.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index d34c1c2f4709..c0d31799cf11 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -33,7 +33,7 @@ use ws2812_timer_delay::Ws2812; use pac::{interrupt, CorePeripherals, Peripherals}; const INTERVAL: u16 = 100u16; // Controls the speed of morse code generation -const CHAR_QUEUE_LENTGH: usize = 32; +const CHAR_QUEUE_LENTGH: usize = 1024; const STATE_QUEUE_LENGTH: usize = 32; struct CharQueue { @@ -340,11 +340,12 @@ fn main() -> ! { USB_BUS = Some( UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) .manufacturer("Agilistas!") - .product("Serial port") - .serial_number("TRINKEY_MORSE") + .product("Serial Port Morse Emitter") + .serial_number("TRINKY_MORSE") .device_class(USB_CLASS_CDC) .build(), ); + // USB_BUS.event_queue = Some(&mut USB_BUS_EVENTS); } unsafe { @@ -405,6 +406,9 @@ fn poll_usb() { } serial.write("Received: ".as_bytes()).ok(); serial.write(&[c.clone()]).ok(); + // serial.write("\tCharacter queue size: ".as_bytes()).ok(); // Hmmm. How do I do this in embedded Rust? + // let queue_size = i32::from(CHAR_QUEUE.length); + // serial.write(queue_size.to_str().as_bytes()).ok(); serial.write("\r\n".as_bytes()).ok(); // emit_morse_letter('e'); @@ -850,3 +854,17 @@ fn USB() { // the USB interrupt in the future. poll_usb(); } + +fn print_serial_header() { + unsafe { + let serial = USB_SERIAL.as_mut().unwrap(); + serial + .write("Connected to Neo Trinky Morse Echo.\r\n: ".as_bytes()) + .ok(); + serial + .write( + "Type letters and the LED will emit their morse code equivalents.\r\n: ".as_bytes(), + ) + .ok(); + } +} From 10408dbd9778519883de9019ddca9c914dc34771 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Wed, 8 Feb 2023 04:00:30 -0800 Subject: [PATCH 42/45] Fix incorrect 'n' encoding. QA'd all letters and numbers but haven't verified punctuation. --- boards/neo_trinkey/examples/usb_morse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/neo_trinkey/examples/usb_morse.rs b/boards/neo_trinkey/examples/usb_morse.rs index c0d31799cf11..c5f8aaf54590 100644 --- a/boards/neo_trinkey/examples/usb_morse.rs +++ b/boards/neo_trinkey/examples/usb_morse.rs @@ -506,7 +506,7 @@ fn emit_morse_letter(letter: char) { } 'n' => { emit_morse_dash(); - emit_morse_dash(); + emit_morse_dot(); push_letter_interval(); } 'o' => { From dc0c558d7ec4b1e54a1fbcde53cbec2499cd5ae2 Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 12 Feb 2023 14:00:21 -0800 Subject: [PATCH 43/45] Extract morse queues and character generation into a module. The module isn't used yet. --- boards/neo_trinkey/examples/morse_queues.rs | 706 ++++++++++++++++++++ 1 file changed, 706 insertions(+) create mode 100644 boards/neo_trinkey/examples/morse_queues.rs diff --git a/boards/neo_trinkey/examples/morse_queues.rs b/boards/neo_trinkey/examples/morse_queues.rs new file mode 100644 index 000000000000..d2603a4d14e5 --- /dev/null +++ b/boards/neo_trinkey/examples/morse_queues.rs @@ -0,0 +1,706 @@ +// const INTERVAL: u16 = 100u16; // Controls the speed of morse code generation + +mod morse_queues { + const CHAR_QUEUE_LENTGH: usize = 1024; + const STATE_QUEUE_LENGTH: usize = 32; + + struct CharQueue { + queue: [char; CHAR_QUEUE_LENTGH], + length: usize, + write_position: usize, + read_position: usize, + } + + struct PinControlQueue { + queue: [PinControlDescriptor; STATE_QUEUE_LENGTH], + length: usize, + write_position: usize, + read_position: usize, + } + + static mut CHAR_QUEUE: CharQueue = CharQueue { + queue: ['\r'; CHAR_QUEUE_LENTGH], + length: 0, + write_position: 0, + read_position: 0, + }; + + static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { + queue: [ + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + ], + length: 0, + write_position: 0, + read_position: 0, + }; + + struct PinControlDescriptor { + pin_state: bool, + duration: u8, + } + + fn push_dot() { + let dot = PinControlDescriptor { + pin_state: true, + duration: 1, + }; + let interval = PinControlDescriptor { + pin_state: false, + duration: 1, + }; + push_state(dot); + push_state(interval); + } + + fn push_dash() { + let dash = PinControlDescriptor { + pin_state: true, + duration: 3, + }; + let interval = PinControlDescriptor { + pin_state: false, + duration: 1, + }; + push_state(dash); + push_state(interval); + } + + fn push_space() { + let space = PinControlDescriptor { + pin_state: false, + duration: 7, + }; + push_state(space); + } + + fn push_letter_interval() { + let space = PinControlDescriptor { + pin_state: false, + duration: 3, + }; + push_state(space); + } + + static mut COUNT_DOWN: u8 = 0; + static mut CURRENT_PIN_STATE: bool = false; + + fn get_next_state() -> bool { + let mut pin_state: bool; + unsafe { + if COUNT_DOWN <= 0 { + if PIN_CONTROL_QUEUE.length == 0 { + // Only push a new character into our que if we've drained it fully + emit_morse_letter(pop_char()); + } + let pin_state_descriptor = pop_state(); + COUNT_DOWN = pin_state_descriptor.duration; + CURRENT_PIN_STATE = pin_state_descriptor.pin_state; + } + COUNT_DOWN -= 1; + return CURRENT_PIN_STATE; + } + } + + fn push_char(letter: char) { + unsafe { + let index = CHAR_QUEUE.write_position as usize; + let queue = &mut CHAR_QUEUE; + queue.queue[index] = letter; + CHAR_QUEUE.write_position = (CHAR_QUEUE.write_position + 1) % CHAR_QUEUE_LENTGH; + queue.length += 1; + } + } + + fn pop_char() -> char { + unsafe { + if CHAR_QUEUE.length == 0 { + return '\r'; // Use CR to indicate empty queue + } + let return_value = CHAR_QUEUE.queue[CHAR_QUEUE.read_position]; + CHAR_QUEUE.read_position = (CHAR_QUEUE.read_position + 1) % CHAR_QUEUE_LENTGH; + CHAR_QUEUE.length -= 1; + return return_value; + } + } + + fn push_state(state: PinControlDescriptor) { + unsafe { + let index = PIN_CONTROL_QUEUE.write_position as usize; + let queue = &mut PIN_CONTROL_QUEUE; + queue.queue[index] = state; + PIN_CONTROL_QUEUE.write_position = + (PIN_CONTROL_QUEUE.write_position + 1) % STATE_QUEUE_LENGTH; + queue.length += 1; + } + } + + fn pop_state() -> PinControlDescriptor { + unsafe { + if PIN_CONTROL_QUEUE.length == 0 { + return PinControlDescriptor { + pin_state: false, + duration: 1, + }; + } + let return_value = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.read_position]; + PIN_CONTROL_QUEUE.length -= 1; + PIN_CONTROL_QUEUE.read_position = + (PIN_CONTROL_QUEUE.read_position + 1) % STATE_QUEUE_LENGTH; + return PinControlDescriptor { + pin_state: return_value.pin_state, + duration: return_value.duration, + }; + } + } + + fn emit_morse_letter(letter: char) { + let downcased_letter = letter.to_ascii_lowercase(); // Add support for Latin 1 later. + match downcased_letter { + 'a' => { + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'b' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'c' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'd' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'e' => { + emit_morse_dot(); + push_letter_interval(); + } + 'f' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'g' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'h' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'i' => { + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'j' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'k' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'l' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'm' => { + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'n' => { + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'o' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'p' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'q' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'r' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 's' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 't' => { + emit_morse_dash(); + push_letter_interval(); + } + 'u' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'v' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'w' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'x' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'y' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'z' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '0' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '1' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '2' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '3' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '4' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '5' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '6' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '7' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '8' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '9' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + ' ' => { + push_space(); + } + ',' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '.' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '?' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '\'' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '!' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '/' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '(' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + ')' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '&' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + ':' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + ';' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '=' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '+' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '-' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '_' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '"' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '$' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '@' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '\r' => { + // We use CR to indicate the quueue is empty, so we make it phs only one blank cycle. + push_letter_interval(); + } + _ => { + emit_morse_space(); + } + } + } + + fn emit_morse_dot() { + push_dot(); + } + fn emit_morse_dash() { + push_dash(); + } + fn emit_morse_space() { + push_space(); + } +} From bad9fb8646020aa8e1bcc420ea7eeb271d2db89b Mon Sep 17 00:00:00 2001 From: jazKatalyst Date: Sun, 12 Feb 2023 15:07:14 -0700 Subject: [PATCH 44/45] Initial implemenation of hex to rgb function for trinkey --- .../examples/hex_color_converter.rs | 53 ++ boards/neo_trinkey/examples/usb_colors.rs | 873 ++++++++++++++++++ 2 files changed, 926 insertions(+) create mode 100644 boards/neo_trinkey/examples/hex_color_converter.rs create mode 100644 boards/neo_trinkey/examples/usb_colors.rs diff --git a/boards/neo_trinkey/examples/hex_color_converter.rs b/boards/neo_trinkey/examples/hex_color_converter.rs new file mode 100644 index 000000000000..42e0762ac9a9 --- /dev/null +++ b/boards/neo_trinkey/examples/hex_color_converter.rs @@ -0,0 +1,53 @@ +#![no_std] +#![no_main] + +pub fn hex_to_rgb(hex: &str) -> Result<(u8, u8, u8), &str> { + let hex = hex.trim_start_matches('#'); + + let result: Result<(u8, u8, u8), &str> = if hex.len() == 6 { + let r = u8::from_str_radix(&hex[0..2], 16).unwrap(); + let g = u8::from_str_radix(&hex[2..4], 16).unwrap(); + let b = u8::from_str_radix(&hex[4..6], 16).unwrap(); + Ok((r, g, b)) + } else if hex.len() == 3 { + let r = u8::from_str_radix(&hex[0..1], 16).unwrap(); + let g = u8::from_str_radix(&hex[1..2], 16).unwrap(); + let b = u8::from_str_radix(&hex[2..3], 16).unwrap(); + Ok((r * 16 + r, g * 16 + g, b * 16 + b)) + } else { + Err("Invalid color") + }; + + result +} + +#[cfg(test)] +mod tests { + use super::hex_to_rgb; + + #[test] + fn test_valid_hex_to_rgb() { + let success_cases: [(&str, (u8, u8, u8)); 7] = [ + ("#000000", (0, 0, 0)), + ("#ffffff", (255, 255, 255)), + ("#FF0000", (255, 0, 0)), + ("#00FF00", (0, 255, 0)), + ("#0000FF", (0, 0, 255)), + ("#F0F0F0", (240, 240, 240)), + ("#abcdef", (171, 205, 239)), + ]; + + for case in success_cases.iter() { + let (hex, expected) = case; + let result = hex_to_rgb(hex); + + assert_eq!(result.ok().unwrap(), *expected, "hex: {}", hex); + } + } + + #[test] + fn test_invalid_hex_to_rgb() { + let invalid_result = hex_to_rgb("invalid"); + assert_eq!(invalid_result.err().unwrap(), "Invalid color"); + } +} \ No newline at end of file diff --git a/boards/neo_trinkey/examples/usb_colors.rs b/boards/neo_trinkey/examples/usb_colors.rs new file mode 100644 index 000000000000..1e91548cfc30 --- /dev/null +++ b/boards/neo_trinkey/examples/usb_colors.rs @@ -0,0 +1,873 @@ +#![no_std] +#![no_main] +use bsp::pac::dsu::length; +use panic_halt as _; + +use core::mem::MaybeUninit; +use fixed_slice_vec::FixedSliceVec; + +use cortex_m::asm::delay as cycle_delay; +use cortex_m::peripheral::NVIC; +use usb_device::bus::UsbBusAllocator; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use neo_trinkey as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use hal::clock::GenericClockController; +use hal::usb::UsbBus; + +// Added +use hal::delay::Delay; +// use hal::pac::{CorePeripherals, Peripherals}; +use hal::prelude::*; +use hal::timer::TimerCounter; + +use smart_leds::{hsv::RGB8, SmartLedsWrite}; +use ws2812_timer_delay::Ws2812; +// End Added +use pac::{interrupt, CorePeripherals, Peripherals}; + +mod hex_color_converter; + +const INTERVAL: u16 = 100u16; // Controls the speed of morse code generation +const CHAR_QUEUE_LENTGH: usize = 1024; +const STATE_QUEUE_LENGTH: usize = 32; + +struct CharQueue { + queue: [char; CHAR_QUEUE_LENTGH], + length: usize, + write_position: usize, + read_position: usize, +} + +struct PinControlQueue { + queue: [PinControlDescriptor; STATE_QUEUE_LENGTH], + length: usize, + write_position: usize, + read_position: usize, +} + +static mut CHAR_QUEUE: CharQueue = CharQueue { + queue: ['\r'; CHAR_QUEUE_LENTGH], + length: 0, + write_position: 0, + read_position: 0, +}; + +static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { + queue: [ + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + PinControlDescriptor { + pin_state: false, + duration: 0, + }, + ], + length: 0, + write_position: 0, + read_position: 0, +}; + +struct PinControlDescriptor { + pin_state: bool, + duration: u8, +} + +fn push_dot() { + let dot = PinControlDescriptor { + pin_state: true, + duration: 1, + }; + let interval = PinControlDescriptor { + pin_state: false, + duration: 1, + }; + push_state(dot); + push_state(interval); +} + +fn push_dash() { + let dash = PinControlDescriptor { + pin_state: true, + duration: 3, + }; + let interval = PinControlDescriptor { + pin_state: false, + duration: 1, + }; + push_state(dash); + push_state(interval); +} + +fn push_space() { + let space = PinControlDescriptor { + pin_state: false, + duration: 7, + }; + push_state(space); +} + +fn push_letter_interval() { + let space = PinControlDescriptor { + pin_state: false, + duration: 3, + }; + push_state(space); +} + +static mut COUNT_DOWN: u8 = 0; +static mut CURRENT_PIN_STATE: bool = false; + +fn get_next_state() -> bool { + let mut pin_state: bool; + unsafe { + if COUNT_DOWN <= 0 { + if PIN_CONTROL_QUEUE.length == 0 { + // Only push a new character into our que if we've drained it fully + emit_morse_letter(pop_char()); + } + let pin_state_descriptor = pop_state(); + COUNT_DOWN = pin_state_descriptor.duration; + CURRENT_PIN_STATE = pin_state_descriptor.pin_state; + } + COUNT_DOWN -= 1; + return CURRENT_PIN_STATE; + } +} + +fn push_char(letter: char) { + unsafe { + let index = CHAR_QUEUE.write_position as usize; + let queue = &mut CHAR_QUEUE; + queue.queue[index] = letter; + CHAR_QUEUE.write_position = (CHAR_QUEUE.write_position + 1) % CHAR_QUEUE_LENTGH; + queue.length += 1; + } +} + +fn pop_char() -> char { + unsafe { + if CHAR_QUEUE.length == 0 { + return '\r'; // Use CR to indicate empty queue + } + let return_value = CHAR_QUEUE.queue[CHAR_QUEUE.read_position]; + CHAR_QUEUE.read_position = (CHAR_QUEUE.read_position + 1) % CHAR_QUEUE_LENTGH; + CHAR_QUEUE.length -= 1; + return return_value; + } +} + +fn push_state(state: PinControlDescriptor) { + unsafe { + let index = PIN_CONTROL_QUEUE.write_position as usize; + let queue = &mut PIN_CONTROL_QUEUE; + queue.queue[index] = state; + PIN_CONTROL_QUEUE.write_position = + (PIN_CONTROL_QUEUE.write_position + 1) % STATE_QUEUE_LENGTH; + queue.length += 1; + } +} + +fn pop_state() -> PinControlDescriptor { + unsafe { + if PIN_CONTROL_QUEUE.length == 0 { + return PinControlDescriptor { + pin_state: false, + duration: 1, + }; + } + let return_value = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.read_position]; + PIN_CONTROL_QUEUE.length -= 1; + PIN_CONTROL_QUEUE.read_position = + (PIN_CONTROL_QUEUE.read_position + 1) % STATE_QUEUE_LENGTH; + return PinControlDescriptor { + pin_state: return_value.pin_state, + duration: return_value.duration, + }; + } +} + +#[entry] +fn main() -> ! { + let result = hex_color_converter::hex_to_rgb("123"); + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + unsafe { + USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Agilistas!") + .product("Serial Port Morse Emitter") + .serial_number("TRINKY_MORSE") + .device_class(USB_CLASS_CDC) + .build(), + ); + // USB_BUS.event_queue = Some(&mut USB_BUS_EVENTS); + } + + unsafe { + core.NVIC.set_priority(interrupt::USB, 1); + NVIC::unmask(interrupt::USB); + } + + let gclk0 = clocks.gclk0(); + let timer_clock = clocks.tcc2_tc3(&gclk0).unwrap(); + let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.TC3, &mut peripherals.PM); + timer.start(3.mhz()); + let neo_pixel = pins.neo_pixel.into_push_pull_output(); + let mut ws2812 = Ws2812::new(timer, neo_pixel); + + let mut delay = Delay::new(core.SYST, &mut clocks); + + const NUM_LEDS: usize = 4; + let off = [RGB8::default(); NUM_LEDS]; + let on = [ + RGB8::new(5, 5, 0), + RGB8::new(0, 5, 5), + RGB8::new(5, 0, 5), + RGB8::new(2, 2, 2), + ]; + + loop { + // let letter = pop(); + // emit_morse_letter(letter); + let state = get_next_state(); + if state { + // turn on + ws2812.write(on.iter().cloned()).unwrap(); + } else { + // turn off + ws2812.write(off.iter().cloned()).unwrap(); + } + + // ws2812.write(off.iter().cloned()).unwrap(); + delay.delay_ms(INTERVAL); + } +} + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; + +fn poll_usb() { + unsafe { + USB_BUS.as_mut().map(|usb_dev| { + USB_SERIAL.as_mut().map(|serial| { + usb_dev.poll(&mut [serial]); + let mut buf = [0u8; 64]; + + if let Ok(count) = serial.read(&mut buf) { + for (i, c) in buf.iter().enumerate() { + if i >= count { + break; + } + serial.write("Received: ".as_bytes()).ok(); + serial.write(&[c.clone()]).ok(); + // serial.write("\tCharacter queue size: ".as_bytes()).ok(); // Hmmm. How do I do this in embedded Rust? + // let queue_size = i32::from(CHAR_QUEUE.length); + // serial.write(queue_size.to_str().as_bytes()).ok(); + serial.write("\r\n".as_bytes()).ok(); + // emit_morse_letter('e'); + + let letter = char::from_u32([c.clone()][0] as u32).unwrap(); + push_char(letter); + // emit_morse_letter(letter); // TODO: Move this to next state)_ + } + }; + }); + }); + }; +} + +fn emit_morse_letter(letter: char) { + let downcased_letter = letter.to_ascii_lowercase(); // Add support for Latin 1 later. + match downcased_letter { + 'a' => { + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'b' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'c' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'd' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'e' => { + emit_morse_dot(); + push_letter_interval(); + } + 'f' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'g' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'h' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'i' => { + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'j' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'k' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'l' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 'm' => { + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'n' => { + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'o' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'p' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 'q' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'r' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + 's' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + 't' => { + emit_morse_dash(); + push_letter_interval(); + } + 'u' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'v' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'w' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'x' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + 'y' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + 'z' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '0' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '1' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '2' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '3' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '4' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '5' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '6' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '7' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '8' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '9' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + ' ' => { + push_space(); + } + ',' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '.' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '?' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + '\'' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '!' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + push_letter_interval(); + } + '/' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '(' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + ')' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '&' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + ':' => { + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + push_letter_interval(); + } + ';' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '=' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '+' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '-' => { + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '_' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + push_letter_interval(); + } + '"' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '$' => { + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '@' => { + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dash(); + emit_morse_dot(); + emit_morse_dash(); + emit_morse_dot(); + push_letter_interval(); + } + '\r' => { + // We use CR to indicate the quueue is empty, so we make it phs only one blank cycle. + push_letter_interval(); + } + _ => { + emit_morse_space(); + } + } +} + +fn emit_morse_dot() { + push_dot(); +} +fn emit_morse_dash() { + push_dash(); +} +fn emit_morse_space() { + push_space(); +} + +#[interrupt] +fn USB() { + // Note: USB is the name of the interrupt, you can not attach the #[interrupt] + // tag to poll_usb. Although you could add the contents of poll_usb into + // this function, separating them allows you to add more functions to run on + // the USB interrupt in the future. + poll_usb(); +} + +fn print_serial_header() { + unsafe { + let serial = USB_SERIAL.as_mut().unwrap(); + serial + .write("Connected to Neo Trinky Morse Echo.\r\n: ".as_bytes()) + .ok(); + serial + .write( + "Type letters and the LED will emit their morse code equivalents.\r\n: ".as_bytes(), + ) + .ok(); + } +} \ No newline at end of file From 6ab56ba225987736e7b93e9610dbdf9e64a76d0d Mon Sep 17 00:00:00 2001 From: Ian McFarland Date: Sun, 12 Feb 2023 14:18:08 -0800 Subject: [PATCH 45/45] Extracted morse specific library code into separate module. --- boards/neo_trinkey/examples/morse_queues.rs | 34 +- .../examples/usb_morse_with_modules.rs | 874 ++++++++++++++++++ 2 files changed, 891 insertions(+), 17 deletions(-) create mode 100644 boards/neo_trinkey/examples/usb_morse_with_modules.rs diff --git a/boards/neo_trinkey/examples/morse_queues.rs b/boards/neo_trinkey/examples/morse_queues.rs index d2603a4d14e5..a0a0bb60ed51 100644 --- a/boards/neo_trinkey/examples/morse_queues.rs +++ b/boards/neo_trinkey/examples/morse_queues.rs @@ -1,17 +1,17 @@ // const INTERVAL: u16 = 100u16; // Controls the speed of morse code generation -mod morse_queues { +pub mod morse_queues { const CHAR_QUEUE_LENTGH: usize = 1024; const STATE_QUEUE_LENGTH: usize = 32; - struct CharQueue { + pub struct CharQueue { queue: [char; CHAR_QUEUE_LENTGH], length: usize, write_position: usize, read_position: usize, } - struct PinControlQueue { + pub struct PinControlQueue { queue: [PinControlDescriptor; STATE_QUEUE_LENGTH], length: usize, write_position: usize, @@ -161,12 +161,12 @@ mod morse_queues { read_position: 0, }; - struct PinControlDescriptor { + pub struct PinControlDescriptor { pin_state: bool, duration: u8, } - fn push_dot() { + pub fn push_dot() { let dot = PinControlDescriptor { pin_state: true, duration: 1, @@ -179,7 +179,7 @@ mod morse_queues { push_state(interval); } - fn push_dash() { + pub fn push_dash() { let dash = PinControlDescriptor { pin_state: true, duration: 3, @@ -192,7 +192,7 @@ mod morse_queues { push_state(interval); } - fn push_space() { + pub fn push_space() { let space = PinControlDescriptor { pin_state: false, duration: 7, @@ -200,7 +200,7 @@ mod morse_queues { push_state(space); } - fn push_letter_interval() { + pub fn push_letter_interval() { let space = PinControlDescriptor { pin_state: false, duration: 3, @@ -211,7 +211,7 @@ mod morse_queues { static mut COUNT_DOWN: u8 = 0; static mut CURRENT_PIN_STATE: bool = false; - fn get_next_state() -> bool { + pub fn get_next_state() -> bool { let mut pin_state: bool; unsafe { if COUNT_DOWN <= 0 { @@ -228,7 +228,7 @@ mod morse_queues { } } - fn push_char(letter: char) { + pub fn push_char(letter: char) { unsafe { let index = CHAR_QUEUE.write_position as usize; let queue = &mut CHAR_QUEUE; @@ -238,7 +238,7 @@ mod morse_queues { } } - fn pop_char() -> char { + pub fn pop_char() -> char { unsafe { if CHAR_QUEUE.length == 0 { return '\r'; // Use CR to indicate empty queue @@ -250,7 +250,7 @@ mod morse_queues { } } - fn push_state(state: PinControlDescriptor) { + pub fn push_state(state: PinControlDescriptor) { unsafe { let index = PIN_CONTROL_QUEUE.write_position as usize; let queue = &mut PIN_CONTROL_QUEUE; @@ -261,7 +261,7 @@ mod morse_queues { } } - fn pop_state() -> PinControlDescriptor { + pub fn pop_state() -> PinControlDescriptor { unsafe { if PIN_CONTROL_QUEUE.length == 0 { return PinControlDescriptor { @@ -280,7 +280,7 @@ mod morse_queues { } } - fn emit_morse_letter(letter: char) { + pub fn emit_morse_letter(letter: char) { let downcased_letter = letter.to_ascii_lowercase(); // Add support for Latin 1 later. match downcased_letter { 'a' => { @@ -694,13 +694,13 @@ mod morse_queues { } } - fn emit_morse_dot() { + pub fn emit_morse_dot() { push_dot(); } - fn emit_morse_dash() { + pub fn emit_morse_dash() { push_dash(); } - fn emit_morse_space() { + pub fn emit_morse_space() { push_space(); } } diff --git a/boards/neo_trinkey/examples/usb_morse_with_modules.rs b/boards/neo_trinkey/examples/usb_morse_with_modules.rs new file mode 100644 index 000000000000..1fc22445f6e3 --- /dev/null +++ b/boards/neo_trinkey/examples/usb_morse_with_modules.rs @@ -0,0 +1,874 @@ +#![no_std] +#![no_main] +use bsp::pac::dsu::length; +use panic_halt as _; + +use core::mem::MaybeUninit; +use fixed_slice_vec::FixedSliceVec; + +use cortex_m::asm::delay as cycle_delay; +use cortex_m::peripheral::NVIC; +use usb_device::bus::UsbBusAllocator; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use neo_trinkey as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use hal::clock::GenericClockController; +use hal::usb::UsbBus; + +// Added +use hal::delay::Delay; +// use hal::pac::{CorePeripherals, Peripherals}; +use hal::prelude::*; +use hal::timer::TimerCounter; + +use smart_leds::{hsv::RGB8, SmartLedsWrite}; +use ws2812_timer_delay::Ws2812; +// End Added +use pac::{interrupt, CorePeripherals, Peripherals}; + +pub mod morse_queues; +use crate::morse_queues::morse_queues::get_next_state; +use crate::morse_queues::morse_queues::push_char; + +const INTERVAL: u16 = 100u16; // Controls the speed of morse code generation + // const CHAR_QUEUE_LENTGH: usize = 1024; + // const STATE_QUEUE_LENGTH: usize = 32; + +// struct CharQueue { +// queue: [char; CHAR_QUEUE_LENTGH], +// length: usize, +// write_position: usize, +// read_position: usize, +// } + +// struct PinControlQueue { +// queue: [PinControlDescriptor; STATE_QUEUE_LENGTH], +// length: usize, +// write_position: usize, +// read_position: usize, +// } + +// static mut CHAR_QUEUE: CharQueue = CharQueue { +// queue: ['\r'; CHAR_QUEUE_LENTGH], +// length: 0, +// write_position: 0, +// read_position: 0, +// }; + +// static mut PIN_CONTROL_QUEUE: PinControlQueue = PinControlQueue { +// queue: [ +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// PinControlDescriptor { +// pin_state: false, +// duration: 0, +// }, +// ], +// length: 0, +// write_position: 0, +// read_position: 0, +// }; + +// struct PinControlDescriptor { +// pin_state: bool, +// duration: u8, +// } + +// fn push_dot() { +// let dot = PinControlDescriptor { +// pin_state: true, +// duration: 1, +// }; +// let interval = PinControlDescriptor { +// pin_state: false, +// duration: 1, +// }; +// push_state(dot); +// push_state(interval); +// } + +// fn push_dash() { +// let dash = PinControlDescriptor { +// pin_state: true, +// duration: 3, +// }; +// let interval = PinControlDescriptor { +// pin_state: false, +// duration: 1, +// }; +// push_state(dash); +// push_state(interval); +// } + +// fn push_space() { +// let space = PinControlDescriptor { +// pin_state: false, +// duration: 7, +// }; +// push_state(space); +// } + +// fn push_letter_interval() { +// let space = PinControlDescriptor { +// pin_state: false, +// duration: 3, +// }; +// push_state(space); +// } + +// static mut COUNT_DOWN: u8 = 0; +// static mut CURRENT_PIN_STATE: bool = false; + +// fn get_next_state() -> bool { +// let mut pin_state: bool; +// unsafe { +// if COUNT_DOWN <= 0 { +// if PIN_CONTROL_QUEUE.length == 0 { +// // Only push a new character into our que if we've drained it fully +// emit_morse_letter(pop_char()); +// } +// let pin_state_descriptor = pop_state(); +// COUNT_DOWN = pin_state_descriptor.duration; +// CURRENT_PIN_STATE = pin_state_descriptor.pin_state; +// } +// COUNT_DOWN -= 1; +// return CURRENT_PIN_STATE; +// } +// } + +// fn push_char(letter: char) { +// unsafe { +// let index = CHAR_QUEUE.write_position as usize; +// let queue = &mut CHAR_QUEUE; +// queue.queue[index] = letter; +// CHAR_QUEUE.write_position = (CHAR_QUEUE.write_position + 1) % CHAR_QUEUE_LENTGH; +// queue.length += 1; +// } +// } + +// fn pop_char() -> char { +// unsafe { +// if CHAR_QUEUE.length == 0 { +// return '\r'; // Use CR to indicate empty queue +// } +// let return_value = CHAR_QUEUE.queue[CHAR_QUEUE.read_position]; +// CHAR_QUEUE.read_position = (CHAR_QUEUE.read_position + 1) % CHAR_QUEUE_LENTGH; +// CHAR_QUEUE.length -= 1; +// return return_value; +// } +// } + +// fn push_state(state: PinControlDescriptor) { +// unsafe { +// let index = PIN_CONTROL_QUEUE.write_position as usize; +// let queue = &mut PIN_CONTROL_QUEUE; +// queue.queue[index] = state; +// PIN_CONTROL_QUEUE.write_position = +// (PIN_CONTROL_QUEUE.write_position + 1) % STATE_QUEUE_LENGTH; +// queue.length += 1; +// } +// } + +// fn pop_state() -> PinControlDescriptor { +// unsafe { +// if PIN_CONTROL_QUEUE.length == 0 { +// return PinControlDescriptor { +// pin_state: false, +// duration: 1, +// }; +// } +// let return_value = &PIN_CONTROL_QUEUE.queue[PIN_CONTROL_QUEUE.read_position]; +// PIN_CONTROL_QUEUE.length -= 1; +// PIN_CONTROL_QUEUE.read_position = +// (PIN_CONTROL_QUEUE.read_position + 1) % STATE_QUEUE_LENGTH; +// return PinControlDescriptor { +// pin_state: return_value.pin_state, +// duration: return_value.duration, +// }; +// } +// } + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + unsafe { + USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) + .manufacturer("Agilistas!") + .product("Serial Port Morse Emitter") + .serial_number("TRINKY_MORSE") + .device_class(USB_CLASS_CDC) + .build(), + ); + // USB_BUS.event_queue = Some(&mut USB_BUS_EVENTS); + } + + unsafe { + core.NVIC.set_priority(interrupt::USB, 1); + NVIC::unmask(interrupt::USB); + } + + let gclk0 = clocks.gclk0(); + let timer_clock = clocks.tcc2_tc3(&gclk0).unwrap(); + let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.TC3, &mut peripherals.PM); + timer.start(3.mhz()); + let neo_pixel = pins.neo_pixel.into_push_pull_output(); + let mut ws2812 = Ws2812::new(timer, neo_pixel); + + let mut delay = Delay::new(core.SYST, &mut clocks); + + const NUM_LEDS: usize = 4; + let off = [RGB8::default(); NUM_LEDS]; + let on = [ + RGB8::new(5, 5, 0), + RGB8::new(0, 5, 5), + RGB8::new(5, 0, 5), + RGB8::new(2, 2, 2), + ]; + + loop { + // let letter = pop(); + // emit_morse_letter(letter); + let state = get_next_state(); + if state { + // turn on + ws2812.write(on.iter().cloned()).unwrap(); + } else { + // turn off + ws2812.write(off.iter().cloned()).unwrap(); + } + + // ws2812.write(off.iter().cloned()).unwrap(); + delay.delay_ms(INTERVAL); + } +} + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; + +fn poll_usb() { + unsafe { + USB_BUS.as_mut().map(|usb_dev| { + USB_SERIAL.as_mut().map(|serial| { + usb_dev.poll(&mut [serial]); + let mut buf = [0u8; 64]; + + if let Ok(count) = serial.read(&mut buf) { + for (i, c) in buf.iter().enumerate() { + if i >= count { + break; + } + serial.write("Received: ".as_bytes()).ok(); + serial.write(&[c.clone()]).ok(); + // serial.write("\tCharacter queue size: ".as_bytes()).ok(); // Hmmm. How do I do this in embedded Rust? + // let queue_size = i32::from(CHAR_QUEUE.length); + // serial.write(queue_size.to_str().as_bytes()).ok(); + serial.write("\r\n".as_bytes()).ok(); + // emit_morse_letter('e'); + + let letter = char::from_u32([c.clone()][0] as u32).unwrap(); + push_char(letter); + // emit_morse_letter(letter); // TODO: Move this to next state)_ + } + }; + }); + }); + }; +} + +// fn emit_morse_letter(letter: char) { +// let downcased_letter = letter.to_ascii_lowercase(); // Add support for Latin 1 later. +// match downcased_letter { +// 'a' => { +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'b' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'c' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'd' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'e' => { +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'f' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'g' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'h' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'i' => { +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'j' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'k' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'l' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'm' => { +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'n' => { +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'o' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'p' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 'q' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'r' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 's' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// 't' => { +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'u' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'v' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'w' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'x' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'y' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// 'z' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '0' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '1' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '2' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '3' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '4' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '5' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '6' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '7' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '8' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '9' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// ' ' => { +// push_space(); +// } +// ',' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '.' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '?' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '\'' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '!' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '/' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '(' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// ')' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '&' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// ':' => { +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// ';' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '=' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '+' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '-' => { +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '_' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// push_letter_interval(); +// } +// '"' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '$' => { +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '@' => { +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dash(); +// emit_morse_dot(); +// emit_morse_dash(); +// emit_morse_dot(); +// push_letter_interval(); +// } +// '\r' => { +// // We use CR to indicate the quueue is empty, so we make it phs only one blank cycle. +// push_letter_interval(); +// } +// _ => { +// emit_morse_space(); +// } +// } +// } + +// fn emit_morse_dot() { +// push_dot(); +// } +// fn emit_morse_dash() { +// push_dash(); +// } +// fn emit_morse_space() { +// push_space(); +// } + +#[interrupt] +fn USB() { + // Note: USB is the name of the interrupt, you can not attach the #[interrupt] + // tag to poll_usb. Although you could add the contents of poll_usb into + // this function, separating them allows you to add more functions to run on + // the USB interrupt in the future. + poll_usb(); +} + +fn print_serial_header() { + unsafe { + let serial = USB_SERIAL.as_mut().unwrap(); + serial + .write("Connected to Neo Trinky Morse Echo.\r\n: ".as_bytes()) + .ok(); + serial + .write( + "Type letters and the LED will emit their morse code equivalents.\r\n: ".as_bytes(), + ) + .ok(); + } +}