This is a part of the Kinetiszer project.

Dependencies:   inc

Dependents:   kinetisizer

keyboard.c

Committer:
Clemo
Date:
2014-10-28
Revision:
1:8ae4ab73ca6a
Parent:
0:cb80470434eb

File content as of revision 1:8ae4ab73ca6a:

#include "atmegatron.h"


keyboard_key_t g_encoder[] =
{
	// Function bit 7 is either reserved 1 (IOCON_RESERVED_BIT_7) or "Digital functional mode" (IOCON_DIGMODE_EN),
	// meaning that it has to be set in all cases.
	// No pull-ups or -downs on rotary encoder pins. All inputs are inverted to read as 1 on contact closed.
	// Rotary encoders are handled as two non-matrix keys.

	#if defined BOARD_KEYBOARD_RE0 /* S1 */
		{ BOARD_KEYBOARD_RE0_A_PORT, BOARD_KEYBOARD_RE0_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE0_B_PORT, BOARD_KEYBOARD_RE0_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif

	#if defined BOARD_KEYBOARD_RE1 /* S2 */
		{ BOARD_KEYBOARD_RE1_A_PORT, BOARD_KEYBOARD_RE1_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE1_B_PORT, BOARD_KEYBOARD_RE1_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif

	#if defined BOARD_KEYBOARD_RE2 /* S3 */
		{ BOARD_KEYBOARD_RE2_A_PORT, BOARD_KEYBOARD_RE2_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE2_B_PORT, BOARD_KEYBOARD_RE2_B_PIN, IOCON_FUNC1|IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif

	#if defined BOARD_KEYBOARD_RE3 /* S4 */
		{ BOARD_KEYBOARD_RE3_A_PORT, BOARD_KEYBOARD_RE3_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE3_B_PORT, BOARD_KEYBOARD_RE3_B_PIN, IOCON_FUNC1|IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif

	#if defined BOARD_KEYBOARD_RE4 /* S5 */
		{ BOARD_KEYBOARD_RE4_A_PORT, BOARD_KEYBOARD_RE4_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE4_B_PORT, BOARD_KEYBOARD_RE4_B_PIN, IOCON_FUNC1|IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif

	#if defined BOARD_KEYBOARD_RE5 /* S6 */
		{ BOARD_KEYBOARD_RE5_A_PORT, BOARD_KEYBOARD_RE5_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE5_B_PORT, BOARD_KEYBOARD_RE5_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif

	#if defined BOARD_KEYBOARD_RE6 /* S7 */
		{ BOARD_KEYBOARD_RE6_A_PORT, BOARD_KEYBOARD_RE6_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE6_B_PORT, BOARD_KEYBOARD_RE6_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif

	#if defined BOARD_KEYBOARD_RE7 /* S8 */
		{ BOARD_KEYBOARD_RE7_A_PORT, BOARD_KEYBOARD_RE7_A_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
		{ BOARD_KEYBOARD_RE7_B_PORT, BOARD_KEYBOARD_RE7_B_PIN, IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif
};


keyboard_key_t g_key[] =
{
	// Function bit 7 is either reserved 1 (IOCON_RESERVED_BIT_7) or "Digital functional mode" (IOCON_DIGMODE_EN),
	// meaning that it has to be set in all cases.
	// Pull-ups needed. All inputs are inverted to read as 1 on contact closed.

	// S9 (ISP)
	{ BOARD_KEYBOARD_ISP_PORT, BOARD_KEYBOARD_ISP_PIN, IOCON_MODE_PULLUP|IOCON_DIGMODE_EN|IOCON_INV_EN },

	#if defined RESET_IS_GPIO
		// S10 (reset) could go here...
		{ BOARD_KEYBOARD_RESET_PORT, BOARD_KEYBOARD_RESET_PIN, IOCON_FUNC1|IOCON_MODE_PULLUP|IOCON_DIGMODE_EN|IOCON_INV_EN },
	#endif
};


keyboard_matrix_key_t g_matrix_key[] =
{
#ifdef BOARD_KEYBOARD_S00  /* S1 */
	{ BOARD_KEYBOARD_C0_PORT, BOARD_KEYBOARD_C0_PIN, BOARD_KEYBOARD_R0_PORT, BOARD_KEYBOARD_R0_PIN, { 0, key_released, false }},
#endif

#ifdef BOARD_KEYBOARD_S01  /* S2 */
	{ BOARD_KEYBOARD_C1_PORT, BOARD_KEYBOARD_C1_PIN, BOARD_KEYBOARD_R0_PORT, BOARD_KEYBOARD_R0_PIN, { 0, key_released, false }},
#endif

#ifdef BOARD_KEYBOARD_S02  /* S3 */
	{ BOARD_KEYBOARD_C2_PORT, BOARD_KEYBOARD_C2_PIN, BOARD_KEYBOARD_R0_PORT, BOARD_KEYBOARD_R0_PIN, { 0, key_released, false }},
#endif

#ifdef BOARD_KEYBOARD_S10  /* S4 */
	{ BOARD_KEYBOARD_C0_PORT, BOARD_KEYBOARD_C0_PIN, BOARD_KEYBOARD_R1_PORT, BOARD_KEYBOARD_R1_PIN, { 0, key_released, false }},
#endif

#ifdef BOARD_KEYBOARD_S11  /* S5 */
	{ BOARD_KEYBOARD_C1_PORT, BOARD_KEYBOARD_C1_PIN, BOARD_KEYBOARD_R1_PORT, BOARD_KEYBOARD_R1_PIN, { 0, key_released, false }},
#endif

#ifdef BOARD_KEYBOARD_S12  /* S6 */
	{ BOARD_KEYBOARD_C2_PORT, BOARD_KEYBOARD_C2_PIN, BOARD_KEYBOARD_R1_PORT, BOARD_KEYBOARD_R1_PIN, { 0, key_released, false }},
#endif

#ifdef BOARD_KEYBOARD_S20  /* S7 */
	{ BOARD_KEYBOARD_C0_PORT, BOARD_KEYBOARD_C0_PIN, BOARD_KEYBOARD_R2_PORT, BOARD_KEYBOARD_R2_PIN, { 0, key_released, false }},
#endif

#ifdef BOARD_KEYBOARD_S21  /* S8 */
	{ BOARD_KEYBOARD_C1_PORT, BOARD_KEYBOARD_C1_PIN, BOARD_KEYBOARD_R2_PORT, BOARD_KEYBOARD_R2_PIN, { 0, key_released, false }},
#endif

	// FYI: S9 is ISP, S10 is reset button.

#ifdef BOARD_KEYBOARD_S22  /* S11 */
	{ BOARD_KEYBOARD_C2_PORT, BOARD_KEYBOARD_C2_PIN, BOARD_KEYBOARD_R2_PORT, BOARD_KEYBOARD_R2_PIN, { 0, key_released, false }},
#endif
};


// Since all data is zero, a memset would have been quicker to type.
keyboard_rotary_encoder_data_t g_encoder_data[] =
{
#ifdef BOARD_KEYBOARD_RE0  /* S1 */
	{
		0, 0, 0, 0, 0
	},
#endif

#ifdef BOARD_KEYBOARD_RE1  /* S2 */
	{
		0, 0, 0, 0, 0
	},
#endif

#ifdef BOARD_KEYBOARD_RE2  /* S3 */
	{
		0, 0, 0, 0, 0
	},
#endif

#ifdef BOARD_KEYBOARD_RE3  /* S4 */
	{
		0, 0, 0, 0, 0
	},
#endif

#ifdef BOARD_KEYBOARD_RE4  /* S5 */
	{
		0, 0, 0, 0, 0
	},
#endif

#ifdef BOARD_KEYBOARD_RE5  /* S6 */
	{
		0, 0, 0, 0, 0
	},
#endif

#ifdef BOARD_KEYBOARD_RE6  /* S7 */
	{
		0, 0, 0, 0, 0
	},
#endif

#ifdef BOARD_KEYBOARD_RE7  /* S8 */
	{
		0, 0, 0, 0, 0
	},
#endif
};


#define MATRIX_KEY_COUNT  (sizeof(g_matrix_key)/sizeof(g_matrix_key[0]))
#define ENCODER_PIN_COUNT  (sizeof(g_encoder)/sizeof(g_encoder[0]))
#define ENCODER_COUNT  (sizeof(g_encoder_data)/sizeof(g_encoder_data[0]))
#define KEYS_OTHER_COUNT  (sizeof(g_key)/sizeof(g_key[0]))

/*
DigitalIn encoder1_a(PTA0); // phase A
DigitalIn encoder1_b(PTE27); // phase B
DigitalIn encoder1_k(PTD2); // integrated pushbutton

DigitalIn encoder2_a(PTC4); // phase A
DigitalIn encoder2_b(PTE25); // phase B
DigitalIn encoder2_k(PTD0); // integrated pushbutton

AnalogIn pot2(A5);
AnalogIn pot3(A4);
AnalogIn pot4(A3);
AnalogIn pot5(A2);
AnalogIn pot6(A1);
AnalogIn pot7(A0);
*/
void keyboard_init(void)
{
	int i;
	
	//encoder1_a.mode(PullUp);
	//encoder1_b.mode(PullUp);
	//encoder1_k.mode(PullUp);
	//encoder2_a.mode(PullUp);
	//encoder2_b.mode(PullUp);
	//encoder2_k.mode(PullUp);
	
	keyboard_matrix_key_t *p_matrix_key;
	keyboard_key_t *p_encoder;
	keyboard_key_t *p_keys_other;

	// Initialize key matrix.
	p_matrix_key = g_matrix_key;
	for (i=0; i<MATRIX_KEY_COUNT; i++)
	{
		// Function bit 7 is either reserved 1 (IOCON_RESERVED_BIT_7) or "Digital functional mode" (IOCON_DIGMODE_EN),
		// meaning that it has to be set in all cases.
		// Pull-ups needed on row pins. All inputs are inverted to read as 1 on contact closed.
		//Chip_IOCON_PinMuxSet(LPC_IOCON,p_matrix_key->row_port,p_matrix_key->row_pin,IOCON_MODE_PULLUP|IOCON_DIGMODE_EN|IOCON_INV_EN);
		//Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_matrix_key->col_port,p_matrix_key->col_pin,OUTPUT);
		//Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_matrix_key->row_port,p_matrix_key->row_pin,INPUT);
		p_matrix_key->data.debounce = 0;
		p_matrix_key->data.value = key_released;
		p_matrix_key->data.changed = false;
		p_matrix_key++;
	}

	// Initialize rotary encoders.
	p_encoder = g_encoder;
	// A rotary encoder has two pins which is why we use ENCODER_PIN_COUNT.
	for (i=0; i<ENCODER_PIN_COUNT; i++)
	{
		//Chip_IOCON_PinMuxSet(LPC_IOCON,p_encoder->port,p_encoder->pin,p_encoder->function);
		//Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_encoder->port,p_encoder->pin,INPUT);
		p_encoder->data.debounce = 0;
		p_encoder->data.value = key_released;
		p_encoder++;
	}

	// Initialize remaining keys like S9 & S10.
	p_keys_other = g_key;
	for (i=0; i<KEYS_OTHER_COUNT; i++)
	{
		//Chip_IOCON_PinMuxSet(LPC_IOCON,p_keys_other->port,p_keys_other->pin,p_keys_other->function);
		//Chip_GPIO_WriteDirBit(LPC_GPIO_PORT,p_keys_other->port,p_keys_other->pin,INPUT);
		p_keys_other->data.debounce = 0;
		p_keys_other->data.value = key_released;
		p_keys_other++;
	}
}


int8_t keyboard_key_is_debounced(int8_t debounce)
{
	int8_t result = 0;
	if (debounce>=KEY_DEBOUNCE_MAX)
	{
		// Key debounced high.
		result = 1;
	}
	else if (debounce<=KEY_DEBOUNCE_MIN)
	{
		// Key debounced low.
		result = -1;
	}
	return result;
}


uint8_t keyboard_matrix_key_read(keyboard_matrix_key_t *p_key)
{
	uint8_t value = 0;

	// Scan a key. Pressed keys read as high (inverted input).
//	Chip_GPIO_WritePortBit(LPC_GPIO_PORT,p_key->col_port,p_key->col_pin,0);
//	value = Chip_GPIO_ReadPortBit(LPC_GPIO_PORT,p_key->row_port,p_key->row_pin);
//	Chip_GPIO_WritePortBit(LPC_GPIO_PORT,p_key->col_port,p_key->col_pin,1);
	return value;
}


inline uint8_t keyboard_key_read(keyboard_key_t *p_key)
{
	// Pressed keys read as high (inverted input).
	//return Chip_GPIO_ReadPortBit(LPC_GPIO_PORT,p_key->port,p_key->pin);
	return 0;
}


uint8_t keyboard_key_debounce(int8_t *p_debounce, uint8_t state)
{
	uint8_t result = 0;

	// Debounce.
	if (state!=0)
	{
		if ((*p_debounce)<KEY_DEBOUNCE_MAX) (*p_debounce)++;
		if ((*p_debounce)>=KEY_DEBOUNCE_MAX) result = 1;
	}
	else
	{
		if ((*p_debounce)>KEY_DEBOUNCE_MIN) (*p_debounce)--;
		if ((*p_debounce)<=KEY_DEBOUNCE_MIN) result = 1;
	}

	return result;
}


uint32_t keyboard_scan_matrix(void)
{
	int i;
	uint8_t state;

	// Scan key matrix.
	for (i=0; i<MATRIX_KEY_COUNT; i++)
	{
		state = keyboard_matrix_key_read(&g_matrix_key[i]);
		if (keyboard_key_debounce(&g_matrix_key[i].data.debounce,state)!=0)
		{
			// Update pushbutton value.
			if (g_matrix_key[i].data.debounce>=KEY_DEBOUNCE_MAX)
			{
				if (g_matrix_key[i].data.value!=key_pressed)
				{
					g_matrix_key[i].data.changed = true;
				}
				g_matrix_key[i].data.value = key_pressed;
			}
			else
			{
				if (g_matrix_key[i].data.value!=key_released)
				{
					g_matrix_key[i].data.changed = true;
				}
				g_matrix_key[i].data.value = key_released;
			}
		}
	}

	// Scan other keys (S9, S10) too.
	for (i=0; i<KEYS_OTHER_COUNT; i++)
	{
		state = keyboard_key_read(&g_key[i]);
		if (keyboard_key_debounce(&g_key[i].data.debounce,state)!=0)
		{
			// Update pushbutton value.
			if (g_key[i].data.debounce>=KEY_DEBOUNCE_MAX)
			{
				if (g_key[i].data.value!=key_pressed)
				{
					g_key[i].data.changed = true;
				}
				g_key[i].data.value = key_pressed;
			}
			else
			{
				if (g_key[i].data.value!=key_released)
				{
					g_key[i].data.changed = true;
				}
				g_key[i].data.value = key_released;
			}
		}
	}

	return 0;
}


uint32_t keyboard_scan_encoders(void)
{
	int i, j, inc;
	int8_t state_new;
	uint8_t a, b;

	j = 0;
	for (i=0; i<ENCODER_COUNT; i++)
	{
		a = keyboard_key_read(&g_encoder[j]);
		j += 1;
		b = keyboard_key_read(&g_encoder[j]);
		j += 1;
		state_new = (a<<1) | b;
		if (state_new!=g_encoder_data[i].state)
		{
			inc = a ^ (g_encoder_data[i].state&0x01);
			if (inc==0) inc = -1;
			g_encoder_data[i].state = state_new;

			g_encoder_data[i].state_sub += inc;
			if ((g_encoder_data[i].state_sub<=-4) || (g_encoder_data[i].state_sub>=4))
			{
				g_encoder_data[i].state_sub = 0;
				g_encoder_data[i].value -= inc;
				keyboard_encoder_speed(&g_encoder_data[i]);
			}
		}
	}

	return 0;
}


void keyboard_encoder_speed(keyboard_rotary_encoder_data_t *p_encoder_data)
{
	uint32_t timestamp = systick_counter;
	uint32_t delta = timestamp - p_encoder_data->timestamp;
	//delta = 0x1ffff >> delta;
	if (delta<KEY_PERIOD_MIN) delta = KEY_PERIOD_MIN;
	else if (delta>KEY_PERIOD_MAX) delta = KEY_PERIOD_MAX;
	p_encoder_data->accelerator = (uint8_t)(KEY_PERIOD_MAX/delta);
	if (p_encoder_data->accelerator==0) p_encoder_data->accelerator = 1;
	p_encoder_data->timestamp = timestamp;
}


bool keyboard_get_pushbutton_changed(uint8_t key_nr)
{
	if (key_nr>=BOARD_KEYBOARD_ISP)
	{
		// "Other" pushbuttons start at S9.
		return g_key[key_nr-BOARD_KEYBOARD_ISP].data.changed;
	}
	else
	{
		return g_matrix_key[key_nr].data.changed;
	}
}


keyboard_key_press_t keyboard_get_pushbutton(uint8_t key_nr, bool use)
{
	if (key_nr>=BOARD_KEYBOARD_ISP)
	{
		// "Other" pushbuttons start at S9.
		if (use==true) g_key[key_nr-BOARD_KEYBOARD_ISP].data.changed = false;
		return g_key[key_nr-BOARD_KEYBOARD_ISP].data.value;
	}
	else
	{
		if (use==true) g_matrix_key[key_nr].data.changed = false;
		return g_matrix_key[key_nr].data.value;
	}
}


void keyboard_set_pushbutton(uint8_t key_nr, keyboard_key_press_t value)
{
	if (key_nr>=BOARD_KEYBOARD_ISP)
	{
		// "Other" pushbuttons start at S9.
		g_key[key_nr-BOARD_KEYBOARD_ISP].data.value = value;
		g_key[key_nr-BOARD_KEYBOARD_ISP].data.changed = false;
	}
	else
	{
		g_matrix_key[key_nr].data.value = value;
		g_matrix_key[key_nr].data.changed = false;
	}
}


int8_t keyboard_get_rotary_encoder_value(uint8_t encoder_nr)
{
	return g_encoder_data[encoder_nr].value;
}


void keyboard_set_rotary_encoder_value(uint8_t encoder_nr, int8_t value)
{
	g_encoder_data[encoder_nr].value = value;
}


uint8_t keyboard_get_rotary_encoder_accelerator(uint8_t encoder_nr)
{
	return g_encoder_data[encoder_nr].accelerator;
}