use bitreader::BitReader;
use num_enum::TryFromPrimitive;
use std::convert::TryFrom;
use crate::error::{Error, Result};
pub(crate) const START_BYTE: u8 = 0xA0;
#[derive(Copy, Clone, PartialEq, Debug, TryFromPrimitive)]
#[repr(u8)]
pub(crate) enum CommandType {
Reset = 0x70,
SetUARTBaudRate = 0x71,
GetFirmwareVersion = 0x72,
SetReaderAddress = 0x73,
SetWorkAntenna = 0x74,
GetWorkAntenna = 0x75,
SetOutputPower = 0x76,
GetOutputPower = 0x77,
SetFrequencyRegion = 0x78,
GetFrequencyRegion = 0x79,
SetBeeperMode = 0x7A,
GetReaderTemperature = 0x7B,
ReadGPIOValue = 0x60,
WriteGPIOValue = 0x61,
SetAntConnectionDetector = 0x62,
GetAntConnectionDetector = 0x63,
SetTemporaryOutputPower = 0x66,
SetReaderIdentifier = 0x67,
GetReaderIdentifier = 0x68,
SetRFLinkProfile = 0x69,
GetRFLinkProfile = 0x6A,
GetRFPortReturnLoss = 0x7E,
Inventory = 0x80,
Read = 0x81,
Write = 0x82,
Lock = 0x83,
Kill = 0x84,
SetAccessEPCMatch = 0x85,
GetAccessEPCMatch = 0x86,
RealTimeInventory = 0x89,
FastSwitchAntInventory = 0x8A,
CustomizedSessionTargetInventory = 0x8B,
SetImpinjFastTID = 0x8C,
SetAndSaveImpinjFastTIC = 0x8D,
GetImpinjFastTID = 0x8E,
Inventory6B = 0xB0,
Read6B = 0xB1,
Write6B = 0xB2,
Lock6B = 0xB3,
QueryLock6B = 0xB4,
GetInventoryBuffer = 0x90,
GetAndResetInventoryBuffer = 0x91,
GetBufferTagCount = 0x92,
ResetInventoryBuffer = 0x93,
}
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum ResponseCode {
Success = 0x10,
Fail = 0x11,
MCUResetError = 0x20,
CWOnError = 0x21,
AntennaMissingError = 0x22,
WriteFlashError = 0x23,
ReadFlashError = 0x24,
SetOutputPowerError = 0x25,
TagInventoryError = 0x31,
TagReadError = 0x32,
TagWriteError = 0x33,
TagLockError = 0x34,
TagKillError = 0x35,
NoTagError = 0x36,
InventoryOKAccessFailError = 0x37,
BufferEmptyError = 0x38,
AccessFailError = 0x40,
InvalidParameterError = 0x41,
WordCntTooLongError = 0x42,
MemBankOutOfRangeError = 0x43,
LockRegionOutOfRangeError = 0x44,
LockTypeOutOfRangeError = 0x45,
InvalidReaderAddressError = 0x46,
InvalidAntennaIDError = 0x47,
OutputPowerOutOfRangeError = 0x48,
InvalidFrequencyRegionError = 0x49,
InvalidBaudRateError = 0x4A,
InvalidBeeperModeError = 0x4B,
EPCMatchLenTooLongError = 0x4C,
EPCMatchLenError = 0x4D,
InvalidEPCMatchModeError = 0x4E,
InvalidFrequencyRangeError = 0x4F,
FailToGetRN16Error = 0x50,
InvalidDRMModeError = 0x51,
PLLLockFailError = 0x52,
RFChipError = 0x53,
FailToAchieveDesiredPowerError = 0x54,
CopyrightAuthenticationError = 0x55,
SpectrumRegulationError = 0x56,
OutputPowerTooLowError = 0x57,
}
fn command_has_response_code(command: CommandType, length: usize) -> bool {
match command {
CommandType::GetFirmwareVersion
| CommandType::GetOutputPower
| CommandType::GetReaderTemperature
| CommandType::GetRFPortReturnLoss
| CommandType::GetWorkAntenna
| CommandType::GetAntConnectionDetector => false,
CommandType::RealTimeInventory | CommandType::Read | CommandType::SetAccessEPCMatch => {
length == 0x04
}
_ => true,
}
}
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum FrequencyRegion {
FCC = 0x01,
ETSI = 0x02,
CHN = 0x03,
UserDefined = 0x04,
}
#[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u8)]
pub enum MemoryBank {
Reserved = 0x00,
EPC = 0x01,
TID = 0x02,
User = 0x03,
}
fn convert_to_frequency(freq: u8) -> f32 {
if freq < 7 {
865. + 0.5 * f32::from(freq)
} else {
902. + 0.5 * f32::from(freq - 7)
}
}
pub(crate) fn convert_from_frequency(frequency: f32) -> Result<u8> {
if frequency >= 865. && frequency <= 868. {
return Ok(((frequency - 865.) / 0.5) as u8);
} else if frequency >= 902. && frequency <= 928. {
return Ok(((frequency - 902.) / 0.5) as u8 + 7);
}
Err(Error::Program(format!("Invalid frequency {}", frequency)))
}
fn convert_rssi(rssi: u8) -> i8 {
if rssi > 89 {
(i16::from(rssi) - 129) as i8
} else {
(i16::from(rssi) - 130) as i8
}
}
fn calculate_checksum(data: &[u8]) -> u8 {
let mut sum: u8 = 0;
for byte in data {
let (newsum, _) = sum.overflowing_add(*byte);
sum = newsum;
}
let (result, _) = (!sum).overflowing_add(1);
result
}
#[derive(PartialEq, Debug)]
pub(crate) struct Command {
pub address: u8,
pub command: CommandType,
pub data: Vec<u8>,
}
impl Command {
pub(crate) fn to_bytes(&self) -> Vec<u8> {
let pkt_len: usize = self.data.len() + 3;
let mut pkt: Vec<u8> = Vec::with_capacity(pkt_len + 2);
pkt.push(START_BYTE);
pkt.push(pkt_len as u8);
pkt.push(self.address);
pkt.push(self.command as u8);
pkt.append(&mut self.data.clone());
pkt.push(calculate_checksum(&pkt));
pkt
}
}
#[derive(PartialEq, Debug)]
pub(crate) struct Response {
pub address: u8,
pub command: CommandType,
pub status: Option<ResponseCode>,
pub data: Vec<u8>,
}
impl Response {
pub(crate) fn from_bytes(data: &[u8]) -> Result<Response> {
assert_eq!(data[0], START_BYTE);
assert_eq!(data[1] as usize, data.len() - 2);
let len = data.len();
let checksum = calculate_checksum(&data[0..len - 1]);
if data[len - 1] != checksum {
return Err(Error::Program(format!(
"Bad checksum: got {:?}, expecting {:?}",
data[len], checksum
)));
}
let command_type = CommandType::try_from(data[3])?;
let response_code = if command_has_response_code(command_type, len - 2) {
Some(ResponseCode::try_from(data[4])?)
} else {
None
};
let data_offset = match response_code {
Some(_) => 5,
None => 4
};
Response {
address: data[2],
command: command_type,
status: response_code,
data: data[data_offset..len - 1].to_owned(),
}
.raise_error()
}
fn raise_error(self) -> Result<Response> {
match self.status {
Some(ResponseCode::Success) => Ok(self),
Some(ResponseCode::NoTagError) => Ok(self),
None => Ok(self),
Some(status) => Err(Error::from(status)),
}
}
}
#[derive(PartialEq, Debug)]
pub struct InventoryItem {
pub frequency: f32,
pub antenna: u8,
pub pc: Vec<u8>,
pub epc: Vec<u8>,
pub rssi: i8,
}
impl InventoryItem {
pub(crate) fn from_bytes(data: &[u8]) -> Result<InventoryItem> {
let first_byte = [data[0]];
let mut reader = BitReader::new(&first_byte);
let len = data.len();
Ok(InventoryItem {
frequency: convert_to_frequency(reader.read_u8(6)?),
antenna: reader.read_u8(2)?,
pc: data[1..3].to_owned(),
epc: data[3..len - 1].to_owned(),
rssi: convert_rssi(data[len - 1]),
})
}
}
#[derive(PartialEq, Debug)]
pub struct InventoryResult {
pub items: Vec<InventoryItem>,
pub antenna: u8,
pub read_rate: u16,
pub total_read: u32,
}
impl InventoryResult {
pub(crate) fn from_bytes(data: &[u8], items: Vec<InventoryItem>) -> Result<InventoryResult> {
let mut reader = BitReader::new(data);
Ok(InventoryResult {
items,
antenna: reader.read_u8(8)?,
read_rate: reader.read_u16(16)?,
total_read: reader.read_u32(32)?,
})
}
}
#[derive(PartialEq, Debug)]
pub struct ReadResult {
pub epc: Vec<u8>,
pub data: Vec<u8>,
pub frequency: f32,
pub antenna: u8,
pub read_count: u8,
}
impl ReadResult {
pub(crate) fn from_bytes(packet: &[u8]) -> Result<(usize, ReadResult)> {
let mut reader = BitReader::new(packet);
let tag_count = reader.read_u16(16)?;
let data_len = reader.read_u8(8)? as usize;
let mut data = Vec::new();
for _i in 0..data_len {
data.push(reader.read_u8(8)?);
}
let read_len = reader.read_u8(8)? as usize;
let frequency = convert_to_frequency(reader.read_u8(6)?);
let antenna = reader.read_u8(2)?;
let read_count = reader.read_u8(8)?;
Ok((
tag_count as usize,
ReadResult {
epc: data[2..(data_len - read_len - 2)].to_vec(),
data: data[(data_len - read_len)..data_len].to_vec(),
frequency,
antenna,
read_count,
},
))
}
}
#[test]
fn test_checksum() {
assert_eq!(calculate_checksum(&[1, 2, 3, 4]), 246);
assert_eq!(calculate_checksum(&[134, 200, 3, 253]), 178);
assert_eq!(calculate_checksum(&[220, 4, 3, 30]), 255);
assert_eq!(calculate_checksum(&[20, 45, 3, 30, 150, 230, 120]), 170);
assert_eq!(calculate_checksum(&[0xA0, 0x03, 0x01, 0x72]), 0xEA);
}
#[test]
fn test_convert_to_frequency() {
assert_eq!(convert_to_frequency(5), 867.5);
assert_eq!(convert_to_frequency(7), 902.0);
assert_eq!(convert_to_frequency(14), 905.5);
assert_eq!(convert_to_frequency(22), 909.5);
assert_eq!(convert_to_frequency(48), 922.5);
assert_eq!(convert_to_frequency(59), 928.0);
}
#[test]
fn test_convert_from_frequency() {
assert_eq!(convert_from_frequency(867.5).unwrap(), 5);
assert_eq!(convert_from_frequency(909.5).unwrap(), 22);
assert_eq!(convert_from_frequency(922.5).unwrap(), 48);
assert_eq!(convert_from_frequency(928.0).unwrap(), 59);
}
#[test]
fn test_read() {
let data = [
160, 33, 1, 129, 0, 1, 24, 48, 0, 48, 57, 96, 98, 195, 149, 13, 64, 0, 17, 184, 151, 205,
11, 226, 128, 104, 144, 32, 0, 80, 1, 8, 11, 1, 141,
];
let res = Response::from_bytes(&data).unwrap();
println!("{:?}", res);
let result = ReadResult::from_bytes(&res.data);
println!("{:?}", result);
}