mirror of
https://github.com/fossasia/badgemagic-rs
synced 2025-07-27 05:53:57 +00:00
feat: add support for brightness control
This commit is contained in:
parent
5d745ab8fd
commit
a9b38fb427
2 changed files with 65 additions and 12 deletions
|
@ -6,7 +6,7 @@ use std::{fs, path::PathBuf};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use badgemagic::{
|
use badgemagic::{
|
||||||
ble::Device as BleDevice,
|
ble::Device as BleDevice,
|
||||||
protocol::{Mode, PayloadBuffer, Speed, Style},
|
protocol::{Brightness, Mode, PayloadBuffer, Speed, Style},
|
||||||
usb_hid::Device as UsbDevice,
|
usb_hid::Device as UsbDevice,
|
||||||
};
|
};
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
|
@ -63,6 +63,8 @@ enum TransportProtocol {
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
struct Config {
|
struct Config {
|
||||||
|
#[serde(default)]
|
||||||
|
brightness: Option<Brightness>,
|
||||||
#[serde(rename = "message")]
|
#[serde(rename = "message")]
|
||||||
messages: Vec<Message>,
|
messages: Vec<Message>,
|
||||||
}
|
}
|
||||||
|
@ -148,6 +150,7 @@ fn gnerate_payload(args: &mut Args) -> Result<PayloadBuffer> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut payload = PayloadBuffer::new();
|
let mut payload = PayloadBuffer::new();
|
||||||
|
payload.set_brightness(config.brightness.unwrap_or_default());
|
||||||
|
|
||||||
for message in config.messages {
|
for message in config.messages {
|
||||||
let mut style = Style::default();
|
let mut style = Style::default();
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
//! Protocol used to update the badge
|
//! Protocol used to update the badge
|
||||||
|
|
||||||
use std::num::TryFromIntError;
|
|
||||||
|
|
||||||
#[cfg(feature = "embedded-graphics")]
|
#[cfg(feature = "embedded-graphics")]
|
||||||
use embedded_graphics::{
|
use embedded_graphics::{
|
||||||
draw_target::DrawTarget,
|
draw_target::DrawTarget,
|
||||||
|
@ -11,6 +9,7 @@ use embedded_graphics::{
|
||||||
primitives::Rectangle,
|
primitives::Rectangle,
|
||||||
Drawable,
|
Drawable,
|
||||||
};
|
};
|
||||||
|
use std::num::TryFromIntError;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, U16};
|
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, U16};
|
||||||
|
|
||||||
|
@ -54,7 +53,7 @@ impl Style {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show a dotted border arround the display.
|
/// Show a dotted border around the display.
|
||||||
/// ```
|
/// ```
|
||||||
/// use badgemagic::protocol::Style;
|
/// use badgemagic::protocol::Style;
|
||||||
/// # (
|
/// # (
|
||||||
|
@ -161,7 +160,7 @@ impl TryFrom<u8> for Speed {
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
/// Scroll thorugh the message from left to right
|
/// Scroll through the message from left to right
|
||||||
#[default]
|
#[default]
|
||||||
Left,
|
Left,
|
||||||
|
|
||||||
|
@ -193,14 +192,47 @@ pub enum Mode {
|
||||||
Laser,
|
Laser,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Display Brightness
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||||
|
pub enum Brightness {
|
||||||
|
#[default]
|
||||||
|
Full = 0x00,
|
||||||
|
ThreeQuarters = 0x10,
|
||||||
|
Half = 0x20,
|
||||||
|
OneQuarter = 0x30,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Brightness> for u8 {
|
||||||
|
fn from(value: Brightness) -> Self {
|
||||||
|
value as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u8> for Brightness {
|
||||||
|
type Error = TryFromIntError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
0x00 => Self::Full,
|
||||||
|
0x10 => Self::ThreeQuarters,
|
||||||
|
0x20 => Self::Half,
|
||||||
|
0x30 => Self::OneQuarter,
|
||||||
|
_ => return Err(u8::try_from(-1).unwrap_err()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MSG_PADDING_ALIGN: usize = 64;
|
const MSG_PADDING_ALIGN: usize = 64;
|
||||||
|
|
||||||
const MAGIC: [u8; 6] = *b"wang\0\0";
|
const MAGIC: [u8; 5] = *b"wang\0";
|
||||||
|
|
||||||
#[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]
|
#[derive(FromBytes, IntoBytes, Immutable, KnownLayout)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Header {
|
struct Header {
|
||||||
magic: [u8; 6],
|
magic: [u8; 5],
|
||||||
|
brightness: u8,
|
||||||
blink: u8,
|
blink: u8,
|
||||||
border: u8,
|
border: u8,
|
||||||
speed_and_mode: [u8; 8],
|
speed_and_mode: [u8; 8],
|
||||||
|
@ -241,7 +273,7 @@ impl Timestamp {
|
||||||
|
|
||||||
/// Buffer to create a payload
|
/// Buffer to create a payload
|
||||||
///
|
///
|
||||||
/// A payload consits of up to 8 messages
|
/// A payload consists of up to 8 messages
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[cfg(feature = "embedded-graphics")]
|
/// # #[cfg(feature = "embedded-graphics")]
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
|
@ -252,7 +284,7 @@ impl Timestamp {
|
||||||
/// primitives::{PrimitiveStyle, Rectangle, Styled},
|
/// primitives::{PrimitiveStyle, Rectangle, Styled},
|
||||||
/// };
|
/// };
|
||||||
///
|
///
|
||||||
/// let mut buffer = PayloadBuffer::new();
|
/// let mut buffer = PayloadBuffer::default();
|
||||||
/// buffer.add_message_drawable(
|
/// buffer.add_message_drawable(
|
||||||
/// Style::default(),
|
/// Style::default(),
|
||||||
/// &Styled::new(
|
/// &Styled::new(
|
||||||
|
@ -283,6 +315,7 @@ impl PayloadBuffer {
|
||||||
num_messages: 0,
|
num_messages: 0,
|
||||||
data: Header {
|
data: Header {
|
||||||
magic: MAGIC,
|
magic: MAGIC,
|
||||||
|
brightness: 0,
|
||||||
blink: 0,
|
blink: 0,
|
||||||
border: 0,
|
border: 0,
|
||||||
speed_and_mode: [0; 8],
|
speed_and_mode: [0; 8],
|
||||||
|
@ -300,6 +333,10 @@ impl PayloadBuffer {
|
||||||
Header::mut_from_prefix(&mut self.data).unwrap().0
|
Header::mut_from_prefix(&mut self.data).unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_brightness(&mut self, brightness: Brightness) {
|
||||||
|
self.header_mut().brightness = brightness.into();
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the current number of messages
|
/// Return the current number of messages
|
||||||
pub fn num_messages(&mut self) -> usize {
|
pub fn num_messages(&mut self) -> usize {
|
||||||
self.num_messages as usize
|
self.num_messages as usize
|
||||||
|
@ -368,7 +405,7 @@ impl PayloadBuffer {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the payload buffe into bytes (with padding)
|
/// Convert the payload buffer into bytes (with padding)
|
||||||
#[allow(clippy::missing_panics_doc)] // should never panic
|
#[allow(clippy::missing_panics_doc)] // should never panic
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_padded_bytes(self) -> impl AsRef<[u8]> {
|
pub fn into_padded_bytes(self) -> impl AsRef<[u8]> {
|
||||||
|
@ -484,10 +521,9 @@ impl DrawTarget for MessageBuffer<'_> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::{Brightness, Speed};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use super::Speed;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn speed_to_u8_and_back() {
|
fn speed_to_u8_and_back() {
|
||||||
const VALID_SPEED_VALUES: Range<u8> = 1..8;
|
const VALID_SPEED_VALUES: Range<u8> = 1..8;
|
||||||
|
@ -499,4 +535,18 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn brightness_to_u8() {
|
||||||
|
const VALID_BRIGHTNESS_VALUES: [(Brightness, u8); 4] = [
|
||||||
|
(Brightness::Full, 0x00),
|
||||||
|
(Brightness::ThreeQuarters, 0x10),
|
||||||
|
(Brightness::Half, 0x20),
|
||||||
|
(Brightness::OneQuarter, 0x30),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (value, raw) in VALID_BRIGHTNESS_VALUES {
|
||||||
|
assert_eq!(u8::from(value), raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue