Skip to content
Snippets Groups Projects
Commit 6ac96671 authored by Benjamin Koch's avatar Benjamin Koch
Browse files

refactoring: move ProgramInfoBuilder into dedicated file

parent 03d3cc50
No related branches found
No related tags found
No related merge requests found
......@@ -25,6 +25,7 @@ use heapless::String;
use heizung::i2c_scan::{self, ScanResultForBus};
use heizung::modbus_server::{ModbusServer, ModbusRegisters, ModbusErrorCode, ModbusAdressMatch, U16Pusher};
use heizung::program_info::ProgramInfoBuilder;
use heizung::rs485::RS485;
use heizung::uf2updater::UF2UpdateHandler;
use heizung::watchdog::WatchdogFixed;
......@@ -700,203 +701,7 @@ fn init_early() {
// Add program info.
#[used]
#[link_section = ".program_info"]
pub static PROGRAM_INFO: [u8; 4096] = make_program_info();
struct ProgramInfoBuilder {
addr: u32,
buf: [u8; 4096],
info_pos: usize,
data_pos: usize,
info_table_size: usize,
data_end_offset: usize,
}
impl ProgramInfoBuilder {
const fn new(addr: u32, info_table_size: u32, copy_table_size: u32) -> Self {
let copy_table_size = copy_table_size as usize;
let dummy_item_ptr = addr + info_table_size;
let dummy_item_size = 4;
core::assert!(info_table_size % 4 == 0);
ProgramInfoBuilder {
addr,
buf: {
let mut x = [0xff; 4096];
// mark end of copy table with zero in first entry
x[4096 - copy_table_size + 0] = 0;
x[4096 - copy_table_size + 1] = 0;
x[4096 - copy_table_size + 2] = 0;
x[4096 - copy_table_size + 3] = 0;
x
},
info_pos: 0,
data_pos: info_table_size as usize + dummy_item_size,
data_end_offset: 4096 - copy_table_size as usize,
info_table_size: info_table_size as usize,
}
}
const fn build(mut self: Self) -> [u8; 4096] {
if self.info_pos < self.info_table_size {
self = self.align();
let addr = self.addr + self.data_pos as u32;
self = self.push_u32(0xffffffff).fill_info_table(addr);
}
self.buf
}
const fn push_info_u8(mut self: Self, value: u8) -> Self {
self.buf[self.info_pos] = value;
self.info_pos += 1;
if self.info_pos > self.info_table_size {
core::panic!("ProgramInfoBuilder: too much data for info table")
}
self
}
const fn push_info_ptr(mut self: Self, value: u32) -> Self {
self
.push_info_u8((value & 0xff) as u8)
.push_info_u8(((value >> 8) & 0xff) as u8)
.push_info_u8(((value >> 16) & 0xff) as u8)
.push_info_u8(((value >> 24) & 0xff) as u8)
}
const fn push_current_info_ptr(mut self: Self) -> Self {
self = self.align();
let addr = self.addr + self.data_pos as u32;
self.push_info_ptr(addr)
}
const fn fill_info_table(mut self: Self, value: u32) -> Self {
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self.fill_info_table(value)
} else {
self
}
}
const fn push(mut self: Self, value: u8) -> Self {
self.buf[self.data_pos] = value;
self.data_pos += 1;
if self.data_pos > self.data_end_offset {
core::panic!("ProgramInfoBuilder: too much data")
}
self
}
const fn align(mut self: Self) -> Self {
if self.data_pos % 4 != 0 {
self = self.push(0xff);
}
if self.data_pos % 4 != 0 {
self = self.push(0xff);
}
if self.data_pos % 4 != 0 {
self = self.push(0xff);
}
self
}
const fn push_u16(self: Self, value: u16) -> Self {
self
.push((value & 0xff) as u8)
.push(((value >> 8) & 0xff) as u8)
}
const fn push_u32(self: Self, value: u32) -> Self {
self
.push((value & 0xff) as u8)
.push(((value >> 8) & 0xff) as u8)
.push(((value >> 16) & 0xff) as u8)
.push(((value >> 24) & 0xff) as u8)
}
const fn push_raspberry_tag(self: Self) -> Self {
self.push('R' as u8)
.push('P' as u8)
}
const fn push_extra_data(mut self: Self, value: &[u8]) -> (Self, u32) {
if self.data_pos - self.info_pos < value.len() {
core::panic!("ProgramInfoBuilder: too much data")
}
let offset = self.data_pos;
//self.buf[offset..self.data_pos].copy_from_slice(value);
//for i in 0..value.len() {
// self.buf[offset+i] = value[i];
//}
if value.len() > 0 { self.buf[offset+0] = value[0]; }
if value.len() > 1 { self.buf[offset+1] = value[1]; }
if value.len() > 2 { self.buf[offset+2] = value[2]; }
if value.len() > 3 { self.buf[offset+3] = value[3]; }
if value.len() > 4 { self.buf[offset+4] = value[4]; }
if value.len() > 5 { self.buf[offset+5] = value[5]; }
if value.len() > 6 { self.buf[offset+6] = value[6]; }
if value.len() > 7 { self.buf[offset+7] = value[7]; }
if value.len() > 8 { core::panic!("too long") }
self.data_pos += value.len();
let addr = self.addr + offset as u32;
(self, addr)
}
const fn push_string(mut self: Self, value: &str) -> Self {
if self.data_pos - self.info_pos < value.len() {
core::panic!("ProgramInfoBuilder: too much data")
}
let x1 = self.data_pos;
self = self.push_u32(0);
let (self2, addr) = self.push_extra_data(value.as_bytes());
self = self2;
(self, _) = self.push_extra_data(&[0]);
let x2 = self.data_pos;
self.data_pos = x1;
self = self.push_u32(addr);
self.data_pos = x2;
self
}
const BINARY_INFO_TYPE_ID_AND_INT: u16 = 5;
const BINARY_INFO_TYPE_ID_AND_STRING: u16 = 6;
const BINARY_INFO_ID_RP_PROGRAM_NAME: u32 = 0x02031c86;
const BINARY_INFO_ID_RP_BINARY_END: u32 = 0x68f465de;
const fn push_program_name(self: Self, value: &str) -> Self {
self.push_current_info_ptr()
.push_u16(Self::BINARY_INFO_TYPE_ID_AND_STRING)
.push_raspberry_tag()
.push_u32(Self::BINARY_INFO_ID_RP_PROGRAM_NAME)
.push_string(value)
}
#[allow(unused)]
const fn push_binary_end(self: Self, value: &str) -> Self {
self.push_current_info_ptr()
.push_u16(Self::BINARY_INFO_TYPE_ID_AND_INT)
.push_raspberry_tag()
.push_u32(Self::BINARY_INFO_ID_RP_BINARY_END)
.push_string(value)
}
}
const fn make_program_info() -> [u8; 4096] {
pub static PROGRAM_INFO: [u8; 4096] = {
// all of these must match the values in the bootloader
const PROGRAM_INFO_FLASH_OFFSET: u32 = 0x10087000 - PROGRAM_INFO_TOTAL_SIZE; // last 4k of active partition
const PROGRAM_INFO_TOTAL_SIZE: u32 = 4096;
......@@ -904,6 +709,6 @@ const fn make_program_info() -> [u8; 4096] {
const PROGRAM_INFO_COPY_TABLE_SIZE: u32 = 128; // 3*u32 for each entry, picotool stops after 10 entries
ProgramInfoBuilder::new(PROGRAM_INFO_FLASH_OFFSET, PROGRAM_INFO_TABLE_SIZE, PROGRAM_INFO_COPY_TABLE_SIZE)
.push_program_name("Test 123")
.program_name("Test 123")
.build()
}
};
......@@ -8,3 +8,4 @@ pub mod clear_bootloader_state;
pub mod uf2;
pub mod uf2updater;
pub mod watchdog;
pub mod program_info;
pub struct ProgramInfoBuilder {
addr: u32,
buf: [u8; 4096],
info_pos: usize,
data_pos: usize,
info_table_size: usize,
data_end_offset: usize,
}
const fn copy(mut buf: [u8; 4096], offset: usize, source: &[u8], source_offset: usize) -> [u8; 4096] {
if source_offset >= source.len() {
buf
} else {
buf[offset] = source[source_offset];
copy(buf, offset+1, source, source_offset+1)
}
}
impl ProgramInfoBuilder {
pub const fn new(addr: u32, info_table_size: u32, copy_table_size: u32) -> Self {
let copy_table_size = copy_table_size as usize;
core::assert!(info_table_size % 4 == 0);
ProgramInfoBuilder {
addr,
buf: {
let mut x = [0xff; 4096];
// mark end of copy table with zero in first entry
x[4096 - copy_table_size + 0] = 0;
x[4096 - copy_table_size + 1] = 0;
x[4096 - copy_table_size + 2] = 0;
x[4096 - copy_table_size + 3] = 0;
x
},
info_pos: 0,
data_pos: info_table_size as usize,
data_end_offset: 4096 - copy_table_size as usize,
info_table_size: info_table_size as usize,
}
}
pub const fn build(mut self: Self) -> [u8; 4096] {
if self.info_pos < self.info_table_size {
self = self.align();
let addr = self.addr + self.data_pos as u32;
self = self.push_u32(0xffffffff).fill_info_table(addr);
}
self.buf
}
const fn push_info_u8(mut self: Self, value: u8) -> Self {
self.buf[self.info_pos] = value;
self.info_pos += 1;
if self.info_pos > self.info_table_size {
core::panic!("ProgramInfoBuilder: too much data for info table")
}
self
}
const fn push_info_ptr(self: Self, value: u32) -> Self {
self
.push_info_u8((value & 0xff) as u8)
.push_info_u8(((value >> 8) & 0xff) as u8)
.push_info_u8(((value >> 16) & 0xff) as u8)
.push_info_u8(((value >> 24) & 0xff) as u8)
}
const fn push_current_info_ptr(mut self: Self) -> Self {
self = self.align();
let addr = self.addr + self.data_pos as u32;
self.push_info_ptr(addr)
}
const fn fill_info_table(mut self: Self, value: u32) -> Self {
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self = self.push_info_ptr(value);
}
if self.info_pos < self.info_table_size {
self.fill_info_table(value)
} else {
self
}
}
const fn push(mut self: Self, value: u8) -> Self {
self.buf[self.data_pos] = value;
self.data_pos += 1;
if self.data_pos > self.data_end_offset {
core::panic!("ProgramInfoBuilder: too much data")
}
self
}
pub const fn align(mut self: Self) -> Self {
if self.data_pos % 4 != 0 {
self = self.push(0xff);
}
if self.data_pos % 4 != 0 {
self = self.push(0xff);
}
if self.data_pos % 4 != 0 {
self = self.push(0xff);
}
self
}
const fn push_u16(self: Self, value: u16) -> Self {
self
.push((value & 0xff) as u8)
.push(((value >> 8) & 0xff) as u8)
}
const fn push_u32(self: Self, value: u32) -> Self {
self
.push((value & 0xff) as u8)
.push(((value >> 8) & 0xff) as u8)
.push(((value >> 16) & 0xff) as u8)
.push(((value >> 24) & 0xff) as u8)
}
const fn push_raspberry_tag(self: Self) -> Self {
self.push('R' as u8)
.push('P' as u8)
}
const fn push_extra_data(mut self: Self, value: &[u8]) -> (Self, u32) {
if self.data_end_offset - self.data_pos < value.len() {
core::panic!("ProgramInfoBuilder: too much data")
}
let offset = self.data_pos;
//self.buf[offset..offset+value.len()].copy_from_slice(value);
self.buf = copy(self.buf, offset, value, 0);
self.data_pos += value.len();
let addr = self.addr + offset as u32;
(self, addr)
}
//NOTE This will push the address and then add the string so this must be the last item of the data record.
const fn push_string(mut self: Self, value: &str) -> Self {
if self.data_pos - self.info_pos < value.len() {
core::panic!("ProgramInfoBuilder: too much data")
}
// push dummy value (will be replaced by address)
let x1 = self.data_pos;
self = self.push_u32(0);
let (self2, addr) = self.push_extra_data(value.as_bytes());
self = self2;
(self, _) = self.push_extra_data(&[0]);
// replace dummy by actual address
let x2 = self.data_pos;
self.data_pos = x1;
self = self.push_u32(addr);
self.data_pos = x2;
self
}
const BINARY_INFO_TYPE_ID_AND_INT: u16 = 5;
const BINARY_INFO_TYPE_ID_AND_STRING: u16 = 6;
pub const BINARY_INFO_ID_RP_PROGRAM_NAME: u32 = 0x02031c86;
pub const BINARY_INFO_ID_RP_PROGRAM_VERSION_STRING: u32 = 0x11a9bc3a;
pub const BINARY_INFO_ID_RP_PROGRAM_BUILD_DATE_STRING: u32 = 0x9da22254;
pub const BINARY_INFO_ID_RP_BINARY_END: u32 = 0x68f465de;
pub const BINARY_INFO_ID_RP_PROGRAM_URL: u32 = 0x1856239a;
pub const BINARY_INFO_ID_RP_PROGRAM_DESCRIPTION: u32 = 0xb6a07c19;
pub const BINARY_INFO_ID_RP_PROGRAM_FEATURE: u32 = 0xa1f4b453;
pub const BINARY_INFO_ID_RP_PROGRAM_BUILD_ATTRIBUTE: u32 = 0x4275f0d3;
pub const BINARY_INFO_ID_RP_SDK_VERSION: u32 = 0x5360b3ab;
pub const BINARY_INFO_ID_RP_PICO_BOARD: u32 = 0xb63cffbb;
pub const BINARY_INFO_ID_RP_BOOT2_NAME: u32 = 0x7f8882e1;
pub const fn program_name(self: Self, value: &str) -> Self {
self.push_current_info_ptr()
.push_u16(Self::BINARY_INFO_TYPE_ID_AND_STRING)
.push_raspberry_tag()
.push_u32(Self::BINARY_INFO_ID_RP_PROGRAM_NAME)
.push_string(value)
}
pub const fn binary_end_address(self: Self, value: u32) -> Self {
self.push_current_info_ptr()
.push_u16(Self::BINARY_INFO_TYPE_ID_AND_INT)
.push_raspberry_tag()
.push_u32(Self::BINARY_INFO_ID_RP_BINARY_END)
.push_u32(value)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment