-
Notifications
You must be signed in to change notification settings - Fork 6
/
passthrough.c
193 lines (153 loc) · 3.55 KB
/
passthrough.c
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
/*
* Passthrough between UART and an nRF24.
*
* Licensed under AGPLv3.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <string.h>
#include <avr/wdt.h>
#include "timer1.h"
#include "uart.h"
#define CE_DDR DDRC
#define CE_PORT PORTC
#define CSN_DDR DDRB
#define CSN_PORT PORTB
#define CE_PIN (1 << 1)
#define CSN_PIN (1 << 2)
#include "spi.h"
#include "nrf24.h"
#ifndef MAX_PKT_SIZE
# define MAX_PKT_SIZE 32
#endif
#define FIFO_MASK 255
static struct ring_buffer_s {
uint8_t data[FIFO_MASK + 1];
uint8_t start, len;
} tx_fifo;
static void handle_input(char ch) {
tx_fifo.data[(tx_fifo.start + tx_fifo.len ++) & FIFO_MASK] = ch;
}
#define min(a, b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
static uint8_t eeprom_read(uint16_t addr) {
while (EECR & (1 << EEPE));
EEAR = addr;
EECR |= 1 << EERE; /* Start eeprom read by writing EERE */
return EEDR;
}
void setup(void) {
uint8_t s = SREG;
uint8_t m = MCUCR;
uint8_t i, addrs[6];
wdt_disable();
serial_init();
timer_init();
spi_init();
nrf24_init();
sei();
/*
* Set our radio address and the remote end's radio address, read
* the addresses from EEPROM where they need to be saved first.
*/
for (i = 0; i < 6; i ++)
addrs[i] = eeprom_read(i);
nrf24_set_rx_addr(addrs + 0);
nrf24_set_tx_addr(addrs + 3);
/* Write something to say hello */
serial_write_str("SREG:");
serial_write_hex16(s);
serial_write_str(", MCUCR:");
serial_write_hex16(m);
serial_write_str(", our addr: ");
serial_write1(addrs[0]);
serial_write1(addrs[1]);
serial_write1(addrs[2]);
serial_write_eol();
nrf24_rx_mode();
serial_set_handler(handle_input);
}
void loop(void) {
static uint8_t tx_cnt; /* Consecutive Tx packets counter */
/*
* Note: all nrf24 calls are serialised in this function so as
* to avoid any concurrency issues.
*/
if (nrf24_rx_fifo_data()) {
uint8_t pkt_len, pkt_buf[32], i;
#ifdef SEQN
static uint8_t seqn = 0xff;
#endif
#ifdef FLASH_TOOL_MODE
flasher_rx_handle();
#endif
nrf24_rx_read(pkt_buf, &pkt_len);
#ifdef SEQN
if (pkt_buf[0] != seqn) {
seqn = pkt_buf[0];
for (i = 1; i < pkt_len; i ++)
serial_write1(pkt_buf[i]);
}
#else
for (i = 0; i < pkt_len; i ++)
serial_write1(pkt_buf[i]);
#endif
tx_cnt = 0;
}
if (tx_fifo.len) { /* .len access should be atomic */
uint8_t pkt_len, pkt_buf[MAX_PKT_SIZE], split;
#ifdef SEQN
static uint8_t seqn = 0x00;
uint8_t count = 128;
#define MAX_PLD_SIZE (MAX_PKT_SIZE - 1)
pkt_buf[0] = seqn ++;
#else
uint8_t count = 2;
#define MAX_PLD_SIZE MAX_PKT_SIZE
#endif
#ifdef FLASH_TOOL_MODE
flasher_tx_handle();
#endif
tx_cnt ++;
cli();
pkt_len = min(tx_fifo.len, MAX_PLD_SIZE);
sei();
/* HACK */
if (tx_cnt == 2 && MAX_PLD_SIZE > 2 && pkt_len == MAX_PLD_SIZE)
pkt_len = MAX_PLD_SIZE - 2;
else if (MAX_PLD_SIZE > 2 && tx_cnt == 3)
pkt_len = 1;
split = min(pkt_len,
(uint16_t) (~tx_fifo.start & FIFO_MASK) + 1);
#define START (MAX_PKT_SIZE - MAX_PLD_SIZE)
memcpy(pkt_buf + START, tx_fifo.data +
(tx_fifo.start & FIFO_MASK), split);
memcpy(pkt_buf + START + split, tx_fifo.data, pkt_len - split);
/*
* Or we could just do pkt_buf = tx_fifo.data + ...;
* pkt_len = split;
*/
cli();
tx_fifo.len -= pkt_len;
tx_fifo.start += pkt_len;
sei();
while (-- count) {
/* Don't flood the remote end with the comms */
my_delay(4);
nrf24_tx(pkt_buf, pkt_len + START);
if (!nrf24_tx_result_wait())
break;
}
}
}
int main(void) {
setup();
#ifdef FLASH_TOOL_MODE
flasher_setup();
#endif
for (;;)
loop();
return 0;
}