diff --git a/CMakeLists.txt b/CMakeLists.txt index c2d08cf..359ef71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,11 +18,14 @@ set(SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/common/tools.cpp ## Modules - # Server Module + # Net Module ${CMAKE_CURRENT_SOURCE_DIR}/src/modules/net_module/socket.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/modules/net_module/nrf9160_setup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/modules/net_module/net_module.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/modules/net_module/net_scheduler.cpp + + # Tracking Module + ${CMAKE_CURRENT_SOURCE_DIR}/src/modules/tracking_module/tracking_module.cpp ) # target_include_directories(app PRIVATE diff --git a/prj.conf b/prj.conf index 995d37b..b0a3058 100644 --- a/prj.conf +++ b/prj.conf @@ -26,6 +26,16 @@ CONFIG_LTE_LINK_CONTROL=y CONFIG_PDN=y CONFIG_PDN_ESM_STRERROR=y +CONFIG_NRF_CLOUD_REST=y +CONFIG_MODEM_INFO=y +CONFIG_NRF_CLOUD_AGNSS=y +CONFIG_LOCATION=y +CONFIG_LOCATION_SERVICE_NRF_CLOUD=y + +CONFIG_MODEM_JWT=y + +CONFIG_POSIX_CLOCK=y + CONFIG_SPI=y CONFIG_BOOTLOADER_MCUBOOT=y diff --git a/src/common/location.h b/src/common/location.h index 21273a1..3128846 100644 --- a/src/common/location.h +++ b/src/common/location.h @@ -1,6 +1,6 @@ #pragma once struct Location { - double lat; - double lon; + double lat; + double lon; }; diff --git a/src/main.c b/src/main.c deleted file mode 100644 index ec2c76b..0000000 --- a/src/main.c +++ /dev/null @@ -1,62 +0,0 @@ -#include - - -#include "modules/server_module/nrf9160_setup.h" -#include "modules/server_module/server_module.h" - -#include "common/van_info.h" -#include "common/location.h" - -#define POSIX_MODE - -#ifndef POSIX_MODE -#include -#define LED0_NODE DT_ALIAS(led0) -static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); -#endif - -#define SLEEP_TIME_MS 2000 - - -VanInfo van_info; - -int main() { - printk("Welcome to the OreCart Hardware Project!\r\n"); - int ret; - - server_module_init(); - -#ifndef POSIX_MODE - if (!gpio_is_ready_dt(&led)) { - return 0; - } - - ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); - if (ret < 0) { - return 0; - } -#endif - -#if defined(CONFIG_NRF_MODEM_LIB) - init_nrf9160_modem(); -#endif - - struct VanInfo van_info = { - .van_id = 1 - }; - - while (1) { - // printk("Beep\r\n"); - #ifndef POSIX_MODE - gpio_pin_toggle_dt(&led); - #endif - server_send_van_location(&van_info, (struct Location){.lat = 213.12, .lon=20.123}, 100); - k_sleep(K_SECONDS(50)); - } - - while (1) { - k_sleep(K_SECONDS(15)); - } - - return 0; -} diff --git a/src/main.cpp b/src/main.cpp index 161afa1..3cbdeab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,47 +1,42 @@ #include #include +#include + #include "common/van_info.h" #include "common/location.h" #include "modules/net_module/net_module.h" - -#define LED0_NODE DT_ALIAS(led0) -static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios); - -#define SLEEP_TIME_MS 2000 +#include "modules/tracking_module/tracking_module.h" +#include "modules/tracking_module/tracking_event.h" +#include "modules/tracking_module/tracking_exception.h" VanInfo van_info; int main() { - OC_LOG_INFO("Welcome to the OreCart Hardware Project!"); - int ret; - - net_module_init(); - - if (!gpio_is_ready_dt(&led)) { - return 0; - } - - ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE); - if (ret < 0) { - return 0; - } - - struct VanInfo van_info = { - .van_id = 1 - }; - - struct Location location = {.lat=213.12, .lon=20.123}; - - while (1) { - forward_van_location(van_info, location, 100); - k_sleep(K_SECONDS(20)); - } - - while (1) { - k_sleep(K_SECONDS(15)); - } + OC_LOG_INFO("Welcome to the OreCart Hardware Project!"); + int ret; + + net_module_init(); + + try { + tracking_module_init(); + } catch (TrackingException e) { + OC_LOG_ERROR(e.toStr()); + } + + while (true) { + k_sleep(K_SECONDS(1)); + } + + return 0; +} - return 0; +static bool _app_event_handler(const struct app_event_header *aeh) { + if (is_tracking_event(aeh)) { + + } } + +APP_EVENT_LISTENER(main, _app_event_handler); +APP_EVENT_SUBSCRIBE(main, tracking_event); \ No newline at end of file diff --git a/src/modules/server_module/nrf9160_setup.c b/src/modules/server_module/nrf9160_setup.c deleted file mode 100644 index 324e603..0000000 --- a/src/modules/server_module/nrf9160_setup.c +++ /dev/null @@ -1,135 +0,0 @@ -// The nRF9160 is one odd duck in the flock. -// Unlike its friends, it refuses to bring a driver dish to the kernel potluck, so we're DIY-ing it right here. - -#if defined(CONFIG_NRF_MODEM_LIB) - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "server_module.h" - -static const char cert[] = { -#include "../../../res/cert/DigiCertGlobalRootCA.pem" -}; - -// NRF_MODEM_LIB_ON_INIT(orecart_init_hook, on_modem_lib_init, NULL); - -#define TLS_SEC_TAG 42 - -void pdn_event_handler(uint8_t cid, enum pdn_event event, int reason) -{ - switch (event) { - case PDN_EVENT_CNEC_ESM: - printk("PDP context %d error, %s\n", cid, pdn_esm_strerror(reason)); - break; - case PDN_EVENT_ACTIVATED: - printk("PDP context %d activated\n", cid); - break; - case PDN_EVENT_DEACTIVATED: - printk("PDP context %d deactivated\n", cid); - break; - case PDN_EVENT_NETWORK_DETACH: - printk("PDP context %d network detached\n", cid); - break; - case PDN_EVENT_IPV6_UP: - printk("PDP context %d IPv6 up\n", cid); - break; - case PDN_EVENT_IPV6_DOWN: - printk("PDP context %d IPv6 down\n", cid); - break; - default: - printk("PDP context %d, unknown event %d\n", cid, event); - break; - } -} - -int cert_provision(void) -{ - int err; - bool exists; - int mismatch; - - /* It may be sufficient for you application to check whether the correct - * certificate is provisioned with a given tag directly using modem_key_mgmt_cmp(). - * Here, for the sake of the completeness, we check that a certificate exists - * before comparing it with what we expect it to be. - */ - err = modem_key_mgmt_exists(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, &exists); - if (err) { - printk("Failed to check for certificates err %d\n", err); - return err; - } - - if (exists) { - mismatch = modem_key_mgmt_cmp(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, cert, - strlen(cert)); - if (!mismatch) { - printk("Certificate match!\n"); - return 0; - } - - printk("Certificate mismatch\n"); - err = modem_key_mgmt_delete(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN); - if (err) { - printk("Failed to delete existing certificate, err %d\n", err); - } - } - - printk("Provisioning certificate\n"); - - /* Provision certificate to the modem */ - err = modem_key_mgmt_write(TLS_SEC_TAG, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, cert, - sizeof(cert) - 1); - if (err) { - printk("Failed to provision certificate, err %d\n", err); - return err; - } - - return 0; -} - -void init_nrf9160_modem() { - printk("Initializing the nRF910 modem....\r\n"); - int err; - - err = nrf_modem_lib_init(); - if (err) { - printk("Modem library initialization failed, error: %d\n", err); - return; - } - - err = pdn_default_ctx_cb_reg(pdn_event_handler); - if (err) { - printk("pdn_default_ctx_cb_reg, error: %d", err); - return; - } - - err = cert_provision(); - if (err) { - return; - } - - printk("Waiting for network.. \r\n"); - - err = lte_lc_init_and_connect(); - if (err) { - printk("Failed to connect to the LTE network, err %d\n", err); - return; - } - - printk("nRF9160 successfully connected to the LTE network!\r\n"); - - - k_sem_give(&is_modem_available); -} - -#endif \ No newline at end of file diff --git a/src/modules/server_module/nrf9160_setup.h b/src/modules/server_module/nrf9160_setup.h deleted file mode 100644 index 2f68e15..0000000 --- a/src/modules/server_module/nrf9160_setup.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void init_nrf9160_modem(); diff --git a/src/modules/server_module/server_module.c b/src/modules/server_module/server_module.c deleted file mode 100644 index c10d4e1..0000000 --- a/src/modules/server_module/server_module.c +++ /dev/null @@ -1,238 +0,0 @@ -#include -#include -#include -#include - -#include - -#include "server_module.h" -#include "socket.h" -#include "../../common/van_info.h" -#include "../../common/tools.h" - -#define MAX_INFLIGHT_REQUESTS 3 -#define PAYLOAD_MAX_SIZE 64 -#define MAX_URL_LEN 32 -#define MAX_RESP_LEN 128 - -#define _STACK_SIZE 256 -#define _PRIORITY 5 - -K_THREAD_STACK_DEFINE(server_stack_area, _STACK_SIZE); -K_SEM_DEFINE(http_requests_sem, MAX_INFLIGHT_REQUESTS, MAX_INFLIGHT_REQUESTS); - -struct k_work_q server_work_q; - -// What should we do if a request fails (runs out of tries or expires)? -enum RequestFailedAction { - // Drop the request (forget it forever) - DROP, - - // Try to upload it when the OreCart is in downtime (ie: parked). This can - // be useful for analytical data that we want still want but don't quickly - // (ie: fine to send later). - DOWNTIME_UPLOAD -}; - -struct OreCartRequest { - struct k_work work; - struct http_request http_req; - - char payload[PAYLOAD_MAX_SIZE]; - char url[MAX_URL_LEN]; - int sock; - - // Some expiration (in UNIX epoch milliseconds) after which it's no longer worth sending this request. - // A lot of the requests here (like location) need to be processed quickly an quickly expire. We don't - // want to be sending the location from 3 minutes ago. This saves on networking resources and allows - uint64_t expiration; - uint8_t tries; // Number of times we'll retry sending this request before we give up. - - enum RequestFailedAction request_failed_action; - - char resp_buffer[MAX_RESP_LEN]; -}; - -typedef struct OreCartRequest OreCartRequest; - -OreCartRequest* inflight_requests[MAX_INFLIGHT_REQUESTS]; // All buffers available by default - -K_SEM_DEFINE(is_modem_available, 0, 1); - -static void on_http_response(struct http_response *rsp, - enum http_final_call final_data, - void *user_data) { - if (final_data == HTTP_DATA_FINAL) { - // printk("\r\nresp: %d\r\n", rsp->http_status_code); - uint32_t inflight_index = (uint32_t)user_data; - - - // If we failed, let's try and this back to the request queue. - if (rsp->http_status_code != 200) { - printk("\r\nResponse failed with status code: %d\r\n", rsp->http_status_code); - inflight_requests[inflight_index]->tries--; - k_work_submit_to_queue(&server_work_q, &inflight_requests[inflight_index]->work); - } else { - printk("\r\nResponse success with status code: %d\r\n", rsp->http_status_code); - - // Some response processing (TBD). - // for (int i=0; icontent_length; i++) { - // printk("%X ", rsp->recv_buf[i]); - // } - - free(inflight_requests[inflight_index]); - } - - close(inflight_requests[inflight_index]->sock); - - inflight_requests[inflight_index] = NULL; - k_sem_give(&http_requests_sem); - - } else { - printk("."); - } -} - - -// Process queue items, send them over to the server. -static void server_work_handler(struct k_work* work) { - printk("New work handle called.\r\n"); - - struct OreCartRequest *request = CONTAINER_OF( - work, struct OreCartRequest, work - ); - - uint64_t uptime = k_uptime_get(); - - if (request->tries == 0 || uptime > request->expiration) { - printk("Request expired, discarding...\r\n"); - - free(request); - return; - } - - // Semaphore limits inflight requests, this makes us wait - // if there are still requests that haven't been handled. - k_sem_take(&http_requests_sem, K_FOREVER); // TODO: Add some sane timeout. - - - // Pick first available buffer (TODO: THIS IS NOT THREAD SAFE YET!!!!) - uint32_t i = 0; - while (inflight_requests[i] != NULL) { - i++; - if (i > MAX_INFLIGHT_REQUESTS - 1) return; // Something bad happened, should never be true. - } - - - inflight_requests[i] = request; - - struct http_request* http_req = &request->http_req; - - http_req->response = on_http_response; - http_req->recv_buf_len = sizeof(MAX_RESP_LEN); - http_req->recv_buf = request->resp_buffer; - - struct addrinfo *res; - struct addrinfo hints = { - .ai_flags = AI_NUMERICSERV, /* Let getaddrinfo() set port */ - .ai_socktype = SOCK_STREAM, - }; - - int err = getaddrinfo(SERVER_HOST, NULL, &hints, &res); - if (err) { - printk("getaddrinfo() failed, err %d %d\n", errno, err); - return; - } - - char peer_addr[INET6_ADDRSTRLEN]; - - inet_ntop(res->ai_family, &((struct sockaddr_in *)(res->ai_addr))->sin_addr, peer_addr, - INET6_ADDRSTRLEN); - - printk("Address Resolved!!! %s\r\n", peer_addr); - - struct sockaddr_in addr4; - - // err = connect(request->sock, res->ai_addr, res->ai_addrlen); - err = connect_socket(AF_INET, peer_addr, SERVER_PORT, - &request->sock, (struct sockaddr *)&addr4, - sizeof(addr4)); - - if (err) { - printk("connect_socket() failed, err: %d\n", errno); - - // Not creating a socket is real bad, means we probably have 0 connectivity. - k_sleep(K_MSEC(400)); // Wait some amount of time for things to resolve themselves. - - close(request->sock); - - // Push current item back to the queue. - inflight_requests[i] = NULL; - request->tries--; - k_work_submit_to_queue(&server_work_q, &request->work); - k_sem_give(&http_requests_sem); // Don't block future requests - return; - } - - // request->sock = socket(res->ai_family, SOCK_STREAM | SOCK_NATIVE_TLS, IPPROTO_TLS_1_2); // TLS - // request->sock = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP); - int ret = http_client_req(request->sock, &request->http_req, TIMEOUT, (void*)i); -} - -void server_module_init() { - k_work_queue_init(&server_work_q); - - k_work_queue_start(&server_work_q, server_stack_area, - K_THREAD_STACK_SIZEOF(server_stack_area), _PRIORITY, - NULL - ); -} - -bool server_send_van_location(VanInfo* vanInfo, struct Location location, uint64_t ts) { - // This will need to stay allocated until the work is finished (ie: HTTP response received) - OreCartRequest* request = malloc(sizeof(OreCartRequest)); - - printk("Sending location...\r\n"); - - // Handle memory allocation failure - if (request == NULL) { - printk("Memory allocation failure.\r\n"); - return false; - } - - // Order types from largest to smallest for data packing. - struct VanLocationPayload { - double lat; - double lon; - uint64_t ts; - } payload; - - payload.lat = location.lat; - payload.lon = location.lon; - payload.ts = ts; - - memcpy(&request->payload, &payload, sizeof(struct VanLocationPayload)); - - char vanIdStr[4]; - uint8_t_to_str(vanInfo->van_id, vanIdStr); - - // Construct the route url, we need to append the van id at the end - strcpy(request->url, SEND_VAN_LOCATION_ROUTE); - strcat(request->url, vanIdStr); - request->expiration = k_uptime_get() + 10000; // 10 second expiration - request->tries = 10; // Try maximum 10 times. - - struct http_request* http_req = &request->http_req; - http_req->method = HTTP_POST; - http_req->url = request->url; - http_req->host = SERVER_HOST; - http_req->protocol = PROTOCOL; - http_req->payload_len = sizeof(struct VanLocationPayload); - http_req->payload = request->payload; - - k_work_init(&request->work, server_work_handler); - k_work_submit_to_queue(&server_work_q, &request->work); - - return true; -} - diff --git a/src/modules/server_module/server_module.h b/src/modules/server_module/server_module.h deleted file mode 100644 index 64538b7..0000000 --- a/src/modules/server_module/server_module.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include "../../common/location.h" -#include "../../common/van_info.h" - -#define SERVER_HOST "orecart.local" -#define SERVER_PORT 8000 - -// #define SERVER_HOST "142.251.41.14" -// #define SERVER_PORT 80 - -#define PROTOCOL "HTTP/1.1" -#define TIMEOUT 5000 - -#define SEND_VAN_LOCATION_ROUTE "/location/" -// #define SEND_VAN_LOCATION_ROUTE "/" -#define SEND_OCCUPANCY_ROUTE "/states/ridership/" - -extern struct k_sem is_modem_available; - -// Lock semaphore until initialized. - -void server_module_init(); - -// Send the current van location to the server. -// @location - a lat/long position of the van -// returns success boolean -bool server_send_van_location(VanInfo* vanInfo, struct Location location, uint64_t ts); - -// Send the current ridership to the server. -// @ridership_delta - how many people got on/off the bus, negative for off and positive for on. -// returns success boolean -// bool server_send_ridership(VanInfo* vanInfo, int8_t ridership_delta, uint64_t ts); diff --git a/src/modules/server_module/socket.c b/src/modules/server_module/socket.c deleted file mode 100644 index ba6277b..0000000 --- a/src/modules/server_module/socket.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include - -#include "server_module.h" - -#define TLS_SEC_TAG 42 - -static int setup_socket(sa_family_t family, const char *server, int port, - int *sock, struct sockaddr *addr, socklen_t addr_len) -{ - const char *family_str = family == AF_INET ? "IPv4" : "IPv6"; - int ret = 0; - - memset(addr, 0, addr_len); - - if (family == AF_INET) { - net_sin(addr)->sin_family = AF_INET; - net_sin(addr)->sin_port = htons(port); - inet_pton(family, server, &net_sin(addr)->sin_addr); - } else { - net_sin6(addr)->sin6_family = AF_INET6; - net_sin6(addr)->sin6_port = htons(port); - inet_pton(family, server, &net_sin6(addr)->sin6_addr); - } - - if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS)) { - sec_tag_t sec_tag_list[] = { - TLS_SEC_TAG, - }; - - *sock = socket(family, SOCK_STREAM, IPPROTO_TLS_1_2); - if (*sock >= 0) { - ret = setsockopt(*sock, SOL_TLS, TLS_SEC_TAG_LIST, - sec_tag_list, sizeof(sec_tag_list)); - if (ret < 0) { - printk("Failed to set %s secure option (%d)", - family_str, -errno); - ret = -errno; - } - - ret = setsockopt(*sock, SOL_TLS, TLS_HOSTNAME, - SERVER_HOST, - sizeof(SERVER_HOST)); - if (ret < 0) { - printk("Failed to set %s TLS_HOSTNAME " - "option (%d)", family_str, -errno); - ret = -errno; - } - } - } else { - *sock = socket(family, SOCK_STREAM, IPPROTO_TCP); - } - - if (*sock < 0) { - printk("Failed to create %s HTTP socket (%d)", family_str, - -errno); - } - - return ret; -} - - -int connect_socket(sa_family_t family, const char *server, int port, - int *sock, struct sockaddr *addr, socklen_t addr_len) { - int ret; - - ret = setup_socket(family, server, port, sock, addr, addr_len); - if (ret < 0 || *sock < 0) { - return -1; - } - - ret = connect(*sock, addr, addr_len); - if (ret < 0) { - printk("Cannot connect to %s remote (%d)", - family == AF_INET ? "IPv4" : "IPv6", - -errno); - ret = -errno; - } - - return ret; -} \ No newline at end of file diff --git a/src/modules/server_module/socket.h b/src/modules/server_module/socket.h deleted file mode 100644 index 6386c9f..0000000 --- a/src/modules/server_module/socket.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -int connect_socket(sa_family_t family, const char *server, int port, - int *sock, struct sockaddr *addr, socklen_t addr_len); \ No newline at end of file diff --git a/src/modules/tracking_module/tracking_event.h b/src/modules/tracking_module/tracking_event.h new file mode 100644 index 0000000..5ee3dbe --- /dev/null +++ b/src/modules/tracking_module/tracking_event.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#include "../../common/location.h" + +struct tracking_event { + /** Data module application event header. */ + struct app_event_header header; + /** Data module event type. */ + enum data_module_event_type type; + + union { + Location location; + } data; +}; \ No newline at end of file diff --git a/src/modules/tracking_module/tracking_exception.h b/src/modules/tracking_module/tracking_exception.h new file mode 100644 index 0000000..c206c6e --- /dev/null +++ b/src/modules/tracking_module/tracking_exception.h @@ -0,0 +1,14 @@ +#pragma once +#include + +class TrackingException { + std::string _exception; + +public: + TrackingException(std::string & exception); + TrackingException(const char * exception); + + const char* toStr() { + return _exception.c_str(); + } +}; diff --git a/src/modules/tracking_module/tracking_module.c b/src/modules/tracking_module/tracking_module.c deleted file mode 100644 index 0ffdd02..0000000 --- a/src/modules/tracking_module/tracking_module.c +++ /dev/null @@ -1 +0,0 @@ -// TODO \ No newline at end of file diff --git a/src/modules/tracking_module/tracking_module.cpp b/src/modules/tracking_module/tracking_module.cpp new file mode 100644 index 0000000..368965f --- /dev/null +++ b/src/modules/tracking_module/tracking_module.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tracking_exception.h" +#include "../../common/location.h" + +static nrf_modem_gnss_pvt_data_frame last_pvt; +K_MSGQ_DEFINE(nmea_queue, sizeof(struct nrf_modem_gnss_nmea_data_frame *), 10, 4); +static K_SEM_DEFINE(pvt_data_sem, 0, 1); +static K_SEM_DEFINE(time_sem, 0, 1); + +TrackingException::TrackingException(std::string & exception) : _exception(exception) {} +TrackingException::TrackingException(const char * exception) : _exception(exception) {} + +static void _gnss_event_handler(int event); + +void tracking_module_init() { + if (nrf_modem_gnss_event_handler_set(_gnss_event_handler) != 0) { + throw TrackingException("Failed to set GNSS event handler"); + } + + // Enable all NMEA messages. + uint16_t nmea_mask = NRF_MODEM_GNSS_NMEA_RMC_MASK | + NRF_MODEM_GNSS_NMEA_GGA_MASK | + NRF_MODEM_GNSS_NMEA_GLL_MASK | + NRF_MODEM_GNSS_NMEA_GSA_MASK | + NRF_MODEM_GNSS_NMEA_GSV_MASK; + + if (nrf_modem_gnss_nmea_mask_set(nmea_mask) != 0) { + throw TrackingException("Failed to set GNSS mask"); + } + + /* Make QZSS satellites visible in the NMEA output. */ + if (nrf_modem_gnss_qzss_nmea_mode_set(NRF_MODEM_GNSS_QZSS_NMEA_MODE_CUSTOM) != 0) { + LOG_WRN("Failed to enable custom QZSS NMEA mode"); + } + + /* This use case flag should always be set. */ + uint8_t use_case = NRF_MODEM_GNSS_USE_CASE_MULTIPLE_HOT_START; + + if (IS_ENABLED(CONFIG_GNSS_SAMPLE_LOW_ACCURACY)) { + use_case |= NRF_MODEM_GNSS_USE_CASE_LOW_ACCURACY; + } + + if (nrf_modem_gnss_use_case_set(use_case) != 0) { + LOG_WRN("Failed to set GNSS use case"); + } + + /* Default to no power saving. */ + uint8_t power_mode = NRF_MODEM_GNSS_PSM_DISABLED; + + if (nrf_modem_gnss_power_mode_set(power_mode) != 0) { + throw TrackingException("Failed to set GNSS power saving mode"); + } + + // Continuous Tracking + uint16_t fix_retry = 0; + uint16_t fix_interval = 1; + + if (nrf_modem_gnss_fix_retry_set(fix_retry) != 0) { + throw TrackingException("Failed to set GNSS fix retry"); + } + + if (nrf_modem_gnss_fix_interval_set(fix_interval) != 0) { + throw TrackingException("Failed to set GNSS fix interval"); + } + + if (nrf_modem_gnss_start() != 0) { + throw TrackingException("Failed to start GNSS"); + } +} + +static void _gnss_event_handler(int event) { + int retval; + + switch (event) { + case NRF_MODEM_GNSS_EVT_PVT: + retval = nrf_modem_gnss_read(&last_pvt, sizeof(last_pvt), NRF_MODEM_GNSS_DATA_PVT); + + Location location; + location.lat = last_pvt.latitude; + location.lon = last_pvt.longitude; + + auto time = last_pvt.datetime; + + // printk("Latitude: %d Longitude: %d\r\n", location.lat, location.lon); + + if (retval == 0) { + k_sem_give(&pvt_data_sem); + } + break; + + case NRF_MODEM_GNSS_EVT_NMEA: + nrf_modem_gnss_nmea_data_frame* nmea_data = new nrf_modem_gnss_nmea_data_frame; + + retval = nrf_modem_gnss_read( + nmea_data, + sizeof(nrf_modem_gnss_nmea_data_frame), + NRF_MODEM_GNSS_DATA_NMEA + ); + + if (retval == 0) { + retval = k_msgq_put(&nmea_queue, nmea_data, K_NO_WAIT); + } + + if (retval != 0) { + delete nmea_data; + } + + break; + + case NRF_MODEM_GNSS_EVT_AGNSS_REQ: + break; + + default: + break; + } +} \ No newline at end of file diff --git a/src/modules/tracking_module/tracking_module.h b/src/modules/tracking_module/tracking_module.h new file mode 100644 index 0000000..a272f9c --- /dev/null +++ b/src/modules/tracking_module/tracking_module.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../../common/location.h" + +void tracking_module_init(); + +Location location_gnss_high_accuracy_get(); + +void location_with_fallback_get(); \ No newline at end of file