/* keypad.c - 4x4 matrix keypad driver.
 * Copyright 2008 Colin D. Bennett <colin@gibibit.com>.
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * This is a driver for the 4x4 matrix keypad on the Dragon12-Plus board.
 * Keypresses are debounced to eliminate incorrect key detections when
 * keys are pressed or released during a scan.
 *
 * Currently the scanning is done by polling and contains about 28 ms of
 * delay loops to get good readings.  A better solution, particularly for
 * programs that are doing other things too, would be to use interrupts
 * to handle the scanning instead of polling.  An interrupt driver solution
 * would be slightly more complex, but not unbearably so.
 */

#include "hc12drivers/keypad.h"
#include "hc12/hcs12.h"
#include "hc12/delay.h"

void keypad_init(void)
{
	/*** Configure matrix keypad input. ***/
	// PA0-3 are the column lines, and they are used as outputs.
	// PA4-7 are the row lines, and they are used as inputs.
	DDRA = 0x0F;   // Set columns for output, rows for input.
}

// States (0 or 1) of the keys.
static uint8_t scan1[16];
static uint8_t scan2[16];

static void scan(uint8_t *scanbuf)
{
	/* Scan columns by sequentially raising each one. */
	for (uint8_t col = 0; col < 4; col++)
	{
		PORTA = 1 << col;   /* Select column. */
		delay_ms(1);

		/* Scan all keys in the row. */
		for (uint8_t row = 0; row < 4; row++)
		{
			uint8_t key = row * 4 + col;
			if (PORTA & ((1 << row) << 4))
				scanbuf[key] = 1;
			else
				scanbuf[key] = 0;
		}
	}
}

int8_t keypad_read_scancode(void)
{
	// Debounce key presses by scanning the keys twice.
	scan(scan1);
	delay_ms(20);
	scan(scan2);
	
	for (uint8_t i = 0; i < 16; i++)
	{
		if (scan1[i] && scan2[i])
			return i;
	}
	return -1;
}

