1#[derive(Debug, Clone)]
5pub struct TagInfo {
6 pub epc: String,
7 pub rssi: u8,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[repr(u8)]
13pub enum MemoryBank {
14 Reserved = 0x00,
16 Epc = 0x01,
18 Tid = 0x02,
20 User = 0x03,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
26#[repr(u8)]
27pub enum SelectTarget {
28 #[default]
30 S0 = 0x00,
31 S1 = 0x01,
33 S2 = 0x02,
35 S3 = 0x03,
37 Sl = 0x04,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
43#[repr(u8)]
44pub enum SelectAction {
45 #[default]
47 Action0 = 0x00,
48 Action1 = 0x01,
50 Action2 = 0x02,
52 Action3 = 0x03,
54 Action4 = 0x04,
56 Action5 = 0x05,
58 Action6 = 0x06,
60 Action7 = 0x07,
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
66#[repr(u8)]
67pub enum SelectMode {
68 Always = 0x00,
70 #[default]
72 Disabled = 0x01,
73 NonPolling = 0x02,
75}
76
77#[derive(Debug, Clone)]
79pub struct SelectParams {
80 pub target: SelectTarget,
82 pub action: SelectAction,
84 pub mem_bank: MemoryBank,
86 pub pointer: u32,
88 pub mask: Vec<u8>,
90 pub truncate: bool,
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96#[repr(u8)]
97pub enum Region {
98 China900 = 0x01,
100 Us = 0x02,
102 Europe = 0x03,
104 China800 = 0x04,
106 Korea = 0x06,
108}
109
110impl Region {
111 pub fn base_frequency(&self) -> f64 {
113 match self {
114 Region::China900 => 920.125,
115 Region::Us => 902.25,
116 Region::Europe => 865.1,
117 Region::China800 => 840.125,
118 Region::Korea => 917.1,
119 }
120 }
121
122 pub fn channel_spacing(&self) -> f64 {
124 match self {
125 Region::China900 => 0.25,
126 Region::Us => 0.5,
127 Region::Europe => 0.2,
128 Region::China800 => 0.25,
129 Region::Korea => 0.2,
130 }
131 }
132
133 pub fn channel_from_frequency(&self, freq_mhz: f64) -> u8 {
135 ((freq_mhz - self.base_frequency()) / self.channel_spacing()) as u8
136 }
137
138 pub fn frequency_from_channel(&self, channel: u8) -> f64 {
140 (channel as f64) * self.channel_spacing() + self.base_frequency()
141 }
142}
143
144impl TryFrom<u8> for Region {
145 type Error = ();
146
147 fn try_from(value: u8) -> Result<Self, Self::Error> {
148 match value {
149 0x01 => Ok(Region::China900),
150 0x02 => Ok(Region::Us),
151 0x03 => Ok(Region::Europe),
152 0x04 => Ok(Region::China800),
153 0x06 => Ok(Region::Korea),
154 _ => Err(()),
155 }
156 }
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub struct QueryParams {
162 pub sel: QuerySel,
164 pub session: QuerySession,
166 pub target: QueryTarget,
168 pub q: u8,
170}
171
172impl Default for QueryParams {
173 fn default() -> Self {
174 Self {
175 sel: QuerySel::All,
176 session: QuerySession::S0,
177 target: QueryTarget::A,
178 q: 4,
179 }
180 }
181}
182
183impl QueryParams {
184 pub fn to_bytes(&self) -> [u8; 2] {
186 let byte0 = 0x10 | ((self.sel as u8) << 2) | (self.session as u8);
189 let byte1 = ((self.target as u8) << 7) | ((self.q & 0x0F) << 3);
190 [byte0, byte1]
191 }
192
193 pub fn from_bytes(bytes: [u8; 2]) -> Self {
195 let sel = match (bytes[0] >> 2) & 0x03 {
196 0 | 1 => QuerySel::All,
197 2 => QuerySel::NotSl,
198 3 => QuerySel::Sl,
199 _ => QuerySel::All,
200 };
201 let session = match bytes[0] & 0x03 {
202 0 => QuerySession::S0,
203 1 => QuerySession::S1,
204 2 => QuerySession::S2,
205 3 => QuerySession::S3,
206 _ => QuerySession::S0,
207 };
208 let target = if (bytes[1] >> 7) & 0x01 == 0 {
209 QueryTarget::A
210 } else {
211 QueryTarget::B
212 };
213 let q = (bytes[1] >> 3) & 0x0F;
214
215 Self {
216 sel,
217 session,
218 target,
219 q,
220 }
221 }
222}
223
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
226#[repr(u8)]
227pub enum QuerySel {
228 #[default]
230 All = 0x00,
231 NotSl = 0x02,
233 Sl = 0x03,
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
239#[repr(u8)]
240pub enum QuerySession {
241 #[default]
242 S0 = 0x00,
243 S1 = 0x01,
244 S2 = 0x02,
245 S3 = 0x03,
246}
247
248#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
250#[repr(u8)]
251pub enum QueryTarget {
252 #[default]
253 A = 0x00,
254 B = 0x01,
255}
256
257impl PartialEq for TagInfo {
258 fn eq(&self, other: &Self) -> bool {
259 self.epc == other.epc
260 }
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265#[repr(u8)]
266pub enum LockAction {
267 Unlock = 0x00,
269 Lock = 0x01,
271 PermUnlock = 0x02,
273 PermLock = 0x03,
275}
276
277#[derive(Debug, Clone, Copy, PartialEq, Eq)]
279#[repr(u8)]
280pub enum LockTarget {
281 User = 0x01,
283 Tid = 0x02,
285 Epc = 0x03,
287 AccessPassword = 0x04,
289 KillPassword = 0x05,
291}
292
293#[derive(Debug, Clone)]
295pub struct LockPayload {
296 pub target: LockTarget,
298 pub action: LockAction,
300}
301
302impl LockPayload {
303 pub fn to_bytes(&self) -> [u8; 3] {
305 let shift = match self.target {
316 LockTarget::User => 0,
317 LockTarget::Tid => 2,
318 LockTarget::Epc => 4,
319 LockTarget::AccessPassword => 6,
320 LockTarget::KillPassword => 8,
321 };
322
323 let mask: u16 = 0x03 << shift;
325
326 let action: u16 = (self.action as u16) << shift;
328
329 let payload: u32 = ((mask as u32) << 10) | (action as u32);
332
333 [
334 ((payload >> 16) & 0xFF) as u8,
335 ((payload >> 8) & 0xFF) as u8,
336 (payload & 0xFF) as u8,
337 ]
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
343#[repr(u8)]
344pub enum RfLinkProfile {
345 Fm0_40kHz = 0xD0,
347 Fm0_400kHz = 0xD1,
349 Miller4_250kHz = 0xD2,
351 Miller4_300kHz = 0xD3,
353 Miller2_40kHzDrm = 0xD4,
355}
356
357impl TryFrom<u8> for RfLinkProfile {
358 type Error = ();
359
360 fn try_from(value: u8) -> Result<Self, Self::Error> {
361 match value {
362 0xD0 => Ok(RfLinkProfile::Fm0_40kHz),
363 0xD1 => Ok(RfLinkProfile::Fm0_400kHz),
364 0xD2 => Ok(RfLinkProfile::Miller4_250kHz),
365 0xD3 => Ok(RfLinkProfile::Miller4_300kHz),
366 0xD4 => Ok(RfLinkProfile::Miller2_40kHzDrm),
367 _ => Err(()),
368 }
369 }
370}
371
372#[derive(Debug, Clone, Copy, PartialEq, Eq)]
374pub struct QtControl {
375 pub short_range: bool,
377 pub persistence: bool,
379}
380
381impl QtControl {
382 pub fn to_byte(&self) -> u8 {
384 let mut byte = 0u8;
385 if self.short_range {
386 byte |= 0x01;
387 }
388 if self.persistence {
389 byte |= 0x02;
390 }
391 byte
392 }
393}
394
395#[derive(Debug)]
397pub enum UhfError {
398 Transport(String),
400 InvalidParameter(String),
402 InvalidResponse(String),
404}
405
406pub(crate) fn bytes_to_hex(bytes: &[u8]) -> String {
408 bytes.iter().map(|b| format!("{:02X}", b)).collect()
409}