Add config writing capability #99
|
@ -1,7 +1,7 @@
|
||||||
use crate::sd_reader;
|
use crate::sd_reader;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use alloc::{string::FromUtf8Error, string::String, vec::Vec};
|
use alloc::{string::FromUtf8Error, string::String, vec::Vec};
|
||||||
use core_io::{self as io, BufRead, BufReader, Read};
|
use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, ErrorKind, SeekFrom};
|
||||||
|
|
||||||
use libboard_zynq::sdio;
|
use libboard_zynq::sdio;
|
||||||
|
|
||||||
|
@ -61,6 +61,39 @@ fn parse_config<'a>(
|
||||||
}
|
}
|
||||||
Err(Error::KeyNotFoundError(key))
|
Err(Error::KeyNotFoundError(key))
|
||||||
}
|
}
|
||||||
|
fn delete_old_entry<'a>(
|
||||||
|
key: &str,
|
||||||
|
file: fatfs::File<sd_reader::SdReader>,
|
||||||
|
mut file_tmp: fatfs::File<sd_reader::SdReader>,
|
||||||
|
) -> Result<'a, ()> {
|
||||||
|
let prefix = [key, "="].concat();
|
||||||
|
let buf_reader = BufReader::new(file);
|
||||||
|
|
||||||
|
for line in buf_reader.lines() {
|
||||||
|
let line = line?;
|
||||||
|
if !line.starts_with(&prefix) {
|
||||||
|
file_tmp.write_all(&[line.as_str(), "\n"].concat().as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rename_file<'a>(dir: &fatfs::Dir<sd_reader::SdReader>, old_file_name: &str, new_file_name: &str) -> Result<'a, ()>{
|
||||||
|
{
|
||||||
|
let old_file = dir.open_file(old_file_name)?;
|
||||||
|
let mut new_file = dir.create_file(new_file_name)?;
|
||||||
|
new_file.truncate()?;
|
||||||
|
|
||||||
|
for line in BufReader::new(old_file).lines() {
|
||||||
|
let line = line?;
|
||||||
|
new_file.write_all(&[line.as_str(), "\n"].concat().as_bytes())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.remove(old_file_name)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
fs: Option<fatfs::FileSystem<sd_reader::SdReader>>,
|
fs: Option<fatfs::FileSystem<sd_reader::SdReader>>,
|
||||||
|
@ -103,4 +136,76 @@ impl Config {
|
||||||
pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> {
|
pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> {
|
||||||
Ok(String::from_utf8(self.read(key)?)?)
|
Ok(String::from_utf8(self.read(key)?)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_str<'b>(&mut self, key: &str, data: &str) -> Result<'b, ()>{
|
||||||
|
if let Some(fs) = &self.fs {
|
||||||
|
let root_dir = fs.root_dir();
|
||||||
|
|
||||||
|
let config_key_bin = &["/CONFIG/", key, ".BIN"].concat();
|
||||||
|
let config_txt_tmp = "/CONFIG.TMP";
|
||||||
|
|
||||||
|
if data.is_ascii() & (data.len() <= 100) {
|
||||||
|
match root_dir.create_file("/CONFIG.TXT") {
|
||||||
|
Ok(file) => {
|
||||||
|
let mut file_tmp = root_dir.create_file(config_txt_tmp)?;
|
||||||
|
file_tmp.truncate()?;
|
||||||
|
delete_old_entry(key, file, file_tmp)?;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
return Err(Error::IoError(e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rename_file(&root_dir, config_txt_tmp, "/CONFIG.TXT")?;
|
||||||
|
|
||||||
|
let mut file = root_dir.open_file("/CONFIG.TXT")?;
|
||||||
|
file.seek(SeekFrom::End(0))?;
|
||||||
|
file.write_all(&["\n", key, "=", data, "\n"].concat().as_bytes())?;
|
||||||
|
|
||||||
|
match root_dir.remove(config_key_bin) {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(e) => match e.kind() {
|
||||||
|
ErrorKind::NotFound => {},
|
||||||
|
_ => {
|
||||||
|
return Err(Error::IoError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
root_dir.create_dir("/CONFIG")?;
|
||||||
|
match root_dir.create_file(config_key_bin) {
|
||||||
|
Ok(mut file) => {
|
||||||
|
file.truncate()?;
|
||||||
|
file.write_all(&[data, "\n"].concat().as_bytes())?;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
return Err(Error::IoError(e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut need_to_rename = false;
|
||||||
|
match root_dir.open_file("/CONFIG.TXT") {
|
||||||
|
Ok(file) => {
|
||||||
|
need_to_rename = true;
|
||||||
|
let mut file_tmp = root_dir.create_file(config_txt_tmp)?;
|
||||||
|
file_tmp.truncate()?;
|
||||||
|
delete_old_entry(key, file, file_tmp)?;
|
||||||
|
},
|
||||||
|
Err(e) => match e.kind() {
|
||||||
|
ErrorKind::NotFound => {},
|
||||||
|
_ => {
|
||||||
|
return Err(Error::IoError(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if need_to_rename { // docs: ensure no ref to files
|
||||||
|
rename_file(&root_dir, config_txt_tmp, "/CONFIG.TXT")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::NoConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue