1use crate::error::{FinsError, Result};
48use crate::header::{FinsHeader, NodeAddress, FINS_HEADER_SIZE};
49use crate::memory::MemoryArea;
50
51pub(crate) const MRC_MEMORY_READ: u8 = 0x01;
53pub(crate) const SRC_MEMORY_READ: u8 = 0x01;
55pub(crate) const MRC_MEMORY_WRITE: u8 = 0x01;
57pub(crate) const SRC_MEMORY_WRITE: u8 = 0x02;
59pub(crate) const SRC_MEMORY_FILL: u8 = 0x03;
61pub(crate) const SRC_MULTIPLE_READ: u8 = 0x04;
63pub(crate) const SRC_MEMORY_TRANSFER: u8 = 0x05;
65pub(crate) const MRC_RUN: u8 = 0x04;
67pub(crate) const SRC_RUN: u8 = 0x01;
69pub(crate) const SRC_STOP: u8 = 0x02;
71pub(crate) const MRC_FORCED: u8 = 0x23;
73pub(crate) const SRC_FORCED_SET_RESET: u8 = 0x01;
75pub(crate) const SRC_FORCED_CANCEL: u8 = 0x02;
77
78pub const MAX_WORDS_PER_COMMAND: u16 = 700;
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub struct Address {
88 pub word: u16,
90 pub bit: u8,
92}
93
94impl Address {
95 pub fn word(word: u16) -> Self {
107 Self { word, bit: 0 }
108 }
109
110 pub fn bit(word: u16, bit: u8) -> Result<Self> {
126 if bit > 15 {
127 return Err(FinsError::invalid_parameter("bit", "must be 0-15"));
128 }
129 Ok(Self { word, bit })
130 }
131
132 pub(crate) fn to_bytes(self) -> [u8; 3] {
134 [(self.word >> 8) as u8, (self.word & 0xFF) as u8, self.bit]
135 }
136}
137
138#[derive(Debug, Clone)]
140pub struct ReadWordCommand {
141 header: FinsHeader,
142 area: MemoryArea,
143 address: Address,
144 count: u16,
145}
146
147impl ReadWordCommand {
148 pub fn new(
178 destination: NodeAddress,
179 source: NodeAddress,
180 sid: u8,
181 area: MemoryArea,
182 word_address: u16,
183 count: u16,
184 ) -> Result<Self> {
185 if count == 0 {
186 return Err(FinsError::invalid_parameter(
187 "count",
188 "must be greater than 0",
189 ));
190 }
191 if count > area.max_words() {
192 return Err(FinsError::invalid_parameter(
193 "count",
194 format!(
195 "must not exceed area capacity of {} words",
196 area.max_words()
197 ),
198 ));
199 }
200
201 Ok(Self {
202 header: FinsHeader::new_command(destination, source, sid),
203 area,
204 address: Address::word(word_address),
205 count,
206 })
207 }
208
209 pub fn sid(&self) -> u8 {
211 self.header.sid
212 }
213
214 pub fn to_bytes(&self) -> Vec<u8> {
216 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 8);
217 bytes.extend_from_slice(&self.header.to_bytes());
218 bytes.push(MRC_MEMORY_READ);
219 bytes.push(SRC_MEMORY_READ);
220 bytes.push(self.area.word_code());
221 bytes.extend_from_slice(&self.address.to_bytes());
222 bytes.push((self.count >> 8) as u8);
223 bytes.push((self.count & 0xFF) as u8);
224 bytes
225 }
226}
227
228#[derive(Debug, Clone)]
230pub struct WriteWordCommand {
231 header: FinsHeader,
232 area: MemoryArea,
233 address: Address,
234 data: Vec<u16>,
235}
236
237impl WriteWordCommand {
238 pub fn new(
268 destination: NodeAddress,
269 source: NodeAddress,
270 sid: u8,
271 area: MemoryArea,
272 word_address: u16,
273 data: &[u16],
274 ) -> Result<Self> {
275 if data.is_empty() {
276 return Err(FinsError::invalid_parameter("data", "must not be empty"));
277 }
278 if data.len() > area.max_words() as usize {
279 return Err(FinsError::invalid_parameter(
280 "data",
281 format!(
282 "must not exceed area capacity of {} words",
283 area.max_words()
284 ),
285 ));
286 }
287
288 Ok(Self {
289 header: FinsHeader::new_command(destination, source, sid),
290 area,
291 address: Address::word(word_address),
292 data: data.to_vec(),
293 })
294 }
295
296 pub fn sid(&self) -> u8 {
298 self.header.sid
299 }
300
301 pub fn to_bytes(&self) -> Vec<u8> {
303 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 8 + self.data.len() * 2);
304 bytes.extend_from_slice(&self.header.to_bytes());
305 bytes.push(MRC_MEMORY_WRITE);
306 bytes.push(SRC_MEMORY_WRITE);
307 bytes.push(self.area.word_code());
308 bytes.extend_from_slice(&self.address.to_bytes());
309 bytes.push((self.data.len() >> 8) as u8);
310 bytes.push((self.data.len() & 0xFF) as u8);
311 for word in &self.data {
312 bytes.push((word >> 8) as u8);
313 bytes.push((word & 0xFF) as u8);
314 }
315 bytes
316 }
317}
318
319#[derive(Debug, Clone)]
321pub struct ReadBitCommand {
322 header: FinsHeader,
323 area: MemoryArea,
324 address: Address,
325}
326
327impl ReadBitCommand {
328 pub fn new(
360 destination: NodeAddress,
361 source: NodeAddress,
362 sid: u8,
363 area: MemoryArea,
364 word_address: u16,
365 bit: u8,
366 ) -> Result<Self> {
367 area.bit_code()?;
369
370 Ok(Self {
371 header: FinsHeader::new_command(destination, source, sid),
372 area,
373 address: Address::bit(word_address, bit)?,
374 })
375 }
376
377 pub fn sid(&self) -> u8 {
379 self.header.sid
380 }
381
382 pub fn to_bytes(&self) -> Result<Vec<u8>> {
384 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 8);
385 bytes.extend_from_slice(&self.header.to_bytes());
386 bytes.push(MRC_MEMORY_READ);
387 bytes.push(SRC_MEMORY_READ);
388 bytes.push(self.area.bit_code()?);
389 bytes.extend_from_slice(&self.address.to_bytes());
390 bytes.push(0x00); bytes.push(0x01); Ok(bytes)
393 }
394}
395
396#[derive(Debug, Clone)]
398pub struct WriteBitCommand {
399 header: FinsHeader,
400 area: MemoryArea,
401 address: Address,
402 value: bool,
403}
404
405impl WriteBitCommand {
406 pub fn new(
440 destination: NodeAddress,
441 source: NodeAddress,
442 sid: u8,
443 area: MemoryArea,
444 word_address: u16,
445 bit: u8,
446 value: bool,
447 ) -> Result<Self> {
448 area.bit_code()?;
450
451 Ok(Self {
452 header: FinsHeader::new_command(destination, source, sid),
453 area,
454 address: Address::bit(word_address, bit)?,
455 value,
456 })
457 }
458
459 pub fn sid(&self) -> u8 {
461 self.header.sid
462 }
463
464 pub fn to_bytes(&self) -> Result<Vec<u8>> {
466 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 9);
467 bytes.extend_from_slice(&self.header.to_bytes());
468 bytes.push(MRC_MEMORY_WRITE);
469 bytes.push(SRC_MEMORY_WRITE);
470 bytes.push(self.area.bit_code()?);
471 bytes.extend_from_slice(&self.address.to_bytes());
472 bytes.push(0x00); bytes.push(0x01); bytes.push(if self.value { 0x01 } else { 0x00 });
475 Ok(bytes)
476 }
477}
478
479#[derive(Debug, Clone)]
481pub struct FillCommand {
482 header: FinsHeader,
483 area: MemoryArea,
484 address: Address,
485 count: u16,
486 value: u16,
487}
488
489impl FillCommand {
490 pub fn new(
522 destination: NodeAddress,
523 source: NodeAddress,
524 sid: u8,
525 area: MemoryArea,
526 word_address: u16,
527 count: u16,
528 value: u16,
529 ) -> Result<Self> {
530 if count == 0 {
531 return Err(FinsError::invalid_parameter(
532 "count",
533 "must be greater than 0",
534 ));
535 }
536 if count > area.max_words() {
537 return Err(FinsError::invalid_parameter(
538 "count",
539 format!(
540 "must not exceed area capacity of {} words",
541 area.max_words()
542 ),
543 ));
544 }
545
546 Ok(Self {
547 header: FinsHeader::new_command(destination, source, sid),
548 area,
549 address: Address::word(word_address),
550 count,
551 value,
552 })
553 }
554
555 pub fn sid(&self) -> u8 {
557 self.header.sid
558 }
559
560 pub fn to_bytes(&self) -> Vec<u8> {
562 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 10);
563 bytes.extend_from_slice(&self.header.to_bytes());
564 bytes.push(MRC_MEMORY_READ); bytes.push(SRC_MEMORY_FILL);
566 bytes.push(self.area.word_code());
567 bytes.extend_from_slice(&self.address.to_bytes());
568 bytes.push((self.count >> 8) as u8);
569 bytes.push((self.count & 0xFF) as u8);
570 bytes.push((self.value >> 8) as u8);
571 bytes.push((self.value & 0xFF) as u8);
572 bytes
573 }
574}
575
576#[derive(Debug, Clone, Copy, PartialEq, Eq)]
578pub enum PlcMode {
579 Debug,
581 Monitor,
583 Run,
585}
586
587impl PlcMode {
588 pub(crate) fn code(self) -> u8 {
590 match self {
591 PlcMode::Debug => 0x01,
592 PlcMode::Monitor => 0x02,
593 PlcMode::Run => 0x04,
594 }
595 }
596}
597
598#[derive(Debug, Clone)]
600pub struct RunCommand {
601 header: FinsHeader,
602 mode: PlcMode,
603}
604
605impl RunCommand {
606 pub fn new(destination: NodeAddress, source: NodeAddress, sid: u8, mode: PlcMode) -> Self {
628 Self {
629 header: FinsHeader::new_command(destination, source, sid),
630 mode,
631 }
632 }
633
634 pub fn sid(&self) -> u8 {
636 self.header.sid
637 }
638
639 pub fn to_bytes(&self) -> Vec<u8> {
641 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 5);
642 bytes.extend_from_slice(&self.header.to_bytes());
643 bytes.push(MRC_RUN);
644 bytes.push(SRC_RUN);
645 bytes.push(0xFF); bytes.push(0xFF); bytes.push(self.mode.code());
648 bytes
649 }
650}
651
652#[derive(Debug, Clone)]
654pub struct StopCommand {
655 header: FinsHeader,
656}
657
658impl StopCommand {
659 pub fn new(destination: NodeAddress, source: NodeAddress, sid: u8) -> Self {
679 Self {
680 header: FinsHeader::new_command(destination, source, sid),
681 }
682 }
683
684 pub fn sid(&self) -> u8 {
686 self.header.sid
687 }
688
689 pub fn to_bytes(&self) -> Vec<u8> {
691 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 2);
692 bytes.extend_from_slice(&self.header.to_bytes());
693 bytes.push(MRC_RUN);
694 bytes.push(SRC_STOP);
695 bytes
696 }
697}
698
699#[derive(Debug, Clone)]
701pub struct TransferCommand {
702 header: FinsHeader,
703 src_area: MemoryArea,
704 src_address: Address,
705 dst_area: MemoryArea,
706 dst_address: Address,
707 count: u16,
708}
709
710impl TransferCommand {
711 #[allow(clippy::too_many_arguments)]
745 pub fn new(
746 destination: NodeAddress,
747 source: NodeAddress,
748 sid: u8,
749 src_area: MemoryArea,
750 src_address: u16,
751 dst_area: MemoryArea,
752 dst_address: u16,
753 count: u16,
754 ) -> Result<Self> {
755 if count == 0 {
756 return Err(FinsError::invalid_parameter(
757 "count",
758 "must be greater than 0",
759 ));
760 }
761 let max_transfer = std::cmp::min(src_area.max_words(), dst_area.max_words());
762 if count > max_transfer {
763 return Err(FinsError::invalid_parameter(
764 "count",
765 format!("must not exceed area capacity of {} words", max_transfer),
766 ));
767 }
768
769 Ok(Self {
770 header: FinsHeader::new_command(destination, source, sid),
771 src_area,
772 src_address: Address::word(src_address),
773 dst_area,
774 dst_address: Address::word(dst_address),
775 count,
776 })
777 }
778
779 pub fn sid(&self) -> u8 {
781 self.header.sid
782 }
783
784 pub fn to_bytes(&self) -> Vec<u8> {
786 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 12);
787 bytes.extend_from_slice(&self.header.to_bytes());
788 bytes.push(MRC_MEMORY_READ); bytes.push(SRC_MEMORY_TRANSFER);
790 bytes.push(self.src_area.word_code());
791 bytes.extend_from_slice(&self.src_address.to_bytes());
792 bytes.push(self.dst_area.word_code());
793 bytes.extend_from_slice(&self.dst_address.to_bytes());
794 bytes.push((self.count >> 8) as u8);
795 bytes.push((self.count & 0xFF) as u8);
796 bytes
797 }
798}
799
800#[derive(Debug, Clone, Copy, PartialEq, Eq)]
802pub enum ForceSpec {
803 ForceOff,
805 ForceOn,
807 Release,
809}
810
811impl ForceSpec {
812 pub(crate) fn code(self) -> u16 {
814 match self {
815 ForceSpec::ForceOff => 0x0000,
816 ForceSpec::ForceOn => 0x0001,
817 ForceSpec::Release => 0x8000,
818 }
819 }
820}
821
822#[derive(Debug, Clone)]
824pub struct ForcedBit {
825 pub area: MemoryArea,
827 pub address: u16,
829 pub bit: u8,
831 pub spec: ForceSpec,
833}
834
835#[derive(Debug, Clone)]
837pub struct ForcedSetResetCommand {
838 header: FinsHeader,
839 specs: Vec<ForcedBit>,
840}
841
842impl ForcedSetResetCommand {
843 pub fn new(
872 destination: NodeAddress,
873 source: NodeAddress,
874 sid: u8,
875 specs: Vec<ForcedBit>,
876 ) -> Result<Self> {
877 if specs.is_empty() {
878 return Err(FinsError::invalid_parameter("specs", "must not be empty"));
879 }
880
881 for spec in &specs {
883 spec.area.bit_code()?;
884 if spec.bit > 15 {
885 return Err(FinsError::invalid_parameter("bit", "must be 0-15"));
886 }
887 }
888
889 Ok(Self {
890 header: FinsHeader::new_command(destination, source, sid),
891 specs,
892 })
893 }
894
895 pub fn sid(&self) -> u8 {
897 self.header.sid
898 }
899
900 pub fn to_bytes(&self) -> Result<Vec<u8>> {
902 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 4 + self.specs.len() * 6);
903 bytes.extend_from_slice(&self.header.to_bytes());
904 bytes.push(MRC_FORCED);
905 bytes.push(SRC_FORCED_SET_RESET);
906 bytes.push((self.specs.len() >> 8) as u8);
907 bytes.push((self.specs.len() & 0xFF) as u8);
908
909 for spec in &self.specs {
910 let code = spec.spec.code();
911 bytes.push((code >> 8) as u8);
912 bytes.push((code & 0xFF) as u8);
913 bytes.push(spec.area.bit_code()?);
914 bytes.push((spec.address >> 8) as u8);
915 bytes.push((spec.address & 0xFF) as u8);
916 bytes.push(spec.bit);
917 }
918
919 Ok(bytes)
920 }
921}
922
923#[derive(Debug, Clone)]
925pub struct ForcedSetResetCancelCommand {
926 header: FinsHeader,
927}
928
929impl ForcedSetResetCancelCommand {
930 pub fn new(destination: NodeAddress, source: NodeAddress, sid: u8) -> Self {
950 Self {
951 header: FinsHeader::new_command(destination, source, sid),
952 }
953 }
954
955 pub fn sid(&self) -> u8 {
957 self.header.sid
958 }
959
960 pub fn to_bytes(&self) -> Vec<u8> {
962 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 2);
963 bytes.extend_from_slice(&self.header.to_bytes());
964 bytes.push(MRC_FORCED);
965 bytes.push(SRC_FORCED_CANCEL);
966 bytes
967 }
968}
969
970#[derive(Debug, Clone)]
972pub struct MultiReadSpec {
973 pub area: MemoryArea,
975 pub address: u16,
977 pub bit: Option<u8>,
979}
980
981#[derive(Debug, Clone)]
983pub struct MultipleReadCommand {
984 header: FinsHeader,
985 specs: Vec<MultiReadSpec>,
986}
987
988impl MultipleReadCommand {
989 pub fn new(
1019 destination: NodeAddress,
1020 source: NodeAddress,
1021 sid: u8,
1022 specs: Vec<MultiReadSpec>,
1023 ) -> Result<Self> {
1024 if specs.is_empty() {
1025 return Err(FinsError::invalid_parameter("specs", "must not be empty"));
1026 }
1027
1028 for spec in &specs {
1030 if let Some(bit) = spec.bit {
1031 spec.area.bit_code()?;
1032 if bit > 15 {
1033 return Err(FinsError::invalid_parameter("bit", "must be 0-15"));
1034 }
1035 }
1036 }
1037
1038 Ok(Self {
1039 header: FinsHeader::new_command(destination, source, sid),
1040 specs,
1041 })
1042 }
1043
1044 pub fn sid(&self) -> u8 {
1046 self.header.sid
1047 }
1048
1049 pub fn to_bytes(&self) -> Result<Vec<u8>> {
1051 let mut bytes = Vec::with_capacity(FINS_HEADER_SIZE + 2 + self.specs.len() * 4);
1052 bytes.extend_from_slice(&self.header.to_bytes());
1053 bytes.push(MRC_MEMORY_READ);
1054 bytes.push(SRC_MULTIPLE_READ);
1055
1056 for spec in &self.specs {
1057 if let Some(bit) = spec.bit {
1058 bytes.push(spec.area.bit_code()?);
1059 bytes.push((spec.address >> 8) as u8);
1060 bytes.push((spec.address & 0xFF) as u8);
1061 bytes.push(bit);
1062 } else {
1063 bytes.push(spec.area.word_code());
1064 bytes.push((spec.address >> 8) as u8);
1065 bytes.push((spec.address & 0xFF) as u8);
1066 bytes.push(0x00);
1067 }
1068 }
1069
1070 Ok(bytes)
1071 }
1072}
1073
1074#[cfg(test)]
1075mod tests {
1076 use super::*;
1077
1078 fn test_addresses() -> (NodeAddress, NodeAddress) {
1079 (NodeAddress::new(0, 10, 0), NodeAddress::new(0, 1, 0))
1080 }
1081
1082 #[test]
1083 fn test_address_word() {
1084 let addr = Address::word(0x1234);
1085 assert_eq!(addr.word, 0x1234);
1086 assert_eq!(addr.bit, 0);
1087 assert_eq!(addr.to_bytes(), [0x12, 0x34, 0x00]);
1088 }
1089
1090 #[test]
1091 fn test_address_bit() {
1092 let addr = Address::bit(0x1234, 5).unwrap();
1093 assert_eq!(addr.word, 0x1234);
1094 assert_eq!(addr.bit, 5);
1095 assert_eq!(addr.to_bytes(), [0x12, 0x34, 0x05]);
1096 }
1097
1098 #[test]
1099 fn test_address_bit_invalid() {
1100 let result = Address::bit(100, 16);
1101 assert!(result.is_err());
1102 }
1103
1104 #[test]
1105 fn test_read_word_command_serialization() {
1106 let (dest, src) = test_addresses();
1107 let cmd = ReadWordCommand::new(dest, src, 0x01, MemoryArea::DM, 100, 10).unwrap();
1108 let bytes = cmd.to_bytes();
1109
1110 assert_eq!(bytes.len(), 18);
1112
1113 assert_eq!(bytes[0], 0x80); assert_eq!(bytes[9], 0x01); assert_eq!(bytes[10], MRC_MEMORY_READ);
1119 assert_eq!(bytes[11], SRC_MEMORY_READ);
1120 assert_eq!(bytes[12], 0x82); assert_eq!(bytes[13], 0x00);
1124 assert_eq!(bytes[14], 0x64);
1125 assert_eq!(bytes[15], 0x00); assert_eq!(bytes[16], 0x00);
1129 assert_eq!(bytes[17], 0x0A);
1130 }
1131
1132 #[test]
1133 fn test_read_word_command_invalid_count() {
1134 let (dest, src) = test_addresses();
1135
1136 let result = ReadWordCommand::new(dest, src, 0x01, MemoryArea::DM, 100, 0);
1137 assert!(result.is_err());
1138
1139 let result = ReadWordCommand::new(dest, src, 0x01, MemoryArea::DM, 100, 4097);
1140 assert!(result.is_err());
1141 }
1142
1143 #[test]
1144 fn test_write_word_command_serialization() {
1145 let (dest, src) = test_addresses();
1146 let cmd =
1147 WriteWordCommand::new(dest, src, 0x02, MemoryArea::DM, 100, &[0x1234, 0x5678]).unwrap();
1148 let bytes = cmd.to_bytes();
1149
1150 assert_eq!(bytes.len(), 22);
1152
1153 assert_eq!(bytes[10], MRC_MEMORY_WRITE);
1155 assert_eq!(bytes[11], SRC_MEMORY_WRITE);
1156
1157 assert_eq!(bytes[16], 0x00);
1159 assert_eq!(bytes[17], 0x02);
1160
1161 assert_eq!(bytes[18], 0x12);
1163 assert_eq!(bytes[19], 0x34);
1164 assert_eq!(bytes[20], 0x56);
1165 assert_eq!(bytes[21], 0x78);
1166 }
1167
1168 #[test]
1169 fn test_write_word_command_invalid_data() {
1170 let (dest, src) = test_addresses();
1171
1172 let result = WriteWordCommand::new(dest, src, 0x01, MemoryArea::DM, 100, &[]);
1173 assert!(result.is_err());
1174 }
1175
1176 #[test]
1177 fn test_read_bit_command_serialization() {
1178 let (dest, src) = test_addresses();
1179 let cmd = ReadBitCommand::new(dest, src, 0x03, MemoryArea::CIO, 100, 5).unwrap();
1180 let bytes = cmd.to_bytes().unwrap();
1181
1182 assert_eq!(bytes.len(), 18);
1184
1185 assert_eq!(bytes[12], 0x30);
1187
1188 assert_eq!(bytes[13], 0x00);
1190 assert_eq!(bytes[14], 0x64); assert_eq!(bytes[15], 0x05); assert_eq!(bytes[16], 0x00);
1195 assert_eq!(bytes[17], 0x01);
1196 }
1197
1198 #[test]
1199 fn test_read_bit_command_dm_fails() {
1200 let (dest, src) = test_addresses();
1201 let result = ReadBitCommand::new(dest, src, 0x01, MemoryArea::DM, 100, 5);
1202 assert!(result.is_err());
1203 }
1204
1205 #[test]
1206 fn test_write_bit_command_serialization() {
1207 let (dest, src) = test_addresses();
1208 let cmd = WriteBitCommand::new(dest, src, 0x04, MemoryArea::WR, 50, 10, true).unwrap();
1209 let bytes = cmd.to_bytes().unwrap();
1210
1211 assert_eq!(bytes.len(), 19);
1213
1214 assert_eq!(bytes[12], 0x31);
1216
1217 assert_eq!(bytes[13], 0x00);
1219 assert_eq!(bytes[14], 0x32); assert_eq!(bytes[15], 0x0A); assert_eq!(bytes[18], 0x01); }
1225
1226 #[test]
1227 fn test_write_bit_command_false_value() {
1228 let (dest, src) = test_addresses();
1229 let cmd = WriteBitCommand::new(dest, src, 0x05, MemoryArea::HR, 200, 0, false).unwrap();
1230 let bytes = cmd.to_bytes().unwrap();
1231
1232 assert_eq!(bytes[12], 0x32); assert_eq!(bytes[18], 0x00); }
1235
1236 #[test]
1237 fn test_fill_command_serialization() {
1238 let (dest, src) = test_addresses();
1239 let cmd = FillCommand::new(dest, src, 0x01, MemoryArea::DM, 100, 50, 0xABCD).unwrap();
1240 let bytes = cmd.to_bytes();
1241
1242 assert_eq!(bytes.len(), 20);
1244
1245 assert_eq!(bytes[10], MRC_MEMORY_READ); assert_eq!(bytes[11], SRC_MEMORY_FILL); assert_eq!(bytes[12], 0x82); assert_eq!(bytes[13], 0x00);
1252 assert_eq!(bytes[14], 0x64);
1253 assert_eq!(bytes[15], 0x00); assert_eq!(bytes[16], 0x00);
1257 assert_eq!(bytes[17], 0x32);
1258
1259 assert_eq!(bytes[18], 0xAB);
1261 assert_eq!(bytes[19], 0xCD);
1262 }
1263
1264 #[test]
1265 fn test_fill_command_invalid_count() {
1266 let (dest, src) = test_addresses();
1267
1268 let result = FillCommand::new(dest, src, 0x01, MemoryArea::DM, 100, 0, 0x0000);
1269 assert!(result.is_err());
1270
1271 let result = FillCommand::new(dest, src, 0x01, MemoryArea::DM, 100, 4097, 0x0000);
1272 assert!(result.is_err());
1273 }
1274
1275 #[test]
1276 fn test_run_command_serialization() {
1277 let (dest, src) = test_addresses();
1278 let cmd = RunCommand::new(dest, src, 0x01, PlcMode::Monitor);
1279 let bytes = cmd.to_bytes();
1280
1281 assert_eq!(bytes.len(), 15);
1283
1284 assert_eq!(bytes[10], MRC_RUN); assert_eq!(bytes[11], SRC_RUN); assert_eq!(bytes[12], 0xFF);
1290 assert_eq!(bytes[13], 0xFF);
1291
1292 assert_eq!(bytes[14], 0x02);
1294 }
1295
1296 #[test]
1297 fn test_run_command_modes() {
1298 let (dest, src) = test_addresses();
1299
1300 let cmd = RunCommand::new(dest, src, 0x01, PlcMode::Debug);
1301 assert_eq!(cmd.to_bytes()[14], 0x01);
1302
1303 let cmd = RunCommand::new(dest, src, 0x01, PlcMode::Monitor);
1304 assert_eq!(cmd.to_bytes()[14], 0x02);
1305
1306 let cmd = RunCommand::new(dest, src, 0x01, PlcMode::Run);
1307 assert_eq!(cmd.to_bytes()[14], 0x04);
1308 }
1309
1310 #[test]
1311 fn test_stop_command_serialization() {
1312 let (dest, src) = test_addresses();
1313 let cmd = StopCommand::new(dest, src, 0x01);
1314 let bytes = cmd.to_bytes();
1315
1316 assert_eq!(bytes.len(), 12);
1318
1319 assert_eq!(bytes[10], MRC_RUN); assert_eq!(bytes[11], SRC_STOP); }
1323
1324 #[test]
1325 fn test_transfer_command_serialization() {
1326 let (dest, src) = test_addresses();
1327 let cmd = TransferCommand::new(
1328 dest,
1329 src,
1330 0x01,
1331 MemoryArea::DM,
1332 100,
1333 MemoryArea::DM,
1334 200,
1335 10,
1336 )
1337 .unwrap();
1338 let bytes = cmd.to_bytes();
1339
1340 assert_eq!(bytes.len(), 22);
1342
1343 assert_eq!(bytes[10], MRC_MEMORY_READ); assert_eq!(bytes[11], SRC_MEMORY_TRANSFER); assert_eq!(bytes[12], 0x82); assert_eq!(bytes[13], 0x00);
1350 assert_eq!(bytes[14], 0x64); assert_eq!(bytes[15], 0x00);
1352
1353 assert_eq!(bytes[16], 0x82); assert_eq!(bytes[17], 0x00);
1356 assert_eq!(bytes[18], 0xC8); assert_eq!(bytes[19], 0x00);
1358
1359 assert_eq!(bytes[20], 0x00);
1361 assert_eq!(bytes[21], 0x0A);
1362 }
1363
1364 #[test]
1365 fn test_transfer_command_invalid_count() {
1366 let (dest, src) = test_addresses();
1367
1368 let result =
1369 TransferCommand::new(dest, src, 0x01, MemoryArea::DM, 100, MemoryArea::DM, 200, 0);
1370 assert!(result.is_err());
1371
1372 let result = TransferCommand::new(
1373 dest,
1374 src,
1375 0x01,
1376 MemoryArea::DM,
1377 100,
1378 MemoryArea::DM,
1379 200,
1380 4097,
1381 );
1382 assert!(result.is_err());
1383 }
1384
1385 #[test]
1386 fn test_forced_set_reset_command_serialization() {
1387 let (dest, src) = test_addresses();
1388 let cmd = ForcedSetResetCommand::new(
1389 dest,
1390 src,
1391 0x01,
1392 vec![
1393 ForcedBit {
1394 area: MemoryArea::CIO,
1395 address: 0,
1396 bit: 0,
1397 spec: ForceSpec::ForceOn,
1398 },
1399 ForcedBit {
1400 area: MemoryArea::CIO,
1401 address: 0,
1402 bit: 1,
1403 spec: ForceSpec::ForceOff,
1404 },
1405 ],
1406 )
1407 .unwrap();
1408 let bytes = cmd.to_bytes().unwrap();
1409
1410 assert_eq!(bytes.len(), 26);
1412
1413 assert_eq!(bytes[10], MRC_FORCED); assert_eq!(bytes[11], SRC_FORCED_SET_RESET); assert_eq!(bytes[12], 0x00);
1419 assert_eq!(bytes[13], 0x02);
1420
1421 assert_eq!(bytes[14], 0x00); assert_eq!(bytes[15], 0x01); assert_eq!(bytes[16], 0x30); assert_eq!(bytes[17], 0x00); assert_eq!(bytes[18], 0x00); assert_eq!(bytes[19], 0x00); assert_eq!(bytes[20], 0x00); assert_eq!(bytes[21], 0x00); assert_eq!(bytes[22], 0x30); assert_eq!(bytes[23], 0x00); assert_eq!(bytes[24], 0x00); assert_eq!(bytes[25], 0x01); }
1437
1438 #[test]
1439 fn test_forced_set_reset_command_empty_specs() {
1440 let (dest, src) = test_addresses();
1441 let result = ForcedSetResetCommand::new(dest, src, 0x01, vec![]);
1442 assert!(result.is_err());
1443 }
1444
1445 #[test]
1446 fn test_forced_set_reset_command_dm_fails() {
1447 let (dest, src) = test_addresses();
1448 let result = ForcedSetResetCommand::new(
1449 dest,
1450 src,
1451 0x01,
1452 vec![ForcedBit {
1453 area: MemoryArea::DM,
1454 address: 0,
1455 bit: 0,
1456 spec: ForceSpec::ForceOn,
1457 }],
1458 );
1459 assert!(result.is_err());
1460 }
1461
1462 #[test]
1463 fn test_forced_set_reset_cancel_command_serialization() {
1464 let (dest, src) = test_addresses();
1465 let cmd = ForcedSetResetCancelCommand::new(dest, src, 0x01);
1466 let bytes = cmd.to_bytes();
1467
1468 assert_eq!(bytes.len(), 12);
1470
1471 assert_eq!(bytes[10], MRC_FORCED); assert_eq!(bytes[11], SRC_FORCED_CANCEL); }
1475
1476 #[test]
1477 fn test_multiple_read_command_serialization() {
1478 let (dest, src) = test_addresses();
1479 let cmd = MultipleReadCommand::new(
1480 dest,
1481 src,
1482 0x01,
1483 vec![
1484 MultiReadSpec {
1485 area: MemoryArea::DM,
1486 address: 100,
1487 bit: None,
1488 },
1489 MultiReadSpec {
1490 area: MemoryArea::DM,
1491 address: 200,
1492 bit: None,
1493 },
1494 MultiReadSpec {
1495 area: MemoryArea::CIO,
1496 address: 0,
1497 bit: Some(5),
1498 },
1499 ],
1500 )
1501 .unwrap();
1502 let bytes = cmd.to_bytes().unwrap();
1503
1504 assert_eq!(bytes.len(), 24);
1506
1507 assert_eq!(bytes[10], MRC_MEMORY_READ); assert_eq!(bytes[11], SRC_MULTIPLE_READ); assert_eq!(bytes[12], 0x82); assert_eq!(bytes[13], 0x00);
1514 assert_eq!(bytes[14], 0x64); assert_eq!(bytes[15], 0x00);
1516
1517 assert_eq!(bytes[16], 0x82); assert_eq!(bytes[17], 0x00);
1520 assert_eq!(bytes[18], 0xC8); assert_eq!(bytes[19], 0x00);
1522
1523 assert_eq!(bytes[20], 0x30); assert_eq!(bytes[21], 0x00);
1526 assert_eq!(bytes[22], 0x00); assert_eq!(bytes[23], 0x05); }
1529
1530 #[test]
1531 fn test_multiple_read_command_empty_specs() {
1532 let (dest, src) = test_addresses();
1533 let result = MultipleReadCommand::new(dest, src, 0x01, vec![]);
1534 assert!(result.is_err());
1535 }
1536
1537 #[test]
1538 fn test_multiple_read_command_dm_bit_fails() {
1539 let (dest, src) = test_addresses();
1540 let result = MultipleReadCommand::new(
1541 dest,
1542 src,
1543 0x01,
1544 vec![MultiReadSpec {
1545 area: MemoryArea::DM,
1546 address: 100,
1547 bit: Some(5),
1548 }],
1549 );
1550 assert!(result.is_err());
1551 }
1552
1553 #[test]
1554 fn test_force_spec_codes() {
1555 assert_eq!(ForceSpec::ForceOff.code(), 0x0000);
1556 assert_eq!(ForceSpec::ForceOn.code(), 0x0001);
1557 assert_eq!(ForceSpec::Release.code(), 0x8000);
1558 }
1559
1560 #[test]
1561 fn test_plc_mode_codes() {
1562 assert_eq!(PlcMode::Debug.code(), 0x01);
1563 assert_eq!(PlcMode::Monitor.code(), 0x02);
1564 assert_eq!(PlcMode::Run.code(), 0x04);
1565 }
1566}