Skip to content
This repository was archived by the owner on Mar 31, 2025. It is now read-only.

Commit 244eae5

Browse files
committed
load images over serial
1 parent 4fbff60 commit 244eae5

9 files changed

Lines changed: 292 additions & 106 deletions

File tree

firmware/src/main.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,14 @@ type UpdateTrigger = Mutex<2, bool>;
126126
type IdentifyTrigger = Mutex<3, bool>;
127127
type RgbControls = Mutex<4, (bool, RgbProfile)>; // (changed, settings)
128128
type ConnectionStatus = Mutex<5, Connection>;
129-
type Icons = Mutex<6, [[u16; 32 * 32]; 12]>;
129+
type Icons = Mutex<6, [(bool, [u16; 32 * 32]); 12]>;
130130

131131
static CONNECTION_STATUS: ConnectionStatus = Mutex::new(Connection::NotConnected(true));
132132
static PERIPHERAL_INPUTS: PeripheralInputs = Mutex::new(inputs_default());
133133
static UPDATE_TRIGGER: UpdateTrigger = Mutex::new(false);
134134
static IDENTIFY_TRIGGER: IdentifyTrigger = Mutex::new(false);
135135
static RGB_CONTROLS: RgbControls = Mutex::new((false, RgbProfile::default_device_profile()));
136-
static ICONS: Icons = Mutex::new([[0; 32 * 32]; 12]);
136+
static ICONS: Icons = Mutex::new([(false, [0; 32 * 32]); 12]);
137137

138138
fn time_func(t: &Timer, mut f: impl FnMut() -> ()) -> Duration<u64, 1, 1000000> {
139139
let s = t.get_counter();
@@ -150,11 +150,12 @@ fn reset_icons() {
150150
let mut x = 0;
151151
while x < 32 {
152152
// TODO: use dma to swap out the icons
153-
icons[i][32 * y + x] = !DEFAULT_ICONS[i][32 * y + x];
153+
icons[i].1[32 * y + x] = !DEFAULT_ICONS[i][32 * y + x];
154154
x += 1;
155155
}
156156
y += 1;
157157
}
158+
icons[i].0 = true;
158159
i += 1;
159160
}
160161
});
@@ -254,6 +255,7 @@ fn main() -> ! {
254255
&UPDATE_TRIGGER,
255256
&IDENTIFY_TRIGGER,
256257
&RGB_CONTROLS,
258+
&ICONS,
257259
);
258260

259261
// core 1 event loop (GPIO)

firmware/src/modules/screen.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl ScreenMod {
163163
return self;
164164
}
165165

166-
let elapse_clear_fb = time_func(t, || {
166+
let _elapse_clear_fb = time_func(t, || {
167167
// // using multiple channels did not meaningfully improve performance.
168168
// self.dma_ch0 = {
169169
// let (dma_ch0, _, _) =
@@ -174,40 +174,42 @@ impl ScreenMod {
174174
// };
175175
});
176176

177-
let elapse_draw_icons = time_func(t, || {
178-
self.icons.with_lock(|i| {
177+
let _elapse_draw_icons = time_func(t, || {
178+
self.icons.with_mut_lock(|i| {
179179
for y in 0..3 {
180180
for x in 0..4 {
181181
let idx = y * 4 + x;
182182

183-
if self.keys_status[idx] == self.keys_previous_frame[idx] {
183+
if self.keys_status[idx] == self.keys_previous_frame[idx] && !i[idx].0 {
184184
continue;
185185
}
186186

187187
self.draw_icon(
188-
&i[idx],
188+
&i[idx].1,
189189
self.keys_status[idx],
190190
4 + (64 + 6) * y,
191191
23 + (64 + 6) * x,
192192
);
193+
194+
i[idx].0 = false;
193195
}
194196
}
195197
});
196198
});
197199

198-
let elapse_push_fb = time_func(t, || {
200+
let _elapse_push_fb = time_func(t, || {
199201
#[allow(static_mut_refs)]
200202
self.st.push_framebuffer(unsafe { &FBDATA });
201203
self.st.backlight_on();
202204
});
203205

204-
info!(
205-
"times:\nclear-fb={}us\ndraw-icons={}us\npush-fb={}us\ntotal={}",
206-
elapse_clear_fb.to_micros(),
207-
elapse_draw_icons.to_micros(),
208-
elapse_push_fb.to_micros(),
209-
(elapse_clear_fb + elapse_draw_icons + elapse_push_fb).to_micros()
210-
);
206+
// info!(
207+
// "times:\nclear-fb={}us\ndraw-icons={}us\npush-fb={}us\ntotal={}",
208+
// _elapse_clear_fb.to_micros(),
209+
// _elapse_draw_icons.to_micros(),
210+
// _elapse_push_fb.to_micros(),
211+
// (_elapse_clear_fb + _elapse_draw_icons + _elapse_push_fb).to_micros()
212+
// );
211213

212214
self.keys_previous_frame = self.keys_status;
213215
for k in self.keys_status.iter_mut() {

firmware/src/modules/serial.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ use rp2040_hal::{fugit::ExtU32, timer::CountDown, usb::UsbBus};
2020
use usbd_serial::SerialPort;
2121

2222
use crate::{
23-
inputs_default, modules::rgb::DEFAULT_RGB, reset_icons, ConnectionStatus, IdentifyTrigger,
24-
PeripheralInputs, RgbControls, UpdateTrigger,
23+
inputs_default, modules::rgb::DEFAULT_RGB, reset_icons, ConnectionStatus, Icons,
24+
IdentifyTrigger, PeripheralInputs, RgbControls, UpdateTrigger,
2525
};
2626

27-
const BUFFER_SIZE: usize = 2048;
27+
const BUFFER_SIZE: usize = 4096;
2828

2929
const KEEPALIVE: u32 = 500;
3030

@@ -38,6 +38,7 @@ pub struct SerialMod {
3838
update_trigger: &'static UpdateTrigger,
3939
identify_trigger: &'static IdentifyTrigger,
4040
rgb_controls: &'static RgbControls,
41+
icons: &'static Icons,
4142
}
4243

4344
impl SerialMod {
@@ -48,6 +49,7 @@ impl SerialMod {
4849
update_trigger: &'static UpdateTrigger,
4950
identify_trigger: &'static IdentifyTrigger,
5051
rgb_controls: &'static RgbControls,
52+
icons: &'static Icons,
5153
) -> Self {
5254
keepalive_timer.start(KEEPALIVE.millis());
5355

@@ -60,6 +62,7 @@ impl SerialMod {
6062
update_trigger,
6163
identify_trigger,
6264
rgb_controls,
65+
icons,
6366
}
6467
}
6568

@@ -256,7 +259,25 @@ impl SerialMod {
256259
}
257260
Command::SetScrIcon => {
258261
// TODO:
259-
unknown()
262+
263+
let slot = data[0];
264+
let new_icon = &data[1..32 * 32 * 2 + 1];
265+
266+
self.icons.with_mut_lock(|icons| {
267+
let scr_icon = &mut icons[slot as usize];
268+
let mut i = 0;
269+
while i < 32 * 32 {
270+
scr_icon.1[i] =
271+
((new_icon[i * 2 + 1] as u16) << 8) | (new_icon[i * 2] as u16);
272+
i += 1;
273+
}
274+
scr_icon.0 = true;
275+
});
276+
277+
Self::send(serial, b"001");
278+
Self::send(serial, &[RSP_ACK]);
279+
280+
true
260281
}
261282
Command::Identify => {
262283
// TODO: flash led for identifying

software/jukebox_util/src/protocol.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl Command {
4444
CMD_GREET => Self::Greeting,
4545
CMD_GET_INPUT_KEYS => Self::GetInputKeys,
4646
CMD_SET_RGB_MODE => Self::SetRgbMode,
47-
CMD_SET_SCR_ICON => Self::SetScrMode,
47+
CMD_SET_SCR_ICON => Self::SetScrIcon,
4848
CMD_SET_SCR_MODE => Self::SetScrMode,
4949
CMD_IDENTIFY => Self::Identify,
5050
CMD_UPDATE => Self::Update,
@@ -79,7 +79,7 @@ fn decode_size_digit(w: u8) -> usize {
7979
b'E' => 0xE,
8080
b'f' => 0xF,
8181
b'F' => 0xF,
82-
_ => panic!("cannot decode digit"),
82+
_ => panic!("cannot decode digit {}", w),
8383
}
8484
}
8585

@@ -101,7 +101,7 @@ fn encode_size_digit(w: usize) -> u8 {
101101
0xD => b'D',
102102
0xE => b'E',
103103
0xF => b'F',
104-
_ => panic!("cannot encode digit"),
104+
_ => panic!("cannot encode digit {}", w),
105105
}
106106
}
107107

software/src/actions/action.rs

Lines changed: 76 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@ use std::{
77

88
use anyhow::Result;
99
use futures::future::join_all;
10+
use jukebox_util::{color::RgbProfile, peripheral::DeviceType};
1011
use tokio::sync::{
1112
mpsc::{UnboundedReceiver, UnboundedSender},
1213
Mutex,
1314
};
1415

1516
use crate::{
16-
config::JukeBoxConfig,
17+
config::{ActionConfig, JukeBoxConfig},
1718
input::InputKey,
1819
serial::{SerialCommand, SerialEvent},
1920
};
2021

22+
use super::types::get_icon_bytes;
23+
2124
pub async fn action_task(
2225
mut s_evnt_rx: UnboundedReceiver<SerialEvent>,
2326
config: Arc<Mutex<JukeBoxConfig>>,
@@ -44,9 +47,60 @@ pub async fn action_task(
4447
.and_then(|p| Some((p.key_map, p.rgb_profile)))
4548
.unwrap_or((HashMap::new(), None));
4649

47-
(profile, rgb, c.current_profile.clone()) // TODO: add hardware input info
50+
let device_type = c
51+
.devices
52+
.get(device_uid)
53+
.and_then(|d| Some(d.0))
54+
.unwrap()
55+
.clone();
56+
57+
(device_type, profile, rgb, c.current_profile.clone()) // TODO: add hardware input info
4858
};
4959

60+
let update_device_configs =
61+
async |scmd_txs: Arc<Mutex<HashMap<String, UnboundedSender<SerialCommand>>>>,
62+
device_uid: &String,
63+
device_type: DeviceType,
64+
keys: HashMap<InputKey, ActionConfig>,
65+
rgb_profile: RgbProfile| {
66+
let txs = scmd_txs.lock().await;
67+
let tx = if let Some(tx) = txs.get(device_uid) {
68+
tx
69+
} else {
70+
return;
71+
};
72+
73+
if device_type == DeviceType::KeyPad {
74+
// send rgb profile
75+
let _ = tx.send(SerialCommand::SetRgbMode(rgb_profile));
76+
77+
// set icons on screen
78+
let slots = [
79+
InputKey::KeySwitch1,
80+
InputKey::KeySwitch2,
81+
InputKey::KeySwitch3,
82+
InputKey::KeySwitch4,
83+
InputKey::KeySwitch5,
84+
InputKey::KeySwitch6,
85+
InputKey::KeySwitch7,
86+
InputKey::KeySwitch8,
87+
InputKey::KeySwitch9,
88+
InputKey::KeySwitch10,
89+
InputKey::KeySwitch11,
90+
InputKey::KeySwitch12,
91+
];
92+
93+
for (i, k) in slots.iter().enumerate() {
94+
if let Some(a) = keys.get(k) {
95+
let bytes = get_icon_bytes(a.action.icon_source());
96+
let _ = tx.send(SerialCommand::SetScrIcon(i as u8, bytes));
97+
}
98+
}
99+
}
100+
101+
// TODO: set hardware inputs here
102+
};
103+
50104
while let Some(evnt) = s_evnt_rx.recv().await {
51105
match evnt {
52106
SerialEvent::Connected { device_info } => {
@@ -55,13 +109,16 @@ pub async fn action_task(
55109
clear_set(&mut prevkeys, device_uid).await;
56110

57111
// TODO: set hardware inputs here
58-
let (_, current_rgb_profile, _) = get_profile_info(&config, device_uid).await;
59-
let rgb_profile =
60-
current_rgb_profile.unwrap_or(jukebox_util::color::RgbProfile::Off);
61-
let txs = scmd_txs.lock().await;
62-
let _ = txs
63-
.get(device_uid)
64-
.and_then(|t| Some(t.send(SerialCommand::SetRgbMode(rgb_profile))));
112+
let (device_type, keys, rgb_profile, _) =
113+
get_profile_info(&config, device_uid).await;
114+
update_device_configs(
115+
scmd_txs.clone(),
116+
device_uid,
117+
device_type,
118+
keys,
119+
rgb_profile.unwrap_or(RgbProfile::default_gui_profile()),
120+
)
121+
.await;
65122
}
66123
SerialEvent::GetInputKeys { device_uid, keys } => {
67124
if !prevkeys.contains_key(&device_uid) {
@@ -73,7 +130,7 @@ pub async fn action_task(
73130
let scmd_txs = scmd_txs.clone();
74131

75132
tokio::spawn(async move {
76-
let (current_profile, _, current_profile_name) =
133+
let (_, current_profile, _, current_profile_name) =
77134
get_profile_info(&config, &device_uid).await;
78135

79136
let mut prevkeys = prevkeys.lock().await;
@@ -101,22 +158,18 @@ pub async fn action_task(
101158

102159
*prevkeys = keys;
103160

104-
let (_, new_rgb_profile, new_profile_name) =
161+
let (device_type, new_keys, new_rgb_profile, new_profile_name) =
105162
get_profile_info(&config, &device_uid).await;
106163

107164
if current_profile_name != new_profile_name {
108-
let rgb_profile =
109-
new_rgb_profile.unwrap_or(jukebox_util::color::RgbProfile::Off);
110-
let txs = scmd_txs.lock().await;
111-
let tx = if let Some(tx) = txs.get(&device_uid) {
112-
tx
113-
} else {
114-
return;
115-
};
116-
117-
let _ = tx.send(SerialCommand::SetRgbMode(rgb_profile));
118-
119-
// TODO: set hardware inputs here
165+
update_device_configs(
166+
scmd_txs.clone(),
167+
&device_uid,
168+
device_type,
169+
new_keys,
170+
new_rgb_profile.unwrap_or(RgbProfile::default_gui_profile()),
171+
)
172+
.await;
120173
}
121174
});
122175
}

software/src/actions/types.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use std::{collections::HashMap, sync::Arc};
44

55
use anyhow::Result;
66
use dyn_clone::{clone_trait_object, DynClone};
7-
use eframe::egui::{vec2, Image, ImageSource, TextureFilter, TextureOptions, TextureWrapMode, Ui};
7+
use eframe::egui::{
8+
load::Bytes, vec2, Image, ImageSource, TextureFilter, TextureOptions, TextureWrapMode, Ui,
9+
};
810
use jukebox_util::peripheral::DeviceType;
911
use tokio::sync::Mutex;
1012

@@ -149,3 +151,25 @@ impl ActionMap {
149151
c
150152
}
151153
}
154+
155+
pub fn get_icon_bytes(icon_source: ImageSource) -> [u8; 32 * 32 * 2] {
156+
let b = match icon_source {
157+
ImageSource::Uri(_) => panic!(),
158+
ImageSource::Texture(_) => panic!(),
159+
ImageSource::Bytes { uri: _, bytes } => match bytes {
160+
Bytes::Static(items) => items,
161+
Bytes::Shared(items) => &items.clone(),
162+
},
163+
};
164+
165+
let (_, b) = b.split_at(0x7A);
166+
167+
if b.len() != (32 * 32 * 2) {
168+
panic!();
169+
}
170+
171+
let mut bytes = [0u8; 32 * 32 * 2];
172+
bytes.copy_from_slice(b);
173+
174+
bytes
175+
}

0 commit comments

Comments
 (0)