-
-
Notifications
You must be signed in to change notification settings - Fork 84
/
parser.cpp
137 lines (122 loc) · 4.23 KB
/
parser.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
#include "parser.h"
#include <arpa/inet.h>
#include <cstddef>
#include <string.h>
#include <stdexcept>
#include <sys/types.h>
ssize_t parseCANFrame(canfd_frame* frame, const uint8_t* rawData, const uint8_t* rawDataEnd) {
using namespace cannelloni;
const uint8_t* rawDataOrig = rawData;
canid_t tmp;
memcpy(&tmp, rawData, sizeof (canid_t));
frame->can_id = ntohl(tmp);
/* += 4 */
rawData += sizeof (canid_t);
frame->len = *rawData;
/* += 1 */
rawData += sizeof (frame->len);
/* If this is a CAN FD frame, also retrieve the flags */
if (frame->len & CANFD_FRAME)
{
frame->flags = *rawData;
/* += 1 */
rawData += sizeof (frame->flags);
}
/* RTR Frames have no data section although they have a dlc */
if ((frame->can_id & CAN_RTR_FLAG) == 0)
{
/* Check again now that we know the dlc */
if (rawData + canfd_len(frame) > rawDataEnd)
{
frame->len = 0;
return -1;
}
memcpy(frame->data, rawData, canfd_len(frame));
rawData += canfd_len(frame);
}
return rawData-rawDataOrig;
}
void parseFrames(uint16_t len, const uint8_t* buffer, std::function<canfd_frame*()> frameAllocator,
std::function<void(canfd_frame*, bool)> frameReceiver)
{
using namespace cannelloni;
const struct CannelloniDataPacket* data;
/* Check for OP Code */
data = reinterpret_cast<const struct CannelloniDataPacket*> (buffer);
if (data->version != CANNELLONI_FRAME_VERSION)
throw std::runtime_error("Received wrong version");
if (data->op_code != DATA)
throw std::runtime_error("Received wrong OP code");
if (ntohs(data->count) == 0)
return; // Empty packets silently ignored
const uint8_t* rawData = buffer + CANNELLONI_DATA_PACKET_BASE_SIZE;
const uint8_t* bufferEnd = buffer + len;
for (uint16_t i = 0; i < ntohs(data->count); i++)
{
if (rawData - buffer + CANNELLONI_FRAME_BASE_SIZE > len)
throw std::runtime_error("Received incomplete packet");
/* We got at least a complete canfd_frame header */
canfd_frame* frame = frameAllocator();
if (!frame)
throw std::runtime_error("Allocation error.");
ssize_t bytesParsed = parseCANFrame(frame, rawData, bufferEnd);
rawData+=bytesParsed;
if (bytesParsed > 0) {
frameReceiver(frame, true);
} else {
frameReceiver(frame, false);
throw std::runtime_error("Received incomplete packet / can header corrupt!");
}
}
}
size_t encodeFrame(uint8_t *data, canfd_frame *frame) {
using namespace cannelloni;
uint8_t *dataOrig = data;
canid_t tmp = htonl(frame->can_id);
memcpy(data, &tmp, sizeof(canid_t));
/* += 4 */
data += sizeof(canid_t);
*data = frame->len;
/* += 1 */
data += sizeof(frame->len);
/* If this is a CAN FD frame, also send the flags */
if (frame->len & CANFD_FRAME) {
*data = frame->flags;
/* += 1 */
data += sizeof(frame->flags);
}
if ((frame->can_id & CAN_RTR_FLAG) == 0) {
memcpy(data, frame->data, canfd_len(frame));
data += canfd_len(frame);
}
return data-dataOrig;
}
uint8_t* buildPacket(uint16_t len, uint8_t* packetBuffer,
std::list<canfd_frame*>& frames, uint8_t seqNo,
std::function<void(std::list<canfd_frame*>&, std::list<canfd_frame*>::iterator)> handleOverflow)
{
using namespace cannelloni;
uint16_t frameCount = 0;
uint8_t* data = packetBuffer + CANNELLONI_DATA_PACKET_BASE_SIZE;
for (auto it = frames.begin(); it != frames.end(); it++)
{
canfd_frame* frame = *it;
/* Check for packet overflow */
if ((data - packetBuffer + CANNELLONI_FRAME_BASE_SIZE + canfd_len(frame)
+ ((frame->len & CANFD_FRAME) ? sizeof(frame->flags) : 0))
> len)
{
handleOverflow(frames, it);
break;
}
data += encodeFrame(data, frame);
frameCount++;
}
struct CannelloniDataPacket* dataPacket;
dataPacket = (struct CannelloniDataPacket*) (packetBuffer);
dataPacket->version = CANNELLONI_FRAME_VERSION;
dataPacket->op_code = DATA;
dataPacket->seq_no = seqNo;
dataPacket->count = htons(frameCount);
return data;
}