From 5466f96bd75f602f5b5fd44a7ccee745f2abfca0 Mon Sep 17 00:00:00 2001 From: Abdellah El Morabit Date: Tue, 5 Nov 2024 09:24:48 +0100 Subject: no clue what i did here --- recourses/Keypad.py | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 recourses/Keypad.py (limited to 'recourses/Keypad.py') 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)&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() + + + + + -- cgit v1.2.3-70-g09d2