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