///|
pub(all) enum FirmwareFormat {
IntelHexFormat
SRecordFormat
} derive(Eq, Debug)
///|
pub struct ParsedFirmware {
format_value : FirmwareFormat
image_value : FirmwareImage
record_count_value : Int
} derive(Eq, Debug)
///|
pub struct FirmwareInput {
label_value : String
text_value : String
format_value : FirmwareFormat?
policy_value : OverlapPolicy
} derive(Eq, Debug)
///|
pub struct FirmwareBatchItem {
label_value : String
format_value : FirmwareFormat?
image_value : FirmwareImage?
error_value : FirmwareError?
} derive(Eq, Debug)
///|
pub struct FirmwareBatch {
item_values : Array[FirmwareBatchItem]
success_count_value : Int
failure_count_value : Int
total_bytes_value : Int
} derive(Eq, Debug)
///|
/// Detect Intel HEX or S-record from the first non-line-ending code unit.
pub fn detect_firmware_format(
text : String,
) -> Result[FirmwareFormat, FirmwareError] {
for index = 0; index < text.length(); index = index + 1 {
let code = text[index].to_int()
if code == 13 || code == 10 {
continue
}
if code == 58 {
return Ok(IntelHexFormat)
}
if code == 83 {
return Ok(SRecordFormat)
}
return Err(
FirmwareError::new(
RecordInvalidPrefix,
"firmware text is neither Intel HEX nor Motorola S-record",
SourcePosition::column(0, index),
),
)
}
Err(
FirmwareError::new(
RecordEmpty,
"firmware text contains no records",
SourcePosition::line(0),
),
)
}
///|
/// Parse either supported format and build a canonical sparse image.
pub fn parse_firmware_image(
text : String,
format? : FirmwareFormat? = None,
policy? : OverlapPolicy = RejectOverlap,
) -> Result[ParsedFirmware, FirmwareError] {
let selected = match format {
Some(value) => value
None =>
match detect_firmware_format(text) {
Ok(value) => value
Err(error) => return Err(error)
}
}
match selected {
IntelHexFormat => {
let document = match parse_intel_hex_document(text) {
Ok(value) => value
Err(error) => return Err(error)
}
let count = document.records().length()
let image = match FirmwareImage::from_intel_document(document, policy~) {
Ok(value) => value
Err(error) => return Err(error)
}
Ok({
format_value: selected,
image_value: image,
record_count_value: count,
})
}
SRecordFormat => {
let document = match parse_srecord_document(text) {
Ok(value) => value
Err(error) => return Err(error)
}
let count = document.records().length()
let image = match
FirmwareImage::from_srecord_document(document, policy~) {
Ok(value) => value
Err(error) => return Err(error)
}
Ok({
format_value: selected,
image_value: image,
record_count_value: count,
})
}
}
}
///|
pub fn ParsedFirmware::format(self : ParsedFirmware) -> FirmwareFormat {
self.format_value
}
///|
pub fn ParsedFirmware::image(self : ParsedFirmware) -> FirmwareImage {
self.image_value
}
///|
pub fn ParsedFirmware::record_count(self : ParsedFirmware) -> Int {
self.record_count_value
}
///|
pub fn FirmwareInput::new(
label : String,
text : String,
format? : FirmwareFormat? = None,
policy? : OverlapPolicy = RejectOverlap,
) -> FirmwareInput {
{
label_value: label,
text_value: text,
format_value: format,
policy_value: policy,
}
}
///|
/// Process inputs independently and retain ordered error evidence.
pub fn process_firmware_batch(inputs : Array[FirmwareInput]) -> FirmwareBatch {
let items : Array[FirmwareBatchItem] = []
let mut successes = 0
let mut failures = 0
let mut total_bytes = 0
for input in inputs {
match
parse_firmware_image(
input.text_value,
format=input.format_value,
policy=input.policy_value,
) {
Ok(parsed) => {
let image = parsed.image()
total_bytes = total_bytes + image.total_bytes()
successes = successes + 1
items.push({
label_value: input.label_value,
format_value: Some(parsed.format()),
image_value: Some(image),
error_value: None,
})
}
Err(error) => {
failures = failures + 1
let format = match input.format_value {
Some(value) => Some(value)
None =>
match detect_firmware_format(input.text_value) {
Ok(value) => Some(value)
Err(_) => None
}
}
items.push({
label_value: input.label_value,
format_value: format,
image_value: None,
error_value: Some(error),
})
}
}
}
{
item_values: items,
success_count_value: successes,
failure_count_value: failures,
total_bytes_value: total_bytes,
}
}
///|
pub fn FirmwareBatchItem::label(self : FirmwareBatchItem) -> String {
self.label_value
}
///|
pub fn FirmwareBatchItem::format(self : FirmwareBatchItem) -> FirmwareFormat? {
self.format_value
}
///|
pub fn FirmwareBatchItem::image(self : FirmwareBatchItem) -> FirmwareImage? {
self.image_value
}
///|
pub fn FirmwareBatchItem::error(self : FirmwareBatchItem) -> FirmwareError? {
self.error_value
}
///|
pub fn FirmwareBatch::items(self : FirmwareBatch) -> Array[FirmwareBatchItem] {
self.item_values.copy()
}
///|
pub fn FirmwareBatch::success_count(self : FirmwareBatch) -> Int {
self.success_count_value
}
///|
pub fn FirmwareBatch::failure_count(self : FirmwareBatch) -> Int {
self.failure_count_value
}
///|
pub fn FirmwareBatch::total_bytes(self : FirmwareBatch) -> Int {
self.total_bytes_value
}