#ifndef KEYBOARD_H
#define KEYBOARD_H

#define KEYBOARD_CLOCK (5)
#define KEYBOARD_CLOCK_PORT (PORTD)
#define KEYBOARD_CLOCK_PIN (PIND)
#define KEYBOARD_CLOCK_DDR (DDRD)

#define KEYBOARD_DATA (6)
#define KEYBOARD_DATA_PORT (PORTD)
#define KEYBOARD_DATA_PIN (PIND)
#define KEYBOARD_DATA_DDR (DDRD)

#define KEYBOARD_LINE_LOW(line, port, ddr) ddr |= (uint8_t)_BV(line)
#define KEYBOARD_LINE_HIGH(line, port, ddr) ddr &= (uint8_t)~_BV(line)

#define KEYBOARD_CLOCK_LOW() KEYBOARD_LINE_LOW(KEYBOARD_CLOCK, KEYBOARD_CLOCK_PORT, KEYBOARD_CLOCK_DDR)
#define KEYBOARD_CLOCK_HIGH() KEYBOARD_LINE_HIGH(KEYBOARD_CLOCK, KEYBOARD_CLOCK_PORT, KEYBOARD_CLOCK_DDR)

#define KEYBOARD_DATA_LOW() KEYBOARD_LINE_LOW(KEYBOARD_DATA, KEYBOARD_DATA_PORT, KEYBOARD_DATA_DDR)
#define KEYBOARD_DATA_HIGH() KEYBOARD_LINE_HIGH(KEYBOARD_DATA, KEYBOARD_DATA_PORT, KEYBOARD_DATA_DDR)

#define KEYBOARD_BUFFER_SIZE 16

enum keyboard_transmission_direction_t {
	KEYBOARD_TRANSMISSION_DEVICE_TO_HOST, // The device is sending data to the host (normal mode).
	KEYBOARD_TRANSMISSION_HOST_TO_DEVICE, // The host is sending data to the device.
};

extern volatile enum keyboard_transmission_direction_t keyboard_transmission_direction;

enum keyboard_receive_mode_t {
	KEYBOARD_RECEIVE_SCANCODE, // The host is receiving scancodes (normal mode).
	KEYBOARD_RECEIVE_ACKNOWLEDGEMENT, // The host is waiting for acknowledgement.
	KEYBOARD_RECEIVE_ACKNOWLEDGEMENT_LED, // The host is waiting for acknowledgement before sending LED status.
};

extern volatile enum keyboard_receive_mode_t keyboard_receive_mode;

enum keyboard_led_status_t {
	KEYBOARD_LED_SCROLL_LOCK = 0x01,
	KEYBOARD_LED_NUM_LOCK = 0x02,
	KEYBOARD_LED_CAPS_LOCK = 0x04,
};

extern volatile uint8_t keyboard_key_state[16];

void keyboard_clear_receive_buffer(void);

void keyboard_reset(void);

void keyboard_byte_received(uint8_t value);

void keyboard_bit_received(uint8_t bit);

void keyboard_send_byte(uint8_t value);

void keyboard_send_bit(void);

extern void keyboard_enable_clock_interrupt(void);

extern void keyboard_disable_clock_interrupt(void);

void keyboard_set_led_status(enum keyboard_led_status_t status);

extern volatile uint8_t keyboard_buffer_count;

char keyboard_buffer_dequeue(void);

extern volatile uint8_t keyboard_reset_flag;

extern volatile uint8_t keyboard_key_received_flag;

#endif