semi_e37/
generic.rs

1//! # GENERIC SERVICES
2//! 
3//! Defines the full functionality of the [HSMS] protocol without modification
4//! by any subsidiary standards. This involves the sending of messages of
5//! particular types and at particular times as allowed by the protocol.
6//! 
7//! ---------------------------------------------------------------------------
8//! 
9//! To use the [Generic Services]:
10//! 
11//! - Build [Message]s which use a [Message ID] and [Message Contents]:
12//!   - [Data Message]
13//!   - [Select.req]
14//!   - [Select.rsp]
15//!   - [Deselect.req]
16//!   - [Deselect.rsp]
17//!   - [Linktest.req]
18//!   - [Linktest.rsp]
19//!   - [Reject.req]
20//!   - [Separate.req]
21//! - Create an [Client] by providing the [New Client] function with
22//!   [Parameter Settings].
23//! - Manage the [Connection State] with the [Connect Procedure] and
24//!   [Disconnect Procedure].
25//! - Manage the [Selection State] with the [Select Procedure],
26//!   [Deselect Procedure], and [Separate Procedure].
27//! - Receive [Data Message]s with the hook provided by the
28//!   [Connect Procedure].
29//! - Test connection integrity with the [Linktest Procedure].
30//! - Send [Data Message]s with the [Data Procedure].
31//! - Send [Reject.req] messages [Reject Procedure].
32//! 
33//! [HSMS]:                 crate
34//! [Generic Services]:     crate::generic
35//! [Client]:               Client
36//! [New Client]:           Client::new
37//! [Connect Procedure]:    Client::connect
38//! [Disconnect Procedure]: Client::disconnect
39//! [Select Procedure]:     Client::select
40//! [Deselect Procedure]:   Client::deselect
41//! [Separate Procedure]:   Client::separate
42//! [Linktest Procedure]:   Client::linktest
43//! [Data Procedure]:       Client::data
44//! [Reject Procedure]:     Client::reject
45//! [Message]:              Message
46//! [Message ID]:           MessageID
47//! [Message Contents]:     MessageContents
48//! [Data Message]:         MessageContents::DataMessage
49//! [Select.req]:           MessageContents::SelectRequest
50//! [Select.rsp]:           MessageContents::SelectResponse
51//! [Deselect.req]:         MessageContents::DeselectRequest
52//! [Deselect.rsp]:         MessageContents::DeselectResponse
53//! [Linktest.req]:         MessageContents::LinktestRequest
54//! [Linktest.rsp]:         MessageContents::LinktestResponse
55//! [Reject.req]:           MessageContents::RejectRequest
56//! [Separate.req]:         MessageContents::SeparateRequest
57//! [Connection State]:     crate::primitive::ConnectionState
58//! [Selection State]:      SelectionState
59//! [Parameter Settings]:   ParameterSettings
60
61use std::{
62  collections::HashMap,
63  io::{
64    Error,
65    ErrorKind,
66  },
67  net::SocketAddr,
68  ops::{
69    Deref,
70    DerefMut,
71  },
72  sync::{
73    atomic::Ordering::Relaxed,
74    Arc,
75    Mutex,
76    mpsc::{
77      channel,
78      Receiver,
79      Sender,
80    },
81  },
82  thread::{
83    self,
84    JoinHandle,
85  },
86  time::Duration,
87};
88use atomic::Atomic;
89use bytemuck::NoUninit;
90use oneshot::Sender as SendOnce;
91use crate::{
92  PresentationType,
93  primitive,
94};
95
96pub use crate::primitive::ConnectionMode;
97
98/// ## CLIENT
99/// 
100/// Encapsulates the full functionality of the [HSMS] protocol without
101/// reference to any subsidiary standards, known as the [Generic Services].
102/// 
103/// [HSMS]:             crate
104/// [Generic Services]: crate::generic
105pub struct Client {
106  parameter_settings: ParameterSettings,
107  primitive_client: Arc<primitive::Client>,
108  selection_state: Atomic<SelectionState>,
109  selection_mutex: Mutex<()>,
110  outbox: Mutex<HashMap<u32, (MessageID, SendOnce<Option<Message>>)>>,
111  system: Mutex<u32>,
112}
113
114/// ## CONNECTION PROCEDURES
115/// **Based on SEMI E37-1109§6.3-6.5**
116/// 
117/// Encapsulates the parts of the [Client]'s functionality dealing with
118/// establishing and breaking a TCP/IP connection.
119/// 
120/// - [New Client]
121/// - [Connect Procedure]
122/// - [Disconnect Procedure]
123/// 
124/// [Client]:               Client
125/// [New Client]:           Client::new
126/// [Connect Procedure]:    Client::connect
127/// [Disconnect Procedure]: Client::disconnect
128impl Client {
129  /// ### NEW CLIENT
130  /// 
131  /// 
132  /// Creates a [Client] in the [NOT CONNECTED] state, ready to initiate the
133  /// [Connect Procedure].
134  /// 
135  /// [Client]:            Client
136  /// [Connect Procedure]: Client::connect
137  /// [NOT CONNECTED]:     primitive::ConnectionState::NotConnected
138  pub fn new(
139    parameter_settings: ParameterSettings
140  ) -> Arc<Self> {
141    Arc::new(Client {
142      parameter_settings,
143      primitive_client: primitive::Client::new(),
144      selection_state:  Default::default(),
145      selection_mutex:  Default::default(),
146      outbox:           Default::default(),
147      system:           Default::default(),
148    })
149  }
150
151  /// ### CONNECT PROCEDURE
152  /// **Based on SEMI E37-1109§6.3.4-6.3.7**
153  /// 
154  /// Connects the [Client] to the Remote Entity.
155  /// 
156  /// -------------------------------------------------------------------------
157  /// 
158  /// The [Connection State] must be in the [NOT CONNECTED] state to use this
159  /// procedure.
160  /// 
161  /// -------------------------------------------------------------------------
162  /// 
163  /// The [Connect Procedure] has two different behaviors based on the
164  /// [Connection Mode] provided to it:
165  /// - [PASSIVE] - The socket address of the Local Entity must be provided,
166  ///   and the [Client] listens for and accepts the [Connect Procedure] when
167  ///   initiated by the Remote Entity.
168  /// - [ACTIVE] - The socket address of the Remote Entity must be provided,
169  ///   and the [Client] initiates the [Connect Procedure] and waits up to the
170  ///   time specified by [T5] for the Remote Entity to respond.
171  /// 
172  /// -------------------------------------------------------------------------
173  /// 
174  /// Upon completion of the [Connect Procedure], the [T8] parameter is set as
175  /// the TCP stream's read and write timeout, and the [CONNECTED] state is
176  /// entered.
177  /// 
178  /// [Connection State]:  primitive::ConnectionState
179  /// [NOT CONNECTED]:     primitive::ConnectionState::NotConnected
180  /// [CONNECTED]:         primitive::ConnectionState::Connected
181  /// [Connection Mode]:   primitive::ConnectionMode
182  /// [PASSIVE]:           primitive::ConnectionMode::Passive
183  /// [ACTIVE]:            primitive::ConnectionMode::Active
184  /// [Client]:            Client
185  /// [Connect Procedure]: Client::connect
186  /// [T5]:                ParameterSettings::t5
187  /// [T8]:                ParameterSettings::t8
188  pub fn connect(
189    self: &Arc<Self>,
190    entity: &str,
191  ) -> Result<(SocketAddr, Receiver<(MessageID, semi_e5::Message)>), Error> {
192    // Connect Primitive Client
193    let (socket, rx_receiver) = self.primitive_client.connect(entity, self.parameter_settings.connect_mode, self.parameter_settings.t5, self.parameter_settings.t8)?;
194    // Create Channel
195    let (data_sender, data_receiver) = channel::<(MessageID, semi_e5::Message)>();
196    // Start RX Thread
197    let clone: Arc<Client> = self.clone();
198    thread::spawn(move || {clone.receive(rx_receiver, data_sender)});
199    // Finish
200    Ok((socket, data_receiver))
201  }
202
203  /// ### DISCONNECT PROCEDURE
204  /// **Based on SEMI E37-1109§6.4-6.5**
205  /// 
206  /// Disconnects the [Client] from the Remote Entity.
207  /// 
208  /// -------------------------------------------------------------------------
209  /// 
210  /// The [Connection State] must be in the [CONNECTED] state to use this
211  /// procedure.
212  /// 
213  /// -------------------------------------------------------------------------
214  /// 
215  /// Upon completion of the [Disconnect Procedure], the [NOT CONNECTED] state
216  /// is entered.
217  /// 
218  /// [Connection State]:     primitive::ConnectionState
219  /// [NOT CONNECTED]:        primitive::ConnectionState::NotConnected
220  /// [CONNECTED]:            primitive::ConnectionState::Connected
221  /// [Client]:               Client
222  /// [Disconnect Procedure]: Client::disconnect
223  pub fn disconnect(
224    self: &Arc<Self>,
225  ) -> Result<(), Error> {
226    // TO: NOT CONNECTED
227    let result: Result<(), Error> = self.primitive_client.disconnect();
228    // TO: NOT SELECTED
229    let _guard = self.selection_mutex.lock().unwrap();
230    if let SelectionState::Selected = self.selection_state.load(Relaxed) {
231      self.selection_state.store(SelectionState::NotSelected, Relaxed);
232    }
233    // Finish
234    result
235  }
236}
237
238/// ## MESSAGE EXCHANGE PROCEDURES
239/// **Based on SEMI E37-1109§7**
240/// 
241/// Encapsulates the parts of the [Client]'s functionality dealing with
242/// exchanging [Message]s.
243/// 
244/// - [Data Procedure] - [Data Message]s
245/// - [Select Procedure] - [Select.req] and [Select.rsp]
246/// - [Deselect Procedure] - [Deselect.req] and [Deselect.rsp]
247/// - [Linktest Procedure] - [Linktest.req] and [Linktest.rsp]
248/// - [Separate Procedure] - [Separate.req]
249/// - [Reject Procedure] - [Reject.req]
250/// 
251/// [Message]:            Message
252/// [Client]:             Client
253/// [Select Procedure]:   Client::select
254/// [Data Procedure]:     Client::data
255/// [Deselect Procedure]: Client::deselect
256/// [Linktest Procedure]: Client::linktest
257/// [Separate Procedure]: Client::separate
258/// [Reject Procedure]:   Client::reject
259/// [Data Message]:       MessageContents::DataMessage
260/// [Select.req]:         MessageContents::SelectRequest
261/// [Select.rsp]:         MessageContents::SelectResponse
262/// [Deselect.req]:       MessageContents::DeselectRequest
263/// [Deselect.rsp]:       MessageContents::DeselectResponse
264/// [Linktest.req]:       MessageContents::LinktestRequest
265/// [Linktest.rsp]:       MessageContents::LinktestResponse
266/// [Reject.req]:         MessageContents::RejectRequest
267/// [Separate.req]:       MessageContents::SeparateRequest
268impl Client {
269  /// ### RECEIVE PROCEDURE
270  /// 
271  /// An [Client] in the [CONNECTED] state will automatically receive
272  /// [Message]s and respond based on their [Message Contents] and the current
273  /// [Selection State].
274  /// 
275  /// -------------------------------------------------------------------------
276  /// 
277  /// #### [Data Message]
278  /// 
279  /// - [NOT SELECTED] - The [Client] will respond by transmitting a
280  ///   [Reject.req] message, rejecting the [HSMS Data Procedure] and
281  ///   completing the [HSMS Reject Procedure].
282  /// - [SELECTED], Primary [Data Message] - The [Client] will send the
283  ///   [Data Message] to the hook provided by the [Connect Procedure].
284  /// - [SELECTED], Response [Data Message] - The [Client] will respond by
285  ///   correllating the message to a previously sent Primary [Data Message],
286  ///   finishing a previously initiated [Data Procedure] if successful,
287  ///   or if unsuccessful by transmitting a [Reject.req] message, rejecting
288  ///   the [Data Procedure] and completing the [Reject Procedure].
289  /// 
290  /// -------------------------------------------------------------------------
291  /// 
292  /// #### [Select.req]:
293  /// 
294  /// - [NOT SELECTED] - The [Client] will respond with a [Select.rsp]
295  ///   accepting and completing the [Select Procedure].
296  /// - [SELECTED] - The [Client] will respond with a [Select.rsp] message
297  ///   rejecting the [Select Procedure].
298  /// 
299  /// -------------------------------------------------------------------------
300  /// 
301  /// #### [Select.rsp]:
302  /// 
303  /// - [NOT SELECTED] - The [Client] will complete the [Select Procedure].
304  /// - [SELECTED] - The [Client] will respond with a [Reject.req] message,
305  ///   completing the [Reject Procedure].
306  /// 
307  /// -------------------------------------------------------------------------
308  /// 
309  /// #### [Deselect.req]:
310  /// 
311  /// - Not yet implemented.
312  /// 
313  /// -------------------------------------------------------------------------
314  /// 
315  /// #### [Deselect.rsp]:
316  /// 
317  /// - Not yet implemented.
318  /// 
319  /// -------------------------------------------------------------------------
320  /// 
321  /// #### [Linktest.req]:
322  /// 
323  /// - The [Client] will respond with a [Linktest.rsp], completing the
324  ///   [Linktest Procedure].
325  /// 
326  /// -------------------------------------------------------------------------
327  /// 
328  /// #### [Linktest.rsp]:
329  /// 
330  /// - The [Client] will respond by correllating the message to a previously
331  ///   sent [Linktest.req] message, finishing a previously initiated
332  ///   [Linktest Procedure] if successful, or if unsuccessful by transmitting
333  ///   a [Reject.req] message, completing the [Reject Procedure].
334  /// 
335  /// -------------------------------------------------------------------------
336  /// 
337  /// #### [Reject.req]:
338  /// 
339  /// - Not yet implemented.
340  /// 
341  /// -------------------------------------------------------------------------
342  /// 
343  /// #### [Separate.req]:
344  /// 
345  /// - [NOT SELECTED] - The [Client] will not do anything.
346  /// - [SELECTED] - The [Client] will complete the [Separate Procedure].
347  /// 
348  /// -------------------------------------------------------------------------
349  /// 
350  /// #### Unknown [Primitive Message]:
351  /// 
352  /// - The [Client] will respond by transmitting a [Reject.req] message,
353  ///   completing the [Reject Procedure]. 
354  /// 
355  /// [Primitive Message]:  primitive::Message
356  /// [Connection State]:   primitive::ConnectionState
357  /// [NOT CONNECTED]:      primitive::ConnectionState::NotConnected
358  /// [CONNECTED]:          primitive::ConnectionState::Connected
359  /// [Message]:            Message
360  /// [Message Contents]:   MessageContents
361  /// [Data Message]:       MessageContents::DataMessage
362  /// [Select.req]:         MessageContents::SelectRequest
363  /// [Select.rsp]:         MessageContents::SelectResponse
364  /// [Deselect.req]:       MessageContents::DeselectRequest
365  /// [Deselect.rsp]:       MessageContents::DeselectResponse
366  /// [Linktest.req]:       MessageContents::LinktestRequest
367  /// [Linktest.rsp]:       MessageContents::LinktestResponse
368  /// [Reject.req]:         MessageContents::RejectRequest
369  /// [Separate.req]:       MessageContents::SeparateRequest
370  /// [Client]:             Client
371  /// [Connect Procedure]:  Client::connect
372  /// [Select Procedure]:   Client::select
373  /// [Data Procedure]:     Client::data
374  /// [Deselect Procedure]: Client::deselect
375  /// [Linktest Procedure]: Client::linktest
376  /// [Separate Procedure]: Client::separate
377  /// [Reject Procedure]:   Client::reject
378  /// [Selection State]:    SelectionState
379  /// [NOT SELECTED]:       SelectionState::NotSelected
380  /// [SELECTED]:           SelectionState::Selected
381  /// [SELECT INITIATED]:   SelectionState::SelectInitiated
382  /// [DESELECT INITIATED]: SelectionState::DeselectInitiated
383  fn receive(
384    self: &Arc<Self>,
385    rx_receiver: Receiver<primitive::Message>,
386    rx_sender: Sender<(MessageID, semi_e5::Message)>,
387  ) {
388    for primitive_message in rx_receiver {
389      let primitive_header = primitive_message.header;
390      match Message::try_from(primitive_message) {
391        Ok(rx_message) => match rx_message.contents {
392          // RX: Data Message
393          MessageContents::DataMessage(data) => {
394            match self.selection_state.load(Relaxed) {
395              // IS: SELECTED
396              SelectionState::Selected => {
397                // RX: Primary Data Message
398                if data.function % 2 == 1 {
399                  // INBOX: New Transaction
400                  if rx_sender.send((rx_message.id, data)).is_err() {break}
401                }
402                // RX: Response Data Message
403                else {
404                  // OUTBOX: Find Transaction
405                  let mut outbox = self.outbox.lock().unwrap();
406                  let mut optional_transaction: Option<u32> = None;
407                  for (outbox_id, (message_id, _)) in outbox.deref() {
408                    if *message_id == rx_message.id {
409                      optional_transaction = Some(*outbox_id);
410                      break;
411                    }
412                  }
413                  // OUTBOX: Transaction Found
414                  if let Some(transaction) = optional_transaction {
415                    // OUTBOX: Complete Transaction
416                    let (_, sender) = outbox.deref_mut().remove(&transaction).unwrap();
417                    sender.send(Some(Message{
418                      id: rx_message.id,
419                      contents: MessageContents::DataMessage(data),
420                    })).unwrap();
421                  }
422                  // OUTBOX: Transaction Not Found
423                  else {
424                    // TX: Reject.req 
425                    if self.primitive_client.transmit(Message {
426                      id: rx_message.id,
427                      contents: MessageContents::RejectRequest(0, RejectReason::TransactionNotOpen as u8)
428                    }.into()).is_err() {break}
429                  }
430                }
431              },
432              // IS: NOT SELECTED
433              _ => {
434                // TX: Reject.req
435                if self.primitive_client.transmit(Message {
436                  id: rx_message.id,
437                  contents: MessageContents::RejectRequest(0, RejectReason::EntityNotSelected as u8)
438                }.into()).is_err() {break}
439              },
440            }
441          },
442          // RX: Select.req
443          MessageContents::SelectRequest => {
444            match self.selection_mutex.try_lock() {
445              Ok(_guard) => {
446                match self.selection_state.load(Relaxed) {
447                  // IS: NOT SELECTED
448                  SelectionState::NotSelected => {
449                    // TX: Select.rsp Success
450                    if self.primitive_client.transmit(Message {
451                      id: rx_message.id,
452                      contents: MessageContents::SelectResponse(SelectStatus::Success as u8),
453                    }.into()).is_err() {break};
454                    // TO: SELECTED
455                    self.selection_state.store(SelectionState::Selected, Relaxed);
456                  },
457                  // IS: SELECTED
458                  SelectionState::Selected => {
459                    // TX: Select.rsp Already Active
460                    if self.primitive_client.transmit(Message {
461                      id: rx_message.id,
462                      contents: MessageContents::SelectResponse(SelectStatus::AlreadyActive as u8),
463                    }.into()).is_err() {break};
464                  },
465                  // IS: SELECT INITIATED
466                  // TODO: Find way to reimplement this under the current scheme.
467                  /*SelectionState::SelectInitiated(session_id) => {
468                    // RX: Valid Simultaneous Select
469                    if rx_message.id.session == *session_id {
470                      // TX: Select.rsp Success
471                      if self.primitive_client.transmit(HsmsMessage {
472                        id: rx_message.id,
473                        contents: HsmsMessageContents::SelectResponse(SelectStatus::Success as u8),
474                      }.into()).is_err() {break};
475                    }
476                    // RX: Invalid Simultaneous Select
477                    else {
478                      // TX: Select.rsp Already Active
479                      if self.primitive_client.transmit(HsmsMessage {
480                        id: rx_message.id,
481                        contents: HsmsMessageContents::SelectResponse(SelectStatus::AlreadyActive as u8),
482                      }.into()).is_err() {break};
483                    }
484                  },*/
485                }
486              },
487              Err(_) => {
488                // Todo: probably appropriate to put something here, maybe to do with the simulatenous select procedure?
489              },
490            }
491          },
492          // RX: Select.rsp
493          MessageContents::SelectResponse(select_status) => {
494            // OUTBOX: Find Transaction
495            let mut outbox = self.outbox.lock().unwrap();
496            let mut optional_transaction: Option<u32> = None;
497            for (outbox_id, (message_id, _)) in outbox.deref() {
498              if *message_id == rx_message.id {
499                optional_transaction = Some(*outbox_id);
500                break;
501              }
502            }
503            // OUTBOX: Transaction Found
504            if let Some(transaction) = optional_transaction {
505              // OUTBOX: Complete Transaction
506              let (_, sender) = outbox.deref_mut().remove(&transaction).unwrap();
507              sender.send(Some(Message{
508                id: rx_message.id,
509                contents: MessageContents::SelectResponse(select_status),
510              })).unwrap();
511            }
512            // OUTBOX: Transaction Not Found
513            else {
514              // TX: Reject.req
515              if self.primitive_client.transmit(Message {
516                id: rx_message.id,
517                contents: MessageContents::RejectRequest(0, RejectReason::TransactionNotOpen as u8)
518              }.into()).is_err() {break}
519            }
520          },
521          // RX: Deselect.req
522          MessageContents::DeselectRequest => {
523            todo!()
524          },
525          // RX: Deselect.rsp
526          MessageContents::DeselectResponse(_deselect_status) => {
527            todo!()
528          },
529          // RX: Linktest.req
530          MessageContents::LinktestRequest => {
531            // TX: Linktest.rsp
532            if self.primitive_client.transmit(Message{
533              id: rx_message.id,
534              contents: MessageContents::LinktestResponse,
535            }.into()).is_err() {break};
536          },
537          // RX: Linktest.rsp
538          MessageContents::LinktestResponse => {
539            // OUTBOX: Find Transaction
540            let mut outbox = self.outbox.lock().unwrap();
541            let mut optional_transaction: Option<u32> = None;
542            for (outbox_id, (message_id, _)) in outbox.deref() {
543              if *message_id == rx_message.id {
544                optional_transaction = Some(*outbox_id);
545                break;
546              }
547            }
548            // OUTBOX: Transaction Found
549            if let Some(transaction) = optional_transaction {
550              // OUTBOX: Complete Transaction
551              let (_, sender) = outbox.deref_mut().remove(&transaction).unwrap();
552              sender.send(Some(rx_message)).unwrap();
553            }
554            // OUTBOX: Transaction Not Found
555            else {
556              // TX: Reject.req
557              if self.primitive_client.transmit(Message {
558                id: rx_message.id,
559                contents: MessageContents::RejectRequest(SessionType::LinktestRequest as u8, RejectReason::TransactionNotOpen as u8),
560              }.into()).is_err() {break}
561            }
562          },
563          // RX: Reject.req
564          MessageContents::RejectRequest(_message_type, _reason_code) => {
565            // OUTBOX: Find Transaction
566            let mut outbox = self.outbox.lock().unwrap();
567            let mut optional_transaction: Option<u32> = None;
568            for (outbox_id, (message_id, _)) in outbox.deref() {
569              if *message_id == rx_message.id {
570                optional_transaction = Some(*outbox_id);
571                break;
572              }
573            }
574            // OUTBOX: Transaction Found
575            if let Some(transaction) = optional_transaction {
576              // OUTBOX: Reject Transaction
577              let (_, sender) = outbox.deref_mut().remove(&transaction).unwrap();
578              sender.send(None).unwrap();
579            }
580          },
581          // RX: Separate.req
582          MessageContents::SeparateRequest => {
583            let _guard: std::sync::MutexGuard<'_, ()> = self.selection_mutex.lock().unwrap();
584            if let SelectionState::Selected = self.selection_state.load(Relaxed) {
585              self.selection_state.store(SelectionState::NotSelected, Relaxed);
586            }
587          },
588        },
589        Err(reject_reason) => {
590          // TX: Reject.req
591          if self.primitive_client.transmit(Message {
592            id: MessageID {
593              session: primitive_header.session_id,
594              system: primitive_header.system,
595            },
596            contents: MessageContents::RejectRequest(match reject_reason {
597              RejectReason::UnsupportedPresentationType => primitive_header.presentation_type,
598              _ => primitive_header.session_type,
599            }, reject_reason as u8),
600          }.into()).is_err() {break}
601        },
602      }
603    }
604    // OUTBOX: CLEAR
605    for (_, (_, sender)) in self.outbox.lock().unwrap().deref_mut().drain() {
606      let _ = sender.send(None);
607    }
608  }
609
610  /// ### TRANSMIT PROCEDURE
611  /// **Based on SEMI E37-1109§7.2**
612  /// 
613  /// Serializes a [Message] and transmits it over the TCP/IP connection.
614  /// If a reply is expected, this function will then wait up to the time
615  /// specified for the requisite response [Message] to be recieved.
616  /// 
617  /// -------------------------------------------------------------------------
618  /// 
619  /// The [Connection State] must be in the [CONNECTED] state to use this
620  /// procedure.
621  /// 
622  /// [Message]:          Message
623  /// [Connection State]: primitive::ConnectionState
624  /// [NOT CONNECTED]:    primitive::ConnectionState::NotConnected
625  /// [CONNECTED]:        primitive::ConnectionState::Connected
626  fn transmit(
627    self: &Arc<Self>,
628    message: Message,
629    reply_expected: bool,
630    delay: Duration,
631  ) -> Result<Option<Message>, Error> {
632    let (receiver, system) = {
633      // OUTBOX: LOCK
634      let outbox_lock = if reply_expected {Some(self.deref().outbox.lock().unwrap())} else {None};
635      // TX
636      let message_id = message.id;
637      match self.primitive_client.transmit(message.into()) {
638        // TX: Success
639        Ok(()) => {
640          match outbox_lock {
641            // REPLY NOT EXPECTED: Finish
642            None => return Ok(None),
643            // REPLY EXPECTED
644            Some(mut outbox) => {
645              // OUTBOX: Create Transaction
646              let (sender, receiver) = oneshot::channel::<Option<Message>>();
647              let system = {
648                let mut system_guard = self.deref().system.lock().unwrap();
649                let system_counter = system_guard.deref_mut();
650                let system = *system_counter;
651                *system_counter += 1;
652                system
653              };
654              outbox.deref_mut().insert(system, (message_id, sender));
655              (receiver, system)
656            }
657          }
658        },
659        // TX: Failure
660        Err(error) => {
661          // TO: NOT CONNECTED, NOT SELECTED
662          let _ = self.disconnect();
663          return Err(error)
664        },
665      }
666    };
667    // RX
668    let rx_result = receiver.recv_timeout(delay);
669    // OUTBOX: Remove Transaction
670    let mut outbox = self.outbox.lock().unwrap();
671    outbox.deref_mut().remove(&system);
672    match rx_result {
673      // RX: Success
674      Ok(rx_message) => return Ok(rx_message),
675      // RX: Failure
676      Err(_e) => return Ok(None),
677    }
678  }
679
680  /// ### DATA PROCEDURE
681  /// **Based on SEMI E37-1109§7.5-7.6**
682  /// 
683  /// Asks the [Client] to initiate the [Data Procedure] by transmitting a
684  /// [Data Message] and waiting for the corresponding response to be received
685  /// if it is necessary to do so.
686  /// 
687  /// -------------------------------------------------------------------------
688  /// 
689  /// The [Connection State] must be in the [CONNECTED] state and the
690  /// [Selection State] must be in the [SELECTED] state to use this procedure.
691  /// 
692  /// When a Response [Data Message] is necessary, the [Client] will wait
693  /// to receive it for the amount of time specified by [T3] before it will
694  /// consider it a communications failure and initiate the
695  /// [Disconnect Procedure].
696  /// 
697  /// -------------------------------------------------------------------------
698  /// 
699  /// Although not done within this function, a [Client] in the [CONNECTED]
700  /// state will automatically respond to having received a [Data Message]
701  /// based on its contents and the current [Selection State]:
702  /// - [NOT SELECTED] - The [Client] will respond by transmitting a
703  ///   [Reject.req] message, rejecting the [HSMS Data Procedure] and
704  ///   completing the [HSMS Reject Procedure].
705  /// - [SELECTED], Primary [Data Message] - The [Client] will send the
706  ///   [Data Message] to the hook provided by the [Connect Procedure].
707  /// - [SELECTED], Response [Data Message] - The [Client] will respond by
708  ///   correllating the message to a previously sent Primary [Data Message],
709  ///   finishing a previously initiated [Data Procedure] if successful,
710  ///   or if unsuccessful by transmitting a [Reject.req] message, rejecting
711  ///   the [Data Procedure] and completing the [Reject Procedure].
712  /// 
713  /// [Connection State]:     primitive::ConnectionState
714  /// [CONNECTED]:            primitive::ConnectionState::Connected
715  /// [Selection State]:      SelectionState
716  /// [NOT SELECTED]:         SelectionState::NotSelected
717  /// [SELECTED]:             SelectionState::Selected
718  /// [T3]:                   ParameterSettings::t3
719  /// [Client]:               Client
720  /// [Connect Procedure]:    Client::connect
721  /// [Disconnect Procedure]: Client::disconnect
722  /// [Data Procedure]:       Client::data
723  /// [Reject Procedure]:     Client::reject
724  /// [Data Message]:         MessageContents::DataMessage
725  /// [Reject.req]:           MessageContents::RejectRequest
726  pub fn data(
727    self: &Arc<Self>,
728    id: MessageID,
729    message: semi_e5::Message,
730  ) -> JoinHandle<Result<Option<semi_e5::Message>, Error>> {
731    let clone: Arc<Client> = self.clone();
732    let reply_expected: bool = message.function % 2 == 1 && message.w;
733    thread::spawn(move || {
734      match clone.selection_state.load(Relaxed) {
735        // IS: NOT SELECTED
736        SelectionState::NotSelected => return Err(Error::from(ErrorKind::AlreadyExists)),
737        // IS: SELECTED
738        SelectionState::Selected => {
739          // TX: Data Message
740          match clone.transmit(
741            Message {
742              id,
743              contents: MessageContents::DataMessage(message),
744            },
745            reply_expected,
746            clone.parameter_settings.t3,
747          )?{
748            // RX: Response
749            Some(rx_message) => {
750              match rx_message.contents {
751                // RX: Data
752                MessageContents::DataMessage(data_message) => return Ok(Some(data_message)),
753                // RX: Reject.req
754                MessageContents::RejectRequest(_type, _reason) => return Err(Error::from(ErrorKind::PermissionDenied)),
755                // RX: Unknown
756                _ => return Err(Error::from(ErrorKind::InvalidData)),
757              }
758            },
759            // RX: No Response
760            None => {
761              // REPLY EXPECTED
762              if reply_expected {
763                // TO: NOT CONNECTED
764                clone.disconnect()?;
765                Err(Error::from(ErrorKind::ConnectionAborted))
766                // TODO: HSMS-SS does NOT disconnect when the Data Procedure fails, may require this behavior to be optional.
767              }
768              // REPLY NOT EXPECTED
769              else {
770                return Ok(None);
771              }
772            },
773          }
774        },
775      }
776    })
777  }
778
779  /// ### SELECT PROCEDURE
780  /// **Based on SEMI E37-1109§7.3-7.4**
781  /// 
782  /// Asks the [Client] to initiate the [Select Procedure] by transmitting a
783  /// [Select.req] message and waiting for the corresponding [Select.rsp]
784  /// message to be received.
785  /// 
786  /// -------------------------------------------------------------------------
787  /// 
788  /// The [Connection State] must be in the [CONNECTED] state and the
789  /// [Selection State] must be in the [NOT SELECTED] state to use this
790  /// procedure.
791  /// 
792  /// The [Client] will wait to receive the [Select.rsp] for the amount
793  /// of time specified by [T6] before it will consider it a communications
794  /// failure and initiate the [Disconnect Procedure].
795  /// 
796  /// -------------------------------------------------------------------------
797  /// 
798  /// Although not done within this function, a [Client] in the [CONNECTED]
799  /// state will automatically respond to having received a [Select.req]
800  /// message based on its current [Selection State]:
801  /// - [NOT SELECTED] - The [Client] will respond with a [Select.rsp]
802  ///   accepting and completing the [Select Procedure].
803  /// - [SELECTED] - The [Client] will respond with a [Select.rsp] message
804  ///   rejecting the [Select Procedure].
805  /// 
806  /// -------------------------------------------------------------------------
807  /// 
808  /// Upon completion of the [Select Procedure], the [SELECTED] state
809  /// is entered.
810  /// 
811  /// [Connection State]:     primitive::ConnectionState
812  /// [CONNECTED]:            primitive::ConnectionState::Connected
813  /// [Selection State]:      SelectionState
814  /// [NOT SELECTED]:         SelectionState::NotSelected
815  /// [SELECTED]:             SelectionState::Selected
816  /// [T6]:                   ParameterSettings::t6
817  /// [Client]:               Client
818  /// [Disconnect Procedure]: Client::disconnect
819  /// [Select Procedure]:     Client::select
820  /// [Select.req]:           MessageContents::SelectRequest
821  /// [Select.rsp]:           MessageContents::SelectResponse
822  pub fn select(
823    self: &Arc<Self>,
824    id: MessageID,
825  ) -> JoinHandle<Result<(), Error>> {
826    let clone: Arc<Client> = self.clone();
827    thread::spawn(move || {
828      'disconnect: {
829        let _guard = clone.selection_mutex.lock();
830        match clone.selection_state.load(Relaxed) {
831          SelectionState::NotSelected => {
832            // TX: Select.req
833            match clone.transmit(
834              Message {
835                id,
836                contents: MessageContents::SelectRequest,
837              },
838              true,
839              clone.parameter_settings.t6,
840            )?{
841              // RX: Response
842              Some(rx_message) => {
843                match rx_message.contents {
844                  // RX: Select.rsp
845                  MessageContents::SelectResponse(select_status) => {
846                    // RX: Select.rsp Success
847                    if select_status == SelectStatus::Success as u8 {
848                      // TO: SELECTED
849                      clone.selection_state.store(SelectionState::Selected, Relaxed);
850                      return Ok(())
851                    }
852                    // RX: Select.rsp Failure
853                    else {
854                      return Err(Error::from(ErrorKind::PermissionDenied))
855                    }
856                  },
857                  // RX: Reject.req
858                  MessageContents::RejectRequest(_type, _reason) => return Err(Error::from(ErrorKind::PermissionDenied)),
859                  // RX: Unknown
860                  _ => return Err(Error::from(ErrorKind::InvalidData)),
861                }
862              },
863              // RX: No Response
864              None => {
865                // TO: NOT CONNECTED, NOT SELECTED
866                break 'disconnect;
867              },
868            }
869          },
870          SelectionState::Selected => {
871            return Err(Error::from(ErrorKind::AlreadyExists))
872          },
873        }
874      }
875      clone.disconnect()?;
876      Err(Error::from(ErrorKind::ConnectionAborted))
877    })
878  }
879
880  /// ### DESELECT PROCEDURE (TODO)
881  /// **Based on SEMI E37-1109§7.7**
882  /// 
883  /// Asks the [Client] to initiate the [Deselect Procedure] by transmitting a
884  /// [Deselect.req] message and waiting for the corresponding [Deselect.rsp]
885  /// message to be received.
886  /// 
887  /// -------------------------------------------------------------------------
888  /// 
889  /// The [Connection State] must be in the [CONNECTED] state and the
890  /// [Selection State] must be in the [SELECTED] state to use this procedure.
891  /// 
892  /// The [Client] will wait to receive the [Deselect.rsp] for the amount of
893  /// time specified by [T6] before it will consider it a communications
894  /// failure and initiate the [Disconnect Procedure].
895  /// 
896  /// -------------------------------------------------------------------------
897  /// 
898  /// Although not done within this function, a [Client] in the [CONNECTED]
899  /// state will automatically respond to having received a [Deselect.req]
900  /// message based on its current [Selection State]:
901  /// - [NOT SELECTED] - The [Client] will respond with a [Deselect.rsp]
902  ///   rejecting the [Deselect Procedure].
903  /// - [SELECTED] - The [Client] will respond with a [Deselect.rsp] accepting
904  ///   and completing the [Deselect Procedure].
905  /// 
906  /// -------------------------------------------------------------------------
907  /// 
908  /// Upon completion of the [Deselect Procedure], the [NOT SELECTED] state is
909  /// entered.
910  /// 
911  /// [Connection State]:     primitive::ConnectionState
912  /// [CONNECTED]:            primitive::ConnectionState::Connected
913  /// [Selection State]:      SelectionState
914  /// [NOT SELECTED]:         SelectionState::NotSelected
915  /// [SELECTED]:             SelectionState::Selected
916  /// [T6]:                   ParameterSettings::t6
917  /// [Client]:               Client
918  /// [Disconnect Procedure]: Client::disconnect
919  /// [Deselect Procedure]:   Client::deselect
920  /// [Deselect.req]:         MessageContents::DeselectRequest
921  /// [Deselect.rsp]:         MessageContents::DeselectResponse
922  pub fn deselect(
923    self: &Arc<Self>,
924  ) -> Result<(), Error> {
925    todo!()
926  }
927
928  /// ### LINKTEST PROCEDURE
929  /// **Based on SEMI E37-1109§7.8**
930  /// 
931  /// Asks the [Client] to initiate the [Linktest Procedure] by transmitting a
932  /// [Linktest.req] message and waiting for the corresponding [Linktest.rsp]
933  /// message to be received.
934  /// 
935  /// -------------------------------------------------------------------------
936  /// 
937  /// The [Connection State] must be in the [CONNECTED] state to use this
938  /// procedure.
939  /// 
940  /// The [Client] will wait to receive the [Linktest.rsp] for the amount of
941  /// time specified by [T6] before it will consider it a communications
942  /// failure and initiate the [Disconnect Procedure].
943  /// 
944  /// -------------------------------------------------------------------------
945  /// 
946  /// Although not done within this function, a [Client] in the
947  /// [CONNECTED] state will automatically respond to having received a
948  /// [Linktest.req] message:
949  /// - The [Client] will respond with a [Linktest.rsp], completing the
950  ///   [Linktest Procedure].
951  /// 
952  /// [Connection State]:     primitive::ConnectionState
953  /// [CONNECTED]:            primitive::ConnectionState::Connected
954  /// [Selection State]:      SelectionState
955  /// [NOT SELECTED]:         SelectionState::NotSelected
956  /// [SELECTED]:             SelectionState::Selected
957  /// [T6]:                   ParameterSettings::t6
958  /// [Client]:               Client
959  /// [Disconnect Procedure]: Client::disconnect
960  /// [Linktest Procedure]:   Client::linktest
961  /// [Linktest.req]:         MessageContents::LinktestRequest
962  /// [Linktest.rsp]:         MessageContents::LinktestResponse
963  pub fn linktest(
964    self: &Arc<Self>,
965    system: u32,
966  ) -> JoinHandle<Result<(), Error>> {
967    let clone: Arc<Client> = self.clone();
968    thread::spawn(move || {
969      // TX: Linktest.req
970      match clone.transmit(
971        Message {
972          id: MessageID {
973            session: 0xFFFF,
974            system,
975          },
976          contents: MessageContents::LinktestRequest,
977        },
978        true,
979        clone.parameter_settings.t6,
980      )?{
981        // RX: Response
982        Some(rx_message) => {
983          match rx_message.contents {
984            // RX: Linktest.rsp
985            MessageContents::LinktestResponse => Ok(()),
986            // RX: Reject.req
987            MessageContents::RejectRequest(_type, _reason) => Err(Error::from(ErrorKind::PermissionDenied)),
988            // RX: Unknown
989            _ => Err(Error::from(ErrorKind::InvalidData)),
990          }
991        },
992        // RX: No Response
993        None => {
994          // TO: NOT CONNECTED, NOT SELECTED
995          clone.disconnect()?;
996          Err(Error::from(ErrorKind::ConnectionAborted))
997        },
998      }
999    })
1000  }
1001
1002  /// ### SEPARATE PROCEDURE
1003  /// **Based on SEMI E37-1109§7.9**
1004  /// 
1005  /// Asks the [Client] to initiate the [Separate Procedure] by transmitting a
1006  /// [Separate.req] message.
1007  /// 
1008  /// -------------------------------------------------------------------------
1009  /// 
1010  /// The [Connection State] must be in the [CONNECTED] state and the
1011  /// [Selection State] must be in the [SELECTED] state to use this procedure.
1012  /// 
1013  /// -------------------------------------------------------------------------
1014  /// 
1015  /// Although not done within this function, a [Client] in the [CONNECTED]
1016  /// state will automatically respond to having received a [Separate.req]
1017  /// message based on its current [Selection State]:
1018  /// - [NOT SELECTED] - The [Client] will not do anything.
1019  /// - [SELECTED] - The [Client] will complete the [Separate Procedure].
1020  /// 
1021  /// -------------------------------------------------------------------------
1022  /// 
1023  /// Upon completion of the [Separate Procedure], the [NOT SELECTED] state is
1024  /// entered.
1025  /// 
1026  /// [Connection State]:   primitive::ConnectionState
1027  /// [CONNECTED]:          primitive::ConnectionState::Connected
1028  /// [Selection State]:    SelectionState
1029  /// [NOT SELECTED]:       SelectionState::NotSelected
1030  /// [SELECTED]:           SelectionState::Selected
1031  /// [Client]:             Client
1032  /// [Separate Procedure]: Client::separate
1033  /// [Separate.req]:       MessageContents::SeparateRequest
1034  pub fn separate(
1035    self: &Arc<Self>,
1036    id: MessageID,
1037  ) -> JoinHandle<Result<(), Error>> {
1038    let clone: Arc<Client> = self.clone();
1039    thread::spawn(move || {
1040      let _guard = clone.selection_mutex.lock().unwrap();
1041      match clone.selection_state.load(Relaxed) {
1042        // IS: NOT SELECTED
1043        SelectionState::NotSelected => {
1044          Err(Error::from(ErrorKind::PermissionDenied))
1045        },
1046        // IS: SELECTED
1047        SelectionState::Selected => {
1048          // TX: Separate.req
1049          clone.transmit(
1050            Message {
1051              id,
1052              contents: MessageContents::SeparateRequest,
1053            },
1054            false,
1055            clone.parameter_settings.t6,
1056          )?;
1057          // TO: NOT SELECTED
1058          clone.selection_state.store(SelectionState::NotSelected, Relaxed);
1059          Ok(())
1060        },
1061      }
1062    })
1063  }
1064
1065  /// ### REJECT PROCEDURE (TODO)
1066  /// **Based on SEMI E37-1109§7.10**
1067  /// 
1068  /// Asks the [Client] to initiate the [Reject Procedure] by transmitting a
1069  /// [Reject.req] message.
1070  /// 
1071  /// -------------------------------------------------------------------------
1072  /// 
1073  /// The [Connection State] must be in the [CONNECTED] state to use this
1074  /// procedure.
1075  /// 
1076  /// -------------------------------------------------------------------------
1077  /// 
1078  /// Although not done within this function, a [Client] in the [CONNECTED]
1079  /// state will automatically respond to having received a [Reject.req]:
1080  /// - Not yet implemented.
1081  /// 
1082  /// [Connection State]: primitive::ConnectionState
1083  /// [CONNECTED]:        primitive::ConnectionState::Connected
1084  /// [Selection State]:  SelectionState
1085  /// [NOT SELECTED]:     SelectionState::NotSelected
1086  /// [SELECTED]:         SelectionState::Selected
1087  /// [Client]:           Client
1088  /// [Reject Procedure]: Client::reject
1089  /// [Reject.req]:       MessageContents::RejectRequest
1090  pub fn reject(
1091    self: &Arc<Self>,
1092    _reason: RejectReason,
1093  ) -> Result<(), Error> {
1094    todo!()
1095  }
1096}
1097
1098/// ## SELECTION STATE
1099/// **Based on SEMI E37-1109§5.5.2**
1100/// 
1101/// The [CONNECTED] state has two substates, [NOT SELECTED] and [SELECTED].
1102/// 
1103/// The [Client] moves between them based on whether it has established
1104/// a session with another entity according to the [Select Procedure],
1105/// [Deselect Procedure], and [Separate Procedure].
1106/// 
1107/// [CONNECTED]:          primitive::ConnectionState::Connected
1108/// [NOT SELECTED]:       SelectionState::NotSelected
1109/// [SELECTED]:           SelectionState::Selected
1110/// [Client]:             Client
1111/// [Select Procedure]:   Client::select
1112/// [Deselect Procedure]: Client::deselect
1113/// [Separate Procedure]: Client::separate
1114#[derive(Clone, Copy, Debug, PartialEq, NoUninit)]
1115#[repr(u8)]
1116pub enum SelectionState {
1117  /// ### NOT SELECTED
1118  /// **Based on SEMI E37-1109§5.5.2.1**
1119  /// 
1120  /// In this state, the [Client] is ready to initiate the [Select Procedure]
1121  /// but has either not yet done so, or has terminated a previous session.
1122  /// 
1123  /// [Client]:           Client
1124  /// [Select Procedure]: Client::select
1125  NotSelected,
1126
1127  /// ### SELECTED
1128  /// **Based on SEMI E37-1109§5.5.2.2**
1129  /// 
1130  /// In this state, the [Client] has successfully initiated the
1131  /// [Select Procedure] and is able to send and receive [Data Message]s.
1132  /// 
1133  /// [Client]:           Client
1134  /// [Select Procedure]: Client::select
1135  /// [Data Message]:     MessageContents::DataMessage
1136  Selected,
1137}
1138impl Default for SelectionState {
1139  /// ### DEFAULT SELECTION STATE
1140  /// **Based on SEMI E37-1109§5.4**
1141  /// 
1142  /// Provides the [NOT SELECTED] state by default.
1143  /// 
1144  /// [NOT SELECTED]: SelectionState::NotSelected
1145  fn default() -> Self {
1146    SelectionState::NotSelected
1147  }
1148}
1149
1150/// ## PARAMETER SETTINGS
1151/// **Based on SEMI E37-1109§10.2**
1152/// 
1153/// The required set of paramters which an [HSMS] implementation must provide,
1154/// and which the [Client] will abide by.
1155/// 
1156/// [HSMS]:   crate
1157/// [Client]: Client
1158#[derive(Clone, Copy, Debug, PartialEq)]
1159pub struct ParameterSettings {
1160  /// ### CONNECT MODE
1161  /// 
1162  /// Specifies the [Connection Mode] the [Client] will provide to
1163  /// the [Primitive Client] to use when performing the [Connect Procedure]:
1164  /// [PASSIVE] to wait for an incoming connection, or [ACTIVE] to initiate
1165  /// an outgoing connection.
1166  /// 
1167  /// [Primitive Client]:  primitive::Client
1168  /// [Client]:            Client
1169  /// [Connect Procedure]: Client::connect
1170  /// [Connection Mode]:   ConnectionMode
1171  /// [PASSIVE]:           ConnectionMode::Passive
1172  /// [ACTIVE]:            ConnectionMode::Active
1173  pub connect_mode: ConnectionMode,
1174
1175  /// ### T3: REPLY TIMEOUT
1176  /// 
1177  /// The maximum amount of time that the [Client] will wait after sending
1178  /// a Primary [Data Message] to receive the appropriate Response
1179  /// [Data Message] before it must initiate the [Disconnect Procedure].
1180  /// 
1181  /// [Client]:               Client
1182  /// [Disconnect Procedure]: Client::disconnect
1183  /// [Data Message]:         MessageContents::DataMessage
1184  pub t3: Duration,
1185
1186  /// ### T5: CONNECTION SEPARATION TIMEOUT
1187  /// 
1188  /// The minimum amount of time that the [Client] must wait between successive
1189  /// attempts to initiate the [Connect Procedure] with a [Connect Mode] of
1190  /// [ACTIVE].
1191  /// 
1192  /// [Client]:            Client
1193  /// [Connect Procedure]: Client::connect
1194  /// [Connect Mode]:      ParameterSettings::connect_mode
1195  /// [ACTIVE]:            ConnectionMode::Active
1196  pub t5: Duration,
1197
1198  /// ### T6: CONTROL TRANSACTION TIMEOUT
1199  /// 
1200  /// The maximum amount of time that the [Client] will wait after sending a
1201  /// [Select Request], [Deselect Request], or [Linktest Request] to receive
1202  /// the appropriate [Select Response], [Deselect Response], or
1203  /// [Linktest Response] before it must initiate the [Disconnect Procedure].
1204  /// 
1205  /// [Client]:               Client
1206  /// [Disconnect Procedure]: Client::disconnect
1207  /// [Select Request]:       MessageContents::SelectRequest
1208  /// [Select Response]:      MessageContents::SelectResponse
1209  /// [Deselect Request]:     MessageContents::DeselectRequest
1210  /// [Deselect Response]:    MessageContents::DeselectResponse
1211  /// [Linktest Request]:     MessageContents::LinktestRequest
1212  /// [Linktest Response]:    MessageContents::LinktestResponse
1213  pub t6: Duration,
1214
1215  /// ### T7: NOT SELECTED TIMEOUT
1216  /// 
1217  /// The maximum amount of time that the [Client] will wait after being
1218  /// placed in the [NOT SELECTED] state before it must initiate the
1219  /// [Disconnect Procedure].
1220  /// 
1221  /// [Client]:               Client
1222  /// [Disconnect Procedure]: Client::disconnect
1223  /// [NOT SELECTED]:         SelectionState::NotSelected
1224  pub t7: Duration,
1225
1226  /// ### T8: NETWORK INTERCHARACTER TIMEOUT
1227  /// 
1228  /// The amount of time that the [Client] will provide to the
1229  /// [Primitive Client] to use as the maximum amount of time it may wait while
1230  /// sending or receiving data between successive characters in the same
1231  /// [Primitive Message] before it must initiate the [Disconnect Procedure].
1232  /// 
1233  /// [Primitive Client]:     primitive::Client
1234  /// [Disconnect Procedure]: primitive::Client::disconnect
1235  /// [Primitive Message]:    primitive::Message
1236  /// [Client]:               Client
1237  pub t8: Duration,
1238}
1239impl Default for ParameterSettings {
1240  /// ### DEFAULT PARAMETER SETTINGS
1241  /// **Based on SEMI E37-1109§10.2**
1242  /// 
1243  /// Provides [Parameter Settings] with these values, with timeouts as shown
1244  /// in the 'typical values' column in Table 10.
1245  /// 
1246  /// - [Connect Mode] of [PASSIVE]
1247  /// - [T3] of 45 seconds
1248  /// - [T5] of 10 seconds
1249  /// - [T6] of 5 seconds
1250  /// - [T7] of 10 seconds
1251  /// - [T8] of 5 seconds
1252  /// 
1253  /// [Parameter Settings]: ParameterSettings
1254  /// [PASSIVE]:            ConnectionMode::Passive
1255  /// [Connect Mode]:       ParameterSettings::connect_mode
1256  /// [T3]:                 ParameterSettings::t3
1257  /// [T5]:                 ParameterSettings::t5
1258  /// [T6]:                 ParameterSettings::t6
1259  /// [T7]:                 ParameterSettings::t7
1260  /// [T8]:                 ParameterSettings::t8
1261  fn default() -> Self {
1262    Self {
1263      connect_mode: ConnectionMode::default(),
1264      t3: Duration::from_secs(45),
1265      t5: Duration::from_secs(10),
1266      t6: Duration::from_secs(5),
1267      t7: Duration::from_secs(10),
1268      t8: Duration::from_secs(5),
1269    }
1270  }
1271}
1272
1273/// ## MESSAGE
1274/// **Based on SEMI E37-1109§8.2-8.3**
1275/// 
1276/// Data using the structure defined by the [Generic Services], enforcing
1277/// compliance as determined by a [Presentation Type] of 0, broken down into
1278/// its [Message ID] and [Message Contents].
1279/// 
1280/// [Generic Services]:  crate::generic
1281/// [Presentation Type]: PresentationType
1282/// [Message ID]:        MessageID
1283/// [Message Contents]:  MessageContents
1284#[derive(Clone, Debug)]
1285pub struct Message {
1286  pub id: MessageID,
1287  pub contents: MessageContents,
1288}
1289impl From<Message> for primitive::Message {
1290  /// ### PRIMITIVE MESSAGE FROM GENERIC MESSAGE
1291  /// 
1292  /// Due to the fact that valid [Generic Message]s are a subset of valid
1293  /// [Primitive Message]s, this operation is infallible.
1294  /// 
1295  /// [Generic Message]:   Message
1296  /// [Primitive Message]: primitive::Message
1297  fn from(message: Message) -> Self {
1298    match message.contents {
1299      MessageContents::DataMessage(e5_message) => {
1300        primitive::Message {
1301          header: primitive::MessageHeader {
1302            session_id        : message.id.session,
1303            byte_2            : ((e5_message.w as u8) << 7) | e5_message.stream,
1304            byte_3            : e5_message.function,
1305            presentation_type : PresentationType::SecsII as u8,
1306            session_type      : SessionType::DataMessage as u8,
1307            system            : message.id.system,
1308          },
1309          text: match e5_message.text {
1310            Some(item) => Vec::<u8>::from(item),
1311            None => vec![],
1312          },
1313        }
1314      },
1315      MessageContents::SelectRequest => {
1316        primitive::Message {
1317          header: primitive::MessageHeader {
1318            session_id        : message.id.session,
1319            byte_2            : 0,
1320            byte_3            : 0,
1321            presentation_type : PresentationType::SecsII as u8,
1322            session_type      : SessionType::SelectRequest as u8,
1323            system            : message.id.system,
1324          },
1325          text: vec![],
1326        }
1327      },
1328      MessageContents::SelectResponse(select_status) => {
1329        primitive::Message {
1330          header: primitive::MessageHeader {
1331            session_id        : message.id.session,
1332            byte_2            : 0,
1333            byte_3            : select_status,
1334            presentation_type : PresentationType::SecsII as u8,
1335            session_type      : SessionType::SelectResponse as u8,
1336            system            : message.id.system,
1337          },
1338          text: vec![],
1339        }
1340      },
1341      MessageContents::DeselectRequest => {
1342        primitive::Message {
1343          header: primitive::MessageHeader {
1344            session_id        : message.id.session,
1345            byte_2            : 0,
1346            byte_3            : 0,
1347            presentation_type : PresentationType::SecsII as u8,
1348            session_type      : SessionType::DeselectRequest as u8,
1349            system            : message.id.system,
1350          },
1351          text: vec![],
1352        }
1353      },
1354      MessageContents::DeselectResponse(deselect_status) => {
1355        primitive::Message {
1356          header: primitive::MessageHeader {
1357            session_id        : message.id.session,
1358            byte_2            : 0,
1359            byte_3            : deselect_status,
1360            presentation_type : PresentationType::SecsII as u8,
1361            session_type      : SessionType::DeselectResponse as u8,
1362            system            : message.id.system,
1363          },
1364          text: vec![],
1365        }
1366      },
1367      MessageContents::LinktestRequest => {
1368        primitive::Message {
1369          header: primitive::MessageHeader {
1370            session_id        : 0xFFFF,
1371            byte_2            : 0,
1372            byte_3            : 0,
1373            presentation_type : PresentationType::SecsII as u8,
1374            session_type      : SessionType::LinktestRequest as u8,
1375            system            : message.id.system,
1376          },
1377          text: vec![],
1378        }
1379      },
1380      MessageContents::LinktestResponse => {
1381        primitive::Message {
1382          header: primitive::MessageHeader {
1383            session_id        : 0xFFFF,
1384            byte_2            : 0,
1385            byte_3            : 0,
1386            presentation_type : PresentationType::SecsII as u8,
1387            session_type      : SessionType::LinktestResponse as u8,
1388            system            : message.id.system,
1389          },
1390          text: vec![],
1391        }
1392      },
1393      MessageContents::RejectRequest(message_type, reason_code) => {
1394        primitive::Message {
1395          header: primitive::MessageHeader {
1396            session_id        : message.id.session,
1397            byte_2            : message_type,
1398            byte_3            : reason_code,
1399            presentation_type : PresentationType::SecsII as u8,
1400            session_type      : SessionType::RejectRequest as u8,
1401            system            : message.id.system,
1402          },
1403          text: vec![],
1404        }
1405      },
1406      MessageContents::SeparateRequest => {
1407        primitive::Message {
1408          header: primitive::MessageHeader {
1409            session_id        : message.id.session,
1410            byte_2            : 0,
1411            byte_3            : 0,
1412            presentation_type : PresentationType::SecsII as u8,
1413            session_type      : SessionType::SeparateRequest as u8,
1414            system            : message.id.system,
1415          },
1416          text: vec![],
1417        }
1418      },
1419    }
1420  }
1421}
1422impl TryFrom<primitive::Message> for Message {
1423  type Error = RejectReason;
1424
1425  /// ## GENERIC MESSAGE FROM PRIMITIVE MESSAGE
1426  /// 
1427  /// Due to the fact that valid [Generic Message]s are a subset of valid
1428  /// [Primitive Message]s, this operation is fallable when the
1429  /// [Primitive Message] is not a [Generic Message].
1430  /// 
1431  /// [Generic Message]:   Message
1432  /// [Primitive Message]: primitive::Message
1433  fn try_from(message: primitive::Message) -> Result<Self, Self::Error> {
1434    if message.header.presentation_type != 0 {return Err(RejectReason::UnsupportedPresentationType)}
1435    Ok(Message {
1436      id: MessageID {
1437        session: message.header.session_id,
1438        system: message.header.system,
1439      },
1440      contents: match message.header.session_type {
1441        0 => {
1442          MessageContents::DataMessage(semi_e5::Message{
1443            stream   : message.header.byte_2 & 0b0111_1111,
1444            function : message.header.byte_3,
1445            w        : message.header.byte_2 & 0b1000_0000 > 0,
1446            text     : match semi_e5::Item::try_from(message.text) {
1447              // Valid Item
1448              Ok(text) => Some(text),
1449              // Invalid Item
1450              Err(error) => {
1451                match error {
1452                  // Empty Text: Considered Valid Here
1453                  semi_e5::Error::EmptyText => {None},
1454                  // Other Error: Malformed Data
1455                  _ => {return Err(RejectReason::MalformedData)}
1456                }
1457              },
1458            },
1459          })
1460        },
1461        1 => {
1462          if message.header.byte_2 != 0 {return Err(RejectReason::MalformedData)}
1463          if message.header.byte_3 != 0 {return Err(RejectReason::MalformedData)}
1464          if !message.text.is_empty()   {return Err(RejectReason::MalformedData)}
1465          MessageContents::SelectRequest
1466        },
1467        2 => {
1468          if message.header.byte_2 != 0 {return Err(RejectReason::MalformedData)}
1469          if !message.text.is_empty()   {return Err(RejectReason::MalformedData)}
1470          MessageContents::SelectResponse(message.header.byte_3)
1471        },
1472        3 => {
1473          if message.header.byte_2 != 0 {return Err(RejectReason::MalformedData)}
1474          if message.header.byte_3 != 0 {return Err(RejectReason::MalformedData)}
1475          if !message.text.is_empty()   {return Err(RejectReason::MalformedData)}
1476          MessageContents::DeselectRequest
1477        },
1478        4 => {
1479          if message.header.byte_2 != 0 {return Err(RejectReason::MalformedData)}
1480          if !message.text.is_empty()   {return Err(RejectReason::MalformedData)}
1481          MessageContents::DeselectResponse(message.header.byte_3)
1482        },
1483        5 => {
1484          if message.header.session_id != 0xFFFF {return Err(RejectReason::MalformedData)}
1485          if message.header.byte_2     != 0      {return Err(RejectReason::MalformedData)}
1486          if message.header.byte_3     != 0      {return Err(RejectReason::MalformedData)}
1487          if !message.text.is_empty()            {return Err(RejectReason::MalformedData)}
1488          MessageContents::LinktestRequest
1489        },
1490        6 => {
1491          if message.header.session_id != 0xFFFF {return Err(RejectReason::MalformedData)}
1492          if message.header.byte_2     != 0      {return Err(RejectReason::MalformedData)}
1493          if message.header.byte_3     != 0      {return Err(RejectReason::MalformedData)}
1494          if !message.text.is_empty()            {return Err(RejectReason::MalformedData)}
1495          MessageContents::LinktestResponse
1496        },
1497        7 => {
1498          if !message.text.is_empty() {return Err(RejectReason::MalformedData)}
1499          MessageContents::RejectRequest(message.header.byte_2, message.header.byte_3)
1500        },
1501        9 => {
1502          if message.header.byte_2 != 0 {return Err(RejectReason::MalformedData)}
1503          if message.header.byte_3 != 0 {return Err(RejectReason::MalformedData)}
1504          if !message.text.is_empty()   {return Err(RejectReason::MalformedData)}
1505          MessageContents::SeparateRequest
1506        },
1507        _ => {return Err(RejectReason::UnsupportedSessionType)}
1508      },
1509    })
1510  }
1511}
1512
1513/// ## MESSAGE ID
1514/// **Based on SEMI E37-1109§8.2**
1515/// 
1516/// The uniquely identifying components of a [Message] in forming a valid
1517/// transaction, including the [Session ID] and [System Bytes].
1518/// 
1519/// [Message]:      Message
1520/// [Session ID]:   MessageID::session
1521/// [System Bytes]: MessageID::system
1522#[derive(Clone, Copy, Debug, PartialEq)]
1523pub struct MessageID {
1524  /// ### SESSION ID
1525  /// **Based on SEMI E37-1109§8.2.6.1**
1526  /// 
1527  /// Provides an association between [Message]s across multiple
1528  /// transactions, particularly to link the [Select Procedure] and
1529  /// [Deselect Procedure] to subsequent [Data Message]s.
1530  /// 
1531  /// [Select Procedure]:   Client::select
1532  /// [Deselect Procedure]: Client::deselect
1533  /// [Message]:            Message
1534  /// [Data Message]:       MessageContents::DataMessage
1535  pub session: u16,
1536
1537  /// ### SYSTEM BYTES
1538  /// **Based on SEMI E37-1109§8.2.6.7**
1539  /// 
1540  /// Identifies a transaction uniquely among the set of open transactions.
1541  pub system: u32,
1542}
1543
1544/// ## MESSAGE CONTENTS
1545/// **Based on SEMI E37-1109§8.3.1-8.3.21**
1546/// 
1547/// The contents of a [Message], broken down by its [Session Type]:
1548/// 
1549/// - [SECS-II] formatted [Data Message]
1550/// - [Select.req]
1551/// - [Select.rsp]
1552/// - [Deselect.req]
1553/// - [Deselect.rsp]
1554/// - [Linktest.req]
1555/// - [Linktest.rsp]
1556/// - [Reject.req]
1557/// - [Separate.req]
1558/// 
1559/// [SECS-II]:      semi_e5
1560/// [Message]:      Message
1561/// [Session Type]: SessionType
1562/// [Data Message]: MessageContents::DataMessage
1563/// [Select.req]:   MessageContents::SelectRequest
1564/// [Select.rsp]:   MessageContents::SelectResponse
1565/// [Deselect.req]: MessageContents::DeselectRequest
1566/// [Deselect.rsp]: MessageContents::DeselectResponse
1567/// [Linktest.req]: MessageContents::LinktestRequest
1568/// [Linktest.rsp]: MessageContents::LinktestResponse
1569/// [Reject.req]:   MessageContents::RejectRequest
1570/// [Separate.req]: MessageContents::SeparateRequest
1571#[repr(u8)]
1572#[derive(Clone, Debug)]
1573pub enum MessageContents {
1574  /// ## DATA MESSAGE
1575  /// **Based on SEMI E37-1109§8.3.1-8.3.3**
1576  /// 
1577  /// A [Message] with a [Session Type] of 0, used by the initiator of or
1578  /// responding entity in the [Data Procedure] to send data.
1579  /// 
1580  /// Contains [SECS-II] formatted data.
1581  /// 
1582  /// [SECS-II]:        semi_e5
1583  /// [Message]:        Message
1584  /// [Session Type]:   SessionType
1585  /// [Data Procedure]: Client::data
1586  DataMessage(semi_e5::Message) = SessionType::DataMessage as u8,
1587
1588  /// ## SELECT REQUEST
1589  /// **Based on SEMI E37-1109§8.3.4**
1590  /// 
1591  /// A [Message] with a [Session Type] of 1, used by the initiator of the
1592  /// [Select Procedure] for establishing communications.
1593  /// 
1594  /// [Message]:          Message
1595  /// [Select Procedure]: Client::select
1596  /// [Session Type]:     SessionType
1597  SelectRequest = SessionType::SelectRequest as u8,
1598
1599  /// ## SELECT RESPONSE
1600  /// **Based on SEMI E37-1109§8.3.5-8.3.7**
1601  /// 
1602  /// A [Message] with a [Session Type] of 2, used by the responding
1603  /// entity in the [Select Procedure].
1604  /// 
1605  /// Contains a [Select Status], indicating the success or failure mode of
1606  /// the [Select Procedure].
1607  /// 
1608  /// [Message]:          Message
1609  /// [Select Procedure]: Client::select
1610  /// [Session Type]:     SessionType
1611  /// [Select Status]:    SelectStatus
1612  SelectResponse(u8) = SessionType::SelectResponse as u8,
1613
1614  /// ## DESELECT REQUEST
1615  /// **Based on SEMI E37-1109§8.3.8-8.3.10**
1616  /// 
1617  /// A [Message] with a [Session Type] of 3, used by the initiator of the
1618  /// [Deselect Procedure] for breaking communications.
1619  /// 
1620  /// [Message]:            Message
1621  /// [Deselect Procedure]: Client::deselect
1622  /// [Session Type]:       SessionType
1623  DeselectRequest = SessionType::DeselectRequest as u8,
1624
1625  /// ## DESELECT RESPONSE
1626  /// **Based on SEMI E37-1109§8.3.11-8.3.13**
1627  /// 
1628  /// An [Message] with a [Session Type] of 4, used by the responding entity
1629  /// in the [Deselect Procedure].
1630  /// 
1631  /// Contains a [Deselect Status], indicating the success or failure mode of
1632  /// the [Deselect Procedure].
1633  /// 
1634  /// [Message]:            Message
1635  /// [Deselect Procedure]: Client::deselect
1636  /// [Session Type]:       SessionType
1637  /// [Deselect Status]:    DeselectStatus
1638  DeselectResponse(u8) = SessionType::DeselectResponse as u8,
1639
1640  /// ## LINKTEST REQUEST
1641  /// **Based on SEMI E37-1109§8.3.14-8.3.16**
1642  /// 
1643  /// A [Message] with a [Session Type] of 5, used by the initiator of the
1644  /// [Linktest Procedure] for checking communications stability.
1645  /// 
1646  /// [Message]:            Message
1647  /// [Session Type]:       SessionType
1648  /// [Linktest Procedure]: Client::linktest
1649  LinktestRequest = SessionType::LinktestRequest as u8,
1650
1651  /// ## LINKTEST RESPONSE
1652  /// **Based on SEMI E37-1109§8.3.17-8.3.19**
1653  /// 
1654  /// A [Message] with a [Session Type] of 6, used by the responding entity
1655  /// in the [Linktest Procedure].
1656  /// 
1657  /// [Message]:            Message
1658  /// [Session Type]:       SessionType
1659  /// [Linktest Procedure]: Client::linktest
1660  LinktestResponse = SessionType::LinktestResponse as u8,
1661
1662  /// ## REJECT REQUEST
1663  /// **Based on SEMI E37-1109§8.3.20-8.3.21**
1664  /// 
1665  /// A [Message] with a [Session Type] of 7, used by the responding entity
1666  /// in the [Reject Procedure].
1667  /// 
1668  /// Contains the [Presentation Type] or [Session Type] of the [Message] being
1669  /// rejected, and the [Reason Code] indicating why the message was rejected.
1670  /// 
1671  /// [Message]:           Message
1672  /// [Reject Procedure]:  Client::reject
1673  /// [Presentation Type]: PresentationType
1674  /// [Session Type]:      SessionType
1675  /// [Reason Code]:       RejectReason
1676  RejectRequest(u8, u8) = SessionType::RejectRequest as u8,
1677
1678  /// ## SEPARATE REQUEST
1679  /// **Based on SEMI E37-1109§8.3.22**
1680  /// 
1681  /// A [Message] with a [Session Type] of 9, used by the initiator of the
1682  /// [Separate Procedure] for breaking communications.
1683  /// 
1684  /// [Message]:            Message
1685  /// [Separate Procedure]: Client::separate
1686  /// [Session Type]:       SessionType
1687  SeparateRequest = SessionType::SeparateRequest as u8,
1688}
1689
1690/// ## SESSION TYPE
1691/// **Based on SEMI E37-1109§8.2.6.5-8.2.6.6**
1692/// 
1693/// Defines the type of [Message] being sent.
1694/// 
1695/// Values 11-127 are reserved for Subsidiary Standards.
1696/// 
1697/// Values 8, 10, and 128-255 are reserved and may not be used.
1698/// 
1699/// [Message]: Message
1700#[repr(u8)]
1701#[derive(Clone, Copy, Debug, PartialEq)]
1702pub enum SessionType {
1703  /// ### DATA MESSAGE
1704  /// 
1705  /// Denotes a [SECS-II] formatted [Data Message].
1706  /// 
1707  /// [SECS-II]:      semi_e5
1708  /// [Data Message]: MessageContents::DataMessage 
1709  DataMessage = 0,
1710
1711  /// ### SELECT REQUEST
1712  /// 
1713  /// Denotes a [Select.req] message.
1714  /// 
1715  /// [Select.req]: MessageContents::SelectRequest
1716  SelectRequest = 1,
1717
1718  /// ### SELECT RESPONSE
1719  /// 
1720  /// Denotes a [Select.rsp] message.
1721  /// 
1722  /// [Select.rsp]: MessageContents::SelectResponse
1723  SelectResponse = 2,
1724
1725  /// ### DESELECT REQUEST
1726  /// 
1727  /// Denotes a [Deselect.req] message.
1728  /// 
1729  /// [Deselect.req]: MessageContents::DeselectRequest
1730  DeselectRequest = 3,
1731
1732  /// ### DESELECT RESPONSE
1733  /// 
1734  /// Denotes a [Deselect.rsp] message.
1735  /// 
1736  /// [Deselect.rsp]: MessageContents::DeselectResponse
1737  DeselectResponse = 4,
1738
1739  /// ### LINKTEST REQUEST
1740  /// 
1741  /// Denotes a [Linktest.req] message.
1742  /// 
1743  /// [Linktest.req]: MessageContents::LinktestRequest
1744  LinktestRequest = 5,
1745
1746  /// ### LINKTEST RESPONSE
1747  /// 
1748  /// Denotes a [Linktest.rsp] message.
1749  /// 
1750  /// [Linktest.rsp]: MessageContents::LinktestResponse
1751  LinktestResponse = 6,
1752
1753  /// ### REJECT REQUEST
1754  /// 
1755  /// Denotes a [Reject.req] message.
1756  /// 
1757  /// [Reject.req]: MessageContents::RejectRequest
1758  RejectRequest = 7,
1759
1760  /// ### SEPARATE REQUEST
1761  /// 
1762  /// Denotes a [Separate.req] message.
1763  /// 
1764  /// [Separate.req]: MessageContents::SeparateRequest
1765  SeparateRequest = 9,
1766}
1767
1768/// ## SELECT STATUS
1769/// **Based on SEMI E37-1109§8.3.7.2**
1770/// 
1771/// [Byte 3] of a [Deselect.rsp] message, used as the indication of success or
1772/// reason for failure of the [Select Procedure].
1773/// 
1774/// Values 4-127 are reserved for Subsidiary Standards.
1775/// 
1776/// Values 128-255 are reserved for the Local Entity.
1777/// 
1778/// [Byte 3]:           primitive::MessageHeader::byte_3
1779/// [Deselect.rsp]:     MessageContents::DeselectResponse
1780/// [Select Procedure]: Client::select
1781#[repr(u8)]
1782#[derive(Clone, Copy, Debug, PartialEq)]
1783pub enum SelectStatus {
1784  Success       = 0,
1785  AlreadyActive = 1,
1786  NotReady      = 2,
1787  Exhausted     = 3,
1788}
1789
1790/// ## DESELECT STATUS
1791/// **Based on SEMI E37-1109§8.3.13.2**
1792/// 
1793/// [Byte 3] of a [Deselect.rsp] message, used as the indication of success or
1794/// reason for failure of the [Deselect Procedure].
1795/// 
1796/// Values 3-127 are reserved for Subsidiary Standards.
1797/// 
1798/// Values 128-255 are reserved for the Local Entity.
1799/// 
1800/// [Byte 3]:             primitive::MessageHeader::byte_3
1801/// [Deselect.rsp]:       MessageContents::DeselectResponse
1802/// [Deselect Procedure]: Client::deselect
1803#[repr(u8)]
1804#[derive(Clone, Copy, Debug, PartialEq)]
1805pub enum DeselectStatus {
1806  Success        = 0,
1807  NotEstablished = 1,
1808  Busy           = 2,
1809}
1810
1811/// ## REJECT REASON
1812/// **Based on SEMI E37-1109§8.3.21.3**
1813/// 
1814/// [Byte 3] of a [Reject.req] message, specifying the reason a message has
1815/// been rejected in the [Reject Procedure].
1816/// 
1817/// Values 4-127 are reserved for Subsidiary Standards.
1818/// 
1819/// Values 0, and 128-255 are reserved for the Local Entity.
1820/// 
1821/// [Byte 3]:           primitive::MessageHeader::byte_3
1822/// [Reject.req]:       MessageContents::RejectRequest
1823/// [Reject Procedure]: Client::reject
1824#[repr(u8)]
1825#[derive(Clone, Copy, Debug, PartialEq)]
1826pub enum RejectReason {
1827  /// ### MALFORMED DATA
1828  /// **Local Entity Specific Reason**
1829  /// 
1830  /// A [Message] was recieved which was valid according to the
1831  /// [Primitive Services] but invalid according to the [Generic Services].
1832  /// 
1833  /// [Message]:            primitive::Message
1834  /// [Primitive Services]: primitive
1835  /// [Generic Services]:   crate::generic
1836  MalformedData = 0,
1837
1838  /// ### SESSION TYPE NOT SUPPORTED
1839  /// 
1840  /// A [Message] was received whose [Session Type] value is not allowed.
1841  /// 
1842  /// [Message]:      primitive::Message
1843  /// [Session Type]: SessionType
1844  UnsupportedSessionType = 1,
1845
1846  /// ### PRESENTATION TYPE NOT SUPPORTED
1847  /// 
1848  /// A [Message] was received whose [Presentation Type] value is not allowed.
1849  /// 
1850  /// [Message]:           primitive::Message
1851  /// [Presentation Type]: crate::PresentationType
1852  UnsupportedPresentationType = 2,
1853
1854  /// ### TRANSACTION NOT OPEN
1855  /// 
1856  /// A [Select.rsp], [Deselect.rsp], or [Linktest.rsp] was recieved when there
1857  /// was no outstanding [Select.req], [Deselect.req], or [Linktest.req] which
1858  /// corresponded to it.
1859  /// 
1860  /// [Select.req]:   MessageContents::SelectRequest
1861  /// [Select.rsp]:   MessageContents::SelectResponse
1862  /// [Deselect.req]: MessageContents::DeselectRequest
1863  /// [Deselect.rsp]: MessageContents::DeselectResponse
1864  /// [Linktest.req]: MessageContents::LinktestRequest
1865  /// [Linktest.rsp]: MessageContents::LinktestResponse
1866  TransactionNotOpen = 3,
1867
1868  /// ### ENTITY NOT SELECTED
1869  /// 
1870  /// A [Data Message] was recieved when not in the [SELECTED] state.
1871  /// 
1872  /// [Data Message]: MessageContents::DataMessage
1873  /// [SELECTED]:     SelectionState::Selected
1874  EntityNotSelected = 4,
1875}