bgneal@0
|
1 # Copyright (C) 2013 by Brian Neal.
|
bgneal@0
|
2 # This file is part of m209, the M-209 simulation.
|
bgneal@0
|
3 # m209 is released under the MIT License (see LICENSE.txt).
|
bgneal@0
|
4
|
bgneal@0
|
5 """This module contains the key wheel related classes for the M209
|
bgneal@0
|
6 simulation.
|
bgneal@0
|
7
|
bgneal@0
|
8 """
|
bgneal@0
|
9 from . import M209Error
|
bgneal@0
|
10
|
bgneal@0
|
11 class KeyWheelError(M209Error):
|
bgneal@0
|
12 """Exception class for all key wheel errors"""
|
bgneal@0
|
13 pass
|
bgneal@0
|
14
|
bgneal@0
|
15
|
bgneal@0
|
16 class KeyWheel:
|
bgneal@0
|
17 """Simulates a key wheel in a M209 converter"""
|
bgneal@0
|
18
|
bgneal@0
|
19 def __init__(self, letters, guide_letter, effective_pins=None):
|
bgneal@0
|
20 """Initialize a KeyWheel instance:
|
bgneal@0
|
21
|
bgneal@0
|
22 letters - an iterable of letters which appear on the wheel face
|
bgneal@0
|
23
|
bgneal@0
|
24 guide_letter - must be a letter that appears within the letters
|
bgneal@0
|
25 parameter. It indicates which letter affects the guide arm when the
|
bgneal@0
|
26 first letter in letters is displayed to the operator.
|
bgneal@0
|
27
|
bgneal@0
|
28 effective_pins - see the description of set_pins(), below.
|
bgneal@0
|
29
|
bgneal@0
|
30 """
|
bgneal@0
|
31 self.letters = list(letters)
|
bgneal@0
|
32 self.num_pins = len(self.letters)
|
bgneal@0
|
33
|
bgneal@0
|
34 self.letter_offsets = {letter : n for n, letter in enumerate(self.letters)}
|
bgneal@0
|
35
|
bgneal@0
|
36 if self.num_pins < 1:
|
bgneal@0
|
37 raise KeyWheelError("Too few key wheel letters")
|
bgneal@0
|
38
|
bgneal@0
|
39 # pin effectivity list:
|
bgneal@0
|
40 if effective_pins:
|
bgneal@0
|
41 self.set_pins(effective_pins)
|
bgneal@0
|
42 else:
|
bgneal@0
|
43 self.reset_pins()
|
bgneal@0
|
44
|
bgneal@0
|
45 try:
|
bgneal@0
|
46 self.guide_offset = self.letter_offsets[guide_letter]
|
bgneal@0
|
47 except KeyError:
|
bgneal@0
|
48 raise KeyWheelError("Invalid guide_letter")
|
bgneal@0
|
49
|
bgneal@0
|
50 # rotational position; 0 means first letter shown to operator
|
bgneal@0
|
51 self.pos = 0
|
bgneal@0
|
52
|
bgneal@0
|
53 def reset_pins(self):
|
bgneal@0
|
54 """Reset all pins to the ineffective state."""
|
bgneal@0
|
55 self.pins = [False] * self.num_pins
|
bgneal@0
|
56
|
bgneal@0
|
57 def set_pins(self, effective_pins):
|
bgneal@0
|
58 """Sets which pins are effective.
|
bgneal@0
|
59
|
bgneal@0
|
60 effective_pins - must be an iterable of letters whose pins are slide to
|
bgneal@0
|
61 the "effective" position (to the right). Letters not appearing in this
|
bgneal@0
|
62 sequence are considered to be in the "ineffective" position (to the
|
bgneal@0
|
63 left). If None or empty, all pins are set to be ineffective.
|
bgneal@0
|
64
|
bgneal@0
|
65 """
|
bgneal@0
|
66 self.reset_pins()
|
bgneal@0
|
67 for letter in effective_pins:
|
bgneal@0
|
68 try:
|
bgneal@0
|
69 n = self.letter_offsets[letter]
|
bgneal@0
|
70 except KeyError:
|
bgneal@0
|
71 raise KeyWheelError("Invalid pin: {}".format(letter))
|
bgneal@0
|
72 self.pins[n] = True
|
bgneal@0
|
73
|
bgneal@0
|
74 def rotate(self, steps=1):
|
bgneal@0
|
75 """Rotate the key wheel the given number of steps."""
|
bgneal@0
|
76 self.pos = (self.pos + steps) % self.num_pins
|
bgneal@0
|
77
|
bgneal@0
|
78 def display(self):
|
bgneal@0
|
79 """Returns the letter shown to the operator based on the current key
|
bgneal@0
|
80 wheel position.
|
bgneal@0
|
81
|
bgneal@0
|
82 """
|
bgneal@0
|
83 return self.letters[self.pos]
|
bgneal@0
|
84
|
bgneal@0
|
85 def guide_letter(self):
|
bgneal@0
|
86 """Returns the letter of the pin that is in position to effect the guide
|
bgneal@0
|
87 arm. To check to see if this pin will effect the guide arm, call
|
bgneal@0
|
88 is_effective().
|
bgneal@0
|
89
|
bgneal@0
|
90 """
|
bgneal@0
|
91 n = (self.pos + self.guide_offset) % self.num_pins
|
bgneal@0
|
92 return self.letters[n]
|
bgneal@0
|
93
|
bgneal@0
|
94 def is_effective(self):
|
bgneal@0
|
95 """Returns True if the key wheel, in the current position, has a pin in
|
bgneal@0
|
96 the effective position, and False otherwise.
|
bgneal@0
|
97
|
bgneal@0
|
98 """
|
bgneal@0
|
99 n = (self.pos + self.guide_offset) % self.num_pins
|
bgneal@0
|
100 return self.pins[n]
|
bgneal@0
|
101
|
bgneal@0
|
102 def set_pos(self, c):
|
bgneal@0
|
103 """Sets the position of the key wheel to the letter c."""
|
bgneal@0
|
104 try:
|
bgneal@0
|
105 self.pos = self.letter_offsets[c]
|
bgneal@0
|
106 except KeyError:
|
bgneal@0
|
107 raise KeyWheelError("Invalid position {}".format(c))
|