use crate::async_proto::{ASYNC_MARKER, ASYNC_TERMINATOR, subcommand_crc};
use crate::codes::{AntennaPortsOption, CommandCode, RegionCode};
use crate::error::ProtocolError;
use crate::frame::{build_host_frame, push_u16_be, push_u32_be};
use crate::parsers::{AntennaPair, AntennaPower, AntennaPowerSettling};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SelectContent {
pub address_bits: u32,
pub bit_len: u16,
pub data: Vec<u8>,
}
impl SelectContent {
pub(crate) fn encode_with_option(&self, out: &mut Vec<u8>, option: InventoryOption) {
let select_option_bits = option.select_option_bits();
if select_option_bits.mode() != Some(SelectMode::Epc) {
push_u32_be(out, self.address_bits);
}
if select_option_bits.extended_data_length() {
out.push((self.bit_len >> 8) as u8);
out.push((self.bit_len & 0xFF) as u8);
} else {
out.push(self.bit_len as u8);
}
out.extend_from_slice(&self.data);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SelectMode {
Disabled = 0x00,
Epc = 0x01,
Tid = 0x02,
UserMemory = 0x03,
EpcBank = 0x04,
PasswordOnly = 0x05,
}
impl SelectMode {
pub const fn as_u8(self) -> u8 {
self as u8
}
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0x00 => Some(SelectMode::Disabled),
0x01 => Some(SelectMode::Epc),
0x02 => Some(SelectMode::Tid),
0x03 => Some(SelectMode::UserMemory),
0x04 => Some(SelectMode::EpcBank),
0x05 => Some(SelectMode::PasswordOnly),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SelectOptionBits(u8);
impl SelectOptionBits {
pub const fn new(mode: SelectMode) -> Self {
Self(mode.as_u8())
}
pub const fn from_raw(raw: u8) -> Self {
Self(raw & 0x2F)
}
pub const fn raw(self) -> u8 {
self.0
}
pub const fn mode(self) -> Option<SelectMode> {
SelectMode::from_u8(self.0 & 0x0F)
}
pub const fn invert_flag(self) -> bool {
(self.0 & 0x08) != 0
}
pub const fn extended_data_length(self) -> bool {
(self.0 & 0x20) != 0
}
pub const fn with_invert_flag(self, en: bool) -> Self {
Self(if en { self.0 | 0x08 } else { self.0 & !0x08 })
}
pub const fn with_extended_data_length(self, en: bool) -> Self {
Self(if en { self.0 | 0x20 } else { self.0 & !0x20 })
}
}
impl From<SelectMode> for SelectOptionBits {
fn from(mode: SelectMode) -> Self {
Self::new(mode)
}
}
impl From<u8> for SelectOptionBits {
fn from(value: u8) -> Self {
Self::from_raw(value)
}
}
impl From<SelectOptionBits> for u8 {
fn from(value: SelectOptionBits) -> Self {
value.raw()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InventoryOption(u8);
impl InventoryOption {
pub const fn default() -> Self {
Self(0)
}
pub const fn from_raw(raw: u8) -> Self {
Self(raw)
}
pub const fn raw(self) -> u8 {
self.0
}
pub const fn select_option_bits(self) -> SelectOptionBits {
SelectOptionBits::from_raw(self.0 & 0x2F)
}
pub const fn single_tag_metadata_enabled(self) -> bool {
(self.0 & 0x10) != 0
}
pub const fn with_single_tag_metadata(self, enabled: bool) -> Self {
if enabled {
Self(self.0 | 0x10)
} else {
Self(self.0 & !0x10)
}
}
}
impl From<u8> for InventoryOption {
fn from(value: u8) -> Self {
Self::from_raw(value)
}
}
impl From<SelectOptionBits> for InventoryOption {
fn from(bits: SelectOptionBits) -> Self {
Self(bits.raw())
}
}
impl From<InventoryOption> for u8 {
fn from(value: InventoryOption) -> Self {
value.raw()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "web-serial", derive(serde::Serialize))]
pub struct InventorySearchFlags(u16);
impl InventorySearchFlags {
pub const fn new() -> Self {
Self(0)
}
pub const fn from_raw(raw: u16) -> Self {
Self(raw)
}
pub const fn raw(self) -> u16 {
self.0
}
pub const fn async_rest_ratio_steps(self) -> u8 {
((self.0 >> 8) & 0x0F) as u8
}
pub const fn async_heartbeat_enabled(self) -> bool {
(self.0 & 0x8000) != 0
}
pub const fn async_auto_stop_enabled(self) -> bool {
(self.0 & 0x4000) != 0
}
pub const fn embedded_command_enabled(self) -> bool {
(self.0 & 0x0004) != 0
}
pub fn with_async_rest_ratio_steps(self, steps: u8) -> Result<Self, ProtocolError> {
if steps > 15 {
return Err(ProtocolError::InvalidArgument(
"async rest ratio steps must be in 0..=15",
));
}
let raw = (self.0 & !(0x0F << 8)) | ((steps as u16) << 8);
Ok(Self(raw))
}
pub const fn with_async_heartbeat(self, enabled: bool) -> Self {
if enabled {
Self(self.0 | 0x8000)
} else {
Self(self.0 & !0x8000)
}
}
pub const fn with_async_auto_stop(self, enabled: bool) -> Self {
if enabled {
Self(self.0 | 0x4000)
} else {
Self(self.0 & !0x4000)
}
}
pub const fn with_embedded_command(self, enabled: bool) -> Self {
if enabled {
Self(self.0 | 0x0004)
} else {
Self(self.0 & !0x0004)
}
}
}
impl From<u16> for InventorySearchFlags {
fn from(value: u16) -> Self {
Self::from_raw(value)
}
}
impl From<InventorySearchFlags> for u16 {
fn from(value: InventorySearchFlags) -> Self {
value.raw()
}
}
impl Default for InventorySearchFlags {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "web-serial", derive(serde::Serialize))]
pub struct MetadataFlags(u16);
impl MetadataFlags {
pub const NONE: Self = Self(0x0000);
pub const ALL: Self = Self(0x00FF);
pub const fn from_raw(raw: u16) -> Self {
Self(raw)
}
pub const fn raw(self) -> u16 {
self.0
}
pub const fn read_count(self) -> bool {
(self.0 & 0x0001) != 0
}
pub const fn rssi(self) -> bool {
(self.0 & 0x0002) != 0
}
pub const fn antenna_id(self) -> bool {
(self.0 & 0x0004) != 0
}
pub const fn frequency(self) -> bool {
(self.0 & 0x0008) != 0
}
pub const fn timestamp(self) -> bool {
(self.0 & 0x0010) != 0
}
pub const fn rfu(self) -> bool {
(self.0 & 0x0020) != 0
}
pub const fn protocol_id(self) -> bool {
(self.0 & 0x0040) != 0
}
pub const fn data_length(self) -> bool {
(self.0 & 0x0080) != 0
}
pub const fn with_read_count(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0001
} else {
self.0 & !0x0001
})
}
pub const fn with_rssi(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0002
} else {
self.0 & !0x0002
})
}
pub const fn with_antenna_id(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0004
} else {
self.0 & !0x0004
})
}
pub const fn with_frequency(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0008
} else {
self.0 & !0x0008
})
}
pub const fn with_timestamp(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0010
} else {
self.0 & !0x0010
})
}
pub const fn with_rfu(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0020
} else {
self.0 & !0x0020
})
}
pub const fn with_protocol_id(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0040
} else {
self.0 & !0x0040
})
}
pub const fn with_data_length(self, en: bool) -> Self {
Self(if en {
self.0 | 0x0080
} else {
self.0 & !0x0080
})
}
}
impl From<u16> for MetadataFlags {
fn from(value: u16) -> Self {
Self::from_raw(value)
}
}
impl From<MetadataFlags> for u16 {
fn from(value: MetadataFlags) -> Self {
value.raw()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum MemBank {
Reserved = 0x00,
Epc = 0x01,
Tid = 0x02,
User = 0x03,
}
impl MemBank {
pub const fn as_u8(self) -> u8 {
self as u8
}
pub fn from_u8(raw: u8) -> Result<Self, ProtocolError> {
match raw {
0x00 => Ok(Self::Reserved),
0x01 => Ok(Self::Epc),
0x02 => Ok(Self::Tid),
0x03 => Ok(Self::User),
_ => Err(ProtocolError::InvalidArgument(
"membank must be one of 0x00..=0x03",
)),
}
}
}
impl From<MemBank> for u8 {
fn from(value: MemBank) -> Self {
value.as_u8()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InventoryEmbeddedCommandContent {
ReadTagData(EmbeddedReadTagData),
}
impl InventoryEmbeddedCommandContent {
fn encoded_len(&self) -> usize {
match self {
Self::ReadTagData(cmd) => 3 + cmd.data_field_len(),
}
}
fn encode(&self, out: &mut Vec<u8>) {
match self {
Self::ReadTagData(cmd) => cmd.encode(out),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EmbeddedReadTagData {
pub read_membank: MemBank,
pub read_address_words: u32,
pub word_count: u8,
}
impl EmbeddedReadTagData {
fn data_field_len(&self) -> usize {
9
}
fn encode(&self, out: &mut Vec<u8>) {
out.push(0x01);
out.push(self.data_field_len() as u8);
out.push(CommandCode::ReadTagData.as_u8());
push_u16_be(out, 0x0000);
out.push(0x00);
out.push(self.read_membank.as_u8());
push_u32_be(out, self.read_address_words);
out.push(self.word_count);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum AsyncSubcommandCode {
Start = 0xAA48,
Stop = 0xAA49,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AsyncInventoryStartData {
pub metadata_flags: MetadataFlags,
pub option: InventoryOption,
pub search_flags: InventorySearchFlags,
pub access_password: Option<u32>,
pub select_content: Option<SelectContent>,
pub embedded_command_content: Option<InventoryEmbeddedCommandContent>,
}
impl AsyncInventoryStartData {
fn encode(&self) -> Vec<u8> {
let mut data = Vec::with_capacity(
2 + 1
+ 2
+ if self.access_password.is_some() { 4 } else { 0 }
+ self
.select_content
.as_ref()
.map(|s| 4 + 2 + s.data.len()) .unwrap_or(0)
+ self
.embedded_command_content
.as_ref()
.map(InventoryEmbeddedCommandContent::encoded_len)
.unwrap_or(0),
);
push_u16_be(&mut data, self.metadata_flags.raw());
data.push(self.option.raw());
push_u16_be(&mut data, self.search_flags.raw());
if let Some(password) = self.access_password {
push_u32_be(&mut data, password);
}
if let Some(select) = &self.select_content {
select.encode_with_option(&mut data, self.option);
}
if let Some(embedded) = &self.embedded_command_content {
embedded.encode(&mut data);
}
data
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AntennaPortsConfiguration {
AccessPair(AntennaPair),
InventoryPairs(Vec<AntennaPair>),
Power(Vec<AntennaPower>),
PowerAndSettling(Vec<AntennaPowerSettling>),
}
impl AntennaPortsConfiguration {
fn encode(&self) -> Result<Vec<u8>, ProtocolError> {
match self {
Self::AccessPair(pair) => Ok(vec![
AntennaPortsOption::AccessPair.as_u8(),
pair.tx,
pair.rx,
]),
Self::InventoryPairs(pairs) => {
if pairs.is_empty() {
return Err(ProtocolError::InvalidArgument(
"inventory antenna pairs cannot be empty",
));
}
let mut data = Vec::with_capacity(1 + pairs.len() * 2);
data.push(AntennaPortsOption::InventoryPairs.as_u8());
for pair in pairs {
data.push(pair.tx);
data.push(pair.rx);
}
Ok(data)
}
Self::Power(entries) => {
if entries.is_empty() {
return Err(ProtocolError::InvalidArgument(
"antenna power entries cannot be empty",
));
}
let mut data = Vec::with_capacity(1 + entries.len() * 5);
data.push(AntennaPortsOption::Power.as_u8());
for entry in entries {
data.push(entry.tx);
push_u16_be(&mut data, entry.read_power);
push_u16_be(&mut data, entry.write_power);
}
Ok(data)
}
Self::PowerAndSettling(entries) => {
if entries.is_empty() {
return Err(ProtocolError::InvalidArgument(
"antenna power and settling entries cannot be empty",
));
}
let mut data = Vec::with_capacity(1 + entries.len() * 7);
data.push(AntennaPortsOption::PowerAndSettling.as_u8());
for entry in entries {
data.push(entry.tx);
push_u16_be(&mut data, entry.read_power);
push_u16_be(&mut data, entry.write_power);
push_u16_be(&mut data, entry.settling_time_us);
}
Ok(data)
}
}
}
}
pub struct HostCommand;
impl HostCommand {
pub fn raw(command: u8, data: &[u8]) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(command, data)
}
pub fn write_flash(
finflag: u8,
write_addr: u32,
write_data: &[u8],
) -> Result<Vec<u8>, ProtocolError> {
if write_data.is_empty() || (write_data.len() % 4 != 0) {
return Err(ProtocolError::InvalidArgument(
"write_data must be non-empty and a multiple of 4 bytes",
));
}
if write_data.len() > 128 {
return Err(ProtocolError::InvalidArgument(
"write_data cannot exceed 128 bytes",
));
}
let words = (write_data.len() / 4) as u8;
let mut data = Vec::with_capacity(1 + 4 + 1 + write_data.len());
data.push(finflag);
push_u32_be(&mut data, write_addr);
data.push(words);
data.extend_from_slice(write_data);
build_host_frame(CommandCode::WriteFlash.as_u8(), &data)
}
pub fn read_flash(read_addr: u32, read_len_words: u8) -> Result<Vec<u8>, ProtocolError> {
if read_len_words > 32 {
return Err(ProtocolError::InvalidArgument(
"read_len_words must be <= 32",
));
}
let mut data = Vec::with_capacity(5);
push_u32_be(&mut data, read_addr);
data.push(read_len_words);
build_host_frame(CommandCode::ReadFlash.as_u8(), &data)
}
pub fn get_version() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetVersion.as_u8(), &[])
}
pub fn boot_firmware() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::BootFirmware.as_u8(), &[])
}
pub fn set_baud_rate(baud_rate: u32) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::with_capacity(4);
push_u32_be(&mut data, baud_rate);
build_host_frame(CommandCode::SetBaudRate.as_u8(), &data)
}
pub fn verify_firmware(
check_addr: u32,
check_data_len_words: u32,
check_crc: u32,
) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::with_capacity(12);
push_u32_be(&mut data, check_addr);
push_u32_be(&mut data, check_data_len_words);
push_u32_be(&mut data, check_crc);
build_host_frame(CommandCode::VerifyFirmware.as_u8(), &data)
}
pub fn boot_bootloader() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::BootBootloader.as_u8(), &[])
}
pub fn get_run_phase() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetRunPhase.as_u8(), &[])
}
pub fn get_serial_number(option: u8, data_flags: u8) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetSerialNumber.as_u8(), &[option, data_flags])
}
pub fn single_tag_inventory(
timeout_ms: u16,
option: InventoryOption,
metadata_flags: Option<MetadataFlags>,
select: Option<SelectContent>,
) -> Result<Vec<u8>, ProtocolError> {
if option.single_tag_metadata_enabled() && metadata_flags.is_none() {
return Err(ProtocolError::InvalidArgument(
"single_tag_inventory requires metadata_flags when option bit 4 (0x10) is set",
));
}
if !option.single_tag_metadata_enabled() && metadata_flags.is_some() {
return Err(ProtocolError::InvalidArgument(
"single_tag_inventory must omit metadata_flags when option bit 4 (0x10) is clear",
));
}
let mut data = Vec::new();
push_u16_be(&mut data, timeout_ms);
data.push(option.raw());
if let Some(flags) = metadata_flags {
push_u16_be(&mut data, flags.raw());
}
if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
build_host_frame(CommandCode::SingleTagInventory.as_u8(), &data)
}
pub fn synchronous_inventory(
option: InventoryOption,
search_flags: u16,
timeout_ms: u16,
access_password: Option<u32>,
select: Option<SelectContent>,
embedded_command: Option<&[u8]>,
) -> Result<Vec<u8>, ProtocolError> {
Self::synchronous_inventory_raw_embedded(
option,
InventorySearchFlags::from_raw(search_flags),
timeout_ms,
access_password,
select,
embedded_command,
)
}
pub fn synchronous_inventory_typed(
option: InventoryOption,
search_flags: InventorySearchFlags,
timeout_ms: u16,
access_password: Option<u32>,
select: Option<SelectContent>,
embedded_command: Option<InventoryEmbeddedCommandContent>,
) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::new();
data.push(option.raw());
push_u16_be(&mut data, search_flags.raw());
push_u16_be(&mut data, timeout_ms);
if let Some(pw) = access_password {
push_u32_be(&mut data, pw);
}
if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
if let Some(embedded) = embedded_command {
embedded.encode(&mut data);
}
build_host_frame(CommandCode::SynchronousInventory.as_u8(), &data)
}
pub fn synchronous_inventory_raw_embedded(
option: InventoryOption,
search_flags: InventorySearchFlags,
timeout_ms: u16,
access_password: Option<u32>,
select: Option<SelectContent>,
embedded_command: Option<&[u8]>,
) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::new();
data.push(option.raw());
push_u16_be(&mut data, search_flags.raw());
push_u16_be(&mut data, timeout_ms);
if let Some(pw) = access_password {
push_u32_be(&mut data, pw);
}
if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
if let Some(embedded) = embedded_command {
data.extend_from_slice(embedded);
}
build_host_frame(CommandCode::SynchronousInventory.as_u8(), &data)
}
pub fn get_tag_buffer(
metadata_flags: MetadataFlags,
option: InventoryOption,
) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::with_capacity(3);
push_u16_be(&mut data, metadata_flags.raw());
data.push(option.raw());
build_host_frame(CommandCode::GetTagBuffer.as_u8(), &data)
}
pub fn write_tag_epc(
timeout_ms: u16,
option: InventoryOption,
access_password: Option<u32>,
select: Option<SelectContent>,
epc: &[u8],
) -> Result<Vec<u8>, ProtocolError> {
if epc.is_empty() {
return Err(ProtocolError::InvalidArgument("epc cannot be empty"));
}
let mut data = Vec::new();
push_u16_be(&mut data, timeout_ms);
data.push(option.raw());
if option.raw() == 0x00 {
data.push(0x00); }
if option.raw() != 0x00 {
if let Some(pw) = access_password {
push_u32_be(&mut data, pw);
} else {
push_u32_be(&mut data, 0x00000000);
}
}
if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
data.extend_from_slice(epc);
build_host_frame(CommandCode::WriteTagEpc.as_u8(), &data)
}
pub fn write_tag_data(
timeout_ms: u16,
option: InventoryOption,
write_address_words: u32,
write_membank: MemBank,
access_password: Option<u32>,
select: Option<SelectContent>,
write_data: &[u8],
) -> Result<Vec<u8>, ProtocolError> {
if write_data.is_empty() || (write_data.len() % 2 != 0) {
return Err(ProtocolError::InvalidArgument(
"write_data must be non-empty and multiple of 2 bytes",
));
}
if write_data.len() > 64 {
return Err(ProtocolError::InvalidArgument(
"write_data must be <= 64 bytes",
));
}
let mut data = Vec::new();
push_u16_be(&mut data, timeout_ms);
data.push(option.raw());
push_u32_be(&mut data, write_address_words);
data.push(write_membank.as_u8());
if let Some(pw) = access_password {
push_u32_be(&mut data, pw);
} else {
push_u32_be(&mut data, 0x00000000);
}
if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
data.extend_from_slice(write_data);
build_host_frame(CommandCode::WriteTagData.as_u8(), &data)
}
pub fn lock_tag(
timeout_ms: u16,
option: InventoryOption,
access_password: u32,
mask_bits: u16,
action_bits: u16,
select: Option<SelectContent>,
) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::new();
push_u16_be(&mut data, timeout_ms);
data.push(option.raw());
push_u32_be(&mut data, access_password);
push_u16_be(&mut data, mask_bits);
push_u16_be(&mut data, action_bits);
if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
build_host_frame(CommandCode::LockTag.as_u8(), &data)
}
pub fn kill_tag(
timeout_ms: u16,
option: InventoryOption,
kill_password: u32,
select: Option<SelectContent>,
) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::new();
push_u16_be(&mut data, timeout_ms);
data.push(option.raw());
push_u32_be(&mut data, kill_password);
data.push(0x00); if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
build_host_frame(CommandCode::KillTag.as_u8(), &data)
}
pub fn read_tag_data(
timeout_ms: u16,
option: InventoryOption,
metadata_flags: Option<MetadataFlags>,
read_membank: MemBank,
read_address_words: u32,
word_count: u8,
access_password: Option<u32>,
select: Option<SelectContent>,
) -> Result<Vec<u8>, ProtocolError> {
if word_count == 0 || word_count > 96 {
return Err(ProtocolError::InvalidArgument(
"word_count must be in 1..=96",
));
}
let mut data = Vec::new();
push_u16_be(&mut data, timeout_ms);
data.push(option.raw());
if let Some(flags) = metadata_flags {
push_u16_be(&mut data, flags.raw());
}
data.push(read_membank.as_u8());
push_u32_be(&mut data, read_address_words);
data.push(word_count);
if let Some(pw) = access_password {
push_u32_be(&mut data, pw);
} else {
push_u32_be(&mut data, 0x00000000);
}
if let Some(sel) = select {
sel.encode_with_option(&mut data, option);
}
println!("Read Tag Data command data: {:02X?}", data);
build_host_frame(CommandCode::ReadTagData.as_u8(), &data)
}
pub fn set_antenna_ports(config: &AntennaPortsConfiguration) -> Result<Vec<u8>, ProtocolError> {
let data = config.encode()?;
build_host_frame(CommandCode::SetAntennaPorts.as_u8(), &data)
}
pub fn set_current_tag_protocol(protocol: u16) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::with_capacity(2);
push_u16_be(&mut data, protocol);
build_host_frame(CommandCode::SetCurrentTagProtocol.as_u8(), &data)
}
pub fn set_frequency_hopping(data_field: &[u8]) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::SetFrequencyHopping.as_u8(), data_field)
}
pub fn set_gpo(data_field: &[u8]) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::SetGpo.as_u8(), data_field)
}
pub fn set_current_region(region_code: RegionCode) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(
CommandCode::SetCurrentRegion.as_u8(),
&[region_code.as_u8()],
)
}
pub fn set_reader_configuration(
option: u8,
key: u8,
value: u8,
) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(
CommandCode::SetReaderConfiguration.as_u8(),
&[option, key, value],
)
}
pub fn set_protocol_configuration(
protocol_value: u8,
parameter: u8,
option: Option<u8>,
value: Option<u8>,
) -> Result<Vec<u8>, ProtocolError> {
let mut data = vec![protocol_value, parameter];
if let Some(opt) = option {
data.push(opt);
}
if let Some(v) = value {
data.push(v);
}
build_host_frame(CommandCode::SetProtocolConfiguration.as_u8(), &data)
}
pub fn get_antenna_ports(option: AntennaPortsOption) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetAntennaPorts.as_u8(), &[option.as_u8()])
}
pub fn get_current_tag_protocol() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetCurrentTagProtocol.as_u8(), &[])
}
pub fn get_frequency_hopping(option: Option<u8>) -> Result<Vec<u8>, ProtocolError> {
match option {
Some(v) => build_host_frame(CommandCode::GetFrequencyHopping.as_u8(), &[v]),
None => build_host_frame(CommandCode::GetFrequencyHopping.as_u8(), &[]),
}
}
pub fn get_gpi() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetGpi.as_u8(), &[])
}
pub fn get_current_region() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetCurrentRegion.as_u8(), &[])
}
pub fn get_available_regions() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetAvailableRegions.as_u8(), &[])
}
pub fn get_reader_configuration(option: u8, key: u8) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetReaderConfiguration.as_u8(), &[option, key])
}
pub fn get_protocol_configuration(
protocol_value: u8,
parameter: u8,
) -> Result<Vec<u8>, ProtocolError> {
build_host_frame(
CommandCode::GetProtocolConfiguration.as_u8(),
&[protocol_value, parameter],
)
}
pub fn get_current_temperature() -> Result<Vec<u8>, ProtocolError> {
build_host_frame(CommandCode::GetCurrentTemperature.as_u8(), &[])
}
pub fn async_start(start: &AsyncInventoryStartData) -> Result<Vec<u8>, ProtocolError> {
let subcommand_data = start.encode();
Self::async_inventory(AsyncSubcommandCode::Start, &subcommand_data)
}
pub fn async_stop() -> Result<Vec<u8>, ProtocolError> {
Self::async_inventory(AsyncSubcommandCode::Stop, &[])
}
pub fn async_inventory(
subcommand: AsyncSubcommandCode,
subcommand_data: &[u8],
) -> Result<Vec<u8>, ProtocolError> {
let mut data = Vec::with_capacity(10 + 2 + subcommand_data.len() + 2);
data.extend_from_slice(ASYNC_MARKER);
push_u16_be(&mut data, subcommand as u16);
data.extend_from_slice(subcommand_data);
let sub_crc = subcommand_crc(subcommand as u16, subcommand_data);
data.push(sub_crc);
data.push(ASYNC_TERMINATOR);
build_host_frame(CommandCode::AsynchronousInventory.as_u8(), &data)
}
}