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 +}