Skip to content
This repository was archived by the owner on Nov 26, 2025. It is now read-only.

Commit 0a326fa

Browse files
MikeGitbdcyoung
authored andcommitted
Refactor some libsweep internals (#110)
* [libsweep] Move scan decode logic into member functions * [libsweep] Change implementation of scan from SoA to AoS * [libsweep] Use return types instead of out parameters in protocol functions * [libsweep] Remove unnecessary parameters of protocol functions
1 parent 694c926 commit 0a326fa

File tree

3 files changed

+105
-95
lines changed

3 files changed

+105
-95
lines changed

libsweep/include/protocol.hpp

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -88,25 +88,32 @@ struct response_scan_packet_s {
8888
uint16_t distance;
8989
uint8_t signal_strength;
9090
uint8_t checksum;
91+
92+
struct sync_error_bits {
93+
enum bits : uint8_t {
94+
sync = 1 << 0, // beginning of new full scan
95+
communication_error = 1 << 1, // communication error
96+
97+
// Reserved for future error bits
98+
reserved2 = 1 << 2,
99+
reserved3 = 1 << 3,
100+
reserved4 = 1 << 4,
101+
reserved5 = 1 << 5,
102+
reserved6 = 1 << 6,
103+
reserved7 = 1 << 7,
104+
};
105+
};
106+
107+
bool is_sync() const { return sync_error & sync_error_bits::sync; }
108+
bool has_error() const { return sync_error >> 1 != 0; } // shift out sync bit, others are errors
109+
int get_angle_millideg() const {
110+
// angle is transmitted as fixed point integer with scaling factor of 16
111+
return static_cast<int>(angle * 1000 / 16.0f);
112+
}
91113
};
92114

93115
static_assert(sizeof(response_scan_packet_s) == 7, "response scan packet size mismatch");
94116

95-
namespace response_scan_packet_sync {
96-
enum bits : uint8_t {
97-
sync = 1 << 0, // beginning of new full scan
98-
communication_error = 1 << 1, // communication error
99-
100-
// Reserved for future error bits
101-
reserved2 = 1 << 2,
102-
reserved3 = 1 << 3,
103-
reserved4 = 1 << 4,
104-
reserved5 = 1 << 5,
105-
reserved6 = 1 << 6,
106-
reserved7 = 1 << 7,
107-
};
108-
}
109-
110117
struct response_info_device_s {
111118
uint8_t cmdByte1;
112119
uint8_t cmdByte2;
@@ -172,23 +179,17 @@ void write_command(sweep::serial::device_s serial, const uint8_t cmd[2]);
172179

173180
void write_command_with_arguments(sweep::serial::device_s serial, const uint8_t cmd[2], const uint8_t arg[2]);
174181

175-
void read_response_header(sweep::serial::device_s serial, const uint8_t cmd[2], response_header_s* header);
176-
177-
void read_response_param(sweep::serial::device_s serial, const uint8_t cmd[2], response_param_s* param);
182+
response_header_s read_response_header(sweep::serial::device_s serial, const uint8_t cmd[2]);
178183

179-
void read_response_scan(sweep::serial::device_s serial, response_scan_packet_s* scan);
184+
response_param_s read_response_param(sweep::serial::device_s serial, const uint8_t cmd[2]);
180185

181-
void read_response_info_motor_ready(sweep::serial::device_s serial, const uint8_t cmd[2], response_info_motor_ready_s* info);
186+
response_scan_packet_s read_response_scan(sweep::serial::device_s serial);
182187

183-
void read_response_info_motor_speed(sweep::serial::device_s serial, const uint8_t cmd[2], response_info_motor_speed_s* info);
188+
response_info_motor_ready_s read_response_info_motor_ready(sweep::serial::device_s serial);
184189

185-
void read_response_info_sample_rate(sweep::serial::device_s serial, const uint8_t cmd[2], response_info_sample_rate_s* info);
190+
response_info_motor_speed_s read_response_info_motor_speed(sweep::serial::device_s serial);
186191

187-
// Some protocol conversion utilities
188-
inline int angle_raw_to_millideg(uint16_t v) {
189-
// angle is transmitted as fixed point integer with scaling factor of 16
190-
return static_cast<int>(v * 1000 / 16.0f);
191-
}
192+
response_info_sample_rate_s read_response_info_sample_rate(sweep::serial::device_s serial);
192193

193194
inline void integral_to_ascii_bytes(const int32_t integral, uint8_t bytes[2]) {
194195
SWEEP_ASSERT(integral >= 0);

libsweep/src/protocol.cc

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -55,91 +55,100 @@ void write_command_with_arguments(serial::device_s serial, const uint8_t cmd[2],
5555
serial::device_write(serial, &packet, sizeof(cmd_param_packet_s));
5656
}
5757

58-
void read_response_header(serial::device_s serial, const uint8_t cmd[2], response_header_s* header) {
58+
response_header_s read_response_header(serial::device_s serial, const uint8_t cmd[2]) {
5959
SWEEP_ASSERT(serial);
6060
SWEEP_ASSERT(cmd);
61-
SWEEP_ASSERT(header);
6261

63-
serial::device_read(serial, header, sizeof(response_header_s));
62+
response_header_s header;
63+
serial::device_read(serial, &header, sizeof(header));
6464

65-
uint8_t checksum = checksum_response_header(*header);
65+
uint8_t checksum = checksum_response_header(header);
6666

67-
if (checksum != header->cmdSum)
67+
if (checksum != header.cmdSum)
6868
throw error{"invalid response header checksum"};
6969

70-
bool ok = header->cmdByte1 == cmd[0] && header->cmdByte2 == cmd[1];
70+
bool ok = header.cmdByte1 == cmd[0] && header.cmdByte2 == cmd[1];
7171

7272
if (!ok)
7373
throw error{"invalid header response commands"};
74+
75+
return header;
7476
}
7577

76-
void read_response_param(serial::device_s serial, const uint8_t cmd[2], response_param_s* param) {
78+
response_param_s read_response_param(serial::device_s serial, const uint8_t cmd[2]) {
7779
SWEEP_ASSERT(serial);
7880
SWEEP_ASSERT(cmd);
79-
SWEEP_ASSERT(param);
8081

81-
serial::device_read(serial, param, sizeof(response_param_s));
82+
response_param_s param;
83+
serial::device_read(serial, &param, sizeof(param));
8284

83-
uint8_t checksum = checksum_response_param(*param);
85+
uint8_t checksum = checksum_response_param(param);
8486

85-
if (checksum != param->cmdSum)
87+
if (checksum != param.cmdSum)
8688
throw error{"invalid response param header checksum"};
8789

88-
bool ok = param->cmdByte1 == cmd[0] && param->cmdByte2 == cmd[1];
90+
bool ok = param.cmdByte1 == cmd[0] && param.cmdByte2 == cmd[1];
8991

9092
if (!ok)
9193
throw error{"invalid param response commands"};
94+
95+
return param;
9296
}
9397

94-
void read_response_scan(serial::device_s serial, response_scan_packet_s* scan) {
98+
response_scan_packet_s read_response_scan(serial::device_s serial) {
9599
SWEEP_ASSERT(serial);
96-
SWEEP_ASSERT(scan);
97100

98-
serial::device_read(serial, scan, sizeof(response_scan_packet_s));
101+
response_scan_packet_s scan;
102+
serial::device_read(serial, &scan, sizeof(scan));
99103

100-
uint8_t checksum = checksum_response_scan_packet(*scan);
104+
uint8_t checksum = checksum_response_scan_packet(scan);
101105

102-
if (checksum != scan->checksum)
106+
if (checksum != scan.checksum)
103107
throw error{"invalid scan response commands"};
108+
109+
return scan;
104110
}
105111

106-
void read_response_info_motor_ready(serial::device_s serial, const uint8_t cmd[2], response_info_motor_ready_s* info) {
112+
response_info_motor_ready_s read_response_info_motor_ready(serial::device_s serial) {
107113
SWEEP_ASSERT(serial);
108-
SWEEP_ASSERT(cmd);
109-
SWEEP_ASSERT(info);
110114

111-
serial::device_read(serial, info, sizeof(response_info_motor_ready_s));
115+
response_info_motor_ready_s info;
116+
serial::device_read(serial, &info, sizeof(info));
112117

113-
bool ok = info->cmdByte1 == cmd[0] && info->cmdByte2 == cmd[1];
118+
bool ok = info.cmdByte1 == MOTOR_READY[0] && info.cmdByte2 == MOTOR_READY[1];
114119

115120
if (!ok)
116121
throw error{"invalid motor ready response commands"};
122+
123+
return info;
117124
}
118125

119-
void read_response_info_motor_speed(serial::device_s serial, const uint8_t cmd[2], response_info_motor_speed_s* info) {
126+
response_info_motor_speed_s read_response_info_motor_speed(serial::device_s serial) {
120127
SWEEP_ASSERT(serial);
121-
SWEEP_ASSERT(cmd);
122-
SWEEP_ASSERT(info);
123128

124-
serial::device_read(serial, info, sizeof(response_info_motor_speed_s));
129+
response_info_motor_speed_s info;
130+
serial::device_read(serial, &info, sizeof(info));
125131

126-
bool ok = info->cmdByte1 == cmd[0] && info->cmdByte2 == cmd[1];
132+
bool ok = info.cmdByte1 == MOTOR_INFORMATION[0] && info.cmdByte2 == MOTOR_INFORMATION[1];
127133

128134
if (!ok)
129135
throw error{"invalid motor info response commands"};
136+
137+
return info;
130138
}
131139

132-
void read_response_info_sample_rate(sweep::serial::device_s serial, const uint8_t cmd[2], response_info_sample_rate_s* info) {
140+
response_info_sample_rate_s read_response_info_sample_rate(sweep::serial::device_s serial) {
133141
SWEEP_ASSERT(serial);
134-
SWEEP_ASSERT(cmd);
135-
SWEEP_ASSERT(info);
136142

137-
serial::device_read(serial, info, sizeof(response_info_sample_rate_s));
143+
response_info_sample_rate_s info;
144+
serial::device_read(serial, &info, sizeof(info));
138145

139-
bool ok = info->cmdByte1 == cmd[0] && info->cmdByte2 == cmd[1];
146+
bool ok = info.cmdByte1 == SAMPLE_RATE_INFORMATION[0] && info.cmdByte2 == SAMPLE_RATE_INFORMATION[1];
140147

141148
if (!ok)
142149
throw error{"invalid sample rate info response commands"};
150+
151+
return info;
143152
}
144153

145154
} // ns protocol

libsweep/src/sweep.cc

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "sweep.h"
77

8+
#include <algorithm>
89
#include <chrono>
910
#include <exception>
1011
#include <string>
@@ -19,13 +20,25 @@ struct sweep_error {
1920

2021
#define SWEEP_MAX_SAMPLES 4096
2122

23+
struct sample {
24+
int32_t angle; // in millidegrees
25+
int32_t distance; // in cm
26+
int32_t signal_strength; // range 0:255
27+
};
28+
2229
struct sweep_scan {
23-
int32_t angle[SWEEP_MAX_SAMPLES]; // in millidegrees
24-
int32_t distance[SWEEP_MAX_SAMPLES]; // in cm
25-
int32_t signal_strength[SWEEP_MAX_SAMPLES]; // range 0:255
30+
sample samples[SWEEP_MAX_SAMPLES];
2631
int32_t count;
2732
};
2833

34+
static sample parse_payload(const sweep::protocol::response_scan_packet_s& msg) {
35+
sample ret;
36+
ret.angle = msg.get_angle_millideg();
37+
ret.distance = msg.distance;
38+
ret.signal_strength = msg.signal_strength;
39+
return ret;
40+
}
41+
2942
struct sweep_device {
3043
sweep::serial::device_s serial; // serial port communication
3144
bool is_scanning;
@@ -88,36 +101,31 @@ static void sweep_device_accumulate_scans(sweep_device_s device) try {
88101
SWEEP_ASSERT(device);
89102
SWEEP_ASSERT(device->is_scanning);
90103

91-
sweep::protocol::response_scan_packet_s responses[SWEEP_MAX_SAMPLES];
104+
sample buffer[SWEEP_MAX_SAMPLES];
92105
int32_t received = 0;
93106

94107
while (!device->stop_thread && received < SWEEP_MAX_SAMPLES) {
95-
sweep::protocol::read_response_scan(device->serial, &responses[received]);
96108

97-
const bool is_sync = responses[received].sync_error & sweep::protocol::response_scan_packet_sync::sync;
98-
const bool has_error = (responses[received].sync_error >> 1) != 0; // shift out sync bit, others are errors
109+
const auto response = sweep::protocol::read_response_scan(device->serial);
99110

100-
if (!has_error) {
111+
if (!response.has_error()) {
112+
buffer[received] = parse_payload(response);
101113
received++;
102114
}
103115

104-
if (is_sync) {
105-
if (received <= 1)
106-
continue;
116+
if (response.is_sync() && received > 1) {
117+
107118
// package the previous scan without the sync reading from the subsequent scan
108119
auto out = std::unique_ptr<sweep_scan>(new sweep_scan);
109120
out->count = received - 1; // minus 1 to exclude sync reading
110-
for (int32_t it = 0; it < received - 1; ++it) {
111-
out->angle[it] = sweep::protocol::angle_raw_to_millideg(responses[it].angle);
112-
out->distance[it] = responses[it].distance;
113-
out->signal_strength[it] = responses[it].signal_strength;
114-
}
121+
122+
std::copy_n(std::begin(buffer), received - 1, std::begin(out->samples));
115123

116124
// place the scan in the queue
117125
device->scan_queue.enqueue({std::move(out), nullptr});
118126

119127
// place the sync reading at the start for the next scan
120-
responses[0] = responses[received - 1];
128+
buffer[0] = buffer[received - 1];
121129

122130
// reset received
123131
received = 1;
@@ -140,8 +148,7 @@ static void sweep_device_attempt_start_scanning(sweep_device_s device, sweep_err
140148

141149
sweep::protocol::write_command(device->serial, sweep::protocol::DATA_ACQUISITION_START);
142150

143-
sweep::protocol::response_header_s response;
144-
sweep::protocol::read_response_header(device->serial, sweep::protocol::DATA_ACQUISITION_START, &response);
151+
auto response = sweep::protocol::read_response_header(device->serial, sweep::protocol::DATA_ACQUISITION_START);
145152

146153
// Check the status bytes do not indicate failure
147154
const uint8_t status_bytes[2] = {response.cmdStatusByte1, response.cmdStatusByte2};
@@ -172,8 +179,7 @@ static void sweep_device_attempt_set_motor_speed(sweep_device_s device, int32_t
172179

173180
sweep::protocol::write_command_with_arguments(device->serial, sweep::protocol::MOTOR_SPEED_ADJUST, args);
174181

175-
sweep::protocol::response_param_s response;
176-
sweep::protocol::read_response_param(device->serial, sweep::protocol::MOTOR_SPEED_ADJUST, &response);
182+
const auto response = sweep::protocol::read_response_param(device->serial, sweep::protocol::MOTOR_SPEED_ADJUST);
177183

178184
// Check the status bytes do not indicate failure
179185
const uint8_t status_bytes[2] = {response.cmdStatusByte1, response.cmdStatusByte2};
@@ -288,9 +294,8 @@ void sweep_device_stop_scanning(sweep_device_s device, sweep_error_s* error) try
288294
// Read the response from the first stop command
289295
// It is possible this will contain garbage bytes (leftover from data stream), and will error
290296
// But we are guaranteed to read at least as many bytes as the length of a stop response
291-
sweep::protocol::response_header_s garbage_response;
292297
try {
293-
sweep::protocol::read_response_header(device->serial, sweep::protocol::DATA_ACQUISITION_STOP, &garbage_response);
298+
sweep::protocol::read_response_header(device->serial, sweep::protocol::DATA_ACQUISITION_STOP);
294299
} catch (const std::exception& ignore) {
295300
// Catch and ignore the error in the case of the stop response containing garbage bytes
296301
// Occurs if the device was actively streaming data before the stop cmd
@@ -304,8 +309,7 @@ void sweep_device_stop_scanning(sweep_device_s device, sweep_error_s* error) try
304309
sweep::protocol::write_command(device->serial, sweep::protocol::DATA_ACQUISITION_STOP);
305310

306311
// read the response
307-
sweep::protocol::response_header_s response;
308-
sweep::protocol::read_response_header(device->serial, sweep::protocol::DATA_ACQUISITION_STOP, &response);
312+
sweep::protocol::read_response_header(device->serial, sweep::protocol::DATA_ACQUISITION_STOP);
309313

310314
device->is_scanning = false;
311315
} catch (const std::exception& e) {
@@ -338,8 +342,7 @@ bool sweep_device_get_motor_ready(sweep_device_s device, sweep_error_s* error) t
338342

339343
sweep::protocol::write_command(device->serial, sweep::protocol::MOTOR_READY);
340344

341-
sweep::protocol::response_info_motor_ready_s response;
342-
sweep::protocol::read_response_info_motor_ready(device->serial, sweep::protocol::MOTOR_READY, &response);
345+
const auto response = sweep::protocol::read_response_info_motor_ready(device->serial);
343346

344347
int32_t ready_code = sweep::protocol::ascii_bytes_to_integral(response.motor_ready);
345348
SWEEP_ASSERT(ready_code >= 0);
@@ -357,8 +360,7 @@ int32_t sweep_device_get_motor_speed(sweep_device_s device, sweep_error_s* error
357360

358361
sweep::protocol::write_command(device->serial, sweep::protocol::MOTOR_INFORMATION);
359362

360-
sweep::protocol::response_info_motor_speed_s response;
361-
sweep::protocol::read_response_info_motor_speed(device->serial, sweep::protocol::MOTOR_INFORMATION, &response);
363+
const auto response = sweep::protocol::read_response_info_motor_speed(device->serial);
362364

363365
int32_t speed = sweep::protocol::ascii_bytes_to_integral(response.motor_speed);
364366
SWEEP_ASSERT(speed >= 0);
@@ -391,8 +393,7 @@ int32_t sweep_device_get_sample_rate(sweep_device_s device, sweep_error_s* error
391393

392394
sweep::protocol::write_command(device->serial, sweep::protocol::SAMPLE_RATE_INFORMATION);
393395

394-
sweep::protocol::response_info_sample_rate_s response;
395-
sweep::protocol::read_response_info_sample_rate(device->serial, sweep::protocol::SAMPLE_RATE_INFORMATION, &response);
396+
const auto response = sweep::protocol::read_response_info_sample_rate(device->serial);
396397

397398
// 01: 500-600Hz, 02: 750-800Hz, 03: 1000-1050Hz
398399
int32_t code = sweep::protocol::ascii_bytes_to_integral(response.sample_rate);
@@ -446,8 +447,7 @@ void sweep_device_set_sample_rate(sweep_device_s device, int32_t hz, sweep_error
446447

447448
sweep::protocol::write_command_with_arguments(device->serial, sweep::protocol::SAMPLE_RATE_ADJUST, args);
448449

449-
sweep::protocol::response_param_s response;
450-
sweep::protocol::read_response_param(device->serial, sweep::protocol::SAMPLE_RATE_ADJUST, &response);
450+
const auto response = sweep::protocol::read_response_param(device->serial, sweep::protocol::SAMPLE_RATE_ADJUST);
451451

452452
// Check the status bytes do not indicate failure
453453
const uint8_t status_bytes[2] = {response.cmdStatusByte1, response.cmdStatusByte2};
@@ -474,21 +474,21 @@ int32_t sweep_scan_get_angle(sweep_scan_s scan, int32_t sample) {
474474
SWEEP_ASSERT(scan);
475475
SWEEP_ASSERT(sample >= 0 && sample < scan->count && "sample index out of bounds");
476476

477-
return scan->angle[sample];
477+
return scan->samples[sample].angle;
478478
}
479479

480480
int32_t sweep_scan_get_distance(sweep_scan_s scan, int32_t sample) {
481481
SWEEP_ASSERT(scan);
482482
SWEEP_ASSERT(sample >= 0 && sample < scan->count && "sample index out of bounds");
483483

484-
return scan->distance[sample];
484+
return scan->samples[sample].distance;
485485
}
486486

487487
int32_t sweep_scan_get_signal_strength(sweep_scan_s scan, int32_t sample) {
488488
SWEEP_ASSERT(scan);
489489
SWEEP_ASSERT(sample >= 0 && sample < scan->count && "sample index out of bounds");
490490

491-
return scan->signal_strength[sample];
491+
return scan->samples[sample].signal_strength;
492492
}
493493

494494
void sweep_scan_destruct(sweep_scan_s scan) {

0 commit comments

Comments
 (0)