a500kbd
diff src/amigakb.c @ 2:a4fd9c5a6655
first working version
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 17 Oct 2017 15:25:33 +0300 |
parents | |
children | 31a1f0b53d98 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/amigakb.c Tue Oct 17 15:25:33 2017 +0300 1.3 @@ -0,0 +1,124 @@ 1.4 +#include <stdio.h> 1.5 +#include <avr/io.h> 1.6 +#include <avr/interrupt.h> 1.7 +#include <util/delay.h> 1.8 +#include "amigakb.h" 1.9 +#include "defs.h" 1.10 +#include "timer.h" 1.11 + 1.12 +#define TIMEOUT_MSEC 143 1.13 + 1.14 +static void resync(void); 1.15 + 1.16 +void amikb_sendkey(unsigned char keycode, int press) 1.17 +{ 1.18 + int i; 1.19 + static unsigned char prev_keycode = 0xff; 1.20 + 1.21 + /* keycode bit transfer order: 6 5 4 3 2 1 0 7 (7 is pressed flag) */ 1.22 + keycode = (keycode << 1) | (~press & 1); 1.23 + if(keycode == prev_keycode) return; 1.24 + prev_keycode = keycode; 1.25 + 1.26 + /* make sure we don't pulse the lines while grabbing control 1.27 + * by first reinstating the pullups before changing direction 1.28 + */ 1.29 + PORTD |= ACLK_BIT | ADATA_BIT; 1.30 + DDRD |= ACLK_BIT | ADATA_BIT; 1.31 + 1.32 + /* pulse the data line and wait for about 100us */ 1.33 + PORTD &= ~ADATA_BIT; 1.34 + _delay_us(20); 1.35 + PORTD |= ADATA_BIT; 1.36 + _delay_us(100); 1.37 + 1.38 + for(i=0; i<8; i++) { 1.39 + /* data line is inverted */ 1.40 + if(keycode & 0x80) { 1.41 + PORTD &= ~ADATA_BIT; 1.42 + } else { 1.43 + PORTD |= ADATA_BIT; 1.44 + } 1.45 + keycode <<= 1; 1.46 + _delay_us(20); 1.47 + /* pulse the clock */ 1.48 + cli(); 1.49 + PORTD &= ~ACLK_BIT; 1.50 + EIFR |= (1 << INTF1); 1.51 + sei(); 1.52 + _delay_us(20); 1.53 + PORTD |= ACLK_BIT; 1.54 + _delay_us(20); 1.55 + } 1.56 + 1.57 + /* similarly tristate first, then drop the pullups */ 1.58 + DDRD &= ~(ACLK_BIT | ADATA_BIT); 1.59 + PORTD &= ~(ACLK_BIT | ADATA_BIT); 1.60 + 1.61 + /* wait for ack */ 1.62 + reset_timer(); 1.63 + while(PIND & ADATA_BIT) { 1.64 + if(get_msec() >= TIMEOUT_MSEC) { 1.65 + resync(); 1.66 + break; 1.67 + } 1.68 + } 1.69 +} 1.70 + 1.71 +void amikb_reset(void) 1.72 +{ 1.73 + cli(); 1.74 + PORTD &= ~ARST_BIT; 1.75 + DDRD |= ARST_BIT; 1.76 + _delay_ms(10); 1.77 + PORTD |= ARST_BIT; 1.78 + DDRD &= ~ARST_BIT; 1.79 + sei(); 1.80 +} 1.81 + 1.82 +static void resync(void) 1.83 +{ 1.84 + PORTD |= ACLK_BIT | ADATA_BIT; 1.85 + printf("lost sync\r\n"); 1.86 + 1.87 + for(;;) { 1.88 + cli(); 1.89 + DDRD |= ACLK_BIT | ADATA_BIT; 1.90 + 1.91 + PORTD &= ~ACLK_BIT; 1.92 + EIFR |= (1 << INTF1); /* clear interrupt raised by the previous line */ 1.93 + sei(); 1.94 + _delay_us(20); 1.95 + PORTD |= ACLK_BIT; 1.96 + 1.97 + DDRD &= ~(ACLK_BIT | ADATA_BIT); 1.98 + 1.99 + reset_timer(); 1.100 + while(get_msec() < TIMEOUT_MSEC) { 1.101 + if(!(PIND & ADATA_BIT)) { 1.102 + return; 1.103 + } 1.104 + } 1.105 + } 1.106 +} 1.107 + 1.108 +static void handle_cmd(unsigned char cmd) 1.109 +{ 1.110 + printf("amikbd got cmd: %x\r\n", (unsigned int)cmd); 1.111 +} 1.112 + 1.113 +ISR(INT1_vect) 1.114 +{ 1.115 + static unsigned char value; 1.116 + static int nbits; 1.117 + 1.118 + value <<= 1; 1.119 + if(PIND & ADATA_BIT) { 1.120 + value |= 1; 1.121 + } 1.122 + if(++nbits >= 8) { 1.123 + handle_cmd(value); 1.124 + nbits = 0; 1.125 + value = 0; 1.126 + } 1.127 +}