Reorganize to support Pico
This commit is contained in:
parent
ccd5b0e741
commit
f6202c3b16
42
Cargo.toml
42
Cargo.toml
|
@ -1,45 +1,7 @@
|
|||
[package]
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
name = "trinket-streamdeck"
|
||||
version = "0.1.0"
|
||||
build = "src/build.rs"
|
||||
|
||||
[dependencies]
|
||||
apa102-spi = "0.3.2"
|
||||
atsamd-hal = { version = "0.14", default-features = false, features = [
|
||||
"samd21e",
|
||||
"samd21e-rt",
|
||||
"unproven",
|
||||
"usb",
|
||||
] }
|
||||
bitbang-hal = "0.3.2"
|
||||
cortex-m = "0.7.4"
|
||||
cortex-m-rt = "0.7.1"
|
||||
cortex-m-semihosting = "0.3.3"
|
||||
embedded-hal = "0.2"
|
||||
once_cell = { version = "1.7.2", default-features = false }
|
||||
panic-halt = "0.2.0"
|
||||
smart-leds = "0.3"
|
||||
usb-device = "0.2"
|
||||
usbd-serial = "0.1"
|
||||
streamdeck-common = { version = "0.1.0", path = "./streamdeck-common" }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1.0"
|
||||
toml = "0.5.8"
|
||||
|
||||
# this lets you use `cargo fix`!
|
||||
[[bin]]
|
||||
name = "trinket-streamdeck"
|
||||
test = false
|
||||
bench = false
|
||||
[workspace]
|
||||
members = ["trinket", "common", "pico"]
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1 # better optimizations
|
||||
debug = true # symbols are nice and they don't increase the size on Flash
|
||||
lto = true # better optimizations
|
||||
|
||||
[workspace]
|
||||
members = ["./streamdeck-common"]
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
[package]
|
||||
name = "streamdeck-common"
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
31
pico/Cargo.toml
Normal file
31
pico/Cargo.toml
Normal file
|
@ -0,0 +1,31 @@
|
|||
[package]
|
||||
name = "pico-streamdeck"
|
||||
version = "0.1.0"
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
readme = "../README.md"
|
||||
edition = "2021"
|
||||
build = "src/build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
common = { version = "0.1.0", path = "../common" }
|
||||
cortex-m = "0.7"
|
||||
cortex-m-rt = { version = "0.7", features = ["device"] }
|
||||
embedded-hal = "0.2"
|
||||
once_cell = { version = "1.7.2", default-features = false }
|
||||
panic-halt = "0.2.0"
|
||||
rp2040-hal = { version = "0.3.0", features = ["rt"] }
|
||||
# rp-pico = "0.2.0"
|
||||
usb-device = "0.2"
|
||||
usbd-serial = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1.0"
|
||||
toml = "0.5.8"
|
||||
|
||||
# this lets you use `cargo fix`!
|
||||
[[bin]]
|
||||
name = "pico-streamdeck"
|
||||
test = false
|
||||
bench = false
|
47
pico/src/bsp.rs
Normal file
47
pico/src/bsp.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
//// The linker will place this boot block at the start of our program image. We
|
||||
//// need this to help the ROM bootloader get our code up and running.
|
||||
#[cfg(feature = "boot2")]
|
||||
#[link_section = ".boot2"]
|
||||
#[no_mangle]
|
||||
#[used]
|
||||
pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
|
||||
|
||||
pub use cortex_m_rt::entry;
|
||||
pub use rp2040_hal::pac;
|
||||
|
||||
rp2040_hal::bsp_pins!(
|
||||
Gpio0 { name: gpio0 },
|
||||
Gpio1 { name: gpio1 },
|
||||
Gpio2 { name: gpio2 },
|
||||
Gpio3 { name: gpio3 },
|
||||
Gpio4 { name: gpio4 },
|
||||
Gpio5 { name: gpio5 },
|
||||
Gpio6 { name: gpio6 },
|
||||
Gpio7 { name: gpio7 },
|
||||
Gpio8 { name: gpio8 },
|
||||
Gpio9 { name: gpio9 },
|
||||
Gpio10 { name: gpio10 },
|
||||
Gpio11 { name: gpio11 },
|
||||
Gpio12 { name: gpio12 },
|
||||
Gpio13 { name: gpio13 },
|
||||
Gpio14 { name: gpio14 },
|
||||
Gpio15 { name: gpio15 },
|
||||
Gpio16 { name: gpio16 },
|
||||
Gpio17 { name: gpio17 },
|
||||
Gpio18 { name: gpio18 },
|
||||
Gpio19 { name: gpio19 },
|
||||
Gpio20 { name: gpio20 },
|
||||
Gpio21 { name: gpio21 },
|
||||
Gpio22 { name: gpio22 },
|
||||
Gpio23 { name: b_power_save },
|
||||
Gpio24 { name: vbus_detect },
|
||||
Gpio25 { name: led },
|
||||
Gpio26 { name: gpio26 },
|
||||
Gpio27 { name: gpio27 },
|
||||
Gpio28 { name: gpio28 },
|
||||
Gpio29 {
|
||||
name: voltage_monitor
|
||||
},
|
||||
);
|
||||
|
||||
pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;
|
41
pico/src/buttons.rs
Normal file
41
pico/src/buttons.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use common::{ButtonPins, ButtonState};
|
||||
use core::convert::Infallible;
|
||||
use embedded_hal::digital::v2::InputPin;
|
||||
use rp2040_hal::gpio::pin::{
|
||||
bank0::{Gpio0, Gpio1, Gpio2, Gpio3, Gpio4},
|
||||
Disabled, Input, Pin, PullDown, PullUp,
|
||||
};
|
||||
|
||||
pub(crate) struct Buttons {
|
||||
pub(crate) d0: Pin<Gpio0, Disabled<PullDown>>,
|
||||
pub(crate) d1: Pin<Gpio1, Disabled<PullDown>>,
|
||||
pub(crate) d2: Pin<Gpio2, Disabled<PullDown>>,
|
||||
pub(crate) d3: Pin<Gpio3, Disabled<PullDown>>,
|
||||
pub(crate) d4: Pin<Gpio4, Disabled<PullDown>>,
|
||||
}
|
||||
|
||||
pub(crate) struct Pins {
|
||||
d0: Pin<Gpio0, Input<PullUp>>,
|
||||
d1: Pin<Gpio1, Input<PullUp>>,
|
||||
d2: Pin<Gpio2, Input<PullUp>>,
|
||||
d3: Pin<Gpio3, Input<PullUp>>,
|
||||
d4: Pin<Gpio4, Input<PullUp>>,
|
||||
}
|
||||
|
||||
impl<'a> ButtonPins<'a, 5> for Pins {
|
||||
fn to_array(&'a self) -> [&'a dyn InputPin<Error = Infallible>; 5] {
|
||||
[&self.d0, &self.d1, &self.d2, &self.d3, &self.d4]
|
||||
}
|
||||
}
|
||||
|
||||
impl Buttons {
|
||||
pub(crate) fn init(self) -> ButtonState<Pins, 5> {
|
||||
ButtonState::from_pins(Pins {
|
||||
d0: self.d0.into_mode(),
|
||||
d1: self.d1.into_mode(),
|
||||
d2: self.d2.into_mode(),
|
||||
d3: self.d3.into_mode(),
|
||||
d4: self.d4.into_mode(),
|
||||
})
|
||||
}
|
||||
}
|
70
pico/src/device_signature.rs
Normal file
70
pico/src/device_signature.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
//! Blatently stolen from https://github.com/korken89/pico-probe/blob/master/src/device_signature.rs
|
||||
|
||||
use rp2040_hal::pac::{IO_QSPI, XIP_SSI};
|
||||
|
||||
#[inline(always)]
|
||||
#[link_section = ".data.ram_func"]
|
||||
unsafe fn set_cs(level: bool) {
|
||||
(*IO_QSPI::ptr()).gpio_qspiss.gpio_ctrl.modify(|_, w| {
|
||||
if level {
|
||||
w.outover().high()
|
||||
} else {
|
||||
w.outover().low()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[link_section = ".data.ram_func"]
|
||||
#[inline(never)]
|
||||
unsafe fn do_flash_cmd(txrxbuf: &mut [u8]) {
|
||||
// Load important addresses to the stack
|
||||
let connect_internal_flash = rp2040_hal::rom_data::connect_internal_flash;
|
||||
let flash_exit_xip = rp2040_hal::rom_data::flash_exit_xip;
|
||||
let flash_flush_cache = rp2040_hal::rom_data::flash_flush_cache;
|
||||
|
||||
let mut boot2: core::mem::MaybeUninit<[u8; 256]> = core::mem::MaybeUninit::uninit();
|
||||
|
||||
let xip_base = 0x10000000 as *const u32;
|
||||
rp2040_hal::rom_data::memcpy(boot2.as_mut_ptr() as _, xip_base as _, 256);
|
||||
|
||||
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
connect_internal_flash();
|
||||
flash_exit_xip();
|
||||
|
||||
set_cs(false);
|
||||
|
||||
let ssi = &*XIP_SSI::ptr();
|
||||
|
||||
for b in txrxbuf {
|
||||
while !ssi.sr.read().tfnf().bit_is_set() {}
|
||||
ssi.dr0.write(|w| w.dr().bits(*b as _));
|
||||
|
||||
while !ssi.sr.read().rfne().bit_is_set() {}
|
||||
*b = ssi.dr0.read().dr().bits() as _;
|
||||
}
|
||||
|
||||
set_cs(true);
|
||||
|
||||
flash_flush_cache();
|
||||
|
||||
let ptr = (boot2.as_mut_ptr() as *const u8).add(1) as *const ();
|
||||
let start: extern "C" fn() = core::mem::transmute(ptr);
|
||||
start();
|
||||
}
|
||||
|
||||
pub fn read_uid() -> [u8; 8] {
|
||||
const FLASH_RUID_CMD: u8 = 0x4b;
|
||||
const FLASH_RUID_DUMMY_BYTES: usize = 4;
|
||||
const FLASH_RUID_DATA_BYTES: usize = 8;
|
||||
const FLASH_RUID_TOTAL_BYTES: usize = 1 + FLASH_RUID_DUMMY_BYTES + FLASH_RUID_DATA_BYTES;
|
||||
|
||||
let mut buf = [0; FLASH_RUID_TOTAL_BYTES];
|
||||
buf[0] = FLASH_RUID_CMD;
|
||||
|
||||
unsafe {
|
||||
do_flash_cmd(&mut buf);
|
||||
}
|
||||
|
||||
buf[FLASH_RUID_DUMMY_BYTES + 1..].try_into().unwrap()
|
||||
}
|
216
pico/src/main.rs
Normal file
216
pico/src/main.rs
Normal file
|
@ -0,0 +1,216 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use panic_halt as _;
|
||||
|
||||
use common::{handle_input, Handshake, UnsafeSync};
|
||||
use core::cell::RefCell;
|
||||
use cortex_m::{asm::delay as cycle_delay, interrupt::Mutex, peripheral::NVIC};
|
||||
use once_cell::unsync::OnceCell;
|
||||
use rp2040_hal::{
|
||||
pac::{interrupt, Interrupt, Peripherals},
|
||||
usb::UsbBus,
|
||||
Sio, Watchdog,
|
||||
};
|
||||
use usb_device::{class_prelude::*, prelude::*};
|
||||
use usbd_serial::{SerialPort, USB_CLASS_CDC};
|
||||
|
||||
mod bsp;
|
||||
mod buttons;
|
||||
mod device_signature;
|
||||
|
||||
use bsp::{entry, Pins};
|
||||
use buttons::Buttons;
|
||||
|
||||
static USB_ALLOCATOR: UnsafeSync<OnceCell<UsbBusAllocator<UsbBus>>> =
|
||||
UnsafeSync::new(OnceCell::new());
|
||||
// static RTC_COUNT: Mutex<RefCell<Option<Rtc<Count32Mode>>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
static USB_BUS: Mutex<RefCell<Option<UsbDevice<UsbBus>>>> = Mutex::new(RefCell::new(None));
|
||||
static USB_SERIAL: Mutex<RefCell<Option<SerialPort<UsbBus>>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
static HANDSHAKE: Mutex<RefCell<Handshake>> = Mutex::new(RefCell::new(Handshake::new()));
|
||||
|
||||
fn get_current_time() -> u32 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn is_handshake_complete() -> bool {
|
||||
cortex_m::interrupt::free(|cs| HANDSHAKE.borrow(cs).borrow().is_complete())
|
||||
}
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let mut peripherals = Peripherals::take().unwrap();
|
||||
|
||||
let mut watchdog = Watchdog::new(peripherals.WATCHDOG);
|
||||
|
||||
let clocks = rp2040_hal::clocks::init_clocks_and_plls(
|
||||
bsp::XOSC_CRYSTAL_FREQ,
|
||||
peripherals.XOSC,
|
||||
peripherals.CLOCKS,
|
||||
peripherals.PLL_SYS,
|
||||
peripherals.PLL_USB,
|
||||
&mut peripherals.RESETS,
|
||||
&mut watchdog,
|
||||
)
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
let sio = Sio::new(peripherals.SIO);
|
||||
|
||||
let pins = Pins::new(
|
||||
peripherals.IO_BANK0,
|
||||
peripherals.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut peripherals.RESETS,
|
||||
);
|
||||
|
||||
let usb_allocator = UsbBusAllocator::new(UsbBus::new(
|
||||
peripherals.USBCTRL_REGS,
|
||||
peripherals.USBCTRL_DPRAM,
|
||||
clocks.usb_clock,
|
||||
true,
|
||||
&mut peripherals.RESETS,
|
||||
));
|
||||
|
||||
// SAFETY: No interrupt will access USB_ALLOCATOR before this point, since it is only
|
||||
// referenced from inside the USB_SERIAL mutex and the USB_BUS mutex, which have not been set
|
||||
// yet.
|
||||
//
|
||||
// SAFETY: This is the only line of the program that modifies USB_ALLOCATOR
|
||||
let allocator = unsafe {
|
||||
USB_ALLOCATOR.get().set(usb_allocator).ok().unwrap();
|
||||
USB_ALLOCATOR.get().get().unwrap()
|
||||
};
|
||||
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let serial = USB_SERIAL.borrow(cs);
|
||||
let mut serial = serial.borrow_mut();
|
||||
*serial = Some(SerialPort::new(allocator));
|
||||
});
|
||||
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let bus = USB_BUS.borrow(cs);
|
||||
let mut bus = bus.borrow_mut();
|
||||
*bus = Some(
|
||||
UsbDeviceBuilder::new(allocator, UsbVidPid(0x16c0, 0x27dd))
|
||||
.manufacturer("Aode Lion")
|
||||
.product("Pico Streamdeck")
|
||||
.serial_number("AAAB")
|
||||
.device_class(USB_CLASS_CDC)
|
||||
.build(),
|
||||
);
|
||||
});
|
||||
|
||||
unsafe {
|
||||
NVIC::unmask(Interrupt::USBCTRL_IRQ);
|
||||
}
|
||||
|
||||
let mut buttons = Buttons {
|
||||
d0: pins.gpio0,
|
||||
d1: pins.gpio1,
|
||||
d2: pins.gpio2,
|
||||
d3: pins.gpio3,
|
||||
d4: pins.gpio4,
|
||||
}
|
||||
.init();
|
||||
|
||||
loop {
|
||||
let current_time = get_current_time();
|
||||
|
||||
if !is_handshake_complete() {
|
||||
cycle_delay(1024 * 15);
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(byte) = buttons.tick(current_time) {
|
||||
let _ = cortex_m::interrupt::free(|cs| {
|
||||
let mut serial = USB_SERIAL.borrow(cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
let _ = serial.write(&[byte])?;
|
||||
serial.flush()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[interrupt]
|
||||
fn USBCTRL_IRQ() {
|
||||
poll_usb();
|
||||
}
|
||||
|
||||
fn poll_usb() -> Option<()> {
|
||||
let ready = cortex_m::interrupt::free(|cs1| {
|
||||
cortex_m::interrupt::free(|cs2| {
|
||||
let mut usb_dev = USB_BUS.borrow(cs1).borrow_mut();
|
||||
let usb_dev = usb_dev.as_mut()?;
|
||||
let mut serial = USB_SERIAL.borrow(cs2).borrow_mut();
|
||||
let serial = serial.as_mut()?;
|
||||
|
||||
Some(usb_dev.poll(&mut [&mut *serial]))
|
||||
})
|
||||
})?;
|
||||
|
||||
if !ready {
|
||||
return Some(());
|
||||
}
|
||||
|
||||
let mut input = [0u8; 32];
|
||||
|
||||
let count = cortex_m::interrupt::free(|cs| {
|
||||
USB_SERIAL
|
||||
.borrow(cs)
|
||||
.borrow_mut()
|
||||
.as_mut()?
|
||||
.read(&mut input)
|
||||
.ok()
|
||||
})?;
|
||||
|
||||
let current_time = get_current_time();
|
||||
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let mut handshake = HANDSHAKE.borrow(cs).borrow_mut();
|
||||
|
||||
if count == 32 && handshake.perform(&input, current_time, &mut Device)? {
|
||||
return None;
|
||||
}
|
||||
|
||||
let is_complete = handshake.is_complete();
|
||||
if !is_complete {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(())
|
||||
})?;
|
||||
|
||||
handle_input(&mut Device, &input, count)?;
|
||||
Some(())
|
||||
}
|
||||
|
||||
struct Device;
|
||||
|
||||
impl common::Device<8, 1> for Device {
|
||||
fn serial_number(&mut self) -> [u8; 8] {
|
||||
device_signature::read_uid()
|
||||
}
|
||||
|
||||
fn write(&mut self, bytes: &[u8]) -> Option<()> {
|
||||
cortex_m::interrupt::free(|cs| {
|
||||
let mut serial = USB_SERIAL.borrow(cs).borrow_mut();
|
||||
let serial = serial.as_mut()?;
|
||||
serial.write(bytes).ok()?;
|
||||
serial.flush().ok()
|
||||
})
|
||||
}
|
||||
|
||||
fn extras() -> [(&'static str, &'static str); 1] {
|
||||
[("version", env!("FIRMWARE_VERSION"))]
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
cortex_m::interrupt::disable();
|
||||
rp2040_hal::rom_data::reset_to_usb_boot(0, 0);
|
||||
}
|
||||
}
|
37
trinket/Cargo.toml
Normal file
37
trinket/Cargo.toml
Normal file
|
@ -0,0 +1,37 @@
|
|||
[package]
|
||||
authors = ["asonix <asonix@asonix.dog>"]
|
||||
edition = "2021"
|
||||
readme = "../README.md"
|
||||
name = "trinket-streamdeck"
|
||||
version = "0.1.0"
|
||||
build = "src/build.rs"
|
||||
|
||||
[dependencies]
|
||||
apa102-spi = "0.3.2"
|
||||
atsamd-hal = { version = "0.14", default-features = false, features = [
|
||||
"samd21e",
|
||||
"samd21e-rt",
|
||||
"unproven",
|
||||
"usb",
|
||||
] }
|
||||
bitbang-hal = "0.3.2"
|
||||
common = { version = "0.1.0", path = "../common" }
|
||||
cortex-m = "0.7.4"
|
||||
cortex-m-rt = "0.7.1"
|
||||
cortex-m-semihosting = "0.3.3"
|
||||
embedded-hal = "0.2"
|
||||
once_cell = { version = "1.7.2", default-features = false }
|
||||
panic-halt = "0.2.0"
|
||||
smart-leds = "0.3"
|
||||
usb-device = "0.2"
|
||||
usbd-serial = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1.0"
|
||||
toml = "0.5.8"
|
||||
|
||||
# this lets you use `cargo fix`!
|
||||
[[bin]]
|
||||
name = "trinket-streamdeck"
|
||||
test = false
|
||||
bench = false
|
60
trinket/src/build.rs
Normal file
60
trinket/src/build.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
use std::{fs::File, io::Read, path::Path, process::Command};
|
||||
|
||||
fn git_info() -> Option<String> {
|
||||
let mut git_string: Option<String> = None;
|
||||
|
||||
if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() {
|
||||
if output.status.success() {
|
||||
let git_hash = String::from_utf8_lossy(&output.stdout);
|
||||
git_string = Some(git_hash.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(output) = Command::new("git")
|
||||
.args(["rev-parse", "--abbrev-ref", "HEAD"])
|
||||
.output()
|
||||
{
|
||||
if output.status.success() {
|
||||
let git_branch = String::from_utf8_lossy(&output.stdout);
|
||||
if let Some(ref mut hash) = &mut git_string {
|
||||
hash.push('-');
|
||||
hash.push_str(git_branch.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
git_string
|
||||
}
|
||||
|
||||
fn version_info() -> Result<String, anyhow::Error> {
|
||||
let cargo_toml = Path::new(&std::env::var("CARGO_MANIFEST_DIR")?).join("Cargo.toml");
|
||||
|
||||
let mut file = File::open(&cargo_toml)?;
|
||||
|
||||
let mut cargo_data = String::new();
|
||||
file.read_to_string(&mut cargo_data)?;
|
||||
|
||||
let data: toml::Value = toml::from_str(&cargo_data)?;
|
||||
|
||||
let name = data["package"]["name"]
|
||||
.as_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing package name string"))?;
|
||||
let version = data["package"]["version"]
|
||||
.as_str()
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing version string"))?;
|
||||
|
||||
Ok(format!("{}-{}", name, version))
|
||||
}
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
let version = version_info()?;
|
||||
let version = if let Some(git) = git_info() {
|
||||
format!("{}-{}", version, git)
|
||||
} else {
|
||||
version
|
||||
};
|
||||
|
||||
println!("cargo:rustc-env=FIRMWARE_VERSION={}", version);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
use atsamd_hal::common::gpio::v2::{
|
||||
Disabled, Floating, Input, Pin, PullUp, PA02, PA06, PA07, PA08, PA09,
|
||||
};
|
||||
use common::{ButtonPins, ButtonState};
|
||||
use core::convert::Infallible;
|
||||
use embedded_hal::digital::v2::InputPin;
|
||||
use streamdeck_common::{ButtonPins, ButtonState};
|
||||
|
||||
pub(crate) struct Buttons {
|
||||
pub(crate) d0: Pin<PA08, Disabled<Floating>>,
|
|
@ -1,19 +1,17 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use atsamd_hal::{
|
||||
clock::{ClockGenId, ClockSource},
|
||||
rtc::{Count32Mode, Rtc},
|
||||
timer::TimerCounter,
|
||||
};
|
||||
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
|
||||
|
||||
use atsamd_hal::{
|
||||
clock::GenericClockController,
|
||||
clock::{ClockGenId, ClockSource, GenericClockController},
|
||||
pac::{interrupt, CorePeripherals, Peripherals},
|
||||
prelude::_atsamd_hal_embedded_hal_digital_v2_OutputPin,
|
||||
rtc::{Count32Mode, Rtc},
|
||||
timer::TimerCounter,
|
||||
usb::UsbBus,
|
||||
};
|
||||
use common::{handle_input, Handshake, UnsafeSync};
|
||||
use core::cell::RefCell;
|
||||
use cortex_m::{
|
||||
asm::delay as cycle_delay,
|
||||
|
@ -22,15 +20,14 @@ use cortex_m::{
|
|||
};
|
||||
use once_cell::unsync::OnceCell;
|
||||
use smart_leds::{SmartLedsWrite, RGB8};
|
||||
use streamdeck_common::{handle_input, Handshake, UnsafeSync};
|
||||
use usb_device::{bus::UsbBusAllocator, prelude::*};
|
||||
use usbd_serial::{SerialPort, USB_CLASS_CDC};
|
||||
|
||||
mod bsp;
|
||||
mod trinket_buttons;
|
||||
mod buttons;
|
||||
|
||||
use bsp::{entry, Dotstar, Pins};
|
||||
use trinket_buttons::Buttons;
|
||||
use buttons::Buttons;
|
||||
|
||||
static USB_ALLOCATOR: UnsafeSync<OnceCell<UsbBusAllocator<UsbBus>>> =
|
||||
UnsafeSync::new(OnceCell::new());
|
||||
|
@ -103,7 +100,7 @@ fn main() -> ! {
|
|||
*bus = Some(
|
||||
UsbDeviceBuilder::new(allocator, UsbVidPid(0x16c0, 0x27dd))
|
||||
.manufacturer("Aode Lion")
|
||||
.product("Streamdeck")
|
||||
.product("Trinket Streamdeck")
|
||||
.serial_number("AAAA")
|
||||
.device_class(USB_CLASS_CDC)
|
||||
.build(),
|
||||
|
@ -186,6 +183,7 @@ fn main() -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[interrupt]
|
||||
fn USB() {
|
||||
poll_usb();
|
||||
|
@ -240,7 +238,7 @@ fn poll_usb() -> Option<()> {
|
|||
|
||||
struct Device;
|
||||
|
||||
impl streamdeck_common::Device<16, 1> for Device {
|
||||
impl common::Device<16, 1> for Device {
|
||||
// section 10.3.3 of datasheet for SAMD21
|
||||
fn serial_number(&mut self) -> [u8; 16] {
|
||||
let generator: [*const [u8; 4]; 4] = [
|
Loading…
Reference in a new issue