use std::collections::HashMap;
use crate::{subsystems::memory::{memory_types, MemoryBackend}, Error, Result};
use memory_types::{FromMemoryBackend, MemoryType};
#[derive(Debug)]
pub struct OwMemory {
memory: MemoryBackend,
used_pins: u32,
vid: u8,
pid: u8,
elements: HashMap<String, String>
}
impl OwMemory {
pub fn used_pins(&self) -> u32 {
self.used_pins
}
pub fn set_used_pins(&mut self, used_pins: u32) {
self.used_pins = used_pins;
}
pub fn vid(&self) -> u8 {
self.vid
}
pub fn set_vid(&mut self, vid: u8) {
self.vid = vid;
}
pub fn pid(&self) -> u8 {
self.pid
}
pub fn set_pid(&mut self, pid: u8) {
self.pid = pid;
}
pub fn elements(&self) -> &HashMap<String, String> {
&self.elements
}
pub fn elements_mut(&mut self) -> &mut HashMap<String, String> {
&mut self.elements
}
pub fn set_elements(&mut self, elements: HashMap<String, String>) {
self.elements = elements;
}
}
impl FromMemoryBackend for OwMemory {
async fn from_memory_backend(memory: MemoryBackend) -> Result<Self> {
if memory.memory_type == MemoryType::OneWire {
Ok(OwMemory::new(memory).await?)
} else {
Err(Error::MemoryError("Wrong type of memory!".to_owned()))
}
}
async fn initialize_memory_backend(memory: MemoryBackend) -> Result<Self> {
if memory.memory_type == MemoryType::OneWire {
Ok(OwMemory::initialize(memory).await?)
} else {
Err(Error::MemoryError("Wrong type of memory!".to_owned()))
}
}
fn close_memory(self) -> MemoryBackend {
self.memory
}
}
impl OwMemory {
pub(crate) async fn new(memory: MemoryBackend) -> Result<Self> {
let header = memory.read::<fn(usize, usize)>(0, 8, None).await?;
if header[0] != 0xEB {
return Err(Error::MemoryError("Invalid OneWire header".to_owned()));
}
let used_pins = u32::from_le_bytes([header[1], header[2], header[3], header[4]]);
let vid = header[5];
let pid = header[6];
let crc_byte = header[7];
let crc_data = &header[0..7];
let calculated_crc = crc32fast::hash(crc_data);
let expected_crc_lsb = (calculated_crc & 0xFF) as u8;
if crc_byte != expected_crc_lsb {
return Err(Error::MemoryError("OneWire CRC validation failed".to_owned()));
}
let element_header = memory.read::<fn(usize, usize)>(8, 2, None).await?;
let version = element_header[0];
let element_length = element_header[1];
if version != 0 {
return Err(Error::MemoryError("Unsupported OneWire version".to_owned()));
}
let elements = memory.read::<fn(usize, usize)>(10, element_length as usize, None).await?;
let elements_crc = memory.read::<fn(usize, usize)>(10 + element_length as usize, 1, None).await?[0];
let mut data = element_header;
data.extend_from_slice(&elements);
let calculated_crc = crc32fast::hash(&data);
let expected_crc_lsb = (calculated_crc & 0xFF) as u8;
if elements_crc != expected_crc_lsb {
return Err(Error::MemoryError("OneWire data CRC validation failed".to_owned()));
}
let elements_map = Self::parse_elements(&elements);
Ok(OwMemory {
memory,
used_pins,
vid,
pid,
elements: elements_map
})
}
pub(crate) async fn initialize(memory: MemoryBackend) -> Result<Self> {
Ok(OwMemory {
memory,
used_pins: 0,
vid: 0,
pid: 0,
elements: HashMap::new()
})
}
fn parse_elements(data: &[u8]) -> HashMap<String, String> {
let mut elements = HashMap::new();
let mut offset = 0;
while offset < data.len() {
if offset + 1 >= data.len() {
break;
}
let element_id = data[offset];
let element_length = data[offset + 1];
offset += 2;
if offset + element_length as usize > data.len() {
break;
}
let element_data = &data[offset..offset + element_length as usize];
offset += element_length as usize;
match element_id {
1 => { if let Ok(board_name) = String::from_utf8(element_data.to_vec()) {
elements.insert("boardName".to_string(), board_name);
}
},
2 => { if let Ok(revision) = String::from_utf8(element_data.to_vec()) {
elements.insert("revision".to_string(), revision);
}
},
3 => { let custom_data = hex::encode(element_data);
elements.insert("customData".to_string(), custom_data);
},
_ => {
}
}
}
elements
}
}