-
Notifications
You must be signed in to change notification settings - Fork 4
/
IO.cpp
283 lines (236 loc) · 6.49 KB
/
IO.cpp
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/*
* Copyright (C) 2015,2016,2017,2018,2020,2021,2023 by Jonathan Naylor G4KLX
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
* Copyright (C) 2016 by Colin Durbridge G4EML
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Config.h"
#include "Globals.h"
#include "IO.h"
const q15_t DC_OFFSET = 2048;
CIO::CIO() :
m_rxBuffer(RX_RINGBUFFER_SIZE),
m_txBuffer(TX_RINGBUFFER_SIZE),
m_rxLevel(RX_LEVEL * 128),
m_pPersist(P_PERSISTENCE),
m_slotTime((SLOT_TIME / 10U) * 240U),
m_dcd(false),
m_ledCount(0U),
m_ledValue(true),
m_slotCount(0U),
m_canTX(false),
m_x(1U),
m_a(0xB7U),
m_b(0x73U),
m_c(0xF6U)
{
}
void CIO::selfTest()
{
bool ledValue = false;
for (uint8_t i = 0U; i < 6U; i++) {
ledValue = !ledValue;
// We exclude PTT to avoid trigger the transmitter
setLEDInt(ledValue);
setCOSInt(ledValue);
#if defined(MODE_LEDS)
setMode1Int(ledValue);
setMode2Int(ledValue);
setMode3Int(ledValue);
setMode4Int(ledValue);
#endif
delayInt(250);
}
#if defined(MODE_LEDS)
setMode1Int(false);
setMode2Int(false);
setMode3Int(false);
setMode4Int(false);
setMode1Int(true);
delayInt(250);
setMode2Int(true);
delayInt(250);
setMode3Int(true);
delayInt(250);
setMode4Int(true);
delayInt(250);
setMode4Int(false);
delayInt(250);
setMode3Int(false);
delayInt(250);
setMode2Int(false);
delayInt(250);
setMode1Int(false);
#endif
}
void CIO::start()
{
initRand();
initInt();
selfTest();
startInt();
}
void CIO::process()
{
#if defined(CONSTANT_SRV_LED)
setLEDInt(true);
#else
if (m_ledCount >= 24000U) {
m_ledCount = 0U;
m_ledValue = !m_ledValue;
setLEDInt(m_ledValue);
}
#endif
// Switch off the transmitter if needed
if (m_txBuffer.getData() == 0U && m_tx) {
m_tx = false;
setPTTInt(false);
DEBUG1("TX OFF");
}
if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) {
// Only do the CSMA calculations when in simplex mode
if (!m_duplex) {
if (m_dcd) {
m_slotCount = 0U;
} else {
m_slotCount += RX_BLOCK_SIZE;
if (m_slotCount >= m_slotTime) {
m_slotCount = 0U;
m_canTX = (m_pPersist >= rand());
}
}
}
q15_t samples[RX_BLOCK_SIZE];
for (uint16_t i = 0U; i < RX_BLOCK_SIZE; i++) {
uint16_t sample;
m_rxBuffer.get(sample);
q15_t res1 = q15_t(sample) - DC_OFFSET;
q31_t res2 = res1 * m_rxLevel;
samples[i] = q15_t(__SSAT((res2 >> 15), 16));
}
switch (m_mode) {
case 1U:
ax25RX.samples(samples, RX_BLOCK_SIZE);
break;
case 2U:
mode2RX.samples(samples, RX_BLOCK_SIZE);
break;
default:
break;
}
}
}
void CIO::write(q15_t* samples, uint16_t length)
{
// Switch the transmitter on if needed
if (!m_tx) {
m_tx = true;
setPTTInt(true);
DEBUG1("TX ON");
}
for (uint16_t i = 0U; i < length; i++) {
uint16_t res = uint16_t(samples[i] + DC_OFFSET);
m_txBuffer.put(res);
}
}
void CIO::showMode()
{
#if defined(MODE_LEDS)
switch (m_mode) {
case 1U:
setMode1Int(true);
setMode2Int(false);
setMode3Int(false);
setMode4Int(false);
break;
case 2U:
setMode1Int(false);
setMode2Int(true);
setMode3Int(false);
setMode4Int(false);
break;
default:
setMode1Int(false);
setMode2Int(false);
setMode3Int(false);
setMode4Int(false);
break;
}
#endif
}
uint16_t CIO::getSpace() const
{
return m_txBuffer.getSpace();
}
void CIO::setDecode(bool dcd)
{
if (dcd != m_dcd)
setCOSInt(dcd);
m_dcd = dcd;
}
void CIO::setRXLevel(uint8_t value)
{
m_rxLevel = q15_t(value * 128);
}
void CIO::setPPersist(uint8_t value)
{
m_pPersist = value;
}
void CIO::setSlotTime(uint8_t value)
{
m_slotTime = value * 240U;
}
bool CIO::canTX() const
{
if (m_duplex)
return true;
if (m_dcd)
return false;
return m_canTX;
}
// Taken from https://www.electro-tech-online.com/threads/ultra-fast-pseudorandom-number-generator-for-8-bit.124249/
//X ABC Algorithm Random Number Generator for 8-Bit Devices:
//This is a small PRNG, experimentally verified to have at least a 50 million byte period
//by generating 50 million bytes and observing that there were no overapping sequences and repeats.
//This generator passes serial correlation, entropy , Monte Carlo Pi value, arithmetic mean,
//And many other statistical tests. This generator may have a period of up to 2^32, but this has
//not been verified.
//
// By XORing 3 bytes into the a,b, and c registers, you can add in entropy from
//an external source easily.
//
//This generator is free to use, but is not suitable for cryptography due to its short period(by //cryptographic standards) and simple construction. No attempt was made to make this generator
// suitable for cryptographic use.
//
//Due to the use of a constant counter, the generator should be resistant to latching up.
//A significant performance gain is had in that the x variable is only ever incremented.
//
//Only 4 bytes of ram are needed for the internal state, and generating a byte requires 3 XORs , //2 ADDs, one bit shift right , and one increment. Difficult or slow operations like multiply, etc
//were avoided for maximum speed on ultra low power devices.
void CIO::initRand() //Can also be used to seed the rng with more entropy during use.
{
m_a = (m_a ^ m_c ^ m_x);
m_b = (m_b + m_a);
m_c = (m_c + ((m_b >> 1) ^ m_a));
}
uint8_t CIO::rand()
{
m_x++; //x is incremented every round and is not affected by any other variable
m_a = (m_a ^ m_c ^ m_x); //note the mix of addition and XOR
m_b = (m_b + m_a); //And the use of very few instructions
m_c = (m_c + ((m_b >> 1) ^ m_a)); //the right shift is to ensure that high-order bits from b can affect
return uint8_t(m_c); //low order bits of other variables
}