Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subsys: lorawan: add devicetime request support #78155

Merged
merged 3 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 37 additions & 4 deletions include/zephyr/lorawan/lorawan.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ enum lorawan_message_type {
LORAWAN_MSG_CONFIRMED, /**< Confirmed message */
};

/**
* @brief LoRaWAN downlink flags.
*/
enum lorawan_dl_flags {
LORAWAN_DATA_PENDING = BIT(0),
LORAWAN_TIME_UPDATED = BIT(1),
};

/**
* @brief LoRaWAN join parameters for over-the-Air activation (OTAA)
*
Expand Down Expand Up @@ -181,15 +189,14 @@ struct lorawan_downlink_cb {
* and should therefore be as short as possible.
*
* @param port Port message was sent on
* @param data_pending Network server has more downlink packets pending
* @param flags Downlink data flags (see @ref lorawan_dl_flags)
* @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 (*cb)(uint8_t port, bool data_pending,
int16_t rssi, int8_t snr,
uint8_t len, const uint8_t *data);
void (*cb)(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len,
const uint8_t *data);
/** Node for callback list */
sys_snode_t node;
};
Expand Down Expand Up @@ -372,6 +379,32 @@ void lorawan_get_payload_sizes(uint8_t *max_next_payload_size,
*/
int lorawan_set_region(enum lorawan_region region);

/**
* @brief Request for time according to DeviceTimeReq MAC cmd
*
* Append MAC DevTimeReq command. It will be processed on next send
* message or force sending empty message to request time immediately.
*
* @param force_request Immediately send an empty message to execute the request
* @return 0 if successful, negative errno otherwise
*/
int lorawan_request_device_time(bool force_request);

/**
* @brief Retrieve the current time from LoRaWAN stack updated by
* DeviceTimeAns on MAC layer.
*
* This function uses the GPS epoch format, as used in all LoRaWAN services.
*
* The GPS epoch started on 1980-01-06T00:00:00Z, but has since diverged
* from UTC, as it does not consider corrections like leap seconds.
*
* @param gps_time Synchronized time in GPS epoch format truncated to 32-bit.
*
* @return 0 if successful, -EAGAIN if the clock is not yet synchronized.
*/
int lorawan_device_time_get(uint32_t *gps_time);

#ifdef CONFIG_LORAWAN_APP_CLOCK_SYNC

/**
Expand Down
8 changes: 4 additions & 4 deletions samples/subsys/lorawan/class_a/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ LOG_MODULE_REGISTER(lorawan_class_a);

char data[] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'};

static void dl_callback(uint8_t port, bool data_pending,
int16_t rssi, int8_t snr,
uint8_t len, const uint8_t *hex_data)
static void dl_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len,
const uint8_t *hex_data)
{
LOG_INF("Port %d, Pending %d, RSSI %ddB, SNR %ddBm", port, data_pending, rssi, snr);
LOG_INF("Port %d, Pending %d, RSSI %ddB, SNR %ddBm, Time %d", port,
flags & LORAWAN_DATA_PENDING, rssi, snr, !!(flags & LORAWAN_TIME_UPDATED));
if (hex_data) {
LOG_HEXDUMP_INF(hex_data, len, "Payload: ");
}
Expand Down
7 changes: 3 additions & 4 deletions samples/subsys/lorawan/fuota/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ LOG_MODULE_REGISTER(lorawan_fuota, CONFIG_LORAWAN_SERVICES_LOG_LEVEL);

char data[] = {'h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd'};

static void downlink_info(uint8_t port, bool data_pending, int16_t rssi, int8_t snr,
uint8_t len, const uint8_t *data)
static void downlink_info(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr, uint8_t len,
const uint8_t *data)
{
LOG_INF("Received from port %d, pending %d, RSSI %ddB, SNR %ddBm",
port, data_pending, rssi, snr);
LOG_INF("Received from port %d, flags %d, RSSI %ddB, SNR %ddBm", port, flags, rssi, snr);
if (data) {
LOG_HEXDUMP_INF(data, len, "Payload: ");
}
Expand Down
80 changes: 67 additions & 13 deletions subsys/lorawan/lorawan.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,20 @@ K_SEM_DEFINE(mcps_confirm_sem, 0, 1);
K_MUTEX_DEFINE(lorawan_join_mutex);
K_MUTEX_DEFINE(lorawan_send_mutex);

/* lorawan flags: store lorawan states */
enum {
LORAWAN_FLAG_ADR_ENABLE,
LORAWAN_FLAG_DEVICETIME_UPDATED_ONCE,
LORAWAN_FLAG_COUNT,
};

/* We store both the default datarate requested through lorawan_set_datarate
* and the current datarate so that we can use the default datarate for all
* join requests, even as the current datarate changes due to ADR.
*/
static enum lorawan_datarate default_datarate;
static enum lorawan_datarate current_datarate;
static bool lorawan_adr_enable;
static ATOMIC_DEFINE(lorawan_flags, LORAWAN_FLAG_COUNT);

static sys_slist_t dl_callbacks;

Expand Down Expand Up @@ -138,7 +145,7 @@ static void mcps_confirm_handler(McpsConfirm_t *mcps_confirm)
}

/* Datarate may have changed due to a missed ADRACK */
if (lorawan_adr_enable) {
if (atomic_test_bit(lorawan_flags, LORAWAN_FLAG_ADR_ENABLE)) {
datarate_observe(false);
}

Expand All @@ -149,6 +156,7 @@ static void mcps_confirm_handler(McpsConfirm_t *mcps_confirm)
static void mcps_indication_handler(McpsIndication_t *mcps_indication)
{
struct lorawan_downlink_cb *cb;
uint8_t flags = 0;

LOG_DBG("Received McpsIndication %d", mcps_indication->McpsIndication);

Expand All @@ -159,19 +167,26 @@ static void mcps_indication_handler(McpsIndication_t *mcps_indication)
}

/* Datarate can change as result of ADR command from server */
if (lorawan_adr_enable) {
if (atomic_test_bit(lorawan_flags, LORAWAN_FLAG_ADR_ENABLE)) {
datarate_observe(false);
}

/* Save time has been updated at least once */
if (!atomic_test_bit(lorawan_flags, LORAWAN_FLAG_DEVICETIME_UPDATED_ONCE) &&
mcps_indication->DeviceTimeAnsReceived) {
atomic_set_bit(lorawan_flags, LORAWAN_FLAG_DEVICETIME_UPDATED_ONCE);
}

/* IsUplinkTxPending also indicates pending downlinks */
flags |= (mcps_indication->IsUplinkTxPending == 1 ? LORAWAN_DATA_PENDING : 0);
flags |= (mcps_indication->DeviceTimeAnsReceived ? LORAWAN_TIME_UPDATED : 0);

/* Iterate over all registered downlink callbacks */
SYS_SLIST_FOR_EACH_CONTAINER(&dl_callbacks, cb, node) {
if ((cb->port == LW_RECV_PORT_ANY) ||
(cb->port == mcps_indication->Port)) {
cb->cb(mcps_indication->Port,
/* IsUplinkTxPending also indicates pending downlinks */
mcps_indication->IsUplinkTxPending == 1,
mcps_indication->Rssi, mcps_indication->Snr,
mcps_indication->BufferSize,
cb->cb(mcps_indication->Port, flags, mcps_indication->Rssi,
mcps_indication->Snr, mcps_indication->BufferSize,
mcps_indication->Buffer);
}
}
Expand Down Expand Up @@ -202,6 +217,9 @@ static void mlme_confirm_handler(MlmeConfirm_t *mlme_confirm)
/* Not implemented */
LOG_INF("Link check not implemented yet!");
break;
case MLME_DEVICE_TIME:
LOG_INF("DevTimeReq done");
break;
default:
break;
}
Expand Down Expand Up @@ -382,6 +400,42 @@ int lorawan_set_region(enum lorawan_region region)
return 0;
}

int lorawan_request_device_time(bool force_request)
{
int ret = 0;
LoRaMacStatus_t status;
MlmeReq_t mlme_req;

mlme_req.Type = MLME_DEVICE_TIME;
status = LoRaMacMlmeRequest(&mlme_req);
if (status != LORAMAC_STATUS_OK) {
LOG_ERR("DeviceTime Req. failed: %s", lorawan_status2str(status));
ret = lorawan_status2errno(status);
return ret;
}

if (force_request) {
ret = lorawan_send(0U, "", 0U, LORAWAN_MSG_UNCONFIRMED);
}

return ret;
}

int lorawan_device_time_get(uint32_t *gps_time)
{
SysTime_t local_time;

__ASSERT(gps_time != NULL, "gps_time parameter is required");

if (!atomic_test_bit(lorawan_flags, LORAWAN_FLAG_DEVICETIME_UPDATED_ONCE)) {
return -EAGAIN;
}

local_time = SysTimeGet();
*gps_time = local_time.Seconds - UNIX_GPS_EPOCH_OFFSET;
return 0;
}

int lorawan_join(const struct lorawan_join_config *join_cfg)
{
MibRequestConfirm_t mib_req;
Expand Down Expand Up @@ -440,7 +494,7 @@ int lorawan_join(const struct lorawan_join_config *join_cfg)
* performed when ADR is disabled as it the network servers
* responsibility to increase datarates when ADR is enabled.
*/
if (!lorawan_adr_enable) {
if (!atomic_test_bit(lorawan_flags, LORAWAN_FLAG_ADR_ENABLE)) {
MibRequestConfirm_t mib_req2;

mib_req2.Type = MIB_CHANNELS_DATARATE;
Expand Down Expand Up @@ -520,7 +574,7 @@ int lorawan_set_datarate(enum lorawan_datarate dr)
MibRequestConfirm_t mib_req;

/* Bail out if using ADR */
if (lorawan_adr_enable) {
if (atomic_test_bit(lorawan_flags, LORAWAN_FLAG_ADR_ENABLE)) {
return -EINVAL;
}

Expand Down Expand Up @@ -564,11 +618,11 @@ void lorawan_enable_adr(bool enable)
{
MibRequestConfirm_t mib_req;

if (enable != lorawan_adr_enable) {
lorawan_adr_enable = enable;
if (enable != atomic_test_bit(lorawan_flags, LORAWAN_FLAG_ADR_ENABLE)) {
atomic_set_bit_to(lorawan_flags, LORAWAN_FLAG_ADR_ENABLE, enable);

mib_req.Type = MIB_ADR;
mib_req.Param.AdrEnable = lorawan_adr_enable;
mib_req.Param.AdrEnable = atomic_test_bit(lorawan_flags, LORAWAN_FLAG_ADR_ENABLE);
LoRaMacMibSetRequestConfirm(&mib_req);
}
}
Expand Down
2 changes: 1 addition & 1 deletion subsys/lorawan/services/clock_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static inline k_timeout_t clock_sync_calc_periodicity(void)
return K_SECONDS(ctx.periodicity - 30 + sys_rand32_get() % 61);
}

static void clock_sync_package_callback(uint8_t port, bool data_pending, int16_t rssi, int8_t snr,
static void clock_sync_package_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr,
uint8_t len, const uint8_t *rx_buf)
{
uint8_t tx_buf[3 * MAX_CLOCK_SYNC_ANS_LEN];
Expand Down
4 changes: 2 additions & 2 deletions subsys/lorawan/services/frag_transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ static struct frag_transport_context ctx;
/* Callback for notification of finished firmware transfer */
static void (*finished_cb)(void);

static void frag_transport_package_callback(uint8_t port, bool data_pending, int16_t rssi,
int8_t snr, uint8_t len, const uint8_t *rx_buf)
static void frag_transport_package_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr,
uint8_t len, const uint8_t *rx_buf)
{
uint8_t tx_buf[FRAG_TRANSPORT_MAX_CMDS_PER_PACKAGE * FRAG_TRANSPORT_MAX_ANS_LEN];
uint8_t tx_pos = 0;
Expand Down
2 changes: 1 addition & 1 deletion subsys/lorawan/services/multicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ static int32_t multicast_schedule_class_c_session(uint8_t id, uint32_t session_t
return time_to_start;
}

static void multicast_package_callback(uint8_t port, bool data_pending, int16_t rssi, int8_t snr,
static void multicast_package_callback(uint8_t port, uint8_t flags, int16_t rssi, int8_t snr,
uint8_t len, const uint8_t *rx_buf)
{
uint8_t tx_buf[MAX_MULTICAST_CMDS_PER_PACKAGE * MAX_MULTICAST_ANS_LEN];
Expand Down
Loading