///|
fn hex_digit_value(code : Int) -> Int {
if code >= 48 && code <= 57 {
code - 48
} else if code >= 65 && code <= 70 {
code - 55
} else if code >= 97 && code <= 102 {
code - 87
} else {
-1
}
}
///|
fn hex_character(value : Int) -> String {
let digits = "0123456789ABCDEF"
match digits[value & 0xF].to_char() {
Some(character) => character.to_string()
None => "?"
}
}
///|
/// Decode an even-length hexadecimal string without ignoring whitespace.
pub fn decode_hex_bytes(
text : String,
line_index? : Int = 0,
) -> Result[Bytes, FirmwareError] {
if text.length() % 2 != 0 {
return Err(
FirmwareError::new(
HexOddLength,
"hexadecimal input must contain an even number of digits",
SourcePosition::line(line_index),
),
)
}
for index = 0; index < text.length(); index = index + 1 {
if hex_digit_value(text[index].to_int()) < 0 {
return Err(
FirmwareError::new(
HexInvalidDigit,
"hexadecimal input contains an invalid digit",
SourcePosition::column(line_index, index),
),
)
}
}
Ok(
Bytes::makei(text.length() / 2, index => {
let high = hex_digit_value(text[index * 2].to_int())
let low = hex_digit_value(text[index * 2 + 1].to_int())
(high * 16 + low).to_byte()
}),
)
}
///|
/// Encode bytes using two uppercase hexadecimal digits per byte.
pub fn encode_hex_bytes(bytes : Bytes) -> String {
let mut result = ""
for byte in bytes {
let value = byte.to_int()
result = result + hex_character(value >> 4) + hex_character(value)
}
result
}
///|
/// Return the low eight bits of the sum of all bytes.
pub fn checksum_sum(bytes : Bytes) -> Int {
let mut sum = 0
for byte in bytes {
sum = (sum + byte.to_int()) & 0xFF
}
sum
}
///|
/// Calculate the Intel HEX two's-complement checksum byte.
pub fn twos_complement_checksum(bytes : Bytes) -> Byte {
(-checksum_sum(bytes) & 0xFF).to_byte()
}
///|
/// Verify a byte sequence that includes its Intel HEX checksum byte.
pub fn twos_complement_valid(bytes : Bytes) -> Bool {
checksum_sum(bytes) == 0
}
///|
/// Calculate the Motorola S-record one's-complement checksum byte.
pub fn ones_complement_checksum(bytes : Bytes) -> Byte {
(0xFF - checksum_sum(bytes)).to_byte()
}
///|
/// Verify a byte sequence that includes its S-record checksum byte.
pub fn ones_complement_valid(bytes : Bytes) -> Bool {
checksum_sum(bytes) == 0xFF
}