/* ----------------------------------------------------------------------------
 * ergoDOX : controller specific exports
 * ----------------------------------------------------------------------------
 * Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
 * Released under The MIT License (MIT) (see "license.md")
 * Project located at <https://github.com/benblazak/ergodox-firmware>
 * ------------------------------------------------------------------------- */

#pragma once

#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdbool.h>
#include <stdint.h>
#include <util/delay.h>
#include <util/twi.h>
#include "./matrix.h"
#include "./options.h"

// --------------------------------------------------------------------

uint8_t kb_init(void);
uint8_t kb_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]);

// --------------------------------------------------------------------

#define MCP23018_TWI_ADDRESS 0b0100000

uint8_t mcp23018_init(void);
uint8_t mcp23018_update_matrix( bool matrix[KB_ROWS][KB_COLUMNS] );

// --------------------------------------------------------------------

uint8_t teensy_init(void);
uint8_t teensy_update_matrix( bool matrix[KB_ROWS][KB_COLUMNS] );

// --------------------------------------------------------------------

#define _kb_led_1_on()           (DDRB |=  (1<<5))
#define _kb_led_1_off()          (DDRB &= ~(1<<5))
#define _kb_led_1_set(n)         (OCR1A = (uint8_t)(n))
#define _kb_led_1_set_percent(n) (OCR1A = (uint8_t)((n) * 0xFF))

#define _kb_led_2_on()           (DDRB |=  (1<<6))
#define _kb_led_2_off()          (DDRB &= ~(1<<6))
#define _kb_led_2_set(n)         (OCR1B = (uint8_t)(n))
#define _kb_led_2_set_percent(n) (OCR1B = (uint8_t)((n) * 0xFF))

#define _kb_led_3_on()           (DDRB |=  (1<<7))
#define _kb_led_3_off()          (DDRB &= ~(1<<7))
#define _kb_led_3_set(n)         (OCR1C = (uint8_t)(n))
#define _kb_led_3_set_percent(n) (OCR1C = (uint8_t)((n) * 0xFF))


#define _kb_led_all_on() do {                   \
		_kb_led_1_on();                             \
		_kb_led_2_on();                             \
		_kb_led_3_on();                             \
  } while(0)

#define _kb_led_all_off() do {                  \
		_kb_led_1_off();                            \
		_kb_led_2_off();                            \
		_kb_led_3_off();                            \
  } while(0)

#define _kb_led_all_set(n) do {                 \
		_kb_led_1_set(n);                           \
		_kb_led_2_set(n);                           \
		_kb_led_3_set(n);                           \
  } while(0)

#define _kb_led_all_set_percent(n) do {         \
		_kb_led_1_set_percent(n);                   \
		_kb_led_2_set_percent(n);                   \
		_kb_led_3_set_percent(n);                   \
  } while(0)

// --------------------------------------------------------------------

#define TWI_FREQ 400000

void    twi_init  (void);
uint8_t twi_start (void);
void    twi_stop  (void);
uint8_t twi_send  (uint8_t data);
uint8_t twi_read  (uint8_t * data);

// --------------------------------------------------------------------

void usb_init(void);			// initialize everything
uint8_t usb_configured(void);		// is the USB port configured

int8_t usb_keyboard_press(uint8_t key, uint8_t modifier);
int8_t usb_keyboard_send(void);
extern uint8_t keyboard_modifier_keys;
extern uint8_t keyboard_keys[6];
extern volatile uint8_t keyboard_leds;

extern uint16_t consumer_key;

// This file does not include the HID debug functions, so these empty
// macros replace them with nothing, so users can compile code that
// has calls to these functions.
#define usb_debug_putchar(c)
#define usb_debug_flush_output()

int8_t usb_extra_consumer_send();

// Everything below this point is only intended for usb_serial.c

#define EP_TYPE_CONTROL			0x00
#define EP_TYPE_BULK_IN			0x81
#define EP_TYPE_BULK_OUT		0x80
#define EP_TYPE_INTERRUPT_IN		0xC1
#define EP_TYPE_INTERRUPT_OUT		0xC0
#define EP_TYPE_ISOCHRONOUS_IN		0x41
#define EP_TYPE_ISOCHRONOUS_OUT		0x40

#define EP_SINGLE_BUFFER		0x02
#define EP_DOUBLE_BUFFER		0x06

#define EP_SIZE(s)	((s) == 64 ? 0x30 :	\
			((s) == 32 ? 0x20 :	\
			((s) == 16 ? 0x10 :	\
			             0x00)))

#define MAX_ENDPOINT		4

#define LSB(n) (n & 255)
#define MSB(n) ((n >> 8) & 255)

#define HW_CONFIG() (UHWCON = 0x01)
#define PLL_CONFIG() (PLLCSR = 0x12)
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))

// standard control endpoint request types
#define GET_STATUS			0
#define CLEAR_FEATURE			1
#define SET_FEATURE			3
#define SET_ADDRESS			5
#define GET_DESCRIPTOR			6
#define GET_CONFIGURATION		8
#define SET_CONFIGURATION		9
#define GET_INTERFACE			10
#define SET_INTERFACE			11
// HID (human interface device)
#define HID_GET_REPORT			1
#define HID_GET_IDLE			2
#define HID_GET_PROTOCOL		3
#define HID_SET_REPORT			9
#define HID_SET_IDLE			10
#define HID_SET_PROTOCOL		11
// CDC (communication class device)
#define CDC_SET_LINE_CODING		0x20
#define CDC_GET_LINE_CODING		0x21
#define CDC_SET_CONTROL_LINE_STATE	0x22
