lorawan: add emulator for unit testing
The emulator can be used for unit testing of LoRaWAN services. It provides interfaces to send arbitrary messages to the LoRaWAN stack and receive the response through callbacks without using actual LoRa hardware. Signed-off-by: Martin Jäger <martin@libre.solar>
This commit is contained in:
parent
248bee9b17
commit
8bb9bb67db
4 changed files with 222 additions and 2 deletions
45
include/zephyr/lorawan/emul.h
Normal file
45
include/zephyr/lorawan/emul.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2024 A Labs GmbH
|
||||
* Copyright (c) 2024 tado GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_LORAWAN_EMUL_H_
|
||||
#define ZEPHYR_INCLUDE_LORAWAN_EMUL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <zephyr/lorawan/lorawan.h>
|
||||
|
||||
/**
|
||||
* @brief Defines the emulator uplink callback handler function signature.
|
||||
*
|
||||
* @param port LoRaWAN port
|
||||
* @param len Payload data length
|
||||
* @param data Pointer to the payload data
|
||||
*/
|
||||
typedef void (*lorawan_uplink_cb_t)(uint8_t port, uint8_t len, const uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief Emulate LoRaWAN downlink message
|
||||
*
|
||||
* @param port Port message was sent on
|
||||
* @param data_pending Network server has more downlink packets pending
|
||||
* @param rssi Received signal strength in dBm
|
||||
* @param snr Signal to Noise ratio in dBm
|
||||
* @param len Length of data received, will be 0 for ACKs
|
||||
* @param data Data received, will be NULL for ACKs
|
||||
*/
|
||||
void lorawan_emul_send_downlink(uint8_t port, bool data_pending, int16_t rssi, int8_t snr,
|
||||
uint8_t len, const uint8_t *data);
|
||||
|
||||
/**
|
||||
* @brief Register callback for emulated uplink messages
|
||||
*
|
||||
* @param cb Pointer to the uplink callback handler function
|
||||
*/
|
||||
void lorawan_emul_register_uplink_callback(lorawan_uplink_cb_t cb);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_LORAWAN_EMUL_H_ */
|
|
@ -20,8 +20,15 @@ zephyr_compile_definitions_ifdef(CONFIG_LORAMAC_REGION_IN865 REGION_IN865)
|
|||
zephyr_compile_definitions_ifdef(CONFIG_LORAMAC_REGION_US915 REGION_US915)
|
||||
zephyr_compile_definitions_ifdef(CONFIG_LORAMAC_REGION_RU864 REGION_RU864)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_LORAWAN lorawan.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LORAWAN lw_priv.c)
|
||||
if(CONFIG_LORAWAN)
|
||||
if(CONFIG_LORAWAN_EMUL)
|
||||
zephyr_library_sources(lorawan_emul.c)
|
||||
else()
|
||||
zephyr_library_sources(lorawan.c)
|
||||
endif()
|
||||
|
||||
zephyr_library_sources(lw_priv.c)
|
||||
endif()
|
||||
|
||||
add_subdirectory(services)
|
||||
add_subdirectory(nvm)
|
||||
|
|
|
@ -20,6 +20,16 @@ module = LORAWAN
|
|||
module-str = lorawan
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
config LORAWAN_EMUL
|
||||
bool "LoRaWAN Emulator"
|
||||
help
|
||||
The emulator can be used for unit testing of LoRaWAN services.
|
||||
It provides interfaces to send arbitrary messages to the LoRaWAN
|
||||
stack and receive the response through callbacks without using
|
||||
actual LoRa hardware.
|
||||
|
||||
See include/zephyr/lorawan/emul.h for the emulator API.
|
||||
|
||||
config LORAWAN_SYSTEM_MAX_RX_ERROR
|
||||
int "LoRaWAN System Max Rx Error"
|
||||
default 20
|
||||
|
|
158
subsys/lorawan/lorawan_emul.c
Normal file
158
subsys/lorawan/lorawan_emul.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2024 A Labs GmbH
|
||||
* Copyright (c) 2024 tado GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/lorawan/emul.h>
|
||||
#include <zephyr/lorawan/lorawan.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <LoRaMac.h>
|
||||
#include <Region.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(lorawan_emul, CONFIG_LORAWAN_LOG_LEVEL);
|
||||
|
||||
static bool lorawan_adr_enable;
|
||||
|
||||
static sys_slist_t dl_callbacks;
|
||||
|
||||
static DeviceClass_t current_class;
|
||||
|
||||
static lorawan_battery_level_cb_t battery_level_cb;
|
||||
static lorawan_dr_changed_cb_t dr_changed_cb;
|
||||
static lorawan_uplink_cb_t uplink_cb;
|
||||
|
||||
/* implementation required by the soft-se (software secure element) */
|
||||
void BoardGetUniqueId(uint8_t *id)
|
||||
{
|
||||
/* Do not change the default value */
|
||||
}
|
||||
|
||||
void lorawan_emul_send_downlink(uint8_t port, bool data_pending, int16_t rssi, int8_t snr,
|
||||
uint8_t len, const uint8_t *data)
|
||||
{
|
||||
struct lorawan_downlink_cb *cb;
|
||||
|
||||
/* Iterate over all registered downlink callbacks */
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&dl_callbacks, cb, node) {
|
||||
if ((cb->port == LW_RECV_PORT_ANY) || (cb->port == port)) {
|
||||
cb->cb(port, data_pending, rssi, snr, len, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int lorawan_join(const struct lorawan_join_config *join_cfg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lorawan_set_class(enum lorawan_class dev_class)
|
||||
{
|
||||
switch (dev_class) {
|
||||
case LORAWAN_CLASS_A:
|
||||
current_class = CLASS_A;
|
||||
break;
|
||||
case LORAWAN_CLASS_B:
|
||||
LOG_ERR("Class B not supported yet!");
|
||||
return -ENOTSUP;
|
||||
case LORAWAN_CLASS_C:
|
||||
current_class = CLASS_C;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lorawan_set_datarate(enum lorawan_datarate dr)
|
||||
{
|
||||
ARG_UNUSED(dr);
|
||||
|
||||
/* Bail out if using ADR */
|
||||
if (lorawan_adr_enable) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lorawan_get_payload_sizes(uint8_t *max_next_payload_size, uint8_t *max_payload_size)
|
||||
{
|
||||
LoRaMacTxInfo_t tx_info;
|
||||
|
||||
/* QueryTxPossible cannot fail */
|
||||
(void)LoRaMacQueryTxPossible(0, &tx_info);
|
||||
|
||||
*max_next_payload_size = tx_info.MaxPossibleApplicationDataSize;
|
||||
*max_payload_size = tx_info.CurrentPossiblePayloadSize;
|
||||
}
|
||||
|
||||
enum lorawan_datarate lorawan_get_min_datarate(void)
|
||||
{
|
||||
return LORAWAN_DR_0;
|
||||
}
|
||||
|
||||
void lorawan_enable_adr(bool enable)
|
||||
{
|
||||
lorawan_adr_enable = enable;
|
||||
}
|
||||
|
||||
int lorawan_set_conf_msg_tries(uint8_t tries)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lorawan_send(uint8_t port, uint8_t *data, uint8_t len, enum lorawan_message_type type)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uplink_cb != NULL) {
|
||||
uplink_cb(port, len, data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lorawan_register_battery_level_callback(lorawan_battery_level_cb_t cb)
|
||||
{
|
||||
battery_level_cb = cb;
|
||||
}
|
||||
|
||||
void lorawan_register_downlink_callback(struct lorawan_downlink_cb *cb)
|
||||
{
|
||||
sys_slist_append(&dl_callbacks, &cb->node);
|
||||
}
|
||||
|
||||
void lorawan_register_dr_changed_callback(lorawan_dr_changed_cb_t cb)
|
||||
{
|
||||
dr_changed_cb = cb;
|
||||
}
|
||||
|
||||
int lorawan_start(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lorawan_init(void)
|
||||
{
|
||||
sys_slist_init(&dl_callbacks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void lorawan_emul_register_uplink_callback(lorawan_uplink_cb_t cb)
|
||||
{
|
||||
uplink_cb = cb;
|
||||
}
|
||||
|
||||
SYS_INIT(lorawan_init, POST_KERNEL, 0);
|
Loading…
Add table
Add a link
Reference in a new issue