ghpascon_rust/devices/rfid/r700/
config.rs1use std::collections::HashMap;
2
3use serde_json::{Map, Number, Value, json};
4
5pub type ParamMap = HashMap<String, Value>;
6
7#[derive(Debug, Clone)]
10pub struct AntennaConfig {
11 pub antenna_port: u8,
12 pub estimated_tag_population: u32,
13 pub fast_id: bool,
14 pub inventory_search_mode: String,
15 pub inventory_session: u8,
16 pub receive_sensitivity_dbm: i32,
17 pub rf_mode: u32,
18 pub transmit_power_cdbm: i32,
19 pub protected_mode_pin_hex: Option<String>,
20}
21
22impl Default for AntennaConfig {
23 fn default() -> Self {
24 Self {
25 antenna_port: 1,
26 estimated_tag_population: 16,
27 fast_id: true,
28 inventory_search_mode: "dual-target".to_string(),
29 inventory_session: 1,
30 receive_sensitivity_dbm: -80,
31 rf_mode: 4,
32 transmit_power_cdbm: 3000,
33 protected_mode_pin_hex: None,
34 }
35 }
36}
37
38impl AntennaConfig {
39 pub fn to_json(&self) -> Value {
40 let mut obj = Map::new();
41 obj.insert("antennaPort".to_string(), json!(self.antenna_port));
42 obj.insert(
43 "estimatedTagPopulation".to_string(),
44 json!(self.estimated_tag_population),
45 );
46 obj.insert(
47 "fastId".to_string(),
48 json!(if self.fast_id { "enabled" } else { "disabled" }),
49 );
50 obj.insert(
51 "inventorySearchMode".to_string(),
52 json!(self.inventory_search_mode),
53 );
54 obj.insert(
55 "inventorySession".to_string(),
56 json!(self.inventory_session),
57 );
58 obj.insert(
59 "receiveSensitivityDbm".to_string(),
60 json!(self.receive_sensitivity_dbm),
61 );
62 obj.insert("rfMode".to_string(), json!(self.rf_mode));
63 obj.insert(
64 "transmitPowerCdbm".to_string(),
65 json!(self.transmit_power_cdbm),
66 );
67 if let Some(pin) = &self.protected_mode_pin_hex {
68 obj.insert("protectedModePinHex".to_string(), json!(pin));
69 }
70 Value::Object(obj)
71 }
72}
73
74#[derive(Debug, Clone)]
77pub struct R700Config {
78 pub name: String,
79 pub ip: String,
80 pub username: String,
81 pub password: String,
82 pub start_reading: bool,
83 pub firmware_version: Option<String>,
84 pub session: u8,
85 pub read_power: i32,
86 pub read_rssi: i32,
87 pub search_mode: String,
88 pub rf_mode: u32,
89 pub gpi_start: bool,
90 pub protected_inventory_active: bool,
91 pub protected_inventory_password: String,
92 pub reconnection_time: u64,
93 pub active_ant: Vec<u8>,
94 pub reading_config: Option<Value>,
97}
98
99impl Default for R700Config {
100 fn default() -> Self {
101 Self {
102 name: "R700".to_string(),
103 ip: "192.168.1.101".to_string(),
104 username: "root".to_string(),
105 password: "impinj".to_string(),
106 start_reading: false,
107 firmware_version: None,
108 session: 1,
109 read_power: 3000,
110 read_rssi: -80,
111 search_mode: "single-target".to_string(),
112 rf_mode: 4,
113 gpi_start: false,
114 protected_inventory_active: false,
115 protected_inventory_password: "12345678".to_string(),
116 reconnection_time: 2,
117 active_ant: vec![1],
118 reading_config: None,
119 }
120 }
121}
122
123impl R700Config {
124 pub fn build_reading_config(&self) -> Value {
126 if let Some(custom) = &self.reading_config {
127 return custom.clone();
128 }
129
130 let antennas: Vec<Value> = self
131 .active_ant
132 .iter()
133 .map(|&port| {
134 let mut ant = AntennaConfig {
135 antenna_port: port,
136 inventory_session: self.session,
137 receive_sensitivity_dbm: self.read_rssi,
138 transmit_power_cdbm: self.read_power,
139 inventory_search_mode: self.search_mode.clone(),
140 rf_mode: self.rf_mode,
141 ..AntennaConfig::default()
142 };
143 if self.protected_inventory_active {
144 ant.protected_mode_pin_hex = Some(self.protected_inventory_password.clone());
145 }
146 ant.to_json()
147 })
148 .collect();
149
150 let mut cfg = Map::new();
151 cfg.insert("antennaConfigs".to_string(), Value::Array(antennas));
152
153 if self.gpi_start {
154 cfg.insert(
155 "startTriggers".to_string(),
156 json!([{"gpiTransitionEvent": {"gpi": 1, "transition": "high-to-low"}}]),
157 );
158 cfg.insert(
159 "stopTriggers".to_string(),
160 json!([{"gpiTransitionEvent": {"gpi": 1, "transition": "low-to-high"}}]),
161 );
162 }
163
164 cfg.insert(
165 "eventConfig".to_string(),
166 json!({
167 "common": {"hostname": "disabled"},
168 "tagInventory": {
169 "epc": "disabled",
170 "epcHex": "enabled",
171 "xpcHex": "disabled",
172 "tid": "disabled",
173 "tidHex": "enabled",
174 "antennaPort": "enabled",
175 "transmitPowerCdbm": "disabled",
176 "peakRssiCdbm": "enabled",
177 "frequency": "disabled",
178 "pc": "disabled",
179 "lastSeenTime": "disabled",
180 "phaseAngle": "disabled",
181 "tagReporting": {
182 "reportingIntervalSeconds": 1,
183 "tagCacheSize": 2048,
184 "antennaIdentifier": "antennaPort",
185 "tagIdentifier": "epc"
186 }
187 }
188 }),
189 );
190
191 Value::Object(cfg)
192 }
193
194 pub fn base_url(&self) -> String {
195 format!("https://{}/api/v1", self.ip)
196 }
197
198 pub fn from_map(params: ParamMap) -> Result<Self, String> {
201 let mut cfg = Self::default();
202
203 if let Some(Value::String(v)) = params.get("name") {
204 cfg.name = v.clone();
205 }
206 if let Some(Value::String(v)) = params.get("ip") {
207 cfg.ip = v.clone();
208 }
209 if let Some(Value::String(v)) = params.get("username") {
210 cfg.username = v.clone();
211 }
212 if let Some(Value::String(v)) = params.get("password") {
213 cfg.password = v.clone();
214 }
215 if let Some(Value::Bool(v)) = params.get("start_reading") {
216 cfg.start_reading = *v;
217 }
218 if let Some(Value::String(v)) = params.get("firmware_version") {
219 cfg.firmware_version = Some(v.clone());
220 }
221 if let Some(v) = params.get("session").and_then(|v| v.as_u64()) {
222 cfg.session = (v.clamp(0, 3)) as u8;
223 }
224 if let Some(v) = params.get("read_power").and_then(|v| v.as_i64()) {
225 let mut p = v as i32;
226 if p < 1000 {
227 p *= 100;
228 }
229 if !(1000..=3300).contains(&p) {
230 p = 3000;
231 }
232 cfg.read_power = p;
233 }
234 if let Some(v) = params.get("read_rssi").and_then(|v| v.as_i64()) {
235 cfg.read_rssi = v as i32;
236 }
237 if let Some(Value::String(v)) = params.get("search_mode") {
238 if matches!(v.as_str(), "single-target" | "dual-target") {
239 cfg.search_mode = v.clone();
240 } else {
241 cfg.search_mode = "single-target".to_string();
242 }
243 }
244 if let Some(v) = params.get("rf_mode").and_then(|v| v.as_u64()) {
245 cfg.rf_mode = v as u32;
246 }
247 if let Some(Value::Bool(v)) = params.get("gpi_start") {
248 cfg.gpi_start = *v;
249 if *v {
250 cfg.start_reading = false;
251 }
252 }
253 if let Some(Value::Bool(v)) = params.get("protected_inventory_active") {
254 cfg.protected_inventory_active = *v;
255 }
256 if let Some(Value::String(v)) = params.get("protected_inventory_password") {
257 cfg.protected_inventory_password = v.clone();
258 }
259 if let Some(v) = params.get("reconnection_time").and_then(|v| v.as_u64()) {
260 cfg.reconnection_time = v;
261 }
262 if let Some(Value::Array(arr)) = params.get("active_ant") {
263 cfg.active_ant = arr
264 .iter()
265 .filter_map(|v| v.as_u64().map(|n| n as u8))
266 .collect();
267 if cfg.active_ant.is_empty() {
268 cfg.active_ant = vec![1];
269 }
270 }
271
272 if let Some(Value::Object(obj)) = params.get("reading_config") {
273 cfg.reading_config = Some(Value::Object(obj.clone()));
274 }
275
276 Ok(cfg)
277 }
278
279 pub fn to_map(&self) -> ParamMap {
280 let mut map = HashMap::new();
281 map.insert("name".to_string(), Value::String(self.name.clone()));
282 map.insert("ip".to_string(), Value::String(self.ip.clone()));
283 map.insert("username".to_string(), Value::String(self.username.clone()));
284 map.insert("password".to_string(), Value::String(self.password.clone()));
285 map.insert("start_reading".to_string(), Value::Bool(self.start_reading));
286 map.insert(
287 "firmware_version".to_string(),
288 self.firmware_version
289 .clone()
290 .map(Value::String)
291 .unwrap_or(Value::Null),
292 );
293 map.insert(
294 "session".to_string(),
295 Value::Number(Number::from(self.session)),
296 );
297 map.insert(
298 "read_power".to_string(),
299 Value::Number(Number::from(self.read_power)),
300 );
301 map.insert(
302 "read_rssi".to_string(),
303 Value::Number(Number::from(self.read_rssi)),
304 );
305 map.insert(
306 "search_mode".to_string(),
307 Value::String(self.search_mode.clone()),
308 );
309 map.insert(
310 "rf_mode".to_string(),
311 Value::Number(Number::from(self.rf_mode)),
312 );
313 map.insert("gpi_start".to_string(), Value::Bool(self.gpi_start));
314 map.insert(
315 "protected_inventory_active".to_string(),
316 Value::Bool(self.protected_inventory_active),
317 );
318 map.insert(
319 "protected_inventory_password".to_string(),
320 Value::String(self.protected_inventory_password.clone()),
321 );
322 map.insert(
323 "reconnection_time".to_string(),
324 Value::Number(Number::from(self.reconnection_time)),
325 );
326 map.insert(
327 "active_ant".to_string(),
328 Value::Array(
329 self.active_ant
330 .iter()
331 .map(|&a| Value::Number(Number::from(a)))
332 .collect(),
333 ),
334 );
335 map.insert(
336 "reading_config".to_string(),
337 self.reading_config.clone().unwrap_or(Value::Null),
338 );
339 map
340 }
341}