Mercurial > louis > mq > lightsd
view use_echo_request_reply_to_measure_latency.patch @ 556:ac035949357d default tip master
Finish some patches
author | Louis Opter <louis@opter.org> |
---|---|
date | Thu, 18 May 2017 12:09:23 -0700 |
parents | 4e48b4325f12 |
children |
line wrap: on
line source
# HG changeset patch # Parent f97ea54c6a70a4085ae6709851a67fd2486d2ba9 diff --git a/lifx/gateway.c b/lifx/gateway.c --- a/lifx/gateway.c +++ b/lifx/gateway.c @@ -59,6 +59,9 @@ LGTD_STATS_ADD_AND_UPDATE_PROCTITLE(gateways, -1); lgtd_timer_stop(gw->refresh_timer); + if (gw->ping_timer) { + lgtd_timer_stop(gw->ping_timer); + } event_del(gw->write_ev); if (gw->socket != -1) { evutil_closesocket(gw->socket); @@ -227,6 +230,18 @@ } static void +lgtd_lifx_gateway_send_ping_request(struct lgtd_lifx_gateway *gw) +{ + assert(gw); + + struct lgtd_lifx_packet_echo pkt = { { 0 } }; + snprintf( + pkt.payload, sizeof(pkt), "%jx", (uintmax_t)lgtd_time_monotonic_msecs() + ); + lgtd_lifx_gateway_send_to_site_quiet(gw, LGTD_LIFX_ECHO_REQUEST, &pkt); +} + +static void lgtd_lifx_gateway_send_get_all_light_state(struct lgtd_lifx_gateway *gw) { assert(gw); @@ -256,6 +271,31 @@ lgtd_timer_activate(gw->refresh_timer); } +static void +lgtd_lifx_gateway_ping_callback(struct lgtd_timer *timer, + union lgtd_timer_ctx ctx) +{ + (void)timer; + + struct lgtd_lifx_gateway *gw = ctx.as_ptr; + + if (!gw->latency && + lgtd_time_monotonic_msecs() - gw->opened_at + > LGTD_LIFX_GATEWAY_PING_CALLBACK_TIMEOUT_MSECS) { + char site[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "site %s on gateway [%s]:%hu doesn't seem to support ECHO_REQUEST, " + "only the gateway ICMP latency will be measured", + LGTD_IEEE8023MACTOA(gw->site.as_array, site), gw->ip_addr, gw->port + ); + lgtd_timer_stop(timer); + gw->ping_timer = NULL; + return; + } + + lgtd_lifx_gateway_send_ping_request(gw); +} + static struct lgtd_lifx_bulb * lgtd_lifx_gateway_get_or_open_bulb(struct lgtd_lifx_gateway *gw, const uint8_t *bulb_addr) @@ -323,6 +363,7 @@ gw->last_req_at = received_at; gw->next_req_at = received_at; gw->last_pkt_at = received_at; + gw->opened_at = received_at; union lgtd_timer_ctx ctx = { .as_ptr = gw }; gw->refresh_timer = lgtd_timer_start( @@ -331,7 +372,13 @@ lgtd_lifx_gateway_refresh_callback, ctx ); - if (!gw->refresh_timer) { + gw->ping_timer = lgtd_timer_start( + LGTD_TIMER_ACTIVATE_NOW|LGTD_TIMER_PERSISTENT, + LGTD_LIFX_GATEWAY_MIN_PING_INTERVAL_MSECS, + lgtd_lifx_gateway_ping_callback, + ctx + ); + if (!gw->refresh_timer || !gw->ping_timer) { lgtd_warn("can't allocate a new timer"); goto error_allocate; } @@ -353,6 +400,12 @@ return gw; error_allocate: + if (gw->ping_timer) { + lgtd_timer_stop(gw->ping_timer); + } + if (gw->refresh_timer) { + lgtd_timer_stop(gw->refresh_timer); + } if (gw->write_ev) { event_free(gw->write_ev); } @@ -472,6 +525,9 @@ { assert(gw); + if (gw->latency) { + return gw->latency; + } if (gw->last_req_at < gw->last_pkt_at) { // this doesn't look right return gw->last_pkt_at - gw->last_req_at; } @@ -899,3 +955,36 @@ lgtd_lifx_bulb_set_ambient_light, pkt->illuminance ); } + +void +lgtd_lifx_gateway_handle_echo_response(struct lgtd_lifx_gateway *gw, + const struct lgtd_lifx_packet_header *hdr, + const struct lgtd_lifx_packet_echo *pkt) +{ + assert(gw && hdr && pkt); + + char addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "ECHO_RESPONSE <-- [%s]:%hu - %s payload=%.*s", + gw->ip_addr, gw->port, + LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), + LGTD_LIFX_PACKET_ECHO_PAYLOAD_SIZE, pkt->payload + ); + + if (!memchr(pkt->payload, 0, LGTD_LIFX_PACKET_ECHO_PAYLOAD_SIZE)) { + return; + } + + char *endptr = NULL; + lgtd_time_mono_t ping_at = strtoull(pkt->payload, &endptr, 16); + if (!endptr || *endptr != '\0') { + return; + } + + gw->latency = lgtd_time_monotonic_msecs() - ping_at; + + struct timeval tv = LGTD_MSECS_TO_TIMEVAL( + LGTD_LIFX_GATEWAY_MIN_REFRESH_INTERVAL_MSECS + ); + lgtd_timer_reschedule(gw->ping_timer, &tv); +} diff --git a/lifx/gateway.h b/lifx/gateway.h --- a/lifx/gateway.h +++ b/lifx/gateway.h @@ -23,6 +23,9 @@ // still draw about 2W in ZigBee and about 3W in WiFi). enum { LGTD_LIFX_GATEWAY_MIN_REFRESH_INTERVAL_MSECS = 800 }; +enum { LGTD_LIFX_GATEWAY_MIN_PING_INTERVAL_MSECS = 500 }; +enum { LGTD_LIFX_GATEWAY_PING_CALLBACK_TIMEOUT_MSECS = 20000 }; + // You can't send more than one lifx packet per UDP datagram. enum { LGTD_LIFX_GATEWAY_PACKET_RING_SIZE = 16 }; @@ -67,6 +70,10 @@ lgtd_time_mono_t last_req_at; lgtd_time_mono_t next_req_at; lgtd_time_mono_t last_pkt_at; + // But for bulbs with a more recent firmware we can properly measure the + // latency with an ECHO REQUEST packet: + lgtd_time_mono_t latency; + lgtd_time_mono_t opened_at; struct lgtd_lifx_message pkt_ring[LGTD_LIFX_GATEWAY_PACKET_RING_SIZE]; #define LGTD_LIFX_GATEWAY_INC_MESSAGE_RING_INDEX(idx) do { \ (idx) += 1; \ @@ -79,6 +86,7 @@ struct evbuffer *write_buf; bool pending_refresh_req; struct lgtd_timer *refresh_timer; + struct lgtd_timer *ping_timer; }; LIST_HEAD(lgtd_lifx_gateway_list, lgtd_lifx_gateway); @@ -151,3 +159,6 @@ void lgtd_lifx_gateway_handle_ambient_light(struct lgtd_lifx_gateway *, const struct lgtd_lifx_packet_header *, const struct lgtd_lifx_packet_ambient_light *); +void lgtd_lifx_gateway_handle_echo_response(struct lgtd_lifx_gateway *, + const struct lgtd_lifx_packet_header *, + const struct lgtd_lifx_packet_echo *); diff --git a/lifx/wire_proto.c b/lifx/wire_proto.c --- a/lifx/wire_proto.c +++ b/lifx/wire_proto.c @@ -327,6 +327,21 @@ .decode = DECODER(lgtd_lifx_wire_decode_ambient_light), .handle = HANDLER(lgtd_lifx_gateway_handle_ambient_light) }, + { + REQUEST_ONLY, + .encode = lgtd_lifx_wire_null_packet_encoder_decoder, + .name = "ECHO_REQUEST", + .type = LGTD_LIFX_ECHO_REQUEST, + .size = sizeof(struct lgtd_lifx_packet_echo) + }, + { + RESPONSE_ONLY, + .name = "ECHO_RESPONSE", + .type = LGTD_LIFX_ECHO_RESPONSE, + .size = sizeof(struct lgtd_lifx_packet_echo), + .decode = lgtd_lifx_wire_null_packet_encoder_decoder, + .handle = HANDLER(lgtd_lifx_gateway_handle_echo_response) + }, // Unimplemented but "known" packets { UNIMPLEMENTED, @@ -390,16 +405,6 @@ }, { UNIMPLEMENTED, - .name = "ECHO_REQUEST", - .type = LGTD_LIFX_ECHO_REQUEST - }, - { - UNIMPLEMENTED, - .name = "ECHO_RESPONSE", - .type = LGTD_LIFX_ECHO_RESPONSE - }, - { - UNIMPLEMENTED, .name = "SET_DIM_ABSOLUTE", .type = LGTD_LIFX_SET_DIM_ABSOLUTE }, diff --git a/lifx/wire_proto.h b/lifx/wire_proto.h --- a/lifx/wire_proto.h +++ b/lifx/wire_proto.h @@ -303,6 +303,12 @@ floatle_t illuminance; // lux }; +enum { LGTD_LIFX_PACKET_ECHO_PAYLOAD_SIZE = 64 }; + +struct lgtd_lifx_packet_echo { + char payload[LGTD_LIFX_PACKET_ECHO_PAYLOAD_SIZE]; +}; + #pragma pack(pop) enum { LGTD_LIFX_VENDOR_ID = 1 };