rgb_led/
lib.rs

1// SPDX-FileCopyrightText: 2024 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3pub mod messages;
4
5use std::time::Duration;
6
7use server::{CheckedConn, CheckedPermissions, MessageAllowed};
8
9use crate::messages::*;
10
11#[macro_export]
12macro_rules! use_api {
13    () => {
14        mod rgb_permissions {
15            use $crate::messages::*;
16            #[derive(Clone, Default, server::Permissions)]
17            #[server_name = "os/rgb-server"]
18            pub struct RgbPermissions;
19        }
20        type RgbApi = $crate::RgbApi<rgb_permissions::RgbPermissions>;
21    };
22}
23
24#[derive(Default)]
25pub struct RgbApi<P: CheckedPermissions> {
26    conn: CheckedConn<P>,
27}
28
29impl<P: CheckedPermissions> RgbApi<P> {
30    pub fn try_new_with_timeout(timeout: Duration) -> Option<Self> {
31        Some(Self { conn: CheckedConn::try_connect_with_timeout(timeout)? })
32    }
33
34    pub fn set_all_to(&self, color: RgbColor)
35    where
36        P: MessageAllowed<SetAllTo>,
37    {
38        self.conn.try_send_scalar(SetAllTo(color)).ok();
39    }
40
41    pub fn set_to(&self, index: u32, color: RgbColor)
42    where
43        P: MessageAllowed<SetTo>,
44    {
45        self.conn.try_send_scalar(SetTo(index, color)).ok();
46    }
47
48    pub fn animate_all(&self, animation: RgbAnimation)
49    where
50        P: MessageAllowed<AnimateAllTo>,
51    {
52        self.conn.try_send_scalar(AnimateAllTo(animation)).ok();
53    }
54
55    #[cfg(not(keyos))]
56    pub fn subscribe_color_updates<S>(&self, context: &mut server::ServerContext<S>)
57    where
58        P: MessageAllowed<messages::SubscribeColorUpdates>,
59        S: server::Server + server::ScalarEventHandler<RgbColor>,
60    {
61        self.conn.subscribe_scalar_infallible(messages::SubscribeColorUpdates, context);
62    }
63}
64
65#[derive(Debug, Copy, Clone, PartialEq)]
66pub struct RgbColor {
67    pub r: u8,
68    pub g: u8,
69    pub b: u8,
70}
71
72impl From<u32> for RgbColor {
73    fn from(value: u32) -> Self {
74        let [r, g, b, _] = value.to_le_bytes();
75        Self { r, g, b }
76    }
77}
78
79impl From<RgbColor> for u32 {
80    fn from(value: RgbColor) -> Self {
81        let arr = [value.r, value.g, value.b, 0];
82        Self::from_le_bytes(arr)
83    }
84}
85
86impl RgbColor {
87    pub const BLACK: RgbColor = RgbColor { r: 0, g: 0, b: 0 };
88    pub const RED: RgbColor = RgbColor { r: 0xff, g: 0x00, b: 0x00 };
89    pub const TEAL: RgbColor = RgbColor { r: 0x00, g: 0x9d, b: 0xb9 };
90    pub const WHITE: RgbColor = RgbColor { r: 0xff, g: 0xff, b: 0xff };
91
92    pub const fn new(r: u8, g: u8, b: u8) -> Self { RgbColor { r, g, b } }
93
94    pub fn lerp(self, other: Self, ratio: f32) -> Self {
95        Self {
96            r: (self.r as f32 + (other.r as f32 - self.r as f32) * ratio).round() as u8,
97            g: (self.g as f32 + (other.g as f32 - self.g as f32) * ratio).round() as u8,
98            b: (self.b as f32 + (other.b as f32 - self.b as f32) * ratio).round() as u8,
99        }
100    }
101
102    pub fn scale(self, ratio: f32) -> Self {
103        Self {
104            r: (self.r as f32 * ratio).round() as u8,
105            g: (self.g as f32 * ratio).round() as u8,
106            b: (self.b as f32 * ratio).round() as u8,
107        }
108    }
109}
110
111#[derive(Debug, Copy, Clone)]
112pub struct RgbAnimation {
113    pub from: RgbColor,
114    pub to: RgbColor,
115    pub duration_ms: usize,
116    pub reset: bool,
117}
118
119impl RgbAnimation {
120    pub const fn new(from: RgbColor, to: RgbColor, duration_ms: usize, reset: bool) -> Self {
121        Self { from, to, duration_ms, reset }
122    }
123}