ADD: GNSS Driver for U-BLOX M10 & Support for UBX Messages

MODEM_UBX: Adds Support for UBX Messages in Modem Subsystem.

GNSS API Supported: get_supported_systems, set_fix_rate, get_fix_rate,
	set_enabled_systems, get_enabled_systems, set_navigation_mode,
	get_navigation_mode.

Boards Tested: MIMXRT1062_FMURT6, VMU_RT1170.

Note: Partial support for U-BLOX Messages is provided as of now.

Signed-off-by: Sumit Batra <sumit.batra@nxp.com>
Signed-off-by: Mayank Mahajan <mayankmahajan.x@nxp.com>
This commit is contained in:
Mayank Mahajan 2024-01-24 16:52:22 +05:30 committed by Fabio Baltieri
parent bc140e1a36
commit 3d81167eaf
16 changed files with 2392 additions and 0 deletions

View file

@ -9,3 +9,5 @@ zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA0183 gnss_nmea0183.c)
zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA0183_MATCH gnss_nmea0183_match.c)
zephyr_library_sources_ifdef(CONFIG_GNSS_NMEA_GENERIC gnss_nmea_generic.c)
zephyr_library_sources_ifdef(CONFIG_GNSS_QUECTEL_LCX6G gnss_quectel_lcx6g.c)
zephyr_library_sources_ifdef(CONFIG_GNSS_U_BLOX_M10 gnss_u_blox_m10.c)
zephyr_library_sources_ifdef(CONFIG_GNSS_U_BLOX_PROTOCOL gnss_u_blox_protocol/gnss_u_blox_protocol.c)

View file

@ -60,11 +60,18 @@ config GNSS_INIT_PRIORITY
help
Driver initialization priority for GNSS drivers.
config GNSS_U_BLOX_PROTOCOL
bool "GNSS U-BLOX protocol"
select MODEM_UBX
help
Enable gnss u-blox protocol.
module = GNSS
module-str = gnss
source "subsys/logging/Kconfig.template.log_config"
rsource "Kconfig.generic"
rsource "Kconfig.quectel_lcx6g"
rsource "Kconfig.u_blox_m10"
endif

View file

@ -0,0 +1,29 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
config GNSS_U_BLOX_M10
bool "U-BLOX M10 GNSS Module"
default y
depends on GNSS
depends on DT_HAS_U_BLOX_M10_ENABLED
select MODEM_MODULES
select MODEM_BACKEND_UART
select MODEM_CHAT
select MODEM_UBX
select GNSS_PARSE
select GNSS_NMEA0183
select GNSS_NMEA0183_MATCH
select GNSS_U_BLOX_PROTOCOL
select UART_USE_RUNTIME_CONFIGURE
help
Enable U-BLOX M10 GNSS modem driver.
config GNSS_U_BLOX_M10_SATELLITES_COUNT
int "Maximum satellite count"
depends on GNSS_SATELLITES
default 24
help
Maximum number of satellite that the driver that can be decoded from
the GNSS device. This does not affect the number of devices that the
device is actually tracking, just how many of those can be reported
in the satellites callback.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,180 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "gnss_u_blox_protocol.h"
const uint32_t ubx_baudrate[UBX_BAUDRATE_COUNT] = {
4800,
9600,
19200,
38400,
57600,
115200,
230400,
460800,
921600,
};
static inline int ubx_validate_payload_size_ack(uint8_t msg_id, uint16_t payload_size)
{
switch (msg_id) {
case UBX_ACK_ACK:
return payload_size == UBX_CFG_ACK_PAYLOAD_SZ ? 0 : -1;
case UBX_ACK_NAK:
return payload_size == UBX_CFG_NAK_PAYLOAD_SZ ? 0 : -1;
default:
return -1;
}
}
static inline int ubx_validate_payload_size_cfg(uint8_t msg_id, uint16_t payload_size)
{
switch (msg_id) {
case UBX_CFG_RATE:
return payload_size == UBX_CFG_RATE_PAYLOAD_SZ ? 0 : -1;
case UBX_CFG_PRT:
return (payload_size == UBX_CFG_PRT_POLL_PAYLOAD_SZ ||
payload_size == UBX_CFG_PRT_SET_PAYLOAD_SZ) ? 0 : -1;
case UBX_CFG_RST:
return payload_size == UBX_CFG_RST_PAYLOAD_SZ ? 0 : -1;
case UBX_CFG_NAV5:
return payload_size == UBX_CFG_NAV5_PAYLOAD_SZ ? 0 : -1;
case UBX_CFG_GNSS:
return ((payload_size - UBX_CFG_GNSS_PAYLOAD_INIT_SZ) %
UBX_CFG_GNSS_PAYLOAD_CFG_BLK_SZ == 0) ? 0 : -1;
case UBX_CFG_MSG:
return payload_size == UBX_CFG_MSG_PAYLOAD_SZ ? 0 : -1;
default:
return -1;
}
}
static inline int ubx_validate_payload_size(uint8_t msg_cls, uint8_t msg_id, uint16_t payload_size)
{
if (payload_size == 0) {
return 0;
}
if (payload_size > UBX_PAYLOAD_SZ_MAX) {
return -1;
}
switch (msg_cls) {
case UBX_CLASS_ACK:
return ubx_validate_payload_size_ack(msg_id, payload_size);
case UBX_CLASS_CFG:
return ubx_validate_payload_size_cfg(msg_id, payload_size);
default:
return -1;
}
}
int ubx_create_and_validate_frame(uint8_t *ubx_frame, uint16_t ubx_frame_size, uint8_t msg_cls,
uint8_t msg_id, const void *payload, uint16_t payload_size)
{
if (ubx_validate_payload_size(msg_cls, msg_id, payload_size)) {
return -1;
}
return modem_ubx_create_frame(ubx_frame, ubx_frame_size, msg_cls, msg_id, payload,
payload_size);
}
void ubx_cfg_ack_payload_default(struct ubx_cfg_ack_payload *payload)
{
payload->message_class = UBX_CLASS_CFG;
payload->message_id = UBX_CFG_PRT;
}
void ubx_cfg_rate_payload_default(struct ubx_cfg_rate_payload *payload)
{
payload->meas_rate_ms = 1000;
payload->nav_rate = 1;
payload->time_ref = UBX_CFG_RATE_TIME_REF_UTC;
}
void ubx_cfg_prt_poll_payload_default(struct ubx_cfg_prt_poll_payload *payload)
{
payload->port_id = UBX_PORT_NUMBER_UART;
}
void ubx_cfg_prt_set_payload_default(struct ubx_cfg_prt_set_payload *payload)
{
payload->port_id = UBX_PORT_NUMBER_UART;
payload->reserved0 = UBX_CFG_PRT_RESERVED0;
payload->tx_ready_pin_conf = UBX_CFG_PRT_TX_READY_PIN_CONF_POL_HIGH;
payload->port_mode = UBX_CFG_PRT_PORT_MODE_CHAR_LEN_8 | UBX_CFG_PRT_PORT_MODE_PARITY_NONE |
UBX_CFG_PRT_PORT_MODE_STOP_BITS_1;
payload->baudrate = ubx_baudrate[3];
payload->in_proto_mask = UBX_CFG_PRT_IN_PROTO_UBX | UBX_CFG_PRT_IN_PROTO_NMEA |
UBX_CFG_PRT_IN_PROTO_RTCM;
payload->out_proto_mask = UBX_CFG_PRT_OUT_PROTO_UBX | UBX_CFG_PRT_OUT_PROTO_NMEA |
UBX_CFG_PRT_OUT_PROTO_RTCM3;
payload->flags = UBX_CFG_PRT_FLAGS_DEFAULT;
payload->reserved1 = UBX_CFG_PRT_RESERVED1;
}
void ubx_cfg_rst_payload_default(struct ubx_cfg_rst_payload *payload)
{
payload->nav_bbr_mask = UBX_CFG_RST_NAV_BBR_MASK_HOT_START;
payload->reset_mode = UBX_CFG_RST_RESET_MODE_CONTROLLED_SOFT_RESET;
payload->reserved0 = UBX_CFG_RST_RESERVED0;
}
void ubx_cfg_nav5_payload_default(struct ubx_cfg_nav5_payload *payload)
{
payload->mask = UBX_CFG_NAV5_MASK_ALL;
payload->dyn_model = UBX_DYN_MODEL_PORTABLE;
payload->fix_mode = UBX_FIX_AUTO_FIX;
payload->fixed_alt = UBX_CFG_NAV5_FIXED_ALT_DEFAULT;
payload->fixed_alt_var = UBX_CFG_NAV5_FIXED_ALT_VAR_DEFAULT;
payload->min_elev = UBX_CFG_NAV5_MIN_ELEV_DEFAULT;
payload->dr_limit = UBX_CFG_NAV5_DR_LIMIT_DEFAULT;
payload->p_dop = UBX_CFG_NAV5_P_DOP_DEFAULT;
payload->t_dop = UBX_CFG_NAV5_T_DOP_DEFAULT;
payload->p_acc = UBX_CFG_NAV5_P_ACC_DEFAULT;
payload->t_acc = UBX_CFG_NAV5_T_ACC_DEFAULT;
payload->static_hold_threshold = UBX_CFG_NAV5_STATIC_HOLD_THRESHOLD_DEFAULT;
payload->dgnss_timeout = UBX_CFG_NAV5_DGNSS_TIMEOUT_DEFAULT;
payload->cno_threshold_num_svs = UBX_CFG_NAV5_CNO_THRESHOLD_NUM_SVS_DEFAULT;
payload->cno_threshold = UBX_CFG_NAV5_CNO_THRESHOLD_DEFAULT;
payload->reserved0 = UBX_CFG_NAV5_RESERVED0;
payload->static_hold_dist_threshold = UBX_CFG_NAV5_STATIC_HOLD_DIST_THRESHOLD;
payload->utc_standard = UBX_CFG_NAV5_UTC_STANDARD_DEFAULT;
}
static struct ubx_cfg_gnss_payload_config_block ubx_cfg_gnss_payload_config_block_default = {
.gnss_id = UBX_GNSS_ID_GPS,
.num_res_trk_ch = 0x00,
.max_num_trk_ch = 0x00,
.reserved0 = UBX_CFG_GNSS_RESERVED0,
.flags = UBX_CFG_GNSS_FLAG_ENABLE | UBX_CFG_GNSS_FLAG_SGN_CNF_GPS_L1C_A,
};
void ubx_cfg_gnss_payload_default(struct ubx_cfg_gnss_payload *payload)
{
payload->msg_ver = UBX_CFG_GNSS_MSG_VER;
payload->num_trk_ch_hw = UBX_CFG_GNSS_NUM_TRK_CH_HW_DEFAULT;
payload->num_trk_ch_use = UBX_CFG_GNSS_NUM_TRK_CH_USE_DEFAULT;
for (int i = 0; i < payload->num_config_blocks; ++i) {
payload->config_blocks[i] = ubx_cfg_gnss_payload_config_block_default;
}
}
void ubx_cfg_msg_payload_default(struct ubx_cfg_msg_payload *payload)
{
payload->message_class = UBX_CLASS_NMEA;
payload->message_id = UBX_NMEA_GGA;
payload->rate = UBX_CFG_MSG_RATE_DEFAULT;
}

View file

@ -0,0 +1,251 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <zephyr/modem/ubx.h>
#include "gnss_u_blox_protocol_defines.h"
#ifndef ZEPHYR_U_BLOX_PROTOCOL_
#define ZEPHYR_U_BLOX_PROTOCOL_
#define UBX_BAUDRATE_COUNT 9
/* When a configuration frame is sent, the device requires some delay to reflect the changes. */
/* TODO: check what is the precise waiting time for each message. */
#define UBX_CFG_RST_WAIT_MS 6000
#define UBX_CFG_GNSS_WAIT_MS 6000
#define UBX_CFG_NAV5_WAIT_MS 6000
extern const uint32_t ubx_baudrate[UBX_BAUDRATE_COUNT];
#define UBX_FRM_GET_PAYLOAD_SZ 0
#define UBX_CFG_ACK_PAYLOAD_SZ 2
#define UBX_CFG_NAK_PAYLOAD_SZ 2
#define UBX_CFG_RATE_PAYLOAD_SZ 6
#define UBX_CFG_PRT_POLL_PAYLOAD_SZ 1
#define UBX_CFG_PRT_POLL_FRM_SZ (UBX_FRM_SZ_WO_PAYLOAD + UBX_CFG_PRT_POLL_PAYLOAD_SZ)
#define UBX_CFG_PRT_SET_PAYLOAD_SZ 20
#define UBX_CFG_PRT_SET_FRM_SZ (UBX_FRM_SZ_WO_PAYLOAD + UBX_CFG_PRT_SET_PAYLOAD_SZ)
#define UBX_CFG_RST_PAYLOAD_SZ 4
#define UBX_CFG_RST_FRM_SZ (UBX_FRM_SZ_WO_PAYLOAD + UBX_CFG_RST_PAYLOAD_SZ)
#define UBX_CFG_NAV5_PAYLOAD_SZ 36
#define UBX_CFG_NAV5_FRM_SZ (UBX_FRM_SZ_WO_PAYLOAD + UBX_CFG_NAV5_PAYLOAD_SZ)
#define UBX_CFG_MSG_PAYLOAD_SZ 3
#define UBX_CFG_MSG_FRM_SZ (UBX_FRM_SZ_WO_PAYLOAD + UBX_CFG_MSG_PAYLOAD_SZ)
#define UBX_CFG_GNSS_PAYLOAD_INIT_SZ 4
#define UBX_CFG_GNSS_PAYLOAD_CFG_BLK_SZ 8
#define UBX_CFG_GNSS_PAYLOAD_SZ(n) \
(UBX_CFG_GNSS_PAYLOAD_INIT_SZ + UBX_CFG_GNSS_PAYLOAD_CFG_BLK_SZ * n)
#define UBX_CFG_GNSS_FRM_SZ(n) (UBX_FRM_SZ_WO_PAYLOAD + UBX_CFG_GNSS_PAYLOAD_SZ(n))
int ubx_create_and_validate_frame(uint8_t *ubx_frame, uint16_t ubx_frame_size, uint8_t msg_cls,
uint8_t msg_id, const void *payload, uint16_t payload_size);
struct ubx_cfg_ack_payload {
uint8_t message_class;
uint8_t message_id;
};
void ubx_cfg_ack_payload_default(struct ubx_cfg_ack_payload *payload);
#define UBX_CFG_RATE_TIME_REF_UTC 0 /* Align measurements to UTC time. */
#define UBX_CFG_RATE_TIME_REF_GPS 1 /* Align measurements to GPS time. */
#define UBX_CFG_RATE_TIME_REF_GLO 2 /* Align measurements to GLONASS time. */
#define UBX_CFG_RATE_TIME_REF_BDS 3 /* Align measurements to BeiDou time. */
#define UBX_CFG_RATE_TIME_REF_GAL 4 /* Align measurements to Galileo time. */
struct ubx_cfg_rate_payload {
uint16_t meas_rate_ms;
uint16_t nav_rate;
uint16_t time_ref;
};
void ubx_cfg_rate_payload_default(struct ubx_cfg_rate_payload *payload);
struct ubx_cfg_prt_poll_payload {
uint8_t port_id;
};
void ubx_cfg_prt_poll_payload_default(struct ubx_cfg_prt_poll_payload *payload);
#define UBX_CFG_PRT_IN_PROTO_UBX BIT(0)
#define UBX_CFG_PRT_IN_PROTO_NMEA BIT(1)
#define UBX_CFG_PRT_IN_PROTO_RTCM BIT(2)
#define UBX_CFG_PRT_IN_PROTO_RTCM3 BIT(5)
#define UBX_CFG_PRT_OUT_PROTO_UBX BIT(0)
#define UBX_CFG_PRT_OUT_PROTO_NMEA BIT(1)
#define UBX_CFG_PRT_OUT_PROTO_RTCM3 BIT(5)
#define UBX_CFG_PRT_PORT_MODE_CHAR_LEN_5 0U
#define UBX_CFG_PRT_PORT_MODE_CHAR_LEN_6 BIT(6)
#define UBX_CFG_PRT_PORT_MODE_CHAR_LEN_7 BIT(7)
#define UBX_CFG_PRT_PORT_MODE_CHAR_LEN_8 (BIT(6) | BIT(7))
#define UBX_CFG_PRT_PORT_MODE_PARITY_EVEN 0U
#define UBX_CFG_PRT_PORT_MODE_PARITY_ODD BIT(9)
#define UBX_CFG_PRT_PORT_MODE_PARITY_NONE BIT(11)
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_1 0U
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_1_HALF BIT(12)
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_2 BIT(13)
#define UBX_CFG_PRT_PORT_MODE_STOP_BITS_HALF (BIT(12) | BIT(13))
#define UBX_CFG_PRT_RESERVED0 0x00
#define UBX_CFG_PRT_TX_READY_PIN_CONF_DEFAULT 0x0000
#define UBX_CFG_PRT_TX_READY_PIN_CONF_EN BIT(0)
#define UBX_CFG_PRT_TX_READY_PIN_CONF_POL_LOW BIT(1)
#define UBX_CFG_PRT_TX_READY_PIN_CONF_POL_HIGH 0U
#define UBX_CFG_PRT_RESERVED1 0x00
#define UBX_CFG_PRT_FLAGS_DEFAULT 0x0000
#define UBX_CFG_PRT_FLAGS_EXTENDED_TX_TIMEOUT BIT(0)
struct ubx_cfg_prt_set_payload {
uint8_t port_id;
uint8_t reserved0;
uint16_t tx_ready_pin_conf;
uint32_t port_mode;
uint32_t baudrate;
uint16_t in_proto_mask;
uint16_t out_proto_mask;
uint16_t flags;
uint8_t reserved1;
};
void ubx_cfg_prt_set_payload_default(struct ubx_cfg_prt_set_payload *payload);
#define UBX_CFG_RST_NAV_BBR_MASK_HOT_START 0x0000
#define UBX_CFG_RST_NAV_BBR_MASK_WARM_START 0x0001
#define UBX_CFG_RST_NAV_BBR_MASK_COLD_START 0xFFFF
#define UBX_CFG_RST_RESET_MODE_HARD_RESET 0x00
#define UBX_CFG_RST_RESET_MODE_CONTROLLED_SOFT_RESET 0x01
#define UBX_CFG_RST_RESET_MODE_CONTROLLED_SOFT_RESET_GNSS_ONLY 0x02
#define UBX_CFG_RST_RESET_MODE_HARD_RESET_AFTER_SHUTDOWN 0x04
#define UBX_CFG_RST_RESET_MODE_CONTROLLED_GNSS_STOP 0x08
#define UBX_CFG_RST_RESET_MODE_CONTROLLED_GNSS_START 0x09
#define UBX_CFG_RST_RESERVED0 0x00
struct ubx_cfg_rst_payload {
uint16_t nav_bbr_mask;
uint8_t reset_mode;
uint8_t reserved0;
};
void ubx_cfg_rst_payload_default(struct ubx_cfg_rst_payload *payload);
#define UBX_CFG_NAV5_MASK_ALL 0x05FF
#define UBX_CFG_NAV5_FIX_MODE_DEFAULT UBX_FIX_AUTO_FIX
#define UBX_CFG_NAV5_FIXED_ALT_DEFAULT 0
#define UBX_CFG_NAV5_FIXED_ALT_VAR_DEFAULT 1U
#define UBX_CFG_NAV5_MIN_ELEV_DEFAULT 5
#define UBX_CFG_NAV5_DR_LIMIT_DEFAULT 3U
#define UBX_CFG_NAV5_P_DOP_DEFAULT 100U
#define UBX_CFG_NAV5_T_DOP_DEFAULT 100U
#define UBX_CFG_NAV5_P_ACC_DEFAULT 100U
#define UBX_CFG_NAV5_T_ACC_DEFAULT 350U
#define UBX_CFG_NAV5_STATIC_HOLD_THRESHOLD_DEFAULT 0U
#define UBX_CFG_NAV5_DGNSS_TIMEOUT_DEFAULT 60U
#define UBX_CFG_NAV5_CNO_THRESHOLD_NUM_SVS_DEFAULT 0U
#define UBX_CFG_NAV5_CNO_THRESHOLD_DEFAULT 0U
#define UBX_CFG_NAV5_RESERVED0 0U
#define UBX_CFG_NAV5_STATIC_HOLD_DIST_THRESHOLD 0U
#define UBX_CFG_NAV5_UTC_STANDARD_DEFAULT UBX_UTC_AUTOUTC
struct ubx_cfg_nav5_payload {
uint16_t mask;
uint8_t dyn_model;
uint8_t fix_mode;
int32_t fixed_alt;
uint32_t fixed_alt_var;
int8_t min_elev;
uint8_t dr_limit;
uint16_t p_dop;
uint16_t t_dop;
uint16_t p_acc;
uint16_t t_acc;
uint8_t static_hold_threshold;
uint8_t dgnss_timeout;
uint8_t cno_threshold_num_svs;
uint8_t cno_threshold;
uint16_t reserved0;
uint16_t static_hold_dist_threshold;
uint8_t utc_standard;
};
void ubx_cfg_nav5_payload_default(struct ubx_cfg_nav5_payload *payload);
#define UBX_CFG_GNSS_MSG_VER 0x00
#define UBX_CFG_GNSS_NUM_TRK_CH_HW_DEFAULT 0x31
#define UBX_CFG_GNSS_NUM_TRK_CH_USE_DEFAULT 0x31
#define UBX_CFG_GNSS_RESERVED0 0x00
#define UBX_CFG_GNSS_FLAG_ENABLE BIT(0)
#define UBX_CFG_GNSS_FLAG_DISABLE 0U
#define UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT 16
/* When gnss_id is 0 (GPS) */
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GPS_L1C_A (0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GPS_L2C (0x10 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GPS_L5 (0x20 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
/* When gnss_id is 1 (SBAS) */
#define UBX_CFG_GNSS_FLAG_SGN_CNF_SBAS_L1C_A (0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
/* When gnss_id is 2 (Galileo) */
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GALILEO_E1 (0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GALILEO_E5A (0x10 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GALILEO_E5B (0x20 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
/* When gnss_id is 3 (BeiDou) */
#define UBX_CFG_GNSS_FLAG_SGN_CNF_BEIDOU_B1I (0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_BEIDOU_B2I (0x10 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_BEIDOU_B2A (0x80 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
/* When gnss_id is 4 (IMES) */
#define UBX_CFG_GNSS_FLAG_SGN_CNF_IMES_L1 (0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
/* When gnss_id is 5 (QZSS) */
#define UBX_CFG_GNSS_FLAG_SGN_CNF_QZSS_L1C_A (0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_QZSS_L1S (0x04 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_QZSS_L2C (0x10 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_QZSS_L5 (0x20 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
/* When gnss_id is 6 (GLONASS) */
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GLONASS_L1 (0x01 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
#define UBX_CFG_GNSS_FLAG_SGN_CNF_GLONASS_L2 (0x10 << UBX_CFG_GNSS_FLAG_SGN_CNF_SHIFT)
struct ubx_cfg_gnss_payload_config_block {
uint8_t gnss_id;
uint8_t num_res_trk_ch;
uint8_t max_num_trk_ch;
uint8_t reserved0;
uint32_t flags;
};
struct ubx_cfg_gnss_payload {
uint8_t msg_ver;
uint8_t num_trk_ch_hw;
uint8_t num_trk_ch_use;
uint8_t num_config_blocks;
struct ubx_cfg_gnss_payload_config_block config_blocks[];
};
void ubx_cfg_gnss_payload_default(struct ubx_cfg_gnss_payload *payload);
#define UBX_CFG_MSG_RATE_DEFAULT 1
struct ubx_cfg_msg_payload {
uint8_t message_class;
uint8_t message_id;
uint8_t rate;
};
void ubx_cfg_msg_payload_default(struct ubx_cfg_msg_payload *payload);
#endif /* ZEPHYR_U_BLOX_PROTOCOL_ */

View file

@ -0,0 +1,258 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Referred some enum definitions from file "include/zephyr/drivers/gnss/ublox_neo_m8_defines.h"
* from the pull request #46447 (link - https://github.com/zephyrproject-rtos/zephyr/pull/46447).
*/
#ifndef ZEPHYR_U_BLOX_PROTOCOL_DEFINES_
#define ZEPHYR_U_BLOX_PROTOCOL_DEFINES_
enum ubx_gnss_id {
UBX_GNSS_ID_GPS = 0,
UBX_GNSS_ID_SBAS = 1,
UBX_GNSS_ID_GALILEO = 2,
UBX_GNSS_ID_BEIDOU = 3,
UBX_GNSS_ID_IMES = 4,
UBX_GNSS_ID_QZSS = 5,
UBX_GNSS_ID_GLONASS = 6,
};
enum ubx_port_number {
UBX_PORT_NUMBER_DDC = 0,
UBX_PORT_NUMBER_UART,
UBX_PORT_NUMBER_USB,
UBX_PORT_NUMBER_SPI,
};
enum ubx_dynamic_model {
UBX_DYN_MODEL_PORTABLE = 0,
UBX_DYN_MODEL_STATIONARY = 2,
UBX_DYN_MODEL_PEDESTRIAN = 3,
UBX_DYN_MODEL_AUTOMOTIV = 4,
UBX_DYN_MODEL_SEA = 5,
UBX_DYN_MODEL_AIRBONE1G = 6,
UBX_DYN_MODEL_AIRBONE2G = 7,
UBX_DYN_MODEL_AIRBONE4G = 8,
UBX_DYN_MODEL_WIRST = 9,
UBX_DYN_MODEL_BIKE = 10,
};
enum ubx_fix_mode {
UBX_FIX_P_2D = 1,
UBX_FIX_P_3D,
UBX_FIX_AUTO_FIX,
};
enum ubx_utc_standard {
UBX_UTC_AUTOUTC = 0,
UBX_UTC_GPS = 3,
UBX_UTC_GALILEO = 5,
UBX_UTC_GLONASS,
UBX_UTC_BEIDOU,
UBX_UTC_NAVIC,
};
enum ubx_msg_class {
UBX_CLASS_NAV = 0x01,
UBX_CLASS_RXM = 0x02,
UBX_CLASS_INF = 0x04,
UBX_CLASS_ACK = 0x05,
UBX_CLASS_CFG = 0x06,
UBX_CLASS_UPD = 0x09,
UBX_CLASS_MON = 0x0A,
UBX_CLASS_AID = 0x0B,
UBX_CLASS_TIM = 0x0D,
UBX_CLASS_ESF = 0x10,
UBX_CLASS_MGA = 0x13,
UBX_CLASS_LOG = 0x21,
UBX_CLASS_SEC = 0x27,
UBX_CLASS_HNR = 0x28,
UBX_CLASS_NMEA = 0xF0,
};
enum ubx_ack_message {
UBX_ACK_ACK = 0x01,
UBX_ACK_NAK = 0x00,
};
enum ubx_config_message {
UBX_CFG_ANT = 0x13,
UBX_CFG_BATCH = 0x93,
UBX_CFG_CFG = 0x09,
UBX_CFG_DAT = 0x06,
UBX_CFG_DGNSS = 0x70,
UBX_CFG_DOSC = 0x61,
UBX_CFG_ESFALG = 0x56,
UBX_CFG_ESFAE = 0x4C,
UBX_CFG_ESFGE = 0x4D,
UBX_CFG_ESFWTE = 0x82,
UBX_CFG_ESRCE = 0x60,
UBX_CFG_GEOFENCE = 0x69,
UBX_CFG_GNSS = 0x3E,
UBX_CFG_HNR = 0x5C,
UBX_CFG_INF = 0x02,
UBX_CFG_ITFM = 0x39,
UBX_CFG_LOGFILTER = 0x47,
UBX_CFG_MSG = 0x01,
UBX_CFG_NAV5 = 0x24,
UBX_CFG_NAVX5 = 0x23,
UBX_CFG_NMEA = 0x17,
UBX_CFG_ODO = 0x1E,
UBX_CFG_PM2 = 0x3B,
UBX_CFG_PMS = 0x86,
UBX_CFG_PRT = 0x00,
UBX_CFG_PWR = 0x57,
UBX_CFG_RATE = 0x08,
UBX_CFG_RINV = 0x34,
UBX_CFG_RST = 0x04,
UBX_CFG_RXM = 0x11,
UBX_CFG_SBAS = 0x16,
UBX_CFG_SENIF = 0x88,
UBX_CFG_SLAS = 0x8D,
UBX_CFG_SMGR = 0x62,
UBX_CFG_SPT = 0x64,
UBX_CFG_TMODE2 = 0x3D,
UBX_CFG_TMODE3 = 0x71,
UBX_CFG_TP5 = 0x31,
UBX_CFG_TXSLOT = 0x53,
UBX_CFG_USB = 0x1B,
};
enum ubx_information_message {
UBX_INF_DEBUG = 0x04,
UBX_INF_ERROR = 0x00,
UBX_INF_NOTICE = 0x02,
UBX_INF_TEST = 0x03,
UBX_INF_WARNING = 0x01,
};
enum ubx_logging_message {
UBX_LOG_BATCH = 0x11,
UBX_LOG_CREATE = 0x07,
UBX_LOG_ERASE = 0x03,
UBX_LOG_FINDTIME = 0x0E,
UBX_LOG_INFO = 0x08,
UBX_LOG_RETRIEVEBATCH = 0x10,
UBX_LOG_RETRIEVEPOSEXTRA = 0x0f,
UBX_LOG_RETRIEVEPOS = 0x0b,
UBX_LOG_RETRIEVESTRING = 0x0d,
UBX_LOG_RETRIEVE = 0x09,
UBX_LOG_STRING = 0x04,
};
enum ubx_multiple_gnss_assistance_message {
UBX_MGA_ACK = 0x60,
UBX_MGA_ANO = 0x20,
UBX_MGA_BDS = 0x03,
UBX_MGA_DBD = 0x80,
UBX_MGA_FLASH = 0x21,
UBX_MGA_GAL = 0x02,
UBX_MGA_GLO = 0x06,
UBX_MGA_GPS = 0x00,
UBX_MGA_INI = 0x40,
UBX_MGA_QZSS = 0x05,
};
enum ubx_monitoring_message {
UBX_MON_BATCH = 0x32,
UBX_MON_GNSS = 0x28,
UBX_MON_HW2 = 0x0B,
UBX_MON_HW = 0x09,
UBX_MON_IO = 0x02,
UBX_MON_MSGPP = 0x06,
UBX_MON_PATCH = 0x27,
UBX_MON_RXBUF = 0x07,
UBX_MON_RXR = 0x21,
UBX_MON_SMGR = 0x2E,
UBX_MON_SPT = 0x2F,
UBX_MON_TXBUF = 0x08,
UBX_MON_VER = 0x04,
};
enum ubx_nagivation_results_message {
UBX_NAV_AOPSTATUS = 0x60,
UBX_NAV_ATT = 0x05,
UBX_NAV_CLOCK = 0x22,
UBX_NAV_COV = 0x36,
UBX_NAV_DGPS = 0x31,
UBX_NAV_DOP = 0x04,
UBX_NAV_EELL = 0x3d,
UBX_NAV_EOE = 0x61,
UBX_NAV_GEOFENCE = 0x39,
UBX_NAV_HPPOSECEF = 0x13,
UBX_NAV_HPPOSLLH = 0x14,
UBX_NAV_NMI = 0x28,
UBX_NAV_ODO = 0x09,
UBX_NAV_ORB = 0x34,
UBX_NAV_POSECEF = 0x01,
UBX_NAV_POSLLH = 0x02,
UBX_NAV_PVT = 0x07,
UBX_NAV_RELPOSNED = 0x3C,
UBX_NAV_RESETODO = 0x10,
UBX_NAV_SAT = 0x35,
UBX_NAV_SBAS = 0x32,
UBX_NAV_SLAS = 0x42,
UBX_NAV_SOL = 0x06,
UBX_NAV_STATUS = 0x03,
UBX_NAV_SVINFO = 0x30,
UBX_NAV_SVIN = 0x3B,
UBX_NAV_TIMEBDS = 0x24,
UBX_NAV_TIMEGAL = 0x25,
UBX_NAV_TIMEGLO = 0x23,
UBX_NAV_TIMEGPS = 0x20,
UBX_NAV_TIMELS = 0x26,
UBX_NAV_TIMEUTC = 0x21,
UBX_NAV_VELECEF = 0x11,
UBX_NAV_VELNED = 0x12,
};
enum ubx_receiver_manager_message {
UBX_RXM_IMES = 0x61,
UBX_RXM_MEASX = 0x14,
UBX_RXM_PMREQ = 0x41,
UBX_RXM_RAWX = 0x15,
UBX_RXM_RLM = 0x59,
UBX_RXM_RTCM = 0x32,
UBX_RXM_SFRBX = 0x13,
};
enum ubx_timing_message {
UBX_TIM_DOSC = 0x11,
UBX_TIM_FCHG = 0x16,
UBX_TIM_HOC = 0x17,
UBX_TIM_SMEAS = 0x13,
UBX_TIM_SVIN = 0x04,
UBX_TIM_TM2 = 0x03,
UBX_TIM_TOS = 0x12,
UBX_TIM_TP = 0x01,
UBX_TIM_VCOCAL = 0x15,
UBX_TIM_VRFY = 0x06,
};
enum ubx_nmea_message_id {
UBX_NMEA_DTM = 0x0A,
UBX_NMEA_GBQ = 0x44,
UBX_NMEA_GBS = 0x09,
UBX_NMEA_GGA = 0x00,
UBX_NMEA_GLL = 0x01,
UBX_NMEA_GLQ = 0x43,
UBX_NMEA_GNQ = 0x42,
UBX_NMEA_GNS = 0x0D,
UBX_NMEA_GPQ = 0x40,
UBX_NMEA_GRS = 0x06,
UBX_NMEA_GSA = 0x02,
UBX_NMEA_GST = 0x07,
UBX_NMEA_GSV = 0x03,
UBX_NMEA_RMC = 0x04,
UBX_NMEA_THS = 0x0E,
UBX_NMEA_TXT = 0x41,
UBX_NMEA_VLW = 0x0F,
UBX_NMEA_VTG = 0x05,
UBX_NMEA_ZDA = 0x08,
};
#endif /* ZEPHYR_U_BLOX_PROTOCOL_DEFINES_ */

View file

@ -0,0 +1,17 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
description: U-BLOX M10 GNSS Module
compatible: "u-blox,m10"
include:
- uart-device.yaml
properties:
uart-baudrate:
type: int
description: |
Baudrate for communication on the UART port.
default: 115200
enum: [4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600]

View file

@ -0,0 +1,23 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_U_BLOX_M10_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_U_BLOX_M10_H_
#include <zephyr/dt-bindings/dt-util.h>
/* UART Baudrate. */
#define UBX_M10_UART_BAUDRATE_4800 0x00
#define UBX_M10_UART_BAUDRATE_9600 0x01
#define UBX_M10_UART_BAUDRATE_19200 0x02
#define UBX_M10_UART_BAUDRATE_38400 0x03
#define UBX_M10_UART_BAUDRATE_57600 0x04
#define UBX_M10_UART_BAUDRATE_115200 0x05
#define UBX_M10_UART_BAUDRATE_230400 0x06
#define UBX_M10_UART_BAUDRATE_460800 0x07
#define UBX_M10_UART_BAUDRATE_921600 0x08
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_U_BLOX_M10_H_ */

175
include/zephyr/modem/ubx.h Normal file
View file

@ -0,0 +1,175 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/modem/pipe.h>
#ifndef ZEPHYR_MODEM_UBX_
#define ZEPHYR_MODEM_UBX_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Modem Ubx
* @defgroup modem_ubx Modem Ubx
* @ingroup modem
* @{
*/
#define UBX_FRM_HEADER_SZ 6
#define UBX_FRM_FOOTER_SZ 2
#define UBX_FRM_SZ_WITHOUT_PAYLOAD (UBX_FRM_HEADER_SZ + UBX_FRM_FOOTER_SZ)
#define UBX_FRM_SZ(payload_size) (payload_size + UBX_FRM_SZ_WITHOUT_PAYLOAD)
#define UBX_PREAMBLE_SYNC_CHAR_1 0xB5
#define UBX_PREAMBLE_SYNC_CHAR_2 0x62
#define UBX_FRM_PREAMBLE_SYNC_CHAR_1_IDX 0
#define UBX_FRM_PREAMBLE_SYNC_CHAR_2_IDX 1
#define UBX_FRM_MSG_CLASS_IDX 2
#define UBX_FRM_MSG_ID_IDX 3
#define UBX_FRM_PAYLOAD_SZ_L_IDX 4
#define UBX_FRM_PAYLOAD_SZ_H_IDX 5
#define UBX_FRM_PAYLOAD_IDX 6
#define UBX_FRM_CHECKSUM_START_IDX 2
#define UBX_FRM_CHECKSUM_STOP_IDX(frame_len) (frame_len - 2)
#define UBX_PAYLOAD_SZ_MAX 256
#define UBX_FRM_SZ_MAX UBX_FRM_SZ(UBX_PAYLOAD_SZ_MAX)
struct ubx_frame {
uint8_t preamble_sync_char_1;
uint8_t preamble_sync_char_2;
uint8_t message_class;
uint8_t message_id;
uint8_t payload_size_low;
uint8_t payload_size_high;
uint8_t payload_and_checksum[];
};
struct modem_ubx_script {
struct ubx_frame *request;
struct ubx_frame *response;
struct ubx_frame *match;
uint16_t retry_count;
k_timeout_t timeout;
};
struct modem_ubx {
void *user_data;
atomic_t state;
uint8_t *receive_buf;
uint16_t receive_buf_size;
uint8_t *work_buf;
uint16_t work_buf_size;
uint16_t work_buf_len;
bool ubx_preamble_sync_chars_received;
const struct modem_ubx_script *script;
struct modem_pipe *pipe;
struct k_work send_work;
struct k_work process_work;
struct k_sem script_stopped_sem;
struct k_sem script_running_sem;
};
struct modem_ubx_config {
void *user_data;
uint8_t *receive_buf;
uint16_t receive_buf_size;
uint8_t *work_buf;
uint16_t work_buf_size;
};
/**
* @brief Attach pipe to Modem Ubx
*
* @param ubx Modem Ubx instance
* @param pipe Pipe instance to attach Modem Ubx instance to
* @returns 0 if successful
* @returns negative errno code if failure
* @note Modem Ubx instance is enabled if successful
*/
int modem_ubx_attach(struct modem_ubx *ubx, struct modem_pipe *pipe);
/**
* @brief Release pipe from Modem Ubx instance
*
* @param ubx Modem Ubx instance
*/
void modem_ubx_release(struct modem_ubx *ubx);
/**
* @brief Initialize Modem Ubx instance
* @param ubx Modem Ubx instance
* @param config Configuration which shall be applied to the Modem Ubx instance
* @note Modem Ubx instance must be attached to a pipe instance
*/
int modem_ubx_init(struct modem_ubx *ubx, const struct modem_ubx_config *config);
/**
* @brief Writes the ubx frame in script.request and reads back its response (if available)
* @details For each ubx frame sent, the device responds in 0, 1 or both of the following ways:
* 1. The device sends back a UBX-ACK frame to denote 'acknowledge' and 'not-acknowledge'.
* Note: the message id of UBX-ACK frame determines whether the device acknowledged.
* Ex: when we send a UBX-CFG frame, the device responds with a UBX-ACK frame.
* 2. The device sends back the same frame that we sent to it, with it's payload populated.
* It's used to get the current configuration corresponding to the frame that we sent.
* Ex: frame types such as "get" or "poll" ubx frames respond this way.
* This response (if received) is written to script.response.
*
* This function writes the ubx frame in script.request then reads back it's response.
* If script.match is not NULL, then every ubx frame received from the device is compared with
* script.match to check if a match occurred. This could be used to match UBX-ACK frame sent
* from the device by populating script.match with UBX-ACK that the script expects to receive.
*
* The script terminates when either of the following happens:
* 1. script.match is successfully received and matched.
* 2. timeout (denoted by script.timeout) occurs.
* @param ubx Modem Ubx instance
* @param script Script to be executed
* @note The length of ubx frame in the script.request should not exceed UBX_FRM_SZ_MAX
* @note Modem Ubx instance must be attached to a pipe instance
* @returns 0 if device acknowledged via UBX-ACK and no "get" response was received
* @returns positive integer denoting the length of "get" response that was received
* @returns negative errno code if failure
*/
int modem_ubx_run_script(struct modem_ubx *ubx, const struct modem_ubx_script *script);
/**
* @brief Initialize ubx frame
* @param ubx_frame Ubx frame buffer
* @param ubx_frame_size Ubx frame buffer size
* @param msg_cls Message class
* @param msg_id Message id
* @param payload Payload buffer
* @param payload_size Payload buffer size
* @returns positive integer denoting the length of the ubx frame created
* @returns negative errno code if failure
*/
int modem_ubx_create_frame(uint8_t *ubx_frame, uint16_t ubx_frame_size, uint8_t msg_cls,
uint8_t msg_id, const void *payload, uint16_t payload_size);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_MODEM_UBX_ */

View file

@ -0,0 +1,4 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
CONFIG_UART_INTERRUPT_DRIVEN=y

View file

@ -0,0 +1,25 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
aliases {
gnss = &lpuart2;
};
};
&lpuart2 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&pinmux_lpuart2>;
pinctrl-1 = <&pinmux_lpuart2_sleep>;
pinctrl-names = "default", "sleep";
u_blox_m10: u-blox,m10 {
status = "okay";
compatible = "u-blox,m10";
uart-baudrate = <115200>;
};
};

View file

@ -0,0 +1,22 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
aliases {
gnss = &lpuart3;
};
};
&lpuart3 {
status = "okay";
current-speed = <115200>;
u_blox_m10: u-blox,m10 {
status = "okay";
compatible = "u-blox,m10";
uart-baudrate = <115200>;
};
};

View file

@ -9,6 +9,7 @@ zephyr_library_sources_ifdef(CONFIG_MODEM_CHAT modem_chat.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_CMUX modem_cmux.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_PIPE modem_pipe.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_PPP modem_ppp.c)
zephyr_library_sources_ifdef(CONFIG_MODEM_UBX modem_ubx.c)
add_subdirectory(backends)

View file

@ -54,6 +54,21 @@ config MODEM_PPP_NET_BUF_FRAG_SIZE
endif
config MODEM_UBX
bool "Modem U-BLOX module"
select RING_BUFFER
select MODEM_PIPE
help
Enable Modem U-BLOX module.
if MODEM_UBX
config MODEM_UBX_LOG_BUFFER
int "Modem U-BLOX log buffer size"
default 128
endif
module = MODEM_MODULES
module-str = modem_modules
source "subsys/logging/Kconfig.template.log_config"

338
subsys/modem/modem_ubx.c Normal file
View file

@ -0,0 +1,338 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/modem/ubx.h>
#include <string.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(modem_ubx, CONFIG_MODEM_MODULES_LOG_LEVEL);
#define MODEM_UBX_STATE_ATTACHED_BIT 0
static int modem_ubx_validate_frame_size(uint16_t ubx_frame_size, uint8_t msg_cls, uint8_t msg_id,
uint16_t payload_size)
{
if (ubx_frame_size > UBX_FRM_SZ_MAX ||
ubx_frame_size < UBX_FRM_SZ_WITHOUT_PAYLOAD ||
ubx_frame_size < UBX_FRM_SZ_WITHOUT_PAYLOAD + payload_size) {
return -1;
}
return 0;
}
int modem_ubx_create_frame(uint8_t *ubx_frame, uint16_t ubx_frame_size, uint8_t msg_cls,
uint8_t msg_id, const void *payload, uint16_t payload_size)
{
if (modem_ubx_validate_frame_size(ubx_frame_size, msg_cls, msg_id, payload_size)) {
return -1;
}
struct ubx_frame *frame = (struct ubx_frame *) ubx_frame;
frame->preamble_sync_char_1 = UBX_PREAMBLE_SYNC_CHAR_1;
frame->preamble_sync_char_2 = UBX_PREAMBLE_SYNC_CHAR_2;
frame->message_class = msg_cls;
frame->message_id = msg_id;
frame->payload_size_low = payload_size;
frame->payload_size_high = payload_size >> 8;
memcpy(frame->payload_and_checksum, payload, payload_size);
uint16_t ubx_frame_len = payload_size + UBX_FRM_SZ_WITHOUT_PAYLOAD;
uint8_t ckA = 0, ckB = 0;
for (unsigned int i = UBX_FRM_CHECKSUM_START_IDX;
i < (UBX_FRM_CHECKSUM_STOP_IDX(ubx_frame_len)); i++) {
ckA += ubx_frame[i];
ckB += ckA;
}
frame->payload_and_checksum[payload_size] = ckA;
frame->payload_and_checksum[payload_size + 1] = ckB;
return ubx_frame_len;
}
static void modem_ubx_reset_received_ubx_preamble_sync_chars(struct modem_ubx *ubx)
{
ubx->ubx_preamble_sync_chars_received = false;
}
static void modem_ubx_reset_parser(struct modem_ubx *ubx)
{
modem_ubx_reset_received_ubx_preamble_sync_chars(ubx);
}
static int modem_ubx_get_payload_length(struct ubx_frame *frame)
{
uint16_t payload_len = frame->payload_size_high;
payload_len = payload_len << 8;
return payload_len | frame->payload_size_low;
}
static int modem_ubx_get_frame_length(struct ubx_frame *frame)
{
return modem_ubx_get_payload_length(frame) + UBX_FRM_SZ_WITHOUT_PAYLOAD;
}
static bool modem_ubx_match_frame_type(struct ubx_frame *frame_1, struct ubx_frame *frame_2)
{
if (frame_1->message_class == frame_2->message_class
&& frame_1->message_id == frame_2->message_id) {
return true;
} else {
return false;
}
}
static bool modem_ubx_match_frame_full(struct ubx_frame *frame_1, struct ubx_frame *frame_2)
{
if (modem_ubx_get_frame_length(frame_1) != modem_ubx_get_frame_length(frame_2)) {
return false;
}
if (memcmp(frame_1, frame_2, modem_ubx_get_frame_length(frame_1)) == 0) {
return true;
} else {
return false;
}
}
static void modem_ubx_script_init(struct modem_ubx *ubx, const struct modem_ubx_script *script)
{
ubx->script = script;
}
static int modem_ubx_run_script_helper(struct modem_ubx *ubx, const struct modem_ubx_script *script)
{
int ret;
if (ubx->pipe == NULL) {
return -EPERM;
}
k_sem_reset(&ubx->script_stopped_sem);
modem_ubx_reset_parser(ubx);
k_work_submit(&ubx->send_work);
if (ubx->script->match == NULL) {
return 0;
}
ret = k_sem_take(&ubx->script_stopped_sem, script->timeout);
if (ret < 0) {
return ret;
}
return 0;
}
int modem_ubx_run_script(struct modem_ubx *ubx, const struct modem_ubx_script *script)
{
int ret, attempt;
if (modem_ubx_get_frame_length(script->request) > UBX_FRM_SZ_MAX) {
return -EFBIG;
}
if (atomic_test_bit(&ubx->state, MODEM_UBX_STATE_ATTACHED_BIT) == false) {
return -EPERM;
}
ret = k_sem_take(&ubx->script_running_sem, K_FOREVER);
if (ret < 0) {
return ret;
}
modem_ubx_script_init(ubx, script);
for (attempt = 0; attempt < script->retry_count; ++attempt) {
ret = modem_ubx_run_script_helper(ubx, script);
if (ret > -1) {
LOG_INF("Successfully executed script on attempt: %d.", attempt);
break;
} else if (ret == -EPERM) {
break;
}
}
if (ret < 0) {
LOG_ERR("Failed to execute script successfully. Attempts: %d.", attempt);
goto unlock;
}
unlock:
k_sem_give(&ubx->script_running_sem);
return ret;
}
static void modem_ubx_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
void *user_data)
{
struct modem_ubx *ubx = (struct modem_ubx *)user_data;
if (event == MODEM_PIPE_EVENT_RECEIVE_READY) {
k_work_submit(&ubx->process_work);
}
}
static void modem_ubx_send_handler(struct k_work *item)
{
struct modem_ubx *ubx = CONTAINER_OF(item, struct modem_ubx, send_work);
int ret, tx_frame_len;
tx_frame_len = modem_ubx_get_frame_length(ubx->script->request);
ret = modem_pipe_transmit(ubx->pipe, (const uint8_t *) ubx->script->request, tx_frame_len);
if (ret < tx_frame_len) {
LOG_ERR("Ubx frame transmission failed. Returned %d.", ret);
return;
}
}
static int modem_ubx_process_received_ubx_frame(struct modem_ubx *ubx)
{
int ret;
struct ubx_frame *received = (struct ubx_frame *) ubx->work_buf;
if (modem_ubx_match_frame_full(received, ubx->script->match) == true) {
/* Frame matched successfully. Terminate the script. */
k_sem_give(&ubx->script_stopped_sem);
ret = 0;
} else if (modem_ubx_match_frame_type(received, ubx->script->request) == true) {
/* Response received successfully. Script not ended. */
memcpy(ubx->script->response, ubx->work_buf, ubx->work_buf_len);
ret = -1;
} else {
/* Ignore the received frame. The device may automatically send periodic frames.
* These frames are not relevant for our script's execution and must be ignored.
*/
ret = -1;
}
modem_ubx_reset_parser(ubx);
return ret;
}
static int modem_ubx_process_received_byte(struct modem_ubx *ubx, uint8_t byte)
{
static uint8_t prev_byte;
static uint16_t rx_ubx_frame_len;
if (ubx->ubx_preamble_sync_chars_received == false) {
if (prev_byte == UBX_PREAMBLE_SYNC_CHAR_1 && byte == UBX_PREAMBLE_SYNC_CHAR_2) {
ubx->ubx_preamble_sync_chars_received = true;
ubx->work_buf[0] = UBX_PREAMBLE_SYNC_CHAR_1;
ubx->work_buf[1] = UBX_PREAMBLE_SYNC_CHAR_2;
ubx->work_buf_len = 2;
}
} else {
ubx->work_buf[ubx->work_buf_len] = byte;
++ubx->work_buf_len;
if (ubx->work_buf_len == UBX_FRM_HEADER_SZ) {
uint16_t rx_ubx_payload_len = ubx->work_buf[UBX_FRM_PAYLOAD_SZ_H_IDX];
rx_ubx_payload_len = ubx->work_buf[UBX_FRM_PAYLOAD_SZ_H_IDX] << 8;
rx_ubx_payload_len |= ubx->work_buf[UBX_FRM_PAYLOAD_SZ_L_IDX];
rx_ubx_frame_len = rx_ubx_payload_len + UBX_FRM_SZ_WITHOUT_PAYLOAD;
}
if (ubx->work_buf_len == rx_ubx_frame_len) {
return modem_ubx_process_received_ubx_frame(ubx);
}
}
prev_byte = byte;
return -1;
}
static void modem_ubx_process_handler(struct k_work *item)
{
struct modem_ubx *ubx = CONTAINER_OF(item, struct modem_ubx, process_work);
int ret;
ret = modem_pipe_receive(ubx->pipe, ubx->receive_buf, ubx->receive_buf_size);
if (ret < 1) {
return;
}
for (int i = 0; i < ret; i++) {
ret = modem_ubx_process_received_byte(ubx, ubx->receive_buf[i]);
if (ret == 0) { /* Frame matched successfully. Terminate the script. */
break;
}
}
k_work_submit(&ubx->process_work);
}
int modem_ubx_attach(struct modem_ubx *ubx, struct modem_pipe *pipe)
{
if (atomic_test_and_set_bit(&ubx->state, MODEM_UBX_STATE_ATTACHED_BIT) == true) {
return 0;
}
ubx->pipe = pipe;
modem_pipe_attach(ubx->pipe, modem_ubx_pipe_callback, ubx);
k_sem_give(&ubx->script_running_sem);
return 0;
}
void modem_ubx_release(struct modem_ubx *ubx)
{
struct k_work_sync sync;
if (atomic_test_and_clear_bit(&ubx->state, MODEM_UBX_STATE_ATTACHED_BIT) == false) {
return;
}
modem_pipe_release(ubx->pipe);
k_work_cancel_sync(&ubx->send_work, &sync);
k_work_cancel_sync(&ubx->process_work, &sync);
k_sem_reset(&ubx->script_stopped_sem);
k_sem_reset(&ubx->script_running_sem);
ubx->work_buf_len = 0;
modem_ubx_reset_parser(ubx);
ubx->pipe = NULL;
}
int modem_ubx_init(struct modem_ubx *ubx, const struct modem_ubx_config *config)
{
__ASSERT_NO_MSG(ubx != NULL);
__ASSERT_NO_MSG(config != NULL);
__ASSERT_NO_MSG(config->receive_buf != NULL);
__ASSERT_NO_MSG(config->receive_buf_size > 0);
__ASSERT_NO_MSG(config->work_buf != NULL);
__ASSERT_NO_MSG(config->work_buf_size > 0);
memset(ubx, 0x00, sizeof(*ubx));
ubx->user_data = config->user_data;
ubx->receive_buf = config->receive_buf;
ubx->receive_buf_size = config->receive_buf_size;
ubx->work_buf = config->work_buf;
ubx->work_buf_size = config->work_buf_size;
ubx->pipe = NULL;
k_work_init(&ubx->send_work, modem_ubx_send_handler);
k_work_init(&ubx->process_work, modem_ubx_process_handler);
k_sem_init(&ubx->script_stopped_sem, 0, 1);
k_sem_init(&ubx->script_running_sem, 1, 1);
return 0;
}