/* * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2024 Conexio Technologies, Inc * * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ #include #include #include #include #include #include #include #include /* Header file for the MQTT Library*/ #include #include #include "mqtt_connection.h" /* The mqtt client struct */ static struct mqtt_client client; /* File descriptor */ static struct pollfd fds; /* Declare helper variables to find the TTFF */ static int64_t gnss_start_time; //static bool first_fix = false; static void gnss_event_handler(int event); static void print_fix_data(struct nrf_modem_gnss_pvt_data_frame *pvt_data); K_SEM_DEFINE(lte_connected, 0, 1); K_SEM_DEFINE(gnss_fix_sem, 0, 1); LOG_MODULE_REGISTER(Cellfund_Project, LOG_LEVEL_INF); static struct nrf_modem_gnss_pvt_data_frame current_pvt; static struct nrf_modem_gnss_pvt_data_frame last_pvt; static enum tracker_status {status_nolte = DK_LED1, status_searching = DK_LED2, status_fixed = DK_LED3} device_status; static void lte_handler(const struct lte_lc_evt *const evt) { switch (evt->type) { case LTE_LC_EVT_NW_REG_STATUS: if ((evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_HOME) && (evt->nw_reg_status != LTE_LC_NW_REG_REGISTERED_ROAMING)) { break; } LOG_INF("Network registration status: %s\n", evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ? "Connected - home network" : "Connected - roaming\n"); k_sem_give(<e_connected); break; case LTE_LC_EVT_PSM_UPDATE: LOG_INF("PSM parameter update: TAU: %d, Active time: %d\n", evt->psm_cfg.tau, evt->psm_cfg.active_time); break; case LTE_LC_EVT_EDRX_UPDATE: { char log_buf[60]; ssize_t len; len = snprintf(log_buf, sizeof(log_buf), "eDRX parameter update: eDRX: %f, PTW: %f\n", (double)evt->edrx_cfg.edrx, (double)evt->edrx_cfg.ptw); if (len > 0) { LOG_INF("%s\n", log_buf); } } break; case LTE_LC_EVT_RRC_UPDATE: LOG_INF("RRC mode: %s\n", evt->rrc_mode == LTE_LC_RRC_MODE_CONNECTED ? "Connected" : "Idle\n"); break; case LTE_LC_EVT_CELL_UPDATE: LOG_INF("LTE cell changed: Cell ID: %d, Tracking area: %d\n", evt->cell.id, evt->cell.tac); break; default: break; } } static int modem_configure(void) { int err; LOG_INF("Initializing modem library"); err = nrf_modem_lib_init(); if (err) { LOG_ERR("Failed to initialize the modem library, error: %d", err); return err; } LOG_INF("Connecting to LTE network"); err = lte_lc_connect_async(lte_handler); if (err) { LOG_ERR("Error in lte_lc_connect_async, error: %d", err); return err; } /* Decativate LTE and enable GNSS. */ err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_DEACTIVATE_LTE); if (err) { LOG_ERR("Failed to decativate LTE and enable GNSS functional mode"); return err; } return 0; } static void button_handler(uint32_t button_state, uint32_t has_changed) { switch (has_changed) { case DK_BTN1_MSK: /* When button 1/Mode is pressed, call data_publish() to publish a message */ if (button_state & DK_BTN1_MSK){ int err = data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE, CONFIG_BUTTON_EVENT_PUBLISH_MSG, sizeof(CONFIG_BUTTON_EVENT_PUBLISH_MSG)-1); if (err) { LOG_INF("Failed to send message, %d", err); return; } } break; } } /* Define a function to log fix data in a readable format */ static void print_fix_data(struct nrf_modem_gnss_pvt_data_frame *pvt_data) { LOG_INF("Latitude: %.06f", pvt_data->latitude); LOG_INF("Longitude: %.06f", pvt_data->longitude); LOG_INF("Altitude: %.01f m", pvt_data->altitude); LOG_INF("Time (UTC): %02u:%02u:%02u.%03u", pvt_data->datetime.hour, pvt_data->datetime.minute, pvt_data->datetime.seconds, pvt_data->datetime.ms); } static void gnss_event_handler(int event) { int err; switch (event) { case NRF_MODEM_GNSS_EVT_PVT: LOG_INF("Searching for GNSS Satellites....\n\r"); device_status = status_searching; break; case NRF_MODEM_GNSS_EVT_FIX: LOG_INF("GNSS fix event\n\r"); break; case NRF_MODEM_GNSS_EVT_PERIODIC_WAKEUP: LOG_INF("GNSS woke up in periodic mode\n\r"); break; case NRF_MODEM_GNSS_EVT_BLOCKED: LOG_INF("GNSS is blocked by LTE event\n\r"); break; case NRF_MODEM_GNSS_EVT_SLEEP_AFTER_FIX: LOG_INF("GNSS enters sleep because fix was achieved in periodic mode\n\r"); device_status = status_fixed; err = nrf_modem_gnss_read(&last_pvt, sizeof(last_pvt), NRF_MODEM_GNSS_DATA_PVT); if (err == 0){ current_pvt = last_pvt; print_fix_data(¤t_pvt); k_sem_give(&gnss_fix_sem); } break; case NRF_MODEM_GNSS_EVT_SLEEP_AFTER_TIMEOUT: LOG_INF("GNSS enters sleep because fix retry timeout was reached\n\r"); break; default: break; } } static int gnss_init_and_start(void) { #if defined(CONFIG_GNSS_HIGH_ACCURACY_TIMING_SOURCE) if (nrf_modem_gnss_timing_source_set(NRF_MODEM_GNSS_TIMING_SOURCE_TCXO)){ LOG_ERR("Failed to set TCXO timing source"); return -1; } #endif #if defined(CONFIG_GNSS_LOW_ACCURACY) || defined (CONFIG_BOARD_THINGY91_NRF9160_NS) uint8_t use_case; use_case = NRF_MODEM_GNSS_USE_CASE_MULTIPLE_HOT_START | NRF_MODEM_GNSS_USE_CASE_LOW_ACCURACY; if (nrf_modem_gnss_use_case_set(use_case) != 0) { LOG_ERR("Failed to set low accuracy use case"); return -1; } #endif /* Configure GNSS event handler . */ if (nrf_modem_gnss_event_handler_set(gnss_event_handler) != 0) { LOG_ERR("Failed to set GNSS event handler"); return -1; } if (nrf_modem_gnss_fix_interval_set(1) != 0) { LOG_ERR("Failed to set GNSS fix interval"); return -1; } if (nrf_modem_gnss_fix_retry_set(600) != 0) { LOG_ERR("Failed to set GNSS fix retry"); return -1; } if (nrf_modem_gnss_start() != 0) { LOG_ERR("Failed to start GNSS"); return -1; } if (nrf_modem_gnss_prio_mode_enable() != 0){ LOG_ERR("Error setting GNSS priority mode"); return -1; } return 0; } int try_mqtt_connect(void) { int err = 0; for (int connect_attempt = 0; connect_attempt < 5; connect_attempt++) { LOG_INF("Connection to broker using mqtt_connect"); err = mqtt_connect(&client); if (!err) { break; } LOG_ERR("Error in mqtt_connect: %d", err); LOG_INF("Reconnecting in %d seconds...", CONFIG_MQTT_RECONNECT_DELAY_S); k_sleep(K_SECONDS(CONFIG_MQTT_RECONNECT_DELAY_S)); } if (err) { return err; } err = fds_init(&client,&fds); if (err) { LOG_ERR("Error in fds_init: %d", err); return 0; } return err; } int main(void) { int err; err = dk_leds_init(); if (err){ LOG_ERR("Failed to initlize the LEDs Library"); } device_status = status_nolte; err = modem_configure(); if (err) { LOG_ERR("Failed to configure the modem"); return 0; } err = dk_buttons_init(button_handler); if (err) { LOG_ERR("Failed to initlize button handler: %d\n", err); return 0; } if (dk_leds_init() != 0) { LOG_ERR("Failed to initialize the LED library"); } LOG_INF("Starting GNSS...."); gnss_init_and_start(); LOG_INF("Starting MQTT sample on %s\n", CONFIG_BOARD); err = client_init(&client); if (err) { LOG_ERR("Failed to initialize MQTT client: %d", err); return 0; } /* Log the current system uptime */ gnss_start_time = k_uptime_get(); try_mqtt_connect(); while (1) { k_sem_take(&gnss_fix_sem, K_FOREVER); err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_NORMAL); if (err != 0){ LOG_ERR("Failed to activate LTE"); break; } k_sem_take(<e_connected, K_FOREVER); try_mqtt_connect(); for (int i = 0; i < 10; i++) { err = poll(&fds, 1, mqtt_keepalive_time_left(&client)); if (err < 0) { LOG_ERR("Error in poll(): %d", errno); break; } err = mqtt_live(&client); if ((err != 0) && (err != -EAGAIN)) { LOG_ERR("Error in mqtt_live: %d", err); break; } if ((fds.revents & POLLIN) == POLLIN) { err = mqtt_input(&client); if (err != 0) { LOG_ERR("Error in mqtt_input: %d", err); break; } } if ((fds.revents & POLLERR) == POLLERR) { LOG_ERR("POLLERR"); break; } if ((fds.revents & POLLNVAL) == POLLNVAL) { LOG_ERR("POLLNVAL"); break; } err = data_publish(&client, MQTT_QOS_1_AT_LEAST_ONCE, CONFIG_BUTTON_EVENT_PUBLISH_MSG, sizeof(CONFIG_BUTTON_EVENT_PUBLISH_MSG)-1); k_msleep(1000); } err = mqtt_disconnect(&client); if (err) { LOG_ERR("Could not disconnect MQTT client: %d", err); } err = lte_lc_func_mode_set(LTE_LC_FUNC_MODE_DEACTIVATE_LTE); if (err != 0){ LOG_ERR("Failed to decativate LTE and enable GNSS functional mode"); break; } } LOG_INF("Disconnecting MQTT client"); err = mqtt_disconnect(&client); if (err) { LOG_ERR("Could not disconnect MQTT client: %d", err); } /* This is never reached */ return 0; }