aboutsummaryrefslogtreecommitdiff
path: root/quantum/split_common/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/split_common/serial.c')
-rw-r--r--quantum/split_common/serial.c742
1 files changed, 355 insertions, 387 deletions
diff --git a/quantum/split_common/serial.c b/quantum/split_common/serial.c
index 322ab8030..c4ef2a97e 100644
--- a/quantum/split_common/serial.c
+++ b/quantum/split_common/serial.c
@@ -8,7 +8,7 @@
8 */ 8 */
9 9
10#ifndef F_CPU 10#ifndef F_CPU
11#define F_CPU 16000000 11# define F_CPU 16000000
12#endif 12#endif
13 13
14#include <avr/io.h> 14#include <avr/io.h>
@@ -21,252 +21,224 @@
21 21
22#ifdef SOFT_SERIAL_PIN 22#ifdef SOFT_SERIAL_PIN
23 23
24#ifdef __AVR_ATmega32U4__ 24# ifdef __AVR_ATmega32U4__
25 // if using ATmega32U4 I2C, can not use PD0 and PD1 in soft serial. 25// if using ATmega32U4 I2C, can not use PD0 and PD1 in soft serial.
26 #ifdef USE_AVR_I2C 26# ifdef USE_AVR_I2C
27 #if SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1 27# if SOFT_SERIAL_PIN == D0 || SOFT_SERIAL_PIN == D1
28 #error Using ATmega32U4 I2C, so can not use PD0, PD1 28# error Using ATmega32U4 I2C, so can not use PD0, PD1
29 #endif 29# endif
30 #endif 30# endif
31 31
32 #define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin) & 0xF), \ 32# define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
33 PORTx_ADDRESS(pin) |= _BV((pin) & 0xF)) 33# define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
34 #define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin) & 0xF)) 34# define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
35 #define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin) & 0xF)) 35# define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
36 #define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin) & 0xF)) 36# define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
37 #define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin) & 0xF))) 37
38 38# if SOFT_SERIAL_PIN >= D0 && SOFT_SERIAL_PIN <= D3
39 #if SOFT_SERIAL_PIN >= D0 && SOFT_SERIAL_PIN <= D3 39# if SOFT_SERIAL_PIN == D0
40 #if SOFT_SERIAL_PIN == D0 40# define EIMSK_BIT _BV(INT0)
41 #define EIMSK_BIT _BV(INT0) 41# define EICRx_BIT (~(_BV(ISC00) | _BV(ISC01)))
42 #define EICRx_BIT (~(_BV(ISC00) | _BV(ISC01))) 42# define SERIAL_PIN_INTERRUPT INT0_vect
43 #define SERIAL_PIN_INTERRUPT INT0_vect 43# elif SOFT_SERIAL_PIN == D1
44 #elif SOFT_SERIAL_PIN == D1 44# define EIMSK_BIT _BV(INT1)
45 #define EIMSK_BIT _BV(INT1) 45# define EICRx_BIT (~(_BV(ISC10) | _BV(ISC11)))
46 #define EICRx_BIT (~(_BV(ISC10) | _BV(ISC11))) 46# define SERIAL_PIN_INTERRUPT INT1_vect
47 #define SERIAL_PIN_INTERRUPT INT1_vect 47# elif SOFT_SERIAL_PIN == D2
48 #elif SOFT_SERIAL_PIN == D2 48# define EIMSK_BIT _BV(INT2)
49 #define EIMSK_BIT _BV(INT2) 49# define EICRx_BIT (~(_BV(ISC20) | _BV(ISC21)))
50 #define EICRx_BIT (~(_BV(ISC20) | _BV(ISC21))) 50# define SERIAL_PIN_INTERRUPT INT2_vect
51 #define SERIAL_PIN_INTERRUPT INT2_vect 51# elif SOFT_SERIAL_PIN == D3
52 #elif SOFT_SERIAL_PIN == D3 52# define EIMSK_BIT _BV(INT3)
53 #define EIMSK_BIT _BV(INT3) 53# define EICRx_BIT (~(_BV(ISC30) | _BV(ISC31)))
54 #define EICRx_BIT (~(_BV(ISC30) | _BV(ISC31))) 54# define SERIAL_PIN_INTERRUPT INT3_vect
55 #define SERIAL_PIN_INTERRUPT INT3_vect 55# endif
56 #endif 56# elif SOFT_SERIAL_PIN == E6
57 #elif SOFT_SERIAL_PIN == E6 57# define EIMSK_BIT _BV(INT6)
58 #define EIMSK_BIT _BV(INT6) 58# define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61)))
59 #define EICRx_BIT (~(_BV(ISC60) | _BV(ISC61))) 59# define SERIAL_PIN_INTERRUPT INT6_vect
60 #define SERIAL_PIN_INTERRUPT INT6_vect 60# else
61 #else 61# error invalid SOFT_SERIAL_PIN value
62 #error invalid SOFT_SERIAL_PIN value 62# endif
63 #endif 63
64 64# else
65#else 65# error serial.c now support ATmega32U4 only
66 #error serial.c now support ATmega32U4 only 66# endif
67#endif 67
68 68# define ALWAYS_INLINE __attribute__((always_inline))
69#define ALWAYS_INLINE __attribute__((always_inline)) 69# define NO_INLINE __attribute__((noinline))
70#define NO_INLINE __attribute__((noinline)) 70# define _delay_sub_us(x) __builtin_avr_delay_cycles(x)
71#define _delay_sub_us(x) __builtin_avr_delay_cycles(x)
72 71
73// parity check 72// parity check
74#define ODD_PARITY 1 73# define ODD_PARITY 1
75#define EVEN_PARITY 0 74# define EVEN_PARITY 0
76#define PARITY EVEN_PARITY 75# define PARITY EVEN_PARITY
77 76
78#ifdef SERIAL_DELAY 77# ifdef SERIAL_DELAY
79 // custom setup in config.h 78// custom setup in config.h
80 // #define TID_SEND_ADJUST 2 79// #define TID_SEND_ADJUST 2
81 // #define SERIAL_DELAY 6 // micro sec 80// #define SERIAL_DELAY 6 // micro sec
82 // #define READ_WRITE_START_ADJUST 30 // cycles 81// #define READ_WRITE_START_ADJUST 30 // cycles
83 // #define READ_WRITE_WIDTH_ADJUST 8 // cycles 82// #define READ_WRITE_WIDTH_ADJUST 8 // cycles
84#else 83# else
85// ============ Standard setups ============ 84// ============ Standard setups ============
86 85
87#ifndef SELECT_SOFT_SERIAL_SPEED 86# ifndef SELECT_SOFT_SERIAL_SPEED
88#define SELECT_SOFT_SERIAL_SPEED 1 87# define SELECT_SOFT_SERIAL_SPEED 1
89// 0: about 189kbps (Experimental only) 88// 0: about 189kbps (Experimental only)
90// 1: about 137kbps (default) 89// 1: about 137kbps (default)
91// 2: about 75kbps 90// 2: about 75kbps
92// 3: about 39kbps 91// 3: about 39kbps
93// 4: about 26kbps 92// 4: about 26kbps
94// 5: about 20kbps 93// 5: about 20kbps
95#endif 94# endif
96 95
97#if __GNUC__ < 6 96# if __GNUC__ < 6
98 #define TID_SEND_ADJUST 14 97# define TID_SEND_ADJUST 14
99#else 98# else
100 #define TID_SEND_ADJUST 2 99# define TID_SEND_ADJUST 2
101#endif 100# endif
102 101
103#if SELECT_SOFT_SERIAL_SPEED == 0 102# if SELECT_SOFT_SERIAL_SPEED == 0
104 // Very High speed 103// Very High speed
105 #define SERIAL_DELAY 4 // micro sec 104# define SERIAL_DELAY 4 // micro sec
106 #if __GNUC__ < 6 105# if __GNUC__ < 6
107 #define READ_WRITE_START_ADJUST 33 // cycles 106# define READ_WRITE_START_ADJUST 33 // cycles
108 #define READ_WRITE_WIDTH_ADJUST 3 // cycles 107# define READ_WRITE_WIDTH_ADJUST 3 // cycles
109 #else 108# else
110 #define READ_WRITE_START_ADJUST 34 // cycles 109# define READ_WRITE_START_ADJUST 34 // cycles
111 #define READ_WRITE_WIDTH_ADJUST 7 // cycles 110# define READ_WRITE_WIDTH_ADJUST 7 // cycles
112 #endif 111# endif
113#elif SELECT_SOFT_SERIAL_SPEED == 1 112# elif SELECT_SOFT_SERIAL_SPEED == 1
114 // High speed 113// High speed
115 #define SERIAL_DELAY 6 // micro sec 114# define SERIAL_DELAY 6 // micro sec
116 #if __GNUC__ < 6 115# if __GNUC__ < 6
117 #define READ_WRITE_START_ADJUST 30 // cycles 116# define READ_WRITE_START_ADJUST 30 // cycles
118 #define READ_WRITE_WIDTH_ADJUST 3 // cycles 117# define READ_WRITE_WIDTH_ADJUST 3 // cycles
119 #else 118# else
120 #define READ_WRITE_START_ADJUST 33 // cycles 119# define READ_WRITE_START_ADJUST 33 // cycles
121 #define READ_WRITE_WIDTH_ADJUST 7 // cycles 120# define READ_WRITE_WIDTH_ADJUST 7 // cycles
122 #endif 121# endif
123#elif SELECT_SOFT_SERIAL_SPEED == 2 122# elif SELECT_SOFT_SERIAL_SPEED == 2
124 // Middle speed 123// Middle speed
125 #define SERIAL_DELAY 12 // micro sec 124# define SERIAL_DELAY 12 // micro sec
126 #define READ_WRITE_START_ADJUST 30 // cycles 125# define READ_WRITE_START_ADJUST 30 // cycles
127 #if __GNUC__ < 6 126# if __GNUC__ < 6
128 #define READ_WRITE_WIDTH_ADJUST 3 // cycles 127# define READ_WRITE_WIDTH_ADJUST 3 // cycles
129 #else 128# else
130 #define READ_WRITE_WIDTH_ADJUST 7 // cycles 129# define READ_WRITE_WIDTH_ADJUST 7 // cycles
131 #endif 130# endif
132#elif SELECT_SOFT_SERIAL_SPEED == 3 131# elif SELECT_SOFT_SERIAL_SPEED == 3
133 // Low speed 132// Low speed
134 #define SERIAL_DELAY 24 // micro sec 133# define SERIAL_DELAY 24 // micro sec
135 #define READ_WRITE_START_ADJUST 30 // cycles 134# define READ_WRITE_START_ADJUST 30 // cycles
136 #if __GNUC__ < 6 135# if __GNUC__ < 6
137 #define READ_WRITE_WIDTH_ADJUST 3 // cycles 136# define READ_WRITE_WIDTH_ADJUST 3 // cycles
138 #else 137# else
139 #define READ_WRITE_WIDTH_ADJUST 7 // cycles 138# define READ_WRITE_WIDTH_ADJUST 7 // cycles
140 #endif 139# endif
141#elif SELECT_SOFT_SERIAL_SPEED == 4 140# elif SELECT_SOFT_SERIAL_SPEED == 4
142 // Very Low speed 141// Very Low speed
143 #define SERIAL_DELAY 36 // micro sec 142# define SERIAL_DELAY 36 // micro sec
144 #define READ_WRITE_START_ADJUST 30 // cycles 143# define READ_WRITE_START_ADJUST 30 // cycles
145 #if __GNUC__ < 6 144# if __GNUC__ < 6
146 #define READ_WRITE_WIDTH_ADJUST 3 // cycles 145# define READ_WRITE_WIDTH_ADJUST 3 // cycles
147 #else 146# else
148 #define READ_WRITE_WIDTH_ADJUST 7 // cycles 147# define READ_WRITE_WIDTH_ADJUST 7 // cycles
149 #endif 148# endif
150#elif SELECT_SOFT_SERIAL_SPEED == 5 149# elif SELECT_SOFT_SERIAL_SPEED == 5
151 // Ultra Low speed 150// Ultra Low speed
152 #define SERIAL_DELAY 48 // micro sec 151# define SERIAL_DELAY 48 // micro sec
153 #define READ_WRITE_START_ADJUST 30 // cycles 152# define READ_WRITE_START_ADJUST 30 // cycles
154 #if __GNUC__ < 6 153# if __GNUC__ < 6
155 #define READ_WRITE_WIDTH_ADJUST 3 // cycles 154# define READ_WRITE_WIDTH_ADJUST 3 // cycles
156 #else 155# else
157 #define READ_WRITE_WIDTH_ADJUST 7 // cycles 156# define READ_WRITE_WIDTH_ADJUST 7 // cycles
158 #endif 157# endif
159#else 158# else
160#error invalid SELECT_SOFT_SERIAL_SPEED value 159# error invalid SELECT_SOFT_SERIAL_SPEED value
161#endif /* SELECT_SOFT_SERIAL_SPEED */ 160# endif /* SELECT_SOFT_SERIAL_SPEED */
162#endif /* SERIAL_DELAY */ 161# endif /* SERIAL_DELAY */
163 162
164#define SERIAL_DELAY_HALF1 (SERIAL_DELAY/2) 163# define SERIAL_DELAY_HALF1 (SERIAL_DELAY / 2)
165#define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY/2) 164# define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY / 2)
166 165
167#define SLAVE_INT_WIDTH_US 1 166# define SLAVE_INT_WIDTH_US 1
168#ifndef SERIAL_USE_MULTI_TRANSACTION 167# ifndef SERIAL_USE_MULTI_TRANSACTION
169 #define SLAVE_INT_RESPONSE_TIME SERIAL_DELAY 168# define SLAVE_INT_RESPONSE_TIME SERIAL_DELAY
170#else 169# else
171 #define SLAVE_INT_ACK_WIDTH_UNIT 2 170# define SLAVE_INT_ACK_WIDTH_UNIT 2
172 #define SLAVE_INT_ACK_WIDTH 4 171# define SLAVE_INT_ACK_WIDTH 4
173#endif 172# endif
174 173
175static SSTD_t *Transaction_table = NULL; 174static SSTD_t *Transaction_table = NULL;
176static uint8_t Transaction_table_size = 0; 175static uint8_t Transaction_table_size = 0;
177 176
178inline static void serial_delay(void) ALWAYS_INLINE; 177inline static void serial_delay(void) ALWAYS_INLINE;
179inline static 178inline static void serial_delay(void) { _delay_us(SERIAL_DELAY); }
180void serial_delay(void) {
181 _delay_us(SERIAL_DELAY);
182}
183 179
184inline static void serial_delay_half1(void) ALWAYS_INLINE; 180inline static void serial_delay_half1(void) ALWAYS_INLINE;
185inline static 181inline static void serial_delay_half1(void) { _delay_us(SERIAL_DELAY_HALF1); }
186void serial_delay_half1(void) {
187 _delay_us(SERIAL_DELAY_HALF1);
188}
189 182
190inline static void serial_delay_half2(void) ALWAYS_INLINE; 183inline static void serial_delay_half2(void) ALWAYS_INLINE;
191inline static 184inline static void serial_delay_half2(void) { _delay_us(SERIAL_DELAY_HALF2); }
192void serial_delay_half2(void) {
193 _delay_us(SERIAL_DELAY_HALF2);
194}
195 185
196inline static void serial_output(void) ALWAYS_INLINE; 186inline static void serial_output(void) ALWAYS_INLINE;
197inline static 187inline static void serial_output(void) { setPinOutput(SOFT_SERIAL_PIN); }
198void serial_output(void) {
199 setPinOutput(SOFT_SERIAL_PIN);
200}
201 188
202// make the serial pin an input with pull-up resistor 189// make the serial pin an input with pull-up resistor
203inline static void serial_input_with_pullup(void) ALWAYS_INLINE; 190inline static void serial_input_with_pullup(void) ALWAYS_INLINE;
204inline static 191inline static void serial_input_with_pullup(void) { setPinInputHigh(SOFT_SERIAL_PIN); }
205void serial_input_with_pullup(void) {
206 setPinInputHigh(SOFT_SERIAL_PIN);
207}
208 192
209inline static uint8_t serial_read_pin(void) ALWAYS_INLINE; 193inline static uint8_t serial_read_pin(void) ALWAYS_INLINE;
210inline static 194inline static uint8_t serial_read_pin(void) { return !!readPin(SOFT_SERIAL_PIN); }
211uint8_t serial_read_pin(void) {
212 return !! readPin(SOFT_SERIAL_PIN);
213}
214 195
215inline static void serial_low(void) ALWAYS_INLINE; 196inline static void serial_low(void) ALWAYS_INLINE;
216inline static 197inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
217void serial_low(void) {
218 writePinLow(SOFT_SERIAL_PIN);
219}
220 198
221inline static void serial_high(void) ALWAYS_INLINE; 199inline static void serial_high(void) ALWAYS_INLINE;
222inline static 200inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
223void serial_high(void) {
224 writePinHigh(SOFT_SERIAL_PIN);
225}
226 201
227void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size) 202void soft_serial_initiator_init(SSTD_t *sstd_table, int sstd_table_size) {
228{ 203 Transaction_table = sstd_table;
229 Transaction_table = sstd_table;
230 Transaction_table_size = (uint8_t)sstd_table_size; 204 Transaction_table_size = (uint8_t)sstd_table_size;
231 serial_output(); 205 serial_output();
232 serial_high(); 206 serial_high();
233} 207}
234 208
235void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) 209void soft_serial_target_init(SSTD_t *sstd_table, int sstd_table_size) {
236{ 210 Transaction_table = sstd_table;
237 Transaction_table = sstd_table;
238 Transaction_table_size = (uint8_t)sstd_table_size; 211 Transaction_table_size = (uint8_t)sstd_table_size;
239 serial_input_with_pullup(); 212 serial_input_with_pullup();
240 213
241 // Enable INT0-INT3,INT6 214 // Enable INT0-INT3,INT6
242 EIMSK |= EIMSK_BIT; 215 EIMSK |= EIMSK_BIT;
243#if SOFT_SERIAL_PIN == E6 216# if SOFT_SERIAL_PIN == E6
244 // Trigger on falling edge of INT6 217 // Trigger on falling edge of INT6
245 EICRB &= EICRx_BIT; 218 EICRB &= EICRx_BIT;
246#else 219# else
247 // Trigger on falling edge of INT0-INT3 220 // Trigger on falling edge of INT0-INT3
248 EICRA &= EICRx_BIT; 221 EICRA &= EICRx_BIT;
249#endif 222# endif
250} 223}
251 224
252// Used by the sender to synchronize timing with the reciver. 225// Used by the sender to synchronize timing with the reciver.
253static void sync_recv(void) NO_INLINE; 226static void sync_recv(void) NO_INLINE;
254static 227static void sync_recv(void) {
255void sync_recv(void) { 228 for (uint8_t i = 0; i < SERIAL_DELAY * 5 && serial_read_pin(); i++) {
256 for (uint8_t i = 0; i < SERIAL_DELAY*5 && serial_read_pin(); i++ ) { 229 }
257 } 230 // This shouldn't hang if the target disconnects because the
258 // This shouldn't hang if the target disconnects because the 231 // serial line will float to high if the target does disconnect.
259 // serial line will float to high if the target does disconnect. 232 while (!serial_read_pin())
260 while (!serial_read_pin()); 233 ;
261} 234}
262 235
263// Used by the reciver to send a synchronization signal to the sender. 236// Used by the reciver to send a synchronization signal to the sender.
264static void sync_send(void) NO_INLINE; 237static void sync_send(void) NO_INLINE;
265static 238static void sync_send(void) {
266void sync_send(void) { 239 serial_low();
267 serial_low(); 240 serial_delay();
268 serial_delay(); 241 serial_high();
269 serial_high();
270} 242}
271 243
272// Reads a byte from the serial line 244// Reads a byte from the serial line
@@ -274,92 +246,94 @@ static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) NO_INLINE;
274static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) { 246static uint8_t serial_read_chunk(uint8_t *pterrcount, uint8_t bit) {
275 uint8_t byte, i, p, pb; 247 uint8_t byte, i, p, pb;
276 248
277 _delay_sub_us(READ_WRITE_START_ADJUST); 249 _delay_sub_us(READ_WRITE_START_ADJUST);
278 for( i = 0, byte = 0, p = PARITY; i < bit; i++ ) { 250 for (i = 0, byte = 0, p = PARITY; i < bit; i++) {
279 serial_delay_half1(); // read the middle of pulses 251 serial_delay_half1(); // read the middle of pulses
280 if( serial_read_pin() ) { 252 if (serial_read_pin()) {
281 byte = (byte << 1) | 1; p ^= 1; 253 byte = (byte << 1) | 1;
282 } else { 254 p ^= 1;
283 byte = (byte << 1) | 0; p ^= 0; 255 } else {
284 } 256 byte = (byte << 1) | 0;
285 _delay_sub_us(READ_WRITE_WIDTH_ADJUST); 257 p ^= 0;
286 serial_delay_half2(); 258 }
287 } 259 _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
288 /* recive parity bit */ 260 serial_delay_half2();
289 serial_delay_half1(); // read the middle of pulses 261 }
290 pb = serial_read_pin(); 262 /* recive parity bit */
291 _delay_sub_us(READ_WRITE_WIDTH_ADJUST); 263 serial_delay_half1(); // read the middle of pulses
292 serial_delay_half2(); 264 pb = serial_read_pin();
293 265 _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
294 *pterrcount += (p != pb)? 1 : 0; 266 serial_delay_half2();
295 267
296 return byte; 268 *pterrcount += (p != pb) ? 1 : 0;
269
270 return byte;
297} 271}
298 272
299// Sends a byte with MSB ordering 273// Sends a byte with MSB ordering
300void serial_write_chunk(uint8_t data, uint8_t bit) NO_INLINE; 274void serial_write_chunk(uint8_t data, uint8_t bit) NO_INLINE;
301void serial_write_chunk(uint8_t data, uint8_t bit) { 275void serial_write_chunk(uint8_t data, uint8_t bit) {
302 uint8_t b, p; 276 uint8_t b, p;
303 for( p = PARITY, b = 1<<(bit-1); b ; b >>= 1) { 277 for (p = PARITY, b = 1 << (bit - 1); b; b >>= 1) {
304 if(data & b) { 278 if (data & b) {
305 serial_high(); p ^= 1; 279 serial_high();
280 p ^= 1;
306 } else { 281 } else {
307 serial_low(); p ^= 0; 282 serial_low();
283 p ^= 0;
308 } 284 }
309 serial_delay(); 285 serial_delay();
310 } 286 }
311 /* send parity bit */ 287 /* send parity bit */
312 if(p & 1) { serial_high(); } 288 if (p & 1) {
313 else { serial_low(); } 289 serial_high();
290 } else {
291 serial_low();
292 }
314 serial_delay(); 293 serial_delay();
315 294
316 serial_low(); // sync_send() / senc_recv() need raise edge 295 serial_low(); // sync_send() / senc_recv() need raise edge
317} 296}
318 297
319static void serial_send_packet(uint8_t *buffer, uint8_t size) NO_INLINE; 298static void serial_send_packet(uint8_t *buffer, uint8_t size) NO_INLINE;
320static 299static void serial_send_packet(uint8_t *buffer, uint8_t size) {
321void serial_send_packet(uint8_t *buffer, uint8_t size) { 300 for (uint8_t i = 0; i < size; ++i) {
322 for (uint8_t i = 0; i < size; ++i) { 301 uint8_t data;
323 uint8_t data; 302 data = buffer[i];
324 data = buffer[i]; 303 sync_send();
325 sync_send(); 304 serial_write_chunk(data, 8);
326 serial_write_chunk(data,8); 305 }
327 }
328} 306}
329 307
330static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) NO_INLINE; 308static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) NO_INLINE;
331static 309static uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) {
332uint8_t serial_recive_packet(uint8_t *buffer, uint8_t size) { 310 uint8_t pecount = 0;
333 uint8_t pecount = 0; 311 for (uint8_t i = 0; i < size; ++i) {
334 for (uint8_t i = 0; i < size; ++i) { 312 uint8_t data;
335 uint8_t data; 313 sync_recv();
336 sync_recv(); 314 data = serial_read_chunk(&pecount, 8);
337 data = serial_read_chunk(&pecount, 8); 315 buffer[i] = data;
338 buffer[i] = data; 316 }
339 } 317 return pecount == 0;
340 return pecount == 0;
341} 318}
342 319
343inline static 320inline static void change_sender2reciver(void) {
344void change_sender2reciver(void) { 321 sync_send(); // 0
345 sync_send(); //0 322 serial_delay_half1(); // 1
346 serial_delay_half1(); //1 323 serial_low(); // 2
347 serial_low(); //2 324 serial_input_with_pullup(); // 2
348 serial_input_with_pullup(); //2 325 serial_delay_half1(); // 3
349 serial_delay_half1(); //3
350} 326}
351 327
352inline static 328inline static void change_reciver2sender(void) {
353void change_reciver2sender(void) { 329 sync_recv(); // 0
354 sync_recv(); //0 330 serial_delay(); // 1
355 serial_delay(); //1 331 serial_low(); // 3
356 serial_low(); //3 332 serial_output(); // 3
357 serial_output(); //3 333 serial_delay_half1(); // 4
358 serial_delay_half1(); //4
359} 334}
360 335
361static inline uint8_t nibble_bits_count(uint8_t bits) 336static inline uint8_t nibble_bits_count(uint8_t bits) {
362{
363 bits = (bits & 0x5) + (bits >> 1 & 0x5); 337 bits = (bits & 0x5) + (bits >> 1 & 0x5);
364 bits = (bits & 0x3) + (bits >> 2 & 0x3); 338 bits = (bits & 0x3) + (bits >> 2 & 0x3);
365 return bits; 339 return bits;
@@ -367,51 +341,47 @@ static inline uint8_t nibble_bits_count(uint8_t bits)
367 341
368// interrupt handle to be used by the target device 342// interrupt handle to be used by the target device
369ISR(SERIAL_PIN_INTERRUPT) { 343ISR(SERIAL_PIN_INTERRUPT) {
344# ifndef SERIAL_USE_MULTI_TRANSACTION
345 serial_low();
346 serial_output();
347 SSTD_t *trans = Transaction_table;
348# else
349 // recive transaction table index
350 uint8_t tid, bits;
351 uint8_t pecount = 0;
352 sync_recv();
353 bits = serial_read_chunk(&pecount, 7);
354 tid = bits >> 3;
355 bits = (bits & 7) != nibble_bits_count(tid);
356 if (bits || pecount > 0 || tid > Transaction_table_size) {
357 return;
358 }
359 serial_delay_half1();
370 360
371#ifndef SERIAL_USE_MULTI_TRANSACTION 361 serial_high(); // response step1 low->high
372 serial_low(); 362 serial_output();
373 serial_output(); 363 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT * SLAVE_INT_ACK_WIDTH);
374 SSTD_t *trans = Transaction_table; 364 SSTD_t *trans = &Transaction_table[tid];
375#else 365 serial_low(); // response step2 ack high->low
376 // recive transaction table index 366# endif
377 uint8_t tid, bits; 367
378 uint8_t pecount = 0; 368 // target send phase
379 sync_recv(); 369 if (trans->target2initiator_buffer_size > 0) serial_send_packet((uint8_t *)trans->target2initiator_buffer, trans->target2initiator_buffer_size);
380 bits = serial_read_chunk(&pecount,7); 370 // target switch to input
381 tid = bits>>3; 371 change_sender2reciver();
382 bits = (bits&7) != nibble_bits_count(tid); 372
383 if( bits || pecount> 0 || tid > Transaction_table_size ) { 373 // target recive phase
384 return; 374 if (trans->initiator2target_buffer_size > 0) {
385 } 375 if (serial_recive_packet((uint8_t *)trans->initiator2target_buffer, trans->initiator2target_buffer_size)) {
386 serial_delay_half1(); 376 *trans->status = TRANSACTION_ACCEPTED;
387 377 } else {
388 serial_high(); // response step1 low->high 378 *trans->status = TRANSACTION_DATA_ERROR;
389 serial_output(); 379 }
390 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT*SLAVE_INT_ACK_WIDTH); 380 } else {
391 SSTD_t *trans = &Transaction_table[tid]; 381 *trans->status = TRANSACTION_ACCEPTED;
392 serial_low(); // response step2 ack high->low 382 }
393#endif
394 383
395 // target send phase 384 sync_recv(); // weit initiator output to high
396 if( trans->target2initiator_buffer_size > 0 )
397 serial_send_packet((uint8_t *)trans->target2initiator_buffer,
398 trans->target2initiator_buffer_size);
399 // target switch to input
400 change_sender2reciver();
401
402 // target recive phase
403 if( trans->initiator2target_buffer_size > 0 ) {
404 if (serial_recive_packet((uint8_t *)trans->initiator2target_buffer,
405 trans->initiator2target_buffer_size) ) {
406 *trans->status = TRANSACTION_ACCEPTED;
407 } else {
408 *trans->status = TRANSACTION_DATA_ERROR;
409 }
410 } else {
411 *trans->status = TRANSACTION_ACCEPTED;
412 }
413
414 sync_recv(); //weit initiator output to high
415} 385}
416 386
417///////// 387/////////
@@ -424,105 +394,103 @@ ISR(SERIAL_PIN_INTERRUPT) {
424// TRANSACTION_NO_RESPONSE 394// TRANSACTION_NO_RESPONSE
425// TRANSACTION_DATA_ERROR 395// TRANSACTION_DATA_ERROR
426// this code is very time dependent, so we need to disable interrupts 396// this code is very time dependent, so we need to disable interrupts
427#ifndef SERIAL_USE_MULTI_TRANSACTION 397# ifndef SERIAL_USE_MULTI_TRANSACTION
428int soft_serial_transaction(void) { 398int soft_serial_transaction(void) {
429 SSTD_t *trans = Transaction_table; 399 SSTD_t *trans = Transaction_table;
430#else 400# else
431int soft_serial_transaction(int sstd_index) { 401int soft_serial_transaction(int sstd_index) {
432 if( sstd_index > Transaction_table_size ) 402 if (sstd_index > Transaction_table_size) return TRANSACTION_TYPE_ERROR;
433 return TRANSACTION_TYPE_ERROR; 403 SSTD_t *trans = &Transaction_table[sstd_index];
434 SSTD_t *trans = &Transaction_table[sstd_index]; 404# endif
435#endif 405 cli();
436 cli();
437 406
438 // signal to the target that we want to start a transaction 407 // signal to the target that we want to start a transaction
439 serial_output(); 408 serial_output();
440 serial_low(); 409 serial_low();
441 _delay_us(SLAVE_INT_WIDTH_US); 410 _delay_us(SLAVE_INT_WIDTH_US);
442 411
443#ifndef SERIAL_USE_MULTI_TRANSACTION 412# ifndef SERIAL_USE_MULTI_TRANSACTION
444 // wait for the target response 413 // wait for the target response
445 serial_input_with_pullup(); 414 serial_input_with_pullup();
446 _delay_us(SLAVE_INT_RESPONSE_TIME); 415 _delay_us(SLAVE_INT_RESPONSE_TIME);
416
417 // check if the target is present
418 if (serial_read_pin()) {
419 // target failed to pull the line low, assume not present
420 serial_output();
421 serial_high();
422 *trans->status = TRANSACTION_NO_RESPONSE;
423 sei();
424 return TRANSACTION_NO_RESPONSE;
425 }
447 426
448 // check if the target is present 427# else
449 if (serial_read_pin()) { 428 // send transaction table index
450 // target failed to pull the line low, assume not present 429 int tid = (sstd_index << 3) | (7 & nibble_bits_count(sstd_index));
451 serial_output(); 430 sync_send();
452 serial_high(); 431 _delay_sub_us(TID_SEND_ADJUST);
453 *trans->status = TRANSACTION_NO_RESPONSE; 432 serial_write_chunk(tid, 7);
454 sei(); 433 serial_delay_half1();
455 return TRANSACTION_NO_RESPONSE; 434
456 } 435 // wait for the target response (step1 low->high)
457 436 serial_input_with_pullup();
458#else 437 while (!serial_read_pin()) {
459 // send transaction table index 438 _delay_sub_us(2);
460 int tid = (sstd_index<<3) | (7 & nibble_bits_count(sstd_index)); 439 }
461 sync_send(); 440
462 _delay_sub_us(TID_SEND_ADJUST); 441 // check if the target is present (step2 high->low)
463 serial_write_chunk(tid, 7); 442 for (int i = 0; serial_read_pin(); i++) {
464 serial_delay_half1(); 443 if (i > SLAVE_INT_ACK_WIDTH + 1) {
465 444 // slave failed to pull the line low, assume not present
466 // wait for the target response (step1 low->high) 445 serial_output();
467 serial_input_with_pullup(); 446 serial_high();
468 while( !serial_read_pin() ) { 447 *trans->status = TRANSACTION_NO_RESPONSE;
469 _delay_sub_us(2); 448 sei();
470 } 449 return TRANSACTION_NO_RESPONSE;
471 450 }
472 // check if the target is present (step2 high->low) 451 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT);
473 for( int i = 0; serial_read_pin(); i++ ) { 452 }
474 if (i > SLAVE_INT_ACK_WIDTH + 1) { 453# endif
475 // slave failed to pull the line low, assume not present 454
476 serial_output(); 455 // initiator recive phase
477 serial_high(); 456 // if the target is present syncronize with it
478 *trans->status = TRANSACTION_NO_RESPONSE; 457 if (trans->target2initiator_buffer_size > 0) {
479 sei(); 458 if (!serial_recive_packet((uint8_t *)trans->target2initiator_buffer, trans->target2initiator_buffer_size)) {
480 return TRANSACTION_NO_RESPONSE; 459 serial_output();
481 } 460 serial_high();
482 _delay_sub_us(SLAVE_INT_ACK_WIDTH_UNIT); 461 *trans->status = TRANSACTION_DATA_ERROR;
483 } 462 sei();
484#endif 463 return TRANSACTION_DATA_ERROR;
464 }
465 }
466
467 // initiator switch to output
468 change_reciver2sender();
469
470 // initiator send phase
471 if (trans->initiator2target_buffer_size > 0) {
472 serial_send_packet((uint8_t *)trans->initiator2target_buffer, trans->initiator2target_buffer_size);
473 }
485 474
486 // initiator recive phase 475 // always, release the line when not in use
487 // if the target is present syncronize with it 476 sync_send();
488 if( trans->target2initiator_buffer_size > 0 ) { 477
489 if (!serial_recive_packet((uint8_t *)trans->target2initiator_buffer, 478 *trans->status = TRANSACTION_END;
490 trans->target2initiator_buffer_size) ) { 479 sei();
491 serial_output(); 480 return TRANSACTION_END;
492 serial_high();
493 *trans->status = TRANSACTION_DATA_ERROR;
494 sei();
495 return TRANSACTION_DATA_ERROR;
496 }
497 }
498
499 // initiator switch to output
500 change_reciver2sender();
501
502 // initiator send phase
503 if( trans->initiator2target_buffer_size > 0 ) {
504 serial_send_packet((uint8_t *)trans->initiator2target_buffer,
505 trans->initiator2target_buffer_size);
506 }
507
508 // always, release the line when not in use
509 sync_send();
510
511 *trans->status = TRANSACTION_END;
512 sei();
513 return TRANSACTION_END;
514} 481}
515 482
516#ifdef SERIAL_USE_MULTI_TRANSACTION 483# ifdef SERIAL_USE_MULTI_TRANSACTION
517int soft_serial_get_and_clean_status(int sstd_index) { 484int soft_serial_get_and_clean_status(int sstd_index) {
518 SSTD_t *trans = &Transaction_table[sstd_index]; 485 SSTD_t *trans = &Transaction_table[sstd_index];
519 cli(); 486 cli();
520 int retval = *trans->status; 487 int retval = *trans->status;
521 *trans->status = 0;; 488 *trans->status = 0;
489 ;
522 sei(); 490 sei();
523 return retval; 491 return retval;
524} 492}
525#endif 493# endif
526 494
527#endif 495#endif
528 496