Skip to content

Commit 553af2a

Browse files
committed
add code files
1 parent c517263 commit 553af2a

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import board
2+
import displayio
3+
import keypad
4+
import time
5+
import adafruit_displayio_sh1107
6+
from adafruit_hid.keyboard import Keyboard
7+
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
8+
from adafruit_hid.keycode import Keycode
9+
from adafruit_display_text import label
10+
from adafruit_bitmap_font import bitmap_font
11+
12+
try:
13+
import usb_hid
14+
except ImportError:
15+
usb_hid = None
16+
17+
K_SQ = "√"
18+
K_CL = "<clear>"
19+
K_FN = "<fn>"
20+
K_PA = "<paste>"
21+
22+
KEYMAP0 = [
23+
K_CL, K_FN, '%', '/',
24+
'7', '8', '9', '*',
25+
'4', '5', '6', '-',
26+
'1', '2', '3', '+',
27+
'0', '.', K_SQ, '='
28+
]
29+
30+
KEYMAP1 = [
31+
K_CL, None, '', '',
32+
'', '', '', '',
33+
'', '', '', '',
34+
'', '', '', '',
35+
'', '', '', K_PA,
36+
]
37+
38+
keymaps = {
39+
0: KEYMAP0,
40+
1: KEYMAP1,
41+
}
42+
43+
def lookup(layer, key_number):
44+
while layer >= 0:
45+
if (key := keymaps[layer][key_number]) is not None:
46+
return key
47+
layer -= 1
48+
return None
49+
50+
displayio.release_displays()
51+
# oled_reset = board.D9
52+
53+
# Use for I2C
54+
i2c = board.I2C()
55+
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
56+
57+
# SH1107 is vertically oriented 64x128
58+
WIDTH = 128
59+
HEIGHT = 64
60+
61+
display = adafruit_displayio_sh1107.SH1107(display_bus, width=WIDTH, height=HEIGHT, rotation=180)
62+
63+
font = bitmap_font.load_font("/digit-16px.pcf")
64+
text_area = label.Label(font, text=" ", line_spacing=0.95)
65+
text_area.y = 8
66+
display.show(text_area)
67+
68+
N = float
69+
70+
unary = {
71+
K_SQ: lambda a: a**.5,
72+
}
73+
74+
binary = {
75+
'+': (lambda a, b: a+b, lambda a, b: a * (1+b/100)),
76+
'-': (lambda a, b: a-b, lambda a, b: a * (1-b/100)),
77+
'*': (lambda a, b: a*b, lambda a, b: a * (b/100)),
78+
'/': (lambda a, b: a/b, lambda a, b: a / (b/100)),
79+
}
80+
81+
class Calculator:
82+
def __init__(self):
83+
self._number1 = N("0")
84+
self._number2 = None
85+
self.trail = []
86+
self.entry = ""
87+
self.op = None
88+
self.keyboard = None
89+
self.keyboard_layout = None
90+
91+
def paste(text):
92+
if self.keyboard is None:
93+
if usb_hid:
94+
self.keyboard = Keyboard(usb_hid.devices)
95+
self.keyboard_layout = KeyboardLayoutUS(keyboard)
96+
else:
97+
return
98+
99+
if self.keyboard_layout is None:
100+
self.add_trail(f"No USB")
101+
else:
102+
text = str(text)
103+
keyboard_layout.write(text)
104+
105+
self.add_trail(f"Pasted {text}")
106+
107+
108+
def add_trail(self, msg):
109+
self.trail = self.trail[:3] + [str(msg)]
110+
111+
@property
112+
def number1(self):
113+
return self._number1
114+
115+
@number1.setter
116+
def number1(self, number):
117+
self._number1 = number
118+
self.add_trail(number)
119+
120+
@property
121+
def number2(self):
122+
if self.entry == "":
123+
if self._number2 is not None:
124+
return self._number2
125+
return None
126+
return N(self.entry)
127+
128+
@number2.setter
129+
def number2(self, number):
130+
self._number2 = number
131+
self.entry = ''
132+
133+
def clear(self):
134+
self.number1 = N("0")
135+
136+
def clear_entry(self):
137+
self.number2 = None
138+
139+
def key_pressed(self, k):
140+
if k == K_CL:
141+
if self.entry:
142+
self.entry = self.entry[:-1]
143+
elif self.number2 is None:
144+
self.clear()
145+
else:
146+
self.clear_entry()
147+
148+
if len(k) == 1 and k in "0123456789":
149+
self.entry = self.entry + k
150+
151+
if k == "." and not "." in self.entry:
152+
if self.entry == "": self.entry = "0"
153+
self.entry = self.entry + k
154+
155+
if k == K_PA:
156+
if self.number2 is not None:
157+
paste(self.number2)
158+
else:
159+
paste(self.number1)
160+
161+
if k == "=":
162+
self.do_binary_op(0)
163+
164+
if k == "%":
165+
self.do_binary_op(1)
166+
167+
if op := unary.get(k):
168+
self.do_unary_op(op)
169+
170+
if k in binary:
171+
if self.number2 is not None:
172+
if self.op:
173+
self.do_binary_op(0)
174+
else:
175+
self.number1 = self.number2
176+
self.clear_entry()
177+
self.op = k
178+
179+
def do_unary_op(self, op):
180+
if self.number2 is not None:
181+
self.number2 = op(self.number2)
182+
else:
183+
self.number1 = op(self.number1)
184+
185+
def do_binary_op(self, i):
186+
if self.op and self.number2 is not None:
187+
op = binary[self.op][i]
188+
self.op = None
189+
self.number1 = op(self.number1, self.number2)
190+
self.clear_entry()
191+
192+
def show(self):
193+
display.auto_refresh = False
194+
195+
rows = [""] * 4
196+
trail = self.trail
197+
if len(trail) > 0:
198+
rows[2] = trail[-1]
199+
if len(trail) > 1:
200+
rows[1] = trail[-2]
201+
if len(trail) > 2:
202+
rows[0] = trail[-3]
203+
204+
entry_or_number = self.entry or self.number2
205+
cursor = ' :' if (self.number2 is None or self.entry != "") else ""
206+
rows[-1] = f"{self.op or ''}{entry_or_number or ''}{cursor}"
207+
for r in rows: print(r)
208+
text_area.text = "\n".join(rows)
209+
display.auto_refresh = True
210+
211+
km=keypad.KeyMatrix(row_pins=(board.A2, board.A1, board.A3, board.A0, board.D0), column_pins=(board.D25, board.D11, board.D12, board.D24))
212+
213+
calculator=Calculator()
214+
calculator.show()
215+
216+
layer = 0
217+
while True:
218+
if ev := km.events.get():
219+
key = lookup(layer, ev.key_number)
220+
if ev.pressed:
221+
if key == K_FN:
222+
layer = 1
223+
try:
224+
calculator.key_pressed(key)
225+
except Exception as e:
226+
calculator.add_trail(e)
227+
calculator.show()
228+
229+
elif ev.released:
230+
if key == K_FN:
231+
layer = 0
Binary file not shown.

0 commit comments

Comments
 (0)