#pragma once #include #include #include #include #include "wire.h" #include "timer_queue.h" #include "eth.h" #include "ipv4.h" #include "prepend_buffer.h" #include "udp.h" uint16_t dispatch_listen_port_be(); struct responder { uint32_t message_id; udp::address reply_to; template void respond(const T& msg) const { prepend_buffer<4096> buf; span_writer out(buf.payload_ptr(), 2048); auto r = encode_response_into(out, message_id, msg); if (!r) { return; } buf.append(*r); udp::prepend(buf, reply_to.mac, eth::get_mac(), ipv4::get_ip(), reply_to.ip, dispatch_listen_port_be(), reply_to.port, *r); eth::send_raw(buf.span()); } }; using handler_fn = void (*)(const responder& resp, std::span payload); struct handler_entry { int8_t type_id; handler_fn handle; }; template void typed_handler(const responder& resp, std::span payload) { msgpack::parser p(payload.data(), static_cast(payload.size())); Req req; auto tup = req.as_tuple(); auto r = msgpack::unpack(p, tup); if (!r) { char err[64]; snprintf(err, sizeof(err), "decode request ext_id=%d: msgpack error %d", Req::ext_id, static_cast(r.error())); resp.respond(DeviceError{1, err}); return; } auto result = Fn(resp, req); if (result) resp.respond(*result); } void dispatch_init(uint16_t listen_port_be); timer_handle dispatch_schedule_ms(uint32_t ms, void (*fn)()); bool dispatch_cancel_timer(timer_handle h); [[noreturn]] void dispatch_run(std::span handlers);