1#include "device/referee/referee.h"
5using namespace roboctrl;
8bool referee::init(
const info_type& info) {
9 if (configured_)
throw std::logic_error(
"referee already initialized");
10 if (info.serial_name.empty() || info.offline_timeout <= std::chrono::steady_clock::duration::zero() ||
11 info.ui_period < std::chrono::milliseconds{100})
12 throw std::invalid_argument(
"referee needs serial, positive timeout and UI period >= 100 ms");
17void referee::connect() {
18 if (connected_)
return;
19 if (!configured_)
throw std::logic_error(
"referee connect before init");
20 serial_ = &get<io::serial>(info_.serial_name);
24void referee::start() {
26 if (!connected_)
throw std::logic_error(
"referee start before connect");
28 if (info_.ui_enabled)
spawn(task());
30bool referee::offline()
const {
31 const auto now = referee_protocol::clock::now();
32 return !configured_ || !received_at_ ||
now < *received_at_ ||
now - *received_at_ > info_.offline_timeout;
35 parser_.feed(data, [
this](
const auto& frame) {
36 const auto now = referee_protocol::clock::now();
37 if (state_.accept(frame, now)) received_at_ = now;
38 if (frame_callback_) frame_callback_(frame);
41std::optional<std::pair<std::uint16_t, std::uint16_t>> referee::ui_addresses()
const {
42 if (!connected_ || !info_.ui_enabled ||
43 !state_.robot.fresh(referee_protocol::clock::now(), info_.offline_timeout))
return std::nullopt;
44 const std::uint16_t sender = state_.robot.value.robot_id;
45 const auto receiver = info_.ui_receiver_id != 0 ? std::optional{info_.ui_receiver_id} : referee_protocol::client_id(sender);
46 if (!receiver)
return std::nullopt;
47 return std::pair{sender, *receiver};
49awaitable<void> referee::send_graphics(std::span<const referee_protocol::graphic> items) {
50 if (
const auto addresses = ui_addresses()) {
51 const auto frame = referee_protocol::encode_graphics(items, addresses->first, addresses->second, sequence_++);
52 co_await serial_->send_raw(frame);
56 if (
const auto addresses = ui_addresses()) {
57 const auto frame = referee_protocol::encode_text(item, text, addresses->first, addresses->second, sequence_++);
58 co_await serial_->send_raw(frame);
61awaitable<void> referee::delete_graphics(std::uint8_t operation, std::uint8_t layer) {
62 if (
const auto addresses = ui_addresses()) {
63 const auto frame = referee_protocol::encode_delete(operation, layer, addresses->first, addresses->second, sequence_++);
64 co_await serial_->send_raw(frame);
70 if (
const auto addresses = ui_addresses()) {
71 const auto graphics = referee_protocol::status_graphics(ui_status_, refresh.add_required(*addresses));
74 const auto frame = referee_protocol::encode_graphics(
75 graphics, addresses->first, addresses->second, sequence_++);
76 co_await serial_->send_raw(frame);
77 refresh.submitted(*addresses);
void receive(referee_protocol::bytes data)
void on_raw_data(callback_fn< byte_span > auto fn)
std::span< const std::byte > byte_span
只读 byte span。
awaitable< void > wait_for(const duration &duration)
协程任务等待。
auto spawn(task_context::task_type &&task)
添加一个协程任务到全局任务上下文中执行。
asio::awaitable< T > awaitable
协程任务类型。
auto now()
记录程序启动后的纳秒级时间戳。