1
//! Fields found in command and status words
2

            
3
use crate::Word;
4

            
5
/// Represents a field inside of a 16-bit word
6
///
7
/// Given a mask and offset, the Field struct can get
8
/// or set between 1 and 8 bits in a u16 word.
9
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
10
pub struct Field {
11
    /// The mask used to isolate the value
12
    mask: u16,
13

            
14
    /// The offset used to shift the value to a single byte
15
    offset: u32,
16
}
17

            
18
impl Field {
19
    /// Create a new field
20
42
    pub const fn new() -> Self {
21
42
        Self { mask: 0, offset: 0 }
22
42
    }
23

            
24
    /// Constructor method to add a mask to the field
25
40
    pub const fn with_mask(mut self, mask: u16) -> Self {
26
40
        self.mask = mask;
27
40
        self
28
40
    }
29

            
30
    /// Constructor method to calculate an offset
31
38
    pub const fn with_offset(mut self) -> Self {
32
38
        self.offset = self.mask.trailing_zeros();
33
38
        self
34
38
    }
35

            
36
    /// Create a new field from a mask
37
30
    pub const fn from(mask: u16) -> Self {
38
30
        Self::new().with_mask(mask).with_offset()
39
30
    }
40

            
41
    /// Read the value of the field from a data word
42
200
    pub fn get<T: Word, F: From<u16>>(&self, word: &T) -> F {
43
200
        let value = word.as_value() & self.mask;
44
200
        F::from(value >> self.offset)
45
200
    }
46

            
47
    /// Write the value of the field to a data word
48
98
    pub fn set<T: Word>(&self, word: &mut T, value: u8) {
49
98
        let value = (value as u16) << self.offset;
50
98
        let data = word.as_value() & !self.mask;
51
98
        word.set_value(data | (value & self.mask));
52
98
    }
53
}
54

            
55
/// Mask for parsing the terminal address of a command word.
56
pub(crate) const COMMAND_ADDRESS: u16 = 0b1111100000000000;
57

            
58
/// Field definition for the terminal address of a command word.
59
pub(crate) const COMMAND_ADDRESS_FIELD: Field = Field::from(COMMAND_ADDRESS);
60

            
61
/// Mask for parsing the transmit/receive flag of a command word.
62
pub(crate) const COMMAND_TRANSMIT_RECEIVE: u16 = 0b0000010000000000;
63

            
64
/// Field definition for the transmit/receive flag of a command word.
65
pub(crate) const COMMAND_TRANSMIT_RECEIVE_FIELD: Field = Field::from(COMMAND_TRANSMIT_RECEIVE);
66

            
67
/// Mask for parsing the terminal subaddress of a command word.
68
pub(crate) const COMMAND_SUBADDRESS: u16 = 0b0000001111100000;
69

            
70
/// Field definition for the terminal subaddress of a command word.
71
pub(crate) const COMMAND_SUBADDRESS_FIELD: Field = Field::from(COMMAND_SUBADDRESS);
72

            
73
/// Mask for parsing the mode code of a command word.
74
pub(crate) const COMMAND_MODE_CODE: u16 = 0b0000000000011111;
75

            
76
/// Field definition for the mode code of a command word.
77
pub(crate) const COMMAND_MODE_CODE_FIELD: Field = Field::from(COMMAND_MODE_CODE);
78

            
79
/// Mask for parsing the word count of a command word.
80
pub(crate) const COMMAND_WORD_COUNT: u16 = 0b0000000000011111;
81

            
82
/// Field definition for the word count of a command word.
83
pub(crate) const COMMAND_WORD_COUNT_FIELD: Field = Field::from(COMMAND_WORD_COUNT);
84

            
85
/// Mask for parsing the terminal address of a status word.
86
pub(crate) const STATUS_ADDRESS: u16 = 0b1111100000000000;
87

            
88
/// Field definition for the terminal address of a status word.
89
pub(crate) const STATUS_ADDRESS_FIELD: Field = Field::from(STATUS_ADDRESS);
90

            
91
/// Mask for parsing the error flag of a status word.
92
pub(crate) const STATUS_MESSAGE_ERROR: u16 = 0b0000010000000000;
93

            
94
/// Field definition for the error flag of a status word.
95
pub(crate) const STATUS_MESSAGE_ERROR_FIELD: Field = Field::from(STATUS_MESSAGE_ERROR);
96

            
97
/// Mask for parsing the instrumentation flag of a status word.
98
pub(crate) const STATUS_INSTRUMENTATION: u16 = 0b0000001000000000;
99

            
100
/// Field definition for the instrumentation flag of a status word.
101
pub(crate) const STATUS_INSTRUMENTATION_FIELD: Field = Field::from(STATUS_INSTRUMENTATION);
102

            
103
/// Mask for parsing the service request flag of a status word.
104
pub(crate) const STATUS_SERVICE_REQUEST: u16 = 0b0000000100000000;
105

            
106
/// Field definition for the service request flag of a status word.
107
pub(crate) const STATUS_SERVICE_REQUEST_FIELD: Field = Field::from(STATUS_SERVICE_REQUEST);
108

            
109
/// Mask for parsing the reserved bits of a status word.
110
pub(crate) const STATUS_RESERVED: u16 = 0b0000000011100000;
111

            
112
/// Field definition for the reserved bits of a status word.
113
pub(crate) const STATUS_RESERVED_FIELD: Field = Field::from(STATUS_RESERVED);
114

            
115
/// Mask for parsing the broadcast received flag of a status word.
116
pub(crate) const STATUS_BROADCAST_RECEIVED: u16 = 0b0000000000010000;
117

            
118
/// Field definition for the broadcast received flag of a status word.
119
pub(crate) const STATUS_BROADCAST_RECEIVED_FIELD: Field = Field::from(STATUS_BROADCAST_RECEIVED);
120

            
121
/// Mask for parsing the busy flag of the status word.
122
pub(crate) const STATUS_TERMINAL_BUSY: u16 = 0b0000000000001000;
123

            
124
/// Field definition for the busy flag of the status word.
125
pub(crate) const STATUS_TERMINAL_BUSY_FIELD: Field = Field::from(STATUS_TERMINAL_BUSY);
126

            
127
/// Mask for parsing the subsystem flag of the status word.
128
pub(crate) const STATUS_SUBSYSTEM_ERROR: u16 = 0b0000000000000100;
129

            
130
/// Field definition for the subsystem flag of the status word.
131
pub(crate) const STATUS_SUBSYSTEM_ERROR_FIELD: Field = Field::from(STATUS_SUBSYSTEM_ERROR);
132

            
133
/// Mask for parsing the bus control accept flag of the status word.
134
pub(crate) const STATUS_DYNAMIC_BUS_ACCEPTANCE: u16 = 0b0000000000000010;
135

            
136
/// Field definition for the bus control accept flag of the status word.
137
pub(crate) const STATUS_DYNAMIC_BUS_ACCEPTANCE_FIELD: Field =
138
    Field::from(STATUS_DYNAMIC_BUS_ACCEPTANCE);
139

            
140
/// Mask for parsing the terminal flag of the status word.
141
pub(crate) const STATUS_TERMINAL_ERROR: u16 = 0b0000000000000001;
142

            
143
/// Field definition for the terminal flag of the status word.
144
pub(crate) const STATUS_TERMINAL_ERROR_FIELD: Field = Field::from(STATUS_TERMINAL_ERROR);
145

            
146
#[cfg(test)]
147
mod tests {
148
    use super::*;
149
    use crate::DataWord;
150

            
151
    #[test]
152
2
    fn test_field_clone() {
153
2
        let field1 = Field::from(0b1010101010101010);
154
2
        let field2 = field1.clone();
155
2
        assert_eq!(field1, field2);
156
2
    }
157

            
158
    #[test]
159
2
    fn test_field_new() {
160
2
        let field = Field::new();
161
2
        assert_eq!(field.mask, 0);
162
2
        assert_eq!(field.offset, 0);
163
2
    }
164

            
165
    #[test]
166
2
    fn test_field_with_mask() {
167
2
        let field = Field::new().with_mask(0b1010101010101010);
168
2
        assert_eq!(field.mask, 0b1010101010101010);
169
2
        assert_eq!(field.offset, 0);
170
2
    }
171

            
172
    #[test]
173
2
    fn test_field_with_offset_0() {
174
2
        let field = Field::new().with_mask(0b1010101010101010).with_offset();
175
2
        assert_eq!(field.offset, 1);
176
2
    }
177

            
178
    #[test]
179
2
    fn test_field_with_offset_1() {
180
2
        let field = Field::new().with_mask(0b1010101010101000).with_offset();
181
2
        assert_eq!(field.offset, 3);
182
2
    }
183

            
184
    #[test]
185
2
    fn test_field_with_offset_2() {
186
2
        let field = Field::new().with_mask(0b1010101010100000).with_offset();
187
2
        assert_eq!(field.offset, 5);
188
2
    }
189

            
190
    #[test]
191
2
    fn test_field_with_offset_3() {
192
2
        let field = Field::new().with_mask(0b1010101010000000).with_offset();
193
2
        assert_eq!(field.offset, 7);
194
2
    }
195

            
196
    #[test]
197
2
    fn test_field_from_u16_0() {
198
2
        let input = 0b1010101010101010;
199
2
        let expected = 1;
200
2
        let field = Field::from(input);
201
2
        assert_eq!(field.mask, input);
202
2
        assert_eq!(field.offset, expected);
203
2
    }
204

            
205
    #[test]
206
2
    fn test_field_from_u16_1() {
207
2
        let input = 0b1010101010101000;
208
2
        let expected = 3;
209
2
        let field = Field::from(input);
210
2
        assert_eq!(field.mask, input);
211
2
        assert_eq!(field.offset, expected);
212
2
    }
213

            
214
    #[test]
215
2
    fn test_field_from_u16_2() {
216
2
        let input = 0b1010101010100000;
217
2
        let expected = 5;
218
2
        let field = Field::from(input);
219
2
        assert_eq!(field.mask, input);
220
2
        assert_eq!(field.offset, expected);
221
2
    }
222

            
223
    #[test]
224
2
    fn test_field_from_u16_3() {
225
2
        let input = 0b1010101010000000;
226
2
        let expected = 7;
227
2
        let field = Field::from(input);
228
2
        assert_eq!(field.mask, input);
229
2
        assert_eq!(field.offset, expected);
230
2
    }
231

            
232
    #[test]
233
2
    fn test_field_get_0() {
234
2
        let mask = 0b1110000000000000;
235
2
        let input = 0b1010000000000000;
236
2
        let expected = 0b101;
237
2
        let field = Field::from(mask);
238
2
        let word = DataWord::from(input);
239
2
        let value: u16 = field.get(&word);
240
2
        assert_eq!(value, expected);
241
2
    }
242

            
243
    #[test]
244
2
    fn test_field_get_1() {
245
2
        let mask = 0b0011110000000000;
246
2
        let input = 0b0010110000000000;
247
2
        let expected = 0b1011;
248
2
        let field = Field::from(mask);
249
2
        let word = DataWord::from(input);
250
2
        let value: u16 = field.get(&word);
251
2
        assert_eq!(value, expected);
252
2
    }
253

            
254
    #[test]
255
2
    fn test_field_get_2() {
256
2
        let mask = 0b0000011111000000;
257
2
        let input = 0b0000010101000000;
258
2
        let expected = 0b10101;
259
2
        let field = Field::from(mask);
260
2
        let word = DataWord::from(input);
261
2
        let value: u16 = field.get(&word);
262
2
        assert_eq!(value, expected);
263
2
    }
264

            
265
    #[test]
266
2
    fn test_field_get_3() {
267
2
        let mask = 0b0000000001111110;
268
2
        let input = 0b0000000001011010;
269
2
        let expected = 0b101101;
270
2
        let field = Field::from(mask);
271
2
        let word = DataWord::from(input);
272
2
        let value: u16 = field.get(&word);
273
2
        assert_eq!(value, expected);
274
2
    }
275

            
276
    #[test]
277
2
    fn test_field_get_4() {
278
2
        let mask = 0b0000000000000011;
279
2
        let input = 0b0000000000000011;
280
2
        let expected = 0b0000011;
281
2
        let field = Field::from(mask);
282
2
        let word = DataWord::from(input);
283
2
        let value: u16 = field.get(&word);
284
2
        assert_eq!(value, expected);
285
2
    }
286

            
287
    #[test]
288
2
    fn test_field_set_0() {
289
2
        let mask = 0b1110000000000000;
290
2
        let input = 0b101;
291
2
        let expected = 0b1010000000000000;
292
2
        let field = Field::from(mask);
293
2
        let mut word = DataWord::from(0);
294
2

            
295
2
        field.set(&mut word, input);
296
2
        assert_eq!(word.as_value(), expected);
297
2
    }
298

            
299
    #[test]
300
2
    fn test_field_set_1() {
301
2
        let mask = 0b0011110000000000;
302
2
        let input = 0b1011;
303
2
        let expected = 0b0010110000000000;
304
2
        let field = Field::from(mask);
305
2
        let mut word = DataWord::from(0);
306
2

            
307
2
        field.set(&mut word, input);
308
2
        assert_eq!(word.as_value(), expected);
309
2
    }
310

            
311
    #[test]
312
2
    fn test_field_set_2() {
313
2
        let mask = 0b0000011111000000;
314
2
        let input = 0b10101;
315
2
        let expected = 0b0000010101000000;
316
2
        let field = Field::from(mask);
317
2
        let mut word = DataWord::from(0);
318
2

            
319
2
        field.set(&mut word, input);
320
2
        assert_eq!(word.as_value(), expected);
321
2
    }
322

            
323
    #[test]
324
2
    fn test_field_set_3() {
325
2
        let mask = 0b0000000001111110;
326
2
        let input = 0b101101;
327
2
        let expected = 0b0000000001011010;
328
2
        let field = Field::from(mask);
329
2
        let mut word = DataWord::from(0);
330
2

            
331
2
        field.set(&mut word, input);
332
2
        assert_eq!(word.as_value(), expected);
333
2
    }
334

            
335
    #[test]
336
2
    fn test_field_set_4() {
337
2
        let mask = 0b0000000000000011;
338
2
        let input = 0b0000011;
339
2
        let expected = 0b0000000000000011;
340
2
        let field = Field::from(mask);
341
2
        let mut word = DataWord::from(0);
342
2

            
343
2
        field.set(&mut word, input);
344
2
        assert_eq!(word.as_value(), expected);
345
2
    }
346
}