Reduce and calibrate RAM usage in firmware

This commit is contained in:
daylily
2026-01-10 13:10:15 +08:00
parent 5d3f7f14ac
commit 6469cffef4
3 changed files with 27 additions and 54 deletions
+27 -52
View File
@@ -1,5 +1,3 @@
use core::cmp::Ordering;
use crate::{ use crate::{
epd::Epd, epd::Epd,
midi::UsbMidi, midi::UsbMidi,
@@ -34,7 +32,6 @@ enum Request<'a> {
UpdateDisplay, UpdateDisplay,
SetPattern { SetPattern {
from: u32, from: u32,
to: u32,
chroma: Chroma, chroma: Chroma,
pattern: &'a [u8], pattern: &'a [u8],
}, },
@@ -58,7 +55,7 @@ pub async fn app_task(epd: Epd, midi: UsbMidi) {
App { App {
epd, epd,
midi, midi,
pattern: [0; PATTERN_SIZE], display: Display1in54::default(),
} }
.run() .run()
.await .await
@@ -67,7 +64,7 @@ pub async fn app_task(epd: Epd, midi: UsbMidi) {
struct App { struct App {
epd: Epd, epd: Epd,
midi: UsbMidi, midi: UsbMidi,
pattern: [u8; PATTERN_SIZE], display: Display1in54,
} }
impl App { impl App {
@@ -75,69 +72,45 @@ impl App {
match req { match req {
Request::SetPattern { Request::SetPattern {
from, from,
to,
chroma, chroma,
pattern, pattern,
} => self.handle_set_pattern(from, to, chroma, pattern).await, } => self.handle_set_pattern(from, chroma, pattern).await,
Request::UpdateDisplay => self.handle_update_display().await, Request::UpdateDisplay => self.handle_update_display().await,
Request::GetIdentification => self.handle_get_identification().await, Request::GetIdentification => self.handle_get_identification().await,
Request::Ping => self.write_response(Response::Ping).await, Request::Ping => self.write_response(Response::Ping).await,
} }
} }
async fn handle_set_pattern(&mut self, from: u32, to: u32, _chroma: Chroma, pattern: &[u8]) { async fn handle_set_pattern(&mut self, from: u32, _chroma: Chroma, pattern: &[u8]) {
let from = from as usize; let from = from as usize;
let to = to as usize; let buffer_len = (self.display.size().width * self.display.size().height) as usize;
if from >= PATTERN_SIZE || to > PATTERN_SIZE || from > to {
if from >= PATTERN_SIZE || from + pattern.len() > buffer_len {
warn!( warn!(
"SetPattern: 'from' and/or 'to' out of range (from = {}, to = {}, PATTERN_SIZE = {})", "SetPattern: specified [{}, {}) is out of range (len = {})",
from, to, PATTERN_SIZE from,
from + pattern.len(),
pattern.len(),
); );
return; return;
} }
let buf_size = match pattern.len().cmp(&(to - from)) { let width = self.display.size().width as i32;
Ordering::Less => { for (stride, &byte) in pattern.iter().enumerate() {
warn!( for stroll in 0..8 {
"SetPattern buffer too short (buf_size = {}, range_size = {})", let bit_ix = (from + stride) as i32 * 8 + stroll;
pattern.len(), let x = bit_ix % width;
to - from, let y = bit_ix / width;
); self.display
pattern.len() .set_pixel(Pixel(Point { x, y }, color_at(byte, stroll)));
} }
Ordering::Equal => pattern.len(),
Ordering::Greater => {
warn!(
"SetPattern buffer too long; truncating (buf_size = {}, range_size = {})",
pattern.len(),
to - from,
);
to - from
}
};
for (stride, &byte) in pattern[..buf_size].iter().enumerate() {
self.pattern[from + stride] = byte;
} }
self.write_response(Response::SetPattern).await; self.write_response(Response::SetPattern).await;
} }
async fn handle_update_display(&mut self) { async fn handle_update_display(&mut self) {
let mut display = Display1in54::default(); self.epd.update_display(&self.display);
display.set_rotation(DisplayRotation::Rotate180);
let width = display.size().width as i32;
for (stride, &byte) in self.pattern.iter().enumerate() {
for stroll in 0..8 {
let ix = stride as i32 * 8 + stroll;
let x = ix % width;
let y = ix / width;
display.set_pixel(Pixel(Point { x, y }, color_at(byte, stroll)));
}
}
self.epd.update_display(&display);
self.write_response(Response::UpdateDisplay).await; self.write_response(Response::UpdateDisplay).await;
} }
@@ -150,9 +123,11 @@ impl App {
} }
async fn write_response<'a>(&mut self, resp: Response<'a>) { async fn write_response<'a>(&mut self, resp: Response<'a>) {
const RESP_N: usize = 1024; const SYSEX_MAX: usize = 1024 - 2; // 2-byte framing
const POSTCARD_WIRE_MAX: usize = SYSEX_MAX * 7 / 8; // 7-in-8 encoding overhead
const USB_WIRE_MAX: usize = (SYSEX_MAX * 4).div_ceil(3); // USB MIDI muxing overhead
let mut resp_buffer = [0u8; RESP_N]; let mut resp_buffer = [0u8; POSTCARD_WIRE_MAX];
let payload_slice = match postcard::to_slice(&resp, &mut resp_buffer) { let payload_slice = match postcard::to_slice(&resp, &mut resp_buffer) {
Ok(slice) => slice, Ok(slice) => slice,
Err(err) => { Err(err) => {
@@ -161,7 +136,7 @@ impl App {
} }
}; };
let mut encode_buffer = [0u8; RESP_N]; let mut encode_buffer = [0u8; SYSEX_MAX];
encode_buffer[..MAGIC_NUMBER_LEN].copy_from_slice(&MAGIC_NUMBER); encode_buffer[..MAGIC_NUMBER_LEN].copy_from_slice(&MAGIC_NUMBER);
let Some(encoded_len) = encode_7in8(payload_slice, &mut encode_buffer[MAGIC_NUMBER_LEN..]) let Some(encoded_len) = encode_7in8(payload_slice, &mut encode_buffer[MAGIC_NUMBER_LEN..])
else { else {
@@ -169,7 +144,7 @@ impl App {
return; return;
}; };
let mut sysex_encoder = SysExEncoder::<RESP_N>::new(); let mut sysex_encoder = SysExEncoder::<USB_WIRE_MAX>::new();
let Some(encoded) = sysex_encoder.encode(&encode_buffer[..MAGIC_NUMBER_LEN + encoded_len]) let Some(encoded) = sysex_encoder.encode(&encode_buffer[..MAGIC_NUMBER_LEN + encoded_len])
else { else {
error!("write_response: USB MIDI encoding overflows the buffer"); error!("write_response: USB MIDI encoding overflows the buffer");
@@ -194,7 +169,7 @@ impl App {
} }
pub async fn run(&mut self) { pub async fn run(&mut self) {
let mut sysex_parser = SysExParser::<8192>::new(); let mut sysex_parser = SysExParser::<1024>::new();
'_connection: loop { '_connection: loop {
self.midi.wait_connection().await; self.midi.wait_connection().await;
-1
View File
@@ -17,7 +17,6 @@ const requestSchema = p.enumType('Request', {
UpdateDisplay: p.unitVariant('UpdateDisplay'), UpdateDisplay: p.unitVariant('UpdateDisplay'),
SetPattern: p.structVariant('SetPattern', { SetPattern: p.structVariant('SetPattern', {
from: p.u32(), from: p.u32(),
to: p.u32(),
chroma: chromaSchema, chroma: chromaSchema,
pattern: p.bytes(), pattern: p.bytes(),
}), }),
@@ -44,7 +44,6 @@ async function connectAndWrite() {
type: 'SetPattern', type: 'SetPattern',
value: { value: {
from: i, from: i,
to: i + 500,
chroma: { type: 'Black' }, chroma: { type: 'Black' },
pattern: buffer.slice(i, i + 500), pattern: buffer.slice(i, i + 500),
}, },