spectrusty_peripherals/serial/
keypad.rs1#![allow(clippy::inconsistent_digit_grouping)]
9#![allow(clippy::unusual_byte_groupings)]
10#[cfg(feature = "snapshot")]
11use serde::{Serialize, Deserialize};
12
13use rand::{Rng, SeedableRng};
14use rand::rngs::SmallRng;
15
16use spectrusty_core::clock::{FTs, TimestampOps};
17use super::{SerialPortDevice, DataState, ControlState};
18
19bitflags! {
20 #[derive(Default)]
24 #[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
25 #[cfg_attr(feature = "snapshot", serde(from = "u32", into = "u32"))]
26 pub struct KeypadKeys: u32 {
27 const ROW1_MASK = 0b0000_0000_1111_0000_0000;
29 const ROW2_MASK = 0b0000_1111_0000_0000_0000;
31 const ROW3_MASK = 0b1111_0000_0000_0000_0000;
33 const ROW4_MASK = 0b0000_0000_0000_1111_0000;
35 const ROW5_MASK = 0b0000_0000_0000_0000_1111;
37 const DOT = 0b0000_0000_0000_0000_0010;
38 const PERIOD = Self::DOT.bits();
40 const N0 = 0b0000_0000_0000_0000_1000;
41 const SHIFT = Self::N0.bits();
43 const ENTER = 0b0000_0000_0000_0001_0000;
44 const N3 = 0b0000_0000_0000_0010_0000;
45 const N2 = 0b0000_0000_0000_0100_0000;
46 const N1 = 0b0000_0000_0000_1000_0000;
47 const RPAREN = 0b0000_0000_0001_0000_0000;
48 const TOGGLE = Self::RPAREN.bits();
50 const LPAREN = 0b0000_0000_0010_0000_0000;
51 const ASTERISK = 0b0000_0000_0100_0000_0000;
52 const MULTIPLY = Self::ASTERISK.bits();
54 const SLASH = 0b0000_0000_1000_0000_0000;
55 const DIVIDE = Self::SLASH.bits();
57 const MINUS = 0b0000_0001_0000_0000_0000;
58 const CMND = Self::MINUS.bits();
60 const N9 = 0b0000_0010_0000_0000_0000;
61 const N8 = 0b0000_0100_0000_0000_0000;
62 const N7 = 0b0000_1000_0000_0000_0000;
63 const PLUS = 0b0001_0000_0000_0000_0000;
64 const N6 = 0b0010_0000_0000_0000_0000;
65 const N5 = 0b0100_0000_0000_0000_0000;
66 const N4 = 0b1000_0000_0000_0000_0000;
67 }
68}
69
70mod intervals {
71 use super::FTs;
72 pub const PRESENT_MAX_INTERVAL : FTs = 3593;
73 pub const PRESENT_MIN_INTERVAL : FTs = PRESENT_MAX_INTERVAL/10;
74 pub const CORRECT_MAX_INTERVAL : FTs = 3917;
75 pub const CORRECT_MIN_INTERVAL : FTs = CORRECT_MAX_INTERVAL/10;
76 pub const WAITING_MAX_INTERVAL : FTs = 4121;
77 pub const WAITING_MIN_INTERVAL : FTs = WAITING_MAX_INTERVAL/2;
78 pub const BITLOOP_MAX_INTERVAL : FTs = 570;
79 pub const BITLOOP_MIN_INTERVAL : FTs = BITLOOP_MAX_INTERVAL/4;
80 pub const READY_MAX_INTERVAL : FTs = 250;
81 pub const READY_MIN_INTERVAL : FTs = 50;
82 pub const RESET_MIN_INTERVAL : FTs = 2_000_000;
83 pub const RESET_MAX_INTERVAL : FTs = 7_000_000;
84 pub const SET_GO_TIMEOUT : FTs = 2128; pub const READY_START_TIMEOUT : FTs = 709; pub const STOP_STAND_EASY_TIMEOUT: FTs = 4610; }
88use intervals::*;
89#[derive(Clone, Debug)]
127#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
128#[cfg_attr(feature = "snapshot", serde(rename_all = "camelCase"))]
129pub struct SerialKeypad<T> {
130 keys: KeypadKeys,
131 keys_changed: u32,
132 next_row: u8,
133 output_bits: u8,
134 keypad_io: KeypadIoStatus,
135 keypad_event_ts: T,
136 #[cfg_attr(feature = "snapshot", serde(skip, default = "SmallRng::from_entropy"))]
137 rng: SmallRng,
138}
139
140const STATUS0_ROW_DATA: u8 = 0b_____10;
142const STATUS1_ROW_TEMPLATE: u8 = 0b10_0001;
144const SERIAL_DATA: u8 = 0b_1_0100;
146
147#[inline(always)]
148fn row_data_to_output_bits(nibble: u8) -> u8 {
149 STATUS1_ROW_TEMPLATE | ((nibble & 0xF) << 1)
150}
151
152#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
154enum KeypadIoStatus {
155 Reset,
156 SyncPreset,
157 SyncCorrect,
158 Waiting,
159 Ready,
160 Data,
161 Stopped,
162}
163
164impl<T: Default + TimestampOps> Default for SerialKeypad<T> {
165 fn default() -> Self {
166 let keys = KeypadKeys::default();
167 let keys_changed = 0;
168 let next_row = 0;
169 let output_bits = 0;
170 let rng = SmallRng::from_entropy();
171 let keypad_event_ts = T::default() + RESET_MAX_INTERVAL;
172 let keypad_io = KeypadIoStatus::Reset;
173 SerialKeypad {
174 keys, keys_changed, next_row, output_bits,
175 keypad_event_ts, rng, keypad_io,
176 }
177 }
178}
179
180impl<T: TimestampOps> SerialPortDevice for SerialKeypad<T> {
181 type Timestamp = T;
182 #[inline(always)]
183 fn write_data(&mut self, _rxd: DataState, _timestamp: Self::Timestamp) -> ControlState {
184 ControlState::Inactive
185 }
186 #[inline(always)]
187 fn poll_ready(&mut self, _timestamp: Self::Timestamp) -> ControlState {
188 ControlState::Inactive
189 }
190 #[inline]
191 fn update_cts(&mut self, cts: ControlState, timestamp: Self::Timestamp) {
192 self.update_state(cts, timestamp)
193 }
194 #[inline]
195 fn read_data(&mut self, timestamp: Self::Timestamp) -> DataState {
196 self.read_state(timestamp)
197 }
198 #[inline]
199 fn next_frame(&mut self, eof_timestamp: Self::Timestamp) {
200 if self.keypad_io != KeypadIoStatus::Reset {
201 if eof_timestamp.diff_from(self.keypad_event_ts) > RESET_MIN_INTERVAL as FTs {
203 self.reset_status(eof_timestamp);
204 }
205 }
206 self.keypad_event_ts = self.keypad_event_ts.saturating_sub(eof_timestamp);
207 }
208}
209
210impl<T> SerialKeypad<T> {
211 #[inline]
213 pub fn get_key_state(&self) -> KeypadKeys {
214 self.keys
215 }
216 pub fn set_key_state(&mut self, keys: KeypadKeys) {
218 let keys_changed = (self.keys ^ keys).bits();
219 self.keys_changed |= keys_changed;
220 self.keys = keys;
221 }
222}
223
224impl<T: TimestampOps> SerialKeypad<T> {
225 #[inline]
226 fn gen_range_ts(&mut self, ts: T, lo: FTs, hi: FTs) -> T {
227 let delta = self.rng.gen_range(lo..hi);
228 ts + delta
229 }
230
231 #[inline]
232 fn initiate_output_data(&mut self) {
233 self.next_row = 0;
234 self.keys_changed = KeypadKeys::all().bits();
236 self.output_bits = SERIAL_DATA;
237 }
238
239 #[inline]
240 fn next_output_bit(&mut self) {
241 let bits = self.output_bits >> 1;
242 if (bits & !1) == 0 {
243 self.next_output_data();
244 }
245 else {
246 self.output_bits = bits
247 }
248 }
249
250 #[inline]
251 fn next_output_data(&mut self) {
252 let row = self.next_row % 5;
253 self.next_row = row + 1;
254 let row_bit_shift = 4 * row;
255 let row_mask = 0xF << row_bit_shift;
256 self.output_bits = if self.keys_changed & row_mask == 0 {
257 STATUS0_ROW_DATA
258 }
259 else {
260 let nibble = (self.keys.bits() >> row_bit_shift) as u8;
261 self.keys_changed &= !row_mask;
262 row_data_to_output_bits(nibble)
263 }
264 }
265
266 fn reset_status(&mut self, timestamp: T) {
267 self.keypad_io = KeypadIoStatus::Reset;
268 self.keypad_event_ts = self.gen_range_ts(timestamp, RESET_MIN_INTERVAL, RESET_MAX_INTERVAL);
269 }
271
272 fn read_state(&mut self, timestamp: T) -> DataState {
273 match self.keypad_io {
274 KeypadIoStatus::Reset|
275 KeypadIoStatus::Waiting => {
276 DataState::Mark
277 }
278 KeypadIoStatus::SyncPreset|
279 KeypadIoStatus::Ready => {
280 if timestamp >= self.keypad_event_ts { DataState::Space
282 }
283 else {
284 DataState::Mark
285 }
286 }
287 KeypadIoStatus::SyncCorrect => {
288 if timestamp >= self.keypad_event_ts { DataState::Mark
290 }
291 else {
292 DataState::Space
293 }
294 }
295 KeypadIoStatus::Data => {
296 (self.output_bits & 1 == 1).into()
297 }
298 KeypadIoStatus::Stopped => DataState::Space
299 }
300 }
301
302 fn update_state(&mut self, cts: ControlState, timestamp: T) {
303 match self.keypad_io {
304 KeypadIoStatus::Reset => {
305 if timestamp >= self.keypad_event_ts {
306 if cts.is_active() { self.keypad_event_ts = self.gen_range_ts(timestamp, PRESENT_MIN_INTERVAL, PRESENT_MAX_INTERVAL);
308 self.keypad_io = KeypadIoStatus::SyncPreset;
310 }
311 else {
312 self.reset_status(timestamp);
314 }
315 }
316 }
317 KeypadIoStatus::SyncPreset => {
318 assert!(cts.is_inactive(), "CTS must have been active before");
319 if timestamp >= self.keypad_event_ts { self.keypad_event_ts = self.gen_range_ts(timestamp, CORRECT_MIN_INTERVAL, CORRECT_MAX_INTERVAL);
322 self.keypad_io = KeypadIoStatus::SyncCorrect;
323 }
324 else {
325 self.reset_status(timestamp);
327 }
328 }
329 KeypadIoStatus::SyncCorrect => {
330 assert!(cts.is_active(), "CTS must have been inactive before");
331 if timestamp >= self.keypad_event_ts && timestamp < self.keypad_event_ts + SET_GO_TIMEOUT { self.keypad_event_ts = self.gen_range_ts(timestamp, WAITING_MIN_INTERVAL, WAITING_MAX_INTERVAL);
335 self.keypad_io = KeypadIoStatus::Waiting;
336 self.initiate_output_data();
337 }
338 else {
339 self.reset_status(timestamp);
341 }
342 }
343 KeypadIoStatus::Waiting => { assert!(cts.is_inactive(), "CTS must have been active before");
345 self.keypad_event_ts = self.gen_range_ts(self.keypad_event_ts.max(timestamp),
348 READY_MIN_INTERVAL, READY_MAX_INTERVAL); self.keypad_io = KeypadIoStatus::Ready;
350 }
351 KeypadIoStatus::Ready => {
352 assert!(cts.is_active(), "CTS must have been inactive before");
353 if timestamp >= self.keypad_event_ts && timestamp < self.keypad_event_ts + READY_START_TIMEOUT { self.keypad_event_ts = timestamp; self.keypad_io = KeypadIoStatus::Data;
358 }
361 else {
362 self.reset_status(timestamp);
364 }
365 }
366 KeypadIoStatus::Data => { assert!(cts.is_inactive(), "CTS must have been active before");
368 self.keypad_event_ts = timestamp + STOP_STAND_EASY_TIMEOUT; self.keypad_io = KeypadIoStatus::Stopped;
372 self.next_output_bit();
374 }
375 KeypadIoStatus::Stopped => { assert!(cts.is_active(), "CTS must have been inactive before");
377 if timestamp < self.keypad_event_ts { self.keypad_event_ts = self.gen_range_ts(timestamp, BITLOOP_MIN_INTERVAL, BITLOOP_MAX_INTERVAL);
380 self.keypad_io = KeypadIoStatus::Waiting;
381 }
382 else { self.reset_status(timestamp);
385 }
386 }
387 }
388 }
389}
390
391impl From<u32> for KeypadKeys {
392 fn from(keys: u32) -> Self {
393 KeypadKeys::from_bits_truncate(keys)
394 }
395}
396
397impl From<KeypadKeys> for u32 {
398 fn from(keys: KeypadKeys) -> Self {
399 keys.bits()
400 }
401}