/
HdlcReceiver.java
140 lines (125 loc) · 3.6 KB
/
HdlcReceiver.java
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
package ru.r2cloud.jradio.blocks;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.r2cloud.jradio.ByteInput;
import ru.r2cloud.jradio.Context;
import ru.r2cloud.jradio.MessageInput;
import ru.r2cloud.jradio.crc.Crc16Ccitt;
public class HdlcReceiver implements MessageInput {
private static final Logger LOG = LoggerFactory.getLogger(HdlcReceiver.class);
// flag is 01111110. last bit is always discarded
private static final int FLAG_LENGTH = 7;
private static final int FCS_LENGTH = 2;
private final ByteInput input;
private final byte[] window;
private final boolean checksum;
private final int minBits;
private boolean foundStartFlag = false;
public HdlcReceiver(ByteInput input, int maxLengthBytes) {
this(input, maxLengthBytes, 0, true);
}
public HdlcReceiver(ByteInput input, int maxLengthBytes, int minBytes, boolean checksum) {
if (input.getContext().getSoftBits() == null || Boolean.TRUE.equals(input.getContext().getSoftBits())) {
throw new IllegalArgumentException("expected hard bits");
}
this.input = input;
this.window = new byte[((maxLengthBytes + FCS_LENGTH) * 8) + FLAG_LENGTH];
this.checksum = checksum;
this.minBits = 8 * (minBytes + FCS_LENGTH);
}
@Override
public byte[] readBytes() throws IOException {
int ones = 0;
int packetLength = 0;
while (true) {
byte curBit = input.readByte();
if (curBit == 1) {
ones++;
if (foundStartFlag) {
if (packetLength < window.length) {
window[packetLength] = curBit;
packetLength++;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("found a packet with more than max length: {}. discarding it", packetLength);
}
foundStartFlag = false;
packetLength = 0;
}
}
} else {
if (ones == 5) {
// destuffing
} else if (ones > 5) { // i.e 6
if (!foundStartFlag) {
foundStartFlag = true;
} else {
// pop back 7bits of the last flag
packetLength = packetLength - FLAG_LENGTH;
if (packetLength % 8 != 0 || packetLength < minBits) {
packetLength = 0;
ones = 0;
continue;
}
int payloadLength = packetLength - FCS_LENGTH * 8;
if (checksum) {
int expected = Crc16Ccitt.calculateReverseLsbBits(window, 0, payloadLength);
int crc = extractFcs(packetLength);
if (expected != crc) {
packetLength = 0;
ones = 0;
continue;
}
}
byte[] frame = unpackedToPacked(payloadLength);
CorrelateSyncword.markStartOfPacket(getContext());
return frame;
}
} else {
if (foundStartFlag) {
if (packetLength < window.length) {
window[packetLength] = curBit;
packetLength++;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("found a packet with more than max length: {}. discarding it", packetLength);
}
foundStartFlag = false;
packetLength = 0;
}
}
}
ones = 0;
}
}
}
private int extractFcs(int packetLength) {
int result = 0;
for (int i = 0, j = packetLength - 1; i < 16; i++, j--) {
result = result << 1;
result = result | window[j];
}
return result;
}
private byte[] unpackedToPacked(int packetLength) {
byte[] frame = new byte[packetLength / 8];
for (int i = 0; i < frame.length; i++) {
int curByte = 0;
for (int j = 0; j < 8; j++) {
// LSB
curByte = curByte | (window[i * 8 + j] << j);
}
frame[i] = (byte) curByte;
}
return frame;
}
@Override
public Context getContext() {
return input.getContext();
}
@Override
public void close() throws IOException {
input.close();
}
}