implement CRC write
Some checks failed
Rust/va416xx-rs/pipeline/pr-main There was a failure building this commit
Some checks failed
Rust/va416xx-rs/pipeline/pr-main There was a failure building this commit
This commit is contained in:
parent
1cc8645781
commit
1b313d21c4
@ -34,3 +34,4 @@ debug-assertions = false # <-
|
|||||||
lto = true
|
lto = true
|
||||||
opt-level = 'z' # <-
|
opt-level = 'z' # <-
|
||||||
overflow-checks = false # <-
|
overflow-checks = false # <-
|
||||||
|
strip = true # Automatically strip symbols from the binary.
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
use cortex_m_rt::entry;
|
use cortex_m_rt::entry;
|
||||||
use crc::{Crc, CRC_16_IBM_3740};
|
use crc::{Crc, CRC_32_ISO_HDLC};
|
||||||
use panic_rtt_target as _;
|
use panic_rtt_target as _;
|
||||||
use rtt_target::{rprintln, rtt_init_print};
|
use rtt_target::{rprintln, rtt_init_print};
|
||||||
use va416xx_hal::{
|
use va416xx_hal::{
|
||||||
@ -47,7 +47,7 @@ const FLASH_SELF: bool = false;
|
|||||||
|
|
||||||
const BOOTLOADER_START_ADDR: u32 = 0x0;
|
const BOOTLOADER_START_ADDR: u32 = 0x0;
|
||||||
const BOOTLOADER_END_ADDR: u32 = 0x4000;
|
const BOOTLOADER_END_ADDR: u32 = 0x4000;
|
||||||
const BOOTLOADER_CRC_ADDR: u32 = 0x3FFE;
|
const BOOTLOADER_CRC_ADDR: u32 = 0x3FFC;
|
||||||
const APP_A_START_ADDR: u32 = 0x4000;
|
const APP_A_START_ADDR: u32 = 0x4000;
|
||||||
pub const APP_A_END_ADDR: u32 = 0x22000;
|
pub const APP_A_END_ADDR: u32 = 0x22000;
|
||||||
// The actual size of the image which is relevant for CRC calculation.
|
// The actual size of the image which is relevant for CRC calculation.
|
||||||
@ -64,7 +64,7 @@ pub const VECTOR_TABLE_OFFSET: u32 = 0x0;
|
|||||||
pub const VECTOR_TABLE_LEN: u32 = 0x350;
|
pub const VECTOR_TABLE_LEN: u32 = 0x350;
|
||||||
pub const RESET_VECTOR_OFFSET: u32 = 0x4;
|
pub const RESET_VECTOR_OFFSET: u32 = 0x4;
|
||||||
|
|
||||||
const CRC_ALGO: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740);
|
const CRC_ALGO: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
enum AppSel {
|
enum AppSel {
|
||||||
@ -111,6 +111,7 @@ fn main() -> ! {
|
|||||||
WDT_FREQ_MS,
|
WDT_FREQ_MS,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let nvm = Nvm::new(&mut dp.sysconfig, dp.spi3, &clocks);
|
let nvm = Nvm::new(&mut dp.sysconfig, dp.spi3, &clocks);
|
||||||
|
|
||||||
if FLASH_SELF {
|
if FLASH_SELF {
|
||||||
@ -172,7 +173,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
|
fn check_own_crc(wdt: &OptWdt, nvm: &Nvm, cp: &cortex_m::Peripherals) {
|
||||||
let crc_exp = unsafe { *(BOOTLOADER_CRC_ADDR as *const u16) };
|
let crc_exp = unsafe { *(BOOTLOADER_CRC_ADDR as *const u32) };
|
||||||
wdt.feed();
|
wdt.feed();
|
||||||
// I'd prefer to use [core::slice::from_raw_parts], but that is problematic
|
// I'd prefer to use [core::slice::from_raw_parts], but that is problematic
|
||||||
// because the address of the bootloader is 0x0, so the NULL check fails and the functions
|
// because the address of the bootloader is 0x0, so the NULL check fails and the functions
|
||||||
@ -219,7 +220,7 @@ fn check_app_given_addr(
|
|||||||
image_size_addr: u32,
|
image_size_addr: u32,
|
||||||
wdt: &OptWdt,
|
wdt: &OptWdt,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let crc_exp = unsafe { *(crc_addr as *const u16) };
|
let crc_exp = unsafe { *(crc_addr as *const u32) };
|
||||||
let image_size = unsafe { *(image_size_addr as *const u32) };
|
let image_size = unsafe { *(image_size_addr as *const u32) };
|
||||||
wdt.feed();
|
wdt.feed();
|
||||||
let crc_calc = CRC_ALGO.checksum(unsafe {
|
let crc_calc = CRC_ALGO.checksum(unsafe {
|
||||||
|
@ -10,6 +10,7 @@ import time
|
|||||||
from tmtccmd.com.serial_base import SerialCfg
|
from tmtccmd.com.serial_base import SerialCfg
|
||||||
from tmtccmd.com.serial_cobs import SerialCobsComIF
|
from tmtccmd.com.serial_cobs import SerialCobsComIF
|
||||||
from tmtccmd.com.ser_utils import prompt_com_port
|
from tmtccmd.com.ser_utils import prompt_com_port
|
||||||
|
from crcmod.predefined import PredefinedCrc
|
||||||
from spacepackets.ecss.tc import PusTc
|
from spacepackets.ecss.tc import PusTc
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import dataclasses
|
import dataclasses
|
||||||
@ -19,7 +20,7 @@ from elftools.elf.elffile import ELFFile
|
|||||||
BAUD_RATE = 115200
|
BAUD_RATE = 115200
|
||||||
BOOTLOADER_START_ADDR = 0x0
|
BOOTLOADER_START_ADDR = 0x0
|
||||||
BOOTLOADER_END_ADDR = 0x4000
|
BOOTLOADER_END_ADDR = 0x4000
|
||||||
BOOTLOADER_CRC_ADDR = 0x3FFE
|
BOOTLOADER_CRC_ADDR = 0x3FFC
|
||||||
APP_A_START_ADDR = 0x4000
|
APP_A_START_ADDR = 0x4000
|
||||||
APP_A_END_ADDR = 0x22000
|
APP_A_END_ADDR = 0x22000
|
||||||
# The actual size of the image which is relevant for CRC calculation.
|
# The actual size of the image which is relevant for CRC calculation.
|
||||||
@ -104,9 +105,29 @@ def main() -> int:
|
|||||||
with open(file_path, "rb") as app_file:
|
with open(file_path, "rb") as app_file:
|
||||||
elf_file = ELFFile(app_file)
|
elf_file = ELFFile(app_file)
|
||||||
|
|
||||||
for segment in elf_file.iter_segments("PT_LOAD"):
|
for (idx, segment) in enumerate(elf_file.iter_segments("PT_LOAD")):
|
||||||
if segment.header.p_filesz == 0:
|
if segment.header.p_filesz == 0:
|
||||||
continue
|
continue
|
||||||
|
# Basic validity checks of the base addresses.
|
||||||
|
if idx == 0:
|
||||||
|
if (
|
||||||
|
args.flash == "bl"
|
||||||
|
and segment.header.p_paddr != BOOTLOADER_START_ADDR
|
||||||
|
):
|
||||||
|
raise ValueError(
|
||||||
|
f"detected possibly invalid start address {segment.header.p_paddr} for "
|
||||||
|
f"bootloader, expected {BOOTLOADER_START_ADDR}"
|
||||||
|
)
|
||||||
|
if args.flash == "a" and segment.header.p_paddr != APP_A_START_ADDR:
|
||||||
|
raise ValueError(
|
||||||
|
f"detected possibly invalid start address {segment.header.p_paddr} for "
|
||||||
|
f"App A, expected {APP_A_START_ADDR}"
|
||||||
|
)
|
||||||
|
if args.flash == "b" and segment.header.p_paddr != APP_B_START_ADDR:
|
||||||
|
raise ValueError(
|
||||||
|
f"detected possibly invalid start address {segment.header.p_paddr} for "
|
||||||
|
f"App B, expected {APP_B_START_ADDR}"
|
||||||
|
)
|
||||||
name = None
|
name = None
|
||||||
for section in elf_file.iter_sections():
|
for section in elf_file.iter_sections():
|
||||||
if (
|
if (
|
||||||
@ -138,24 +159,28 @@ def main() -> int:
|
|||||||
next_chunk_size = segment.offset + segment.size - current_addr
|
next_chunk_size = segment.offset + segment.size - current_addr
|
||||||
if next_chunk_size > CHUNK_SIZE:
|
if next_chunk_size > CHUNK_SIZE:
|
||||||
next_chunk_size = CHUNK_SIZE
|
next_chunk_size = CHUNK_SIZE
|
||||||
app_data = bytearray()
|
next_packet = pack_memory_write_command(
|
||||||
app_data.append(BOOT_NVM_MEMORY_ID)
|
current_addr,
|
||||||
# N parameter is always 1 here.
|
segment.data[current_addr : current_addr + next_chunk_size],
|
||||||
app_data.append(1)
|
|
||||||
app_data.extend(struct.pack("!I", current_addr))
|
|
||||||
app_data.extend(struct.pack("!I", next_chunk_size))
|
|
||||||
app_data.extend(
|
|
||||||
segment.data[current_addr : current_addr + next_chunk_size]
|
|
||||||
)
|
)
|
||||||
current_addr += next_chunk_size
|
current_addr += next_chunk_size
|
||||||
next_packet = PusTc(
|
|
||||||
apid=0,
|
|
||||||
service=MEMORY_SERVICE,
|
|
||||||
subservice=RAW_MEMORY_WRITE_SUBSERVICE,
|
|
||||||
app_data=app_data,
|
|
||||||
)
|
|
||||||
com_if.send(next_packet.pack())
|
com_if.send(next_packet.pack())
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
crc_calc = PredefinedCrc("crc-32")
|
||||||
|
for segment in loadable_segments:
|
||||||
|
crc_calc.update(segment)
|
||||||
|
if args.flash == "bl":
|
||||||
|
crc_addr = BOOTLOADER_CRC_ADDR
|
||||||
|
elif args.flash == "a":
|
||||||
|
crc_addr = APP_A_CRC_ADDR
|
||||||
|
elif args.flash == "b":
|
||||||
|
crc_addr = APP_B_CRC_ADDR
|
||||||
|
else:
|
||||||
|
raise ValueError(f"unknown flash target {args.flash}")
|
||||||
|
checksum = crc_calc.digest()
|
||||||
|
checksum_write_packet = pack_memory_write_command(crc_addr, checksum)
|
||||||
|
com_if.send(checksum_write_packet.pack())
|
||||||
|
time.sleep(0.5)
|
||||||
while True:
|
while True:
|
||||||
data_available = com_if.data_available(0.4)
|
data_available = com_if.data_available(0.4)
|
||||||
if data_available:
|
if data_available:
|
||||||
@ -167,5 +192,21 @@ def main() -> int:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def pack_memory_write_command(addr: int, data: bytes) -> PusTc:
|
||||||
|
app_data = bytearray()
|
||||||
|
app_data.append(BOOT_NVM_MEMORY_ID)
|
||||||
|
# N parameter is always 1 here.
|
||||||
|
app_data.append(1)
|
||||||
|
app_data.extend(struct.pack("!I", addr))
|
||||||
|
app_data.extend(struct.pack("!I", len(data)))
|
||||||
|
app_data.extend(data)
|
||||||
|
return PusTc(
|
||||||
|
apid=0,
|
||||||
|
service=MEMORY_SERVICE,
|
||||||
|
subservice=RAW_MEMORY_WRITE_SUBSERVICE,
|
||||||
|
app_data=app_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
spacepackets == 0.24
|
spacepackets == 0.24
|
||||||
tmtccmd == 8.0.1
|
tmtccmd == 8.0.2
|
||||||
toml == 0.10
|
toml == 0.10
|
||||||
pyelftools == 0.31
|
pyelftools == 0.31
|
||||||
|
crcmod == 1.7
|
||||||
|
@ -52,6 +52,7 @@ static CLOCKS: OnceCell<Clocks> = OnceCell::new();
|
|||||||
#[rtic::app(device = pac, dispatchers = [U1, U2, U3])]
|
#[rtic::app(device = pac, dispatchers = [U1, U2, U3])]
|
||||||
mod app {
|
mod app {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use cortex_m::asm;
|
||||||
use embedded_hal_nb::nb;
|
use embedded_hal_nb::nb;
|
||||||
use panic_rtt_target as _;
|
use panic_rtt_target as _;
|
||||||
use rtic::Mutex;
|
use rtic::Mutex;
|
||||||
@ -157,8 +158,9 @@ mod app {
|
|||||||
// `shared` cannot be accessed from this context
|
// `shared` cannot be accessed from this context
|
||||||
#[idle]
|
#[idle]
|
||||||
fn idle(_cx: idle::Context) -> ! {
|
fn idle(_cx: idle::Context) -> ! {
|
||||||
#[allow(clippy::empty_loop)]
|
loop {
|
||||||
loop {}
|
asm::nop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(
|
#[task(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user