summaryrefslogtreecommitdiff
path: root/recourses/Keypad.py
diff options
context:
space:
mode:
authorAbdellah El Morabit <nsrddyn@gmail.com>2024-11-05 09:24:48 +0100
committerAbdellah El Morabit <nsrddyn@gmail.com>2024-11-05 09:24:48 +0100
commit5466f96bd75f602f5b5fd44a7ccee745f2abfca0 (patch)
tree52370ece205756f31dce32ddd607d1884ad1e2a0 /recourses/Keypad.py
parent6198d0333d432b4e0dad7e8da2c2395473a12995 (diff)
no clue what i did here
Diffstat (limited to 'recourses/Keypad.py')
-rw-r--r--recourses/Keypad.py202
1 files changed, 202 insertions, 0 deletions
diff --git a/recourses/Keypad.py b/recourses/Keypad.py
new file mode 100644
index 0000000..f762b4b
--- /dev/null
+++ b/recourses/Keypad.py
@@ -0,0 +1,202 @@
1#!/usr/bin/env python3
2
3import RPi.GPIO as GPIO
4import time
5#class Key:Define some of the properties of Key
6class Key(object):
7 NO_KEY = '\0'
8 #Defines the four states of Key
9 IDLE = 0
10 PRESSED = 1
11 HOLD = 2
12 RELEASED = 3
13 #define OPEN and CLOSED
14 OPEN = 0
15 CLOSED =1
16 #constructor
17 def __init__(self):
18 self.kchar = self.NO_KEY
19 self.kstate = self.IDLE
20 self.kcode = -1
21 self.stateChanged = False
22
23class Keypad(object):
24 NULL = '\0'
25 LIST_MAX = 10 #Max number of keys on the active list.
26 MAPSIZE = 10 #MAPSIZE is the number of rows (times 16 columns)
27 bitMap = [0]*MAPSIZE
28 key = [Key()]*LIST_MAX
29 holdTime = 500 #key hold time
30 holdTimer = 0
31 startTime = 0
32 #Allows custom keymap, pin configuration, and keypad sizes.
33 def __init__(self,usrKeyMap,row_Pins,col_Pins,num_Rows,num_Cols):
34 GPIO.setmode(GPIO.BOARD)
35 self.rowPins = row_Pins
36 self.colPins = col_Pins
37 self.numRows = num_Rows
38 self.numCols = num_Cols
39
40 self.keymap = usrKeyMap
41 self.setDebounceTime(10)
42 #Returns a single key only. Retained for backwards compatibility.
43 def getKey(self):
44 single_key = True
45 if(self.getKeys() and self.key[0].stateChanged and (self.key[0].kstate == self.key[0].PRESSED)):
46 return self.key[0].kchar
47 single_key = False
48 return self.key[0].NO_KEY
49 #Populate the key list.
50 def getKeys(self):
51 keyActivity = False
52 #Limit how often the keypad is scanned.
53 if((time.time() - self.startTime) > self.debounceTime*0.001):
54 self.scanKeys()
55 keyActivity = self.updateList()
56 self.startTime = time.time()
57 return keyActivity
58 #Hardware scan ,the result store in bitMap
59 def scanKeys(self):
60 #Re-intialize the row pins. Allows sharing these pins with other hardware.
61 for pin_r in self.rowPins:
62 GPIO.setup(pin_r,GPIO.IN,pull_up_down = GPIO.PUD_UP)
63 #bitMap stores ALL the keys that are being pressed.
64 for pin_c in self.colPins:
65 GPIO.setup(pin_c,GPIO.OUT)
66 GPIO.output(pin_c,GPIO.LOW)
67 for r in self.rowPins: #keypress is active low so invert to high.
68 self.bitMap[self.rowPins.index(r)] = self.bitWrite(self.bitMap[self.rowPins.index(r)],self.colPins.index(pin_c),not GPIO.input(r))
69 #Set pin to high impedance input. Effectively ends column pulse.
70 GPIO.output(pin_c,GPIO.HIGH)
71 GPIO.setup(pin_c,GPIO.IN)
72 #Manage the list without rearranging the keys. Returns true if any keys on the list changed state.
73 def updateList(self):
74 anyActivity = False
75 kk = Key()
76 #Delete any IDLE keys
77 for i in range(self.LIST_MAX):
78 if(self.key[i].kstate == kk.IDLE):
79 self.key[i].kchar = kk.NO_KEY
80 self.key[i].kcode = -1
81 self.key[i].stateChanged = False
82 # Add new keys to empty slots in the key list.
83 for r in range(self.numRows):
84 for c in range(self.numCols):
85 button = self.bitRead(self.bitMap[r],c)
86 keyChar = self.keymap[r * self.numCols +c]
87 keyCode = r * self.numCols +c
88 idx = self.findInList(keyCode)
89 #Key is already on the list so set its next state.
90 if(idx > -1):
91 self.nextKeyState(idx,button)
92 #Key is NOT on the list so add it.
93 if((idx == -1) and button):
94 for i in range(self.LIST_MAX):
95 if(self.key[i].kchar == kk.NO_KEY): #Find an empty slot or don't add key to list.
96 self.key[i].kchar = keyChar
97 self.key[i].kcode = keyCode
98 self.key[i].kstate = kk.IDLE #Keys NOT on the list have an initial state of IDLE.
99 self.nextKeyState(i,button)
100 break #Don't fill all the empty slots with the same key.
101 #Report if the user changed the state of any key.
102 for i in range(self.LIST_MAX):
103 if(self.key[i].stateChanged):
104 anyActivity = True
105 return anyActivity
106 #This function is a state machine but is also used for debouncing the keys.
107 def nextKeyState(self,idx, button):
108 self.key[idx].stateChanged = False
109 kk = Key()
110 if(self.key[idx].kstate == kk.IDLE):
111 if(button == kk.CLOSED):
112 self.transitionTo(idx,kk.PRESSED)
113 self.holdTimer = time.time() #Get ready for next HOLD state.
114 elif(self.key[idx].kstate == kk.PRESSED):
115 if((time.time() - self.holdTimer) > self.holdTime*0.001): #Waiting for a key HOLD...
116 self.transitionTo(idx,kk.HOLD)
117 elif(button == kk.OPEN): # or for a key to be RELEASED.
118 self.transitionTo(idx,kk.RELEASED)
119 elif(self.key[idx].kstate == kk.HOLD):
120 if(button == kk.OPEN):
121 self.transitionTo(idx,kk.RELEASED)
122 elif(self.key[idx].kstate == kk.RELEASED):
123 self.transitionTo(idx,kk.IDLE)
124
125 def transitionTo(self,idx,nextState):
126 self.key[idx].kstate = nextState
127 self.key[idx].stateChanged = True
128 #Search by code for a key in the list of active keys.
129 #Returns -1 if not found or the index into the list of active keys.
130 def findInList(self,keyCode):
131 for i in range(self.LIST_MAX):
132 if(self.key[i].kcode == keyCode):
133 return i
134 return -1
135 #set Debounce Time, The default is 50ms
136 def setDebounceTime(self,ms):
137 self.debounceTime = ms
138 #set HoldTime,The default is 500ms
139 def setHoldTime(self,ms):
140 self.holdTime = ms
141 #
142 def isPressed(keyChar):
143 for i in range(self.LIST_MAX):
144 if(self.key[i].kchar == keyChar):
145 if(self.key[i].kstate == self.self.key[i].PRESSED and self.key[i].stateChanged):
146 return True
147 return False
148 #
149 def waitForKey():
150 kk = Key()
151 waitKey = kk.NO_KEY
152 while(waitKey == kk.NO_KEY):
153 waitKey = getKey()
154 return waitKey
155
156 def getState():
157 return self.key[0].kstate
158 #
159 def keyStateChanged():
160 return self.key[0].stateChanged
161
162 def bitWrite(self,x,n,b):
163 if(b):
164 x |= (1<<n)
165 else:
166 x &=(~(1<<n))
167 return x
168 def bitRead(self,x,n):
169 if((x>>n)&1 == 1):
170 return True
171 else:
172 return False
173
174ROWS = 4
175COLS = 4
176keys = [ '1','2','3','A',
177 '4','5','6','B',
178 '7','8','9','C',
179 '*','0','#','D' ]
180rowsPins = [12,16,18,22]
181colsPins = [19,15,13,11]
182
183def loop():
184 keypad = Keypad(keys,rowsPins,colsPins,ROWS,COLS)
185 keypad.setDebounceTime(50)
186 while(True):
187 key = keypad.getKey()
188 if(key != keypad.NULL):
189 print ("You Pressed Key : %c "%(key) )
190
191if __name__ == '__main__': # Program start from here
192 print ("Program is starting ... ")
193 try:
194 loop()
195 except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
196 pass
197 GPIO.cleanup()
198
199
200
201
202