-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathpacket_utils.c
203 lines (176 loc) · 6.26 KB
/
packet_utils.c
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
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "crc.h"
#include "packet_utils.h"
/*
* Packet Construction utilities.
*
* Unlike the "high level commands" these are supposed to be general across
* Dynamixel SDK 2.0
* That is, they are supposed to work on both XL-320 and DXL-PRO
* Haven't test on a DXL-PRO though...
*/
inline uint8_t LowBits(uint16_t word);
inline uint8_t HighBits(uint16_t word);
inline uint16_t MakeWord(uint8_t low_bits, uint8_t high_bits);
void SetPacketPrefix(uint8_t* data, uint8_t dxl_id, uint8_t instruction,
uint16_t num_parameters) {
// Header
data[0] = 0xFF;
data[1] = 0xFF;
data[2] = 0xFD;
// Reserved
// At the time of this writing, this register is inconsequential.
// data[3] = 0x00;
// The dynamixel ID to target. 0xFE is broadcast
data[4] = dxl_id;
// Packet Length
// == Length after packet length field
// == Number of parameters + 3
int packet_length = num_parameters + 3;
assert(packet_length <= UINT16_MAX); // No 16bit overflow.
data[5] = LowBits(packet_length); // Low order bits of packet length.
data[6] = HighBits(packet_length); // High order bits of packet length.
// Instruction byte.
data[7] = instruction;
}
/*
* Adds the CRC checksum. The entire data packet up until the
* CRC checksum must already be set, because the value is a function
* of all the preceding bytes.
* Returns the total number of bytes in the packet.
*/
void SetChecksum(uint8_t* data, uint16_t num_parameters) {
// The prefix size is 8 bytes. Check overflow.
assert(num_parameters <= MAX_PACKET_BYTES - PREFIX_SIZE);
uint16_t num_bytes_before_checksum = num_parameters + PREFIX_SIZE;
uint16_t crc = UpdateCRC(0, data, num_bytes_before_checksum);
data[num_bytes_before_checksum] = LowBits(crc);
data[num_bytes_before_checksum + 1] = HighBits(crc);
}
void SetByteParam(uint8_t* data, uint16_t param_byte_offset, uint8_t value) {
data[PREFIX_SIZE + param_byte_offset] = value;
}
void SetWordParam(uint8_t* data, uint16_t param_byte_offset, uint16_t value) {
data[PREFIX_SIZE + param_byte_offset] = LowBits(value);
data[PREFIX_SIZE + param_byte_offset + 1] = HighBits(value);
}
uint8_t GetByteParam(uint8_t* data, uint16_t param_byte_offset) {
return data[PREFIX_SIZE + param_byte_offset];
}
uint16_t GetWordParam(uint8_t* data, uint16_t param_byte_offset) {
return MakeWord(data[PREFIX_SIZE + param_byte_offset],
data[PREFIX_SIZE + param_byte_offset + 1]);
}
void PrintPacket(uint8_t* data, uint16_t num_bytes) {
int i;
if (num_bytes >= PREFIX_SIZE) {
printf("Prefix: ");
for (i = 0; i < PREFIX_SIZE; i++) {
printf("%02x | ", data[i]);
}
printf("Payload: ");
for (; i < num_bytes; i++) {
printf("%02x | ", data[i]);
}
printf("\n");
} else {
printf("Prefix not complete: ");
for (i = 0; i < num_bytes; i++) {
printf("%02x | ", data[i]);
}
}
}
void FinalPacketConsistencyCheck(uint8_t* data, uint16_t num_bytes) {
assert(num_bytes >= BASE_PACKET_SIZE);
// Check header
int i;
for (i = 0; i < HEADER_SIZE; i++) {
assert(data[i] == HEADER[i]);
}
// Check packet length setting
assert(MakeWord(data[LENGTH_L_ADDR], data[LENGTH_H_ADDR]) ==
num_bytes - PREFIX_SIZE + 1);
// Check Instruction
assert(data[INST_ADDR] > 0 && data[INST_ADDR] <= 11);
// CRC Check
uint16_t expected_crc = UpdateCRC(0, data, num_bytes - CHECKSUM_SIZE);
assert(MakeWord(data[num_bytes - 2], data[num_bytes - 1]) == expected_crc);
}
// Higher Level Packet Construction
// Returns number of parameter bytes added.
uint16_t MakePingPacket(uint8_t* data, uint8_t dxl_id) {
uint8_t instruction = 1;
uint16_t num_parameters_tx = 0;
SetPacketPrefix(data, dxl_id, instruction, num_parameters_tx);
return num_parameters_tx;
}
// Returns number of parameter bytes added.
uint16_t MakeReadPacket(uint8_t* data, uint8_t dxl_id, uint16_t start_addr,
uint16_t num_bytes) {
uint8_t instruction = 2;
uint16_t num_parameters_tx = 4;
SetPacketPrefix(data, dxl_id, instruction, num_parameters_tx);
SetWordParam(data, 0, start_addr);
SetWordParam(data, 2, num_bytes);
return num_parameters_tx;
}
// For reading only a single byte
uint16_t MakeReadBytePacket(uint8_t* data, uint8_t dxl_id, uint16_t addr) {
uint8_t instruction = 2;
uint16_t num_parameters_tx = 4;
SetPacketPrefix(data, dxl_id, instruction, num_parameters_tx);
SetWordParam(data, 0, addr);
SetWordParam(data, 2, 1);
return num_parameters_tx;
}
// For reading two consecutive bytes
uint16_t MakeReadWordPacket(uint8_t* data, uint8_t dxl_id,
uint16_t start_addr) {
uint8_t instruction = 2;
uint16_t num_parameters_tx = 4;
SetPacketPrefix(data, dxl_id, instruction, num_parameters_tx);
SetWordParam(data, 0, start_addr);
SetWordParam(data, 2, 2);
return num_parameters_tx;
}
// Returns number of parameter bytes added.
uint16_t MakeWritePacket(uint8_t* data, uint8_t dxl_id, uint16_t start_addr,
uint8_t* write_data, uint16_t num_write_bytes) {
uint8_t instruction = 3;
uint16_t num_parameters_tx = 2 + num_write_bytes; // Start addr and data
SetPacketPrefix(data, dxl_id, instruction, num_parameters_tx);
SetWordParam(data, 0, start_addr);
int i;
for (i = 0; i < num_write_bytes; i++) {
SetByteParam(data, 2 + i, write_data[i]);
}
return num_parameters_tx;
}
uint16_t MakeWriteBytePacket(uint8_t* data, uint8_t dxl_id, uint16_t addr,
uint8_t write_data) {
uint8_t instruction = 3;
uint16_t num_parameters_tx = 2 + 1; // Start addr and data
SetPacketPrefix(data, dxl_id, instruction, num_parameters_tx);
SetWordParam(data, 0, addr);
SetByteParam(data, 2, write_data);
return num_parameters_tx;
}
uint16_t MakeWriteWordPacket(uint8_t* data, uint8_t dxl_id, uint16_t start_addr,
uint16_t write_data) {
uint8_t instruction = 3;
uint16_t num_parameters_tx = 2 + 2; // Start addr and data
SetPacketPrefix(data, dxl_id, instruction, num_parameters_tx);
SetWordParam(data, 0, start_addr);
SetWordParam(data, 2, write_data);
return num_parameters_tx;
}
// TODO Reg write
// TODO Action
// TODO Factory reset
// TODO Reboot
// TODO Sync read
// TODO Sync write
// TODO Bulk read
// TODO Bulk write