feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
+182
@@ -0,0 +1,182 @@
|
||||
/* Copyright 2018 The encode_unicode Developers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
|
||||
* http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
|
||||
* http://opensource.org/licenses/MIT>, at your option. This file may not be
|
||||
* copied, modified, or distributed except according to those terms.
|
||||
*/
|
||||
|
||||
//! Iterator tests
|
||||
|
||||
#![cfg(feature="std")]
|
||||
|
||||
extern crate encode_unicode;
|
||||
|
||||
use encode_unicode::{IterExt, SliceExt, CharExt};
|
||||
use encode_unicode::iterator::Utf8CharSplitter;
|
||||
use encode_unicode::error::InvalidUtf8Slice::*;
|
||||
use encode_unicode::error::InvalidUtf8::*;
|
||||
use encode_unicode::error::InvalidUtf8FirstByte::*;
|
||||
use encode_unicode::error::InvalidCodepoint::*;
|
||||
use encode_unicode::error::Utf16PairError::*;
|
||||
use std::io::Read;
|
||||
use std::cmp::min;
|
||||
|
||||
#[test] fn utf8charmerger() {
|
||||
let slice = b"\xf0\xa1\x92X\xcc\xbb";
|
||||
let mut iter = slice.iter().to_utf8chars();
|
||||
assert_eq!(iter.size_hint(), (1, Some(6)));
|
||||
assert_eq!(format!("{:?}", &iter),
|
||||
format!("Utf8CharMerger {{ buffered: [], inner: {:?} }}", slice.iter()));
|
||||
|
||||
assert_eq!(iter.next(), Some(Err(Utf8(NotAContinuationByte(3)))));
|
||||
assert_eq!(iter.size_hint(), (0, Some(5)));
|
||||
assert_eq!(
|
||||
format!("{:?}", &iter),
|
||||
format!("Utf8CharMerger {{ buffered: [161, 146, 88], inner: {:?} }}", slice[4..].iter())
|
||||
);
|
||||
|
||||
assert_eq!(iter.next(), Some(Err(Utf8(FirstByte(ContinuationByte)))));
|
||||
assert_eq!(iter.into_inner().next(), Some(&b'\xcc'));
|
||||
}
|
||||
|
||||
#[test] fn utf8chardecoder() {
|
||||
let slice = b"\xf4\xbf\x80\x80XY\xcc\xbbZ_";
|
||||
let mut iter = slice.utf8char_indices();
|
||||
assert_eq!(iter.size_hint(), (2, Some(10)));
|
||||
assert_eq!(
|
||||
format!("{:?}", &iter),
|
||||
format!("Utf8CharDecoder {{ bytes[0..]: {:?} }}", &slice)
|
||||
);
|
||||
|
||||
assert_eq!(iter.next(), Some((0, Err(Codepoint(TooHigh)), 1)));
|
||||
assert_eq!(
|
||||
format!("{:?}", &iter),
|
||||
format!("Utf8CharDecoder {{ bytes[1..]: {:?} }}", &slice[1..])
|
||||
);
|
||||
assert_eq!(iter.size_hint(), (2, Some(9)));
|
||||
assert_eq!(iter.count(), 8);
|
||||
}
|
||||
|
||||
#[test] fn utf16charmerger() {
|
||||
let slice = [0xd800, 'x' as u16, 0xd900, 0xdfff, 'λ' as u16];
|
||||
let mut iter = slice.iter().to_utf16chars();
|
||||
assert_eq!(iter.size_hint(), (2, Some(5)));
|
||||
assert_eq!(format!("{:?}", &iter),
|
||||
format!("Utf16CharMerger {{ buffered: None, inner: {:?} }}", slice.iter()));
|
||||
|
||||
assert_eq!(iter.next(), Some(Err(UnmatchedLeadingSurrogate)));
|
||||
assert_eq!(iter.size_hint(), (1, Some(4)));
|
||||
assert_eq!(
|
||||
format!("{:?}", &iter),
|
||||
format!("Utf16CharMerger {{ buffered: Some(120), inner: {:?} }}", slice[2..].iter())
|
||||
);
|
||||
|
||||
assert_eq!(iter.into_inner().next(), Some(&0xd900));
|
||||
}
|
||||
|
||||
#[test] fn utf16chardecoder() {
|
||||
let slice = [0xd800, 'x' as u16, 0xd900, 0xdfff, 'λ' as u16];
|
||||
let mut iter = slice.utf16char_indices();
|
||||
assert_eq!(iter.size_hint(), (2, Some(5)));
|
||||
assert_eq!(
|
||||
format!("{:?}", &iter),
|
||||
format!("Utf16CharDecoder {{ units[0..]: {:?} }}", &slice)
|
||||
);
|
||||
|
||||
assert_eq!(iter.next(), Some((0, Err(UnmatchedLeadingSurrogate), 1)));
|
||||
assert_eq!(
|
||||
format!("{:?}", &iter),
|
||||
format!("Utf16CharDecoder {{ units[1..]: {:?} }}", &slice[1..])
|
||||
);
|
||||
assert_eq!(iter.size_hint(), (2, Some(4)));
|
||||
assert_eq!(iter.count(), 3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Tests for ensuring that iterators which also implement Read support
|
||||
/// interleaving calls of `read()` and `next()`, and that they implement Read
|
||||
/// correctly (support any buffer size at any time).
|
||||
|
||||
#[test] fn read_single_ascii() {
|
||||
let uc = 'a'.to_utf8();
|
||||
assert_eq!(uc.len(), 1);
|
||||
for chunk in 1..5 {
|
||||
let mut buf = [b'E'; 6];
|
||||
let mut iter = uc.into_iter();
|
||||
let mut written = 0;
|
||||
for _ in 0..4 {
|
||||
assert_eq!(iter.read(&mut buf[..0]).unwrap(), 0);
|
||||
let wrote = iter.read(&mut buf[written..written+chunk]).unwrap();
|
||||
assert_eq!(wrote, min(1-written, chunk));
|
||||
written += wrote;
|
||||
for &b in &buf[written..] {assert_eq!(b, b'E');}
|
||||
assert_eq!(buf[..written], AsRef::<[u8]>::as_ref(&uc)[..written]);
|
||||
}
|
||||
assert_eq!(written, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test] fn read_single_nonascii() {
|
||||
let uc = 'ä'.to_utf8();
|
||||
assert_eq!(uc.len(), 2);
|
||||
for chunk in 1..5 {
|
||||
let mut buf = [b'E'; 6];
|
||||
let mut iter = uc.into_iter();
|
||||
let mut written = 0;
|
||||
for _ in 0..4 {
|
||||
assert_eq!(iter.read(&mut buf[..0]).unwrap(), 0);
|
||||
let wrote = iter.read(&mut buf[written..written+chunk]).unwrap();
|
||||
assert_eq!(wrote, min(2-written, chunk));
|
||||
written += wrote;
|
||||
for &b in &buf[written..] {assert_eq!(b, b'E');}
|
||||
assert_eq!(buf[..written], AsRef::<[u8]>::as_ref(&uc)[..written]);
|
||||
}
|
||||
assert_eq!(written, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test] fn utf8charsplitter_read_all_sizes() {
|
||||
let s = "1111\u{104444}\u{222}1\u{833}1111\u{100004}";
|
||||
assert!(s.len()%3 == 1);
|
||||
let mut buf = vec![b'E'; s.len()+6];
|
||||
for size in 2..6 {//s.len()+4 {
|
||||
let mut reader = Utf8CharSplitter::from(s.chars().map(|c| c.to_utf8() ));
|
||||
for (offset, part) in s.as_bytes().chunks(size).enumerate() {
|
||||
let read_to = if part.len() == size {(offset+1)*size} else {buf.len()};
|
||||
assert_eq!(reader.read(&mut buf[offset*size..read_to]).unwrap(), part.len());
|
||||
assert_eq!(&buf[..offset*size+part.len()], &s.as_bytes()[..offset*size+part.len()]);
|
||||
}
|
||||
assert_eq!(reader.read(&mut buf[..]).unwrap(), 0);
|
||||
assert!(buf[s.len()..].iter().all(|&b| b==b'E' ));
|
||||
}
|
||||
}
|
||||
|
||||
#[test] fn utf8charsplitter_alternate_iter_read() {
|
||||
let s = "1111\u{104444}\u{222}1\u{833}1111\u{100004}";
|
||||
let mut buf = [b'0'; 10];
|
||||
for n in 0..2 {
|
||||
// need to collect to test size_hint()
|
||||
// because chars().size_hint() returns ((bytes+3)/4, Some(bytes))
|
||||
let u8chars = s.chars().map(|c| c.to_utf8() ).collect::<Vec<_>>();
|
||||
let mut iter: Utf8CharSplitter<_,_> = u8chars.into_iter().into();
|
||||
for (i, byte) in s.bytes().enumerate() {
|
||||
let until_next = s.as_bytes()[i..].iter().take_while(|&b| (b>>6)==0b10u8 ).count();
|
||||
let remaining_chars = s[i+until_next..].chars().count();
|
||||
println!("{}. run: byte {:02} of {}, remaining: {:02}+{}: 0b{:08b} = {:?}",
|
||||
n, i, s.len(), remaining_chars, until_next, byte, byte as char);
|
||||
assert_eq!(iter.read(&mut[][..]).unwrap(), 0);
|
||||
if i % 2 == n {
|
||||
assert_eq!(iter.next(), Some(byte));
|
||||
} else {
|
||||
assert_eq!(iter.read(&mut buf[..1]).unwrap(), 1);
|
||||
assert_eq!(buf[0], byte);
|
||||
}
|
||||
}
|
||||
assert_eq!(iter.size_hint(), (0, Some(0)));
|
||||
assert_eq!(iter.next(), None);
|
||||
assert_eq!(iter.read(&mut buf[..]).unwrap(), 0);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user