Mercurial > louis > mq > lightsd
changeset 253:aecc19ba45d9
patch reorg
author | Louis Opter <kalessin@kalessin.fr> |
---|---|
date | Sun, 16 Aug 2015 00:48:06 -0700 |
parents | 953786a62e00 |
children | 320dbe44d3f6 |
files | add_ipv4_to_ieee8023mac.patch add_start_stop_timer.patch blublu expose_a_bunch_of_metadata_in_get_light_state.patch fix_addrtoa_mess.patch fix_sockaddrtoa_mess.patch implement_some_metadata_packet_types.patch make_device_timeout_2_5x_force_refresh.patch series |
diffstat | 9 files changed, 1922 insertions(+), 2046 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/add_ipv4_to_ieee8023mac.patch Sun Aug 16 00:48:06 2015 -0700 @@ -0,0 +1,118 @@ +# HG changeset patch +# Parent cb2ea88a7a426fb93e3c781fbc146126e574a9de + +diff --git a/core/proto.c b/core/proto.c +--- a/core/proto.c ++++ b/core/proto.c +@@ -202,11 +202,13 @@ + struct lgtd_lifx_bulb *bulb = device->device; + + char buf[2048], ++ gw_addr[LGTD_LIFX_ADDR_STRLEN], + site_addr[LGTD_LIFX_ADDR_STRLEN], + bulb_addr[LGTD_LIFX_ADDR_STRLEN]; + int i = 0; + + LGTD_IEEE8023MACTOA(bulb->addr, bulb_addr); ++ LGTD_IEEE8023MACTOA(bulb->gw->addr, gw_addr); + LGTD_IEEE8023MACTOA(bulb->gw->site.as_array, site_addr); + + LGTD_SNPRINTF_APPEND( +@@ -215,11 +217,12 @@ + "\"_lifx\":{" + "\"addr\": \"%s\"," + "\"gateway\":{" ++ "\"addr\":\"%s\"," + "\"site\":\"%s\"," + "\"url\":\"tcp://[%s]:%hu\"," + "\"latency\":%ju" + "},", +- bulb_addr, site_addr, ++ bulb_addr, gw_addr, site_addr, + bulb->gw->ip_addr, bulb->gw->port, + (uintmax_t)LGTD_LIFX_GATEWAY_LATENCY(bulb->gw) + ); +diff --git a/lifx/gateway.c b/lifx/gateway.c +--- a/lifx/gateway.c ++++ b/lifx/gateway.c +@@ -15,12 +15,15 @@ + // You should have received a copy of the GNU General Public License + // along with lighstd. If not, see <http://www.gnu.org/licenses/>. + ++#include <sys/ioctl.h> + #include <sys/queue.h> ++#include <sys/socket.h> + #include <sys/tree.h> + #include <assert.h> + #include <endian.h> + #include <err.h> + #include <errno.h> ++#include <net/if_arp.h> + #include <stdarg.h> + #include <stdbool.h> + #include <stdint.h> +@@ -279,6 +282,28 @@ + return bulb; + } + ++// TODO: make a separate shared library to resolve ip addresses to mac ++// addresses: ++static bool ++lgtd_lifx_gateway_resolve_ipv4_addr(int socket, ++ const struct sockaddr_in *sin, ++ uint8_t *hw_addr) ++{ ++ assert(sin); ++ assert(hw_addr); ++ assert(socket >= 0); ++ ++ struct arpreq req; ++ memset(&req, 0, sizeof(req)); ++ memcpy(&req.arp_pa, sin, sizeof(*sin)); ++ memcpy(req.arp_dev, "br0", 4); ++ if (!ioctl(socket, SIOCGARP, &req)) { ++ memcpy(hw_addr, req.arp_ha.sa_data, LGTD_LIFX_ADDR_LENGTH); ++ return true; ++ } ++ return false; ++} ++ + struct lgtd_lifx_gateway * + lgtd_lifx_gateway_open(const struct sockaddr_storage *peer, + ev_socklen_t addrlen, +@@ -314,10 +339,20 @@ + gw->refresh_ev = evtimer_new( + lgtd_ev_base, lgtd_lifx_gateway_refresh_callback, gw + ); ++ + memcpy(&gw->peer, peer, sizeof(gw->peer)); + lgtd_sockaddrtoa(peer, gw->ip_addr, sizeof(gw->ip_addr)); + gw->port = lgtd_sockaddrport(peer); + memcpy(gw->site.as_array, site, sizeof(gw->site.as_array)); ++ if (peer->ss_family == AF_INET) { ++ bool ok = lgtd_lifx_gateway_resolve_ipv4_addr( ++ gw->socket, (const struct sockaddr_in *)peer, gw->addr ++ ); ++ if (!ok) { ++ lgtd_warn("couldn't resolve %s to a LIFX address", gw->ip_addr); ++ } ++ } ++ + gw->last_req_at = received_at; + gw->next_req_at = received_at; + gw->last_pkt_at = received_at; +@@ -332,11 +367,11 @@ + goto error_allocate; + } + +- char site_addr[LGTD_LIFX_ADDR_STRLEN]; ++ char site_addr[LGTD_LIFX_ADDR_STRLEN], addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( +- "gateway for site %s at [%s]:%hu", ++ "gateway for site %s at [%s]:%hu (%s)", + LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr), +- gw->ip_addr, gw->port ++ gw->ip_addr, gw->port, LGTD_IEEE8023MACTOA(gw->addr, addr) + ); + LIST_INSERT_HEAD(&lgtd_lifx_gateways, gw, link); +
--- a/add_start_stop_timer.patch Sat Aug 15 23:22:19 2015 -0700 +++ b/add_start_stop_timer.patch Sun Aug 16 00:48:06 2015 -0700 @@ -1,5 +1,5 @@ # HG changeset patch -# Parent bddbeba717a2c01b12f3818c0d3b24ae72066f3c +# Parent e9bbea56e55f41d6bf2f774208408c8f7e9395bd Add an interface to start and stop standalone timers diff --git a/lifx/timer.c b/lifx/timer.c @@ -100,7 +100,7 @@ -enum { LGTD_LIFX_TIMER_WATCHDOG_INTERVAL_MSECS = 500 }; -enum { LGTD_LIFX_TIMER_ACTIVE_DISCOVERY_INTERVAL_MSECS = 2000 }; -enum { LGTD_LIFX_TIMER_PASSIVE_DISCOVERY_INTERVAL_MSECS = 10000 }; --enum { LGTD_LIFX_TIMER_DEVICE_TIMEOUT_MSECS = 3000 }; +-enum { LGTD_LIFX_TIMER_DEVICE_TIMEOUT_MSECS = 5000 }; -enum { LGTD_LIFX_TIMER_DEVICE_FORCE_REFRESH_MSECS = 2000 }; +enum { + LGTD_LIFX_TIMER_WATCHDOG_INTERVAL_MSECS = 500,
--- a/blublu Sat Aug 15 23:22:19 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -# HG changeset patch -# Parent cf311c1e428a6bccd48b7fb7ca82715fb493ae0b - -diff --git a/lifx/gateway.c b/lifx/gateway.c ---- a/lifx/gateway.c -+++ b/lifx/gateway.c -@@ -285,6 +285,7 @@ - const struct sockaddr_in *sin, - uint8_t *hw_addr) - { -+#if 0 - assert(sin); - assert(hw_addr); - assert(socket >= 0); -@@ -296,6 +297,7 @@ - memcpy(hw_addr, req.arp_ha.sa_data, LGTD_LIFX_ADDR_LENGTH); - return true; - } -+#endif - return false; - } -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/expose_a_bunch_of_metadata_in_get_light_state.patch Sun Aug 16 00:48:06 2015 -0700 @@ -0,0 +1,1312 @@ +# HG changeset patch +# Parent 20f6402b334b0f32e6f7b8efe65a421a3c5fdb97 + +diff --git a/core/daemon.c b/core/daemon.c +--- a/core/daemon.c ++++ b/core/daemon.c +@@ -106,10 +106,9 @@ + char title[LGTD_DAEMON_TITLE_SIZE] = { 0 }; + int i = 0; + +-#define TITLE_APPEND(fmt, ...) do { \ +- int n = snprintf((&title[i]), (sizeof(title) - i), (fmt), __VA_ARGS__); \ +- i = LGTD_MIN(i + n, (int)sizeof(title)); \ +-} while (0) ++#define TITLE_APPEND(fmt, ...) LGTD_SNPRINTF_APPEND( \ ++ title, i, (int)sizeof(title), (fmt), __VA_ARGS__ \ ++) + + #define PREFIX(fmt, ...) TITLE_APPEND( \ + "%s" fmt, (i && title[i - 1] == ')' ? "; " : ""), __VA_ARGS__ \ +diff --git a/core/lightsd.h b/core/lightsd.h +--- a/core/lightsd.h ++++ b/core/lightsd.h +@@ -24,10 +24,33 @@ + #define LGTD_ABS(v) ((v) >= 0 ? (v) : (v) * -1) + #define LGTD_MIN(a, b) ((a) < (b) ? (a) : (b)) + #define LGTD_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) +-#define LGTD_MSECS_TO_TIMEVAL(v) { \ ++#define LGTD_MSECS_TO_TIMEVAL(v) { \ + .tv_sec = (v) / 1000, \ + .tv_usec = ((v) % 1000) * 1000 \ + } ++#define LGTD_NSECS_TO_USECS(v) ((v) / (unsigned int)1E6) ++#define LGTD_NSECS_TO_SECS(v) ((v) / (unsigned int)1E9) ++#define LGTD_SECS_TO_NSECS(v) ((v) * (unsigned int)1E9) ++#define LGTD_TM_TO_ISOTIME(tm, sbuf, bufsz, usec) do { \ ++ /* '2015-01-02T10:13:16.132222+00:00' */ \ ++ if ((usec)) { \ ++ snprintf( \ ++ (sbuf), (bufsz), "%d-%02d-%02dT%02d:%02d:%02d.%jd%c%02ld:%02ld", \ ++ 1900 + (tm)->tm_year, 1 + (tm)->tm_mon, (tm)->tm_mday, \ ++ (tm)->tm_hour, (tm)->tm_min, (tm)->tm_sec, (intmax_t)usec, \ ++ (tm)->tm_gmtoff >= 0 ? '+' : '-', /* %+02ld doesn't work */ \ ++ LGTD_ABS((tm)->tm_gmtoff / 60 / 60), (tm)->tm_gmtoff % (60 * 60) \ ++ ); \ ++ } else { \ ++ snprintf( \ ++ (sbuf), (bufsz), "%d-%02d-%02dT%02d:%02d:%02d%c%02ld:%02ld", \ ++ 1900 + (tm)->tm_year, 1 + (tm)->tm_mon, (tm)->tm_mday, \ ++ (tm)->tm_hour, (tm)->tm_min, (tm)->tm_sec, \ ++ (tm)->tm_gmtoff >= 0 ? '+' : '-', /* %+02ld doesn't work */ \ ++ LGTD_ABS((tm)->tm_gmtoff / 60 / 60), (tm)->tm_gmtoff % (60 * 60) \ ++ ); \ ++ } \ ++} while (0) + #define LGTD_SNPRINTF_APPEND(buf, i, bufsz, ...) do { \ + int n = snprintf(&(buf)[(i)], bufsz - i, __VA_ARGS__); \ + (i) = LGTD_MIN((i) + n, bufsz); \ +@@ -57,6 +80,10 @@ + void lgtd_sockaddrtoa(const struct sockaddr_storage *, char *buf, int buflen); + short lgtd_sockaddrport(const struct sockaddr_storage *); + ++char *lgtd_print_duration(uint64_t, char *, int); ++#define LGTD_PRINT_DURATION(secs, arr) \ ++ lgtd_print_duration((secs), (arr), sizeof((arr))) ++ + void _lgtd_err(void (*)(int, const char *, ...), int, const char *, ...) + __attribute__((format(printf, 3, 4))); + #define lgtd_err(eval, fmt, ...) _lgtd_err(err, (eval), (fmt), ##__VA_ARGS__); +diff --git a/core/log.c b/core/log.c +--- a/core/log.c ++++ b/core/log.c +@@ -53,14 +53,7 @@ + if (!localtime_r(&now.tv_sec, &tm_now)) { + goto error; + } +- // '2015-01-02T10:13:16.132222+00:00' +- snprintf( +- strbuf, bufsz, "%d-%02d-%02dT%02d:%02d:%02d.%jd%c%02ld:%02ld", +- 1900 + tm_now.tm_year, 1 + tm_now.tm_mon, tm_now.tm_mday, +- tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, +- (intmax_t)now.tv_usec, tm_now.tm_gmtoff >= 0 ? '+' : '-', // %+02ld doesn't work +- LGTD_ABS(tm_now.tm_gmtoff / 60 / 60), tm_now.tm_gmtoff % (60 * 60) +- ); ++ LGTD_TM_TO_ISOTIME(&tm_now, strbuf, bufsz, now.tv_usec); + return; + error: + strbuf[0] = '\0'; +@@ -121,6 +114,27 @@ + } + } + ++char * ++lgtd_print_duration(uint64_t secs, char *buf, int bufsz) ++{ ++ assert(buf); ++ assert(bufsz > 0); ++ ++ int days = secs / (60 * 60 * 24); ++ int minutes = secs / 60; ++ int hours = minutes / 60; ++ hours = hours % 24; ++ minutes = minutes % 60; ++ ++ int i = 0; ++ if (days) { ++ int n = snprintf(buf, bufsz, "%d days ", days); ++ i = LGTD_MIN(i + n, bufsz); ++ } ++ snprintf(&buf[i], bufsz - i, "%02d:%02d", hours, minutes); ++ return buf; ++} ++ + void + _lgtd_err(void (*errfn)(int, const char *, ...), + int eval, +diff --git a/core/proto.c b/core/proto.c +--- a/core/proto.c ++++ b/core/proto.c +@@ -195,40 +195,116 @@ + return; + } + +- static const char *state_fmt = ("{" +- "\"hsbk\":[%s,%s,%s,%hu]," +- "\"power\":%s," +- "\"label\":\"%s\"," +- "\"tags\":["); ++ lgtd_client_start_send_response(client); ++ lgtd_client_write_string(client, "["); ++ struct lgtd_router_device *device; ++ SLIST_FOREACH(device, devices, link) { ++ struct lgtd_lifx_bulb *bulb = device->device; ++ ++ char buf[2048], ++ site_addr[LGTD_LIFX_ADDR_STRLEN], ++ bulb_addr[LGTD_LIFX_ADDR_STRLEN]; ++ int i = 0; ++ ++ LGTD_IEEE8023MACTOA(bulb->addr, bulb_addr); ++ LGTD_IEEE8023MACTOA(bulb->gw->site.as_array, site_addr); ++ ++ LGTD_SNPRINTF_APPEND( ++ buf, i, (int)sizeof(buf), ++ "{" ++ "\"_lifx\":{" ++ "\"addr\": \"%s\"," ++ "\"gateway\":{" ++ "\"site\":\"%s\"," ++ "\"url\":\"tcp://[%s]:%hu\"," ++ "\"latency\":%ju" ++ "},", ++ bulb_addr, site_addr, ++ bulb->gw->ip_addr, bulb->gw->port, ++ (uintmax_t)LGTD_LIFX_GATEWAY_LATENCY(bulb->gw) ++ ); ++ ++#define PRINT_LIFX_FW_TIMESTAMPS(fw_info, built_at_buf, installed_at_buf) \ ++ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP((fw_info)->built_at, (built_at_buf)); \ ++ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP( \ ++ (fw_info)->installed_at, (installed_at_buf) \ ++ ) ++ ++ for (int ip = 0; ip != LGTD_LIFX_BULB_IP_COUNT; ip++) { ++ char fw_built_at[64], fw_installed_at[64]; ++ PRINT_LIFX_FW_TIMESTAMPS( ++ &bulb->ips[ip].fw_info, fw_built_at, fw_installed_at ++ ); ++ ++ LGTD_SNPRINTF_APPEND( ++ buf, i, (int)sizeof(buf), ++ "\"%s\":{" ++ "\"firmware_built_at\":\"%s\"," ++ "\"firmware_installed_at\":\"%s\"," ++ "\"firmware_version\":\"%x\"," ++ "\"signal_strength\":%f," ++ "\"tx_bytes\":%u," ++ "\"rx_bytes\":%u," ++ "\"temperature\":%u" ++ "},", ++ lgtd_lifx_bulb_ip_names[ip], ++ fw_built_at, fw_installed_at, bulb->ips[ip].fw_info.version, ++ bulb->ips[ip].state.signal_strength, ++ bulb->ips[ip].state.tx_bytes, ++ bulb->ips[ip].state.rx_bytes, ++ bulb->ips[ip].state.temperature ++ ); ++ } ++ ++ LGTD_SNPRINTF_APPEND( ++ buf, i, (int)sizeof(buf), ++ "\"product_info\":{" ++ "\"vendor_id\":\"%x\"," ++ "\"product_id\":\"%x\"," ++ "\"version\":%u" ++ "},", ++ bulb->product_info.vendor_id, ++ bulb->product_info.product_id, ++ bulb->product_info.version ++ ); ++ ++ char bulb_time[64]; ++ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(bulb->runtime_info.time, bulb_time); ++ LGTD_SNPRINTF_APPEND( ++ buf, i, (int)sizeof(buf), ++ "\"runtime_info\":{" ++ "\"time\":\"%s\"," ++ "\"uptime\":%ju," ++ "\"downtime\":%ju" ++ "}" ++ "},", ++ bulb_time, ++ (uintmax_t)LGTD_NSECS_TO_SECS(bulb->runtime_info.uptime), ++ (uintmax_t)LGTD_NSECS_TO_SECS(bulb->runtime_info.downtime) ++ ); + + #define PRINT_COMPONENT(src, dst, start, stop) \ + lgtd_jsonrpc_uint16_range_to_float_string( \ + (src), (start), (stop), (dst), sizeof((dst)) \ + ) + +- lgtd_client_start_send_response(client); +- lgtd_client_write_string(client, "["); +- struct lgtd_router_device *device; +- SLIST_FOREACH(device, devices, link) { +- struct lgtd_lifx_bulb *bulb = device->device; +- + char h[16], s[16], b[16]; + PRINT_COMPONENT(bulb->state.hue, h, 0, 360); + PRINT_COMPONENT(bulb->state.saturation, s, 0, 1); + PRINT_COMPONENT(bulb->state.brightness, b, 0, 1); + +- char buf[3072], +- bulb_addr[LGTD_LIFX_ADDR_STRLEN], +- site_addr[LGTD_LIFX_ADDR_STRLEN]; +- LGTD_IEEE8023MACTOA(bulb->addr, bulb_addr); +- LGTD_IEEE8023MACTOA(bulb->gw->site.as_array, site_addr); +- int written = snprintf( +- buf, sizeof(buf), state_fmt, ++ LGTD_SNPRINTF_APPEND( ++ buf, i, (int)sizeof(buf), ++ "\"hsbk\":[%s,%s,%s,%hu]," ++ "\"power\":%s," ++ "\"label\":\"%s\"," ++ "\"tags\":[", + h, s, b, bulb->state.kelvin, + bulb->state.power == LGTD_LIFX_POWER_ON ? "true" : "false", + bulb->state.label[0] ? bulb->state.label : bulb_addr + ); +- if (written >= (int)sizeof(buf)) { ++ ++ if (i >= (int)sizeof(buf)) { + lgtd_warnx( + "can't send state of bulb %s (%s) to client " + "[%s]:%hu: output buffer to small", +diff --git a/examples/lightsc.py b/examples/lightsc.py +--- a/examples/lightsc.py ++++ b/examples/lightsc.py +@@ -17,7 +17,7 @@ + "id": str(uuid.uuid4()), + } + socket.send(json.dumps(payload).encode("utf-8")) +- response = socket.recv(2048).decode("utf-8") ++ response = socket.recv(8192).decode("utf-8") + try: + response = json.loads(response) + except ValueError: +diff --git a/lifx/bulb.c b/lifx/bulb.c +--- a/lifx/bulb.c ++++ b/lifx/bulb.c +@@ -33,12 +33,57 @@ + #include "bulb.h" + #include "gateway.h" + #include "core/daemon.h" ++#include "timer.h" + #include "core/stats.h" ++#include "core/jsmn.h" ++#include "core/jsonrpc.h" ++#include "core/client.h" ++#include "core/proto.h" ++#include "core/router.h" + #include "core/lightsd.h" + + struct lgtd_lifx_bulb_map lgtd_lifx_bulbs_table = + RB_INITIALIZER(&lgtd_lifx_bulbs_table); + ++const char * const lgtd_lifx_bulb_ip_names[] = { "mcu", "wifi" }; ++ ++static void ++lgtd_lifx_bulb_fetch_hardware_info(struct lgtd_lifx_timer *timer, ++ union lgtd_lifx_timer_ctx ctx) ++{ ++ assert(timer); ++ assert(ctx.as_uint); ++ ++ // Get the bulb again, it might have been closed while we were waiting: ++ const uint8_t *bulb_addr = (const uint8_t *)&ctx.as_uint; ++ struct lgtd_lifx_bulb *bulb = lgtd_lifx_bulb_get(bulb_addr); ++ if (!bulb) { ++ lgtd_lifx_timer_stop_timer(timer); ++ return; ++ } ++ ++#define RESEND_IF(test, pkt_type) do { \ ++ if ((test)) { \ ++ stop = false; \ ++ lgtd_router_send_to_device(bulb, (pkt_type), NULL); \ ++ } \ ++} while (0) ++ ++ bool stop = true; ++ RESEND_IF(!bulb->product_info.vendor_id, LGTD_LIFX_GET_VERSION); ++ RESEND_IF( ++ !bulb->ips[LGTD_LIFX_BULB_MCU_IP].fw_info.version, ++ LGTD_LIFX_GET_MESH_FIRMWARE ++ ); ++ RESEND_IF( ++ !bulb->ips[LGTD_LIFX_BULB_WIFI_IP].fw_info.version, ++ LGTD_LIFX_GET_WIFI_FIRMWARE_STATE ++ ); ++ if (stop) { ++ lgtd_lifx_timer_stop_timer(timer); ++ } ++} ++ + struct lgtd_lifx_bulb * + lgtd_lifx_bulb_get(const uint8_t *addr) + { +@@ -68,6 +113,14 @@ + + bulb->last_light_state_at = lgtd_time_monotonic_msecs(); + ++ union lgtd_lifx_timer_ctx ctx = { .as_uint = 0 }; ++ memcpy(&ctx.as_uint, addr, LGTD_LIFX_ADDR_LENGTH); ++ lgtd_lifx_timer_start_timer( ++ LGTD_LIFX_BULB_FETCH_HARDWARE_INFO_TIMER_MSECS, ++ lgtd_lifx_bulb_fetch_hardware_info, ++ ctx ++ ); ++ + return bulb; + } + +@@ -124,6 +177,7 @@ + LGTD_STATS_ADD_AND_UPDATE_PROCTITLE( + bulbs_powered_on, state->power == LGTD_LIFX_POWER_ON ? 1 : -1 + ); ++ lgtd_router_send_to_device(bulb, LGTD_LIFX_GET_INFO, NULL); + } + + lgtd_lifx_gateway_update_tag_refcounts(bulb->gw, bulb->state.tags, state->tags); +@@ -141,6 +195,7 @@ + LGTD_STATS_ADD_AND_UPDATE_PROCTITLE( + bulbs_powered_on, power == LGTD_LIFX_POWER_ON ? 1 : -1 + ); ++ lgtd_router_send_to_device(bulb, LGTD_LIFX_GET_INFO, NULL); + } + + bulb->state.power = power; +@@ -155,3 +210,53 @@ + + bulb->state.tags = tags; + } ++ ++void ++lgtd_lifx_bulb_set_ip_state(struct lgtd_lifx_bulb *bulb, ++ enum lgtd_lifx_bulb_ips ip_id, ++ const struct lgtd_lifx_ip_state *state, ++ lgtd_time_mono_t received_at) ++{ ++ assert(bulb); ++ assert(state); ++ ++ struct lgtd_lifx_bulb_ip *ip = &bulb->ips[ip_id]; ++ ip->state_updated_at = received_at; ++ memcpy(&ip->state, state, sizeof(ip->state)); ++} ++ ++void ++lgtd_lifx_bulb_set_ip_firmware_info(struct lgtd_lifx_bulb *bulb, ++ enum lgtd_lifx_bulb_ips ip_id, ++ const struct lgtd_lifx_ip_firmware_info *info, ++ lgtd_time_mono_t received_at) ++{ ++ assert(bulb); ++ assert(info); ++ ++ struct lgtd_lifx_bulb_ip *ip = &bulb->ips[ip_id]; ++ ip->fw_info_updated_at = received_at; ++ memcpy(&ip->fw_info, info, sizeof(ip->fw_info)); ++} ++ ++void ++lgtd_lifx_bulb_set_product_info(struct lgtd_lifx_bulb *bulb, ++ const struct lgtd_lifx_product_info *info) ++{ ++ assert(bulb); ++ assert(info); ++ ++ memcpy(&bulb->product_info, info, sizeof(bulb->product_info)); ++} ++ ++void ++lgtd_lifx_bulb_set_runtime_info(struct lgtd_lifx_bulb *bulb, ++ const struct lgtd_lifx_runtime_info *info, ++ lgtd_time_mono_t received_at) ++{ ++ assert(bulb); ++ assert(info); ++ ++ bulb->runtime_info_updated_at = received_at; ++ memcpy(&bulb->runtime_info, info, sizeof(bulb->runtime_info)); ++} +diff --git a/lifx/bulb.h b/lifx/bulb.h +--- a/lifx/bulb.h ++++ b/lifx/bulb.h +@@ -30,17 +30,64 @@ + char label[LGTD_LIFX_LABEL_SIZE]; + uint64_t tags; + }; ++ ++struct lgtd_lifx_ip_state { ++ float signal_strength; // mW ++ uint32_t tx_bytes; ++ uint32_t rx_bytes; ++ uint16_t temperature; // Deci-celcius: e.g 24.3 -> 2430 ++}; ++ ++struct lgtd_lifx_ip_firmware_info { ++ uint64_t built_at; // ns since epoch ++ uint64_t installed_at; // ns since epoch ++ uint32_t version; ++}; ++ ++struct lgtd_lifx_product_info { ++ uint32_t vendor_id; ++ uint32_t product_id; ++ uint32_t version; ++}; ++ ++struct lgtd_lifx_runtime_info { ++ uint64_t time; // ns since epoch ++ uint64_t uptime; // ns ++ uint64_t downtime; // ns, last power off period duration ++}; + #pragma pack(pop) + ++enum { LGTD_LIFX_BULB_FETCH_HARDWARE_INFO_TIMER_MSECS = 5000 }; ++ ++enum lgtd_lifx_bulb_ips { ++ LGTD_LIFX_BULB_MCU_IP = 0, ++ LGTD_LIFX_BULB_WIFI_IP, ++ LGTD_LIFX_BULB_IP_COUNT, ++}; ++ ++// keyed with enum lgtd_lifx_bulb_ips: ++extern const char * const lgtd_lifx_bulb_ip_names[]; ++ ++struct lgtd_lifx_bulb_ip { ++ struct lgtd_lifx_ip_state state; ++ lgtd_time_mono_t state_updated_at; ++ struct lgtd_lifx_ip_firmware_info fw_info; ++ lgtd_time_mono_t fw_info_updated_at; ++}; ++ + struct lgtd_lifx_bulb { + RB_ENTRY(lgtd_lifx_bulb) link; + SLIST_ENTRY(lgtd_lifx_bulb) link_by_gw; +- struct lgtd_lifx_gateway *gw; +- uint8_t addr[LGTD_LIFX_ADDR_LENGTH]; +- struct lgtd_lifx_light_state state; + lgtd_time_mono_t last_light_state_at; ++ lgtd_time_mono_t runtime_info_updated_at; + lgtd_time_mono_t dirty_at; + uint16_t expected_power_on; ++ uint8_t addr[LGTD_LIFX_ADDR_LENGTH]; ++ struct lgtd_lifx_gateway *gw; ++ struct lgtd_lifx_light_state state; ++ struct lgtd_lifx_bulb_ip ips[LGTD_LIFX_BULB_IP_COUNT]; ++ struct lgtd_lifx_product_info product_info; ++ struct lgtd_lifx_runtime_info runtime_info; + }; + RB_HEAD(lgtd_lifx_bulb_map, lgtd_lifx_bulb); + SLIST_HEAD(lgtd_lifx_bulb_list, lgtd_lifx_bulb); +@@ -69,3 +116,17 @@ + lgtd_time_mono_t); + void lgtd_lifx_bulb_set_power_state(struct lgtd_lifx_bulb *, uint16_t); + void lgtd_lifx_bulb_set_tags(struct lgtd_lifx_bulb *, uint64_t); ++ ++void lgtd_lifx_bulb_set_ip_state(struct lgtd_lifx_bulb *bulb, ++ enum lgtd_lifx_bulb_ips ip_id, ++ const struct lgtd_lifx_ip_state *state, ++ lgtd_time_mono_t received_at); ++void lgtd_lifx_bulb_set_ip_firmware_info(struct lgtd_lifx_bulb *bulb, ++ enum lgtd_lifx_bulb_ips ip_id, ++ const struct lgtd_lifx_ip_firmware_info *info, ++ lgtd_time_mono_t received_at); ++void lgtd_lifx_bulb_set_product_info(struct lgtd_lifx_bulb *, ++ const struct lgtd_lifx_product_info *); ++void lgtd_lifx_bulb_set_runtime_info(struct lgtd_lifx_bulb *, ++ const struct lgtd_lifx_runtime_info *, ++ lgtd_time_mono_t); +diff --git a/lifx/gateway.c b/lifx/gateway.c +--- a/lifx/gateway.c ++++ b/lifx/gateway.c +@@ -501,12 +501,8 @@ + (uintmax_t)pkt->tags + ); + +- struct lgtd_lifx_bulb *b = lgtd_lifx_gateway_get_or_open_bulb( +- gw, hdr->target.device_addr +- ); +- if (!b) { +- return; +- } ++ struct lgtd_lifx_bulb *b; ++ LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, hdr->target.device_addr); + + assert(sizeof(*pkt) == sizeof(b->state)); + lgtd_lifx_bulb_set_light_state( +@@ -531,7 +527,7 @@ + } + } + +- int latency = gw->last_pkt_at - gw->last_req_at; ++ int latency = LGTD_LIFX_GATEWAY_LATENCY(gw); + if (latency < LGTD_LIFX_GATEWAY_MIN_REFRESH_INTERVAL_MSECS) { + if (!event_pending(gw->refresh_ev, EV_TIMEOUT, NULL)) { + int timeout = LGTD_LIFX_GATEWAY_MIN_REFRESH_INTERVAL_MSECS - latency; +@@ -573,14 +569,9 @@ + LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), pkt->power + ); + +- struct lgtd_lifx_bulb *b = lgtd_lifx_gateway_get_or_open_bulb( +- gw, hdr->target.device_addr ++ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( ++ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_power_state, pkt->power + ); +- if (!b) { +- return; +- } +- +- lgtd_lifx_bulb_set_power_state(b, pkt->power); + } + + int +@@ -691,9 +682,10 @@ + } + } + +-void lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *gw, +- const struct lgtd_lifx_packet_header *hdr, +- const struct lgtd_lifx_packet_tags *pkt) ++void ++lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_tags *pkt) + { + assert(gw && hdr && pkt); + +@@ -705,12 +697,8 @@ + (uintmax_t)pkt->tags + ); + +- struct lgtd_lifx_bulb *b = lgtd_lifx_gateway_get_or_open_bulb( +- gw, hdr->target.device_addr +- ); +- if (!b) { +- return; +- } ++ struct lgtd_lifx_bulb *b; ++ LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, hdr->target.device_addr); + + char bulb_addr[LGTD_LIFX_ADDR_STRLEN], site_addr[LGTD_LIFX_ADDR_STRLEN]; + int tag_id; +@@ -729,3 +717,132 @@ + + lgtd_lifx_bulb_set_tags(b, pkt->tags); + } ++ ++void ++lgtd_lifx_gateway_handle_ip_state(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_ip_state *pkt) ++{ ++ assert(gw && hdr && pkt); ++ ++ const char *type; ++ enum lgtd_lifx_bulb_ips ip_id; ++ switch (hdr->packet_type) { ++ case LGTD_LIFX_MESH_INFO: ++ type = "MCU_STATE"; ++ ip_id = LGTD_LIFX_BULB_MCU_IP; ++ break; ++ case LGTD_LIFX_WIFI_INFO: ++ type = "WIFI_STATE"; ++ ip_id = LGTD_LIFX_BULB_WIFI_IP; ++ break; ++ default: ++ lgtd_info("invalid ip state packet_type %#hx", hdr->packet_type); ++#ifndef NDEBUG ++ abort(); ++#endif ++ return; ++ } ++ ++ char addr[LGTD_LIFX_ADDR_STRLEN]; ++ lgtd_debug( ++ "%s <-- [%s]:%hu - %s " ++ "signal_strength=%f, rx_bytes=%u, tx_bytes=%u, temperature=%hu", ++ type, gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), ++ pkt->signal_strength, pkt->rx_bytes, pkt->tx_bytes, pkt->temperature ++ ); ++ ++ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( ++ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_ip_state, ++ ip_id, (const struct lgtd_lifx_ip_state *)pkt, gw->last_pkt_at ++ ); ++} ++ ++void ++lgtd_lifx_gateway_handle_ip_firmware_info(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_ip_firmware_info *pkt) ++{ ++ assert(gw && hdr && pkt); ++ ++ const char *type; ++ enum lgtd_lifx_bulb_ips ip_id; ++ switch (hdr->packet_type) { ++ case LGTD_LIFX_MESH_FIRMWARE: ++ type = "MCU_FIRMWARE_INFO"; ++ ip_id = LGTD_LIFX_BULB_MCU_IP; ++ break; ++ case LGTD_LIFX_WIFI_FIRMWARE_STATE: ++ type = "WIFI_FIRMWARE_INFO"; ++ ip_id = LGTD_LIFX_BULB_WIFI_IP; ++ break; ++ default: ++ lgtd_info("invalid ip firmware packet_type %#hx", hdr->packet_type); ++#ifndef NDEBUG ++ abort(); ++#endif ++ return; ++ } ++ ++ char built_at[64], installed_at[64], addr[LGTD_LIFX_ADDR_STRLEN]; ++ lgtd_debug( ++ "%s <-- [%s]:%hu - %s " ++ "built_at=%s, installed_at=%s, version=%u", ++ type, gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), ++ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->built_at, built_at), ++ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->installed_at, installed_at), ++ pkt->version ++ ); ++ ++ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( ++ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_ip_firmware_info, ++ ip_id, (const struct lgtd_lifx_ip_firmware_info *)pkt, gw->last_pkt_at ++ ); ++} ++ ++void ++lgtd_lifx_gateway_handle_product_info(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_product_info *pkt) ++{ ++ assert(gw && hdr && pkt); ++ ++ char addr[LGTD_LIFX_ADDR_STRLEN]; ++ lgtd_debug( ++ "PRODUCT_INFO <-- [%s]:%hu - %s " ++ "vendor_id=%#x, product_id=%#x, version=%u", ++ gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), ++ pkt->vendor_id, pkt->product_id, pkt->version ++ ); ++ ++ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( ++ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_product_info, ++ (const struct lgtd_lifx_product_info *)pkt ++ ); ++} ++ ++void ++lgtd_lifx_gateway_handle_runtime_info(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_runtime_info *pkt) ++{ ++ assert(gw && hdr && pkt); ++ ++ char device_time[64], uptime[64], downtime[64], addr[LGTD_LIFX_ADDR_STRLEN]; ++ lgtd_debug( ++ "PRODUCT_INFO <-- [%s]:%hu - %s time=%s, uptime=%s, downtime=%s", ++ gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), ++ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->time, device_time), ++ LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->uptime), uptime), ++ LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->downtime), downtime) ++ ); ++ ++ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( ++ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_runtime_info, ++ (const struct lgtd_lifx_runtime_info *)pkt, gw->last_pkt_at ++ ); ++} +diff --git a/lifx/gateway.h b/lifx/gateway.h +--- a/lifx/gateway.h ++++ b/lifx/gateway.h +@@ -36,12 +36,19 @@ + struct lgtd_lifx_gateway { + LIST_ENTRY(lgtd_lifx_gateway) link; + struct lgtd_lifx_bulb_list bulbs; ++#define LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, bulb_addr) do { \ ++ (b) = lgtd_lifx_gateway_get_or_open_bulb((gw), (bulb_addr)); \ ++ if (!(b)) { \ ++ return; \ ++ } \ ++} while (0) + // Multiple gateways can share the same site (that happens when bulbs are + // far away enough that ZigBee can't be used). Moreover the SET_PAN_GATEWAY + // packet doesn't include the device address in the header (i.e: site and + // device_addr have the same value) so we have no choice but to use the + // remote ip address to identify a gateway: + struct sockaddr_storage peer; ++ uint8_t addr[LGTD_LIFX_ADDR_LENGTH]; + char ip_addr[INET6_ADDRSTRLEN]; + uint16_t port; + // TODO: just use an integer and rename it to site_id: +@@ -60,6 +67,7 @@ + lgtd_time_mono_t last_req_at; + lgtd_time_mono_t next_req_at; + lgtd_time_mono_t last_pkt_at; ++#define LGTD_LIFX_GATEWAY_LATENCY(gw) ((gw)->last_pkt_at - (gw)->last_req_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; \ +@@ -77,6 +85,12 @@ + + extern struct lgtd_lifx_gateway_list lgtd_lifx_gateways; + ++#define LGTD_LIFX_GATEWAY_SET_BULB_ATTR(gw, bulb_addr, bulb_fn, ...) do { \ ++ struct lgtd_lifx_bulb *b; \ ++ LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, bulb_addr); \ ++ (bulb_fn)(b, __VA_ARGS__); \ ++} while (0) ++ + struct lgtd_lifx_gateway *lgtd_lifx_gateway_get(const struct sockaddr_storage *); + struct lgtd_lifx_gateway *lgtd_lifx_gateway_open(const struct sockaddr_storage *, + ev_socklen_t, +@@ -119,3 +133,15 @@ + void lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *, + const struct lgtd_lifx_packet_header *, + const struct lgtd_lifx_packet_tags *); ++void lgtd_lifx_gateway_handle_ip_state(struct lgtd_lifx_gateway *, ++ const struct lgtd_lifx_packet_header *, ++ const struct lgtd_lifx_packet_ip_state *); ++void lgtd_lifx_gateway_handle_ip_firmware_info(struct lgtd_lifx_gateway *, ++ const struct lgtd_lifx_packet_header *, ++ const struct lgtd_lifx_packet_ip_firmware_info *); ++void lgtd_lifx_gateway_handle_product_info(struct lgtd_lifx_gateway *, ++ const struct lgtd_lifx_packet_header *, ++ const struct lgtd_lifx_packet_product_info *); ++void lgtd_lifx_gateway_handle_runtime_info(struct lgtd_lifx_gateway *, ++ const struct lgtd_lifx_packet_header *, ++ const struct lgtd_lifx_packet_runtime_info *); +diff --git a/lifx/wire_proto.c b/lifx/wire_proto.c +--- a/lifx/wire_proto.c ++++ b/lifx/wire_proto.c +@@ -24,8 +24,10 @@ + #include <stdarg.h> + #include <stdbool.h> + #include <stdint.h> ++#include <stdio.h> + #include <stdlib.h> + #include <string.h> ++#include <time.h> + + #include <event2/util.h> + +@@ -74,12 +76,32 @@ + (void)pkt; + } + ++static void ++lgtd_lifx_wire_enosys_packet_handler(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const void *pkt) ++{ ++ (void)pkt; ++ ++ const struct lgtd_lifx_packet_info *pkt_info; ++ pkt_info = lgtd_lifx_wire_get_packet_info(hdr->packet_type); ++ bool addressable = hdr->protocol & LGTD_LIFX_PROTOCOL_ADDRESSABLE; ++ bool tagged = hdr->protocol & LGTD_LIFX_PROTOCOL_TAGGED; ++ unsigned int protocol = hdr->protocol & LGTD_LIFX_PROTOCOL_VERSION_MASK; ++ lgtd_info( ++ "%s <-- [%s]:%hu - (Unimplemented, header info: " ++ "addressable=%d, tagged=%d, protocol=%d)", ++ pkt_info->name, gw->ip_addr, gw->port, ++ addressable, tagged, protocol ++ ); ++} ++ + void + lgtd_lifx_wire_load_packet_info_map(void) + { + #define DECODER(x) ((void (*)(void *))(x)) + #define ENCODER(x) ((void (*)(void *))(x)) +-#define HANDLER(x) \ ++#define HANDLER(x) \ + ((void (*)(struct lgtd_lifx_gateway *, \ + const struct lgtd_lifx_packet_header *, \ + const void *))(x)) +@@ -90,6 +112,10 @@ + #define REQUEST_ONLY \ + .decode = lgtd_lifx_wire_null_packet_encoder_decoder, \ + .handle = lgtd_lifx_wire_null_packet_handler ++#define UNIMPLEMENTED \ ++ .decode = lgtd_lifx_wire_null_packet_encoder_decoder, \ ++ .encode = lgtd_lifx_wire_null_packet_encoder_decoder, \ ++ .handle = lgtd_lifx_wire_enosys_packet_handler + + static struct lgtd_lifx_packet_info packet_table[] = { + // Gateway packets: +@@ -187,6 +213,211 @@ + .size = sizeof(struct lgtd_lifx_packet_tags), + .decode = DECODER(lgtd_lifx_wire_decode_tags), + .handle = HANDLER(lgtd_lifx_gateway_handle_tags) ++ }, ++ { ++ REQUEST_ONLY, ++ NO_PAYLOAD, ++ .name = "GET_MESH_INFO", ++ .type = LGTD_LIFX_GET_MESH_INFO ++ }, ++ { ++ RESPONSE_ONLY, ++ .name = "MESH_INFO", ++ .type = LGTD_LIFX_MESH_INFO, ++ .size = sizeof(struct lgtd_lifx_packet_ip_state), ++ .decode = DECODER(lgtd_lifx_wire_decode_ip_state), ++ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_state) ++ }, ++ { ++ REQUEST_ONLY, ++ NO_PAYLOAD, ++ .name = "GET_MESH_FIRMWARE", ++ .type = LGTD_LIFX_GET_MESH_FIRMWARE ++ }, ++ { ++ RESPONSE_ONLY, ++ .name = "MESH_FIRMWARE", ++ .type = LGTD_LIFX_MESH_FIRMWARE, ++ .size = sizeof(struct lgtd_lifx_packet_ip_firmware_info), ++ .decode = DECODER(lgtd_lifx_wire_decode_ip_firmware_info), ++ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_firmware_info) ++ }, ++ { ++ REQUEST_ONLY, ++ NO_PAYLOAD, ++ .name = "GET_WIFI_INFO", ++ .type = LGTD_LIFX_GET_WIFI_INFO, ++ }, ++ { ++ RESPONSE_ONLY, ++ .name = "WIFI_INFO", ++ .type = LGTD_LIFX_WIFI_INFO, ++ .size = sizeof(struct lgtd_lifx_packet_ip_state), ++ .decode = DECODER(lgtd_lifx_wire_decode_ip_state), ++ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_state) ++ }, ++ { ++ REQUEST_ONLY, ++ NO_PAYLOAD, ++ .name = "GET_WIFI_FIRMWARE_STATE", ++ .type = LGTD_LIFX_GET_WIFI_FIRMWARE_STATE ++ }, ++ { ++ RESPONSE_ONLY, ++ .name = "WIFI_FIRMWARE_STATE", ++ .type = LGTD_LIFX_WIFI_FIRMWARE_STATE, ++ .size = sizeof(struct lgtd_lifx_packet_ip_firmware_info), ++ .decode = DECODER(lgtd_lifx_wire_decode_ip_firmware_info), ++ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_firmware_info) ++ }, ++ { ++ REQUEST_ONLY, ++ NO_PAYLOAD, ++ .name = "GET_VERSION", ++ .type = LGTD_LIFX_GET_VERSION ++ }, ++ { ++ RESPONSE_ONLY, ++ .name = "VERSION_STATE", ++ .type = LGTD_LIFX_VERSION_STATE, ++ .size = sizeof(struct lgtd_lifx_packet_product_info), ++ .decode = DECODER(lgtd_lifx_wire_decode_product_info), ++ .handle = HANDLER(lgtd_lifx_gateway_handle_product_info) ++ }, ++ { ++ REQUEST_ONLY, ++ NO_PAYLOAD, ++ .name = "GET_INFO", ++ .type = LGTD_LIFX_GET_INFO ++ }, ++ { ++ RESPONSE_ONLY, ++ .name = "INFO_STATE", ++ .type = LGTD_LIFX_INFO_STATE, ++ .size = sizeof(struct lgtd_lifx_packet_runtime_info), ++ .decode = DECODER(lgtd_lifx_wire_decode_runtime_info), ++ .handle = HANDLER(lgtd_lifx_gateway_handle_runtime_info) ++ }, ++ // Unimplemented but "known" packets ++ { ++ UNIMPLEMENTED, ++ .name = "GET_TIME", ++ .type = LGTD_LIFX_GET_TIME ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "SET_TIME", ++ .type = LGTD_LIFX_SET_TIME ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "TIME_STATE", ++ .type = LGTD_LIFX_TIME_STATE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "GET_RESET_SWITCH_STATE", ++ .type = LGTD_LIFX_GET_RESET_SWITCH_STATE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "RESET_SWITCH_STATE", ++ .type = LGTD_LIFX_RESET_SWITCH_STATE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "GET_BULB_LABEL", ++ .type = LGTD_LIFX_GET_BULB_LABEL ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "SET_BULB_LABEL", ++ .type = LGTD_LIFX_SET_BULB_LABEL ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "BULB_LABEL", ++ .type = LGTD_LIFX_BULB_LABEL ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "GET_MCU_RAIL_VOLTAGE", ++ .type = LGTD_LIFX_GET_MCU_RAIL_VOLTAGE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "MCU_RAIL_VOLTAGE", ++ .type = LGTD_LIFX_MCU_RAIL_VOLTAGE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "REBOOT", ++ .type = LGTD_LIFX_REBOOT ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "SET_FACTORY_TEST_MODE", ++ .type = LGTD_LIFX_SET_FACTORY_TEST_MODE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "DISABLE_FACTORY_TEST_MODE", ++ .type = LGTD_LIFX_DISABLE_FACTORY_TEST_MODE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "ACK", ++ .type = LGTD_LIFX_ACK ++ }, ++ { ++ 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 ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "SET_DIM_RELATIVE", ++ .type = LGTD_LIFX_SET_DIM_RELATIVE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "GET_WIFI_STATE", ++ .type = LGTD_LIFX_GET_WIFI_STATE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "SET_WIFI_STATE", ++ .type = LGTD_LIFX_SET_WIFI_STATE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "WIFI_STATE", ++ .type = LGTD_LIFX_WIFI_STATE ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "GET_ACCESS_POINTS", ++ .type = LGTD_LIFX_GET_ACCESS_POINTS ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "SET_ACCESS_POINTS", ++ .type = LGTD_LIFX_SET_ACCESS_POINTS ++ }, ++ { ++ UNIMPLEMENTED, ++ .name = "ACCESS_POINT", ++ .type = LGTD_LIFX_ACCESS_POINT + } + }; + +@@ -234,6 +465,25 @@ + return LGTD_LIFX_WAVEFORM_INVALID; + } + ++char * ++lgtd_lifx_wire_print_nsec_timestamp(uint64_t nsec_ts, char *buf, int bufsz) ++{ ++ assert(buf); ++ assert(bufsz > 0); ++ ++ time_t ts = LGTD_NSECS_TO_SECS(nsec_ts); ++ ++ struct tm tm_utc; ++ if (gmtime_r(&ts, &tm_utc)) { ++ int64_t usecs = LGTD_NSECS_TO_USECS(nsec_ts - LGTD_SECS_TO_NSECS(ts)); ++ LGTD_TM_TO_ISOTIME(&tm_utc, buf, bufsz, usecs); ++ } else { ++ buf[0] = '\0'; ++ } ++ ++ return buf; ++} ++ + static void + lgtd_lifx_wire_encode_header(struct lgtd_lifx_packet_header *hdr, int flags) + { +@@ -423,3 +673,44 @@ + + pkt->tags = le64toh(pkt->tags); + } ++ ++void ++lgtd_lifx_wire_decode_ip_state(struct lgtd_lifx_packet_ip_state *pkt) ++{ ++ assert(pkt); ++ ++ pkt->signal_strength = lgtd_lifx_wire_lefloattoh(pkt->signal_strength); ++ pkt->tx_bytes = le32toh(pkt->tx_bytes); ++ pkt->rx_bytes = le32toh(pkt->rx_bytes); ++ pkt->temperature = le16toh(pkt->temperature); ++} ++ ++void ++lgtd_lifx_wire_decode_ip_firmware_info(struct lgtd_lifx_packet_ip_firmware_info *pkt) ++{ ++ assert(pkt); ++ ++ pkt->built_at = le64toh(pkt->built_at); ++ pkt->installed_at = le64toh(pkt->installed_at); ++ pkt->version = le32toh(pkt->version); ++} ++ ++void ++lgtd_lifx_wire_decode_product_info(struct lgtd_lifx_packet_product_info *pkt) ++{ ++ assert(pkt); ++ ++ pkt->vendor_id = le32toh(pkt->vendor_id); ++ pkt->product_id = le32toh(pkt->product_id); ++ pkt->version = le32toh(pkt->version); ++} ++ ++void ++lgtd_lifx_wire_decode_runtime_info(struct lgtd_lifx_packet_runtime_info *pkt) ++{ ++ assert(pkt); ++ ++ pkt->time = le64toh(pkt->time); ++ pkt->uptime = le64toh(pkt->uptime); ++ pkt->downtime = le64toh(pkt->downtime); ++} +diff --git a/lifx/wire_proto.h b/lifx/wire_proto.h +--- a/lifx/wire_proto.h ++++ b/lifx/wire_proto.h +@@ -28,7 +28,7 @@ + static inline floatle_t + lgtd_lifx_wire_htolefloat(float f) + { +- union { float f; uint32_t i; } u = { .f = f }; ++ union { float f; uint32_t i; } u = { .f = f }; + htole32(u.i); + return u.f; + } +@@ -36,7 +36,7 @@ + static inline floatle_t + lgtd_lifx_wire_lefloattoh(float f) + { +- union { float f; uint32_t i; } u = { .f = f }; ++ union { float f; uint32_t i; } u = { .f = f }; + le32toh(u.i); + return u.f; + } +@@ -250,6 +250,30 @@ + char label[LGTD_LIFX_LABEL_SIZE]; + }; + ++struct lgtd_lifx_packet_ip_state { ++ floatle_t signal_strength; ++ uint32le_t tx_bytes; ++ uint32le_t rx_bytes; ++ uint16le_t temperature; ++}; ++ ++struct lgtd_lifx_packet_ip_firmware_info { ++ uint64le_t built_at; ++ uint64le_t installed_at; ++ uint32le_t version; ++}; ++ ++struct lgtd_lifx_packet_product_info { ++ uint32le_t vendor_id; ++ uint32le_t product_id; ++ uint32le_t version; ++}; ++ ++struct lgtd_lifx_packet_runtime_info { ++ uint64le_t time; ++ uint64le_t uptime; ++ uint64le_t downtime; ++}; + #pragma pack(pop) + + enum lgtd_lifx_header_flags { +@@ -331,8 +355,10 @@ + (tag_id_varname) != -1; \ + (tag_id_varname) = lgtd_lifx_wire_next_tag_id((tag_id_varname), (tags))) + +- + enum lgtd_lifx_waveform_type lgtd_lifx_wire_waveform_string_id_to_type(const char *, int); ++char* lgtd_lifx_wire_print_nsec_timestamp(uint64_t, char *, int); ++#define LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(ts, arr) \ ++ lgtd_lifx_wire_print_nsec_timestamp((ts), (arr), sizeof((arr))) + + const struct lgtd_lifx_packet_info *lgtd_lifx_wire_get_packet_info(enum lgtd_lifx_packet_type); + void lgtd_lifx_wire_load_packet_info_map(void); +@@ -357,3 +383,8 @@ + void lgtd_lifx_wire_decode_tags(struct lgtd_lifx_packet_tags *); + void lgtd_lifx_wire_encode_tag_labels(struct lgtd_lifx_packet_tag_labels *); + void lgtd_lifx_wire_decode_tag_labels(struct lgtd_lifx_packet_tag_labels *); ++ ++void lgtd_lifx_wire_decode_ip_state(struct lgtd_lifx_packet_ip_state *); ++void lgtd_lifx_wire_decode_ip_firmware_info(struct lgtd_lifx_packet_ip_firmware_info *); ++void lgtd_lifx_wire_decode_product_info(struct lgtd_lifx_packet_product_info *); ++void lgtd_lifx_wire_decode_runtime_info(struct lgtd_lifx_packet_runtime_info *); +diff --git a/tests/lifx/mock_gateway.h b/tests/lifx/mock_gateway.h +--- a/tests/lifx/mock_gateway.h ++++ b/tests/lifx/mock_gateway.h +@@ -129,3 +129,51 @@ + (void)pkt_tags; + } + #endif ++ ++#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_IP_STATE ++void ++lgtd_lifx_gateway_handle_ip_state(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_ip_state *pkt) ++{ ++ (void)gw; ++ (void)hdr; ++ (void)pkt; ++} ++#endif ++ ++#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_IP_FIRMWARE_INFO ++void ++lgtd_lifx_gateway_handle_ip_firmware_info(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_ip_firmware_info *pkt) ++{ ++ (void)gw; ++ (void)hdr; ++ (void)pkt; ++} ++#endif ++ ++#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_PRODUCT_INFO ++void ++lgtd_lifx_gateway_handle_product_info(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_product_info *pkt) ++{ ++ (void)gw; ++ (void)hdr; ++ (void)pkt; ++} ++#endif ++ ++#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_RUNTIME_INFO ++void ++lgtd_lifx_gateway_handle_runtime_info(struct lgtd_lifx_gateway *gw, ++ const struct lgtd_lifx_packet_header *hdr, ++ const struct lgtd_lifx_packet_runtime_info *pkt) ++{ ++ (void)gw; ++ (void)hdr; ++ (void)pkt; ++} ++#endif +diff --git a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c +--- a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c ++++ b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c +@@ -2,7 +2,7 @@ + + #include "wire_proto.c" + +-#include "test_wire_proto_utils.h" ++#include "mock_gateway.h" + + int + main(void) +diff --git a/tests/lifx/wire_proto/test_wire_proto_utils.h b/tests/lifx/wire_proto/test_wire_proto_utils.h +deleted file mode 100644 +--- a/tests/lifx/wire_proto/test_wire_proto_utils.h ++++ /dev/null +@@ -1,46 +0,0 @@ +-#pragma once +- +-void lgtd_lifx_gateway_handle_pan_gateway(struct lgtd_lifx_gateway *gw, +- const struct lgtd_lifx_packet_header *hdr, +- const struct lgtd_lifx_packet_pan_gateway *pkt) +-{ +- (void)gw; +- (void)hdr; +- (void)pkt; +-} +- +-void lgtd_lifx_gateway_handle_light_status(struct lgtd_lifx_gateway *gw, +- const struct lgtd_lifx_packet_header *hdr, +- const struct lgtd_lifx_packet_light_status *pkt) +-{ +- (void)gw; +- (void)hdr; +- (void)pkt; +-} +- +-void lgtd_lifx_gateway_handle_power_state(struct lgtd_lifx_gateway *gw, +- const struct lgtd_lifx_packet_header *hdr, +- const struct lgtd_lifx_packet_power_state *pkt) +-{ +- (void)gw; +- (void)hdr; +- (void)pkt; +-} +- +-void lgtd_lifx_gateway_handle_tag_labels(struct lgtd_lifx_gateway *gw, +- const struct lgtd_lifx_packet_header *hdr, +- const struct lgtd_lifx_packet_tag_labels *pkt) +-{ +- (void)gw; +- (void)hdr; +- (void)pkt; +-} +- +-void lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *gw, +- const struct lgtd_lifx_packet_header *hdr, +- const struct lgtd_lifx_packet_tags *pkt) +-{ +- (void)gw; +- (void)hdr; +- (void)pkt; +-} +diff --git a/tests/lifx/wire_proto/test_wire_proto_waveform_table.c b/tests/lifx/wire_proto/test_wire_proto_waveform_table.c +--- a/tests/lifx/wire_proto/test_wire_proto_waveform_table.c ++++ b/tests/lifx/wire_proto/test_wire_proto_waveform_table.c +@@ -1,6 +1,6 @@ + #include "wire_proto.c" + +-#include "test_wire_proto_utils.h" ++#include "mock_gateway.h" + + int + main(void)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fix_addrtoa_mess.patch Sun Aug 16 00:48:06 2015 -0700 @@ -0,0 +1,468 @@ +# HG changeset patch +# Parent 13b24c5af219c96e98584529bf917d7cef143ab2 + +diff --git a/core/lightsd.h b/core/lightsd.h +--- a/core/lightsd.h ++++ b/core/lightsd.h +@@ -51,7 +51,9 @@ + extern struct lgtd_opts lgtd_opts; + extern struct event_base *lgtd_ev_base; + +-const char *lgtd_addrtoa(const uint8_t *); ++char *lgtd_iee8023mactoa(const uint8_t *addr, char *buf, int buflen); ++#define LGTD_IEEE8023MACTOA(addr, buf) \ ++ lgtd_iee8023mactoa((addr), (buf), sizeof(buf)) + void lgtd_sockaddrtoa(const struct sockaddr_storage *, char *buf, int buflen); + short lgtd_sockaddrport(const struct sockaddr_storage *); + +diff --git a/core/log.c b/core/log.c +--- a/core/log.c ++++ b/core/log.c +@@ -81,17 +81,18 @@ + fprintf(stderr, "[%s] %s", loglvl, showprogname ? "lightsd: " : ""); + } + +-const char * +-lgtd_addrtoa(const uint8_t *addr) ++char * ++lgtd_iee8023mactoa(const uint8_t *addr, char *buf, int buflen) + { + assert(addr); ++ assert(buf); ++ assert(buflen >= 2 * 6 + 5 + 1); + +- static char str[LGTD_LIFX_ADDR_LENGTH * 2 + LGTD_LIFX_ADDR_LENGTH - 1 + 1]; + snprintf( +- str, sizeof(str), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", ++ buf, buflen, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] + ); +- return str; ++ return buf; + } + + void +diff --git a/core/proto.c b/core/proto.c +--- a/core/proto.c ++++ b/core/proto.c +@@ -217,19 +217,22 @@ + PRINT_COMPONENT(bulb->state.saturation, s, 0, 1); + PRINT_COMPONENT(bulb->state.brightness, b, 0, 1); + +- char buf[3072]; ++ char buf[3072], ++ bulb_addr[LGTD_LIFX_ADDR_STRLEN], ++ site_addr[LGTD_LIFX_ADDR_STRLEN]; ++ LGTD_IEEE8023MACTOA(bulb->addr, bulb_addr); ++ LGTD_IEEE8023MACTOA(bulb->gw->site.as_array, site_addr); + int written = snprintf( + buf, sizeof(buf), state_fmt, + h, s, b, bulb->state.kelvin, + bulb->state.power == LGTD_LIFX_POWER_ON ? "true" : "false", +- bulb->state.label[0] ? bulb->state.label : lgtd_addrtoa(bulb->addr) ++ bulb->state.label[0] ? bulb->state.label : bulb_addr + ); + if (written >= (int)sizeof(buf)) { + lgtd_warnx( + "can't send state of bulb %s (%s) to client " + "[%s]:%hu: output buffer to small", +- bulb->state.label, lgtd_addrtoa(bulb->addr), +- client->ip_addr, client->port ++ bulb->state.label, bulb_addr, client->ip_addr, client->port + ); + continue; + } +@@ -248,8 +251,7 @@ + "tag_id %d on bulb %.*s (%s) doesn't " + "exist on gw [%s]:%hu (site %s)", + tag_id, (int)sizeof(bulb->state.label), bulb->state.label, +- lgtd_addrtoa(bulb->addr), bulb->gw->ip_addr, bulb->gw->port, +- lgtd_addrtoa(bulb->gw->site.as_array) ++ bulb_addr, bulb->gw->ip_addr, bulb->gw->port, site_addr + ); + } + } +diff --git a/core/router.c b/core/router.c +--- a/core/router.c ++++ b/core/router.c +@@ -106,7 +106,9 @@ + bulb->expected_power_on = payload->power; + } + +- lgtd_info("sending %s to %s", pkt_info->name, lgtd_addrtoa(bulb->addr)); ++ char addr[LGTD_LIFX_ADDR_STRLEN]; ++ LGTD_IEEE8023MACTOA(bulb->addr, addr); ++ lgtd_info("sending %s to %s", pkt_info->name, addr); + } + + void +diff --git a/lifx/bulb.c b/lifx/bulb.c +--- a/lifx/bulb.c ++++ b/lifx/bulb.c +@@ -100,11 +100,12 @@ + LGTD_STATS_ADD_AND_UPDATE_PROCTITLE(bulbs_powered_on, -1); + } + RB_REMOVE(lgtd_lifx_bulb_map, &lgtd_lifx_bulbs_table, bulb); ++ char addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "closed bulb \"%.*s\" (%s) on [%s]:%hu", + LGTD_LIFX_LABEL_SIZE, + bulb->state.label, +- lgtd_addrtoa(bulb->addr), ++ LGTD_IEEE8023MACTOA(bulb->addr, addr), + bulb->gw->ip_addr, + bulb->gw->port + ); +diff --git a/lifx/gateway.c b/lifx/gateway.c +--- a/lifx/gateway.c ++++ b/lifx/gateway.c +@@ -76,9 +76,10 @@ + lgtd_lifx_gateway_remove_and_close_bulb(gw, bulb); + } + ++ char site[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "connection with gateway bulb [%s]:%hu (site %s) closed", +- gw->ip_addr, gw->port, lgtd_addrtoa(gw->site.as_array) ++ gw->ip_addr, gw->port, LGTD_IEEE8023MACTOA(gw->site.as_array, site) + ); + free(gw); + } +@@ -197,9 +198,10 @@ + gw, pkt_type, pkt, &pkt_info + ); + ++ char site[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "sending %s to site %s", +- pkt_info->name, lgtd_addrtoa(gw->site.as_array) ++ pkt_info->name, LGTD_IEEE8023MACTOA(gw->site.as_array, site) + ); + + return rv; // FIXME, have real return values on the send paths... +@@ -215,9 +217,10 @@ + gw, pkt_type, pkt, &pkt_info + ); + ++ char site[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "sending %s to site %s", +- pkt_info->name, lgtd_addrtoa(gw->site.as_array) ++ pkt_info->name, LGTD_IEEE8023MACTOA(gw->site.as_array, site) + ); + + return rv; // FIXME, have real return values on the send paths... +@@ -266,9 +269,10 @@ + bulb = lgtd_lifx_bulb_open(gw, bulb_addr); + if (bulb) { + SLIST_INSERT_HEAD(&gw->bulbs, bulb, link_by_gw); ++ char addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "bulb %s on [%s]:%hu", +- lgtd_addrtoa(bulb_addr), gw->ip_addr, gw->port ++ LGTD_IEEE8023MACTOA(bulb->addr, addr), gw->ip_addr, gw->port + ); + } + } +@@ -328,9 +332,11 @@ + goto error_allocate; + } + ++ char site_addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "gateway for site %s at [%s]:%hu", +- lgtd_addrtoa(gw->site.as_array), gw->ip_addr, gw->port ++ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr), ++ gw->ip_addr, gw->port + ); + LIST_INSERT_HEAD(&lgtd_lifx_gateways, gw, link); + +@@ -444,10 +450,12 @@ + LGTD_LIFX_WIRE_FOREACH_TAG_ID(tag_id, removed_tags) { + assert(gw->tag_refcounts[tag_id] > 0); + if (--gw->tag_refcounts[tag_id] == 0) { ++ char site[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "deleting unused tag [%s] (%d) from gw [%s]:%hu (site %s)", +- gw->tags[tag_id] ? gw->tags[tag_id]->label : NULL, tag_id, +- gw->ip_addr, gw->port, lgtd_addrtoa(gw->site.as_array) ++ gw->tags[tag_id] ? gw->tags[tag_id]->label : NULL, ++ tag_id, gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(gw->site.as_array, site) + ); + struct lgtd_lifx_packet_tag_labels pkt = { + .tags = ~(gw->tag_ids & ~LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id)) +@@ -465,10 +473,12 @@ + { + assert(gw && hdr && pkt); + ++ char addr[LGTD_LIFX_ADDR_STRLEN], site[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "SET_PAN_GATEWAY <-- [%s]:%hu - %s site=%s, service_type=%d", +- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), +- lgtd_addrtoa(hdr->site), pkt->service_type ++ gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), ++ LGTD_IEEE8023MACTOA(hdr->site, site), pkt->service_type + ); + } + +@@ -479,11 +489,13 @@ + { + assert(gw && hdr && pkt); + ++ char addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "SET_LIGHT_STATE <-- [%s]:%hu - %s " + "hue=%#hx, saturation=%#hx, brightness=%#hx, " + "kelvin=%d, dim=%#hx, power=%#hx, label=%.*s, tags=%#jx", +- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), ++ gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), + pkt->hue, pkt->saturation, pkt->brightness, pkt->kelvin, + pkt->dim, pkt->power, LGTD_LIFX_LABEL_SIZE, pkt->label, + (uintmax_t)pkt->tags +@@ -554,9 +566,11 @@ + { + assert(gw && hdr && pkt); + ++ char addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "SET_POWER_STATE <-- [%s]:%hu - %s power=%#hx", +- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), pkt->power ++ gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), pkt->power + ); + + struct lgtd_lifx_bulb *b = lgtd_lifx_gateway_get_or_open_bulb( +@@ -596,13 +610,15 @@ + assert(tag_id >= -1); + assert(tag_id < LGTD_LIFX_GATEWAY_MAX_TAGS); + ++ char site[LGTD_LIFX_ADDR_STRLEN]; ++ LGTD_IEEE8023MACTOA(gw->site.as_array, site); ++ + if (tag_id == -1) { + tag_id = lgtd_lifx_wire_bitscan64_forward(~gw->tag_ids); + if (tag_id == -1) { + lgtd_warnx( + "no tag_id left for new tag [%s] on gw [%s]:%hu (site %s)", +- tag_label, gw->ip_addr, gw->port, +- lgtd_addrtoa(gw->site.as_array) ++ tag_label, gw->ip_addr, gw->port, site + ); + return -1; + } +@@ -614,14 +630,13 @@ + if (!tag) { + lgtd_warn( + "couldn't allocate a new reference to tag [%s] (site %s)", +- tag_label, lgtd_addrtoa(gw->site.as_array) ++ tag_label, site + ); + return -1; + } + lgtd_debug( + "tag_id %d allocated for tag [%s] on gw [%s]:%hu (site %s)", +- tag_id, tag_label, gw->ip_addr, gw->port, +- lgtd_addrtoa(gw->site.as_array) ++ tag_id, tag_label, gw->ip_addr, gw->port, site + ); + gw->tag_ids |= LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id); + gw->tags[tag_id] = tag; +@@ -638,11 +653,12 @@ + assert(tag_id < LGTD_LIFX_GATEWAY_MAX_TAGS); + + if (gw->tag_ids & LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id)) { ++ char site[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "tag_id %d deallocated for tag [%s] on gw [%s]:%hu (site %s)", + tag_id, gw->tags[tag_id]->label, + gw->ip_addr, gw->port, +- lgtd_addrtoa(gw->site.as_array) ++ LGTD_IEEE8023MACTOA(gw->site.as_array, site) + ); + lgtd_lifx_tagging_decref(gw->tags[tag_id], gw); + gw->tag_ids &= ~LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id); +@@ -657,9 +673,11 @@ + { + assert(gw && hdr && pkt); + ++ char addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "SET_TAG_LABELS <-- [%s]:%hu - %s label=%.*s, tags=%jx", +- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), ++ gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), + LGTD_LIFX_LABEL_SIZE, pkt->label, (uintmax_t)pkt->tags + ); + +@@ -679,9 +697,11 @@ + { + assert(gw && hdr && pkt); + ++ char addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "SET_TAGS <-- [%s]:%hu - %s tags=%#jx", +- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), ++ gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), + (uintmax_t)pkt->tags + ); + +@@ -692,6 +712,7 @@ + return; + } + ++ char bulb_addr[LGTD_LIFX_ADDR_STRLEN], site_addr[LGTD_LIFX_ADDR_STRLEN]; + int tag_id; + LGTD_LIFX_WIRE_FOREACH_TAG_ID(tag_id, pkt->tags) { + if (!(gw->tag_ids & LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id))) { +@@ -699,8 +720,9 @@ + "trying to set unknown tag_id %d (%#jx) " + "on bulb %s (%.*s), gw [%s]:%hu (site %s)", + tag_id, LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id), +- lgtd_addrtoa(b->addr), LGTD_LIFX_LABEL_SIZE, b->state.label, +- gw->ip_addr, gw->port, lgtd_addrtoa(gw->site.as_array) ++ LGTD_IEEE8023MACTOA(b->addr, bulb_addr), ++ LGTD_LIFX_LABEL_SIZE, b->state.label, gw->ip_addr, gw->port, ++ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr) + ); + } + } +diff --git a/lifx/tagging.c b/lifx/tagging.c +--- a/lifx/tagging.c ++++ b/lifx/tagging.c +@@ -123,10 +123,11 @@ + if (dealloc_tag) { + lgtd_info("discovered tag [%s]", tag_label); + } ++ char site_addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_info( + "tag [%s] added to gw [%s]:%hu (site %s) with tag_id %d", + tag_label, gw->ip_addr, gw->port, +- lgtd_addrtoa(gw->site.as_array), tag_id ++ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr), tag_id + ); + site->gw = gw; + site->tag_id = tag_id; +@@ -147,10 +148,11 @@ + struct lgtd_lifx_site *site; + site = lgtd_lifx_tagging_find_site(&tag->sites, gw); + if (site) { ++ char site_addr[LGTD_LIFX_ADDR_STRLEN]; + lgtd_debug( + "tag [%s] removed from gw [%s]:%hu (site %s)", + tag->label, gw->ip_addr, gw->port, +- lgtd_addrtoa(gw->site.as_array) ++ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr) + ); + LIST_REMOVE(site, link); + free(site); +diff --git a/lifx/wire_proto.h b/lifx/wire_proto.h +--- a/lifx/wire_proto.h ++++ b/lifx/wire_proto.h +@@ -44,6 +44,7 @@ + enum { LGTD_LIFX_PROTOCOL_PORT = 56700 }; + + enum { LGTD_LIFX_ADDR_LENGTH = 6 }; ++enum { LGTD_LIFX_ADDR_STRLEN = 32 }; + + #pragma pack(push, 1) + +diff --git a/tests/core/proto/test_proto_tag_create.c b/tests/core/proto/test_proto_tag_create.c +--- a/tests/core/proto/test_proto_tag_create.c ++++ b/tests/core/proto/test_proto_tag_create.c +@@ -31,10 +31,12 @@ + } + + uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { 1, 2, 3, 4, 5 }; ++ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; + if (memcmp(bulb->addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { + errx( + 1, "got bulb with addr %s (expected %s)", +- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(expected_addr) ++ LGTD_IEEE8023MACTOA(bulb->addr, addr), ++ LGTD_IEEE8023MACTOA(expected_addr, expected) + ); + } + +diff --git a/tests/core/proto/test_proto_tag_update.c b/tests/core/proto/test_proto_tag_update.c +--- a/tests/core/proto/test_proto_tag_update.c ++++ b/tests/core/proto/test_proto_tag_update.c +@@ -33,10 +33,12 @@ + } + + uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { 5, 4, 3, 2, 1 }; ++ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; + if (memcmp(bulb->addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { + errx( + 1, "got bulb with addr %s (expected %s)", +- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(expected_addr) ++ LGTD_IEEE8023MACTOA(bulb->addr, addr), ++ LGTD_IEEE8023MACTOA(expected_addr, expected) + ); + } + +diff --git a/tests/core/proto/test_proto_untag.c b/tests/core/proto/test_proto_untag.c +--- a/tests/core/proto/test_proto_untag.c ++++ b/tests/core/proto/test_proto_untag.c +@@ -101,10 +101,12 @@ + } + + uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { 5, 4, 3, 2, 1 }; ++ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; + if (memcmp(bulb->addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { + errx( + 1, "got bulb with addr %s (expected %s)", +- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(expected_addr) ++ LGTD_IEEE8023MACTOA(bulb->addr, addr), ++ LGTD_IEEE8023MACTOA(expected_addr, expected) + ); + } + +diff --git a/tests/lifx/bulb/test_bulb_open.c b/tests/lifx/bulb/test_bulb_open.c +--- a/tests/lifx/bulb/test_bulb_open.c ++++ b/tests/lifx/bulb/test_bulb_open.c +@@ -14,10 +14,12 @@ + errx(1, "lgtd_lifx_bulb_open didn't return any bulb"); + } + ++ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; + if (memcmp(bulb->addr, bulb_addr, LGTD_LIFX_ADDR_LENGTH)) { + errx( + 1, "got bulb addr %s (expected %s)", +- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(bulb_addr) ++ LGTD_IEEE8023MACTOA(bulb->addr, addr), ++ LGTD_IEEE8023MACTOA(bulb_addr, expected) + ); + } + +diff --git a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c +--- a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c ++++ b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c +@@ -78,10 +78,13 @@ + uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { + 0, 0, 44, 0, 0, 0 + }; ++ char expected_addr_buf[LGTD_LIFX_ADDR_STRLEN]; ++ char dev_addr[LGTD_LIFX_ADDR_STRLEN]; + if (memcmp(hdr.target.device_addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { + lgtd_errx( + 1, "device addr = %s (expected = %s)", +- lgtd_addrtoa(hdr.target.device_addr), lgtd_addrtoa(expected_addr) ++ LGTD_IEEE8023MACTOA(hdr.target.device_addr, dev_addr), ++ LGTD_IEEE8023MACTOA(expected_addr, expected_addr_buf) + ); + } + if (le16toh(hdr.packet_type) != LGTD_LIFX_ECHO_REQUEST) { +@@ -109,7 +112,8 @@ + if (memcmp(hdr.target.device_addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { + lgtd_errx( + 1, "device addr = %s (expected = %s)", +- lgtd_addrtoa(hdr.target.device_addr), lgtd_addrtoa(expected_addr) ++ LGTD_IEEE8023MACTOA(hdr.target.device_addr, dev_addr), ++ LGTD_IEEE8023MACTOA(expected_addr, expected_addr_buf) + ); + } + if (hdr.size != 42) {
--- a/fix_sockaddrtoa_mess.patch Sat Aug 15 23:22:19 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,634 +0,0 @@ -# HG changeset patch -# Parent 44e0729fda3081537c2615a458b8d403867ca9b4 - -diff --git a/core/lightsd.h b/core/lightsd.h ---- a/core/lightsd.h -+++ b/core/lightsd.h -@@ -74,14 +74,15 @@ - extern struct lgtd_opts lgtd_opts; - extern struct event_base *lgtd_ev_base; - --const char *lgtd_addrtoa(const uint8_t *); -+char *lgtd_iee8023mactoa(const uint8_t *addr, char *buf, int buflen); -+#define LGTD_IEEE8023MACTOA(addr, buf) \ -+ lgtd_iee8023mactoa((addr), (buf), sizeof(buf)) - void lgtd_sockaddrtoa(const struct sockaddr_storage *, char *buf, int buflen); - short lgtd_sockaddrport(const struct sockaddr_storage *); - --void lgtd_print_duration(uint64_t, char *, int); --#define LGTD_PRINT_DURATION(secs, arr) do { \ -- lgtd_print_duration((secs), (arr), sizeof((arr))); \ --} while (0) -+char *lgtd_print_duration(uint64_t, char *, int); -+#define LGTD_PRINT_DURATION(secs, arr) \ -+ lgtd_print_duration((secs), (arr), sizeof((arr))) - - void _lgtd_err(void (*)(int, const char *, ...), int, const char *, ...) - __attribute__((format(printf, 3, 4))); -diff --git a/core/log.c b/core/log.c ---- a/core/log.c -+++ b/core/log.c -@@ -74,17 +74,18 @@ - fprintf(stderr, "[%s] %s", loglvl, showprogname ? "lightsd: " : ""); - } - --const char * --lgtd_addrtoa(const uint8_t *addr) -+char * -+lgtd_iee8023mactoa(const uint8_t *addr, char *buf, int buflen) - { - assert(addr); -+ assert(buf); -+ assert(buflen >= 2 * 6 + 5 + 1); - -- static char str[LGTD_LIFX_ADDR_LENGTH * 2 + LGTD_LIFX_ADDR_LENGTH - 1 + 1]; - snprintf( -- str, sizeof(str), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", -+ buf, buflen, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] - ); -- return str; -+ return buf; - } - - void -@@ -113,7 +114,7 @@ - } - } - --void -+char * - lgtd_print_duration(uint64_t secs, char *buf, int bufsz) - { - assert(buf); -@@ -131,6 +132,7 @@ - i = LGTD_MIN(i + n, bufsz); - } - snprintf(&buf[i], bufsz - i, "%02d:%02d", hours, minutes); -+ return buf; - } - - void -diff --git a/core/proto.c b/core/proto.c ---- a/core/proto.c -+++ b/core/proto.c -@@ -201,9 +201,16 @@ - SLIST_FOREACH(device, devices, link) { - struct lgtd_lifx_bulb *bulb = device->device; - -- char buf[2048]; -+ char buf[2048], -+ gw_addr[LGTD_LIFX_ADDR_STRLEN], -+ site_addr[LGTD_LIFX_ADDR_STRLEN], -+ bulb_addr[LGTD_LIFX_ADDR_STRLEN]; - int i = 0; - -+ LGTD_IEEE8023MACTOA(bulb->addr, bulb_addr); -+ LGTD_IEEE8023MACTOA(bulb->gw->addr, gw_addr); -+ LGTD_IEEE8023MACTOA(bulb->gw->site.as_array, site_addr); -+ - LGTD_SNPRINTF_APPEND( - buf, i, (int)sizeof(buf), - "{" -@@ -215,9 +222,7 @@ - "\"url\":\"tcp://[%s]:%hu\"," - "\"latency\":%ju" - "},", -- lgtd_addrtoa(bulb->addr), -- lgtd_addrtoa(bulb->gw->addr), -- lgtd_addrtoa(bulb->gw->site.as_array), -+ bulb_addr, gw_addr, site_addr, - bulb->gw->ip_addr, bulb->gw->port, - (uintmax_t)LGTD_LIFX_GATEWAY_LATENCY(bulb->gw) - ); -@@ -299,15 +304,14 @@ - "\"tags\":[", - h, s, b, bulb->state.kelvin, - bulb->state.power == LGTD_LIFX_POWER_ON ? "true" : "false", -- bulb->state.label[0] ? bulb->state.label : lgtd_addrtoa(bulb->addr) -+ bulb->state.label[0] ? bulb->state.label : bulb_addr - ); - - if (i >= (int)sizeof(buf)) { - lgtd_warnx( - "can't send state of bulb %s (%s) to client " - "[%s]:%hu: output buffer to small", -- bulb->state.label, lgtd_addrtoa(bulb->addr), -- client->ip_addr, client->port -+ bulb->state.label, bulb_addr, client->ip_addr, client->port - ); - continue; - } -@@ -326,8 +330,7 @@ - "tag_id %d on bulb %.*s (%s) doesn't " - "exist on gw [%s]:%hu (site %s)", - tag_id, (int)sizeof(bulb->state.label), bulb->state.label, -- lgtd_addrtoa(bulb->addr), bulb->gw->ip_addr, bulb->gw->port, -- lgtd_addrtoa(bulb->gw->site.as_array) -+ bulb_addr, bulb->gw->ip_addr, bulb->gw->port, site_addr - ); - } - } -diff --git a/core/router.c b/core/router.c ---- a/core/router.c -+++ b/core/router.c -@@ -106,7 +106,9 @@ - bulb->expected_power_on = payload->power; - } - -- lgtd_info("sending %s to %s", pkt_info->name, lgtd_addrtoa(bulb->addr)); -+ char addr[LGTD_LIFX_ADDR_STRLEN]; -+ LGTD_IEEE8023MACTOA(bulb->addr, addr); -+ lgtd_info("sending %s to %s", pkt_info->name, addr); - } - - void -diff --git a/lifx/bulb.c b/lifx/bulb.c ---- a/lifx/bulb.c -+++ b/lifx/bulb.c -@@ -153,11 +153,12 @@ - LGTD_STATS_ADD_AND_UPDATE_PROCTITLE(bulbs_powered_on, -1); - } - RB_REMOVE(lgtd_lifx_bulb_map, &lgtd_lifx_bulbs_table, bulb); -+ char addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_info( - "closed bulb \"%.*s\" (%s) on [%s]:%hu", - LGTD_LIFX_LABEL_SIZE, - bulb->state.label, -- lgtd_addrtoa(bulb->addr), -+ LGTD_IEEE8023MACTOA(bulb->addr, addr), - bulb->gw->ip_addr, - bulb->gw->port - ); -diff --git a/lifx/gateway.c b/lifx/gateway.c ---- a/lifx/gateway.c -+++ b/lifx/gateway.c -@@ -79,9 +79,10 @@ - lgtd_lifx_gateway_remove_and_close_bulb(gw, bulb); - } - -+ char site[LGTD_LIFX_ADDR_STRLEN]; - lgtd_info( - "connection with gateway bulb [%s]:%hu (site %s) closed", -- gw->ip_addr, gw->port, lgtd_addrtoa(gw->site.as_array) -+ gw->ip_addr, gw->port, LGTD_IEEE8023MACTOA(gw->site.as_array, site) - ); - free(gw); - } -@@ -200,9 +201,10 @@ - gw, pkt_type, pkt, &pkt_info - ); - -+ char site[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "sending %s to site %s", -- pkt_info->name, lgtd_addrtoa(gw->site.as_array) -+ pkt_info->name, LGTD_IEEE8023MACTOA(gw->site.as_array, site) - ); - - return rv; // FIXME, have real return values on the send paths... -@@ -218,9 +220,10 @@ - gw, pkt_type, pkt, &pkt_info - ); - -+ char site[LGTD_LIFX_ADDR_STRLEN]; - lgtd_info( - "sending %s to site %s", -- pkt_info->name, lgtd_addrtoa(gw->site.as_array) -+ pkt_info->name, LGTD_IEEE8023MACTOA(gw->site.as_array, site) - ); - - return rv; // FIXME, have real return values on the send paths... -@@ -269,9 +272,10 @@ - bulb = lgtd_lifx_bulb_open(gw, bulb_addr); - if (bulb) { - SLIST_INSERT_HEAD(&gw->bulbs, bulb, link_by_gw); -+ char addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_info( - "bulb %s on [%s]:%hu", -- lgtd_addrtoa(bulb_addr), gw->ip_addr, gw->port -+ LGTD_IEEE8023MACTOA(bulb->addr, addr), gw->ip_addr, gw->port - ); - } - } -@@ -362,9 +366,11 @@ - goto error_allocate; - } - -+ char site_addr[LGTD_LIFX_ADDR_STRLEN], addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_info( -- "gateway for site %s at [%s]:%hu", -- lgtd_addrtoa(gw->site.as_array), gw->ip_addr, gw->port -+ "gateway for site %s at [%s]:%hu (%s)", -+ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr), -+ gw->ip_addr, gw->port, LGTD_IEEE8023MACTOA(gw->addr, addr) - ); - LIST_INSERT_HEAD(&lgtd_lifx_gateways, gw, link); - -@@ -478,10 +484,12 @@ - LGTD_LIFX_WIRE_FOREACH_TAG_ID(tag_id, removed_tags) { - assert(gw->tag_refcounts[tag_id] > 0); - if (--gw->tag_refcounts[tag_id] == 0) { -+ char site[LGTD_LIFX_ADDR_STRLEN]; - lgtd_info( - "deleting unused tag [%s] (%d) from gw [%s]:%hu (site %s)", -- gw->tags[tag_id] ? gw->tags[tag_id]->label : NULL, tag_id, -- gw->ip_addr, gw->port, lgtd_addrtoa(gw->site.as_array) -+ gw->tags[tag_id] ? gw->tags[tag_id]->label : NULL, -+ tag_id, gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(gw->site.as_array, site) - ); - struct lgtd_lifx_packet_tag_labels pkt = { - .tags = ~(gw->tag_ids & ~LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id)) -@@ -499,10 +507,12 @@ - { - assert(gw && hdr && pkt); - -+ char addr[LGTD_LIFX_ADDR_STRLEN], site[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "SET_PAN_GATEWAY <-- [%s]:%hu - %s site=%s, service_type=%d", -- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -- lgtd_addrtoa(hdr->site), pkt->service_type -+ gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), -+ LGTD_IEEE8023MACTOA(hdr->site, site), pkt->service_type - ); - } - -@@ -513,11 +523,13 @@ - { - assert(gw && hdr && pkt); - -+ char addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "SET_LIGHT_STATE <-- [%s]:%hu - %s " - "hue=%#hx, saturation=%#hx, brightness=%#hx, " - "kelvin=%d, dim=%#hx, power=%#hx, label=%.*s, tags=%#jx", -- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), - pkt->hue, pkt->saturation, pkt->brightness, pkt->kelvin, - pkt->dim, pkt->power, LGTD_LIFX_LABEL_SIZE, pkt->label, - (uintmax_t)pkt->tags -@@ -584,9 +596,11 @@ - { - assert(gw && hdr && pkt); - -+ char addr[LGTD_LIFX_ADDR_LENGTH]; - lgtd_debug( - "SET_POWER_STATE <-- [%s]:%hu - %s power=%#hx", -- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), pkt->power -+ gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), pkt->power - ); - - LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -@@ -621,13 +635,15 @@ - assert(tag_id >= -1); - assert(tag_id < LGTD_LIFX_GATEWAY_MAX_TAGS); - -+ char site[LGTD_LIFX_ADDR_STRLEN]; -+ LGTD_IEEE8023MACTOA(gw->site.as_array, site); -+ - if (tag_id == -1) { - tag_id = lgtd_lifx_wire_bitscan64_forward(~gw->tag_ids); - if (tag_id == -1) { - lgtd_warnx( - "no tag_id left for new tag [%s] on gw [%s]:%hu (site %s)", -- tag_label, gw->ip_addr, gw->port, -- lgtd_addrtoa(gw->site.as_array) -+ tag_label, gw->ip_addr, gw->port, site - ); - return -1; - } -@@ -639,14 +655,13 @@ - if (!tag) { - lgtd_warn( - "couldn't allocate a new reference to tag [%s] (site %s)", -- tag_label, lgtd_addrtoa(gw->site.as_array) -+ tag_label, site - ); - return -1; - } - lgtd_debug( - "tag_id %d allocated for tag [%s] on gw [%s]:%hu (site %s)", -- tag_id, tag_label, gw->ip_addr, gw->port, -- lgtd_addrtoa(gw->site.as_array) -+ tag_id, tag_label, gw->ip_addr, gw->port, site - ); - gw->tag_ids |= LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id); - gw->tags[tag_id] = tag; -@@ -663,11 +678,12 @@ - assert(tag_id < LGTD_LIFX_GATEWAY_MAX_TAGS); - - if (gw->tag_ids & LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id)) { -+ char site[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "tag_id %d deallocated for tag [%s] on gw [%s]:%hu (site %s)", - tag_id, gw->tags[tag_id]->label, - gw->ip_addr, gw->port, -- lgtd_addrtoa(gw->site.as_array) -+ LGTD_IEEE8023MACTOA(gw->site.as_array, site) - ); - lgtd_lifx_tagging_decref(gw->tags[tag_id], gw); - gw->tag_ids &= ~LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id); -@@ -682,9 +698,11 @@ - { - assert(gw && hdr && pkt); - -+ char addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "SET_TAG_LABELS <-- [%s]:%hu - %s label=%.*s, tags=%jx", -- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), - LGTD_LIFX_LABEL_SIZE, pkt->label, (uintmax_t)pkt->tags - ); - -@@ -705,15 +723,18 @@ - { - assert(gw && hdr && pkt); - -+ char addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "SET_TAGS <-- [%s]:%hu - %s tags=%#jx", -- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), - (uintmax_t)pkt->tags - ); - - struct lgtd_lifx_bulb *b; - LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, hdr->target.device_addr); - -+ char bulb_addr[LGTD_LIFX_ADDR_STRLEN], site_addr[LGTD_LIFX_ADDR_STRLEN]; - int tag_id; - LGTD_LIFX_WIRE_FOREACH_TAG_ID(tag_id, pkt->tags) { - if (!(gw->tag_ids & LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id))) { -@@ -721,8 +742,9 @@ - "trying to set unknown tag_id %d (%#jx) " - "on bulb %s (%.*s), gw [%s]:%hu (site %s)", - tag_id, LGTD_LIFX_WIRE_TAG_ID_TO_VALUE(tag_id), -- lgtd_addrtoa(b->addr), LGTD_LIFX_LABEL_SIZE, b->state.label, -- gw->ip_addr, gw->port, lgtd_addrtoa(gw->site.as_array) -+ LGTD_IEEE8023MACTOA(b->addr, bulb_addr), -+ LGTD_LIFX_LABEL_SIZE, b->state.label, gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr) - ); - } - } -@@ -756,10 +778,12 @@ - return; - } - -+ char addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "%s <-- [%s]:%hu - %s " - "signal_strength=%f, rx_bytes=%u, tx_bytes=%u, temperature=%hu", -- type, gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ type, gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), - pkt->signal_strength, pkt->rx_bytes, pkt->tx_bytes, pkt->temperature - ); - -@@ -776,10 +800,6 @@ - { - assert(gw && hdr && pkt); - -- char built_at[64], installed_at[64]; -- LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->built_at, built_at); -- LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->installed_at, installed_at); -- - const char *type; - enum lgtd_lifx_bulb_ips ip_id; - switch (hdr->packet_type) { -@@ -799,11 +819,15 @@ - return; - } - -+ char built_at[64], installed_at[64], addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "%s <-- [%s]:%hu - %s " - "built_at=%s, installed_at=%s, version=%u", -- type, gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -- built_at, installed_at, pkt->version -+ type, gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->built_at, built_at), -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->installed_at, installed_at), -+ pkt->version - ); - - LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -@@ -819,10 +843,12 @@ - { - assert(gw && hdr && pkt); - -+ char addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "PRODUCT_INFO <-- [%s]:%hu - %s " - "vendor_id=%#x, product_id=%#x, version=%u", -- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), - pkt->vendor_id, pkt->product_id, pkt->version - ); - -@@ -839,15 +865,14 @@ - { - assert(gw && hdr && pkt); - -- char device_time[64], uptime[64], downtime[64]; -- LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->time, device_time); -- LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->uptime), uptime); -- LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->downtime), downtime); -- -+ char device_time[64], uptime[64], downtime[64], addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "PRODUCT_INFO <-- [%s]:%hu - %s time=%s, uptime=%s, downtime=%s", -- gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -- device_time, uptime, downtime -+ gw->ip_addr, gw->port, -+ LGTD_IEEE8023MACTOA(hdr->target.device_addr, addr), -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->time, device_time), -+ LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->uptime), uptime), -+ LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->downtime), downtime) - ); - - LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -diff --git a/lifx/tagging.c b/lifx/tagging.c ---- a/lifx/tagging.c -+++ b/lifx/tagging.c -@@ -123,10 +123,11 @@ - if (dealloc_tag) { - lgtd_info("discovered tag [%s]", tag_label); - } -+ char site_addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_info( - "tag [%s] added to gw [%s]:%hu (site %s) with tag_id %d", - tag_label, gw->ip_addr, gw->port, -- lgtd_addrtoa(gw->site.as_array), tag_id -+ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr), tag_id - ); - site->gw = gw; - site->tag_id = tag_id; -@@ -147,10 +148,11 @@ - struct lgtd_lifx_site *site; - site = lgtd_lifx_tagging_find_site(&tag->sites, gw); - if (site) { -+ char site_addr[LGTD_LIFX_ADDR_STRLEN]; - lgtd_debug( - "tag [%s] removed from gw [%s]:%hu (site %s)", - tag->label, gw->ip_addr, gw->port, -- lgtd_addrtoa(gw->site.as_array) -+ LGTD_IEEE8023MACTOA(gw->site.as_array, site_addr) - ); - LIST_REMOVE(site, link); - free(site); -diff --git a/lifx/wire_proto.c b/lifx/wire_proto.c ---- a/lifx/wire_proto.c -+++ b/lifx/wire_proto.c -@@ -465,7 +465,7 @@ - return LGTD_LIFX_WAVEFORM_INVALID; - } - --void -+char * - lgtd_lifx_wire_print_nsec_timestamp(uint64_t nsec_ts, char *buf, int bufsz) - { - assert(buf); -@@ -477,10 +477,11 @@ - if (gmtime_r(&ts, &tm_utc)) { - int64_t usecs = LGTD_NSECS_TO_USECS(nsec_ts - LGTD_SECS_TO_NSECS(ts)); - LGTD_TM_TO_ISOTIME(&tm_utc, buf, bufsz, usecs); -- return; -+ } else { -+ buf[0] = '\0'; - } - -- buf[0] = '\0'; -+ return buf; - } - - static void -diff --git a/lifx/wire_proto.h b/lifx/wire_proto.h ---- a/lifx/wire_proto.h -+++ b/lifx/wire_proto.h -@@ -44,6 +44,7 @@ - enum { LGTD_LIFX_PROTOCOL_PORT = 56700 }; - - enum { LGTD_LIFX_ADDR_LENGTH = 6 }; -+enum { LGTD_LIFX_ADDR_STRLEN = 32 }; - - #pragma pack(push, 1) - -@@ -355,10 +356,9 @@ - (tag_id_varname) = lgtd_lifx_wire_next_tag_id((tag_id_varname), (tags))) - - enum lgtd_lifx_waveform_type lgtd_lifx_wire_waveform_string_id_to_type(const char *, int); --void lgtd_lifx_wire_print_nsec_timestamp(uint64_t, char *, int); --#define LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(ts, arr) do { \ -- lgtd_lifx_wire_print_nsec_timestamp((ts), (arr), sizeof((arr))); \ --} while (0) -+char* lgtd_lifx_wire_print_nsec_timestamp(uint64_t, char *, int); -+#define LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(ts, arr) \ -+ lgtd_lifx_wire_print_nsec_timestamp((ts), (arr), sizeof((arr))) - - const struct lgtd_lifx_packet_info *lgtd_lifx_wire_get_packet_info(enum lgtd_lifx_packet_type); - void lgtd_lifx_wire_load_packet_info_map(void); -diff --git a/tests/core/proto/test_proto_tag_create.c b/tests/core/proto/test_proto_tag_create.c ---- a/tests/core/proto/test_proto_tag_create.c -+++ b/tests/core/proto/test_proto_tag_create.c -@@ -33,10 +33,12 @@ - } - - uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { 1, 2, 3, 4, 5 }; -+ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; - if (memcmp(bulb->addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { - errx( - 1, "got bulb with addr %s (expected %s)", -- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(expected_addr) -+ LGTD_IEEE8023MACTOA(bulb->addr, addr), -+ LGTD_IEEE8023MACTOA(expected_addr, expected) - ); - } - -diff --git a/tests/core/proto/test_proto_tag_update.c b/tests/core/proto/test_proto_tag_update.c ---- a/tests/core/proto/test_proto_tag_update.c -+++ b/tests/core/proto/test_proto_tag_update.c -@@ -35,10 +35,12 @@ - } - - uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { 5, 4, 3, 2, 1 }; -+ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; - if (memcmp(bulb->addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { - errx( - 1, "got bulb with addr %s (expected %s)", -- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(expected_addr) -+ LGTD_IEEE8023MACTOA(bulb->addr, addr), -+ LGTD_IEEE8023MACTOA(expected_addr, expected) - ); - } - -diff --git a/tests/core/proto/test_proto_untag.c b/tests/core/proto/test_proto_untag.c ---- a/tests/core/proto/test_proto_untag.c -+++ b/tests/core/proto/test_proto_untag.c -@@ -103,10 +103,12 @@ - } - - uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { 5, 4, 3, 2, 1 }; -+ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; - if (memcmp(bulb->addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { - errx( - 1, "got bulb with addr %s (expected %s)", -- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(expected_addr) -+ LGTD_IEEE8023MACTOA(bulb->addr, addr), -+ LGTD_IEEE8023MACTOA(expected_addr, expected) - ); - } - -diff --git a/tests/lifx/bulb/test_bulb_open.c b/tests/lifx/bulb/test_bulb_open.c ---- a/tests/lifx/bulb/test_bulb_open.c -+++ b/tests/lifx/bulb/test_bulb_open.c -@@ -16,10 +16,12 @@ - errx(1, "lgtd_lifx_bulb_open didn't return any bulb"); - } - -+ char addr[LGTD_LIFX_ADDR_STRLEN], expected[LGTD_LIFX_ADDR_STRLEN]; - if (memcmp(bulb->addr, bulb_addr, LGTD_LIFX_ADDR_LENGTH)) { - errx( - 1, "got bulb addr %s (expected %s)", -- lgtd_addrtoa(bulb->addr), lgtd_addrtoa(bulb_addr) -+ LGTD_IEEE8023MACTOA(bulb->addr, addr), -+ LGTD_IEEE8023MACTOA(bulb_addr, expected) - ); - } - -diff --git a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c ---- a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c -+++ b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c -@@ -78,10 +78,13 @@ - uint8_t expected_addr[LGTD_LIFX_ADDR_LENGTH] = { - 0, 0, 44, 0, 0, 0 - }; -+ char expected_addr_buf[LGTD_LIFX_ADDR_STRLEN]; -+ char dev_addr[LGTD_LIFX_ADDR_STRLEN]; - if (memcmp(hdr.target.device_addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { - lgtd_errx( - 1, "device addr = %s (expected = %s)", -- lgtd_addrtoa(hdr.target.device_addr), lgtd_addrtoa(expected_addr) -+ LGTD_IEEE8023MACTOA(hdr.target.device_addr, dev_addr), -+ LGTD_IEEE8023MACTOA(expected_addr, expected_addr_buf) - ); - } - if (le16toh(hdr.packet_type) != LGTD_LIFX_ECHO_REQUEST) { -@@ -109,7 +112,8 @@ - if (memcmp(hdr.target.device_addr, expected_addr, LGTD_LIFX_ADDR_LENGTH)) { - lgtd_errx( - 1, "device addr = %s (expected = %s)", -- lgtd_addrtoa(hdr.target.device_addr), lgtd_addrtoa(expected_addr) -+ LGTD_IEEE8023MACTOA(hdr.target.device_addr, dev_addr), -+ LGTD_IEEE8023MACTOA(expected_addr, expected_addr_buf) - ); - } - if (hdr.size != 42) {
--- a/implement_some_metadata_packet_types.patch Sat Aug 15 23:22:19 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1385 +0,0 @@ -# HG changeset patch -# Parent de1c6a01d9955785187b591d15ab41b516c7cb78 -Handle various informational packet types - -- MCU state & firmware info; -- WiFi state & firmware info; -- device/runtime info. - -diff --git a/core/daemon.c b/core/daemon.c ---- a/core/daemon.c -+++ b/core/daemon.c -@@ -106,10 +106,9 @@ - char title[LGTD_DAEMON_TITLE_SIZE] = { 0 }; - int i = 0; - --#define TITLE_APPEND(fmt, ...) do { \ -- int n = snprintf((&title[i]), (sizeof(title) - i), (fmt), __VA_ARGS__); \ -- i = LGTD_MIN(i + n, (int)sizeof(title)); \ --} while (0) -+#define TITLE_APPEND(fmt, ...) LGTD_SNPRINTF_APPEND( \ -+ title, i, (int)sizeof(title), (fmt), __VA_ARGS__ \ -+) - - #define PREFIX(fmt, ...) TITLE_APPEND( \ - "%s" fmt, (i && title[i - 1] == ')' ? "; " : ""), __VA_ARGS__ \ -diff --git a/core/lightsd.h b/core/lightsd.h ---- a/core/lightsd.h -+++ b/core/lightsd.h -@@ -24,10 +24,33 @@ - #define LGTD_ABS(v) ((v) >= 0 ? (v) : (v) * -1) - #define LGTD_MIN(a, b) ((a) < (b) ? (a) : (b)) - #define LGTD_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) --#define LGTD_MSECS_TO_TIMEVAL(v) { \ -+#define LGTD_MSECS_TO_TIMEVAL(v) { \ - .tv_sec = (v) / 1000, \ - .tv_usec = ((v) % 1000) * 1000 \ - } -+#define LGTD_NSECS_TO_USECS(v) ((v) / (unsigned int)1E6) -+#define LGTD_NSECS_TO_SECS(v) ((v) / (unsigned int)1E9) -+#define LGTD_SECS_TO_NSECS(v) ((v) * (unsigned int)1E9) -+#define LGTD_TM_TO_ISOTIME(tm, sbuf, bufsz, usec) do { \ -+ /* '2015-01-02T10:13:16.132222+00:00' */ \ -+ if ((usec)) { \ -+ snprintf( \ -+ (sbuf), (bufsz), "%d-%02d-%02dT%02d:%02d:%02d.%jd%c%02ld:%02ld", \ -+ 1900 + (tm)->tm_year, 1 + (tm)->tm_mon, (tm)->tm_mday, \ -+ (tm)->tm_hour, (tm)->tm_min, (tm)->tm_sec, (intmax_t)usec, \ -+ (tm)->tm_gmtoff >= 0 ? '+' : '-', /* %+02ld doesn't work */ \ -+ LGTD_ABS((tm)->tm_gmtoff / 60 / 60), (tm)->tm_gmtoff % (60 * 60) \ -+ ); \ -+ } else { \ -+ snprintf( \ -+ (sbuf), (bufsz), "%d-%02d-%02dT%02d:%02d:%02d%c%02ld:%02ld", \ -+ 1900 + (tm)->tm_year, 1 + (tm)->tm_mon, (tm)->tm_mday, \ -+ (tm)->tm_hour, (tm)->tm_min, (tm)->tm_sec, \ -+ (tm)->tm_gmtoff >= 0 ? '+' : '-', /* %+02ld doesn't work */ \ -+ LGTD_ABS((tm)->tm_gmtoff / 60 / 60), (tm)->tm_gmtoff % (60 * 60) \ -+ ); \ -+ } \ -+} while (0) - #define LGTD_SNPRINTF_APPEND(buf, i, bufsz, ...) do { \ - int n = snprintf(&(buf)[(i)], bufsz - i, __VA_ARGS__); \ - (i) = LGTD_MIN((i) + n, bufsz); \ -@@ -55,6 +78,11 @@ - void lgtd_sockaddrtoa(const struct sockaddr_storage *, char *buf, int buflen); - short lgtd_sockaddrport(const struct sockaddr_storage *); - -+void lgtd_print_duration(uint64_t, char *, int); -+#define LGTD_PRINT_DURATION(secs, arr) do { \ -+ lgtd_print_duration((secs), (arr), sizeof((arr))); \ -+} while (0) -+ - void _lgtd_err(void (*)(int, const char *, ...), int, const char *, ...) - __attribute__((format(printf, 3, 4))); - #define lgtd_err(eval, fmt, ...) _lgtd_err(err, (eval), (fmt), ##__VA_ARGS__); -diff --git a/core/log.c b/core/log.c ---- a/core/log.c -+++ b/core/log.c -@@ -53,14 +53,7 @@ - if (!localtime_r(&now.tv_sec, &tm_now)) { - goto error; - } -- // '2015-01-02T10:13:16.132222+00:00' -- snprintf( -- strbuf, bufsz, "%d-%02d-%02dT%02d:%02d:%02d.%jd%c%02ld:%02ld", -- 1900 + tm_now.tm_year, 1 + tm_now.tm_mon, tm_now.tm_mday, -- tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, -- (intmax_t)now.tv_usec, tm_now.tm_gmtoff >= 0 ? '+' : '-', // %+02ld doesn't work -- LGTD_ABS(tm_now.tm_gmtoff / 60 / 60), tm_now.tm_gmtoff % (60 * 60) -- ); -+ LGTD_TM_TO_ISOTIME(&tm_now, strbuf, bufsz, now.tv_usec); - return; - error: - strbuf[0] = '\0'; -@@ -121,6 +114,26 @@ - } - - void -+lgtd_print_duration(uint64_t secs, char *buf, int bufsz) -+{ -+ assert(buf); -+ assert(bufsz > 0); -+ -+ int days = secs / (60 * 60 * 24); -+ int minutes = secs / 60; -+ int hours = minutes / 60; -+ hours = hours % 24; -+ minutes = minutes % 60; -+ -+ int i = 0; -+ if (days) { -+ int n = snprintf(buf, bufsz, "%d days ", days); -+ i = LGTD_MIN(i + n, bufsz); -+ } -+ snprintf(&buf[i], bufsz - i, "%02d:%02d", hours, minutes); -+} -+ -+void - _lgtd_err(void (*errfn)(int, const char *, ...), - int eval, - const char *fmt, -diff --git a/core/proto.c b/core/proto.c ---- a/core/proto.c -+++ b/core/proto.c -@@ -195,36 +195,114 @@ - return; - } - -- static const char *state_fmt = ("{" -- "\"hsbk\":[%s,%s,%s,%hu]," -- "\"power\":%s," -- "\"label\":\"%s\"," -- "\"tags\":["); -+ lgtd_client_start_send_response(client); -+ lgtd_client_write_string(client, "["); -+ struct lgtd_router_device *device; -+ SLIST_FOREACH(device, devices, link) { -+ struct lgtd_lifx_bulb *bulb = device->device; -+ -+ char buf[2048]; -+ int i = 0; -+ -+ LGTD_SNPRINTF_APPEND( -+ buf, i, (int)sizeof(buf), -+ "{" -+ "\"_lifx\":{" -+ "\"addr\": \"%s\"," -+ "\"gateway\":{" -+ "\"addr\":\"%s\"," -+ "\"site\":\"%s\"," -+ "\"url\":\"tcp://[%s]:%hu\"," -+ "\"latency\":%ju" -+ "},", -+ lgtd_addrtoa(bulb->addr), -+ lgtd_addrtoa(bulb->gw->addr), -+ lgtd_addrtoa(bulb->gw->site.as_array), -+ bulb->gw->ip_addr, bulb->gw->port, -+ (uintmax_t)LGTD_LIFX_GATEWAY_LATENCY(bulb->gw) -+ ); -+ -+#define PRINT_LIFX_FW_TIMESTAMPS(fw_info, built_at_buf, installed_at_buf) \ -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP((fw_info)->built_at, (built_at_buf)); \ -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP( \ -+ (fw_info)->installed_at, (installed_at_buf) \ -+ ) -+ -+ for (int ip = 0; ip != LGTD_LIFX_BULB_IP_COUNT; ip++) { -+ char fw_built_at[64], fw_installed_at[64]; -+ PRINT_LIFX_FW_TIMESTAMPS( -+ &bulb->ips[ip].fw_info, fw_built_at, fw_installed_at -+ ); -+ -+ LGTD_SNPRINTF_APPEND( -+ buf, i, (int)sizeof(buf), -+ "\"%s\":{" -+ "\"firmware_built_at\":\"%s\"," -+ "\"firmware_installed_at\":\"%s\"," -+ "\"firmware_version\":\"%x\"," -+ "\"signal_strength\":%f," -+ "\"tx_bytes\":%u," -+ "\"rx_bytes\":%u," -+ "\"temperature\":%u" -+ "},", -+ lgtd_lifx_bulb_ip_names[ip], -+ fw_built_at, fw_installed_at, bulb->ips[ip].fw_info.version, -+ bulb->ips[ip].state.signal_strength, -+ bulb->ips[ip].state.tx_bytes, -+ bulb->ips[ip].state.rx_bytes, -+ bulb->ips[ip].state.temperature -+ ); -+ } -+ -+ LGTD_SNPRINTF_APPEND( -+ buf, i, (int)sizeof(buf), -+ "\"product_info\":{" -+ "\"vendor_id\":\"%x\"," -+ "\"product_id\":\"%x\"," -+ "\"version\":%u" -+ "},", -+ bulb->product_info.vendor_id, -+ bulb->product_info.product_id, -+ bulb->product_info.version -+ ); -+ -+ char bulb_time[64]; -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(bulb->runtime_info.time, bulb_time); -+ LGTD_SNPRINTF_APPEND( -+ buf, i, (int)sizeof(buf), -+ "\"runtime_info\":{" -+ "\"time\":\"%s\"," -+ "\"uptime\":%ju," -+ "\"downtime\":%ju" -+ "}" -+ "},", -+ bulb_time, -+ (uintmax_t)LGTD_NSECS_TO_SECS(bulb->runtime_info.uptime), -+ (uintmax_t)LGTD_NSECS_TO_SECS(bulb->runtime_info.downtime) -+ ); - - #define PRINT_COMPONENT(src, dst, start, stop) \ - lgtd_jsonrpc_uint16_range_to_float_string( \ - (src), (start), (stop), (dst), sizeof((dst)) \ - ) - -- lgtd_client_start_send_response(client); -- lgtd_client_write_string(client, "["); -- struct lgtd_router_device *device; -- SLIST_FOREACH(device, devices, link) { -- struct lgtd_lifx_bulb *bulb = device->device; -- - char h[16], s[16], b[16]; - PRINT_COMPONENT(bulb->state.hue, h, 0, 360); - PRINT_COMPONENT(bulb->state.saturation, s, 0, 1); - PRINT_COMPONENT(bulb->state.brightness, b, 0, 1); - -- char buf[3072]; -- int written = snprintf( -- buf, sizeof(buf), state_fmt, -+ LGTD_SNPRINTF_APPEND( -+ buf, i, (int)sizeof(buf), -+ "\"hsbk\":[%s,%s,%s,%hu]," -+ "\"power\":%s," -+ "\"label\":\"%s\"," -+ "\"tags\":[", - h, s, b, bulb->state.kelvin, - bulb->state.power == LGTD_LIFX_POWER_ON ? "true" : "false", - bulb->state.label[0] ? bulb->state.label : lgtd_addrtoa(bulb->addr) - ); -- if (written >= (int)sizeof(buf)) { -+ -+ if (i >= (int)sizeof(buf)) { - lgtd_warnx( - "can't send state of bulb %s (%s) to client " - "[%s]:%hu: output buffer to small", -diff --git a/examples/lightsc.py b/examples/lightsc.py ---- a/examples/lightsc.py -+++ b/examples/lightsc.py -@@ -17,7 +17,7 @@ - "id": str(uuid.uuid4()), - } - socket.send(json.dumps(payload).encode("utf-8")) -- response = socket.recv(2048).decode("utf-8") -+ response = socket.recv(8192).decode("utf-8") - try: - response = json.loads(response) - except ValueError: -diff --git a/lifx/bulb.c b/lifx/bulb.c ---- a/lifx/bulb.c -+++ b/lifx/bulb.c -@@ -33,12 +33,57 @@ - #include "bulb.h" - #include "gateway.h" - #include "core/daemon.h" -+#include "timer.h" - #include "core/stats.h" -+#include "core/jsmn.h" -+#include "core/jsonrpc.h" -+#include "core/client.h" -+#include "core/proto.h" -+#include "core/router.h" - #include "core/lightsd.h" - - struct lgtd_lifx_bulb_map lgtd_lifx_bulbs_table = - RB_INITIALIZER(&lgtd_lifx_bulbs_table); - -+const char * const lgtd_lifx_bulb_ip_names[] = { "mcu", "wifi" }; -+ -+static void -+lgtd_lifx_bulb_fetch_hardware_info(struct lgtd_lifx_timer *timer, -+ union lgtd_lifx_timer_ctx ctx) -+{ -+ assert(timer); -+ assert(ctx.as_uint); -+ -+ // Get the bulb again, it might have been closed while we were waiting: -+ const uint8_t *bulb_addr = (const uint8_t *)&ctx.as_uint; -+ struct lgtd_lifx_bulb *bulb = lgtd_lifx_bulb_get(bulb_addr); -+ if (!bulb) { -+ lgtd_lifx_timer_stop_timer(timer); -+ return; -+ } -+ -+#define RESEND_IF(test, pkt_type) do { \ -+ if ((test)) { \ -+ stop = false; \ -+ lgtd_router_send_to_device(bulb, (pkt_type), NULL); \ -+ } \ -+} while (0) -+ -+ bool stop = true; -+ RESEND_IF(!bulb->product_info.vendor_id, LGTD_LIFX_GET_VERSION); -+ RESEND_IF( -+ !bulb->ips[LGTD_LIFX_BULB_MCU_IP].fw_info.version, -+ LGTD_LIFX_GET_MESH_FIRMWARE -+ ); -+ RESEND_IF( -+ !bulb->ips[LGTD_LIFX_BULB_WIFI_IP].fw_info.version, -+ LGTD_LIFX_GET_WIFI_FIRMWARE_STATE -+ ); -+ if (stop) { -+ lgtd_lifx_timer_stop_timer(timer); -+ } -+} -+ - struct lgtd_lifx_bulb * - lgtd_lifx_bulb_get(const uint8_t *addr) - { -@@ -68,6 +113,14 @@ - - bulb->last_light_state_at = lgtd_time_monotonic_msecs(); - -+ union lgtd_lifx_timer_ctx ctx = { .as_uint = 0 }; -+ memcpy(&ctx.as_uint, addr, LGTD_LIFX_ADDR_LENGTH); -+ lgtd_lifx_timer_start_timer( -+ LGTD_LIFX_BULB_FETCH_HARDWARE_INFO_TIMER_MSECS, -+ lgtd_lifx_bulb_fetch_hardware_info, -+ ctx -+ ); -+ - return bulb; - } - -@@ -123,6 +176,7 @@ - LGTD_STATS_ADD_AND_UPDATE_PROCTITLE( - bulbs_powered_on, state->power == LGTD_LIFX_POWER_ON ? 1 : -1 - ); -+ lgtd_router_send_to_device(bulb, LGTD_LIFX_GET_INFO, NULL); - } - - lgtd_lifx_gateway_update_tag_refcounts(bulb->gw, bulb->state.tags, state->tags); -@@ -140,6 +194,7 @@ - LGTD_STATS_ADD_AND_UPDATE_PROCTITLE( - bulbs_powered_on, power == LGTD_LIFX_POWER_ON ? 1 : -1 - ); -+ lgtd_router_send_to_device(bulb, LGTD_LIFX_GET_INFO, NULL); - } - - bulb->state.power = power; -@@ -154,3 +209,53 @@ - - bulb->state.tags = tags; - } -+ -+void -+lgtd_lifx_bulb_set_ip_state(struct lgtd_lifx_bulb *bulb, -+ enum lgtd_lifx_bulb_ips ip_id, -+ const struct lgtd_lifx_ip_state *state, -+ lgtd_time_mono_t received_at) -+{ -+ assert(bulb); -+ assert(state); -+ -+ struct lgtd_lifx_bulb_ip *ip = &bulb->ips[ip_id]; -+ ip->state_updated_at = received_at; -+ memcpy(&ip->state, state, sizeof(ip->state)); -+} -+ -+void -+lgtd_lifx_bulb_set_ip_firmware_info(struct lgtd_lifx_bulb *bulb, -+ enum lgtd_lifx_bulb_ips ip_id, -+ const struct lgtd_lifx_ip_firmware_info *info, -+ lgtd_time_mono_t received_at) -+{ -+ assert(bulb); -+ assert(info); -+ -+ struct lgtd_lifx_bulb_ip *ip = &bulb->ips[ip_id]; -+ ip->fw_info_updated_at = received_at; -+ memcpy(&ip->fw_info, info, sizeof(ip->fw_info)); -+} -+ -+void -+lgtd_lifx_bulb_set_product_info(struct lgtd_lifx_bulb *bulb, -+ const struct lgtd_lifx_product_info *info) -+{ -+ assert(bulb); -+ assert(info); -+ -+ memcpy(&bulb->product_info, info, sizeof(bulb->product_info)); -+} -+ -+void -+lgtd_lifx_bulb_set_runtime_info(struct lgtd_lifx_bulb *bulb, -+ const struct lgtd_lifx_runtime_info *info, -+ lgtd_time_mono_t received_at) -+{ -+ assert(bulb); -+ assert(info); -+ -+ bulb->runtime_info_updated_at = received_at; -+ memcpy(&bulb->runtime_info, info, sizeof(bulb->runtime_info)); -+} -diff --git a/lifx/bulb.h b/lifx/bulb.h ---- a/lifx/bulb.h -+++ b/lifx/bulb.h -@@ -30,17 +30,64 @@ - char label[LGTD_LIFX_LABEL_SIZE]; - uint64_t tags; - }; -+ -+struct lgtd_lifx_ip_state { -+ float signal_strength; // mW -+ uint32_t tx_bytes; -+ uint32_t rx_bytes; -+ uint16_t temperature; // Deci-celcius: e.g 24.3 -> 2430 -+}; -+ -+struct lgtd_lifx_ip_firmware_info { -+ uint64_t built_at; // ns since epoch -+ uint64_t installed_at; // ns since epoch -+ uint32_t version; -+}; -+ -+struct lgtd_lifx_product_info { -+ uint32_t vendor_id; -+ uint32_t product_id; -+ uint32_t version; -+}; -+ -+struct lgtd_lifx_runtime_info { -+ uint64_t time; // ns since epoch -+ uint64_t uptime; // ns -+ uint64_t downtime; // ns, last power off period duration -+}; - #pragma pack(pop) - -+enum { LGTD_LIFX_BULB_FETCH_HARDWARE_INFO_TIMER_MSECS = 5000 }; -+ -+enum lgtd_lifx_bulb_ips { -+ LGTD_LIFX_BULB_MCU_IP = 0, -+ LGTD_LIFX_BULB_WIFI_IP, -+ LGTD_LIFX_BULB_IP_COUNT, -+}; -+ -+// keyed with enum lgtd_lifx_bulb_ips: -+extern const char * const lgtd_lifx_bulb_ip_names[]; -+ -+struct lgtd_lifx_bulb_ip { -+ struct lgtd_lifx_ip_state state; -+ lgtd_time_mono_t state_updated_at; -+ struct lgtd_lifx_ip_firmware_info fw_info; -+ lgtd_time_mono_t fw_info_updated_at; -+}; -+ - struct lgtd_lifx_bulb { - RB_ENTRY(lgtd_lifx_bulb) link; - SLIST_ENTRY(lgtd_lifx_bulb) link_by_gw; -- struct lgtd_lifx_gateway *gw; -- uint8_t addr[LGTD_LIFX_ADDR_LENGTH]; -- struct lgtd_lifx_light_state state; - lgtd_time_mono_t last_light_state_at; -+ lgtd_time_mono_t runtime_info_updated_at; - lgtd_time_mono_t dirty_at; - uint16_t expected_power_on; -+ uint8_t addr[LGTD_LIFX_ADDR_LENGTH]; -+ struct lgtd_lifx_gateway *gw; -+ struct lgtd_lifx_light_state state; -+ struct lgtd_lifx_bulb_ip ips[LGTD_LIFX_BULB_IP_COUNT]; -+ struct lgtd_lifx_product_info product_info; -+ struct lgtd_lifx_runtime_info runtime_info; - }; - RB_HEAD(lgtd_lifx_bulb_map, lgtd_lifx_bulb); - SLIST_HEAD(lgtd_lifx_bulb_list, lgtd_lifx_bulb); -@@ -69,3 +116,17 @@ - lgtd_time_mono_t); - void lgtd_lifx_bulb_set_power_state(struct lgtd_lifx_bulb *, uint16_t); - void lgtd_lifx_bulb_set_tags(struct lgtd_lifx_bulb *, uint64_t); -+ -+void lgtd_lifx_bulb_set_ip_state(struct lgtd_lifx_bulb *bulb, -+ enum lgtd_lifx_bulb_ips ip_id, -+ const struct lgtd_lifx_ip_state *state, -+ lgtd_time_mono_t received_at); -+void lgtd_lifx_bulb_set_ip_firmware_info(struct lgtd_lifx_bulb *bulb, -+ enum lgtd_lifx_bulb_ips ip_id, -+ const struct lgtd_lifx_ip_firmware_info *info, -+ lgtd_time_mono_t received_at); -+void lgtd_lifx_bulb_set_product_info(struct lgtd_lifx_bulb *, -+ const struct lgtd_lifx_product_info *); -+void lgtd_lifx_bulb_set_runtime_info(struct lgtd_lifx_bulb *, -+ const struct lgtd_lifx_runtime_info *, -+ lgtd_time_mono_t); -diff --git a/lifx/gateway.c b/lifx/gateway.c ---- a/lifx/gateway.c -+++ b/lifx/gateway.c -@@ -15,12 +15,15 @@ - // You should have received a copy of the GNU General Public License - // along with lighstd. If not, see <http://www.gnu.org/licenses/>. - -+#include <sys/ioctl.h> - #include <sys/queue.h> -+#include <sys/socket.h> - #include <sys/tree.h> - #include <assert.h> - #include <endian.h> - #include <err.h> - #include <errno.h> -+#include <net/if_arp.h> - #include <stdarg.h> - #include <stdbool.h> - #include <stdint.h> -@@ -275,6 +278,28 @@ - return bulb; - } - -+// TODO: make a separate shared library to resolve ip addresses to mac -+// addresses: -+static bool -+lgtd_lifx_gateway_resolve_ipv4_addr(int socket, -+ const struct sockaddr_in *sin, -+ uint8_t *hw_addr) -+{ -+ assert(sin); -+ assert(hw_addr); -+ assert(socket >= 0); -+ -+ struct arpreq req; -+ memset(&req, 0, sizeof(req)); -+ memcpy(&req.arp_pa, sin, sizeof(*sin)); -+ memcpy(req.arp_dev, "br0", 4); -+ if (!ioctl(socket, SIOCGARP, &req)) { -+ memcpy(hw_addr, req.arp_ha.sa_data, LGTD_LIFX_ADDR_LENGTH); -+ return true; -+ } -+ return false; -+} -+ - struct lgtd_lifx_gateway * - lgtd_lifx_gateway_open(const struct sockaddr_storage *peer, - ev_socklen_t addrlen, -@@ -310,10 +335,20 @@ - gw->refresh_ev = evtimer_new( - lgtd_ev_base, lgtd_lifx_gateway_refresh_callback, gw - ); -+ - memcpy(&gw->peer, peer, sizeof(gw->peer)); - lgtd_sockaddrtoa(peer, gw->ip_addr, sizeof(gw->ip_addr)); - gw->port = lgtd_sockaddrport(peer); - memcpy(gw->site.as_array, site, sizeof(gw->site.as_array)); -+ if (peer->ss_family == AF_INET) { -+ bool ok = lgtd_lifx_gateway_resolve_ipv4_addr( -+ gw->socket, (const struct sockaddr_in *)peer, gw->addr -+ ); -+ if (!ok) { -+ lgtd_warn("couldn't resolve %s to a LIFX address", gw->ip_addr); -+ } -+ } -+ - gw->last_req_at = received_at; - gw->next_req_at = received_at; - gw->last_pkt_at = received_at; -@@ -489,12 +524,8 @@ - (uintmax_t)pkt->tags - ); - -- struct lgtd_lifx_bulb *b = lgtd_lifx_gateway_get_or_open_bulb( -- gw, hdr->target.device_addr -- ); -- if (!b) { -- return; -- } -+ struct lgtd_lifx_bulb *b; -+ LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, hdr->target.device_addr); - - assert(sizeof(*pkt) == sizeof(b->state)); - lgtd_lifx_bulb_set_light_state( -@@ -519,7 +550,7 @@ - } - } - -- int latency = gw->last_pkt_at - gw->last_req_at; -+ int latency = LGTD_LIFX_GATEWAY_LATENCY(gw); - if (latency < LGTD_LIFX_GATEWAY_MIN_REFRESH_INTERVAL_MSECS) { - if (!event_pending(gw->refresh_ev, EV_TIMEOUT, NULL)) { - int timeout = LGTD_LIFX_GATEWAY_MIN_REFRESH_INTERVAL_MSECS - latency; -@@ -559,14 +590,9 @@ - gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), pkt->power - ); - -- struct lgtd_lifx_bulb *b = lgtd_lifx_gateway_get_or_open_bulb( -- gw, hdr->target.device_addr -+ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -+ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_power_state, pkt->power - ); -- if (!b) { -- return; -- } -- -- lgtd_lifx_bulb_set_power_state(b, pkt->power); - } - - int -@@ -673,9 +699,10 @@ - } - } - --void lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *gw, -- const struct lgtd_lifx_packet_header *hdr, -- const struct lgtd_lifx_packet_tags *pkt) -+void -+lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_tags *pkt) - { - assert(gw && hdr && pkt); - -@@ -685,12 +712,8 @@ - (uintmax_t)pkt->tags - ); - -- struct lgtd_lifx_bulb *b = lgtd_lifx_gateway_get_or_open_bulb( -- gw, hdr->target.device_addr -- ); -- if (!b) { -- return; -- } -+ struct lgtd_lifx_bulb *b; -+ LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, hdr->target.device_addr); - - int tag_id; - LGTD_LIFX_WIRE_FOREACH_TAG_ID(tag_id, pkt->tags) { -@@ -707,3 +730,129 @@ - - lgtd_lifx_bulb_set_tags(b, pkt->tags); - } -+ -+void -+lgtd_lifx_gateway_handle_ip_state(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_ip_state *pkt) -+{ -+ assert(gw && hdr && pkt); -+ -+ const char *type; -+ enum lgtd_lifx_bulb_ips ip_id; -+ switch (hdr->packet_type) { -+ case LGTD_LIFX_MESH_INFO: -+ type = "MCU_STATE"; -+ ip_id = LGTD_LIFX_BULB_MCU_IP; -+ break; -+ case LGTD_LIFX_WIFI_INFO: -+ type = "WIFI_STATE"; -+ ip_id = LGTD_LIFX_BULB_WIFI_IP; -+ break; -+ default: -+ lgtd_info("invalid ip state packet_type %#hx", hdr->packet_type); -+#ifndef NDEBUG -+ abort(); -+#endif -+ return; -+ } -+ -+ lgtd_debug( -+ "%s <-- [%s]:%hu - %s " -+ "signal_strength=%f, rx_bytes=%u, tx_bytes=%u, temperature=%hu", -+ type, gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ pkt->signal_strength, pkt->rx_bytes, pkt->tx_bytes, pkt->temperature -+ ); -+ -+ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -+ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_ip_state, -+ ip_id, (const struct lgtd_lifx_ip_state *)pkt, gw->last_pkt_at -+ ); -+} -+ -+void -+lgtd_lifx_gateway_handle_ip_firmware_info(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_ip_firmware_info *pkt) -+{ -+ assert(gw && hdr && pkt); -+ -+ char built_at[64], installed_at[64]; -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->built_at, built_at); -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->installed_at, installed_at); -+ -+ const char *type; -+ enum lgtd_lifx_bulb_ips ip_id; -+ switch (hdr->packet_type) { -+ case LGTD_LIFX_MESH_FIRMWARE: -+ type = "MCU_FIRMWARE_INFO"; -+ ip_id = LGTD_LIFX_BULB_MCU_IP; -+ break; -+ case LGTD_LIFX_WIFI_FIRMWARE_STATE: -+ type = "WIFI_FIRMWARE_INFO"; -+ ip_id = LGTD_LIFX_BULB_WIFI_IP; -+ break; -+ default: -+ lgtd_info("invalid ip firmware packet_type %#hx", hdr->packet_type); -+#ifndef NDEBUG -+ abort(); -+#endif -+ return; -+ } -+ -+ lgtd_debug( -+ "%s <-- [%s]:%hu - %s " -+ "built_at=%s, installed_at=%s, version=%u", -+ type, gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ built_at, installed_at, pkt->version -+ ); -+ -+ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -+ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_ip_firmware_info, -+ ip_id, (const struct lgtd_lifx_ip_firmware_info *)pkt, gw->last_pkt_at -+ ); -+} -+ -+void -+lgtd_lifx_gateway_handle_product_info(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_product_info *pkt) -+{ -+ assert(gw && hdr && pkt); -+ -+ lgtd_debug( -+ "PRODUCT_INFO <-- [%s]:%hu - %s " -+ "vendor_id=%#x, product_id=%#x, version=%u", -+ gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ pkt->vendor_id, pkt->product_id, pkt->version -+ ); -+ -+ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -+ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_product_info, -+ (const struct lgtd_lifx_product_info *)pkt -+ ); -+} -+ -+void -+lgtd_lifx_gateway_handle_runtime_info(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_runtime_info *pkt) -+{ -+ assert(gw && hdr && pkt); -+ -+ char device_time[64], uptime[64], downtime[64]; -+ LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(pkt->time, device_time); -+ LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->uptime), uptime); -+ LGTD_PRINT_DURATION(LGTD_NSECS_TO_SECS(pkt->downtime), downtime); -+ -+ lgtd_debug( -+ "PRODUCT_INFO <-- [%s]:%hu - %s time=%s, uptime=%s, downtime=%s", -+ gw->ip_addr, gw->port, lgtd_addrtoa(hdr->target.device_addr), -+ device_time, uptime, downtime -+ ); -+ -+ LGTD_LIFX_GATEWAY_SET_BULB_ATTR( -+ gw, hdr->target.device_addr, lgtd_lifx_bulb_set_runtime_info, -+ (const struct lgtd_lifx_runtime_info *)pkt, gw->last_pkt_at -+ ); -+} -diff --git a/lifx/gateway.h b/lifx/gateway.h ---- a/lifx/gateway.h -+++ b/lifx/gateway.h -@@ -36,12 +36,19 @@ - struct lgtd_lifx_gateway { - LIST_ENTRY(lgtd_lifx_gateway) link; - struct lgtd_lifx_bulb_list bulbs; -+#define LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, bulb_addr) do { \ -+ (b) = lgtd_lifx_gateway_get_or_open_bulb((gw), (bulb_addr)); \ -+ if (!(b)) { \ -+ return; \ -+ } \ -+} while (0) - // Multiple gateways can share the same site (that happens when bulbs are - // far away enough that ZigBee can't be used). Moreover the SET_PAN_GATEWAY - // packet doesn't include the device address in the header (i.e: site and - // device_addr have the same value) so we have no choice but to use the - // remote ip address to identify a gateway: - struct sockaddr_storage peer; -+ uint8_t addr[LGTD_LIFX_ADDR_LENGTH]; - char ip_addr[INET6_ADDRSTRLEN]; - uint16_t port; - // TODO: just use an integer and rename it to site_id: -@@ -60,6 +67,7 @@ - lgtd_time_mono_t last_req_at; - lgtd_time_mono_t next_req_at; - lgtd_time_mono_t last_pkt_at; -+#define LGTD_LIFX_GATEWAY_LATENCY(gw) ((gw)->last_pkt_at - (gw)->last_req_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; \ -@@ -77,6 +85,12 @@ - - extern struct lgtd_lifx_gateway_list lgtd_lifx_gateways; - -+#define LGTD_LIFX_GATEWAY_SET_BULB_ATTR(gw, bulb_addr, bulb_fn, ...) do { \ -+ struct lgtd_lifx_bulb *b; \ -+ LGTD_LIFX_GATEWAY_GET_BULB_OR_RETURN(b, gw, bulb_addr); \ -+ (bulb_fn)(b, __VA_ARGS__); \ -+} while (0) -+ - struct lgtd_lifx_gateway *lgtd_lifx_gateway_get(const struct sockaddr_storage *); - struct lgtd_lifx_gateway *lgtd_lifx_gateway_open(const struct sockaddr_storage *, - ev_socklen_t, -@@ -119,3 +133,15 @@ - void lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *, - const struct lgtd_lifx_packet_header *, - const struct lgtd_lifx_packet_tags *); -+void lgtd_lifx_gateway_handle_ip_state(struct lgtd_lifx_gateway *, -+ const struct lgtd_lifx_packet_header *, -+ const struct lgtd_lifx_packet_ip_state *); -+void lgtd_lifx_gateway_handle_ip_firmware_info(struct lgtd_lifx_gateway *, -+ const struct lgtd_lifx_packet_header *, -+ const struct lgtd_lifx_packet_ip_firmware_info *); -+void lgtd_lifx_gateway_handle_product_info(struct lgtd_lifx_gateway *, -+ const struct lgtd_lifx_packet_header *, -+ const struct lgtd_lifx_packet_product_info *); -+void lgtd_lifx_gateway_handle_runtime_info(struct lgtd_lifx_gateway *, -+ const struct lgtd_lifx_packet_header *, -+ const struct lgtd_lifx_packet_runtime_info *); -diff --git a/lifx/timer.c b/lifx/timer.c ---- a/lifx/timer.c -+++ b/lifx/timer.c -@@ -201,7 +201,6 @@ - if (event_add(lgtd_lifx_timer_context.watchdog_interval_ev, &tv)) { - lgtd_err(1, "can't start watchdog"); - } -- lgtd_debug("starting watchdog timer"); - } - } - -diff --git a/lifx/wire_proto.c b/lifx/wire_proto.c ---- a/lifx/wire_proto.c -+++ b/lifx/wire_proto.c -@@ -24,8 +24,10 @@ - #include <stdarg.h> - #include <stdbool.h> - #include <stdint.h> -+#include <stdio.h> - #include <stdlib.h> - #include <string.h> -+#include <time.h> - - #include <event2/util.h> - -@@ -74,12 +76,32 @@ - (void)pkt; - } - -+static void -+lgtd_lifx_wire_enosys_packet_handler(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const void *pkt) -+{ -+ (void)pkt; -+ -+ const struct lgtd_lifx_packet_info *pkt_info; -+ pkt_info = lgtd_lifx_wire_get_packet_info(hdr->packet_type); -+ bool addressable = hdr->protocol & LGTD_LIFX_PROTOCOL_ADDRESSABLE; -+ bool tagged = hdr->protocol & LGTD_LIFX_PROTOCOL_TAGGED; -+ unsigned int protocol = hdr->protocol & LGTD_LIFX_PROTOCOL_VERSION_MASK; -+ lgtd_info( -+ "%s <-- [%s]:%hu - (Unimplemented, header info: " -+ "addressable=%d, tagged=%d, protocol=%d)", -+ pkt_info->name, gw->ip_addr, gw->port, -+ addressable, tagged, protocol -+ ); -+} -+ - void - lgtd_lifx_wire_load_packet_info_map(void) - { - #define DECODER(x) ((void (*)(void *))(x)) - #define ENCODER(x) ((void (*)(void *))(x)) --#define HANDLER(x) \ -+#define HANDLER(x) \ - ((void (*)(struct lgtd_lifx_gateway *, \ - const struct lgtd_lifx_packet_header *, \ - const void *))(x)) -@@ -90,6 +112,10 @@ - #define REQUEST_ONLY \ - .decode = lgtd_lifx_wire_null_packet_encoder_decoder, \ - .handle = lgtd_lifx_wire_null_packet_handler -+#define UNIMPLEMENTED \ -+ .decode = lgtd_lifx_wire_null_packet_encoder_decoder, \ -+ .encode = lgtd_lifx_wire_null_packet_encoder_decoder, \ -+ .handle = lgtd_lifx_wire_enosys_packet_handler - - static struct lgtd_lifx_packet_info packet_table[] = { - // Gateway packets: -@@ -187,6 +213,211 @@ - .size = sizeof(struct lgtd_lifx_packet_tags), - .decode = DECODER(lgtd_lifx_wire_decode_tags), - .handle = HANDLER(lgtd_lifx_gateway_handle_tags) -+ }, -+ { -+ REQUEST_ONLY, -+ NO_PAYLOAD, -+ .name = "GET_MESH_INFO", -+ .type = LGTD_LIFX_GET_MESH_INFO -+ }, -+ { -+ RESPONSE_ONLY, -+ .name = "MESH_INFO", -+ .type = LGTD_LIFX_MESH_INFO, -+ .size = sizeof(struct lgtd_lifx_packet_ip_state), -+ .decode = DECODER(lgtd_lifx_wire_decode_ip_state), -+ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_state) -+ }, -+ { -+ REQUEST_ONLY, -+ NO_PAYLOAD, -+ .name = "GET_MESH_FIRMWARE", -+ .type = LGTD_LIFX_GET_MESH_FIRMWARE -+ }, -+ { -+ RESPONSE_ONLY, -+ .name = "MESH_FIRMWARE", -+ .type = LGTD_LIFX_MESH_FIRMWARE, -+ .size = sizeof(struct lgtd_lifx_packet_ip_firmware_info), -+ .decode = DECODER(lgtd_lifx_wire_decode_ip_firmware_info), -+ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_firmware_info) -+ }, -+ { -+ REQUEST_ONLY, -+ NO_PAYLOAD, -+ .name = "GET_WIFI_INFO", -+ .type = LGTD_LIFX_GET_WIFI_INFO, -+ }, -+ { -+ RESPONSE_ONLY, -+ .name = "WIFI_INFO", -+ .type = LGTD_LIFX_WIFI_INFO, -+ .size = sizeof(struct lgtd_lifx_packet_ip_state), -+ .decode = DECODER(lgtd_lifx_wire_decode_ip_state), -+ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_state) -+ }, -+ { -+ REQUEST_ONLY, -+ NO_PAYLOAD, -+ .name = "GET_WIFI_FIRMWARE_STATE", -+ .type = LGTD_LIFX_GET_WIFI_FIRMWARE_STATE -+ }, -+ { -+ RESPONSE_ONLY, -+ .name = "WIFI_FIRMWARE_STATE", -+ .type = LGTD_LIFX_WIFI_FIRMWARE_STATE, -+ .size = sizeof(struct lgtd_lifx_packet_ip_firmware_info), -+ .decode = DECODER(lgtd_lifx_wire_decode_ip_firmware_info), -+ .handle = HANDLER(lgtd_lifx_gateway_handle_ip_firmware_info) -+ }, -+ { -+ REQUEST_ONLY, -+ NO_PAYLOAD, -+ .name = "GET_VERSION", -+ .type = LGTD_LIFX_GET_VERSION -+ }, -+ { -+ RESPONSE_ONLY, -+ .name = "VERSION_STATE", -+ .type = LGTD_LIFX_VERSION_STATE, -+ .size = sizeof(struct lgtd_lifx_packet_product_info), -+ .decode = DECODER(lgtd_lifx_wire_decode_product_info), -+ .handle = HANDLER(lgtd_lifx_gateway_handle_product_info) -+ }, -+ { -+ REQUEST_ONLY, -+ NO_PAYLOAD, -+ .name = "GET_INFO", -+ .type = LGTD_LIFX_GET_INFO -+ }, -+ { -+ RESPONSE_ONLY, -+ .name = "INFO_STATE", -+ .type = LGTD_LIFX_INFO_STATE, -+ .size = sizeof(struct lgtd_lifx_packet_runtime_info), -+ .decode = DECODER(lgtd_lifx_wire_decode_runtime_info), -+ .handle = HANDLER(lgtd_lifx_gateway_handle_runtime_info) -+ }, -+ // Unimplemented but "known" packets -+ { -+ UNIMPLEMENTED, -+ .name = "GET_TIME", -+ .type = LGTD_LIFX_GET_TIME -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "SET_TIME", -+ .type = LGTD_LIFX_SET_TIME -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "TIME_STATE", -+ .type = LGTD_LIFX_TIME_STATE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "GET_RESET_SWITCH_STATE", -+ .type = LGTD_LIFX_GET_RESET_SWITCH_STATE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "RESET_SWITCH_STATE", -+ .type = LGTD_LIFX_RESET_SWITCH_STATE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "GET_BULB_LABEL", -+ .type = LGTD_LIFX_GET_BULB_LABEL -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "SET_BULB_LABEL", -+ .type = LGTD_LIFX_SET_BULB_LABEL -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "BULB_LABEL", -+ .type = LGTD_LIFX_BULB_LABEL -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "GET_MCU_RAIL_VOLTAGE", -+ .type = LGTD_LIFX_GET_MCU_RAIL_VOLTAGE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "MCU_RAIL_VOLTAGE", -+ .type = LGTD_LIFX_MCU_RAIL_VOLTAGE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "REBOOT", -+ .type = LGTD_LIFX_REBOOT -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "SET_FACTORY_TEST_MODE", -+ .type = LGTD_LIFX_SET_FACTORY_TEST_MODE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "DISABLE_FACTORY_TEST_MODE", -+ .type = LGTD_LIFX_DISABLE_FACTORY_TEST_MODE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "ACK", -+ .type = LGTD_LIFX_ACK -+ }, -+ { -+ 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 -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "SET_DIM_RELATIVE", -+ .type = LGTD_LIFX_SET_DIM_RELATIVE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "GET_WIFI_STATE", -+ .type = LGTD_LIFX_GET_WIFI_STATE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "SET_WIFI_STATE", -+ .type = LGTD_LIFX_SET_WIFI_STATE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "WIFI_STATE", -+ .type = LGTD_LIFX_WIFI_STATE -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "GET_ACCESS_POINTS", -+ .type = LGTD_LIFX_GET_ACCESS_POINTS -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "SET_ACCESS_POINTS", -+ .type = LGTD_LIFX_SET_ACCESS_POINTS -+ }, -+ { -+ UNIMPLEMENTED, -+ .name = "ACCESS_POINT", -+ .type = LGTD_LIFX_ACCESS_POINT - } - }; - -@@ -234,6 +465,24 @@ - return LGTD_LIFX_WAVEFORM_INVALID; - } - -+void -+lgtd_lifx_wire_print_nsec_timestamp(uint64_t nsec_ts, char *buf, int bufsz) -+{ -+ assert(buf); -+ assert(bufsz > 0); -+ -+ time_t ts = LGTD_NSECS_TO_SECS(nsec_ts); -+ -+ struct tm tm_utc; -+ if (gmtime_r(&ts, &tm_utc)) { -+ int64_t usecs = LGTD_NSECS_TO_USECS(nsec_ts - LGTD_SECS_TO_NSECS(ts)); -+ LGTD_TM_TO_ISOTIME(&tm_utc, buf, bufsz, usecs); -+ return; -+ } -+ -+ buf[0] = '\0'; -+} -+ - static void - lgtd_lifx_wire_encode_header(struct lgtd_lifx_packet_header *hdr, int flags) - { -@@ -423,3 +672,44 @@ - - pkt->tags = le64toh(pkt->tags); - } -+ -+void -+lgtd_lifx_wire_decode_ip_state(struct lgtd_lifx_packet_ip_state *pkt) -+{ -+ assert(pkt); -+ -+ pkt->signal_strength = lgtd_lifx_wire_lefloattoh(pkt->signal_strength); -+ pkt->tx_bytes = le32toh(pkt->tx_bytes); -+ pkt->rx_bytes = le32toh(pkt->rx_bytes); -+ pkt->temperature = le16toh(pkt->temperature); -+} -+ -+void -+lgtd_lifx_wire_decode_ip_firmware_info(struct lgtd_lifx_packet_ip_firmware_info *pkt) -+{ -+ assert(pkt); -+ -+ pkt->built_at = le64toh(pkt->built_at); -+ pkt->installed_at = le64toh(pkt->installed_at); -+ pkt->version = le32toh(pkt->version); -+} -+ -+void -+lgtd_lifx_wire_decode_product_info(struct lgtd_lifx_packet_product_info *pkt) -+{ -+ assert(pkt); -+ -+ pkt->vendor_id = le32toh(pkt->vendor_id); -+ pkt->product_id = le32toh(pkt->product_id); -+ pkt->version = le32toh(pkt->version); -+} -+ -+void -+lgtd_lifx_wire_decode_runtime_info(struct lgtd_lifx_packet_runtime_info *pkt) -+{ -+ assert(pkt); -+ -+ pkt->time = le64toh(pkt->time); -+ pkt->uptime = le64toh(pkt->uptime); -+ pkt->downtime = le64toh(pkt->downtime); -+} -diff --git a/lifx/wire_proto.h b/lifx/wire_proto.h ---- a/lifx/wire_proto.h -+++ b/lifx/wire_proto.h -@@ -28,7 +28,7 @@ - static inline floatle_t - lgtd_lifx_wire_htolefloat(float f) - { -- union { float f; uint32_t i; } u = { .f = f }; -+ union { float f; uint32_t i; } u = { .f = f }; - htole32(u.i); - return u.f; - } -@@ -36,7 +36,7 @@ - static inline floatle_t - lgtd_lifx_wire_lefloattoh(float f) - { -- union { float f; uint32_t i; } u = { .f = f }; -+ union { float f; uint32_t i; } u = { .f = f }; - le32toh(u.i); - return u.f; - } -@@ -249,6 +249,30 @@ - char label[LGTD_LIFX_LABEL_SIZE]; - }; - -+struct lgtd_lifx_packet_ip_state { -+ floatle_t signal_strength; -+ uint32le_t tx_bytes; -+ uint32le_t rx_bytes; -+ uint16le_t temperature; -+}; -+ -+struct lgtd_lifx_packet_ip_firmware_info { -+ uint64le_t built_at; -+ uint64le_t installed_at; -+ uint32le_t version; -+}; -+ -+struct lgtd_lifx_packet_product_info { -+ uint32le_t vendor_id; -+ uint32le_t product_id; -+ uint32le_t version; -+}; -+ -+struct lgtd_lifx_packet_runtime_info { -+ uint64le_t time; -+ uint64le_t uptime; -+ uint64le_t downtime; -+}; - #pragma pack(pop) - - enum lgtd_lifx_header_flags { -@@ -330,8 +354,11 @@ - (tag_id_varname) != -1; \ - (tag_id_varname) = lgtd_lifx_wire_next_tag_id((tag_id_varname), (tags))) - -- - enum lgtd_lifx_waveform_type lgtd_lifx_wire_waveform_string_id_to_type(const char *, int); -+void lgtd_lifx_wire_print_nsec_timestamp(uint64_t, char *, int); -+#define LGTD_LIFX_WIRE_PRINT_NSEC_TIMESTAMP(ts, arr) do { \ -+ lgtd_lifx_wire_print_nsec_timestamp((ts), (arr), sizeof((arr))); \ -+} while (0) - - const struct lgtd_lifx_packet_info *lgtd_lifx_wire_get_packet_info(enum lgtd_lifx_packet_type); - void lgtd_lifx_wire_load_packet_info_map(void); -@@ -356,3 +383,8 @@ - void lgtd_lifx_wire_decode_tags(struct lgtd_lifx_packet_tags *); - void lgtd_lifx_wire_encode_tag_labels(struct lgtd_lifx_packet_tag_labels *); - void lgtd_lifx_wire_decode_tag_labels(struct lgtd_lifx_packet_tag_labels *); -+ -+void lgtd_lifx_wire_decode_ip_state(struct lgtd_lifx_packet_ip_state *); -+void lgtd_lifx_wire_decode_ip_firmware_info(struct lgtd_lifx_packet_ip_firmware_info *); -+void lgtd_lifx_wire_decode_product_info(struct lgtd_lifx_packet_product_info *); -+void lgtd_lifx_wire_decode_runtime_info(struct lgtd_lifx_packet_runtime_info *); -diff --git a/tests/lifx/mock_gateway.h b/tests/lifx/mock_gateway.h ---- a/tests/lifx/mock_gateway.h -+++ b/tests/lifx/mock_gateway.h -@@ -129,3 +129,51 @@ - (void)pkt_tags; - } - #endif -+ -+#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_IP_STATE -+void -+lgtd_lifx_gateway_handle_ip_state(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_ip_state *pkt) -+{ -+ (void)gw; -+ (void)hdr; -+ (void)pkt; -+} -+#endif -+ -+#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_IP_FIRMWARE_INFO -+void -+lgtd_lifx_gateway_handle_ip_firmware_info(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_ip_firmware_info *pkt) -+{ -+ (void)gw; -+ (void)hdr; -+ (void)pkt; -+} -+#endif -+ -+#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_PRODUCT_INFO -+void -+lgtd_lifx_gateway_handle_product_info(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_product_info *pkt) -+{ -+ (void)gw; -+ (void)hdr; -+ (void)pkt; -+} -+#endif -+ -+#ifndef MOCKED_LGTD_LIFX_GATEWAY_HANDLE_RUNTIME_INFO -+void -+lgtd_lifx_gateway_handle_runtime_info(struct lgtd_lifx_gateway *gw, -+ const struct lgtd_lifx_packet_header *hdr, -+ const struct lgtd_lifx_packet_runtime_info *pkt) -+{ -+ (void)gw; -+ (void)hdr; -+ (void)pkt; -+} -+#endif -diff --git a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c ---- a/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c -+++ b/tests/lifx/wire_proto/test_wire_proto_encode_decode_header.c -@@ -2,7 +2,7 @@ - - #include "wire_proto.c" - --#include "test_wire_proto_utils.h" -+#include "mock_gateway.h" - - int - main(void) -diff --git a/tests/lifx/wire_proto/test_wire_proto_utils.h b/tests/lifx/wire_proto/test_wire_proto_utils.h -deleted file mode 100644 ---- a/tests/lifx/wire_proto/test_wire_proto_utils.h -+++ /dev/null -@@ -1,46 +0,0 @@ --#pragma once -- --void lgtd_lifx_gateway_handle_pan_gateway(struct lgtd_lifx_gateway *gw, -- const struct lgtd_lifx_packet_header *hdr, -- const struct lgtd_lifx_packet_pan_gateway *pkt) --{ -- (void)gw; -- (void)hdr; -- (void)pkt; --} -- --void lgtd_lifx_gateway_handle_light_status(struct lgtd_lifx_gateway *gw, -- const struct lgtd_lifx_packet_header *hdr, -- const struct lgtd_lifx_packet_light_status *pkt) --{ -- (void)gw; -- (void)hdr; -- (void)pkt; --} -- --void lgtd_lifx_gateway_handle_power_state(struct lgtd_lifx_gateway *gw, -- const struct lgtd_lifx_packet_header *hdr, -- const struct lgtd_lifx_packet_power_state *pkt) --{ -- (void)gw; -- (void)hdr; -- (void)pkt; --} -- --void lgtd_lifx_gateway_handle_tag_labels(struct lgtd_lifx_gateway *gw, -- const struct lgtd_lifx_packet_header *hdr, -- const struct lgtd_lifx_packet_tag_labels *pkt) --{ -- (void)gw; -- (void)hdr; -- (void)pkt; --} -- --void lgtd_lifx_gateway_handle_tags(struct lgtd_lifx_gateway *gw, -- const struct lgtd_lifx_packet_header *hdr, -- const struct lgtd_lifx_packet_tags *pkt) --{ -- (void)gw; -- (void)hdr; -- (void)pkt; --} -diff --git a/tests/lifx/wire_proto/test_wire_proto_waveform_table.c b/tests/lifx/wire_proto/test_wire_proto_waveform_table.c ---- a/tests/lifx/wire_proto/test_wire_proto_waveform_table.c -+++ b/tests/lifx/wire_proto/test_wire_proto_waveform_table.c -@@ -1,6 +1,6 @@ - #include "wire_proto.c" - --#include "test_wire_proto_utils.h" -+#include "mock_gateway.h" - - int - main(void)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/make_device_timeout_2_5x_force_refresh.patch Sun Aug 16 00:48:06 2015 -0700 @@ -0,0 +1,18 @@ +# HG changeset patch +# Parent 81c70d56434dba896d023f0f182d81de64b00a4e +Bump the device timeout to 2.5x device force refresh + +This will let us do more retries before we drop devices. + +diff --git a/lifx/timer.h b/lifx/timer.h +--- a/lifx/timer.h ++++ b/lifx/timer.h +@@ -20,7 +20,7 @@ + enum { LGTD_LIFX_TIMER_WATCHDOG_INTERVAL_MSECS = 500 }; + enum { LGTD_LIFX_TIMER_ACTIVE_DISCOVERY_INTERVAL_MSECS = 2000 }; + enum { LGTD_LIFX_TIMER_PASSIVE_DISCOVERY_INTERVAL_MSECS = 10000 }; +-enum { LGTD_LIFX_TIMER_DEVICE_TIMEOUT_MSECS = 3000 }; ++enum { LGTD_LIFX_TIMER_DEVICE_TIMEOUT_MSECS = 5000 }; + enum { LGTD_LIFX_TIMER_DEVICE_FORCE_REFRESH_MSECS = 2000 }; + + bool lgtd_lifx_timer_setup(void);
--- a/series Sat Aug 15 23:22:19 2015 -0700 +++ b/series Sun Aug 16 00:48:06 2015 -0700 @@ -1,4 +1,5 @@ +fix_addrtoa_mess.patch +make_device_timeout_2_5x_force_refresh.patch add_start_stop_timer.patch -implement_some_metadata_packet_types.patch -fix_sockaddrtoa_mess.patch -blublu +expose_a_bunch_of_metadata_in_get_light_state.patch +add_ipv4_to_ieee8023mac.patch #+future #+linux