24 return static_cast<uint32_t
>(std::chrono::duration_cast<std::chrono::milliseconds>(
25 std::chrono::steady_clock::now().time_since_epoch())
37 uint32_t done_delay_ms,
const std::string& bind_address) {
38 struct in_addr parsed{};
39 if (inet_pton(AF_INET, broadcast_ip.c_str(), &parsed) != 1) {
40 std::cerr <<
"[AbortBroadcaster] invalid broadcast address '" << broadcast_ip <<
"'"
54 std::cerr <<
"[AbortBroadcaster] WARNING: aborting to the limited broadcast "
55 "255.255.255.255 — set [server_heartbeat].broadcast_ip to the board subnet "
56 "(e.g. 192.168.2.255) or the kernel picks the egress interface"
59 std::cout <<
"[AbortBroadcaster] ABORT/ABORT_DONE/CLEAR_ABORT -> " <<
dest_ip_ <<
":" <<
port_
75 daq::PacketHeader hdr{};
78 hdr.timestamp = host_timestamp_ms();
80 int sock = socket(AF_INET, SOCK_DGRAM, 0);
82 std::cerr <<
"[AbortBroadcaster] socket() failed" << std::endl;
87 setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(broadcast));
92 std::cerr <<
"[AbortBroadcaster] continuing unpinned — the broadcast may leave on the "
98 struct timeval tv{.tv_sec = 0, .tv_usec = 100000};
99 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv,
sizeof(tv));
101 struct sockaddr_in dest{};
102 dest.sin_family = AF_INET;
103 dest.sin_port = htons(
port_);
106 const char* type_name = (packet_type_byte == 7) ?
"ABORT"
107 : (packet_type_byte == 8) ?
"ABORT_DONE"
108 : (packet_type_byte == 9) ?
"CLEAR_ABORT"
115 ssize_t sent = sendto(sock, &hdr,
sizeof(hdr), 0,
reinterpret_cast<struct sockaddr*
>(&dest),
117 if (sent ==
static_cast<ssize_t
>(
sizeof(hdr)))
120 std::cerr <<
"[AbortBroadcaster] sendto(" << type_name <<
") repeat " << (i + 1)
121 <<
" failed: " << strerror(errno) << std::endl;
128 std::cout <<
"[AbortBroadcaster] Sent " << type_name <<
" broadcast (" <<
dest_ip_ <<
":"
132 std::cerr <<
"[AbortBroadcaster] " << type_name <<
" broadcast FAILED — no repeat left the "
133 <<
"host" << std::endl;
149 if (
done_thread_.get_id() == std::this_thread::get_id())
164 const auto step = std::chrono::milliseconds(50);
165 auto elapsed = std::chrono::milliseconds(0);
168 std::this_thread::sleep_for(step);
void waitAndSendAbortDone()
std::mutex done_thread_mutex_
void sendPacket(uint8_t packet_type)
std::string bind_address_
uint32_t abort_done_delay_ms_
void triggerAbort()
Send ABORT broadcast and schedule ABORT_DONE after abort_done_delay_ms.
std::atomic< bool > done_thread_running_
static constexpr int kBroadcastGapUs
static constexpr int kBroadcastRepeats
How many times each broadcast is repeated, and the gap between repeats.
bool configure(const std::string &broadcast_ip, uint16_t port, uint32_t done_delay_ms, const std::string &bind_address)
Adopt the destination and source NIC from config.
AbortBroadcaster(uint16_t port=5005, uint32_t abort_done_delay_ms=3000)
void sendClearAbort()
Send CLEAR_ABORT broadcast (called when leaving abort states).
static const emmc_port_t port
PacketType
Defines the type of data contained in a packet.
bool bindToDaqInterface(int sock, const std::string &address, const char *who)
bind() an already-created socket to address on an ephemeral port.
uint32_t host_timestamp_ms()
static bool elapsed(uint32_t now, uint32_t then, uint32_t interval)