summaryrefslogtreecommitdiffstats
path: root/adb.c
blob: 6848fa652b1513cd015f064e164a43ab3616e39c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include <stdbool.h>
#include <util/delay.h>
#include <avr/io.h>
#include "adb.h"


static inline void data_lo(void);
static inline void data_hi(void);
static inline bool data_in(void);
#ifdef ADB_PSW_BIT
static inline void psw_lo(void);
static inline void psw_hi(void);
static inline bool psw_in(void);
#endif

static inline void attention(void);
static inline void place_bit0(void);
static inline void place_bit1(void);
static inline void send_byte(uint8_t data);
static inline bool read_bit(void);
static inline uint8_t read_byte(void);
static inline uint8_t wait_data_lo(uint8_t us);
static inline uint8_t wait_data_hi(uint8_t us);


void adb_host_init(void)
{
    data_hi();
#ifdef ADB_PSW_BIT
    psw_hi();
#endif
}

#ifdef ADB_PSW_BIT
bool adb_host_psw(void)
{
    return psw_in();
}
#endif

uint16_t adb_host_kbd_recv(void)
{
    uint16_t data = 0;
    attention();
    send_byte(0x2C);            // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00)
    place_bit0();               // Stopbit(0)
    if (!wait_data_lo(0xFF))    // Tlt/Stop to Start(140-260us)
        return 0;               // No data to send
    if (!read_bit())            // Startbit(1)
        return -2;
    data = read_byte();
    data = (data<<8) | read_byte();
    if (read_bit())             // Stopbit(0)
        return -3;
    return data;
}

// send state of LEDs
void adb_host_kbd_led(uint8_t led)
{
    attention();
    send_byte(0x2A);            // Addr:Keyboard(0010), Cmd:Listen(10), Register2(10)
    place_bit0();               // Stopbit(0)
    _delay_us(200);             // Tlt/Stop to Start
    place_bit1();               // Startbit(1)
    send_byte(0);               // send upper byte (not used)
    send_byte(led&0x07);        // send lower byte (bit2: ScrollLock, bit1: CapsLock, bit0: NumLock)
    place_bit0();               // Stopbit(0);
}


static inline void data_lo()
{
    ADB_DDR  |=  (1<<ADB_DATA_BIT);
    ADB_PORT &= ~(1<<ADB_DATA_BIT);
}
static inline void data_hi()
{
    ADB_PORT |=  (1<<ADB_DATA_BIT);
    ADB_DDR  &= ~(1<<ADB_DATA_BIT);
}
static inline bool data_in()
{
    ADB_PORT |=  (1<<ADB_DATA_BIT);
    ADB_DDR  &= ~(1<<ADB_DATA_BIT);
    return ADB_PIN&(1<<ADB_DATA_BIT);
}

#ifdef ADB_PSW_BIT
static inline void psw_lo()
{
    ADB_DDR  |=  (1<<ADB_PSW_BIT);
    ADB_PORT &= ~(1<<ADB_PSW_BIT);
}
static inline void psw_hi()
{
    ADB_PORT |=  (1<<ADB_PSW_BIT);
    ADB_DDR  &= ~(1<<ADB_PSW_BIT);
}
static inline bool psw_in()
{
    ADB_PORT |=  (1<<ADB_PSW_BIT);
    ADB_DDR  &= ~(1<<ADB_PSW_BIT);
    return ADB_PIN&(1<<ADB_PSW_BIT);
}
#endif

static inline void attention(void)
{
    data_lo();
    _delay_us(700);
    place_bit1();
}

static inline void place_bit0(void)
{
    data_lo();
    _delay_us(65);
    data_hi();
    _delay_us(35);
}

static inline void place_bit1(void)
{
    data_lo();
    _delay_us(35);
    data_hi();
    _delay_us(65);
}

static inline void send_byte(uint8_t data)
{
    for (int i = 0; i < 8; i++) {
        if (data&(0x80>>i))
            place_bit1();
        else
            place_bit0();
    }
}

static inline bool read_bit(void)
{
    // ADB Bit Cells
    //
    // bit0: ______~~~
    //       65    :35us
    //
    // bit1: ___~~~~~~
    //       35 :65us
    //
    // bit0 low time: 60-70% of bit cell(42-91us)
    // bit1 low time: 30-40% of bit cell(21-52us)
    // bit cell time: 70-130us
    // [from Apple IIgs Hardware Reference Second Edition]
    //
    // After 55us if data line is low/high then bit is 0/1.
    // Too simple to rely on?
    bool bit;
    wait_data_lo(75);   // wait the beginning of bit cell
    _delay_us(55);
    bit = data_in();
    wait_data_hi(36);   // wait high part of bit cell
    return bit;
}

static inline uint8_t read_byte(void)
{
    uint8_t data = 0;
    for (int i = 0; i < 8; i++) {
        data <<= 1;
        if (read_bit())
            data = data | 1;
    }
    return data;
}

static inline uint8_t wait_data_lo(uint8_t us)
{
    while (data_in() && us) {
        _delay_us(1);
        us--;
    }
    return us;
}

static inline uint8_t wait_data_hi(uint8_t us)
{
    while (!data_in() && us) {
        _delay_us(1);
        us--;
    }
    return us;
}