26 #include <Wt/Chart/WCartesianChart> 27 #include <Wt/Chart/WDataSeries> 29 #include <Wt/WCheckBox> 31 #include <Wt/WComboBox> 32 #include <Wt/WContainerWidget> 34 #include <Wt/WDoubleSpinBox> 36 #include <Wt/WGroupBox> 38 #include <Wt/WLineEdit> 40 #include <Wt/WPushButton> 41 #include <Wt/WStandardItem> 42 #include <Wt/WStandardItemModel> 45 #include "goby/util/as.h" 46 #include "goby/util/dynamic_protobuf_manager.h" 48 #include "goby/acomms/protobuf/mm_driver.pb.h" 51 #include "liaison_acomms.h" 53 const std::string STRIPE_ODD_CLASS =
"odd";
54 const std::string STRIPE_EVEN_CLASS =
"even";
59 goby::common::LiaisonAcomms::LiaisonAcomms(ZeroMQService* zeromq_service,
60 const protobuf::LiaisonConfig& cfg,
61 Wt::WContainerWidget* parent)
62 : LiaisonContainer(parent), MOOSNode(zeromq_service), zeromq_service_(zeromq_service),
63 cfg_(cfg.GetExtension(protobuf::acomms_config)), have_acomms_config_(false), driver_rx_(RX),
64 driver_tx_(TX), mm_rx_stats_box_(0), mm_rx_stats_range_(600)
66 for (
int i = 0, n = cfg.load_shared_library_size(); i < n; ++i)
67 dccl_.load_library(cfg.load_shared_library(i));
69 protobuf::ZeroMQServiceConfig ipc_sockets;
70 protobuf::ZeroMQServiceConfig::Socket* internal_subscribe_socket = ipc_sockets.add_socket();
71 internal_subscribe_socket->set_socket_type(protobuf::ZeroMQServiceConfig::Socket::SUBSCRIBE);
72 internal_subscribe_socket->set_socket_id(LIAISON_INTERNAL_SUBSCRIBE_SOCKET);
73 internal_subscribe_socket->set_transport(protobuf::ZeroMQServiceConfig::Socket::INPROC);
74 internal_subscribe_socket->set_connect_or_bind(protobuf::ZeroMQServiceConfig::Socket::CONNECT);
75 internal_subscribe_socket->set_socket_name(liaison_internal_publish_socket_name());
77 protobuf::ZeroMQServiceConfig::Socket* internal_publish_socket = ipc_sockets.add_socket();
78 internal_publish_socket->set_socket_type(protobuf::ZeroMQServiceConfig::Socket::PUBLISH);
79 internal_publish_socket->set_socket_id(LIAISON_INTERNAL_PUBLISH_SOCKET);
80 internal_publish_socket->set_transport(protobuf::ZeroMQServiceConfig::Socket::INPROC);
81 internal_publish_socket->set_connect_or_bind(protobuf::ZeroMQServiceConfig::Socket::CONNECT);
82 internal_publish_socket->set_socket_name(liaison_internal_subscribe_socket_name());
84 zeromq_service_->merge_cfg(ipc_sockets);
86 subscribe(
"ACOMMS_CONFIG", LIAISON_INTERNAL_SUBSCRIBE_SOCKET);
87 subscribe(
"ACOMMS_QSIZE", LIAISON_INTERNAL_SUBSCRIBE_SOCKET);
88 subscribe(
"ACOMMS_QUEUE_RECEIVE", LIAISON_INTERNAL_SUBSCRIBE_SOCKET);
89 subscribe(
"ACOMMS_MAC_SLOT_START", LIAISON_INTERNAL_SUBSCRIBE_SOCKET);
90 subscribe(
"ACOMMS_MODEM_TRANSMIT", LIAISON_INTERNAL_SUBSCRIBE_SOCKET);
91 subscribe(
"ACOMMS_MODEM_RECEIVE", LIAISON_INTERNAL_SUBSCRIBE_SOCKET);
93 MOOSNode::send(
CMOOSMsg(MOOS_NOTIFY,
"ACOMMS_CONFIG_REQUEST",
"Request"),
94 LIAISON_INTERNAL_PUBLISH_SOCKET);
96 timer_.setInterval(1 / cfg.update_freq() * 1.0e3);
97 timer_.timeout().connect(
this, &LiaisonAcomms::loop);
99 WPanel* dccl_panel =
new Wt::WPanel(
this);
100 dccl_panel->setTitle(
"DCCL");
101 dccl_panel->setCollapsible(
true);
102 dccl_panel->setCollapsed(cfg_.minimize_dccl());
104 WContainerWidget* dccl_box =
new Wt::WContainerWidget();
105 dccl_panel->setCentralWidget(dccl_box);
106 new WLabel(
"Message: ", dccl_box);
107 dccl_combo_ =
new WComboBox(dccl_box);
109 dccl_combo_->addItem(
"(Choose a message)");
111 dccl_combo_->sactivated().connect(
this, &LiaisonAcomms::dccl_select);
113 dccl_message_ =
new WPushButton(
"Show .proto", dccl_box);
114 dccl_message_->clicked().connect(
this, &LiaisonAcomms::dccl_message);
116 dccl_analyze_ =
new WPushButton(
"Analyze", dccl_box);
117 dccl_analyze_->clicked().connect(
this, &LiaisonAcomms::dccl_analyze);
119 new WBreak(dccl_box);
121 dccl_message_text_ =
new WText(
"", Wt::PlainText, dccl_box);
122 WFont mono(Wt::WFont::Monospace);
123 dccl_message_text_->decorationStyle().setFont(mono);
124 dccl_message_text_->hide();
126 new WBreak(dccl_box);
128 dccl_analyze_text_ =
new WText(
"", Wt::PlainText, dccl_box);
129 dccl_analyze_text_->decorationStyle().setFont(mono);
130 dccl_analyze_text_->hide();
132 WPanel* queue_panel =
new Wt::WPanel(
this);
133 queue_panel->setTitle(
"Queue");
134 queue_panel->setCollapsible(
true);
135 WContainerWidget* queue_box =
new Wt::WContainerWidget();
136 queue_panel->setCentralWidget(queue_box);
137 queue_panel->setCollapsed(cfg_.minimize_queue());
139 queue_table_ =
new Wt::WTable(queue_box);
140 queue_table_->setStyleClass(
"basic_small");
141 queue_table_->setHeaderCount(1);
142 queue_table_->elementAt(0, 0)->addWidget(
new WText(
"DCCL Message"));
143 queue_table_->elementAt(0, 1)->addWidget(
new WText(
"Queue Size"));
144 queue_table_->elementAt(0, 2)->addWidget(
new WText(
"Time since Receive"));
146 WPanel* amac_panel =
new Wt::WPanel(
this);
147 amac_panel->setTitle(
"AMAC");
148 amac_panel->setCollapsible(
true);
149 amac_box_ =
new Wt::WContainerWidget();
150 amac_panel->setCentralWidget(amac_box_);
151 amac_panel->setCollapsed(cfg_.minimize_amac());
153 last_slot_.set_slot_index(-1);
155 driver_panel_ =
new Wt::WPanel(
this);
156 driver_panel_->setTitle(
"Driver");
157 driver_panel_->setCollapsible(
true);
158 driver_box_ =
new Wt::WContainerWidget();
159 driver_panel_->setCentralWidget(driver_box_);
160 driver_panel_->setCollapsed(cfg_.minimize_driver());
162 driver_tx_.box =
new Wt::WGroupBox(
"Transmit", driver_box_);
163 driver_tx_.last_time_text =
new Wt::WText(driver_tx_.box);
164 driver_tx_.box->clicked().connect(
165 boost::bind(&LiaisonAcomms::driver_info,
this, _1, &driver_tx_));
167 driver_rx_.box =
new Wt::WGroupBox(
"Receive", driver_box_);
168 driver_rx_.last_time_text =
new Wt::WText(driver_rx_.box);
169 driver_rx_.box->clicked().connect(
170 boost::bind(&LiaisonAcomms::driver_info,
this, _1, &driver_rx_));
172 set_name(
"MOOSAcomms");
175 void goby::common::LiaisonAcomms::loop()
177 while (zeromq_service_->poll(0)) {}
180 for (std::map<dccl::int32, QueueStats>::const_iterator it = queue_stats_.begin(),
181 end = queue_stats_.end();
184 if (it->second.last_rx_time > 0)
185 it->second.last_rx_time_text->setText(
186 "Last: " + format_seconds(now - it->second.last_rx_time) +
" ago");
188 it->second.last_rx_time_text->setText(
"Never");
191 if (mac_bars_.count(last_slot_.slot_index()))
193 int seconds_into_slot = now -
static_cast<int>(last_slot_.time() / 1e6);
194 mac_bars_[last_slot_.slot_index()]->setValue(seconds_into_slot);
196 int seconds_into_cycle = seconds_into_slot;
197 for (
int i = 0, n = last_slot_.slot_index(); i < n; ++i)
198 seconds_into_cycle += acomms_config_.mac_cfg().slot(i).slot_seconds();
199 mac_cycle_bar_->setValue(seconds_into_cycle);
202 update_driver_stats(now, &driver_rx_);
203 update_driver_stats(now, &driver_tx_);
205 if (mm_rx_stats_box_)
207 for (
int i = mm_rx_stats_model_->rowCount() - 1, n = 0; i >= n; --i)
209 int time = Wt::asNumber(mm_rx_stats_model_->data(i, TIME_COLUMN, DisplayRole));
211 if (elapsed < -mm_rx_stats_range_ - 10)
214 mm_rx_stats_model_->setData(i, ELAPSED_COLUMN, elapsed, DisplayRole);
219 void goby::common::LiaisonAcomms::update_driver_stats(
int now,
220 LiaisonAcomms::DriverStats* driver_stats)
222 if (driver_stats->last_time > 0)
224 driver_stats->last_time_text->setText(
225 "Last: " + format_seconds(now - driver_stats->last_time) +
" ago");
227 if (now - driver_stats->last_time > 10)
228 driver_stats->last_time_text->decorationStyle().setBackgroundColor(Wt::WColor());
232 driver_stats->last_time_text->setText(
"Never");
236 void goby::common::LiaisonAcomms::dccl_analyze(
const WMouseEvent&
event)
238 if (dccl_analyze_text_->isHidden())
240 dccl_analyze_->setText(
"Hide Analysis");
241 dccl_analyze_text_->show();
245 dccl_analyze_->setText(
"Analyze");
246 dccl_analyze_text_->hide();
250 void goby::common::LiaisonAcomms::dccl_message(
const WMouseEvent& event)
252 if (dccl_message_text_->isHidden())
254 dccl_message_->setText(
"Hide .proto");
255 dccl_message_text_->show();
259 dccl_message_->setText(
"Show .proto");
260 dccl_message_text_->hide();
264 void goby::common::LiaisonAcomms::dccl_select(WString msg)
266 std::string m = msg.narrow();
267 m = m.substr(m.find(
" ") + 1);
269 const google::protobuf::Descriptor* desc =
270 goby::util::DynamicProtobufManager::find_descriptor(m);
273 std::stringstream ss;
274 boost::mutex::scoped_lock l(dccl_mutex_);
275 dccl_.info(desc, &ss);
276 dccl_analyze_text_->setText(ss.str());
278 std::string proto = desc->DebugString();
279 boost::replace_all(proto,
"\n",
" ");
280 boost::replace_all(proto,
";",
";\n");
281 boost::replace_all(proto,
"} ",
"}\n");
282 dccl_message_text_->setText(proto);
286 dccl_analyze_text_->setText(
"");
287 dccl_message_text_->setText(
"");
291 void goby::common::LiaisonAcomms::moos_inbox(
CMOOSMsg& msg)
293 using goby::moos::operator<<;
295 if (msg.GetKey() ==
"ACOMMS_CONFIG" && !have_acomms_config_)
297 acomms_config_.ParseFromString(dccl::b64_decode(msg.GetString()));
298 process_acomms_config();
299 have_acomms_config_ =
true;
301 else if (msg.GetKey() ==
"ACOMMS_QSIZE")
306 if (queue_bars_.count(size.dccl_id()))
308 queue_bars_[size.dccl_id()]->setValue(size.size());
311 else if (msg.GetKey() ==
"ACOMMS_QUEUE_RECEIVE")
313 boost::shared_ptr<google::protobuf::Message> dccl_msg =
314 dynamic_parse_for_moos(msg.GetString());
315 if (dccl_msg && queue_stats_.count(dccl_.id(dccl_msg->GetDescriptor())))
317 queue_stats_[dccl_.id(dccl_msg->GetDescriptor())].last_rx_time =
321 else if (msg.GetKey() ==
"ACOMMS_MAC_SLOT_START")
323 if (mac_slots_.count(last_slot_.slot_index()))
325 mac_slots_[last_slot_.slot_index()]->decorationStyle().setBackgroundColor(Wt::WColor());
326 mac_slots_[last_slot_.slot_index()]->decorationStyle().setForegroundColor(Wt::WColor());
328 mac_bars_[last_slot_.slot_index()]->setHidden(
true);
333 if (mac_slots_.count(last_slot_.slot_index()))
336 mac_bars_[last_slot_.slot_index()]->setHidden(
false);
337 mac_slots_[last_slot_.slot_index()]->decorationStyle().setBackgroundColor(goby_orange);
338 mac_slots_[last_slot_.slot_index()]->decorationStyle().setForegroundColor(Wt::white);
341 else if (msg.GetKey() ==
"ACOMMS_MODEM_TRANSMIT")
348 for (
int i = 0, n = tx_msg.ExtensionSize(micromodem::protobuf::transmit_stat); i < n; ++i)
350 tx_good && (tx_msg.GetExtension(micromodem::protobuf::transmit_stat, i).mode() ==
351 micromodem::protobuf::TRANSMIT_SUCCESSFUL);
353 handle_modem_message(&driver_tx_, tx_good, tx_msg);
355 else if (msg.GetKey() ==
"ACOMMS_MODEM_RECEIVE")
361 for (
int i = 0, n = rx_msg.ExtensionSize(micromodem::protobuf::receive_stat); i < n; ++i)
363 rx_good && (rx_msg.GetExtension(micromodem::protobuf::receive_stat, i).mode() ==
364 micromodem::protobuf::RECEIVE_GOOD);
366 handle_modem_message(&driver_rx_, rx_good, rx_msg);
368 for (
int i = 0, n = rx_msg.ExtensionSize(micromodem::protobuf::receive_stat); i < n; ++i)
371 rx_msg.GetExtension(micromodem::protobuf::receive_stat, i);
373 if (rx_stats.packet_type() != micromodem::protobuf::PSK)
376 std::vector<WStandardItem*> row;
377 WStandardItem* time =
new WStandardItem;
378 time->setData(rx_stats.time() / 1e6, DisplayRole);
381 WStandardItem* elapsed =
new WStandardItem;
382 elapsed->setData(0, DisplayRole);
383 row.push_back(elapsed);
385 WStandardItem* mse =
new WStandardItem;
386 mse->setData(rx_stats.mse_equalizer(), DisplayRole);
389 WStandardItem* snr_in =
new WStandardItem;
390 snr_in->setData(rx_stats.snr_in(), DisplayRole);
391 row.push_back(snr_in);
393 WStandardItem* snr_out =
new WStandardItem;
394 snr_out->setData(rx_stats.snr_out(), DisplayRole);
395 row.push_back(snr_out);
397 WStandardItem* doppler =
new WStandardItem;
398 doppler->setData(rx_stats.doppler(), DisplayRole);
399 row.push_back(doppler);
401 WStandardItem* bad_frames =
new WStandardItem;
402 bad_frames->setData(
double(rx_stats.number_bad_frames()) / rx_stats.number_frames() *
405 row.push_back(bad_frames);
407 mm_rx_stats_model_->appendRow(row);
412 void goby::common::LiaisonAcomms::handle_modem_message(
413 LiaisonAcomms::DriverStats* driver_stats,
bool good,
416 driver_stats->last_time = msg.time() / 1e6;
419 driver_stats->last_time_text->decorationStyle().setBackgroundColor(goby_blue);
421 driver_stats->last_time_text->decorationStyle().setBackgroundColor(goby_orange);
423 driver_stats->last_msg_ = msg;
426 void goby::common::LiaisonAcomms::process_acomms_config()
428 boost::mutex::scoped_lock l(dccl_mutex_);
431 for (
int i = 0, n = acomms_config_.queue_cfg().message_entry_size(); i < n; ++i)
434 acomms_config_.queue_cfg().message_entry(i);
436 const google::protobuf::Descriptor* desc =
437 goby::util::DynamicProtobufManager::find_descriptor(q.protobuf_name());
442 int id = dccl_.id(desc);
445 glog.is(DEBUG1) &&
glog <<
"Loaded: " << desc <<
": " << q.protobuf_name() << std::endl;
447 int row = queue_table_->rowCount();
448 queue_table_->elementAt(row, 0)->addWidget(
new WText(q.protobuf_name()));
449 QueueBar* new_bar =
new QueueBar;
450 queue_table_->elementAt(row, 1)->addWidget(new_bar);
452 new_bar->setMinimum(0);
453 new_bar->setMaximum(q.max_queue());
455 queue_bars_[id] = new_bar;
457 QueueStats new_stats;
458 new_stats.last_rx_time_text =
459 new WText(goby::util::as<std::string>(new_stats.last_rx_time));
460 queue_table_->elementAt(row, 2)->addWidget(new_stats.last_rx_time_text);
461 queue_stats_[id] = new_stats;
463 WPushButton* info =
new WPushButton(
"Info");
464 info->clicked().connect(boost::bind(&LiaisonAcomms::queue_info,
this, _1,
id));
465 queue_table_->elementAt(row, 3)->addWidget(info);
467 WPushButton* flush =
new WPushButton(
"Clear");
468 flush->clicked().connect(boost::bind(&LiaisonAcomms::queue_flush,
this, _1,
id));
469 queue_table_->elementAt(row, 4)->addWidget(flush);
472 queue_table_->rowAt(row)->setStyleClass(STRIPE_ODD_CLASS);
474 queue_table_->rowAt(row)->setStyleClass(STRIPE_EVEN_CLASS);
478 glog.is(WARN) &&
glog <<
"Cannot find message: " << q.protobuf_name() << std::endl;
483 for (std::map<dccl::int32, const google::protobuf::Descriptor*>::const_iterator
484 it = dccl_.loaded().begin(),
485 it_end = dccl_.loaded().end();
488 dccl_combo_->addItem(
489 std::string(goby::util::as<std::string>(it->first) +
": " + it->second->full_name()));
492 Wt::WContainerWidget* mac_top_box =
new Wt::WContainerWidget(amac_box_);
494 new Wt::WText(
"Number of slots in the cycle: " +
495 goby::util::as<std::string>(acomms_config_.mac_cfg().slot_size()) +
".",
497 mac_cycle_bar_ =
new MACBar(mac_top_box);
498 mac_cycle_bar_->setMinimum(0);
499 int cycle_length = 0;
500 for (
int i = 0, n = acomms_config_.mac_cfg().slot_size(); i < n; ++i)
501 cycle_length += acomms_config_.mac_cfg().slot(i).slot_seconds();
503 mac_cycle_bar_->setMaximum(cycle_length);
504 mac_cycle_bar_->setFloatSide(Wt::Right);
506 new Wt::WText(
"<hr/>", mac_top_box);
508 mac_slot_style_.setBorder(Wt::WBorder(Wt::WBorder::Solid, Wt::WBorder::Thin));
509 for (
int i = 0, n = acomms_config_.mac_cfg().slot_size(); i < n; ++i)
513 Wt::WContainerWidget* box =
new Wt::WContainerWidget(amac_box_);
514 box->setDecorationStyle(mac_slot_style_);
515 box->clicked().connect(boost::bind(&LiaisonAcomms::mac_info,
this, _1, i));
517 double height = std::log10(slot.slot_seconds());
518 box->setPadding(Wt::WLength(height / 2, Wt::WLength::FontEm), Wt::Top | Wt::Bottom);
519 box->setPadding(Wt::WLength(3), Wt::Right | Wt::Left);
520 box->setMargin(Wt::WLength(3));
521 box->resize(Wt::WLength(), Wt::WLength(1 + height, Wt::WLength::FontEm));
523 std::string slot_text;
524 if (slot.type() == goby::acomms::protobuf::ModemTransmission::UNKNOWN)
526 slot_text =
"Non-Acomms Slot";
527 if (slot.has_unique_id())
528 slot_text +=
" (" + goby::util::as<std::string>(slot.unique_id()) +
")";
530 else if (slot.type() == goby::acomms::protobuf::ModemTransmission::DATA)
532 std::stringstream ss;
533 ss <<
"Data Slot | Source: " << slot.src();
534 if (slot.dest() != -1)
535 ss <<
" | Dest: " << slot.dest();
536 ss <<
" | Rate: " << slot.rate();
537 slot_text = ss.str();
541 slot_text = slot.DebugString();
544 new Wt::WText(slot_text, box);
548 MACBar* new_bar =
new MACBar(box);
549 new_bar->setMinimum(0);
550 new_bar->setMaximum(slot.slot_seconds());
551 new_bar->setFloatSide(Wt::Right);
552 new_bar->setHidden(
true);
554 mac_bars_[i] = new_bar;
561 driver_panel_->setTitle(
"Driver: " +
562 goby::acomms::protobuf::DriverType_Name(acomms_config_.driver_type()));
564 if (acomms_config_.driver_type() == goby::acomms::protobuf::DRIVER_WHOI_MICROMODEM)
566 mm_rx_stats_box_ =
new WGroupBox(
"WHOI Micro-Modem Receive Statistics", driver_box_);
567 mm_rx_stats_model_ =
new WStandardItemModel(0, MAX_COLUMN + 1, mm_rx_stats_box_);
569 mm_rx_stats_graph_ =
new Chart::WCartesianChart(Chart::ScatterPlot, mm_rx_stats_box_);
570 mm_rx_stats_graph_->setModel(mm_rx_stats_model_);
571 mm_rx_stats_graph_->setXSeriesColumn(ELAPSED_COLUMN);
573 for (
int i = MSE_COLUMN, n = MAX_COLUMN; i <= n; ++i)
575 Chart::WDataSeries s(i, Chart::LineSeries);
576 Chart::MarkerType type;
580 case MSE_COLUMN: type = Chart::CircleMarker;
break;
581 case SNR_IN_COLUMN: type = Chart::SquareMarker;
break;
582 case SNR_OUT_COLUMN: type = Chart::CrossMarker;
break;
583 case DOPPLER_COLUMN: type = Chart::TriangleMarker;
break;
584 case PERCENT_BAD_FRAMES_COLUMN: type = Chart::XCrossMarker;
break;
588 mm_rx_stats_graph_->addSeries(s);
591 mm_rx_stats_graph_->axis(Chart::XAxis).setTitle(
"Seconds ago");
593 mm_rx_stats_model_->setHeaderData(MSE_COLUMN, std::string(
"MSE"));
594 mm_rx_stats_model_->setHeaderData(SNR_IN_COLUMN, std::string(
"SNR In"));
595 mm_rx_stats_model_->setHeaderData(SNR_OUT_COLUMN, std::string(
"SNR Out"));
596 mm_rx_stats_model_->setHeaderData(DOPPLER_COLUMN, std::string(
"Doppler"));
597 mm_rx_stats_model_->setHeaderData(PERCENT_BAD_FRAMES_COLUMN, std::string(
"% bad frames"));
599 mm_rx_stats_graph_->setPlotAreaPadding(120, Right);
600 mm_rx_stats_graph_->setPlotAreaPadding(50, Left);
601 mm_rx_stats_graph_->setPlotAreaPadding(40, Top | Bottom);
602 mm_rx_stats_graph_->setMargin(10, Top | Bottom);
603 mm_rx_stats_graph_->setMargin(WLength::Auto, Left | Right);
604 mm_rx_stats_graph_->resize(Wt::WLength(40, Wt::WLength::FontEm), 300);
606 mm_rx_stats_graph_->setLegendEnabled(
true);
608 mm_range(mm_rx_stats_range_);
610 mm_rx_stats_graph_->axis(Chart::Y1Axis).setVisible(
false);
611 mm_rx_stats_graph_->axis(Chart::Y1Axis).setVisible(
false);
613 WGroupBox* y1axis_group =
new Wt::WGroupBox(
"Y1 Axis", mm_rx_stats_box_);
614 y1axis_group->resize(Wt::WLength(45, Wt::WLength::Percentage), Wt::WLength::Auto);
615 y1axis_group->setInline(
true);
616 WGroupBox* y2axis_group =
new Wt::WGroupBox(
"Y2 Axis", mm_rx_stats_box_);
617 y2axis_group->resize(Wt::WLength(45, Wt::WLength::Percentage), Wt::WLength::Auto);
618 y2axis_group->setInline(
true);
619 for (
int i = MSE_COLUMN, n = MAX_COLUMN; i <= n; ++i)
621 for (
int j = 0, m = 2; j < m; ++j)
623 mm_rx_chks_[i][j] =
new WCheckBox(asString(mm_rx_stats_model_->headerData(i)),
624 j == 0 ? y1axis_group : y2axis_group);
625 mm_rx_chks_[i][j]->resize(Wt::WLength(40, Wt::WLength::Percentage),
628 mm_rx_chks_[i][j]->checked().connect(
629 boost::bind(&LiaisonAcomms::mm_check,
this, j, i,
true));
630 mm_rx_chks_[i][j]->unChecked().connect(
631 boost::bind(&LiaisonAcomms::mm_check,
this, j, i,
false));
635 mm_rx_chks_[MSE_COLUMN][0]->setChecked(
true);
636 mm_check(0, MSE_COLUMN,
true);
638 new Wt::WBreak(mm_rx_stats_box_);
640 new Wt::WText(
"X Axis Range (seconds):", mm_rx_stats_box_);
642 WDoubleSpinBox* range_box =
new WDoubleSpinBox(mm_rx_stats_box_);
643 range_box->setMinimum(10);
644 range_box->setMaximum(1e100);
645 range_box->setSingleStep(600);
646 range_box->setDecimals(0);
647 range_box->setValue(mm_rx_stats_range_);
648 range_box->valueChanged().connect(
this, &LiaisonAcomms::mm_range);
652 void goby::common::LiaisonAcomms::mm_check(
int axis,
int column,
bool checked)
654 std::cout <<
"Axis: " << axis <<
", column: " << column <<
", check: " << checked << std::endl;
656 Chart::WDataSeries& s = mm_rx_stats_graph_->series(column);
657 s.setHidden(!checked);
658 s.bindToAxis(axis == 0 ? Chart::Y1Axis : Chart::Y2Axis);
662 mm_rx_chks_[column][axis == 0 ? 1 : 0]->setChecked(
false);
664 bool axis_enabled[2] = {
false,
false};
665 for (std::map<
int, std::map<int, Wt::WCheckBox*> >::iterator it = mm_rx_chks_.begin(),
666 end = mm_rx_chks_.end();
669 for (
int i = 0, n = 2; i < n; ++i)
671 if (it->second[i]->isChecked())
672 axis_enabled[i] =
true;
676 for (
int i = 0, n = 2; i < n; ++i)
677 mm_rx_stats_graph_->axis(i == 0 ? Chart::Y1Axis : Chart::Y2Axis)
678 .setVisible(axis_enabled[i]);
681 void goby::common::LiaisonAcomms::mm_range(
double range)
683 mm_rx_stats_range_ = range;
684 mm_rx_stats_graph_->axis(Chart::XAxis).setRange(-mm_rx_stats_range_, 0);
685 mm_rx_stats_graph_->axis(Chart::XAxis).setLabelInterval(mm_rx_stats_range_ / 5);
688 Wt::WString goby::common::QueueBar::text()
const 690 return std::string(goby::util::as<std::string>(value()) +
"/" +
691 goby::util::as<std::string>(maximum()));
694 Wt::WString goby::common::MACBar::text()
const 696 return std::string(goby::util::as<std::string>(value()) +
"/" +
697 goby::util::as<std::string>(maximum()) +
" s");
700 void goby::common::LiaisonAcomms::queue_info(
const Wt::WMouseEvent& event,
int id)
702 const google::protobuf::Descriptor* desc = 0;
704 boost::mutex::scoped_lock l(dccl_mutex_);
705 if (dccl_.loaded().count(
id))
706 desc = dccl_.loaded().find(
id)->second;
712 glog.is(DEBUG1) &&
glog <<
"Queue info for " << desc->full_name() << std::endl;
714 WDialog dialog(
"Queue info for " + desc->full_name());
715 WContainerWidget* message_div =
new WContainerWidget(dialog.contents());
716 new WText(std::string(
"<pre>" +
717 acomms_config_.queue_cfg().message_entry(queue_cfg_[
id]).DebugString() +
721 message_div->setOverflow(WContainerWidget::OverflowAuto);
723 WPushButton ok(
"OK", dialog.contents());
725 dialog.rejectWhenEscapePressed();
726 ok.clicked().connect(&dialog, &WDialog::accept);
728 if (dialog.exec() == WDialog::Accepted) {}
731 void goby::common::LiaisonAcomms::mac_info(
const Wt::WMouseEvent& event,
int id)
733 WDialog dialog(
"AMAC Slot Info for Slot #" + goby::util::as<std::string>(
id));
734 WContainerWidget* message_div =
new WContainerWidget(dialog.contents());
735 new WText(std::string(
"<pre>" + acomms_config_.mac_cfg().slot(
id).DebugString() +
"</pre>"),
738 message_div->setOverflow(WContainerWidget::OverflowAuto);
740 WPushButton ok(
"OK", dialog.contents());
742 dialog.rejectWhenEscapePressed();
743 ok.clicked().connect(&dialog, &WDialog::accept);
745 if (dialog.exec() == WDialog::Accepted) {}
748 void goby::common::LiaisonAcomms::driver_info(
const Wt::WMouseEvent& event,
749 LiaisonAcomms::DriverStats* driver_stats)
751 WDialog dialog(
"Last Message " +
752 std::string(driver_stats->direction == RX ?
"Received" :
"Transmitted"));
753 WContainerWidget* message_div =
new WContainerWidget(dialog.contents());
754 WText* txt =
new WText(std::string(driver_stats->last_msg_.DebugString()), message_div);
755 txt->setTextFormat(PlainText);
757 message_div->setMaximumSize(800, 600);
758 message_div->setOverflow(WContainerWidget::OverflowAuto);
760 WPushButton ok(
"OK", dialog.contents());
762 dialog.rejectWhenEscapePressed();
763 ok.clicked().connect(&dialog, &WDialog::accept);
765 if (dialog.exec() == WDialog::Accepted) {}
768 void goby::common::LiaisonAcomms::queue_flush(
const Wt::WMouseEvent& event,
int id)
771 flush.set_dccl_id(
id);
772 std::string serialized;
773 serialize_for_moos(&serialized, flush);
775 MOOSNode::send(
CMOOSMsg(MOOS_NOTIFY,
"ACOMMS_FLUSH_QUEUE", serialized),
776 LIAISON_INTERNAL_PUBLISH_SOCKET);
779 std::string goby::common::LiaisonAcomms::format_seconds(
int sec)
782 return goby::util::as<std::string>(sec) +
" s";
784 return goby::util::as<std::string>(sec / 60) +
":" + ((sec % 60 < 10) ?
"0" :
"") +
785 goby::util::as<std::string>(sec % 60);
void parse_for_moos(const std::string &in, google::protobuf::Message *msg)
Parses the string in to Google Protocol Buffers message msg. All errors are written to the goby::util...
Helpers for MOOS applications for serializing and parsed Google Protocol buffers messages.
double goby_time< double >()
Returns current UTC time as seconds and fractional seconds since 1970-01-01 00:00:00.
common::FlexOstream glog
Access the Goby logger through this object.