1use crate::common::*;
2use crate::enums::*;
3use crate::structs::*;
4
5use chrono::{DateTime, Local, TimeZone};
6use either::Either;
7use enum_primitive::FromPrimitive;
8use log::*;
9use semver::Version;
10use serde::{Deserialize, Serialize};
11use std::ops::BitXorAssign;
12
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct EchoResponse<'a> {
15 pub destination_id: u8, pub command: EchoCode,
17 pub data: &'a [u8],
18}
19
20pub trait Response<T> {
21 fn decode(raw: &[u8]) -> Result<T>;
22
23 fn get_message_part(raw: &[u8]) -> Result<&[u8]> {
24 if raw.is_empty() {
25 return Err(ProtocolError::NoResponse.into());
26 }
27
28 let (raw_msg, expected_msg_length, msg_length) = match raw[0] {
29 0x7E => {
30 let non_header = &raw[1..];
31 let expected_msg_length = u16::from(non_header[0]) as usize;
32 let msg_length = non_header.len() - 1;
33
34 Ok((&non_header[1..], expected_msg_length, msg_length))
36 },
37 0xFF => match raw[0..4] == EXTENDED_HEADER {
38 true => {
39 let non_header = &raw[4..];
40 let expected_msg_length = u16::from_be_bytes([non_header[0], non_header[1]]) as usize;
41 let msg_length = non_header.len() - 2;
42
43 Ok((&non_header[2..], expected_msg_length, msg_length))
45 },
46 false => Err(ProtocolError::UnexpectedHeaderValue),
47 },
48 other => Err(ProtocolError::UnexpectedFirstHeaderByte(other)),
49 }?;
50
51 if expected_msg_length != msg_length {
52 error!("Message length mismatch, expected: {} but got: {}", expected_msg_length, msg_length);
53 debug!("Raw response: {:?}", raw);
54 return Err(ProtocolError::MessageLengthMismatch.into());
55 };
56
57 let sum = raw_msg.get(msg_length - 1).expect("Missing sum value");
59 let xor = raw_msg.get(msg_length - 2).expect("Missing xor value");
60
61 let mut xor_res: u8 = 0xFF;
64 for d in &raw_msg[..msg_length - 2] {
65 xor_res.bitxor_assign(d);
66 }
67
68 if xor_res != *xor {
71 return Err(ProtocolError::BadXorValue.into());
72 }
73
74 let mut sum_res: u8 = 0;
75 for d in &raw_msg[..msg_length - 1] {
76 sum_res = sum_res.wrapping_add(*d);
77 }
78
79 if sum_res != *sum {
82 return Err(ProtocolError::BadChecksumValue.into());
83 }
84
85 Ok(&raw_msg[0..msg_length - 2])
87 }
88
89 fn get_data_parts(raw: &[u8], expected_command: Option<EchoCode>) -> Result<EchoResponse> {
90 let msg = Self::get_message_part(raw)?;
91 let destination_id = msg[0];
92 let command: EchoCode = EchoCode::from_u8(msg[1]).ok_or(ProtocolError::UnknownCommandCode(msg[1]))?;
93
94 if let Some(exp) = expected_command {
95 if exp != command {
96 return Err(ProtocolError::UnexpectedCommandCode.into());
97 }
98 }
99
100 let data = &msg[2..];
101 Ok(EchoResponse { destination_id, command, data })
102 }
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct PollResponse {
107 pub destination_id: u8,
108 pub function_code: u8,
109 pub source: u8,
110 pub event_type: u8,
111 pub data: ControllerStatus,
112}
113
114impl Response<PollResponse> for PollResponse {
115 fn decode(raw: &[u8]) -> Result<PollResponse> {
116 let msg = Self::get_message_part(raw)?;
117
118 if msg.len() < 5 {
119 return Err(ProtocolError::MessageTooShort.into());
120 }
121
122 let destination_id = msg[0];
123 let function_code = msg[1];
124 let source = msg[2];
125 let event_type = msg[3];
126 let data = ControllerStatus::decode(event_type, &msg[4..])?;
127
128 Ok(PollResponse {
129 destination_id,
130 function_code,
131 source,
132 event_type,
133 data,
134 })
135 }
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct SerialNumberResponse {
140 pub destination_id: u8,
141 pub command: EchoCode,
142 pub source: u8,
143 pub serial: Vec<u8>,
145}
146
147impl Response<SerialNumberResponse> for SerialNumberResponse {
148 fn decode(raw: &[u8]) -> Result<SerialNumberResponse> {
149 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
150 let data = parts.data;
151
152 if data.len() < 15 {
153 return Err(ProtocolError::MessageTooShort.into());
154 }
155
156 let source = data[0];
157 let serial = data[3..15].to_vec();
158
159 Ok(SerialNumberResponse {
160 destination_id: parts.destination_id,
161 command: parts.command,
162 source,
163 serial,
164 })
165 }
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct RelayDelayResponse {
170 pub destination_id: u8,
171 pub command: EchoCode,
172 pub source: u8,
173 pub main_port_door_relay_time: u16, pub wiegand_port_door_relay_time: u16, pub alarm_relay_time: u16, pub lift_controller_time: u16, }
178
179impl Response<RelayDelayResponse> for RelayDelayResponse {
180 fn decode(raw: &[u8]) -> Result<RelayDelayResponse> {
181 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
182 let data = parts.data;
183
184 if data.len() < 9 {
185 return Err(ProtocolError::MessageTooShort.into());
186 }
187
188 let source = data[0];
189 let main_port_door_relay_time = u16::from_be_bytes([data[1], data[2]]);
190 let wiegand_port_door_relay_time = u16::from_be_bytes([data[3], data[4]]);
191 let alarm_relay_time = u16::from_be_bytes([data[5], data[6]]);
192 let lift_controller_time = u16::from_be_bytes([data[7], data[8]]);
193
194 Ok(RelayDelayResponse {
195 destination_id: parts.destination_id,
196 command: parts.command,
197 source,
198 main_port_door_relay_time,
199 wiegand_port_door_relay_time,
200 alarm_relay_time,
201 lift_controller_time,
202 })
203 }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct EditPasswordResponse {
208 pub destination_id: u8,
209 pub command: EchoCode,
210 pub source: u8,
211 pub password: u32,
212}
213
214impl Response<EditPasswordResponse> for EditPasswordResponse {
215 fn decode(raw: &[u8]) -> Result<EditPasswordResponse> {
216 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
217 let data = parts.data;
218
219 if data.len() < 5 {
220 return Err(ProtocolError::MessageTooShort.into());
221 }
222
223 let source = data[0];
224 let password = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
225
226 Ok(EditPasswordResponse {
227 destination_id: parts.destination_id,
228 command: parts.command,
229 source,
230 password,
231 })
232 }
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct ControllerOptionsResponse {
237 pub destination_id: u8,
238 pub command: EchoCode,
239 pub source: u8,
240 pub controller_type: ControllerType,
241 pub controller_options: ControllerOptions,
242}
243
244impl Response<ControllerOptionsResponse> for ControllerOptionsResponse {
245 fn decode(raw: &[u8]) -> Result<ControllerOptionsResponse> {
246 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
247 let data = parts.data;
248
249 if data.len() < 43 {
250 return Err(ProtocolError::MessageTooShort.into());
251 }
252
253 let source = data[0];
254 let controller_type = ControllerType::from_u8(data[1]).ok_or(ProtocolError::UnknownControllerType(data[1]))?;
255 let controller_options = ControllerOptions::decode(data, Version::new(4, 3, 0))?;
256
257 Ok(ControllerOptionsResponse {
258 destination_id: parts.destination_id,
259 command: parts.command,
260 source,
261 controller_type,
262 controller_options,
263 })
264 }
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct IpAndMacAddressResponse {
269 pub destination_id: u8,
270 pub command: EchoCode,
271 pub source: u8,
272 pub address_data: IpAndMacAddress,
273}
274
275impl Response<IpAndMacAddressResponse> for IpAndMacAddressResponse {
276 fn decode(raw: &[u8]) -> Result<IpAndMacAddressResponse> {
277 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
278 let data = parts.data;
279
280 if data.len() < 32 {
281 return Err(ProtocolError::MessageTooShort.into());
282 }
283
284 let source = data[0];
285 let address_data = IpAndMacAddress::decode(&data[2..]);
288
289 Ok(IpAndMacAddressResponse {
290 destination_id: parts.destination_id,
291 command: parts.command,
292 source,
293 address_data,
294 })
295 }
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct RemoteTCPServerParamsResponse {
300 pub destination_id: u8,
301 pub command: EchoCode,
302 pub source: u8,
303 pub remote_server_params: RemoteTCPServerParams,
304}
305
306impl Response<RemoteTCPServerParamsResponse> for RemoteTCPServerParamsResponse {
307 fn decode(raw: &[u8]) -> Result<RemoteTCPServerParamsResponse> {
308 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
309 let data = parts.data;
310
311 if data.len() < 13 {
312 return Err(ProtocolError::MessageTooShort.into());
313 }
314
315 let source = data[0];
316 let remote_server_params = RemoteTCPServerParams::decode(&data[1..]);
317
318 Ok(RemoteTCPServerParamsResponse {
319 destination_id: parts.destination_id,
320 command: parts.command,
321 source,
322 remote_server_params,
323 })
324 }
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct EventLogStatusResponse {
329 pub destination_id: u8,
330 pub command: EchoCode,
331 pub event_log_counter: u8,
332 pub queue_input_point: u8,
333 pub queue_output_point: u8,
334}
335
336impl Response<EventLogStatusResponse> for EventLogStatusResponse {
337 fn decode(raw: &[u8]) -> Result<EventLogStatusResponse> {
338 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
339 let data = parts.data;
340
341 if data.len() < 3 {
342 return Err(ProtocolError::MessageTooShort.into());
343 }
344
345 Ok(EventLogStatusResponse {
346 destination_id: parts.destination_id,
347 command: parts.command,
348 event_log_counter: data[0],
349 queue_input_point: data[1],
350 queue_output_point: data[2],
351 })
352 }
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize)]
356pub struct AckResponse {
357 pub destination_id: u8,
358 pub source: u8,
359 }
361
362impl Response<AckResponse> for AckResponse {
363 fn decode(raw: &[u8]) -> Result<AckResponse> {
364 let parts = Self::get_data_parts(raw, Some(EchoCode::CommandAcknowledged))?;
365 let data = parts.data;
366
367 if data.is_empty() {
368 return Err(ProtocolError::MessageTooShort.into());
369 }
370
371 let source = data[0];
372
373 Ok(AckResponse {
374 destination_id: parts.destination_id,
375 source,
376 })
377 }
378}
379
380#[derive(Debug, Clone, Serialize, Deserialize)]
381pub struct NackResponse {
382 pub destination_id: u8,
383 pub source: u8,
384 }
386
387impl Response<NackResponse> for NackResponse {
388 fn decode(raw: &[u8]) -> Result<NackResponse> {
389 let parts = Self::get_data_parts(raw, Some(EchoCode::CommandUnacknowledged))?;
390 let data = parts.data;
391
392 if data.is_empty() {
393 return Err(ProtocolError::MessageTooShort.into());
394 }
395
396 let source = data[0];
397
398 Ok(NackResponse {
399 destination_id: parts.destination_id,
400 source,
401 })
402 }
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct AckOrNack {
407 res: Either<NackResponse, AckResponse>,
408}
409
410impl AckOrNack {
411 pub fn should_ack(&self) -> Result<AckResponse> {
412 match self.res.as_ref() {
413 Either::Left(_) => Err(ProtocolError::CommandNotAcknowledged.into()),
414 Either::Right(r) => Ok(r.to_owned()),
415 }
416 }
417
418 pub fn handle(raw: Vec<u8>) -> Result<AckOrNack> {
419 match AckResponse::decode(&raw) {
420 Ok(x) => Ok(Either::Right(x)),
421 Err(_) => NackResponse::decode(&raw).map(Either::Left),
422 }
423 .map(|res| AckOrNack { res })
424 }
425}
426
427#[derive(Debug, Clone, Serialize, Deserialize)]
428pub struct EventLogResponse {
429 pub destination_id: u8,
430 pub function_code: EventFunctionCode,
431 pub source: u8,
432 pub timestamp: DateTime<Local>,
433 pub port_number: EventPortNumber,
434 pub user_address_or_tag_id: u16, pub tag_id: TagId32,
436 pub door_number: u8,
441 pub sor_deduction_amount: u16,
442 pub sor_balance: u16, pub user_inputted_code: Option<u32>, }
445
446impl Response<EventLogResponse> for EventLogResponse {
447 fn decode(raw: &[u8]) -> Result<EventLogResponse> {
448 let msg = Self::get_message_part(raw)?;
449
450 let destination_id = msg[0];
451 let function_code = EventFunctionCode::from_u8(msg[1]).ok_or(ProtocolError::UnknownEventFunctionCode(msg[1]))?;
452 let data = &msg[2..];
453
454 if data.len() < 25 {
455 return Err(ProtocolError::MessageTooShort.into());
456 }
457
458 let source = data[0];
459
460 let year = 2000 + data[7] as i32;
461 let month = data[6] as u32;
462 let day = data[5] as u32;
463 let hour = data[3] as u32;
464 let minute = data[2] as u32;
465 let second = data[1] as u32;
466 let timestamp = Local
467 .with_ymd_and_hms(year, month, day, hour, minute, second)
468 .latest()
469 .ok_or(ProtocolError::InvalidDateTime)?;
470
471 let port_number = EventPortNumber::from_u8(data[8]).ok_or(ProtocolError::UnknownPortNumber(data[8]))?;
472
473 let user_address_or_tag_id = u16::from_be_bytes([data[9], data[10]]);
474 let tag_id = TagId32::decode(&[data[15], data[16], data[19], data[20]])?;
475
476 let door_number = data[17];
477
478 let sor_deduction_amount = u16::from_be_bytes([data[21], data[22]]);
479 let sor_balance = u16::from_be_bytes([data[23], data[24]]);
480
481 let user_inputted_code = if function_code == EventFunctionCode::InvalidUserPIN {
482 Some(u32::from_be_bytes([data[25], data[26], data[27], data[28]]))
483 } else {
484 None
485 };
486
487 Ok(EventLogResponse {
488 destination_id,
489 function_code,
490 source,
491 timestamp,
492 port_number,
493 user_address_or_tag_id,
494 tag_id,
495 door_number,
496 sor_deduction_amount,
497 sor_balance,
498 user_inputted_code,
499 })
500 }
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct UserParametersResponse {
505 pub destination_id: u8,
506 pub command: EchoCode,
507 pub source: u8,
508 pub user_parameters: UserParameters,
509}
510
511impl Response<UserParametersResponse> for UserParametersResponse {
512 fn decode(raw: &[u8]) -> Result<UserParametersResponse> {
513 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
514 let data = parts.data;
515
516 if data.len() < 25 {
519 return Err(ProtocolError::MessageTooShort.into());
520 }
521
522 let source = data[0];
523 let user_parameters = UserParameters::decode(&data[1..25])?;
524
525 Ok(UserParametersResponse {
526 destination_id: parts.destination_id,
527 command: parts.command,
528 source,
529 user_parameters,
530 })
531 }
532}
533
534#[derive(Debug, Clone, Serialize, Deserialize)]
535pub struct RelayStatusResponse {
536 pub destination_id: u8,
537 pub command: EchoCode,
538 pub source: u8,
539 pub firmware_version: semver::Version,
540 pub di_port: DIPortStatus,
541 pub relay_port: RelayPortStatus,
542 pub main_port_options: ControllerPortOptions,
543 pub wiegand_port_options: ControllerPortOptions,
544 pub main_port_arming: bool,
545 pub wiegand_port_arming: bool,
546}
547
548impl Response<RelayStatusResponse> for RelayStatusResponse {
549 fn decode(raw: &[u8]) -> Result<RelayStatusResponse> {
550 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
551 let data = parts.data;
552
553 if data.len() < 9 {
554 return Err(ProtocolError::MessageTooShort.into());
555 }
556
557 let source = data[0];
558 let firmware_major = (data[1] & 0xF0) >> 4;
559 let firmware_minor = data[1] & 0x0F;
560 let firmware_version = semver::Version::new(firmware_major as u64, firmware_minor as u64, 0);
561 let di_port = DIPortStatus::decode(data[2]);
562 let relay_port = RelayPortStatus::decode(data[3]);
563 let main_port_options = ControllerPortOptions::decode(data[4]);
564 let wiegand_port_options = ControllerPortOptions::decode(data[5]);
565 let main_port_arming = data[7] & 0b00000001 != 0;
567 let wiegand_port_arming = data[7] & 0b00000010 != 0;
568 Ok(RelayStatusResponse {
571 destination_id: parts.destination_id,
572 command: parts.command,
573 source,
574 firmware_version,
575 di_port,
576 relay_port,
577 main_port_options,
578 wiegand_port_options,
579 main_port_arming,
580 wiegand_port_arming,
581 })
582 }
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize)]
586pub struct RealTimeClockResponse {
587 pub destination_id: u8,
588 pub command: EchoCode,
589 pub source: u8,
590 pub clock: ClockData,
591}
592
593impl Response<RealTimeClockResponse> for RealTimeClockResponse {
594 fn decode(raw: &[u8]) -> Result<RealTimeClockResponse> {
595 let parts = Self::get_data_parts(raw, Some(EchoCode::RequestedData))?;
596 let data = parts.data;
597
598 let source = data[0];
599 let clock = ClockData::decode(&data[1..])?;
600
601 Ok(RealTimeClockResponse {
602 destination_id: parts.destination_id,
603 command: parts.command,
604 source,
605 clock,
606 })
607 }
608}
609
610#[cfg(test)]
611mod tests {
612 use super::*;
613
614 #[test]
615 fn decode_status_io_response() {
616 let raw = vec![255, 0, 90, 165, 0, 10, 0, 9, 1, 0, 1, 0, 16, 0, 230, 1];
617 let d = PollResponse::decode(&raw);
618 assert!(d.is_ok());
619 if let Ok(echo) = d {
620 assert_eq!(echo.destination_id, 0);
621 assert_eq!(echo.function_code, 9);
622 assert_eq!(echo.source, 1);
623 assert_eq!(echo.event_type, 0);
624 assert_eq!(
625 echo.data,
626 ControllerStatus::IoStatus(IoStatusData {
627 status_data: StatusData {
628 keypad_locked: false,
629 door_release_output: false,
630 alarm_output: false,
631 arming: false,
632 controller_alarm: false,
633 egress_released: false,
634 door_open: true
635 },
636 alarm_type: None,
637 controller_options: ControllerPortOptions {
638 anti_pass_back_enabled: false,
639 anti_pass_back_in: false,
640 force_open_alarm: false,
641 egress_button: true,
642 skip_pin_check: false,
643 auto_open_zone: false,
644 auto_lock_door: false,
645 time_attendance_disabled: false
646 },
647 })
648 );
649 }
650 }
651
652 #[test]
653 fn decode_status_all_keys_response() {
654 let raw = vec![255, 0, 90, 165, 0, 21, 0, 9, 1, 1, 139, 4, 210, 0, 16, 1, 0, 5, 0, 3, 4, 0, 1, 11, 0, 178, 71];
655 let d = PollResponse::decode(&raw);
656 assert!(d.is_ok());
657 if let Ok(echo) = d {
658 assert_eq!(echo.destination_id, 0);
659 assert_eq!(echo.function_code, 9);
660 assert_eq!(echo.source, 1);
661 assert_eq!(echo.event_type, 1);
662 assert_eq!(
663 echo.data,
664 ControllerStatus::AllKeysPressed(AllKeysPressedData {
665 fifth_key_data: None,
666 input_value: 1234,
667 device_params: ControllerPortOptions {
668 anti_pass_back_enabled: false,
669 anti_pass_back_in: false,
670 force_open_alarm: false,
671 egress_button: true,
672 skip_pin_check: false,
673 auto_open_zone: false,
674 auto_lock_door: false,
675 time_attendance_disabled: false
676 },
677 })
678 );
679 }
680 }
681
682 #[test]
683 fn decode_status_new_card_response() {
684 let raw = vec![
685 255, 0, 90, 165, 0, 23, 0, 9, 1, 2, 11, 18, 221, 0, 0, 186, 139, 0, 16, 0, 138, 0, 0, 0, 0, 0, 0, 154, 127,
686 ];
687 let d = PollResponse::decode(&raw);
688 assert!(d.is_ok());
689 if let Ok(echo) = d {
690 assert_eq!(echo.destination_id, 0);
691 assert_eq!(echo.function_code, 9);
692 assert_eq!(echo.source, 1);
693 assert_eq!(echo.event_type, 2);
694 assert_eq!(
695 echo.data,
696 ControllerStatus::NewCardPresent(NewCardPresentData {
697 card_id: TagId32::new(4829, 47755),
698 input_value: 0,
699 id_em4001: 0,
700 device_params: ControllerPortOptions {
701 anti_pass_back_enabled: false,
702 anti_pass_back_in: false,
703 force_open_alarm: false,
704 egress_button: true,
705 skip_pin_check: false,
706 auto_open_zone: false,
707 auto_lock_door: false,
708 time_attendance_disabled: false
709 },
710 from_wiegand: false,
711 setting_forced_open_alarm: false
712 })
713 );
714 }
715 }
716
717 #[test]
718 fn decode_controller_options_response() {
719 let raw = vec![
720 255, 0, 90, 165, 0, 57, 0, 3, 1, 193, 1, 2, 0, 1, 226, 64, 0, 0, 0, 0, 0, 0, 0, 0, 4, 210, 0, 0, 0, 0, 1, 4, 0, 100, 2, 188, 2, 188, 5, 220, 48,
721 16, 1, 17, 15, 15, 0, 8, 0, 1, 1, 65, 24, 9, 5, 0, 0, 0, 3, 3, 0, 159, 13,
722 ];
723 let d = ControllerOptionsResponse::decode(&raw);
724 assert!(d.is_ok());
725 if let Ok(o) = d {
726 assert_eq!(o.destination_id, 0);
727 assert_eq!(o.command, EchoCode::RequestedData);
728 assert_eq!(o.source, 1);
729 assert_eq!(o.controller_type, ControllerType::AR725Ev2);
730 assert_eq!(o.controller_options.main_port_door_number, 1);
731 assert_eq!(o.controller_options.wiegand_port_door_number, 2);
732 assert_eq!(o.controller_options.edit_password, 123456);
733 assert_eq!(o.controller_options.master_user_range_start, 0);
734 assert_eq!(o.controller_options.master_user_range_end, 0);
735 assert_eq!(o.controller_options.general_password, 1234);
736 assert_eq!(o.controller_options.duress_code, 0);
737 assert_eq!(o.controller_options.tag_hold_time, 100);
738 assert_eq!(o.controller_options.main_port_door_relay_time, 700);
739 assert_eq!(o.controller_options.wiegand_port_door_relay_time, 700);
740 assert_eq!(o.controller_options.alarm_relay_time, 1500);
741 assert_eq!(
742 o.controller_options.main_port_options,
743 ControllerPortOptions {
744 anti_pass_back_enabled: false,
745 anti_pass_back_in: false,
746 force_open_alarm: true,
747 egress_button: true,
748 skip_pin_check: false,
749 auto_open_zone: false,
750 auto_lock_door: false,
751 time_attendance_disabled: false
752 }
753 );
754 assert_eq!(
755 o.controller_options.wiegand_port_options,
756 ControllerPortOptions {
757 anti_pass_back_enabled: false,
758 anti_pass_back_in: false,
759 force_open_alarm: false,
760 egress_button: true,
761 skip_pin_check: false,
762 auto_open_zone: false,
763 auto_lock_door: false,
764 time_attendance_disabled: false
765 }
766 );
767 assert_eq!(
768 o.controller_options.main_port_extended_options,
769 ExtendedControllerOptions {
770 door_relay_active_in_auto_open_time_zone: false,
771 stop_alarm_at_door_closed: false,
772 free_tag_access_mode: false,
773 use_main_door_relay_for_wiegand_port: false,
774 auto_disarmed_time_zone: false,
775 key_pad_inhibited: false,
776 fingerprint_only_enabled: false,
777 egress_button_sound: true
778 }
779 );
780 assert_eq!(
781 o.controller_options.wiegand_port_extended_options,
782 ExtendedControllerOptions {
783 door_relay_active_in_auto_open_time_zone: false,
784 stop_alarm_at_door_closed: false,
785 free_tag_access_mode: false,
786 use_main_door_relay_for_wiegand_port: true,
787 auto_disarmed_time_zone: false,
788 key_pad_inhibited: false,
789 fingerprint_only_enabled: false,
790 egress_button_sound: true
791 }
792 );
793 assert_eq!(o.controller_options.main_port_door_close_time, 15);
794 assert_eq!(o.controller_options.wiegand_port_door_close_time, 15);
795 assert_eq!(o.controller_options.main_port_arming, false);
796 assert_eq!(o.controller_options.wiegand_port_arming, false);
797 assert_eq!(o.controller_options.access_mode, ControllerAccessMode::PINOnly);
798 assert_eq!(o.controller_options.armed_output_pulse_width, 0);
799 assert_eq!(o.controller_options.arming_delay, 1);
800 assert_eq!(o.controller_options.alarm_delay, 1);
801 }
802 }
803
804 #[test]
805 fn decode_ack_extended() {
806 let raw = vec![255, 0, 90, 165, 0, 15, 0, 4, 1, 193, 67, 15, 145, 16, 16, 0, 0, 0, 0, 230, 175];
807 let d = AckResponse::decode(&raw);
808 println!("Result: {:?}", d);
809 assert!(d.is_ok());
810 }
811
812 #[test]
813 fn decode_ack_simple() {
814 let raw = vec![126, 15, 0, 4, 1, 193, 67, 15, 145, 16, 16, 0, 0, 0, 0, 230, 175];
815 let d = AckResponse::decode(&raw);
816 println!("Result: {:?}", d);
817 assert!(d.is_ok());
818 }
819}