mgmt: mcumgr: transport: Add LoRaWAN MCUmgr SMP transport
Adds a transport that uses LoRaWAN for receiving and responding to messages Signed-off-by: Jamie McCrae <spam@helper3000.net>
This commit is contained in:
parent
62d706e3b3
commit
973ba91487
|
@ -148,6 +148,8 @@ enum smp_transport_type {
|
|||
SMP_UDP_IPV4_TRANSPORT,
|
||||
/** SMP UDP IPv6 */
|
||||
SMP_UDP_IPV6_TRANSPORT,
|
||||
/** SMP LoRaWAN */
|
||||
SMP_LORAWAN_TRANSPORT,
|
||||
/** SMP user defined type */
|
||||
SMP_USER_DEFINED_TRANSPORT
|
||||
};
|
||||
|
|
|
@ -25,6 +25,9 @@ zephyr_library_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_UART
|
|||
zephyr_library_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_UDP
|
||||
src/smp_udp.c
|
||||
)
|
||||
zephyr_library_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_LORAWAN
|
||||
src/smp_lorawan.c
|
||||
)
|
||||
zephyr_library_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_DUMMY
|
||||
src/smp_dummy.c
|
||||
)
|
||||
|
|
|
@ -77,6 +77,8 @@ rsource "Kconfig.dummy"
|
|||
|
||||
rsource "Kconfig.bluetooth"
|
||||
|
||||
rsource "Kconfig.lorawan"
|
||||
|
||||
rsource "Kconfig.shell"
|
||||
|
||||
rsource "Kconfig.uart"
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#
|
||||
# Copyright (c) 2024, Jamie McCrae
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# The Kconfig file is dedicated to the LoRaWAN transport of MCUmgr
|
||||
# subsystem and provides Kconfig options to control aspects of
|
||||
# the transport.
|
||||
#
|
||||
# Options defined in this file should be prefixed:
|
||||
# MCUMGR_TRANSPORT_LORAWAN_
|
||||
|
||||
menuconfig MCUMGR_TRANSPORT_LORAWAN
|
||||
bool "LoRaWAN MCUmgr SMP transport"
|
||||
depends on LORAWAN
|
||||
help
|
||||
Enables handling of SMP commands received over LoRaWAN.
|
||||
|
||||
if MCUMGR_TRANSPORT_LORAWAN
|
||||
|
||||
config MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT
|
||||
int "LoRaWAN SMP frame port"
|
||||
range 1 223
|
||||
default 2
|
||||
help
|
||||
LoRaWAN download and uplink frame port used for communication. All messages received on
|
||||
this port will be treated as SMP packets.
|
||||
|
||||
config MCUMGR_TRANSPORT_LORAWAN_CONFIRMED_UPLINKS
|
||||
bool "Use confirmed packets for uplinks"
|
||||
default y
|
||||
help
|
||||
Will use confirmed uplink packets for responses if enabled, otherwise will use
|
||||
unconfirmed packets.
|
||||
|
||||
config MCUMGR_TRANSPORT_LORAWAN_REASSEMBLY
|
||||
bool "Reassemble LoRaWAN SMP messages"
|
||||
select MCUMGR_TRANSPORT_REASSEMBLY
|
||||
default y
|
||||
help
|
||||
Will reassemble downlink LoRaWAN messages together to allow for messages larger than a
|
||||
single message to be received, otherwise will support messages up to a single packet in
|
||||
size.
|
||||
|
||||
menuconfig MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
|
||||
bool "Send empty packet if partial packet received"
|
||||
depends on MCUMGR_TRANSPORT_LORAWAN_REASSEMBLY
|
||||
default y
|
||||
help
|
||||
Will send an empty packet if a partial (fragmented) message has been received from the
|
||||
server, this will allow the next packet to be received without waiting for next
|
||||
transmission window.
|
||||
|
||||
Note: this requires a dedicated thread in order to prevent blocking the system workqueue.
|
||||
|
||||
if MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
|
||||
|
||||
config MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_STACK_SIZE
|
||||
int "Poll thread stack size"
|
||||
default 1800
|
||||
help
|
||||
Stack size of the thread that will poll for empty additional packets when a partial
|
||||
frame is received.
|
||||
|
||||
config MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_THREAD_PRIORITY
|
||||
int "Poll thread priority"
|
||||
default 3
|
||||
help
|
||||
Priority of the thread for polling for empty additional packets when a partial frame
|
||||
is received.
|
||||
|
||||
config MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_RETRIES
|
||||
int "Poll thread retries"
|
||||
default 3
|
||||
help
|
||||
Number of LoRaWAN message send retries if sending fails for the thread for polling for
|
||||
empty additional packets when a partial frame is received.
|
||||
|
||||
endif # MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
|
||||
|
||||
config MCUMGR_TRANSPORT_LORAWAN_FRAGMENTED_UPLINKS
|
||||
bool "Fragment uplink messages"
|
||||
default y
|
||||
help
|
||||
Will fragment messages into multiple uplink messages if they are too big to fit into a
|
||||
single uplink message. If disabled then uplinks that are too large will not be sent.
|
||||
|
||||
module = MCUMGR_TRANSPORT_LORAWAN
|
||||
module-str = LoRaWAN MCUmgr SMP transport
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
endif # MCUMGR_TRANSPORT_LORAWAN
|
|
@ -0,0 +1,267 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Jamie McCrae
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/lorawan/lorawan.h>
|
||||
#include <zephyr/mgmt/mcumgr/smp/smp.h>
|
||||
#include <zephyr/mgmt/mcumgr/transport/smp.h>
|
||||
#include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
|
||||
|
||||
#include <mgmt/mcumgr/transport/smp_internal.h>
|
||||
#include <mgmt/mcumgr/transport/smp_reassembly.h>
|
||||
|
||||
LOG_MODULE_REGISTER(smp_lorawan, CONFIG_MCUMGR_TRANSPORT_LORAWAN_LOG_LEVEL);
|
||||
|
||||
static void smp_lorawan_downlink(uint8_t port, bool data_pending, int16_t rssi, int8_t snr,
|
||||
uint8_t len, const uint8_t *hex_data);
|
||||
|
||||
static int smp_lorawan_uplink(struct net_buf *nb);
|
||||
|
||||
static uint16_t smp_lorawan_get_mtu(const struct net_buf *nb);
|
||||
|
||||
static struct lorawan_downlink_cb lorawan_smp_downlink_cb = {
|
||||
.port = CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT,
|
||||
.cb = smp_lorawan_downlink,
|
||||
};
|
||||
|
||||
struct smp_transport smp_lorawan_transport = {
|
||||
.functions.output = smp_lorawan_uplink,
|
||||
.functions.get_mtu = smp_lorawan_get_mtu,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SMP_CLIENT
|
||||
struct smp_client_transport_entry smp_lorawan_client_transport = {
|
||||
.smpt = &smp_lorawan_transport,
|
||||
.smpt_type = SMP_LORAWAN_TRANSPORT,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
|
||||
static struct k_thread smp_lorawan_thread;
|
||||
K_KERNEL_STACK_MEMBER(smp_lorawan_stack, CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_STACK_SIZE);
|
||||
K_FIFO_DEFINE(smp_lorawan_fifo);
|
||||
|
||||
struct smp_lorawan_uplink_message_t {
|
||||
void *fifo_reserved;
|
||||
struct net_buf *nb;
|
||||
struct k_sem my_sem;
|
||||
};
|
||||
|
||||
static struct smp_lorawan_uplink_message_t empty_message = {
|
||||
.nb = NULL,
|
||||
};
|
||||
|
||||
static void smp_lorawan_uplink_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
struct smp_lorawan_uplink_message_t *msg;
|
||||
|
||||
while (1) {
|
||||
msg = k_fifo_get(&smp_lorawan_fifo, K_FOREVER);
|
||||
uint16_t size = 0;
|
||||
uint16_t pos = 0;
|
||||
|
||||
if (msg->nb != NULL) {
|
||||
size = msg->nb->len;
|
||||
}
|
||||
|
||||
while (pos < size || size == 0) {
|
||||
uint8_t *data = NULL;
|
||||
uint8_t data_size;
|
||||
uint8_t temp;
|
||||
uint8_t tries = CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_RETRIES;
|
||||
|
||||
lorawan_get_payload_sizes(&data_size, &temp);
|
||||
|
||||
if (data_size > size) {
|
||||
data_size = size;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
if ((data_size + pos) > size) {
|
||||
data_size = size - pos;
|
||||
}
|
||||
|
||||
data = net_buf_pull_mem(msg->nb, data_size);
|
||||
}
|
||||
|
||||
while (tries > 0) {
|
||||
int rc;
|
||||
|
||||
rc = lorawan_send(CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT,
|
||||
data, data_size,
|
||||
#if defined(CONFIG_MCUMGR_TRANSPORT_LORAWAN_CONFIRMED_UPLINKS)
|
||||
LORAWAN_MSG_CONFIRMED
|
||||
#else
|
||||
LORAWAN_MSG_UNCONFIRMED
|
||||
#endif
|
||||
);
|
||||
|
||||
if (rc != 0) {
|
||||
--tries;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
pos += data_size;
|
||||
}
|
||||
|
||||
/* For empty packets, do not trigger semaphore */
|
||||
if (size != 0) {
|
||||
k_sem_give(&msg->my_sem);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void smp_lorawan_downlink(uint8_t port, bool data_pending, int16_t rssi, int8_t snr,
|
||||
uint8_t len, const uint8_t *hex_data)
|
||||
{
|
||||
ARG_UNUSED(data_pending);
|
||||
ARG_UNUSED(rssi);
|
||||
ARG_UNUSED(snr);
|
||||
|
||||
if (port == CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT) {
|
||||
#ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_REASSEMBLY
|
||||
int rc;
|
||||
|
||||
if (len == 0) {
|
||||
/* Empty packet is used to clear partially queued data */
|
||||
(void)smp_reassembly_drop(&smp_lorawan_transport);
|
||||
} else {
|
||||
rc = smp_reassembly_collect(&smp_lorawan_transport, hex_data, len);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = smp_reassembly_complete(&smp_lorawan_transport, false);
|
||||
|
||||
if (rc) {
|
||||
LOG_ERR("LoRaWAN SMP reassembly complete failed: %d", rc);
|
||||
}
|
||||
} else if (rc < 0) {
|
||||
LOG_ERR("LoRaWAN SMP reassembly collect failed: %d", rc);
|
||||
} else {
|
||||
LOG_ERR("LoRaWAN SMP expected data left: %d", rc);
|
||||
|
||||
#ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
|
||||
/* Send empty LoRaWAN packet to receive next packet from server */
|
||||
k_fifo_put(&smp_lorawan_fifo, &empty_message);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (len > sizeof(struct smp_hdr)) {
|
||||
struct net_buf *nb;
|
||||
|
||||
nb = smp_packet_alloc();
|
||||
|
||||
if (!nb) {
|
||||
LOG_ERR("LoRaWAN SMP packet allocation failure");
|
||||
return;
|
||||
}
|
||||
|
||||
net_buf_add_mem(nb, hex_data, len);
|
||||
smp_rx_req(&smp_lorawan_transport, nb);
|
||||
} else {
|
||||
LOG_ERR("Invalid LoRaWAN SMP downlink");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
LOG_ERR("Invalid LoRaWAN SMP downlink");
|
||||
}
|
||||
}
|
||||
|
||||
static int smp_lorawan_uplink(struct net_buf *nb)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAGMENTED_UPLINKS
|
||||
struct smp_lorawan_uplink_message_t tx_data = {
|
||||
.nb = nb,
|
||||
};
|
||||
|
||||
k_sem_init(&tx_data.my_sem, 0, 1);
|
||||
k_fifo_put(&smp_lorawan_fifo, &tx_data);
|
||||
k_sem_take(&tx_data.my_sem, K_FOREVER);
|
||||
#else
|
||||
uint8_t data_size;
|
||||
uint8_t temp;
|
||||
|
||||
lorawan_get_payload_sizes(&data_size, &temp);
|
||||
|
||||
if (nb->len > data_size) {
|
||||
LOG_ERR("Cannot send LoRaWAN SMP message, too large. Message: %d, maximum: %d",
|
||||
nb->len, data_size);
|
||||
} else {
|
||||
rc = lorawan_send(CONFIG_MCUMGR_TRANSPORT_LORAWAN_FRAME_PORT, nb->data, nb->len,
|
||||
#if defined(CONFIG_MCUMGR_TRANSPORT_LORAWAN_CONFIRMED_UPLINKS)
|
||||
LORAWAN_MSG_CONFIRMED
|
||||
#else
|
||||
LORAWAN_MSG_UNCONFIRMED
|
||||
#endif
|
||||
);
|
||||
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Failed to send LoRaWAN SMP message: %d", rc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
smp_packet_free(nb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static uint16_t smp_lorawan_get_mtu(const struct net_buf *nb)
|
||||
{
|
||||
ARG_UNUSED(nb);
|
||||
|
||||
uint8_t max_data_size;
|
||||
uint8_t temp;
|
||||
|
||||
lorawan_get_payload_sizes(&max_data_size, &temp);
|
||||
|
||||
return (uint16_t)max_data_size;
|
||||
}
|
||||
|
||||
static void smp_lorawan_start(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = smp_transport_init(&smp_lorawan_transport);
|
||||
|
||||
#ifdef CONFIG_SMP_CLIENT
|
||||
if (rc == 0) {
|
||||
smp_client_transport_register(&smp_lorawan_client_transport);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rc == 0) {
|
||||
lorawan_register_downlink_callback(&lorawan_smp_downlink_cb);
|
||||
} else {
|
||||
LOG_ERR("Failed to init LoRaWAN MCUmgr SMP transport: %d", rc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_REASSEMBLY
|
||||
smp_reassembly_init(&smp_lorawan_transport);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA
|
||||
k_thread_create(&smp_lorawan_thread, smp_lorawan_stack,
|
||||
K_KERNEL_STACK_SIZEOF(smp_lorawan_stack),
|
||||
smp_lorawan_uplink_thread, NULL, NULL, NULL,
|
||||
CONFIG_MCUMGR_TRANSPORT_LORAWAN_POLL_FOR_DATA_THREAD_PRIORITY, 0,
|
||||
K_FOREVER);
|
||||
|
||||
k_thread_start(&smp_lorawan_thread);
|
||||
#endif
|
||||
}
|
||||
|
||||
MCUMGR_HANDLER_DEFINE(smp_lorawan, smp_lorawan_start);
|
Loading…
Reference in New Issue