@@ -106,6 +106,7 @@ void keyboard_proc(void) | |||
return; | |||
} | |||
// TODO: should send only when changed from last report | |||
if (matrix_is_modified()) { | |||
host_send_keyboard_report(); | |||
#ifdef DEBUG_LED |
@@ -96,13 +96,15 @@ void ps2_host_init(void) | |||
#endif | |||
} | |||
// TODO: send using interrupt if available | |||
uint8_t ps2_host_send(uint8_t data) | |||
{ | |||
bool parity; | |||
RETRY: | |||
parity = true; | |||
ps2_error = 0; | |||
uint8_t res = 0; | |||
bool parity = true; | |||
ps2_error = PS2_ERR_NONE; | |||
#ifdef PS2_INT_DISABLE | |||
PS2_INT_DISABLE(); | |||
#endif | |||
/* terminate a transmission if we have */ | |||
inhibit(); | |||
_delay_us(100); | |||
@@ -139,15 +141,15 @@ RETRY: | |||
WAIT(clock_hi, 50, 8); | |||
WAIT(data_hi, 50, 9); | |||
uint8_t res = ps2_host_recv_response(); | |||
if (res == 0xFE && data != 0xFE) | |||
goto RETRY; | |||
inhibit(); | |||
return res; | |||
res = ps2_host_recv_response(); | |||
ERROR: | |||
#ifdef PS2_INT_ENABLE | |||
PS2_INT_ENABLE(); | |||
idle(); | |||
#else | |||
inhibit(); | |||
return 0; | |||
#endif | |||
return res; | |||
} | |||
/* receive data when host want else inhibit communication */ | |||
@@ -209,46 +211,99 @@ static inline uint8_t pbuf_dequeue(void) | |||
/* get data received by interrupt */ | |||
uint8_t ps2_host_recv(void) | |||
{ | |||
// TODO: release clock line after 100us when inhibited by error | |||
if (ps2_error) { | |||
ps2_host_send(0xFE); // request to resend | |||
ps2_error = PS2_ERR_NONE; | |||
} | |||
return pbuf_dequeue(); | |||
} | |||
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | |||
#define DEBUGP(x) do { PORTC = x; } while (0) | |||
ISR(PS2_INT_VECT) | |||
{ | |||
/* interrupt means start bit comes */ | |||
pbuf_enqueue(recv_data()); | |||
static enum { | |||
INIT, | |||
START, | |||
BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, | |||
PARITY, | |||
STOP, | |||
} state = INIT; | |||
static uint8_t data = 0; | |||
static uint8_t parity = 1; | |||
// TODO: abort if elapse 100us from previous interrupt | |||
// return unless falling edge | |||
if (clock_in()) { | |||
goto RETURN; | |||
} | |||
/* release lines(idle state) */ | |||
idle(); | |||
_delay_us(5); | |||
state++; | |||
DEBUGP(state); | |||
switch (state) { | |||
case START: | |||
if (data_in()) | |||
goto ERROR; | |||
break; | |||
case BIT0: | |||
case BIT1: | |||
case BIT2: | |||
case BIT3: | |||
case BIT4: | |||
case BIT5: | |||
case BIT6: | |||
case BIT7: | |||
data >>= 1; | |||
if (data_in()) { | |||
data |= 0x80; | |||
parity++; | |||
} | |||
break; | |||
case PARITY: | |||
if (data_in()) { | |||
if (!(parity & 0x01)) | |||
goto ERROR; | |||
} else { | |||
if (parity & 0x01) | |||
goto ERROR; | |||
} | |||
break; | |||
case STOP: | |||
if (!data_in()) | |||
goto ERROR; | |||
pbuf_enqueue(data); | |||
goto DONE; | |||
break; | |||
default: | |||
goto ERROR; | |||
} | |||
goto RETURN; | |||
ERROR: | |||
DEBUGP(0xFF); | |||
inhibit(); | |||
ps2_error = state; | |||
DONE: | |||
state = INIT; | |||
data = 0; | |||
parity = 1; | |||
RETURN: | |||
return; | |||
} | |||
#endif | |||
/* | |||
static void ps2_reset(void) | |||
{ | |||
ps2_host_send(0xFF); | |||
if (ps2_host_recv_response() == 0xFA) { | |||
_delay_ms(1000); | |||
ps2_host_recv_response(); | |||
} | |||
} | |||
*/ | |||
/* send LED state to keyboard */ | |||
void ps2_host_set_led(uint8_t led) | |||
{ | |||
#ifdef PS2_INT_DISABLE | |||
PS2_INT_DISABLE(); | |||
#endif | |||
ps2_host_send(0xED); | |||
ps2_host_recv_response(); | |||
ps2_host_send(led); | |||
ps2_host_recv_response(); | |||
#ifdef PS2_INT_ENABLE | |||
PS2_INT_ENABLE(); | |||
idle(); | |||
#endif | |||
} | |||
@@ -257,7 +312,7 @@ static uint8_t recv_data(void) | |||
{ | |||
uint8_t data = 0; | |||
bool parity = true; | |||
ps2_error = 0; | |||
ps2_error = PS2_ERR_NONE; | |||
/* start bit [1] */ | |||
WAIT(clock_lo, 1, 1); | |||
@@ -307,6 +362,7 @@ static inline bool clock_in() | |||
{ | |||
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT); | |||
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT); | |||
_delay_us(1); | |||
return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT); | |||
} | |||
static inline void data_lo() | |||
@@ -324,6 +380,7 @@ static inline bool data_in() | |||
{ | |||
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT); | |||
PS2_DATA_PORT |= (1<<PS2_DATA_BIT); | |||
_delay_us(1); | |||
return PS2_DATA_PIN&(1<<PS2_DATA_BIT); | |||
} | |||
@@ -49,7 +49,7 @@ int main(void) | |||
usbInit(); | |||
print_enable = true; | |||
//debug_enable = true; | |||
debug_enable = true; | |||
keyboard_init(); | |||
/* enforce re-enumeration, do this while interrupts are disabled! */ | |||
@@ -64,56 +64,9 @@ int main(void) | |||
//uint8_t fn_bits = 0; | |||
while (1) { /* main event loop */ | |||
DEBUGP(0x01); | |||
wdt_reset(); | |||
usbPoll(); | |||
host_vusb_keyboard_send(); | |||
DEBUGP(0x02); | |||
keyboard_proc(); | |||
DEBUGP(0x03); | |||
/* | |||
matrix_scan(); | |||
fn_bits = 0; | |||
host_swap_keyboard_report(); | |||
host_clear_keyboard_report(); | |||
mousekey_clear_report(); | |||
for (int row = 0; row < matrix_rows(); row++) { | |||
for (int col = 0; col < matrix_cols(); col++) { | |||
if (!matrix_is_on(row, col)) continue; | |||
uint8_t code = layer_get_keycode(row, col); | |||
if (code == KB_NO) { | |||
// do nothing | |||
} | |||
else if (IS_MOD(code)) { | |||
host_add_mod_bit(MOD_BIT(code)); | |||
} | |||
else if (IS_KEY(code)) { | |||
host_add_key(code); | |||
} | |||
else if (IS_FN(code)) { | |||
fn_bits |= FN_BIT(code); | |||
} | |||
else if (IS_MOUSEKEY(code)) { | |||
mousekey_decode(code); | |||
} | |||
else { | |||
debug("ignore keycode: "); debug_hex(code); debug("\n"); | |||
} | |||
} | |||
} | |||
DEBUGP(0x03); | |||
layer_switching(fn_bits); | |||
if (matrix_is_modified()) { | |||
host_send_keyboard_report(); | |||
} | |||
mousekey_send(); | |||
if (last_led != host_keyboard_led()) { | |||
led_set(host_keyboard_led()); | |||
last_led = host_keyboard_led(); | |||
} | |||
*/ | |||
host_vusb_keyboard_send(); | |||
} | |||
} |
@@ -258,33 +258,6 @@ PROGMEM uchar keyboard_hid_report[] = { | |||
*/ | |||
PROGMEM uchar mouse_hid_report[] = { | |||
/* from HID 1.11 spec example */ | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x02, // Usage (Mouse), | |||
0xA1, 0x01, // Collection (Application), | |||
0x09, 0x01, // Usage (Pointer), | |||
0xA1, 0x00, // Collection (Physical), | |||
0x05, 0x09, // Usage Page (Buttons), | |||
0x19, 0x01, // Usage Minimum (01), | |||
0x29, 0x03, // Usage Maximun (03), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x95, 0x03, // Report Count (3), | |||
0x75, 0x01, // Report Size (1), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), ;3 button bits | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x05, // Report Size (5), | |||
0x81, 0x01, // Input (Constant), ;5 bit padding | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x30, // Usage (X), | |||
0x09, 0x31, // Usage (Y), | |||
0x15, 0x81, // Logical Minimum (-127), | |||
0x25, 0x7F, // Logical Maximum (127), | |||
0x75, 0x08, // Report Size (8), | |||
0x95, 0x02, // Report Count (2), | |||
0x81, 0x06, // Input (Data, Variable, Relative), ;2 position bytes (X & Y) | |||
0xC0, // End Collection, | |||
0xC0, // End Collection | |||
/* | |||
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |||
0x09, 0x02, // USAGE (Mouse) | |||
0xa1, 0x01, // COLLECTION (Application) | |||
@@ -355,7 +328,6 @@ PROGMEM uchar mouse_hid_report[] = { | |||
0xc0, // END_COLLECTION | |||
0xc0, // END_COLLECTION | |||
0xc0 // END_COLLECTION | |||
*/ | |||
}; | |||