23 #include "goby/common/logger.h" 24 #include "goby/util/as.h" 26 #include "waveglider_sv2_frontseat_driver.h" 35 const int allowed_skew = 30;
46 uint16_t crc_compute_incrementally(uint16_t crc,
char a);
47 uint16_t crc_compute(
const std::string& buffer,
unsigned offset,
unsigned count, uint16_t seed);
51 frontseat_providing_data_(false), last_frontseat_data_time_(0),
52 frontseat_state_(
gpb::FRONTSEAT_NOT_CONNECTED),
53 serial_(
goby::moos::SV2SerialConnection::create(io_, waveglider_sv2_config_.pm_serial_port(),
54 waveglider_sv2_config_.pm_serial_baud())),
55 queued_messages_(1), dccl_(
"SV2.id", getenv(
"IFRONTSEAT_DRIVER_LIBRARY"))
57 serial_->message_signal.connect(
58 boost::bind(&WavegliderSV2FrontSeat::handle_sv2_message,
this, _1));
61 glog.is(VERBOSE) &&
glog <<
"Connected to WavegliderSV2 serial port." << std::endl;
62 frontseat_state_ = gpb::FRONTSEAT_ACCEPTING_COMMANDS;
65 void WavegliderSV2FrontSeat::loop()
71 catch (std::exception& e)
73 glog.is(WARN) &&
glog <<
"Failed to poll serial or process received data: " << e.what()
80 frontseat_providing_data_ =
false;
85 if (command.has_desired_course())
87 dccl::uint32 board_addr = waveglider_sv2_config_.board_id() << dccl::BITS_IN_BYTE |
88 waveglider_sv2_config_.task_id();
90 boost::shared_ptr<goby::moos::protobuf::SV2CommandFollowFixedHeading> hdg_cmd(
92 hdg_cmd->mutable_header()->set_start_of_frame(0x7e);
93 hdg_cmd->mutable_header()->set_dest(goby::moos::protobuf::SV2Header::BOARD_ID_CC
94 << dccl::BITS_IN_BYTE |
95 goby::moos::protobuf::SV2Header::CCTASK_ID_COMMAND);
96 hdg_cmd->mutable_header()->set_src(board_addr);
97 hdg_cmd->mutable_header()->set_transaction_id(command.request_id());
98 hdg_cmd->mutable_header()->set_message_type(goby::moos::protobuf::MESSAGE_TYPE_ACK);
100 hdg_cmd->set_original_msg_type(goby::moos::protobuf::MESSAGE_TYPE_REQUEST_QUEUED_MESSAGE);
101 hdg_cmd->set_command_format(0x0001);
104 hdg_cmd->mutable_body();
106 body->set_level2id(0x0A);
107 body->set_wgmsid(0xFFFFFFFF);
108 body->set_data_size(18);
109 body->set_structure_id(0x10);
110 body->set_command_value(0x0008);
111 body->set_reserved(0);
112 body->set_heading_degrees(command.desired_course().heading());
113 body->set_latitude(0);
114 body->set_longitude(0);
118 dccl_.encode(&bytes, *body);
120 bytes = bytes.substr(2);
125 uint16_t calculated = crc_compute(bytes, 0, bytes.size() - CRC_SIZE, 0);
126 body->set_crc16(calculated);
128 hdg_cmd->mutable_footer()->set_crc16(0);
129 hdg_cmd->mutable_header()->set_message_size(
130 dccl_.size(*hdg_cmd) - 3);
132 glog.is(DEBUG1) &&
glog <<
"Queuing fixed heading cmd for heading of: " 133 << command.desired_course().heading() << std::endl;
134 glog.is(DEBUG2) &&
glog << hdg_cmd->DebugString() << std::endl;
135 queued_messages_.push_back(hdg_cmd);
139 glog.is(VERBOSE) &&
glog <<
"Unhandled command: " << command.ShortDebugString()
146 void WavegliderSV2FrontSeat::send_raw_to_frontseat(
const gpb::FrontSeatRaw& data) {}
148 bool WavegliderSV2FrontSeat::frontseat_providing_data()
const {
return frontseat_providing_data_; }
150 goby::moos::protobuf::FrontSeatState WavegliderSV2FrontSeat::frontseat_state()
const 152 return frontseat_state_;
155 void WavegliderSV2FrontSeat::handle_sv2_message(
const std::string& message)
159 MESSAGE_TYPE_START = 9,
160 MESSAGE_TYPE_SIZE = 2
164 std::string bytes = message.substr(MESSAGE_TYPE_START, MESSAGE_TYPE_SIZE) + message;
165 bool ack_requested = !(bytes[1] & 0x80);
166 glog.is(DEBUG2) &&
glog << (ack_requested ?
"ACK Requested" :
"No ACK Requested") << std::endl;
169 unsigned dccl_id = dccl_.id(bytes);
173 dccl_.decode(bytes, &enum_msg);
174 glog.is(DEBUG1) &&
glog <<
"Received enumeration request." << std::endl;
175 glog.is(DEBUG2) &&
glog << enum_msg.DebugString() << std::endl;
176 check_crc(message, enum_msg.footer().crc16());
177 handle_enumeration_request(enum_msg);
182 dccl_.decode(bytes, &request);
183 glog.is(DEBUG1) &&
glog <<
"Received status request." << std::endl;
184 glog.is(DEBUG2) &&
glog << request.DebugString() << std::endl;
185 frontseat_providing_data_ =
true;
187 handle_request_status(request);
192 dccl_.decode(bytes, &request);
193 glog.is(DEBUG1) &&
glog <<
"Received queue message request. " << std::endl;
194 glog.is(DEBUG2) &&
glog << request.DebugString() << std::endl;
195 handle_request_queued_message(request);
200 dccl_.decode(bytes, &ack);
201 glog.is(DEBUG1) &&
glog <<
"Received queue message ack/nak." << std::endl;
202 glog.is(DEBUG2) &&
glog << ack.DebugString() << std::endl;
208 dccl_.decode(bytes, &nak);
209 glog.is(DEBUG1) &&
glog <<
"Received generic nak." << std::endl;
210 glog.is(DEBUG2) &&
glog << nak.DebugString() << std::endl;
216 dccl_.decode(bytes, &ack);
217 glog.is(DEBUG1) &&
glog <<
"Received generic ack." << std::endl;
218 glog.is(DEBUG2) &&
glog << ack.DebugString() << std::endl;
223 glog.is(DEBUG1) &&
glog <<
"Received unhandled message type: " << std::hex << dccl_id
224 << std::dec << std::endl;
228 void WavegliderSV2FrontSeat::check_crc(
const std::string& message, uint16_t expected)
236 uint16_t calculated =
237 crc_compute(message, MAGIC_SIZE, message.size() - MAGIC_SIZE - CRC_SIZE, 0);
238 glog.is(DEBUG2) &&
glog <<
"Given CRC: " << std::hex << expected <<
", computed: " << calculated
239 << std::dec << std::endl;
241 if (calculated != expected)
242 glog.is(WARN) &&
glog <<
"Invalid CRC16" << std::endl;
245 void WavegliderSV2FrontSeat::add_crc(std::string* message)
253 uint16_t calculated =
254 crc_compute(*message, MAGIC_SIZE, message->size() - MAGIC_SIZE - CRC_SIZE, 0);
255 message->at(message->size() - 1) = (calculated >> dccl::BITS_IN_BYTE) & 0xff;
256 message->at(message->size() - 2) = (calculated)&0xff;
257 glog.is(DEBUG2) &&
glog <<
"Computed CRC: " << std::hex << calculated << std::dec << std::endl;
260 void WavegliderSV2FrontSeat::handle_enumeration_request(
265 dccl::uint32 board_addr =
266 waveglider_sv2_config_.board_id() << dccl::BITS_IN_BYTE | waveglider_sv2_config_.task_id();
268 reply.mutable_header()->set_start_of_frame(0x7e);
269 reply.mutable_header()->set_dest(goby::moos::protobuf::SV2Header::BOARD_ID_CC
270 << dccl::BITS_IN_BYTE |
271 goby::moos::protobuf::SV2Header::CCTASK_ID_MAIN);
272 reply.mutable_header()->set_src(board_addr);
273 reply.mutable_header()->set_transaction_id(request.header().transaction_id());
274 reply.mutable_header()->set_message_type(goby::moos::protobuf::MESSAGE_TYPE_ACK);
276 reply.set_original_msg_type(request.header().message_type());
277 reply.set_number_of_devices_responding(1);
278 reply.set_number_of_devices_in_message(1);
279 reply.set_version(1);
280 reply.set_device_type(0x1001);
281 reply.set_board_addr(board_addr);
282 reply.set_serial_number(
"000001");
283 reply.set_location(0);
284 reply.set_polling_frequency(1);
291 COMMAND_ACK_NAK = 0x08
293 reply.set_extra_info(COMMAND_ACK_NAK);
295 reply.set_firmware_major(0);
296 reply.set_firmware_minor(0);
297 reply.set_firmware_revision(1);
299 std::string description(
"iFrontSeat Driver");
300 reply.set_description(description + std::string(20 - description.size(),
'\0'));
301 reply.mutable_footer()->set_crc16(0);
303 reply.mutable_header()->set_message_size(
304 dccl_.size(reply) - 3);
306 glog.is(DEBUG1) &&
glog <<
"Sent enumeration reply." << std::endl;
307 glog.is(DEBUG2) &&
glog << reply.DebugString() << std::endl;
309 encode_and_write(reply);
312 void WavegliderSV2FrontSeat::handle_request_status(
317 dccl::uint32 board_addr =
318 waveglider_sv2_config_.board_id() << dccl::BITS_IN_BYTE | waveglider_sv2_config_.task_id();
320 reply.mutable_header()->set_start_of_frame(0x7e);
321 reply.mutable_header()->set_dest(goby::moos::protobuf::SV2Header::BOARD_ID_CC
322 << dccl::BITS_IN_BYTE |
323 goby::moos::protobuf::SV2Header::CCTASK_ID_MAIN);
324 reply.mutable_header()->set_src(board_addr);
325 reply.mutable_header()->set_transaction_id(request.header().transaction_id());
326 reply.mutable_header()->set_message_type(goby::moos::protobuf::MESSAGE_TYPE_ACK);
328 reply.set_original_msg_type(request.header().message_type());
329 reply.set_number_of_devices_responding(1);
330 reply.set_number_of_devices_in_message(1);
332 bool queued_message_waiting = (queued_messages_.size() > 0);
333 if (queued_message_waiting)
337 reply.set_version(0x0001);
339 reply.set_board_addr(board_addr);
342 reply.set_leak_sensor_1(0);
343 reply.set_leak_sensor_2(0);
344 reply.set_humid_temp(0);
345 reply.set_relative_humidity(0);
346 reply.set_pressure_temp(0);
347 reply.set_pressure(0);
349 reply.mutable_footer()->set_crc16(0);
350 reply.mutable_header()->set_message_size(dccl_.size(reply) - 3);
351 glog.is(DEBUG1) &&
glog <<
"Sent status reply." << std::endl;
352 glog.is(DEBUG2) &&
glog << reply.DebugString() << std::endl;
354 encode_and_write(reply);
357 void WavegliderSV2FrontSeat::handle_request_queued_message(
360 if (queued_messages_.size())
362 boost::shared_ptr<goby::moos::protobuf::SV2CommandFollowFixedHeading> reply =
363 queued_messages_.front();
364 reply->mutable_header()->set_transaction_id(request.header().transaction_id());
365 glog.is(DEBUG1) &&
glog <<
"Sent queued Message reply." << std::endl;
366 glog.is(DEBUG2) &&
glog << reply->DebugString() << std::endl;
367 encode_and_write(*reply);
368 queued_messages_.pop_front();
372 glog.is(WARN) &&
glog <<
"No queued message to provide!" << std::endl;
381 dccl_.encode(&bytes, message);
383 bytes = bytes.substr(2);
385 glog.is(DEBUG2) &&
glog <<
"Sending encoded bytes (w/out escapes): " 386 << dccl::hex_encode(bytes) << std::endl;
387 serial_->write_start(bytes);
389 catch (std::exception& e)
391 glog.is(WARN) &&
glog <<
"Failed to encode and write message: " << e.what() << std::endl;
395 uint16_t crc_compute(
const std::string& buffer,
unsigned offset,
unsigned count, uint16_t seed)
398 for (
unsigned idx = offset; count-- > 0; ++idx)
399 crc = crc_compute_incrementally(crc, buffer[idx]);
403 uint16_t crc_compute_incrementally(uint16_t crc,
char a)
407 for (i = 0; i < 8; i++)
411 crc = (uint16_t)((crc >> 1) ^ 0xA001);
415 crc = (uint16_t)(crc >> 1);
Contains functions for adding color to Terminal window streams.
double goby_time< double >()
Returns current UTC time as seconds and fractional seconds since 1970-01-01 00:00:00.
ReturnType goby_time()
Returns current UTC time as a boost::posix_time::ptime.
common::FlexOstream glog
Access the Goby logger through this object.
The global namespace for the Goby project.