-
Notifications
You must be signed in to change notification settings - Fork 9
/
ax25.cpp
148 lines (127 loc) · 3.54 KB
/
ax25.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
/*
* Copyright (C) 2014 by KC3ARY Rich Nash
*
* Module modified version of code from EA5HAV.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <WProgram.h>
#include "ax25.h"
#include "aprs.h"
// Module constants
// Module globals
static uint16_t crc;
static uint8_t ones_in_a_row;
static uint16_t packet_size; // size in bits of packets
static uint8_t *packet;
static unsigned int maxPacketSize; // bytes
// Module functions
static void update_crc(const uint8_t a_bit)
{
const uint16_t xor_int = crc ^ a_bit; // XOR lsb of CRC with the latest bit
crc >>= 1; // Shift 16-bit CRC one bit to the right
if (xor_int & 0x0001) { // If XOR result from above has lsb set
crc ^= 0x8408; // Shift 16-bit CRC one bit to the right
}
return;
}
// Exported functions
void ax25_send_bit(const uint8_t a_bit, const uint8_t bitStuff)
{
if (bitStuff)
update_crc(a_bit);
if (a_bit) {
packet[packet_size >> 3] |= (1 << (packet_size & 7));
packet_size++;
if (bitStuff && ++ones_in_a_row == 5) {
ax25_send_bit(0, 0);
ones_in_a_row = 0;
}
} else {
ones_in_a_row = 0;
packet[packet_size >> 3] &= ~(1 << (packet_size & 7));
packet_size++;
}
}
void ax25_send_byte(uint8_t a_byte)
{
uint8_t i = 0;
while (i++ < 8) {
ax25_send_bit(a_byte & 1, 1);
a_byte >>= 1;
}
}
void ax25_send_flag()
{
// Send 0x7e without bit stuffing
ax25_send_bit(0, 0);
for (int i = 0; i < 6; i++)
ax25_send_bit(1, 0);
ax25_send_bit(0, 0);
}
unsigned int ax25_getPacketSize()
{
return packet_size;
}
void ax25_send_string(const char * const string)
{
for (int i = 0; string[i]; i++) {
ax25_send_byte(string[i]);
}
}
void ax25_initBuffer(uint8_t *buf, const int bufSize)
{
packet = buf;
maxPacketSize = bufSize;
packet_size = 0;
ones_in_a_row = 0;
crc = 0xffff;
}
void ax25_send_header(const struct PathAddress * const paths, const uint16_t nPaths,
const uint16_t preambleFlags)
{
uint16_t i, j;
for (i = 0; i < preambleFlags; i++) {
ax25_send_flag();
}
for (i = 0; i < nPaths; i++) {
// Transmit callsign
for (j = 0; paths[i].callsign[j]; j++)
ax25_send_byte(paths[i].callsign[j] << 1);
// Transmit pad
for (; j < 6; j++)
ax25_send_byte(' ' << 1);
// Transmit SSID. Termination signaled with last bit = 1
if (i == nPaths - 1)
ax25_send_byte(('0' + paths[i].ssid) << 1 | 1);
else
ax25_send_byte(('0' + paths[i].ssid) << 1);
}
// Control field: 3 = APRS-UI frame
ax25_send_byte(0x03);
// Protocol ID: 0xf0 = no layer 3 data
ax25_send_byte(0xf0);
}
void ax25_send_footer()
{
// Save the crc so that it can be treated it atomically
uint16_t final_crc = crc;
// Send the CRC
ax25_send_byte(~(final_crc & 0xff));
final_crc >>= 8;
ax25_send_byte(~(final_crc & 0xff));
// Signal the end of frame
ax25_send_flag();
}