forked from Railstars/CmdrArduino
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DCCPacket.cpp
87 lines (74 loc) · 2.47 KB
/
DCCPacket.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
#include "DCCPacket.h"
DCCPacket::DCCPacket(uint16_t new_address, uint8_t new_address_kind) : address(new_address), address_kind(new_address_kind), kind(idle_packet_kind), size_repeat(0x40) //size(1), repeat(0)
{
address = new_address;
address_kind = new_address_kind;
data[0] = 0x00; //default to idle packet
data[1] = 0x00;
data[2] = 0x00;
}
uint8_t DCCPacket::getBitstream(uint8_t rawbytes[]) //returns size of array.
{
int total_size = 1; //minimum size
if (kind & MULTIFUNCTION_PACKET_KIND_MASK) {
if (kind == idle_packet_kind) //idle packets work a bit differently:
// since the "address" field is 0xFF, the logic below will produce C0 FF 00 3F instead of FF 00 FF
{
rawbytes[0] = 0xFF;
} else if (address_kind == DCC_LONG_ADDRESS) //This is a 14-bit address
{
rawbytes[0] = (uint8_t)((address >> 8) | 0xC0);
rawbytes[1] = (uint8_t)(address & 0xFF);
++total_size;
} else //we have an 7-bit address
{
rawbytes[0] = (uint8_t)(address & 0x7F);
}
uint8_t i;
for (i = 0; i < getSize(); ++i, ++total_size) {
rawbytes[total_size] = data[i];
}
uint8_t XOR = 0;
for (i = 0; i < total_size; ++i) {
XOR ^= rawbytes[i];
}
rawbytes[total_size] = XOR;
return total_size + 1;
} else if (kind & ACCESSORY_PACKET_KIND_MASK) {
if (kind == basic_accessory_packet_kind) {
// Basic Accessory Packet looks like this:
// {preamble} 0 10AAAAAA 0 1AAACDDD 0 EEEEEEEE 1
// or this:
// {preamble} 0 10AAAAAA 0 1AAACDDD 0 (1110CCVV 0 VVVVVVVV 0 DDDDDDDD) 0 EEEEEEEE 1 (if programming)
rawbytes[0] = 0x80; //set up address byte 0
rawbytes[1] = 0x88; //set up address byte 1
rawbytes[0] |= address & 0x03F;
rawbytes[1] |= (~(address >> 2) & 0x70)
| (data[0] & 0x07);
//now, add any programming bytes (skipping first data byte, of course)
uint8_t i;
uint8_t total_size = 2;
for (i = 1; i < getSize(); ++i, ++total_size) {
rawbytes[total_size] = data[i];
}
//and, finally, the XOR
uint8_t XOR = 0;
for (i = 0; i < total_size; ++i) {
XOR ^= rawbytes[i];
}
rawbytes[total_size] = XOR;
return total_size + 1;
}
}
return 0; //ERROR! SHOULD NEVER REACH HERE! do something useful, like transform it into an idle packet or something! TODO
}
uint8_t DCCPacket::getSize(void)
{
return (size_repeat>>6);
}
void DCCPacket::addData(uint8_t new_data[], uint8_t new_size) //insert freeform data.
{
for(int i = 0; i < new_size; ++i)
data[i] = new_data[i];
size_repeat = (size_repeat & 0x3F) | (new_size<<6);
}