diff --git a/Cargo.lock b/Cargo.lock index 42376a8..4902db4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "1.1.2" @@ -282,6 +288,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "getrandom" version = "0.2.11" @@ -377,6 +393,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "nix" version = "0.27.1" @@ -413,7 +438,7 @@ version = "0.0.0" [[package]] name = "openemc-log" -version = "0.5.0" +version = "0.6.0" dependencies = [ "anyhow", "clap", @@ -421,6 +446,7 @@ dependencies = [ "defmt-decoder", "defmt-parser", "env_logger", + "flate2", "libc", "log", "nix", @@ -826,5 +852,7 @@ version = "0.0.0" dependencies = [ "anyhow", "clap", + "crc32fast", "devx-cmd", + "flate2", ] diff --git a/openemc-log/Cargo.toml b/openemc-log/Cargo.toml index 89f9212..ef2ba6a 100644 --- a/openemc-log/Cargo.toml +++ b/openemc-log/Cargo.toml @@ -3,7 +3,7 @@ name = "openemc-log" description = "OpenEMC Logger" authors = ["Sebastian Urban "] license = "GPL-3.0" -version = "0.5.0" +version = "0.6.0" publish = false edition = "2021" @@ -17,3 +17,4 @@ log = "0.4" libc = "0.2" env_logger = "0.10" ctrlc = { version = "3", features = ["termination"] } +flate2 = "1" diff --git a/openemc-log/src/main.rs b/openemc-log/src/main.rs index bff7634..95dbe0b 100644 --- a/openemc-log/src/main.rs +++ b/openemc-log/src/main.rs @@ -23,6 +23,7 @@ use clap::Parser; use defmt_decoder::{DecodeError, Frame, Location, Table}; use defmt_parser::Level as DefmtLevel; use env_logger::Target; +use flate2::read::GzDecoder; use log::{Level, LevelFilter}; use nix::{ errno::Errno, @@ -44,6 +45,7 @@ mod syslog; const READ_BUFFER_SIZE: usize = 128; const POLL_TIMEOUT: c_int = 60_000; +const FIRMWARE_DIR: &'static str = "/lib/firmware"; static STOP: AtomicBool = AtomicBool::new(false); @@ -123,27 +125,45 @@ fn get_paths(opts: &Opts, bootloader: bool) -> Result<(PathBuf, PathBuf)> { let firmware_elf = match &opts.firmware_elf { Some(firmware_elf) => firmware_elf.clone(), + + None if bootloader => { + let firmware_bin = PathBuf::from(OsString::from_vec( + fs::read(openemc_log.with_file_name("openemc_firmware")) + .context("OpenEMC firmware location not available")?, + )); + let firmware_dir = match firmware_bin.parent() { + Some(dir) if firmware_bin.has_root() => dir, + _ => Path::new(FIRMWARE_DIR), + }; + + let bootloader_crc32 = fs::read_to_string(openemc_log.with_file_name("openemc_bootloader_crc32")) + .context("OpenEMC bootloader CRC32 not available")?; + + let bootloader_elf = firmware_dir.join(format!("openemc_bootloader_{bootloader_crc32}.elf.gz")); + if !bootloader_elf.is_file() { + bail!("OpenEMC bootloader ELF not found"); + } + bootloader_elf + } + None => { let mut firmware_bin = PathBuf::from(OsString::from_vec( fs::read(openemc_log.with_file_name("openemc_firmware")) .context("OpenEMC firmware location not available")?, )); if !firmware_bin.has_root() { - firmware_bin = Path::new("/lib/firmware").join(firmware_bin); + firmware_bin = Path::new(FIRMWARE_DIR).join(firmware_bin); } let firmware_dir = firmware_bin.parent().context("no firmware directory")?; let mut firmware = firmware_bin.file_stem().context("unrecognized firmware name")?.to_os_string(); - if bootloader { - firmware = firmware.to_string_lossy().replace("openemc_", "openemc_bootloader_").into(); - } loop { if firmware.is_empty() { bail!("OpenEMC firmware ELF not found"); } - let firmware_elf = firmware_dir.join(&firmware).with_extension("elf"); + let firmware_elf = firmware_dir.join(&firmware).with_extension("elf.gz"); if firmware_elf.is_file() { break firmware_elf; } @@ -169,7 +189,11 @@ fn perform(opts: &Opts) -> Result { firmware_elf.display() ); - let bytes = fs::read(&firmware_elf).context("cannot read firmware")?; + let mut bytes = Vec::new(); + { + let mut file = GzDecoder::new(File::open(&firmware_elf).context("cannot open firmware")?); + file.read_to_end(&mut bytes).context("cannot read firmware")?; + } let table = Table::parse(&bytes)?.context(".defmt data not found")?; let locs = table.get_locations(&bytes)?; drop(bytes); diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 1a23271..fca3acb 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -9,3 +9,5 @@ edition = "2021" devx-cmd = "0.5" anyhow = "1" clap = { version = "4", features = ["derive"] } +flate2 = "1" +crc32fast = "1.3" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 97f32f3..ed571b3 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -4,12 +4,16 @@ use clap::Parser; use devx_cmd::cmd; +use flate2::{write::GzEncoder, Compression}; use std::{ env, fs, + fs::File, + io::{copy, Write}, path::{Path, PathBuf}, }; const ARCH: &str = "thumbv7m-none-eabi"; +const GZ_LEVEL: Compression = Compression::best(); /// Build OpenEMC images. #[derive(Parser, Debug)] @@ -44,6 +48,15 @@ fn project_root() -> PathBuf { Path::new(&env!("CARGO_MANIFEST_DIR")).ancestors().nth(1).unwrap().to_path_buf() } +fn gzip(src: impl AsRef, dest: impl AsRef) -> std::io::Result<()> { + let mut in_file = File::open(src)?; + let out_file = File::create(dest)?; + let mut gz = GzEncoder::new(out_file, GZ_LEVEL); + copy(&mut in_file, &mut gz)?; + gz.finish()?.flush()?; + Ok(()) +} + fn main() -> anyhow::Result<()> { let args = Args::parse(); let board = &args.board; @@ -60,22 +73,14 @@ fn main() -> anyhow::Result<()> { let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); - if !args.no_bootloader { + let bootloader_elf_gz = if !args.no_bootloader { cmd!(&cargo, "build", "--release", "--no-default-features", "--features", "defmt-ringbuf") .current_dir(project_root().join("openemc-bootloader")) .env("OPENEMC_BOARD", board) .env("OPENEMC_BOOTLOADER", bootloader_variant) .env("DEFMT_LOG", &args.bootloader_log) .run()?; - fs::copy( - project_root() - .join("openemc-bootloader") - .join("target") - .join(ARCH) - .join("release") - .join("openemc-bootloader"), - project_root().join("image").join(format!("{bootloader}.elf")), - )?; + cmd!( &cargo, "objcopy", @@ -93,7 +98,25 @@ fn main() -> anyhow::Result<()> { .env("OPENEMC_BOOTLOADER", bootloader_variant) .env("DEFMT_LOG", &args.bootloader_log) .run()?; - } + + let bootloader_bin_data = fs::read(project_root().join("image").join(format!("{bootloader}.bin")))?; + let bootloader_bin_crc32 = crc32fast::hash(&bootloader_bin_data); + let bootloader_elf_gz = format!("openemc_bootloader_{bootloader_bin_crc32:08x}.elf.gz"); + + gzip( + project_root() + .join("openemc-bootloader") + .join("target") + .join(ARCH) + .join("release") + .join("openemc-bootloader"), + project_root().join("image").join(&bootloader_elf_gz), + )?; + + Some(bootloader_elf_gz) + } else { + None + }; cmd!(&cargo, "build", "--release", "--no-default-features", "--features", "defmt-ringbuf") .args(args.features.iter().flat_map(|feature| ["--features", feature])) @@ -102,15 +125,16 @@ fn main() -> anyhow::Result<()> { .env("OPENEMC_BOOTLOADER", bootloader_variant) .env("DEFMT_LOG", &args.log) .run()?; - fs::copy( + gzip( project_root() .join("openemc-firmware") .join("target") .join(ARCH) .join("release") .join("openemc-firmware"), - project_root().join("image").join(format!("{firmware}.elf")), + project_root().join("image").join(format!("{firmware}.elf.gz")), )?; + cmd!(&cargo, "objcopy", "--release", "--no-default-features", "--features", "defmt-ringbuf",) .args(args.features.iter().flat_map(|feature| ["--features", feature])) .args(["--", "-O", "binary", &format!("../image/{firmware}.bin")]) @@ -140,12 +164,12 @@ fn main() -> anyhow::Result<()> { use std::os::unix::fs::PermissionsExt; let mut files = vec![ project_root().join("image").join(format!("{firmware}.emc")), - project_root().join("image").join(format!("{firmware}.elf")), + project_root().join("image").join(format!("{firmware}.elf.gz")), ]; - if !args.no_bootloader { + if let Some(bootloader_elf_gz) = &bootloader_elf_gz { files.extend([ project_root().join("image").join(format!("{bootloader}.bin")), - project_root().join("image").join(format!("{bootloader}.elf")), + project_root().join("image").join(bootloader_elf_gz), ]); } for file in files { @@ -157,14 +181,12 @@ fn main() -> anyhow::Result<()> { println!(); println!("Board {board}:"); - if !args.no_bootloader { - println!( - "Built {}bootloader image/{bootloader}.{{bin,elf}} with log level {}", - if emc_model == 0xd1 { "debug " } else { "" }, - &args.bootloader_log - ); + if let Some(bootloader_elf_gz) = &bootloader_elf_gz { + let debug = if emc_model == 0xd1 { "debug " } else { "" }; + println!("Built {debug}bootloader image/{bootloader}.bin with log level {}", &args.bootloader_log); + println!("Built {debug}bootloader image/{bootloader_elf_gz}"); } - println!("Built OpenEMC firmware image/{firmware}.{{emc,elf}} with log level {}", &args.log); + println!("Built OpenEMC firmware image/{firmware}.{{emc,elf.gz}} with log level {}", &args.log); println!(); Ok(())