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 }