summaryrefslogtreecommitdiff
path: root/recourses/Keypad.py
diff options
context:
space:
mode:
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 @@
+#!/usr/bin/env python3
+
+import RPi.GPIO as GPIO
+import time
+#class Key:Define some of the properties of Key
+class Key(object):
+ NO_KEY = '\0'
+ #Defines the four states of Key
+ IDLE = 0
+ PRESSED = 1
+ HOLD = 2
+ RELEASED = 3
+ #define OPEN and CLOSED
+ OPEN = 0
+ CLOSED =1
+ #constructor
+ def __init__(self):
+ self.kchar = self.NO_KEY
+ self.kstate = self.IDLE
+ self.kcode = -1
+ self.stateChanged = False
+
+class Keypad(object):
+ NULL = '\0'
+ LIST_MAX = 10 #Max number of keys on the active list.
+ MAPSIZE = 10 #MAPSIZE is the number of rows (times 16 columns)
+ bitMap = [0]*MAPSIZE
+ key = [Key()]*LIST_MAX
+ holdTime = 500 #key hold time
+ holdTimer = 0
+ startTime = 0
+ #Allows custom keymap, pin configuration, and keypad sizes.
+ def __init__(self,usrKeyMap,row_Pins,col_Pins,num_Rows,num_Cols):
+ GPIO.setmode(GPIO.BOARD)
+ self.rowPins = row_Pins
+ self.colPins = col_Pins
+ self.numRows = num_Rows
+ self.numCols = num_Cols
+
+ self.keymap = usrKeyMap
+ self.setDebounceTime(10)
+ #Returns a single key only. Retained for backwards compatibility.
+ def getKey(self):
+ single_key = True
+ if(self.getKeys() and self.key[0].stateChanged and (self.key[0].kstate == self.key[0].PRESSED)):
+ return self.key[0].kchar
+ single_key = False
+ return self.key[0].NO_KEY
+ #Populate the key list.
+ def getKeys(self):
+ keyActivity = False
+ #Limit how often the keypad is scanned.
+ if((time.time() - self.startTime) > self.debounceTime*0.001):
+ self.scanKeys()
+ keyActivity = self.updateList()
+ self.startTime = time.time()
+ return keyActivity
+ #Hardware scan ,the result store in bitMap
+ def scanKeys(self):
+ #Re-intialize the row pins. Allows sharing these pins with other hardware.
+ for pin_r in self.rowPins:
+ GPIO.setup(pin_r,GPIO.IN,pull_up_down = GPIO.PUD_UP)
+ #bitMap stores ALL the keys that are being pressed.
+ for pin_c in self.colPins:
+ GPIO.setup(pin_c,GPIO.OUT)
+ GPIO.output(pin_c,GPIO.LOW)
+ for r in self.rowPins: #keypress is active low so invert to high.
+ self.bitMap[self.rowPins.index(r)] = self.bitWrite(self.bitMap[self.rowPins.index(r)],self.colPins.index(pin_c),not GPIO.input(r))
+ #Set pin to high impedance input. Effectively ends column pulse.
+ GPIO.output(pin_c,GPIO.HIGH)
+ GPIO.setup(pin_c,GPIO.IN)
+ #Manage the list without rearranging the keys. Returns true if any keys on the list changed state.
+ def updateList(self):
+ anyActivity = False
+ kk = Key()
+ #Delete any IDLE keys
+ for i in range(self.LIST_MAX):
+ if(self.key[i].kstate == kk.IDLE):
+ self.key[i].kchar = kk.NO_KEY
+ self.key[i].kcode = -1
+ self.key[i].stateChanged = False
+ # Add new keys to empty slots in the key list.
+ for r in range(self.numRows):
+ for c in range(self.numCols):
+ button = self.bitRead(self.bitMap[r],c)
+ keyChar = self.keymap[r * self.numCols +c]
+ keyCode = r * self.numCols +c
+ idx = self.findInList(keyCode)
+ #Key is already on the list so set its next state.
+ if(idx > -1):
+ self.nextKeyState(idx,button)
+ #Key is NOT on the list so add it.
+ if((idx == -1) and button):
+ for i in range(self.LIST_MAX):
+ if(self.key[i].kchar == kk.NO_KEY): #Find an empty slot or don't add key to list.
+ self.key[i].kchar = keyChar
+ self.key[i].kcode = keyCode
+ self.key[i].kstate = kk.IDLE #Keys NOT on the list have an initial state of IDLE.
+ self.nextKeyState(i,button)
+ break #Don't fill all the empty slots with the same key.
+ #Report if the user changed the state of any key.
+ for i in range(self.LIST_MAX):
+ if(self.key[i].stateChanged):
+ anyActivity = True
+ return anyActivity
+ #This function is a state machine but is also used for debouncing the keys.
+ def nextKeyState(self,idx, button):
+ self.key[idx].stateChanged = False
+ kk = Key()
+ if(self.key[idx].kstate == kk.IDLE):
+ if(button == kk.CLOSED):
+ self.transitionTo(idx,kk.PRESSED)
+ self.holdTimer = time.time() #Get ready for next HOLD state.
+ elif(self.key[idx].kstate == kk.PRESSED):
+ if((time.time() - self.holdTimer) > self.holdTime*0.001): #Waiting for a key HOLD...
+ self.transitionTo(idx,kk.HOLD)
+ elif(button == kk.OPEN): # or for a key to be RELEASED.
+ self.transitionTo(idx,kk.RELEASED)
+ elif(self.key[idx].kstate == kk.HOLD):
+ if(button == kk.OPEN):
+ self.transitionTo(idx,kk.RELEASED)
+ elif(self.key[idx].kstate == kk.RELEASED):
+ self.transitionTo(idx,kk.IDLE)
+
+ def transitionTo(self,idx,nextState):
+ self.key[idx].kstate = nextState
+ self.key[idx].stateChanged = True
+ #Search by code for a key in the list of active keys.
+ #Returns -1 if not found or the index into the list of active keys.
+ def findInList(self,keyCode):
+ for i in range(self.LIST_MAX):
+ if(self.key[i].kcode == keyCode):
+ return i
+ return -1
+ #set Debounce Time, The default is 50ms
+ def setDebounceTime(self,ms):
+ self.debounceTime = ms
+ #set HoldTime,The default is 500ms
+ def setHoldTime(self,ms):
+ self.holdTime = ms
+ #
+ def isPressed(keyChar):
+ for i in range(self.LIST_MAX):
+ if(self.key[i].kchar == keyChar):
+ if(self.key[i].kstate == self.self.key[i].PRESSED and self.key[i].stateChanged):
+ return True
+ return False
+ #
+ def waitForKey():
+ kk = Key()
+ waitKey = kk.NO_KEY
+ while(waitKey == kk.NO_KEY):
+ waitKey = getKey()
+ return waitKey
+
+ def getState():
+ return self.key[0].kstate
+ #
+ def keyStateChanged():
+ return self.key[0].stateChanged
+
+ def bitWrite(self,x,n,b):
+ if(b):
+ x |= (1<<n)
+ else:
+ x &=(~(1<<n))
+ return x
+ def bitRead(self,x,n):
+ if((x>>n)&1 == 1):
+ return True
+ else:
+ return False
+
+ROWS = 4
+COLS = 4
+keys = [ '1','2','3','A',
+ '4','5','6','B',
+ '7','8','9','C',
+ '*','0','#','D' ]
+rowsPins = [12,16,18,22]
+colsPins = [19,15,13,11]
+
+def loop():
+ keypad = Keypad(keys,rowsPins,colsPins,ROWS,COLS)
+ keypad.setDebounceTime(50)
+ while(True):
+ key = keypad.getKey()
+ if(key != keypad.NULL):
+ print ("You Pressed Key : %c "%(key) )
+
+if __name__ == '__main__': # Program start from here
+ print ("Program is starting ... ")
+ try:
+ loop()
+ except KeyboardInterrupt: # When 'Ctrl+C' is pressed, the child program destroy() will be executed.
+ pass
+ GPIO.cleanup()
+
+
+
+
+