11

Dependents:   Program_R11

Revision:
11:a45e64141ce6
Parent:
10:9a9ec143840b
Child:
12:e6623f165199
--- a/keypad.cpp	Fri Nov 02 22:42:28 2012 +0000
+++ b/keypad.cpp	Sat Nov 03 23:33:52 2012 +0000
@@ -6,6 +6,10 @@
     _row0(row0), _row1(row1), _row2(row2), _row3(row3),
     _cols(col0, col1, col2, col3)
 {
+    _rows[0] = &_row0;
+    _rows[1] = &_row1;
+    _rows[2] = &_row2;
+    _rows[3] = &_row3;
     _debounce = debounce_ms;
     _row0.mode(PullUp);
     _row1.mode(PullUp);
@@ -13,71 +17,87 @@
     _row3.mode(PullUp);
     _cols.mode(OpenDrain);
     _cols.output();
-    _setupFallTrigger();
+}
+
+void Keypad::_setupFallTrigger(void)
+{
+    _row0.fall(this, &Keypad::_callback);
+    _row1.fall(this, &Keypad::_callback);
+    _row2.fall(this, &Keypad::_callback);
+    _row3.fall(this, &Keypad::_callback);
 }
 
 void Keypad::Start(void)
 {
+    /* make the columns zero so they can pull rows down */
     _cols = 0x00;
 }
 
 void Keypad::Stop(void)
 {
-    _cols = 0x0F;
+    /* make the columns one so they cannot pull any rows down anymore */
+    _cols = ~0x00;
 }
 
 void Keypad::CallAfterInput(uint32_t (*fptr)(uint32_t index))
 {
     _input.attach(fptr);
+    _setupFallTrigger();
+}
+
+int Keypad::DebouncedScan()
+{
+    int key1 = Scan();
+    
+    /* debounce */
+    wait_ms(_debounce);
+    
+    int key2 = Scan();
+    
+    if (key1 != key2)
+        return -1;
+    else
+        return key1;
 }
 
-void Keypad::_callback(int row, InterruptIn &therow)
+int Keypad::Scan()
 {
-    wait_ms(_debounce);
-    if (therow != 0)
-        return;
+    /* lookup row */
+    int r = -1;
+    for (r = 0; r < row_count; r++) {
+        if (*_rows[r] == 0)
+            break;
+    }
 
+    /* if we didn't find a valid row, return */
+    if (!(0 <= r && r < row_count))
+        return -1;
+
+    /* scan columns to find out which one pulls down the row */ 
     int c = -1;
-    _cols = 0x0E;
-    if (therow == 0)
-        c = 0;
-    else {
-        _cols = 0x0D;
-        if (therow == 0)
-            c = 1;
-        else {
-            _cols = 0x0B;
-            if (therow == 0)
-                c = 2;
-            else
-                c = 3;
-        }
+    for (c = 0; c < col_count; c++) {
+        _cols = ~(1 << c);
+        if (*_rows[r] == 0)
+            break;
     }
-    _input.call(row * 4 + c);
-    Start(); // Re-energize all columns
+
+    /* re-energize all columns */
+    Start();
+
+    /* if we didn't find a valid column, return */
+    if (!(0 <= c && c < col_count))
+        return -1;
+
+    return r * col_count + c;
 }
 
-void Keypad::_cbRow0Fall(void)
-{
-    _callback(0, _row0);
-}
-void Keypad::_cbRow1Fall(void)
+void Keypad::_callback()
 {
-    _callback(1, _row1);
-}
-void Keypad::_cbRow2Fall(void)
-{
-    _callback(2, _row2);
-}
-void Keypad::_cbRow3Fall(void)
-{
-    _callback(3, _row3);
+    /* lookup */
+    int position = DebouncedScan();
+    
+    /* call back a valid position */
+    if (position >= 0)
+        _input.call(position);
 }
 
-void Keypad::_setupFallTrigger(void)
-{
-    _row0.fall(this, &Keypad::_cbRow0Fall);
-    _row1.fall(this, &Keypad::_cbRow1Fall);
-    _row2.fall(this, &Keypad::_cbRow2Fall);
-    _row3.fall(this, &Keypad::_cbRow3Fall);
-}