Include firmware version in streamdeck firmware

This commit is contained in:
Aode (lion) 2021-10-02 17:02:43 -05:00
parent 9fd62972cf
commit 665019678f
6 changed files with 93 additions and 11 deletions

View file

@ -4,6 +4,7 @@ edition = "2018"
readme = "README.md"
name = "trinket-streamdeck"
version = "0.1.0"
build = "src/build.rs"
[dependencies]
atsamd-hal = "0.12"
@ -19,6 +20,10 @@ 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"

60
src/build.rs Normal file
View 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(())
}

View file

@ -201,7 +201,7 @@ fn with_op_lock(mut f: impl FnMut()) {
struct Device;
impl streamdeck_common::Device<16> for Device {
impl streamdeck_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] = [
@ -232,6 +232,10 @@ impl streamdeck_common::Device<16> for Device {
})
}
fn extras() -> [(&'static str, &'static str); 1] {
[("version", env!("FIRMWARE_VERSION"))]
}
// Based on
// - https://github.com/arduino/ArduinoCore-samd/issues/197
// - https://github.com/tinygo-org/tinygo/blob/master/src/machine/board_trinket.go

View file

@ -1,6 +1,6 @@
pub trait Device<const SN_LEN: usize> {
pub trait Device<const SN_LEN: usize, const EXTRAS_LEN: usize> {
fn serial_number(&mut self) -> [u8; SN_LEN];
fn extras() -> [(&'static str, &'static str); EXTRAS_LEN];
fn write(&mut self, bytes: &[u8]) -> Option<()>;
fn reset(&mut self);
}

View file

@ -23,14 +23,14 @@ impl Handshake {
self.step_1_complete && self.step_2_complete
}
pub fn perform<D, const SN_LEN: usize>(
pub fn perform<D, const SN_LEN: usize, const EXTRAS_LEN: usize>(
&mut self,
input: &[u8; 32],
current_time: u32,
device: &mut D,
) -> Option<bool>
where
D: Device<SN_LEN>,
D: Device<SN_LEN, EXTRAS_LEN>,
{
if self.is_complete() {
self.step_1_complete = false;
@ -60,9 +60,13 @@ impl Handshake {
Some(false)
}
fn step_1<D, const SN_LEN: usize>(&mut self, input: &[u8; 32], device: &mut D) -> Option<()>
fn step_1<D, const SN_LEN: usize, const EXTRAS_LEN: usize>(
&mut self,
input: &[u8; 32],
device: &mut D,
) -> Option<()>
where
D: Device<SN_LEN>,
D: Device<SN_LEN, EXTRAS_LEN>,
{
for ((c1, c2), out) in input[..16].iter().zip(&input[16..]).zip(&mut self.buffer) {
*out = c1 ^ c2;

View file

@ -4,13 +4,13 @@ static NAME: &'static [u8] = b"Streamdeck";
static AUTHOR: &'static [u8] = b"asonix";
static REPO: &'static [u8] = b"https://git.asonix.dog/asonix/trinket-streamdeck";
pub fn handle_input<D, const SN_LEN: usize>(
pub fn handle_input<D, const SN_LEN: usize, const EXTRAS_LEN: usize>(
device: &mut D,
input: &[u8; 32],
count: usize,
) -> Option<()>
where
D: Device<SN_LEN>,
D: Device<SN_LEN, EXTRAS_LEN>,
{
if matches(input, count, b"ident") {
let sn = device.serial_number();
@ -24,6 +24,12 @@ where
} else if matches(input, count, b"reset") {
device.reset();
} else {
for (key, value) in D::extras() {
if matches(input, count, key.as_bytes()) {
write_length_delim(device, value.as_bytes())?;
return Some(());
}
}
write_length_delim(device, &input[..count])?;
}
@ -34,9 +40,12 @@ fn matches(input: &[u8], count: usize, bytes: &'static [u8]) -> bool {
count == bytes.len() && input.starts_with(bytes)
}
fn write_length_delim<D, const SN_LEN: usize>(device: &mut D, bytes: &[u8]) -> Option<()>
fn write_length_delim<D, const SN_LEN: usize, const EXTRAS_LEN: usize>(
device: &mut D,
bytes: &[u8],
) -> Option<()>
where
D: Device<SN_LEN>,
D: Device<SN_LEN, EXTRAS_LEN>,
{
device.write(&[bytes.len() as u8])?;
device.write(bytes)