| /* Full-stack IoT client example. */ |
| |
| /* |
| * Copyright (c) 2018 Linaro Ltd |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <logging/log.h> |
| |
| LOG_MODULE_REGISTER(net_google_iot_mqtt, LOG_LEVEL_INF); |
| |
| #include <zephyr.h> |
| |
| #include "dhcp.h" |
| #include "protocol.h" |
| |
| #include <net/sntp.h> |
| #include <net/net_config.h> |
| #include <net/net_event.h> |
| |
| /* This comes from newlib. */ |
| #include <time.h> |
| #include <inttypes.h> |
| |
| #ifdef CONFIG_STDOUT_CONSOLE |
| # include <stdio.h> |
| # define PRINT printf |
| #else |
| # define PRINT printk |
| #endif |
| |
| s64_t time_base; |
| |
| void do_sntp(struct addrinfo *addr) |
| { |
| struct sntp_ctx ctx; |
| int rc; |
| s64_t stamp; |
| u64_t epoch_time; |
| char time_str[sizeof("1970-01-01T00:00:00")]; |
| |
| LOG_INF("Sending NTP request for current time:"); |
| |
| /* Initialize sntp */ |
| rc = sntp_init(&ctx, addr->ai_addr, sizeof(struct sockaddr_in)); |
| if (rc < 0) { |
| LOG_ERR("Unable to init sntp context: %d", rc); |
| return; |
| } |
| |
| rc = sntp_request(&ctx, K_FOREVER, &epoch_time); |
| if (rc == 0) { |
| stamp = k_uptime_get(); |
| time_base = epoch_time * MSEC_PER_SEC - stamp; |
| |
| /* Convert time to make sure. */ |
| time_t now = epoch_time; |
| struct tm now_tm; |
| |
| gmtime_r(&now, &now_tm); |
| strftime(time_str, sizeof(time_str), "%FT%T", &now_tm); |
| LOG_INF(" Acquired time: %s", log_strdup(time_str)); |
| |
| } else { |
| LOG_ERR(" Failed to acquire SNTP, code %d\n", rc); |
| } |
| |
| sntp_close(&ctx); |
| } |
| |
| /* |
| * TODO: These need to be configurable. |
| */ |
| #define MBEDTLS_NETWORK_TIMEOUT 30000 |
| |
| static void show_addrinfo(struct addrinfo *addr) |
| { |
| char hr_addr[NET_IPV6_ADDR_LEN]; |
| void *a; |
| |
| top: |
| LOG_DBG(" flags : %d", addr->ai_flags); |
| LOG_DBG(" family : %d", addr->ai_family); |
| LOG_DBG(" socktype: %d", addr->ai_socktype); |
| LOG_DBG(" protocol: %d", addr->ai_protocol); |
| LOG_DBG(" addrlen : %d", addr->ai_addrlen); |
| |
| /* Assume two words. */ |
| LOG_DBG(" addr[0]: 0x%lx", ((uint32_t *)addr->ai_addr)[0]); |
| LOG_DBG(" addr[1]: 0x%lx", ((uint32_t *)addr->ai_addr)[1]); |
| |
| if (addr->ai_next != 0) { |
| addr = addr->ai_next; |
| goto top; |
| } |
| |
| a = &net_sin(addr->ai_addr)->sin_addr; |
| |
| LOG_INF(" Got %s", |
| log_strdup(net_addr_ntop(addr->ai_family, a, |
| hr_addr, sizeof(hr_addr)))); |
| |
| } |
| |
| /* |
| * Things that make sense in a demo app that would need to be more |
| * robust in a real application: |
| * |
| * - DHCP happens once. If it fails, or we change networks, the |
| * network will just stop working. |
| * |
| */ |
| void main(void) |
| { |
| char time_ip[NET_IPV6_ADDR_LEN]; |
| static struct addrinfo hints; |
| struct addrinfo *haddr; |
| int res; |
| int cnt = 0; |
| |
| LOG_INF("Main entered"); |
| |
| app_dhcpv4_startup(); |
| |
| LOG_INF("Should have DHCPv4 lease at this point."); |
| |
| hints.ai_family = AF_INET; |
| hints.ai_socktype = SOCK_DGRAM; |
| hints.ai_protocol = 0; |
| while ((res = getaddrinfo("time.google.com", "123", &hints, |
| &haddr)) && cnt < 3) { |
| LOG_ERR("Unable to get address for NTP server, retrying"); |
| cnt++; |
| } |
| |
| if (res != 0) { |
| LOG_ERR("Unable to get address of NTP server, exiting %d", res); |
| return; |
| } |
| |
| |
| LOG_INF("DNS resolved for time.google.com:123"); |
| time_base = 0; |
| inet_ntop(AF_INET, &net_sin(haddr->ai_addr)->sin_addr, time_ip, |
| haddr->ai_addrlen); |
| show_addrinfo(haddr); |
| do_sntp(haddr); |
| freeaddrinfo(haddr); |
| |
| /* early return if we failed to acquire time */ |
| if (time_base == 0) { |
| LOG_ERR("Failed to get NTP time"); |
| return; |
| } |
| |
| mqtt_startup("mqtt.googleapis.com", 8883); |
| } |