203 lines
5.5 KiB
C
203 lines
5.5 KiB
C
/*
|
|
* Copyright (c) 2023 Trackunit Corporation
|
|
* Copyright (c) 2023 Bjarki Arge Andreasen
|
|
* Copyright 2023 Google LLC
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/drivers/gnss.h>
|
|
#include <zephyr/drivers/gnss/gnss_publish.h>
|
|
#include <zephyr/modem/chat.h>
|
|
#include <zephyr/modem/backend/uart.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/drivers/gpio.h>
|
|
#include <zephyr/pm/device.h>
|
|
#include <string.h>
|
|
|
|
#include "gnss_nmea0183.h"
|
|
#include "gnss_nmea0183_match.h"
|
|
#include "gnss_parse.h"
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(gnss_nmea_generic, CONFIG_GNSS_LOG_LEVEL);
|
|
|
|
#define UART_RX_BUF_SZ (256 + IS_ENABLED(CONFIG_GNSS_SATELLITES) * 512)
|
|
#define UART_TX_BUF_SZ 64
|
|
#define CHAT_RECV_BUF_SZ 256
|
|
#define CHAT_ARGV_SZ 32
|
|
|
|
struct gnss_nmea_generic_config {
|
|
const struct device *uart;
|
|
const struct modem_chat_script *const init_chat_script;
|
|
};
|
|
|
|
struct gnss_nmea_generic_data {
|
|
struct gnss_nmea0183_match_data match_data;
|
|
#if CONFIG_GNSS_SATELLITES
|
|
struct gnss_satellite satellites[CONFIG_GNSS_NMEA_GENERIC_SATELLITES_COUNT];
|
|
#endif
|
|
|
|
/* UART backend */
|
|
struct modem_pipe *uart_pipe;
|
|
struct modem_backend_uart uart_backend;
|
|
uint8_t uart_backend_receive_buf[UART_RX_BUF_SZ];
|
|
uint8_t uart_backend_transmit_buf[UART_TX_BUF_SZ];
|
|
|
|
/* Modem chat */
|
|
struct modem_chat chat;
|
|
uint8_t chat_receive_buf[CHAT_RECV_BUF_SZ];
|
|
uint8_t *chat_argv[CHAT_ARGV_SZ];
|
|
};
|
|
|
|
MODEM_CHAT_MATCHES_DEFINE(unsol_matches,
|
|
MODEM_CHAT_MATCH_WILDCARD("$??GGA,", ",*", gnss_nmea0183_match_gga_callback),
|
|
MODEM_CHAT_MATCH_WILDCARD("$??RMC,", ",*", gnss_nmea0183_match_rmc_callback),
|
|
#if CONFIG_GNSS_SATELLITES
|
|
MODEM_CHAT_MATCH_WILDCARD("$??GSV,", ",*", gnss_nmea0183_match_gsv_callback),
|
|
#endif
|
|
);
|
|
|
|
static int gnss_nmea_generic_resume(const struct device *dev)
|
|
{
|
|
const struct gnss_nmea_generic_config *cfg = dev->config;
|
|
struct gnss_nmea_generic_data *data = dev->data;
|
|
int ret;
|
|
|
|
ret = modem_pipe_open(data->uart_pipe, K_SECONDS(10));
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = modem_chat_attach(&data->chat, data->uart_pipe);
|
|
|
|
if (ret == 0) {
|
|
ret = modem_chat_run_script(&data->chat, cfg->init_chat_script);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
modem_pipe_close(data->uart_pipe, K_SECONDS(10));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static const struct gnss_driver_api gnss_api = {
|
|
};
|
|
|
|
static int gnss_nmea_generic_init_nmea0183_match(const struct device *dev)
|
|
{
|
|
struct gnss_nmea_generic_data *data = dev->data;
|
|
|
|
const struct gnss_nmea0183_match_config match_config = {
|
|
.gnss = dev,
|
|
#if CONFIG_GNSS_SATELLITES
|
|
.satellites = data->satellites,
|
|
.satellites_size = ARRAY_SIZE(data->satellites),
|
|
#endif
|
|
};
|
|
|
|
return gnss_nmea0183_match_init(&data->match_data, &match_config);
|
|
}
|
|
|
|
static void gnss_nmea_generic_init_pipe(const struct device *dev)
|
|
{
|
|
const struct gnss_nmea_generic_config *cfg = dev->config;
|
|
struct gnss_nmea_generic_data *data = dev->data;
|
|
|
|
const struct modem_backend_uart_config uart_backend_config = {
|
|
.uart = cfg->uart,
|
|
.receive_buf = data->uart_backend_receive_buf,
|
|
.receive_buf_size = sizeof(data->uart_backend_receive_buf),
|
|
.transmit_buf = data->uart_backend_transmit_buf,
|
|
.transmit_buf_size = sizeof(data->uart_backend_transmit_buf),
|
|
};
|
|
|
|
data->uart_pipe = modem_backend_uart_init(&data->uart_backend, &uart_backend_config);
|
|
}
|
|
|
|
static uint8_t gnss_nmea_generic_char_delimiter[] = {'\r', '\n'};
|
|
|
|
static int gnss_nmea_generic_init_chat(const struct device *dev)
|
|
{
|
|
struct gnss_nmea_generic_data *data = dev->data;
|
|
|
|
const struct modem_chat_config chat_config = {
|
|
.user_data = data,
|
|
.receive_buf = data->chat_receive_buf,
|
|
.receive_buf_size = sizeof(data->chat_receive_buf),
|
|
.delimiter = gnss_nmea_generic_char_delimiter,
|
|
.delimiter_size = ARRAY_SIZE(gnss_nmea_generic_char_delimiter),
|
|
.filter = NULL,
|
|
.filter_size = 0,
|
|
.argv = data->chat_argv,
|
|
.argv_size = ARRAY_SIZE(data->chat_argv),
|
|
.unsol_matches = unsol_matches,
|
|
.unsol_matches_size = ARRAY_SIZE(unsol_matches),
|
|
};
|
|
|
|
return modem_chat_init(&data->chat, &chat_config);
|
|
}
|
|
|
|
static int gnss_nmea_generic_init(const struct device *dev)
|
|
{
|
|
int ret;
|
|
|
|
ret = gnss_nmea_generic_init_nmea0183_match(dev);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
gnss_nmea_generic_init_pipe(dev);
|
|
|
|
ret = gnss_nmea_generic_init_chat(dev);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
#if CONFIG_PM_DEVICE
|
|
pm_device_init_suspended(dev);
|
|
#else
|
|
ret = gnss_nmea_generic_resume(dev);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if CONFIG_PM_DEVICE
|
|
static int gnss_nmea_generic_pm_action(const struct device *dev, enum pm_device_action action)
|
|
{
|
|
switch (action) {
|
|
case PM_DEVICE_ACTION_RESUME:
|
|
return gnss_nmea_generic_resume(dev);
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(gnss_nmea_generic)
|
|
MODEM_CHAT_SCRIPT_EMPTY_DEFINE(gnss_nmea_generic_init_chat_script);
|
|
#endif
|
|
|
|
#define GNSS_NMEA_GENERIC(inst) \
|
|
static const struct gnss_nmea_generic_config gnss_nmea_generic_cfg_##inst = { \
|
|
.uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \
|
|
.init_chat_script = &_CONCAT(DT_DRV_COMPAT, _init_chat_script), \
|
|
}; \
|
|
\
|
|
static struct gnss_nmea_generic_data gnss_nmea_generic_data_##inst; \
|
|
\
|
|
PM_DEVICE_DT_INST_DEFINE(inst, gnss_nmea_generic_pm_action); \
|
|
\
|
|
DEVICE_DT_INST_DEFINE(inst, gnss_nmea_generic_init, PM_DEVICE_DT_INST_GET(inst),\
|
|
&gnss_nmea_generic_data_##inst, \
|
|
&gnss_nmea_generic_cfg_##inst, \
|
|
POST_KERNEL, CONFIG_GNSS_INIT_PRIORITY, &gnss_api);
|
|
|
|
#define DT_DRV_COMPAT gnss_nmea_generic
|
|
DT_INST_FOREACH_STATUS_OKAY(GNSS_NMEA_GENERIC)
|
|
#undef DT_DRV_COMPAT
|