pub mod discovery;
pub mod eeprom;
pub mod flash;
pub mod params;
pub mod pixel;
pub mod upgrade;
pub use discovery::*;
pub use flash::*;
pub use pixel::*;
pub const CARD_MAC: [u8; 6] = [0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
pub const SENDER_MAC: [u8; 6] = [0x22, 0x22, 0x33, 0x44, 0x55, 0x66];
pub const BROADCAST: u16 = 0xffff;
pub const HEADER_LEN: usize = 14;
pub(crate) fn write_header(f: &mut [u8], ethertype: [u8; 2]) {
f[..6].copy_from_slice(&CARD_MAC);
f[6..12].copy_from_slice(&SENDER_MAC);
f[12..14].copy_from_slice(ðertype);
}
#[must_use]
pub fn frame_with(ethertype: [u8; 2], payload_len: usize, fill: impl FnOnce(&mut [u8])) -> Vec<u8> {
let mut f = vec![0u8; HEADER_LEN + payload_len];
write_header(&mut f, ethertype);
fill(&mut f[HEADER_LEN..]);
f
}
#[must_use]
pub fn frame(ethertype: [u8; 2], payload: &[u8]) -> Vec<u8> {
frame_with(ethertype, payload.len(), |p| p.copy_from_slice(payload))
}
pub(crate) fn indexed(p: &mut [u8], rcv_index: u16, opcode: u8) {
p[1..3].copy_from_slice(&rcv_index.to_be_bytes());
p[3] = opcode;
}
pub(crate) fn command(rcv_index: u16, opcode: u8, flags: &[u8]) -> Vec<u8> {
frame_with([0x06, 0x00], 126, |p| {
indexed(p, rcv_index, opcode);
p[8..8 + flags.len()].copy_from_slice(flags);
})
}
pub trait Protocol {
fn discover(&self) -> Vec<u8>;
fn discovery_reply(&self, frame: &[u8]) -> Option<DiscoveryInfo>;
fn row(&self, buf: &mut Vec<u8>, row: u16, x: u16, rgb: &[[u8; 3]], order: ColorOrder);
fn latch(&self, brightness: u8) -> Vec<u8>;
fn brightness(&self, brightness: u8) -> Vec<u8>;
fn flash_read(&self, index: u16, page: u16) -> Vec<u8>;
fn flash_reply<'a>(&self, frame: &'a [u8]) -> Option<&'a [u8]>;
fn flash_write(&self, map: &FlashMap, index: u16, block: u8, page: u8, data: &[u8]) -> Result<Vec<u8>, WriteError>;
fn eeprom_write(&self, addr: u16, data: &[u8]) -> Vec<u8>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Colorlight;
impl Protocol for Colorlight {
fn discover(&self) -> Vec<u8> {
discovery()
}
fn discovery_reply(&self, frame: &[u8]) -> Option<DiscoveryInfo> {
parse_discovery_response(frame)
}
fn row(&self, buf: &mut Vec<u8>, row: u16, x: u16, rgb: &[[u8; 3]], order: ColorOrder) {
pixel_row_into(buf, row, x, rgb, order);
}
fn latch(&self, brightness: u8) -> Vec<u8> {
sync(brightness).to_vec()
}
fn brightness(&self, brightness: u8) -> Vec<u8> {
pixel::brightness(brightness).to_vec()
}
fn flash_read(&self, index: u16, page: u16) -> Vec<u8> {
read_flash(index, page)
}
fn flash_reply<'a>(&self, frame: &'a [u8]) -> Option<&'a [u8]> {
flash_reply_data(frame)
}
fn flash_write(&self, map: &FlashMap, index: u16, block: u8, page: u8, data: &[u8]) -> Result<Vec<u8>, WriteError> {
map.write_page(index, block, page, data)
}
fn eeprom_write(&self, addr: u16, data: &[u8]) -> Vec<u8> {
eeprom::write(addr, data)
}
}
#[cfg(test)]
mod protocol_tests {
use super::*;
#[test]
fn the_trait_builds_the_same_frames_as_the_functions() {
let p = Colorlight;
assert_eq!(p.discover(), discovery());
assert_eq!(p.latch(40), sync(40).to_vec());
assert_eq!(p.brightness(40), pixel::brightness(40).to_vec());
assert_eq!(p.flash_read(0, FLASH_PAGE_BASIC_PARAM), read_flash(0, FLASH_PAGE_BASIC_PARAM));
assert_eq!(p.eeprom_write(0x02, &[0; 42]), eeprom::write(0x02, &[0; 42]));
let page = [0u8; FLASH_PAGE_BYTES];
assert_eq!(p.flash_write(&E120, 0, PARAM_BLOCK, 0x80, &page), E120.write_page(0, PARAM_BLOCK, 0x80, &page));
assert_eq!(p.flash_write(&E120, 0, 0x00, 0, &page), Err(WriteError::ForbiddenBlock(0)));
let mut a = Vec::new();
p.row(&mut a, 3, 0, &[[1, 2, 3]; 4], ColorOrder::Bgr);
assert_eq!(a, pixel_row(3, 0, &[[1, 2, 3]; 4], ColorOrder::Bgr));
assert!(p.discovery_reply(&[0; 20]).is_none());
assert!(p.flash_reply(&[0; 20]).is_none());
}
}