a500kbd
annotate 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 |
rev | line source |
---|---|
nuclear@2 | 1 #include <stdio.h> |
nuclear@2 | 2 #include <avr/io.h> |
nuclear@2 | 3 #include <avr/interrupt.h> |
nuclear@2 | 4 #include <util/delay.h> |
nuclear@2 | 5 #include "amigakb.h" |
nuclear@2 | 6 #include "defs.h" |
nuclear@2 | 7 #include "timer.h" |
nuclear@2 | 8 |
nuclear@2 | 9 #define TIMEOUT_MSEC 143 |
nuclear@2 | 10 |
nuclear@2 | 11 static void resync(void); |
nuclear@2 | 12 |
nuclear@2 | 13 void amikb_sendkey(unsigned char keycode, int press) |
nuclear@2 | 14 { |
nuclear@2 | 15 int i; |
nuclear@2 | 16 static unsigned char prev_keycode = 0xff; |
nuclear@2 | 17 |
nuclear@2 | 18 /* keycode bit transfer order: 6 5 4 3 2 1 0 7 (7 is pressed flag) */ |
nuclear@2 | 19 keycode = (keycode << 1) | (~press & 1); |
nuclear@2 | 20 if(keycode == prev_keycode) return; |
nuclear@2 | 21 prev_keycode = keycode; |
nuclear@2 | 22 |
nuclear@2 | 23 /* make sure we don't pulse the lines while grabbing control |
nuclear@2 | 24 * by first reinstating the pullups before changing direction |
nuclear@2 | 25 */ |
nuclear@2 | 26 PORTD |= ACLK_BIT | ADATA_BIT; |
nuclear@2 | 27 DDRD |= ACLK_BIT | ADATA_BIT; |
nuclear@2 | 28 |
nuclear@2 | 29 /* pulse the data line and wait for about 100us */ |
nuclear@2 | 30 PORTD &= ~ADATA_BIT; |
nuclear@2 | 31 _delay_us(20); |
nuclear@2 | 32 PORTD |= ADATA_BIT; |
nuclear@2 | 33 _delay_us(100); |
nuclear@2 | 34 |
nuclear@2 | 35 for(i=0; i<8; i++) { |
nuclear@2 | 36 /* data line is inverted */ |
nuclear@2 | 37 if(keycode & 0x80) { |
nuclear@2 | 38 PORTD &= ~ADATA_BIT; |
nuclear@2 | 39 } else { |
nuclear@2 | 40 PORTD |= ADATA_BIT; |
nuclear@2 | 41 } |
nuclear@2 | 42 keycode <<= 1; |
nuclear@2 | 43 _delay_us(20); |
nuclear@2 | 44 /* pulse the clock */ |
nuclear@2 | 45 cli(); |
nuclear@2 | 46 PORTD &= ~ACLK_BIT; |
nuclear@2 | 47 EIFR |= (1 << INTF1); |
nuclear@2 | 48 sei(); |
nuclear@2 | 49 _delay_us(20); |
nuclear@2 | 50 PORTD |= ACLK_BIT; |
nuclear@2 | 51 _delay_us(20); |
nuclear@2 | 52 } |
nuclear@2 | 53 |
nuclear@2 | 54 /* similarly tristate first, then drop the pullups */ |
nuclear@2 | 55 DDRD &= ~(ACLK_BIT | ADATA_BIT); |
nuclear@2 | 56 PORTD &= ~(ACLK_BIT | ADATA_BIT); |
nuclear@2 | 57 |
nuclear@2 | 58 /* wait for ack */ |
nuclear@2 | 59 reset_timer(); |
nuclear@2 | 60 while(PIND & ADATA_BIT) { |
nuclear@2 | 61 if(get_msec() >= TIMEOUT_MSEC) { |
nuclear@2 | 62 resync(); |
nuclear@2 | 63 break; |
nuclear@2 | 64 } |
nuclear@2 | 65 } |
nuclear@2 | 66 } |
nuclear@2 | 67 |
nuclear@2 | 68 void amikb_reset(void) |
nuclear@2 | 69 { |
nuclear@2 | 70 cli(); |
nuclear@2 | 71 PORTD &= ~ARST_BIT; |
nuclear@2 | 72 DDRD |= ARST_BIT; |
nuclear@2 | 73 _delay_ms(10); |
nuclear@2 | 74 PORTD |= ARST_BIT; |
nuclear@2 | 75 DDRD &= ~ARST_BIT; |
nuclear@2 | 76 sei(); |
nuclear@2 | 77 } |
nuclear@2 | 78 |
nuclear@2 | 79 static void resync(void) |
nuclear@2 | 80 { |
nuclear@2 | 81 PORTD |= ACLK_BIT | ADATA_BIT; |
nuclear@2 | 82 printf("lost sync\r\n"); |
nuclear@2 | 83 |
nuclear@2 | 84 for(;;) { |
nuclear@2 | 85 cli(); |
nuclear@2 | 86 DDRD |= ACLK_BIT | ADATA_BIT; |
nuclear@2 | 87 |
nuclear@2 | 88 PORTD &= ~ACLK_BIT; |
nuclear@2 | 89 EIFR |= (1 << INTF1); /* clear interrupt raised by the previous line */ |
nuclear@2 | 90 sei(); |
nuclear@2 | 91 _delay_us(20); |
nuclear@2 | 92 PORTD |= ACLK_BIT; |
nuclear@2 | 93 |
nuclear@2 | 94 DDRD &= ~(ACLK_BIT | ADATA_BIT); |
nuclear@2 | 95 |
nuclear@2 | 96 reset_timer(); |
nuclear@2 | 97 while(get_msec() < TIMEOUT_MSEC) { |
nuclear@2 | 98 if(!(PIND & ADATA_BIT)) { |
nuclear@2 | 99 return; |
nuclear@2 | 100 } |
nuclear@2 | 101 } |
nuclear@2 | 102 } |
nuclear@2 | 103 } |
nuclear@2 | 104 |
nuclear@2 | 105 static void handle_cmd(unsigned char cmd) |
nuclear@2 | 106 { |
nuclear@2 | 107 printf("amikbd got cmd: %x\r\n", (unsigned int)cmd); |
nuclear@2 | 108 } |
nuclear@2 | 109 |
nuclear@2 | 110 ISR(INT1_vect) |
nuclear@2 | 111 { |
nuclear@2 | 112 static unsigned char value; |
nuclear@2 | 113 static int nbits; |
nuclear@2 | 114 |
nuclear@2 | 115 value <<= 1; |
nuclear@2 | 116 if(PIND & ADATA_BIT) { |
nuclear@2 | 117 value |= 1; |
nuclear@2 | 118 } |
nuclear@2 | 119 if(++nbits >= 8) { |
nuclear@2 | 120 handle_cmd(value); |
nuclear@2 | 121 nbits = 0; |
nuclear@2 | 122 value = 0; |
nuclear@2 | 123 } |
nuclear@2 | 124 } |