coded_chars/
device.rs

1//! Control sequences that are devices-related.
2
3use std::fmt::{Display, Formatter};
4use crate::control::ControlSequence;
5use crate::escape::{escape, EscapeSequence};
6
7/// # Device control 1
8///
9/// DC1 is primarily intended for turning on or starting an ancillary device. If it is not required for this
10/// purpose, it may be used to restore a device to the basic mode of operation (see also DC2 and DC3), or
11/// any other device control function not provided by other DCs.
12///
13/// ### Note
14/// When used for data flow control, DC1 is sometimes called **X-ON**.
15pub const DC1: char = '\x11';
16
17/// # Device control 2
18///
19/// DC2 is primarily intended for turning on or starting an ancillary device. If it is not required for this
20/// purpose, it may be used to set a device to a special mode of operation (in which case DC1 is used to
21/// restore the device to the basic mode), or for any other device control function not provided by other DCs.
22pub const DC2: char = '\x12';
23
24/// # Device control 3
25///
26/// DC3 is primarily intended for turning off or stopping an ancillary device. This function may be a
27/// secondary level stop, for example wait, pause, stand-by or halt (in which case DC1 is used to restore
28/// normal operation). If it is not required for this purpose, it may be used for any other device control
29/// function not provided by other DCs.
30///
31/// ### Note
32///
33/// When used for data flow control, DC3 is sometimes called "X-OFF".
34pub const DC3: char = '\x13';
35
36/// # Device control 4
37///
38/// DC4 is primarily intended for turning off, stopping or interrupting an ancillary device. If it is not
39/// required for this purpose, it may be used for any other device control function not provided by other DCs.
40pub const DC4: char = '\x14';
41
42/// Disable manual input
43pub const DMI: EscapeSequence = escape('`');
44
45/// Enable manual input
46pub const EMI: EscapeSequence = escape('b');
47
48/// Interrupt
49pub const INT: EscapeSequence = escape('a');
50
51/// Reset to initial state
52pub const RIS: EscapeSequence = escape('c');
53
54/// # DA - Device attributes
55///
56/// With a parameter value not equal to 0, DA is used to identify the device which sends the DA. The
57/// parameter value is a device type identification code according to a register which is to be established. If
58/// the parameter value is 0, DA is used to request an identifying DA from a device.
59pub fn attributes(n: usize) -> ControlSequence {
60    ControlSequence::new(&[&n.to_string()], "c")
61}
62
63#[derive(Copy, Clone, Debug)]
64pub enum StatusReport {
65    /// Ready, no malfunction detected.
66    Ready,
67    /// Busy, another DSR must be requested later.
68    BusyRetry,
69    /// Busy, another DSR will be sent later.
70    BusyWaiting,
71    /// Some malfunction detected, another DSR must be requested later.
72    ErrorRetry,
73    /// Some malfunction detected, another DSR will be sent later.
74    ErrorWaiting,
75    /// A DSR is requested.
76    MessageWaiting,
77    /// A report of the active presentation position or of the active data position in the form of ACTIVE
78    /// POSITION REPORT (CPR) is requested.
79    PositionWaiting,
80}
81
82impl Display for StatusReport {
83    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
84        write!(f, "{}", match self {
85            StatusReport::Ready => "0",
86            StatusReport::BusyRetry => "1",
87            StatusReport::BusyWaiting => "2",
88            StatusReport::ErrorRetry => "3",
89            StatusReport::ErrorWaiting => "4",
90            StatusReport::MessageWaiting => "5",
91            StatusReport::PositionWaiting => "6",
92        })
93    }
94}
95
96/// # DSR - Device status report
97///
98/// DSR is used either to report the status of the sending device or to request a status report from the
99/// receiving device.
100///
101/// DSR with parameter value 0 [StatusReport::Ready], 1 [StatusReport::BusyRetry], 2 [StatusReport::BusyWaiting], 3 [StatusReport::ErrorRetry]
102/// or 4 [StatusReport::ErrorWaiting] may be sent either unsolicited or as a response to a request such as a DSR with
103/// a parameter value 5 [StatusReport::MessageWaiting] or MESSAGE WAITING (MW).
104pub fn report_status(status_report: StatusReport) -> ControlSequence {
105    ControlSequence::new(&[&status_report.to_string()], "c")
106}
107
108/// # FNK - Function key
109///
110/// FNK is a control function in which the parameter value identifies the function key which has been
111/// operated.
112pub fn function_key(n: usize) -> ControlSequence {
113    ControlSequence::new(&[&n.to_string()], " W")
114}
115/// # IDCS - Identify device control string
116///
117/// IDCS is used to specify the purpose and format of the command string of subsequent DEVICE
118/// CONTROL STRINGs (DCS). The specified purpose and format remain in effect until the next
119/// occurrence of IDCS in the data stream.
120///
121/// The format and interpretation of the command string corresponding to these parameter values are to be
122/// defined in appropriate standards. If this control function is used to identify a private command string, a
123/// private parameter value shall be used.
124pub fn identify_control_string(control_string: ControlString) -> ControlSequence {
125    ControlSequence::new(&[&control_string.to_string()], " O")
126}
127
128#[derive(Copy, Clone, Debug)]
129pub enum ControlString {
130    SRTMDiagnose,
131    Ecma35DCRS,
132}
133
134impl Display for ControlString {
135    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
136        write!(f, "{}", match self {
137            ControlString::SRTMDiagnose => "1",
138            ControlString::Ecma35DCRS => "2"
139        })
140    }
141}
142
143/// # IGS - Identify graphic sub-repertoire
144///
145/// IGS is used to indicate that a repertoire of the graphic characters of ISO/IEC 10367 is used in the
146/// subsequent text.
147/// The parameter value of IGS identifies a graphic character repertoire registered in accordance with
148/// ISO/IEC 7350.
149pub fn identify_graphic_sub(n: usize) -> ControlSequence {
150    ControlSequence::new(&[&n.to_string()], " W")
151}
152
153#[derive(Copy, Clone, Debug)]
154pub enum CopyStatus {
155    /// Initiate transfer to a primary auxiliary device.
156    InitTo1,
157    /// Initiate transfer from a primary auxiliary device.
158    InitFrom1,
159    /// Initiate transfer to a secondary auxiliary device.
160    InitTo2,
161    /// Initiate transfer from a secondary auxiliary device.
162    InitFrom2,
163    /// Stop relay to a primary auxiliary device.
164    Stop1,
165    /// Start relay to a primary auxiliary device.
166    Start1,
167    /// Stop relay to a secondary auxiliary device.
168    Stop2,
169    /// Start relay to a secondary auxiliary device.
170    Start2,
171}
172
173impl Display for CopyStatus {
174    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
175        write!(f, "{}", match self {
176            CopyStatus::InitTo1 => "0",
177            CopyStatus::InitFrom1 => "1",
178            CopyStatus::InitTo2 => "2",
179            CopyStatus::InitFrom2 => "3",
180            CopyStatus::Stop1 => "4",
181            CopyStatus::Start1 => "5",
182            CopyStatus::Stop2 => "6",
183            CopyStatus::Start2 => "7",
184        })
185    }
186}
187
188/// # MC - Media copy
189///
190/// MC is used either to initiate a transfer of data from or to an auxiliary input/output device or to enable or
191/// disable the relay of the received data stream to an auxiliary input/output device.
192///
193/// This control function may not be used to switch on or off an auxiliary device.
194pub fn media_copy(copy_status: CopyStatus) -> ControlSequence {
195    ControlSequence::new(&[&copy_status.to_string()], "i")
196}
197
198/// # SEF - Sheet eject and feed
199///
200/// SEF causes a sheet of paper to be ejected from a printing device into a specified output stacker and
201/// another sheet to be loaded into the printing device from a specified paper bin.
202pub fn eject_and_feed(bin: usize, stacker: usize) -> ControlSequence {
203    ControlSequence::new(&[&bin.to_string(), &stacker.to_string()], " Y")
204}
205
206
207#[cfg(test)]
208mod tests {
209    use super::*; // Import everything from the current module
210    use crate::introducers::CSI;
211
212    #[test]
213    fn test_attributes() {
214        let sequence = attributes(42);
215        assert_eq!(sequence.to_string(), format!("{}42c", CSI));
216    }
217
218    #[test]
219    fn test_report_status() {
220        let sequence = report_status(StatusReport::Ready);
221        assert_eq!(sequence.to_string(), format!("{}0c", CSI));
222
223        let sequence = report_status(StatusReport::ErrorRetry);
224        assert_eq!(sequence.to_string(), format!("{}3c", CSI));
225
226        let sequence = report_status(StatusReport::MessageWaiting);
227        assert_eq!(sequence.to_string(), format!("{}5c", CSI));
228    }
229
230    #[test]
231    fn test_function_key() {
232        let sequence = function_key(7);
233        assert_eq!(sequence.to_string(), format!("{}7 W", CSI));
234    }
235
236    #[test]
237    fn test_identify_control_string() {
238        let sequence = identify_control_string(ControlString::SRTMDiagnose);
239        assert_eq!(sequence.to_string(), format!("{}1 O", CSI));
240
241        let sequence = identify_control_string(ControlString::Ecma35DCRS);
242        assert_eq!(sequence.to_string(), format!("{}2 O", CSI));
243    }
244
245    #[test]
246    fn test_identify_graphic_sub() {
247        let sequence = identify_graphic_sub(4);
248        assert_eq!(sequence.to_string(), format!("{}4 W", CSI));
249    }
250
251    #[test]
252    fn test_media_copy() {
253        let sequence = media_copy(CopyStatus::InitTo1);
254        assert_eq!(sequence.to_string(), format!("{}0i", CSI));
255
256        let sequence = media_copy(CopyStatus::Start2);
257        assert_eq!(sequence.to_string(), format!("{}7i", CSI));
258    }
259
260    #[test]
261    fn test_eject_and_feed() {
262        let sequence = eject_and_feed(2, 3);
263        assert_eq!(sequence.to_string(), format!("{}2;3 Y", CSI));
264    }
265
266    #[test]
267    fn test_status_report_display() {
268        assert_eq!(StatusReport::Ready.to_string(), "0");
269        assert_eq!(StatusReport::BusyRetry.to_string(), "1");
270        assert_eq!(StatusReport::ErrorRetry.to_string(), "3");
271    }
272
273    #[test]
274    fn test_control_string_display() {
275        assert_eq!(ControlString::SRTMDiagnose.to_string(), "1");
276        assert_eq!(ControlString::Ecma35DCRS.to_string(), "2");
277    }
278
279    #[test]
280    fn test_copy_status_display() {
281        assert_eq!(CopyStatus::InitTo1.to_string(), "0");
282        assert_eq!(CopyStatus::Start2.to_string(), "7");
283    }
284}