use crate::common::Result;
use super::ErrorCorrectionLevel;
pub const FORMAT_INFO_MASK_QR: u32 = 0x5412;
pub const FORMAT_INFO_DECODE_LOOKUP: [[u32; 2]; 32] = [
[0x5412, 0x00],
[0x5125, 0x01],
[0x5E7C, 0x02],
[0x5B4B, 0x03],
[0x45F9, 0x04],
[0x40CE, 0x05],
[0x4F97, 0x06],
[0x4AA0, 0x07],
[0x77C4, 0x08],
[0x72F3, 0x09],
[0x7DAA, 0x0A],
[0x789D, 0x0B],
[0x662F, 0x0C],
[0x6318, 0x0D],
[0x6C41, 0x0E],
[0x6976, 0x0F],
[0x1689, 0x10],
[0x13BE, 0x11],
[0x1CE7, 0x12],
[0x19D0, 0x13],
[0x0762, 0x14],
[0x0255, 0x15],
[0x0D0C, 0x16],
[0x083B, 0x17],
[0x355F, 0x18],
[0x3068, 0x19],
[0x3F31, 0x1A],
[0x3A06, 0x1B],
[0x24B4, 0x1C],
[0x2183, 0x1D],
[0x2EDA, 0x1E],
[0x2BED, 0x1F],
];
#[derive(Hash, Eq, PartialEq, Debug)]
pub struct FormatInformation {
pub hammingDistance: u32,
pub error_correction_level: ErrorCorrectionLevel,
pub data_mask: u8,
pub microVersion: u32,
pub isMirrored: bool,
pub index: u8, pub bitsIndex: u8, }
impl Default for FormatInformation {
fn default() -> Self {
Self {
hammingDistance: 255,
error_correction_level: ErrorCorrectionLevel::Invalid,
data_mask: Default::default(),
microVersion: 0,
isMirrored: false,
index: 255,
bitsIndex: 255,
}
}
}
impl FormatInformation {
fn new(format_info: u8) -> Result<Self> {
let errorCorrectionLevel = ErrorCorrectionLevel::forBits((format_info >> 3) & 0x03)?;
let dataMask = format_info & 0x07;
Ok(Self {
hammingDistance: 255,
microVersion: 0,
error_correction_level: errorCorrectionLevel,
data_mask: dataMask,
isMirrored: false,
index: 255,
bitsIndex: 255,
})
}
pub fn numBitsDiffering(a: u32, b: u32) -> u32 {
(a ^ b).count_ones()
}
pub fn decodeFormatInformation(
masked_format_info1: u32,
masked_format_info2: u32,
) -> Option<FormatInformation> {
let formatInfo = Self::doDecodeFormatInformation(masked_format_info1, masked_format_info2);
if formatInfo.is_some() {
return formatInfo;
}
Self::doDecodeFormatInformation(
masked_format_info1 ^ FORMAT_INFO_MASK_QR,
masked_format_info2 ^ FORMAT_INFO_MASK_QR,
)
}
fn doDecodeFormatInformation(
masked_format_info1: u32,
masked_format_info2: u32,
) -> Option<FormatInformation> {
let mut best_difference = u32::MAX;
let mut best_format_info = 0;
for decodeInfo in FORMAT_INFO_DECODE_LOOKUP {
let targetInfo = decodeInfo[0];
if targetInfo == masked_format_info1 || targetInfo == masked_format_info2 {
return FormatInformation::new(decodeInfo[1] as u8).ok();
}
let mut bits_difference = Self::numBitsDiffering(masked_format_info1, targetInfo);
if bits_difference < best_difference {
best_format_info = decodeInfo[1] as u8;
best_difference = bits_difference;
}
if masked_format_info1 != masked_format_info2 {
bits_difference = Self::numBitsDiffering(masked_format_info2, targetInfo);
if bits_difference < best_difference {
best_format_info = decodeInfo[1] as u8;
best_difference = bits_difference;
}
}
}
if best_difference <= 3 {
return FormatInformation::new(best_format_info).ok();
}
None
}
pub fn getErrorCorrectionLevel(&self) -> ErrorCorrectionLevel {
self.error_correction_level
}
pub fn getDataMask(&self) -> u8 {
self.data_mask
}
}