rel_1.6.0 init

This commit is contained in:
guocheng.kgc 2020-06-18 20:06:52 +08:00 committed by shengdong.dsd
commit 27b3e2883d
19359 changed files with 8093121 additions and 0 deletions

View file

@ -0,0 +1,2 @@
#lib_lorawan
This is lib_lorawan component.

View file

@ -0,0 +1,115 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2015 Semtech
Description: End device commissioning parameters
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef __LORA_COMMISSIONING_H__
#define __LORA_COMMISSIONING_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* When set to 1 the application uses the Over-the-Air activation procedure
* When set to 0 the application uses the Personalization activation procedure
*/
#define OVER_THE_AIR_ACTIVATION 1
/**
* Indicates if the end-device is to be connected to a private or public network
*/
#define LORAWAN_PUBLIC_NETWORK true
/**
* When set to 1 DevEui is LORAWAN_DEVICE_EUI
* When set to 0 DevEui is automatically generated by calling
* BoardGetUniqueId function
*/
#define STATIC_DEVICE_EUI 1
/**
* Mote device IEEE EUI (big endian)
*
* \remark see STATIC_DEVICE_EUI comments
*/
#define LORAWAN_DEVICE_EUI { 0xd8, 0x96, 0xe0, 0xff, 0x00, 0x00, 0x02, 0x2a }
/**
* Application IEEE EUI (big endian)
*/
#define LORAWAN_APPLICATION_EUI { 0xd8, 0x96, 0xe0, 0xe0, 0x00, 0x00, 0xda, 0xb0 }
/**
* AES encryption/decryption cipher application key
*/
#define LORAWAN_APPLICATION_KEY { 0xDC, 0x61, 0x6E, 0xC9, 0xC0, 0x8E, 0x10, 0xAB, 0x47, 0x61, 0x6A, 0xB0, 0x35, 0x37, 0xA7, 0x53 }
/**
* Current network ID
*/
#define LORAWAN_NETWORK_ID ( uint32_t )0
/**
* When set to 1 DevAdd is LORAWAN_DEVICE_ADDRESS
* When set to 0 DevAdd is automatically generated using
* a pseudo random generator seeded with a value derived from
* BoardUniqueId value
*/
#define STATIC_DEVICE_ADDRESS 0
/**
* Device address on the network (big endian)
*
* \remark see STATIC_DEVICE_ADDRESS comments
*/
#define LORAWAN_DEVICE_ADDRESS ( uint32_t )0x0100000a
/**
* AES encryption/decryption cipher network session key
*/
#define LORAWAN_NWKSKEY { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }
/**
* AES encryption/decryption cipher application session key
*/
#define LORAWAN_APPSKEY { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }
/**
* Multicast address
*/
#define LORAWAN_MULTICAST_ADDRESS 0x06344bf2
/**
* AES encryption/decryption cipher network session key for multicast
*/
#define LORAWAN_MULTICAST_NWKSKEY { 0x65, 0xe4, 0x48, 0x3d, 0xe3, 0xa9, 0xce, 0xb1, 0x50, 0xd8, 0x86, 0xf3, 0x61, 0x46, 0x02, 0xb5 }
/**
* AES encryption/decryption cipher application session key for multicast
*/
#define LORAWAN_MULTICAST_APPSKEY { 0xc2, 0x65, 0x67, 0xa3, 0xec, 0xd3, 0x96, 0x67, 0xd6, 0x23, 0xf8, 0x7a, 0xe1, 0x6c, 0x12, 0x23 }
#ifdef __cplusplus
}
#endif
#endif /* __LORA_COMMISSIONING_H__ */

View file

@ -0,0 +1,151 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef LINKWAN_H
#define LINKWAN_H
#include <stdbool.h>
#include <stdio.h>
#include "linkwan_config.h"
#define JOINREQ_NBTRIALS 3
typedef enum node_mode_s
{
NODE_MODE_NORMAL = 0,
NODE_MODE_REPEATER = 1, // Alibaba Node Repeater
NODE_MODE_AUTOSWITCH = 2, // switch between normal and repeater
} node_mode_t;
typedef enum node_freq_type_s
{
FREQ_TYPE_INTER = 0, // uplink and downlink use different frequencies
FREQ_TYPE_INTRA = 1, // uplink and downlink use same frequencies
FREQ_TYPE_MAX,
} node_freq_type_t;
typedef enum
{
VALID_LORA_CONFIG = 0xbeef,
INVALID_LORA_CONFIG = 0xfffe,
};
typedef struct lora_config_s
{
uint32_t freqband;
int8_t datarate;
uint16_t flag;
} lora_config_t;
typedef struct lora_dev_s
{
uint8_t dev_eui[8];
uint8_t app_eui[8];
uint8_t app_key[16];
int8_t class;
uint8_t mode; // normal or repeater
uint16_t mask;
uint16_t flag;
} lora_dev_t;
typedef enum join_method_s
{
STORED_JOIN_METHOD = 0,
DEF_JOIN_METHOD = 1,
SCAN_JOIN_METHOD = 2,
JOIN_METHOD_NUM
} join_method_t;
#ifdef CONFIG_DEBUG_LINKWAN
#include "debug.h"
#define DBG_LINKWAN(...) PRINTF(__VA_ARGS__)
#else
#define DBG_LINKWAN(...)
#define LORA_LOG(...)
#endif
typedef enum eTxEventType
{
TX_ON_TIMER,
TX_ON_EVENT,
TX_ON_NONE
} TxEventType_t;
typedef struct
{
uint8_t *Buff;
uint8_t BuffSize;
uint8_t Port;
} lora_AppData_t;
typedef struct sLoRaMainCallback
{
uint8_t (*BoardGetBatteryLevel)(void);
void (*BoardGetUniqueId)(uint8_t *id);
uint32_t (*BoardGetRandomSeed)(void);
void (*LoraTxData)(lora_AppData_t *AppData);
void (*LoraRxData)(lora_AppData_t *AppData);
} LoRaMainCallback_t;
typedef struct sLoRaParam
{
TxEventType_t TxEvent;
uint32_t TxDutyCycleTime;
bool AdrEnable;
int8_t TxDatarate;
bool EnablePublicNetwork;
uint8_t NbTrials;
} LoRaParam_t;
typedef enum eDevicState
{
DEVICE_STATE_INIT,
DEVICE_STATE_JOIN,
DEVICE_STATE_JOINED,
DEVICE_STATE_SEND,
DEVICE_STATE_SEND_MAC,
DEVICE_STATE_CYCLE,
DEVICE_STATE_SLEEP
} DeviceState_t;
bool set_lora_freqband_mask(uint16_t mask);
uint16_t get_lora_freqband_mask(void);
bool set_lora_dev_eui(uint8_t *eui);
bool set_lora_app_eui(uint8_t *eui);
bool set_lora_app_key(uint8_t *key);
node_freq_type_t get_lora_freq_type(void);
bool set_lora_tx_datarate(int8_t datarate);
int8_t get_lora_tx_datarate(void);
bool set_lora_adr(int state);
int get_lora_adr(void);
bool set_lora_class(int8_t class);
int8_t get_lora_class(void);
bool set_lora_tx_cfm_flag(int confirmed);
int get_lora_tx_cfm_flag(void);
bool set_lora_tx_cfm_trials(uint8_t trials);
uint8_t get_lora_tx_cfm_trials(void);
bool set_lora_state(DeviceState_t state);
bool set_lora_tx_dutycycle(uint32_t dutycycle);
uint32_t get_lora_tx_dutycycle(void);
bool tx_lora_data(void);
lora_AppData_t *get_lora_data(void);
void tx_lora_mac_req(void);
// for linkWAN test
bool set_lora_tx_len(uint16_t len);
uint8_t get_lora_tx_len(void);
bool send_lora_link_check(void);
#endif /* LINKWAN_H */

View file

@ -0,0 +1,31 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef LINKWAN_AT_H
#define LINKWAN_AT_H
#define LORA_AT_HELP "AT+?" // help
#define LORA_AT_RM "AT+RM" // rm stored lora info
#define LORA_AT_APPEUI "AT+APPEUI" // app eui
#define LORA_AT_APPKEY "AT+APPKEY" // app key
#define LORA_AT_DEUI "AT+DEUI" // device eui
#define LORA_AT_DR "AT+DR" // datarate
#define LORA_AT_ADR "AT+ADR" // ADR
#define LORA_AT_CLASS "AT+CLASS" // class
#define LORA_AT_SCANMASK "AT+SMASK" // scan mask
#define LORA_AT_CFM "AT+CFM" // confirmation mode
#define LORA_AT_CFMTRIALS "AT+CTRIALS" // cfm trials
#define LORA_AT_JOIN "AT+JOIN" // join network
#define LORA_AT_DCS "AT+DCS" // dutycycle
#define LORA_AT_TXSIZE "AT+TXSIZE" // tx size
#define LORA_AT_LINKCHK "AT+LINKCHK" // link check req
void linkwan_serial_input(uint8_t cmd);
int linkwan_serial_output(uint8_t *buffer, int len);
#endif

View file

@ -0,0 +1,10 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef LINKWAN_CONFIG_H
#define LORAWAN_APP_DATA_BUFF_SIZE 128
#define LINKWAN_APP_DATA_SIZE 51
#endif

View file

@ -0,0 +1,907 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "linkwan.h"
#include "commissioning.h"
#include "utilities.h"
#include "LoRaMac.h"
#include "Region.h"
#include "RegionCN470A.h"
#include "timeServer.h"
#include "radio.h"
#ifdef AOS_KV
#include <assert.h>
#include "kvmgr.h"
#endif
static uint8_t tx_buf[LORAWAN_APP_DATA_BUFF_SIZE];
static lora_AppData_t tx_data = { tx_buf, 1, 0 };
static uint8_t rx_buf[LORAWAN_APP_DATA_BUFF_SIZE];
static lora_AppData_t rx_data = { rx_buf, 0, 0 };
static uint8_t tx_size = 1;
static LoRaMacPrimitives_t LoRaMacPrimitives;
static LoRaMacCallback_t LoRaMacCallbacks;
static LoRaMainCallback_t *app_callbacks;
static MibRequestConfirm_t mibReq;
static int8_t is_tx_confirmed = ENABLE;
static bool next_tx = true;
static uint8_t num_trials = 8;
static bool rejoin_flag = true;
static uint32_t g_ack_index = 0;
static uint32_t g_msg_index = 0;
static uint8_t g_freqband_num = 0;
static LoRaParam_t lora_param = {
TX_ON_NONE, 0, true, DR_0, LORAWAN_PUBLIC_NETWORK, JOINREQ_NBTRIALS
};
static TimerEvent_t TxNextPacketTimer;
volatile static DeviceState_t device_state = DEVICE_STATE_INIT;
lora_config_t g_lora_config = { 1, DR_5, INVALID_LORA_CONFIG };
lora_dev_t g_lora_dev = { LORAWAN_DEVICE_EUI, LORAWAN_APPLICATION_EUI,
LORAWAN_APPLICATION_KEY, CLASS_A,
NODE_MODE_NORMAL, 0xffff,
VALID_LORA_CONFIG };
node_freq_type_t g_freq_type = FREQ_TYPE_INTRA;
join_method_t g_join_method;
static void start_dutycycle_timer(void);
static bool send_frame(void)
{
McpsReq_t mcpsReq;
LoRaMacTxInfo_t txInfo;
if (tx_data.BuffSize > LINKWAN_APP_DATA_SIZE) {
tx_data.BuffSize = LINKWAN_APP_DATA_SIZE;
}
if (LoRaMacQueryTxPossible(tx_data.BuffSize, &txInfo) !=
LORAMAC_STATUS_OK) {
return true;
}
if (is_tx_confirmed == DISABLE) {
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fPort = tx_data.Port;
mcpsReq.Req.Unconfirmed.fBuffer = tx_data.Buff;
mcpsReq.Req.Unconfirmed.fBufferSize = tx_data.BuffSize;
mcpsReq.Req.Unconfirmed.Datarate = lora_param.TxDatarate;
} else {
mcpsReq.Type = MCPS_CONFIRMED;
mcpsReq.Req.Confirmed.fPort = tx_data.Port;
mcpsReq.Req.Confirmed.fBuffer = tx_data.Buff;
mcpsReq.Req.Confirmed.fBufferSize = tx_data.BuffSize;
mcpsReq.Req.Confirmed.NbTrials = num_trials;
mcpsReq.Req.Confirmed.Datarate = lora_param.TxDatarate;
}
if (LoRaMacMcpsRequest(&mcpsReq) == LORAMAC_STATUS_OK) {
return false;
}
return true;
}
static void prepare_tx_frame(void)
{
if (lora_param.TxEvent == TX_ON_TIMER) {
app_callbacks->LoraTxData(&tx_data);
}
}
static void on_tx_next_packet_timer_event(void)
{
MibRequestConfirm_t mib_req;
LoRaMacStatus_t status;
TimerStop(&TxNextPacketTimer);
mib_req.Type = MIB_NETWORK_JOINED;
status = LoRaMacMibGetRequestConfirm(&mib_req);
if (status == LORAMAC_STATUS_OK) {
if (mib_req.Param.IsNetworkJoined == true) {
device_state = DEVICE_STATE_SEND;
} else {
rejoin_flag = true;
device_state = DEVICE_STATE_JOIN;
}
}
}
static void reset_join_state(void)
{
if (g_lora_config.flag == VALID_LORA_CONFIG) {
g_lora_config.flag = INVALID_LORA_CONFIG;
#ifdef AOS_KV
aos_kv_set("lora", &g_lora_config, sizeof(g_lora_config));
#endif
}
device_state = DEVICE_STATE_JOIN;
}
static void store_lora_config(void)
{
MibRequestConfirm_t mib_req;
LoRaMacStatus_t status;
uint32_t freqband;
int8_t datarate;
mib_req.Type = MIB_FREQ_BAND;
status = LoRaMacMibGetRequestConfirm(&mib_req);
if (status == LORAMAC_STATUS_OK) {
freqband = mib_req.Param.freqband;
} else {
return;
}
mib_req.Type = MIB_CHANNELS_DATARATE;
status = LoRaMacMibGetRequestConfirm(&mib_req);
if (status == LORAMAC_STATUS_OK) {
datarate = mib_req.Param.ChannelsDatarate;
} else {
return;
}
g_lora_config.freqband = freqband;
g_lora_config.datarate = datarate;
g_lora_config.flag = VALID_LORA_CONFIG;
#ifdef AOS_KV
aos_kv_set("lora", &g_lora_config, sizeof(g_lora_config));
#endif
}
static void mcps_confirm(McpsConfirm_t *mcpsConfirm)
{
if (mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK) {
switch (mcpsConfirm->McpsRequest) {
case MCPS_UNCONFIRMED: {
// Check Datarate
// Check TxPower
break;
}
case MCPS_CONFIRMED: {
// Check Datarate
// Check TxPower
// Check AckReceived
// Check NbTrials
break;
}
case MCPS_PROPRIETARY: {
break;
}
default:
break;
}
} else {
switch (mcpsConfirm->McpsRequest) {
case MCPS_UNCONFIRMED: {
// Check Datarate
// Check TxPower
break;
}
case MCPS_CONFIRMED: {
// Check Datarate
// Check TxPower
// Check AckReceived
// Check NbTrials
reset_join_state();
g_join_method = DEF_JOIN_METHOD;
DBG_LINKWAN("Not receive Ack,Start to Join...\r\n");
break;
}
case MCPS_PROPRIETARY: {
break;
}
default:
break;
}
}
next_tx = true;
}
static void McpsIndication(McpsIndication_t *mcpsIndication)
{
if (mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK) {
return;
}
switch (mcpsIndication->McpsIndication) {
case MCPS_UNCONFIRMED: {
break;
}
case MCPS_CONFIRMED: {
break;
}
case MCPS_PROPRIETARY: {
break;
}
case MCPS_MULTICAST: {
DBG_LINKWAN("MCPS_MULTICAST\n");
break;
}
default:
break;
}
// Check Multicast
// Check Port
// Check Datarate
// Check FramePending
// Check Buffer
// Check BufferSize
// Check Rssi
// Check Snr
// Check RxSlot
DBG_LINKWAN("rssi = %d, snr = %d, datarate = %d\r\n", mcpsIndication->Rssi,
mcpsIndication->Snr, mcpsIndication->RxDatarate);
if (mcpsIndication->RxData == true) {
switch (mcpsIndication->Port) {
case 224:
break;
default:
rx_data.Port = mcpsIndication->Port;
rx_data.BuffSize = mcpsIndication->BufferSize;
memcpy1(rx_data.Buff, mcpsIndication->Buffer, rx_data.BuffSize);
app_callbacks->LoraRxData(&rx_data);
break;
}
#ifdef CONFIG_DEBUG_LINKWAN
} else if (mcpsIndication->AckReceived) {
DBG_LINKWAN("rx, ACK, index %d\r\n", g_ack_index++);
#endif
}
}
static uint32_t generate_rejoin_delay(void)
{
uint32_t rejoin_delay = 0;
while (rejoin_delay < 8000) {
rejoin_delay += (Radio.Random() % 250);
}
return rejoin_delay;
}
static uint8_t get_freqband_num(void)
{
for (uint8_t i = 0; i < 16; i++) {
if ((get_lora_freqband_mask() & (1 << i)) && i != 1) {
g_freqband_num++;
}
}
}
static void MlmeConfirm(MlmeConfirm_t *mlmeConfirm)
{
uint32_t rejoin_delay;
switch (mlmeConfirm->MlmeRequest) {
case MLME_JOIN: {
if (mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK) {
// Status is OK, node has joined the network
device_state = DEVICE_STATE_JOINED;
} else {
// Join was not successful. Try to join again
reset_join_state();
if (g_join_method != SCAN_JOIN_METHOD) {
g_join_method = (g_join_method + 1) % JOIN_METHOD_NUM;
rejoin_delay = generate_rejoin_delay();
if (g_join_method == SCAN_JOIN_METHOD) {
get_freqband_num();
}
}
if (g_freqband_num == 0) {
if (g_join_method == DEF_JOIN_METHOD) {
g_join_method = (g_join_method + 1) % JOIN_METHOD_NUM;
rejoin_delay = generate_rejoin_delay();
get_freqband_num();
} else {
g_join_method = DEF_JOIN_METHOD;
rejoin_delay = 60 * 60 * 1000; // 1 hour
DBG_LINKWAN("Wait 1 hour for new round of scan\r\n");
}
} else {
g_freqband_num--;
rejoin_delay = generate_rejoin_delay();
}
TimerSetValue(&TxNextPacketTimer, rejoin_delay);
TimerStart(&TxNextPacketTimer);
rejoin_flag = false;
}
break;
}
case MLME_LINK_CHECK: {
if (mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK) {
// Check DemodMargin
// Check NbGateways
}
break;
}
default:
break;
}
next_tx = true;
}
static char *get_class_name(int8_t class)
{
if (g_lora_dev.class == CLASS_B) {
return "class_b";
} else if (g_lora_dev.class == CLASS_C) {
return "class_c";
} else {
g_lora_dev.class = CLASS_A;
return "class_a";
}
}
void lora_init(LoRaMainCallback_t *callbacks)
{
device_state = DEVICE_STATE_INIT;
app_callbacks = callbacks;
#ifdef AOS_KV
assert(aos_kv_init() == 0);
#endif
#ifdef CONFIG_LINKWAN_AT
extern void linkwan_at_init(void);
linkwan_at_init();
#endif
}
static void print_dev_addr(void)
{
#if (OVER_THE_AIR_ACTIVATION != 0)
DBG_LINKWAN("OTAA\r\n");
DBG_LINKWAN("DevEui= %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\r\n",
g_lora_dev.dev_eui[0], g_lora_dev.dev_eui[1],
g_lora_dev.dev_eui[2], g_lora_dev.dev_eui[3],
g_lora_dev.dev_eui[4], g_lora_dev.dev_eui[5],
g_lora_dev.dev_eui[6], g_lora_dev.dev_eui[7]);
DBG_LINKWAN("AppEui= %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\r\n",
g_lora_dev.app_eui[0], g_lora_dev.app_eui[1],
g_lora_dev.app_eui[2], g_lora_dev.app_eui[3],
g_lora_dev.app_eui[4], g_lora_dev.app_eui[5],
g_lora_dev.app_eui[6], g_lora_dev.app_eui[7]);
DBG_LINKWAN(
"AppKey= "
"%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%"
"02X-%02X\r\n",
g_lora_dev.app_key[0], g_lora_dev.app_key[1], g_lora_dev.app_key[2],
g_lora_dev.app_key[3], g_lora_dev.app_key[4], g_lora_dev.app_key[5],
g_lora_dev.app_key[6], g_lora_dev.app_key[7], g_lora_dev.app_key[8],
g_lora_dev.app_key[9], g_lora_dev.app_key[10], g_lora_dev.app_key[11],
g_lora_dev.app_key[12], g_lora_dev.app_key[13], g_lora_dev.app_key[14],
g_lora_dev.app_key[15]);
#else
DBG_LINKWAN("ABP\r\n");
DBG_LINKWAN("DevAdd= %08X\n\r", DevAddr);
DBG_LINKWAN("DevEui= %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\r\n",
g_lora_dev.dev_eui[0], g_lora_dev.dev_eui[1],
g_lora_dev.dev_eui[2], g_lora_dev.dev_eui[3],
g_lora_dev.dev_eui[4], g_lora_dev.dev_eui[5],
g_lora_dev.dev_eui[6], g_lora_dev.dev_eui[7]);
DBG_LINKWAN("NwkSKey= %02X", NwkSKey[0]);
for (int i = 1; i < 16; i++) {
DBG_LINKWAN(" %02X", NwkSKey[i]);
};
DBG_LINKWAN("\r\n");
DBG_LINKWAN("AppSKey= %02X", AppSKey[0]);
for (int i = 1; i < 16; i++) {
DBG_LINKWAN(" %02X", AppSKey[i]);
};
DBG_LINKWAN("\r\n");
#endif
DBG_LINKWAN("class type %s\r\n", get_class_name(g_lora_dev.class));
DBG_LINKWAN("freq type %s\r\n",
g_freq_type == FREQ_TYPE_INTER ? "inter" : "intra");
DBG_LINKWAN("scan chn mask 0x%04x\r\n", g_lora_dev.mask);
}
void lora_fsm(void)
{
#ifdef CONFIG_LINKWAN
int len = sizeof(g_lora_config);
int ret;
lora_config_t lora_config;
lora_dev_t lora_dev;
#endif
while (1) {
#ifdef CONFIG_LINKWAN_AT
extern void process_linkwan_at(void);
process_linkwan_at();
#endif
switch (device_state) {
case DEVICE_STATE_INIT: {
#ifdef AOS_KV
memset(&lora_config, 0, sizeof(lora_config));
len = sizeof(g_lora_config);
aos_kv_get("lora", &lora_config, &len);
if (lora_config.flag == VALID_LORA_CONFIG) {
memcpy(&g_lora_config, &lora_config, sizeof(g_lora_config));
}
memset(&lora_dev, 0, sizeof(lora_dev));
len = sizeof(g_lora_dev);
aos_kv_get("lora_dev", &lora_dev, &len);
if (lora_dev.flag == VALID_LORA_CONFIG) {
memcpy(&g_lora_dev, &lora_dev, sizeof(g_lora_dev));
}
#endif
if (g_lora_dev.dev_eui[5] & 0x1) {
g_freq_type = FREQ_TYPE_INTER;
}
print_dev_addr();
if (g_lora_config.flag == VALID_LORA_CONFIG) {
g_join_method = STORED_JOIN_METHOD;
} else {
g_join_method = DEF_JOIN_METHOD;
}
LoRaMacPrimitives.MacMcpsConfirm = mcps_confirm;
LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
LoRaMacCallbacks.GetBatteryLevel =
app_callbacks->BoardGetBatteryLevel;
#if defined(REGION_AS923)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_AS923);
#elif defined(REGION_AS923)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_AU915);
#elif defined(REGION_CN470)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_CN470);
#elif defined(REGION_CN779)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_CN779);
#elif defined(REGION_EU433)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_EU433);
#elif defined(REGION_IN865)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_IN865);
#elif defined(REGION_EU868)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_EU868);
#elif defined(REGION_KR920)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_KR920);
#elif defined(REGION_US915)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_US915);
#elif defined(REGION_US915_HYBRID)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_US915_HYBRID);
#elif defined(REGION_CN470A)
LoRaMacInitialization(&LoRaMacPrimitives, &LoRaMacCallbacks,
LORAMAC_REGION_CN470A);
#else
#error "Please define a region in the compiler options."
#endif
TimerInit(&TxNextPacketTimer, on_tx_next_packet_timer_event);
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = lora_param.AdrEnable;
LoRaMacMibSetRequestConfirm(&mibReq);
mibReq.Type = MIB_PUBLIC_NETWORK;
mibReq.Param.EnablePublicNetwork =
lora_param.EnablePublicNetwork;
LoRaMacMibSetRequestConfirm(&mibReq);
mibReq.Type = MIB_DEVICE_CLASS;
mibReq.Param.Class = g_lora_dev.class;
LoRaMacMibSetRequestConfirm(&mibReq);
#if defined(REGION_EU868)
lora_config_duty_cycle_set(LORAWAN_DUTYCYCLE_ON ? ENABLE
: DISABLE);
#if (USE_SEMTECH_DEFAULT_CHANNEL_LINEUP == 1)
LoRaMacChannelAdd(3, (ChannelParams_t)LC4);
LoRaMacChannelAdd(4, (ChannelParams_t)LC5);
LoRaMacChannelAdd(5, (ChannelParams_t)LC6);
LoRaMacChannelAdd(6, (ChannelParams_t)LC7);
LoRaMacChannelAdd(7, (ChannelParams_t)LC8);
LoRaMacChannelAdd(8, (ChannelParams_t)LC9);
LoRaMacChannelAdd(9, (ChannelParams_t)LC10);
mibReq.Type = MIB_RX2_DEFAULT_CHANNEL;
mibReq.Param.Rx2DefaultChannel =
(Rx2ChannelParams_t){ 869525000, DR_3 };
LoRaMacMibSetRequestConfirm(&mibReq);
mibReq.Type = MIB_RX2_CHANNEL;
mibReq.Param.Rx2Channel =
(Rx2ChannelParams_t){ 869525000, DR_3 };
LoRaMacMibSetRequestConfirm(&mibReq);
#endif
#endif
device_state = DEVICE_STATE_JOIN;
break;
}
case DEVICE_STATE_JOIN: {
#if (OVER_THE_AIR_ACTIVATION != 0)
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_JOIN;
mlmeReq.Req.Join.DevEui = g_lora_dev.dev_eui;
mlmeReq.Req.Join.AppEui = g_lora_dev.app_eui;
mlmeReq.Req.Join.AppKey = g_lora_dev.app_key;
mlmeReq.Req.Join.method = g_join_method;
if (g_join_method == STORED_JOIN_METHOD) {
mlmeReq.Req.Join.freqband = g_lora_config.freqband;
mlmeReq.Req.Join.datarate = g_lora_config.datarate;
mlmeReq.Req.Join.NbTrials = 3;
} else {
mlmeReq.Req.Join.NbTrials = 2;
}
if (next_tx == true && rejoin_flag == true) {
if (LoRaMacMlmeRequest(&mlmeReq) == LORAMAC_STATUS_OK) {
next_tx = false;
}
DBG_LINKWAN("Start to Join, method %d, nb_trials:%d\r\n",
g_join_method, mlmeReq.Req.Join.NbTrials);
}
device_state = DEVICE_STATE_SLEEP;
#else
mibReq.Type = MIB_NET_ID;
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
LoRaMacMibSetRequestConfirm(&mibReq);
mibReq.Type = MIB_DEV_ADDR;
mibReq.Param.DevAddr = DevAddr;
LoRaMacMibSetRequestConfirm(&mibReq);
mibReq.Type = MIB_NWK_SKEY;
mibReq.Param.NwkSKey = NwkSKey;
LoRaMacMibSetRequestConfirm(&mibReq);
mibReq.Type = MIB_APP_SKEY;
mibReq.Param.AppSKey = AppSKey;
LoRaMacMibSetRequestConfirm(&mibReq);
mibReq.Type = MIB_NETWORK_JOINED;
mibReq.Param.IsNetworkJoined = true;
LoRaMacMibSetRequestConfirm(&mibReq);
device_state = DEVICE_STATE_SEND;
#endif
break;
}
case DEVICE_STATE_JOINED: {
DBG_LINKWAN("Joined\n\r");
store_lora_config();
device_state = DEVICE_STATE_SEND;
break;
}
case DEVICE_STATE_SEND: {
if (next_tx == true) {
prepare_tx_frame();
next_tx = send_frame();
}
if (lora_param.TxEvent == TX_ON_TIMER) {
start_dutycycle_timer();
} else if (lora_param.TxEvent == TX_ON_EVENT) {
lora_param.TxEvent = TX_ON_NONE;
}
device_state = DEVICE_STATE_SLEEP;
break;
}
case DEVICE_STATE_SEND_MAC: {
if (next_tx == true) {
tx_data.BuffSize = 0;
next_tx = send_frame();
}
device_state = DEVICE_STATE_SLEEP;
break;
}
case DEVICE_STATE_SLEEP: {
// Wake up through events
#ifndef LOW_POWER_DISABLE
LowPower_Handler();
#endif
break;
}
default: {
device_state = DEVICE_STATE_INIT;
break;
}
}
}
}
DeviceState_t lora_getDeviceState(void)
{
return device_state;
}
node_freq_type_t get_lora_freq_type(void)
{
return g_freq_type;
}
bool set_lora_tx_datarate(int8_t datarate)
{
if (datarate >= CN470A_TX_MIN_DATARATE &&
datarate <= CN470A_TX_MAX_DATARATE && get_lora_adr() == 0) {
lora_param.TxDatarate = datarate;
return true;
} else {
return false;
}
}
int8_t get_lora_tx_datarate(void)
{
return lora_param.TxDatarate;
}
bool set_lora_adr(int state)
{
LoRaMacStatus_t status;
MibRequestConfirm_t mib_req;
bool ret = false;
if (state == 0) {
mib_req.Param.AdrEnable = false;
} else {
mib_req.Param.AdrEnable = true;
}
mib_req.Type = MIB_ADR;
status = LoRaMacMibSetRequestConfirm(&mib_req);
if (status == LORAMAC_STATUS_OK) {
ret = true;
}
return ret;
}
int get_lora_adr(void)
{
MibRequestConfirm_t mib_req;
mib_req.Type = MIB_ADR;
LoRaMacMibGetRequestConfirm(&mib_req);
if (mib_req.Param.AdrEnable == true) {
return 1;
}
return 0;
}
static void start_dutycycle_timer(void)
{
MibRequestConfirm_t mib_req;
LoRaMacStatus_t status;
TimerStop(&TxNextPacketTimer);
mib_req.Type = MIB_NETWORK_JOINED;
status = LoRaMacMibGetRequestConfirm(&mib_req);
if (status == LORAMAC_STATUS_OK) {
if (mib_req.Param.IsNetworkJoined == true &&
lora_param.TxEvent == TX_ON_TIMER &&
lora_param.TxDutyCycleTime != 0) {
TimerSetValue(&TxNextPacketTimer, lora_param.TxDutyCycleTime);
TimerStart(&TxNextPacketTimer);
return;
}
}
if (lora_param.TxDutyCycleTime == 0 && lora_param.TxEvent == TX_ON_TIMER) {
lora_param.TxEvent = TX_ON_NONE;
}
}
bool set_lora_tx_dutycycle(uint32_t dutycycle)
{
if (dutycycle != 0 && dutycycle < 1000) {
dutycycle = 1000;
}
lora_param.TxDutyCycleTime = dutycycle;
TimerStop(&TxNextPacketTimer);
if (dutycycle == 0) {
lora_param.TxEvent = TX_ON_NONE;
} else {
lora_param.TxEvent = TX_ON_TIMER;
start_dutycycle_timer();
}
return true;
}
uint32_t get_lora_tx_dutycycle(void)
{
return lora_param.TxDutyCycleTime;
}
lora_AppData_t *get_lora_data(void)
{
if (next_tx == true) {
return &tx_data;
}
return NULL;
}
bool tx_lora_data(void)
{
MibRequestConfirm_t mib_req;
LoRaMacStatus_t status;
if (next_tx == false) {
return false;
}
mib_req.Type = MIB_NETWORK_JOINED;
status = LoRaMacMibGetRequestConfirm(&mib_req);
if (status == LORAMAC_STATUS_OK) {
if (mib_req.Param.IsNetworkJoined == true) {
TimerStop(&TxNextPacketTimer);
lora_param.TxEvent = TX_ON_EVENT;
device_state = DEVICE_STATE_SEND;
return true;
}
}
return false;
}
bool set_lora_tx_cfm_flag(int confirmed)
{
is_tx_confirmed = confirmed;
return true;
}
int get_lora_tx_cfm_flag(void)
{
return is_tx_confirmed;
}
bool set_lora_tx_cfm_trials(uint8_t trials)
{
num_trials = trials;
return true;
}
uint8_t get_lora_tx_cfm_trials(void)
{
return num_trials;
}
bool set_lora_state(DeviceState_t state)
{
if (device_state == DEVICE_STATE_SLEEP) {
TimerStop(&TxNextPacketTimer);
}
device_state = state;
return true;
}
bool set_lora_class(int8_t class)
{
if (class >= CLASS_A && class <= CLASS_C) {
g_lora_dev.class = class;
g_lora_dev.flag = VALID_LORA_CONFIG;
#ifdef AOS_KV
aos_kv_set("lora_dev", &g_lora_dev, sizeof(g_lora_dev));
#endif
return true;
}
return false;
}
int8_t get_lora_class(void)
{
return g_lora_dev.class;
}
bool set_lora_dev_eui(uint8_t *eui)
{
memcpy(g_lora_dev.dev_eui, eui, 8);
g_lora_dev.flag = VALID_LORA_CONFIG;
#ifdef AOS_KV
aos_kv_set("lora_dev", &g_lora_dev, sizeof(g_lora_dev));
#endif
return true;
}
uint8_t *get_lora_dev_eui(void)
{
return g_lora_dev.dev_eui;
}
bool set_lora_app_eui(uint8_t *eui)
{
memcpy(g_lora_dev.app_eui, eui, 8);
g_lora_dev.flag = VALID_LORA_CONFIG;
#ifdef AOS_KV
aos_kv_set("lora_dev", &g_lora_dev, sizeof(g_lora_dev));
#endif
return true;
}
uint8_t *get_lora_app_eui(void)
{
return g_lora_dev.app_eui;
}
bool set_lora_app_key(uint8_t *key)
{
memcpy(g_lora_dev.app_key, key, 16);
g_lora_dev.flag = VALID_LORA_CONFIG;
#ifdef AOS_KV
aos_kv_set("lora_dev", &g_lora_dev, sizeof(g_lora_dev));
#endif
return true;
}
uint8_t *get_lora_app_key(void)
{
return g_lora_dev.app_key;
}
bool set_lora_freqband_mask(uint16_t mask)
{
g_lora_dev.mask = mask;
#ifdef AOS_KV
aos_kv_set("lora_dev", &g_lora_dev, sizeof(g_lora_dev));
#endif
return true;
}
uint16_t get_lora_freqband_mask(void)
{
return g_lora_dev.mask;
}
void tx_lora_mac_req(void)
{
if (device_state != DEVICE_STATE_SEND) {
device_state = DEVICE_STATE_SEND_MAC;
}
}
// for linkWAN test
bool set_lora_tx_len(uint16_t len)
{
if (len <= LORAWAN_APP_DATA_BUFF_SIZE) {
tx_size = len;
return true;
}
return false;
}
uint8_t get_lora_tx_len(void)
{
return tx_size;
}
bool send_lora_link_check(void)
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_LINK_CHECK;
if (next_tx == true) {
if (LoRaMacMlmeRequest(&mlmeReq) == LORAMAC_STATUS_OK) {
next_tx = false;
return true;
}
}
return false;
}

View file

@ -0,0 +1,338 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#include "LoRaMac.h"
#include "Region.h"
#include "linkwan.h"
#include "linkwan_at.h"
#define ATCMD_SIZE 64
uint8_t atcmd[ATCMD_SIZE];
uint16_t atcmd_index = 0;
static int hex2bin(const char *hex, uint8_t *bin, uint16_t bin_length)
{
uint16_t hex_length = strlen(hex);
const char *hex_end = hex + hex_length;
uint8_t *cur = bin;
uint8_t num_chars = hex_length & 1;
uint8_t byte = 0;
if ((hex_length + 1) / 2 > bin_length) {
return -1;
}
while (hex < hex_end) {
if ('A' <= *hex && *hex <= 'F') {
byte |= 10 + (*hex - 'A');
} else if ('a' <= *hex && *hex <= 'f') {
byte |= 10 + (*hex - 'a');
} else if ('0' <= *hex && *hex <= '9') {
byte |= *hex - '0';
} else {
return -1;
}
hex++;
num_chars++;
if (num_chars >= 2) {
num_chars = 0;
*cur++ = byte;
byte = 0;
} else {
byte <<= 4;
}
}
return cur - bin;
}
// this can be in intrpt context
void linkwan_serial_input(uint8_t cmd)
{
if ((cmd >= '0' && cmd <= '9') || (cmd >= 'a' && cmd <= 'z') ||
(cmd >= 'A' && cmd <= 'Z') || cmd == '?' || cmd == '+') {
atcmd[atcmd_index++] = cmd;
} else if (cmd == '\r' || cmd == '\n') {
atcmd[atcmd_index] = '\0';
}
if (atcmd_index > ATCMD_SIZE) {
atcmd_index = 0;
}
}
void process_linkwan_at(void)
{
bool ret = false;
int value;
MibRequestConfirm_t mibReq;
LoRaMacStatus_t status;
uint8_t length;
uint8_t buf[16];
if (atcmd_index == 0 || atcmd[atcmd_index] != '\0') {
return;
}
if (strncmp(atcmd, LORA_AT_HELP, strlen(LORA_AT_HELP)) == 0) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s\r\n", LORA_AT_HELP);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_RM);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_APPEUI);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_APPKEY);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_DEUI);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_DR);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_ADR);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_CLASS);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_SCANMASK);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_CFM);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_CFMTRIALS);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_JOIN);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_DCS);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_TXSIZE);
linkwan_serial_output(atcmd, strlen(atcmd));
snprintf(atcmd, ATCMD_SIZE, "%s\r\n", LORA_AT_LINKCHK);
linkwan_serial_output(atcmd, strlen(atcmd));
return;
} else if (strncmp(atcmd, LORA_AT_APPEUI, strlen(LORA_AT_APPEUI)) == 0) {
if (atcmd_index == strlen(LORA_AT_APPEUI)) {
uint8_t *eui = get_lora_app_eui();
ret = true;
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %02x%02x%02x%02x%02x%02x%02x%02x\r\n", \
LORA_AT_APPEUI, eui[0], eui[1], eui[2], eui[3], eui[4], eui[5], eui[6], eui[7]);
} else if (atcmd_index == (strlen(LORA_AT_APPEUI) + 16)) {
length = hex2bin(&atcmd[strlen(LORA_AT_APPEUI)], buf, 8);
if (length == 8) {
ret = set_lora_app_eui(buf);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %02x%02x%02x%02x%02x%02x%02x%02x\r\n", \
LORA_AT_APPEUI, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
}
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_APPEUI);
}
} else if (strncmp(atcmd, LORA_AT_APPKEY, strlen(LORA_AT_APPKEY)) == 0) {
if (atcmd_index == strlen(LORA_AT_APPKEY)) {
uint8_t *key = get_lora_app_key();
ret = true;
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", \
LORA_AT_APPKEY, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7],
key[8], key[9], key[10], key[11], key[12], key[13], key[14], key[15]);
} else if (atcmd_index == (strlen(LORA_AT_APPKEY) + 32)) {
length = hex2bin(&atcmd[strlen(LORA_AT_APPKEY)], buf, 16);
if (length == 16) {
ret = set_lora_app_key(buf);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", \
LORA_AT_APPKEY, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
}
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_APPKEY);
}
} else if (strncmp(atcmd, LORA_AT_DEUI, strlen(LORA_AT_DEUI)) == 0) {
if (atcmd_index == strlen(LORA_AT_DEUI)) {
uint8_t *eui = get_lora_dev_eui();
ret = true;
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %02x%02x%02x%02x%02x%02x%02x%02x\r\n", \
LORA_AT_DEUI, eui[0], eui[1], eui[2], eui[3], eui[4], eui[5], eui[6], eui[7]);
} else if (atcmd_index == (strlen(LORA_AT_DEUI) + 16)) {
length = hex2bin(&atcmd[strlen(LORA_AT_DEUI)], buf, 8);
if (length == 8) {
ret = set_lora_dev_eui(buf);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %02x%02x%02x%02x%02x%02x%02x%02x\r\n", \
LORA_AT_DEUI, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
}
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_DEUI);
}
} else if (strncmp(atcmd, LORA_AT_RM, strlen(LORA_AT_RM)) == 0) {
aos_kv_del("lora");
aos_kv_del("lora_dev");
ret = true;
snprintf(atcmd, ATCMD_SIZE, "\r\n%s OK\r\n", LORA_AT_RM);
} else if (strncmp(atcmd, LORA_AT_DR, strlen(LORA_AT_DR)) == 0) {
int8_t datarate;
if (atcmd_index == strlen(LORA_AT_DR)) {
ret = true;
datarate = get_lora_tx_datarate();
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_DR, datarate);
} else if (atcmd_index == (strlen(LORA_AT_DR) + 1)) {
datarate = strtol(atcmd + strlen(LORA_AT_DR), NULL, 0);
ret = set_lora_tx_datarate(datarate);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_DR, datarate);
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_DR);
}
} else if (strncmp(atcmd, LORA_AT_ADR, strlen(LORA_AT_ADR)) == 0) {
int adr;
if (atcmd_index == strlen(LORA_AT_ADR)) {
ret = true;
adr = get_lora_adr();
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_ADR, adr);
} else if (atcmd_index == (strlen(LORA_AT_ADR) + 1)) {
adr = strtol(atcmd + strlen(LORA_AT_ADR), NULL, 0);
ret = set_lora_adr(adr);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_ADR, adr);
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_ADR);
}
} else if (strncmp(atcmd, LORA_AT_CLASS, strlen(LORA_AT_CLASS)) == 0) {
int8_t class;
if (atcmd_index == strlen(LORA_AT_CLASS)) {
ret = true;
class = get_lora_class();
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_CLASS, class);
} else if (atcmd_index == (strlen(LORA_AT_CLASS) + 1)) {
class = strtol(atcmd + strlen(LORA_AT_CLASS), NULL, 0);
if (class == 0) {
ret = set_lora_class(CLASS_A);
} else if (class == 2) {
ret = set_lora_class(CLASS_C);
}
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_CLASS, class);
atcmd_index = strlen(atcmd);
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_CLASS);
}
} else if (strncmp(atcmd, LORA_AT_CFM, strlen(LORA_AT_CFM)) == 0) {
int cfm;
if (atcmd_index == strlen(LORA_AT_CFM)) {
ret = true;
cfm = get_lora_tx_cfm_flag();
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_CFM, cfm);
} else if (atcmd_index == (strlen(LORA_AT_CFM) + 1)) {
cfm = strtol(atcmd + strlen(LORA_AT_CFM), NULL, 0);
ret = set_lora_tx_cfm_flag(cfm);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_CFM, cfm);
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_CFM);
}
} else if (strncmp(atcmd, LORA_AT_CFMTRIALS, strlen(LORA_AT_CFMTRIALS)) == 0) {
uint8_t trials;
if (atcmd_index == strlen(LORA_AT_CFMTRIALS)) {
ret = true;
trials = get_lora_tx_cfm_trials();
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_CFMTRIALS, trials);
} else if (atcmd_index > strlen(LORA_AT_CFMTRIALS)) {
trials = strtol(atcmd + strlen(LORA_AT_CFMTRIALS), NULL, 0);
ret = set_lora_tx_cfm_trials(trials);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_CFMTRIALS, trials);
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_CFMTRIALS);
}
} else if (strncmp(atcmd, LORA_AT_JOIN, strlen(LORA_AT_JOIN)) == 0) {
ret = set_lora_state(DEVICE_STATE_JOIN);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s OK\r\n", LORA_AT_JOIN);
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_JOIN);
}
} else if (strncmp(atcmd, LORA_AT_DCS, strlen(LORA_AT_DCS)) == 0) {
uint32_t dutycycle;
if (atcmd_index == strlen(LORA_AT_DCS)) {
ret = true;
dutycycle = get_lora_tx_dutycycle();
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_DCS, dutycycle);
} else if (atcmd_index > strlen(LORA_AT_DCS)) {
dutycycle = strtol(atcmd + strlen(LORA_AT_DCS), NULL, 0);
ret = set_lora_tx_dutycycle(dutycycle);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_DCS, dutycycle);
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_DCS);
}
} else if (strncmp(atcmd, LORA_AT_TXSIZE, strlen(LORA_AT_TXSIZE)) == 0) {
uint8_t len;
if (atcmd_index == strlen(LORA_AT_TXSIZE)) {
ret = true;
len = get_lora_tx_len();
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_TXSIZE, len);
} else if (atcmd_index > strlen(LORA_AT_TXSIZE)) {
len = strtol(atcmd + strlen(LORA_AT_TXSIZE), NULL, 0);
ret = set_lora_tx_len(len);
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s %d\r\n", LORA_AT_TXSIZE, len);
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_TXSIZE);
}
} else if (strncmp(atcmd, LORA_AT_LINKCHK, strlen(LORA_AT_LINKCHK)) == 0) {
ret = send_lora_link_check();
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s OK\r\n", LORA_AT_LINKCHK);
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_LINKCHK);
}
} else if (strncmp(atcmd, LORA_AT_SCANMASK, strlen(LORA_AT_SCANMASK)) == 0) {
uint8_t mask[2];
int length;
if (atcmd_index == strlen(LORA_AT_SCANMASK)) {
ret = true;
snprintf(atcmd, ATCMD_SIZE, "\r\n%s 0x%04x\r\n", LORA_AT_SCANMASK, get_lora_freqband_mask());
} else if (atcmd_index > strlen(LORA_AT_SCANMASK)) {
length = hex2bin(&atcmd[strlen(LORA_AT_SCANMASK)], (uint8_t *)mask, 2);
if (length == 2) {
ret = set_lora_freqband_mask(mask[1] | (mask[0] << 8));
if (ret == true) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s 0x%04x\r\n", LORA_AT_SCANMASK, get_lora_freqband_mask());
}
}
}
if (ret == false) {
snprintf(atcmd, ATCMD_SIZE, "\r\n%s ERROR\r\n", LORA_AT_SCANMASK);
}
} else {
snprintf(atcmd, ATCMD_SIZE, "\r\nERROR\r\n");
}
exit:
linkwan_serial_output(atcmd, strlen(atcmd));
atcmd_index = 0;
memset(atcmd, 0xff, ATCMD_SIZE);
}
void linkwan_at_init(void)
{
atcmd_index = 0;
memset(atcmd, 0xff, ATCMD_SIZE);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,504 @@
/*!
* \file RegionCN470.h
*
* \brief Region definition for CN470
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONCN470 Region CN470
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef __REGION_CN470A_H__
#define __REGION_CN470A_H__
/*!
* LoRaMac maximum number of channels
*/
#define CN470A_MAX_NB_CHANNELS 16
/*!
* Number of default channels
*/
#define CN470A_NUMB_DEFAULT_CHANNELS 8
/*!
* Minimal datarate that can be used by the node
*/
#define CN470A_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define CN470A_TX_MAX_DATARATE DR_5
/*!
* Minimal datarate that can be used by the node
*/
#define CN470A_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define CN470A_RX_MAX_DATARATE DR_5
/*!
* Default datarate used by the node
*/
#define CN470A_DEFAULT_DATARATE DR_2
/*!
* Minimal Rx1 receive datarate offset
*/
#define CN470A_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define CN470A_MAX_RX1_DR_OFFSET 5
/*!
* Default Rx1 receive datarate offset
*/
#define CN470A_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define CN470A_MIN_TX_POWER TX_POWER_7
/*!
* Maximal Tx output power that can be used by the node
*/
#define CN470A_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define CN470A_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP
*/
#define CN470A_DEFAULT_MAX_EIRP 12.15f
/*!
* Default antenna gain
*/
#define CN470A_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define CN470A_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define CN470A_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define CN470A_DUTY_CYCLE_ENABLED 0//1
/*!
* Maximum RX window duration
*/
#define CN470A_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define CN470A_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define CN470A_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define CN470A_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define CN470A_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define CN470A_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define CN470A_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define CN470A_ACK_TIMEOUT_RND 1000
/*!
* Verification of default datarate
*/
#if ( CN470A_DEFAULT_DATARATE > DR_5 )
#error "A default DR higher than DR_5 may lead to connectivity loss."
#endif
/*!
* Second reception window channel frequency definition.
*/
#define CN470A_RX_WND_2_FREQ 505300000
/*!
* Second reception window channel datarate definition.
*/
#define CN470A_RX_WND_2_DR DR_0
/*!
* LoRaMac maximum number of bands
*/
#define CN470A_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define CN470A_BAND0 { 1, CN470A_MAX_TX_POWER, 0, 0 }
/*!
* LoRaMac default channel 1
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC1 { 471900000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 2
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC2 { 472100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 3
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC3 { 472300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 4
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC4 { 472500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 5
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC5 { 472700000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 6
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC6 { 472900000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 7
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC7 { 473100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 8
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN470A_LC8 { 473300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac channels which are allowed for the join procedure
*/
#define CN470A_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) | LC( 4 ) | LC( 5 ) | LC( 6 ) |LC( 7 ) | LC( 8 ) )
/*!
* Data rates table definition
*/
static const uint8_t DataratesCN470A[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
/*!
* Preamble Lenth 2.1s table definition for SF12~7
*/
static const uint16_t PreambleLenthCN470A[] = { 60, 124, 253, 509, 1022, 2047 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsCN470A[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateCN470A[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterCN470A[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionCN470AGetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionCN470ASetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionCN470AInitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionCN470AVerify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionCN470AApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionCN470AChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionCN470AAdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionCN470AComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionCN470ARxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionCN470ATxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470ALinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470ARxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470ANewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionCN470ATxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470ADlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionCN470AAlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionCN470ACalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionCN470ANextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionCN470AChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionCN470AChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionCN470ASetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionCN470AApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONCN470A */
#endif // __REGION_CN470A_H__

View file

@ -0,0 +1,25 @@
--- Revised BSD License ---
Copyright (c) 2013, SEMTECH S.A.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Semtech corporation nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,206 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC layer implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
*/
#include <stdlib.h>
#include <stdint.h>
#include "utilities.h"
#include "aes.h"
#include "cmac.h"
#include "LoRaMacCrypto.h"
/*!
* CMAC/AES Message Integrity Code (MIC) Block B0 size
*/
#define LORAMAC_MIC_BLOCK_B0_SIZE 16
/*!
* MIC field computation initial data
*/
static uint8_t MicBlockB0[] = { 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*!
* Contains the computed MIC field.
*
* \remark Only the 4 first bytes are used
*/
static uint8_t Mic[16];
/*!
* Encryption aBlock and sBlock
*/
static uint8_t aBlock[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static uint8_t sBlock[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*!
* AES computation context variable
*/
static aes_context AesContext;
/*!
* CMAC computation context variable
*/
static AES_CMAC_CTX AesCmacCtx[1];
/*!
* \brief Computes the LoRaMAC frame MIC field
*
* \param [IN] buffer Data buffer
* \param [IN] size Data buffer size
* \param [IN] key AES key to be used
* \param [IN] address Frame address
* \param [IN] dir Frame direction [0: uplink, 1: downlink]
* \param [IN] sequenceCounter Frame sequence counter
* \param [OUT] mic Computed MIC field
*/
void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic )
{
MicBlockB0[5] = dir;
MicBlockB0[6] = ( address ) & 0xFF;
MicBlockB0[7] = ( address >> 8 ) & 0xFF;
MicBlockB0[8] = ( address >> 16 ) & 0xFF;
MicBlockB0[9] = ( address >> 24 ) & 0xFF;
MicBlockB0[10] = ( sequenceCounter ) & 0xFF;
MicBlockB0[11] = ( sequenceCounter >> 8 ) & 0xFF;
MicBlockB0[12] = ( sequenceCounter >> 16 ) & 0xFF;
MicBlockB0[13] = ( sequenceCounter >> 24 ) & 0xFF;
MicBlockB0[15] = size & 0xFF;
AES_CMAC_Init( AesCmacCtx );
AES_CMAC_SetKey( AesCmacCtx, key );
AES_CMAC_Update( AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE );
AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF );
AES_CMAC_Final( Mic, AesCmacCtx );
*mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
}
void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer )
{
uint16_t i;
uint8_t bufferIndex = 0;
uint16_t ctr = 1;
memset1( AesContext.ksch, '\0', 240 );
aes_set_key( key, 16, &AesContext );
aBlock[5] = dir;
aBlock[6] = ( address ) & 0xFF;
aBlock[7] = ( address >> 8 ) & 0xFF;
aBlock[8] = ( address >> 16 ) & 0xFF;
aBlock[9] = ( address >> 24 ) & 0xFF;
aBlock[10] = ( sequenceCounter ) & 0xFF;
aBlock[11] = ( sequenceCounter >> 8 ) & 0xFF;
aBlock[12] = ( sequenceCounter >> 16 ) & 0xFF;
aBlock[13] = ( sequenceCounter >> 24 ) & 0xFF;
while( size >= 16 )
{
aBlock[15] = ( ( ctr ) & 0xFF );
ctr++;
aes_encrypt( aBlock, sBlock, &AesContext );
for( i = 0; i < 16; i++ )
{
encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
}
size -= 16;
bufferIndex += 16;
}
if( size > 0 )
{
aBlock[15] = ( ( ctr ) & 0xFF );
aes_encrypt( aBlock, sBlock, &AesContext );
for( i = 0; i < size; i++ )
{
encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
}
}
}
void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer )
{
LoRaMacPayloadEncrypt( buffer, size, key, address, dir, sequenceCounter, decBuffer );
}
void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic )
{
AES_CMAC_Init( AesCmacCtx );
AES_CMAC_SetKey( AesCmacCtx, key );
AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF );
AES_CMAC_Final( Mic, AesCmacCtx );
*mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
}
void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer )
{
memset1( AesContext.ksch, '\0', 240 );
aes_set_key( key, 16, &AesContext );
aes_encrypt( buffer, decBuffer, &AesContext );
// Check if optional CFList is included
if( size >= 16 )
{
aes_encrypt( buffer + 16, decBuffer + 16, &AesContext );
}
}
void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey )
{
uint8_t nonce[16];
uint8_t *pDevNonce = ( uint8_t * )&devNonce;
memset1( AesContext.ksch, '\0', 240 );
aes_set_key( key, 16, &AesContext );
memset1( nonce, 0, sizeof( nonce ) );
nonce[0] = 0x01;
memcpy1( nonce + 1, appNonce, 6 );
memcpy1( nonce + 7, pDevNonce, 2 );
aes_encrypt( nonce, nwkSKey, &AesContext );
memset1( nonce, 0, sizeof( nonce ) );
nonce[0] = 0x02;
memcpy1( nonce + 1, appNonce, 6 );
memcpy1( nonce + 7, pDevNonce, 2 );
aes_encrypt( nonce, appSKey, &AesContext );
}

View file

@ -0,0 +1,115 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file LoRaMacCrypto.h
*
* \brief LoRa MAC layer cryptography implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup LORAMAC_CRYPTO LoRa MAC layer cryptography implementation
* This module covers the implementation of cryptographic functions
* of the LoRaMAC layer.
* \{
*/
#ifndef __LORAMAC_CRYPTO_H__
#define __LORAMAC_CRYPTO_H__
/*!
* Computes the LoRaMAC frame MIC field
*
* \param [IN] buffer - Data buffer
* \param [IN] size - Data buffer size
* \param [IN] key - AES key to be used
* \param [IN] address - Frame address
* \param [IN] dir - Frame direction [0: uplink, 1: downlink]
* \param [IN] sequenceCounter - Frame sequence counter
* \param [OUT] mic - Computed MIC field
*/
void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic );
/*!
* Computes the LoRaMAC payload encryption
*
* \param [IN] buffer - Data buffer
* \param [IN] size - Data buffer size
* \param [IN] key - AES key to be used
* \param [IN] address - Frame address
* \param [IN] dir - Frame direction [0: uplink, 1: downlink]
* \param [IN] sequenceCounter - Frame sequence counter
* \param [OUT] encBuffer - Encrypted buffer
*/
void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer );
/*!
* Computes the LoRaMAC payload decryption
*
* \param [IN] buffer - Data buffer
* \param [IN] size - Data buffer size
* \param [IN] key - AES key to be used
* \param [IN] address - Frame address
* \param [IN] dir - Frame direction [0: uplink, 1: downlink]
* \param [IN] sequenceCounter - Frame sequence counter
* \param [OUT] decBuffer - Decrypted buffer
*/
void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer );
/*!
* Computes the LoRaMAC Join Request frame MIC field
*
* \param [IN] buffer - Data buffer
* \param [IN] size - Data buffer size
* \param [IN] key - AES key to be used
* \param [OUT] mic - Computed MIC field
*/
void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic );
/*!
* Computes the LoRaMAC join frame decryption
*
* \param [IN] buffer - Data buffer
* \param [IN] size - Data buffer size
* \param [IN] key - AES key to be used
* \param [OUT] decBuffer - Decrypted buffer
*/
void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer );
/*!
* Computes the LoRaMAC join frame decryption
*
* \param [IN] key - AES key to be used
* \param [IN] appNonce - Application nonce
* \param [IN] devNonce - Device nonce
* \param [OUT] nwkSKey - Network session key
* \param [OUT] appSKey - Application session key
*/
void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey );
/*! \} defgroup LORAMAC */
#endif // __LORAMAC_CRYPTO_H__

View file

@ -0,0 +1,85 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file LoRaMacTest.h
*
* \brief LoRa MAC layer test function implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup LORAMACTEST LoRa MAC layer test function implementation
* This module specifies the API implementation of test function of the LoRaMAC layer.
* The functions in this file are only for testing purposes only.
* \{
*/
#ifndef __LORAMACTEST_H__
#define __LORAMACTEST_H__
/*!
* \brief Enabled or disables the reception windows
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [IN] enable - Enabled or disables the reception windows
*/
void LoRaMacTestRxWindowsOn( bool enable );
/*!
* \brief Enables the MIC field test
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [IN] txPacketCounter - Fixed Tx packet counter value
*/
void LoRaMacTestSetMic( uint16_t txPacketCounter );
/*!
* \brief Enabled or disables the duty cycle
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [IN] enable - Enabled or disables the duty cycle
*/
void LoRaMacTestSetDutyCycleOn( bool enable );
/*!
* \brief Sets the channel index
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [IN] channel - Channel index
*/
void LoRaMacTestSetChannel( uint8_t channel );
/*! \} defgroup LORAMACTEST */
#endif // __LORAMACTEST_H__

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,507 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionAS923.h
*
* \brief Region definition for AS923
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONAS923 Region AS923
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_AS923_H__
#define __REGION_AS923_H__
/*!
* LoRaMac maximum number of channels
*/
#define AS923_MAX_NB_CHANNELS 16
/*!
* Number of default channels
*/
#define AS923_NUMB_DEFAULT_CHANNELS 2
/*!
* Number of channels to apply for the CF list
*/
#define AS923_NUMB_CHANNELS_CF_LIST 5
/*!
* Minimal datarate that can be used by the node
*/
#define AS923_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define AS923_TX_MAX_DATARATE DR_7
/*!
* Minimal datarate that can be used by the node
*/
#define AS923_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define AS923_RX_MAX_DATARATE DR_7
/*!
* Default datarate used by the node
*/
#define AS923_DEFAULT_DATARATE DR_2
/*!
* The minimum datarate which is used when the
* dwell time is limited.
*/
#define AS923_DWELL_LIMIT_DATARATE DR_2
/*!
* Minimal Rx1 receive datarate offset
*/
#define AS923_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define AS923_MAX_RX1_DR_OFFSET 7
/*!
* Default Rx1 receive datarate offset
*/
#define AS923_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define AS923_MIN_TX_POWER TX_POWER_7
/*!
* Maximal Tx output power that can be used by the node
*/
#define AS923_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define AS923_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default uplink dwell time configuration
*/
#define AS923_DEFAULT_UPLINK_DWELL_TIME 1
/*!
* Default downlink dwell time configuration
*/
#define AS923_DEFAULT_DOWNLINK_DWELL_TIME 1
/*!
* Default Max EIRP
*/
#define AS923_DEFAULT_MAX_EIRP 16.0f
/*!
* Default antenna gain
*/
#define AS923_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define AS923_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define AS923_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define AS923_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
*/
#define AS923_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define AS923_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define AS923_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define AS923_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define AS923_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define AS923_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define AS923_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define AS923_ACK_TIMEOUT_RND 1000
#if ( AS923_DEFAULT_DATARATE > DR_5 )
#error "A default DR higher than DR_5 may lead to connectivity loss."
#endif
/*!
* Second reception window channel frequency definition.
*/
#define AS923_RX_WND_2_FREQ 923200000
/*!
* Second reception window channel datarate definition.
*/
#define AS923_RX_WND_2_DR DR_2
/*!
* Maximum number of bands
*/
#define AS923_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define AS923_BAND0 { 100, AS923_MAX_TX_POWER, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define AS923_LC1 { 923200000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 2
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define AS923_LC2 { 923400000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac channels which are allowed for the join procedure
*/
#define AS923_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) )
/*!
* RSSI threshold for a free channel [dBm]
*/
#define AS923_RSSI_FREE_TH -85
/*!
* Specifies the time the node performs a carrier sense
*/
#define AS923_CARRIER_SENSE_TIME 6
/*!
* Data rates table definition
*/
static const uint8_t DataratesAS923[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsAS923[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
* The table is valid for the dwell time configuration of 0 for uplinks and downlinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell0AS923[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
* The table is valid for the dwell time configuration of 0 for uplinks and downlinks. The table provides
* repeater support.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterDwell0AS923[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
/*!
* Maximum payload with respect to the datarate index. Can operate with and without repeater.
* The table proides repeater support. The table is only valid for uplinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell1UpAS923[] = { 0, 0, 11, 53, 125, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with and without repeater.
* The table proides repeater support. The table is only valid for downlinks.
*/
static const uint8_t MaxPayloadOfDatarateDwell1DownAS923[] = { 0, 0, 11, 53, 126, 242, 242, 242 };
/*!
* Effective datarate offsets for receive window 1.
*/
static const int8_t EffectiveRx1DrOffsetAS923[] = { 0, 1, 2, 3, 4, 5, -1, -2 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionAS923GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionAS923SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionAS923InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionAS923Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionAS923ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionAS923ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionAS923AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionAS923ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionAS923RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionAS923TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAS923LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAS923RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAS923NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionAS923TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAS923DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionAS923AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionAS923CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionAS923NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionAS923ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionAS923ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionAS923SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionAS923ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONAS923 */
#endif // __REGION_AS923_H__

View file

@ -0,0 +1,868 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC region AU915 implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
*/
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include "radio.h"
//#include "timer.h"
#include "timeServer.h"
#include "LoRaMac.h"
#include "utilities.h"
#include "Region.h"
#include "RegionCommon.h"
#include "RegionAU915.h"
#include "debug.h"
// Definitions
#define CHANNELS_MASK_SIZE 6
// Global attributes
/*!
* LoRaMAC channels
*/
static ChannelParams_t Channels[AU915_MAX_NB_CHANNELS];
/*!
* LoRaMac bands
*/
static Band_t Bands[AU915_MAX_NB_BANDS] =
{
AU915_BAND0
};
/*!
* LoRaMac channels mask
*/
static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
/*!
* LoRaMac channels remaining
*/
static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE];
/*!
* LoRaMac channels default mask
*/
static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
// Static functions
static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
{
uint8_t nextLowerDr = 0;
if( dr == minDr )
{
nextLowerDr = minDr;
}
else
{
nextLowerDr = dr - 1;
}
return nextLowerDr;
}
static uint32_t GetBandwidth( uint32_t drIndex )
{
switch( BandwidthsAU915[drIndex] )
{
default:
case 125000:
return 0;
case 250000:
return 1;
case 500000:
return 2;
}
}
static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
{
int8_t txPowerResult = txPower;
// Limit tx power to the band max
txPowerResult = MAX( txPower, maxBandTxPower );
return txPowerResult;
}
static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTransmission = 0;
for( uint8_t i = 0, k = 0; i < AU915_MAX_NB_CHANNELS; i += 16, k++ )
{
for( uint8_t j = 0; j < 16; j++ )
{
if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
{
if( channels[i + j].Frequency == 0 )
{ // Check if the channel is enabled
continue;
}
if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
channels[i + j].DrRange.Fields.Max ) == false )
{ // Check if the current channel selection supports the given datarate
continue;
}
if( bands[channels[i + j].Band].TimeOff > 0 )
{ // Check if the band is available for transmission
delayTransmission++;
continue;
}
enabledChannels[nbEnabledChannels++] = i + j;
}
}
}
*delayTx = delayTransmission;
return nbEnabledChannels;
}
PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy )
{
PhyParam_t phyParam = { 0 };
switch( getPhy->Attribute )
{
case PHY_MIN_RX_DR:
{
phyParam.Value = AU915_RX_MIN_DATARATE;
break;
}
case PHY_MIN_TX_DR:
{
phyParam.Value = AU915_TX_MIN_DATARATE;
break;
}
case PHY_DEF_TX_DR:
{
phyParam.Value = AU915_DEFAULT_DATARATE;
break;
}
case PHY_NEXT_LOWER_TX_DR:
{
phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, AU915_TX_MIN_DATARATE );
break;
}
case PHY_DEF_TX_POWER:
{
phyParam.Value = AU915_DEFAULT_TX_POWER;
break;
}
case PHY_MAX_PAYLOAD:
{
phyParam.Value = MaxPayloadOfDatarateAU915[getPhy->Datarate];
break;
}
case PHY_MAX_PAYLOAD_REPEATER:
{
phyParam.Value = MaxPayloadOfDatarateRepeaterAU915[getPhy->Datarate];
break;
}
case PHY_DUTY_CYCLE:
{
phyParam.Value = AU915_DUTY_CYCLE_ENABLED;
break;
}
case PHY_MAX_RX_WINDOW:
{
phyParam.Value = AU915_MAX_RX_WINDOW;
break;
}
case PHY_RECEIVE_DELAY1:
{
phyParam.Value = AU915_RECEIVE_DELAY1;
break;
}
case PHY_RECEIVE_DELAY2:
{
phyParam.Value = AU915_RECEIVE_DELAY2;
break;
}
case PHY_JOIN_ACCEPT_DELAY1:
{
phyParam.Value = AU915_JOIN_ACCEPT_DELAY1;
break;
}
case PHY_JOIN_ACCEPT_DELAY2:
{
phyParam.Value = AU915_JOIN_ACCEPT_DELAY2;
break;
}
case PHY_MAX_FCNT_GAP:
{
phyParam.Value = AU915_MAX_FCNT_GAP;
break;
}
case PHY_ACK_TIMEOUT:
{
phyParam.Value = ( AU915_ACKTIMEOUT + randr( -AU915_ACK_TIMEOUT_RND, AU915_ACK_TIMEOUT_RND ) );
break;
}
case PHY_DEF_DR1_OFFSET:
{
phyParam.Value = AU915_DEFAULT_RX1_DR_OFFSET;
break;
}
case PHY_DEF_RX2_FREQUENCY:
{
phyParam.Value = AU915_RX_WND_2_FREQ;
break;
}
case PHY_DEF_RX2_DR:
{
phyParam.Value = AU915_RX_WND_2_DR;
break;
}
case PHY_CHANNELS_MASK:
{
phyParam.ChannelsMask = ChannelsMask;
break;
}
case PHY_CHANNELS_DEFAULT_MASK:
{
phyParam.ChannelsMask = ChannelsDefaultMask;
break;
}
case PHY_MAX_NB_CHANNELS:
{
phyParam.Value = AU915_MAX_NB_CHANNELS;
break;
}
case PHY_CHANNELS:
{
phyParam.Channels = Channels;
break;
}
case PHY_DEF_UPLINK_DWELL_TIME:
case PHY_DEF_DOWNLINK_DWELL_TIME:
{
phyParam.Value = 0;
break;
}
case PHY_DEF_MAX_EIRP:
{
phyParam.fValue = AU915_DEFAULT_MAX_EIRP;
break;
}
case PHY_DEF_ANTENNA_GAIN:
{
phyParam.fValue = AU915_DEFAULT_ANTENNA_GAIN;
break;
}
case PHY_NB_JOIN_TRIALS:
case PHY_DEF_NB_JOIN_TRIALS:
{
phyParam.Value = 2;
break;
}
default:
{
break;
}
}
return phyParam;
}
void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
}
void RegionAU915InitDefaults( InitType_t type )
{
switch( type )
{
case INIT_TYPE_INIT:
{
// Channels
// 125 kHz channels
for( uint8_t i = 0; i < AU915_MAX_NB_CHANNELS - 8; i++ )
{
Channels[i].Frequency = 915200000 + i * 200000;
Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0;
Channels[i].Band = 0;
}
// 500 kHz channels
for( uint8_t i = AU915_MAX_NB_CHANNELS - 8; i < AU915_MAX_NB_CHANNELS; i++ )
{
Channels[i].Frequency = 915900000 + ( i - ( AU915_MAX_NB_CHANNELS - 8 ) ) * 1600000;
Channels[i].DrRange.Value = ( DR_6 << 4 ) | DR_6;
Channels[i].Band = 0;
}
// Initialize channels default mask
ChannelsDefaultMask[0] = 0xFFFF;
ChannelsDefaultMask[1] = 0xFFFF;
ChannelsDefaultMask[2] = 0xFFFF;
ChannelsDefaultMask[3] = 0xFFFF;
ChannelsDefaultMask[4] = 0x00FF;
ChannelsDefaultMask[5] = 0x0000;
// Copy channels default mask
RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
// Copy into channels mask remaining
RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 6 );
break;
}
case INIT_TYPE_RESTORE:
{
// Copy channels default mask
RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
for( uint8_t i = 0; i < 6; i++ )
{ // Copy-And the channels mask
ChannelsMaskRemaining[i] &= ChannelsMask[i];
}
break;
}
default:
{
break;
}
}
}
bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
case PHY_TX_DR:
case PHY_DEF_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_TX_MIN_DATARATE, AU915_TX_MAX_DATARATE );
}
case PHY_RX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE );
}
case PHY_DEF_TX_POWER:
case PHY_TX_POWER:
{
// Remark: switched min and max!
return RegionCommonValueInRange( verify->TxPower, AU915_MAX_TX_POWER, AU915_MIN_TX_POWER );
}
case PHY_DUTY_CYCLE:
{
return AU915_DUTY_CYCLE_ENABLED;
}
case PHY_NB_JOIN_TRIALS:
{
if( verify->NbJoinTrials < 2 )
{
return false;
}
break;
}
default:
return false;
}
return true;
}
void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList )
{
return;
}
bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
{
uint8_t nbChannels = RegionCommonCountChannels( chanMaskSet->ChannelsMaskIn, 0, 4 );
// Check the number of active channels
// According to ACMA regulation, we require at least 20 125KHz channels, if
// the node shall utilize 125KHz channels.
if( ( nbChannels < 20 ) &&
( nbChannels > 0 ) )
{
return false;
}
switch( chanMaskSet->ChannelsMaskType )
{
case CHANNELS_MASK:
{
RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 6 );
for( uint8_t i = 0; i < 6; i++ )
{ // Copy-And the channels mask
ChannelsMaskRemaining[i] &= ChannelsMask[i];
}
break;
}
case CHANNELS_DEFAULT_MASK:
{
RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6 );
break;
}
default:
return false;
}
return true;
}
bool RegionAU915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
{
bool adrAckReq = false;
int8_t datarate = adrNext->Datarate;
int8_t txPower = adrNext->TxPower;
GetPhyParams_t getPhy;
PhyParam_t phyParam;
// Report back the adr ack counter
*adrAckCounter = adrNext->AdrAckCounter;
if( adrNext->AdrEnabled == true )
{
if( datarate == AU915_TX_MIN_DATARATE )
{
*adrAckCounter = 0;
adrAckReq = false;
}
else
{
if( adrNext->AdrAckCounter >= AU915_ADR_ACK_LIMIT )
{
adrAckReq = true;
txPower = AU915_MAX_TX_POWER;
}
else
{
adrAckReq = false;
}
if( adrNext->AdrAckCounter >= ( AU915_ADR_ACK_LIMIT + AU915_ADR_ACK_DELAY ) )
{
if( ( adrNext->AdrAckCounter % AU915_ADR_ACK_DELAY ) == 1 )
{
// Decrease the datarate
getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
getPhy.Datarate = datarate;
getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
phyParam = RegionAU915GetPhyParam( &getPhy );
datarate = phyParam.Value;
if( datarate == AU915_TX_MIN_DATARATE )
{
// We must set adrAckReq to false as soon as we reach the lowest datarate
adrAckReq = false;
if( adrNext->UpdateChanMask == true )
{
// Re-enable default channels
ChannelsMask[0] = 0xFFFF;
ChannelsMask[1] = 0xFFFF;
ChannelsMask[2] = 0xFFFF;
ChannelsMask[3] = 0xFFFF;
ChannelsMask[4] = 0x00FF;
ChannelsMask[5] = 0x0000;
}
}
}
}
}
}
*drOut = datarate;
*txPowOut = txPower;
return adrAckReq;
}
void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
{
double tSymbol = 0.0;
uint32_t radioWakeUpTime;
rxConfigParams->Datarate = datarate;
rxConfigParams->Bandwidth = GetBandwidth( datarate );
if( datarate == DR_7 )
{ // FSK
tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesAU915[datarate] );
}
else
{ // LoRa
tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesAU915[datarate], BandwidthsAU915[datarate] );
}
radioWakeUpTime = Radio.GetRadioWakeUpTime( );
RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, radioWakeUpTime, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
}
bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
if( Radio.GetStatus( ) != RF_IDLE )
{
return false;
}
if( rxConfig->Window == 0 )
{
// Apply window 1 frequency
frequency = AU915_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 8 ) * AU915_STEPWIDTH_RX1_CHANNEL;
}
// Read the physical datarate from the datarates table
phyDr = DataratesAU915[dr];
Radio.SetChannel( frequency );
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
if( rxConfig->RepeaterSupport == true )
{
maxPayload = MaxPayloadOfDatarateRepeaterAU915[dr];
}
else
{
maxPayload = MaxPayloadOfDatarateAU915[dr];
}
Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
DBG_PRINTF("RX on freq %d Hz at DR %d\n\r", frequency, dr);
*datarate = (uint8_t) dr;
return true;
}
bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
{
int8_t phyDr = DataratesAU915[txConfig->Datarate];
int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
int8_t phyTxPower = 0;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
Radio.SetChannel( Channels[txConfig->Channel].Frequency );
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3e3 );
DBG_PRINTF("TX on freq %d Hz at DR %d\n\r", Channels[txConfig->Channel].Frequency, txConfig->Datarate);
*txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
}
uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
{
uint8_t status = 0x07;
LinkAdrParams_t linkAdrParams;
uint8_t nextIndex = 0;
uint8_t bytesProcessed = 0;
uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
// Initialize local copy of channels mask
RegionCommonChanMaskCopy( channelsMask, ChannelsMask, 6 );
while( bytesProcessed < linkAdrReq->PayloadSize )
{
nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
if( nextIndex == 0 )
break; // break loop, since no more request has been found
// Update bytes processed
bytesProcessed += nextIndex;
// Revert status, as we only check the last ADR request for the channel mask KO
status = 0x07;
if( linkAdrParams.ChMaskCtrl == 6 )
{
// Enable all 125 kHz channels
channelsMask[0] = 0xFFFF;
channelsMask[1] = 0xFFFF;
channelsMask[2] = 0xFFFF;
channelsMask[3] = 0xFFFF;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask;
}
else if( linkAdrParams.ChMaskCtrl == 7 )
{
// Disable all 125 kHz channels
channelsMask[0] = 0x0000;
channelsMask[1] = 0x0000;
channelsMask[2] = 0x0000;
channelsMask[3] = 0x0000;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask;
}
else if( linkAdrParams.ChMaskCtrl == 5 )
{
// RFU
status &= 0xFE; // Channel mask KO
}
else
{
channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
}
}
// FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
if( ( linkAdrParams.Datarate < DR_4 ) && ( RegionCommonCountChannels( channelsMask, 0, 4 ) < 2 ) )
{
status &= 0xFE; // Channel mask KO
}
// Verify datarate
if( RegionCommonChanVerifyDr( AU915_MAX_NB_CHANNELS, channelsMask, linkAdrParams.Datarate, AU915_TX_MIN_DATARATE, AU915_TX_MAX_DATARATE, Channels ) == false )
{
status &= 0xFD; // Datarate KO
}
// Verify tx power
if( RegionCommonValueInRange( linkAdrParams.TxPower, AU915_MAX_TX_POWER, AU915_MIN_TX_POWER ) == 0 )
{
// Verify if the maximum TX power is exceeded
if( AU915_MAX_TX_POWER > linkAdrParams.TxPower )
{ // Apply maximum TX power. Accept TX power.
linkAdrParams.TxPower = AU915_MAX_TX_POWER;
}
else
{
status &= 0xFB; // TxPower KO
}
}
// Update channelsMask if everything is correct
if( status == 0x07 )
{
if( linkAdrParams.NbRep == 0 )
{ // Value of 0 is not allowed, revert to default.
linkAdrParams.NbRep = 1;
}
// Copy Mask
RegionCommonChanMaskCopy( ChannelsMask, channelsMask, 6 );
ChannelsMaskRemaining[0] &= ChannelsMask[0];
ChannelsMaskRemaining[1] &= ChannelsMask[1];
ChannelsMaskRemaining[2] &= ChannelsMask[2];
ChannelsMaskRemaining[3] &= ChannelsMask[3];
ChannelsMaskRemaining[4] = ChannelsMask[4];
ChannelsMaskRemaining[5] = ChannelsMask[5];
}
// Update status variables
*drOut = linkAdrParams.Datarate;
*txPowOut = linkAdrParams.TxPower;
*nbRepOut = linkAdrParams.NbRep;
*nbBytesParsed = bytesProcessed;
return status;
}
uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
{
uint8_t status = 0x07;
uint32_t freq = rxParamSetupReq->Frequency;
// Verify radio frequency
if( ( Radio.CheckRfFrequency( freq ) == false ) ||
( freq < AU915_FIRST_RX1_CHANNEL ) ||
( freq > AU915_LAST_RX1_CHANNEL ) ||
( ( ( freq - ( uint32_t ) AU915_FIRST_RX1_CHANNEL ) % ( uint32_t ) AU915_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
{
status &= 0xFE; // Channel frequency KO
}
// Verify datarate
if( RegionCommonValueInRange( rxParamSetupReq->Datarate, AU915_RX_MIN_DATARATE, AU915_RX_MAX_DATARATE ) == false )
{
status &= 0xFD; // Datarate KO
}
if( ( RegionCommonValueInRange( rxParamSetupReq->Datarate, DR_5, DR_7 ) == true ) ||
( rxParamSetupReq->Datarate > DR_13 ) )
{
status &= 0xFD; // Datarate KO
}
// Verify datarate offset
if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, AU915_MIN_RX1_DR_OFFSET, AU915_MAX_RX1_DR_OFFSET ) == false )
{
status &= 0xFB; // Rx1DrOffset range KO
}
return status;
}
uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq )
{
// Datarate and frequency KO
return 0;
}
int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
{
return -1;
}
uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq )
{
return 0;
}
int8_t RegionAU915AlternateDr( AlternateDrParams_t* alternateDr )
{
int8_t datarate = 0;
// Re-enable 500 kHz default channels
ChannelsMask[4] = 0x00FF;
if( ( alternateDr->NbTrials & 0x01 ) == 0x01 )
{
datarate = DR_4;
}
else
{
datarate = DR_0;
}
return datarate;
}
void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff )
{
uint8_t channel = calcBackOff->Channel;
uint16_t joinDutyCycle = 0;
if( calcBackOff->Joined == false )
{
// Get the join duty cycle
joinDutyCycle = RegionCommonGetJoinDc( calcBackOff->ElapsedTime );
// Apply band time-off.
Bands[Channels[channel].Band].TimeOff = calcBackOff->TxTimeOnAir * joinDutyCycle - calcBackOff->TxTimeOnAir;
}
else
{
Bands[Channels[channel].Band].TimeOff = 0;
}
}
bool RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTx = 0;
uint8_t enabledChannels[AU915_MAX_NB_CHANNELS] = { 0 };
TimerTime_t nextTxDelay = 0;
// Count 125kHz channels
if( RegionCommonCountChannels( ChannelsMaskRemaining, 0, 4 ) == 0 )
{ // Reactivate default channels
RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 4 );
}
// Check other channels
if( nextChanParams->Datarate >= DR_4 )
{
if( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 )
{
ChannelsMaskRemaining[4] = ChannelsMask[4];
}
}
if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
{
// Reset Aggregated time off
*aggregatedTimeOff = 0;
// Search how many channels are enabled
nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
ChannelsMaskRemaining, Channels,
Bands, enabledChannels, &delayTx );
}
else
{
delayTx++;
nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
}
if( nbEnabledChannels > 0 )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
// Disable the channel in the mask
RegionCommonChanDisable( ChannelsMaskRemaining, *channel, AU915_MAX_NB_CHANNELS - 8 );
*time = 0;
return true;
}
else
{
if( delayTx > 0 )
{
// Delay transmission due to AggregatedTimeOff or to a band time off
*time = nextTxDelay;
return true;
}
// Datarate not supported by any channel
*time = 0;
return false;
}
}
LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave )
{
int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
int8_t phyTxPower = 0;
uint32_t frequency = Channels[continuousWave->Channel].Frequency;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
}
uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
{
int8_t datarate = DatarateOffsetsAU915[dr][drOffset];
if( datarate < 0 )
{
datarate = DR_0;
}
return datarate;
}

View file

@ -0,0 +1,459 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionAU915.h
*
* \brief Region definition for AU915
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONAU915 Region AU915
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_AU915_H__
#define __REGION_AU915_H__
/*!
* LoRaMac maximum number of channels
*/
#define AU915_MAX_NB_CHANNELS 72
/*!
* Minimal datarate that can be used by the node
*/
#define AU915_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define AU915_TX_MAX_DATARATE DR_6
/*!
* Minimal datarate that can be used by the node
*/
#define AU915_RX_MIN_DATARATE DR_8
/*!
* Maximal datarate that can be used by the node
*/
#define AU915_RX_MAX_DATARATE DR_13
/*!
* Default datarate used by the node
*/
#define AU915_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define AU915_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define AU915_MAX_RX1_DR_OFFSET 6
/*!
* Default Rx1 receive datarate offset
*/
#define AU915_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define AU915_MIN_TX_POWER TX_POWER_10
/*!
* Maximal Tx output power that can be used by the node
*/
#define AU915_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define AU915_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP
*/
#define AU915_DEFAULT_MAX_EIRP 30.0f
/*!
* Default antenna gain
*/
#define AU915_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define AU915_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define AU915_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define AU915_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
*/
#define AU915_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define AU915_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define AU915_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define AU915_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define AU915_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define AU915_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define AU915_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define AU915_ACK_TIMEOUT_RND 1000
/*!
* Second reception window channel frequency definition.
*/
#define AU915_RX_WND_2_FREQ 923300000
/*!
* Second reception window channel datarate definition.
*/
#define AU915_RX_WND_2_DR DR_8
/*!
* LoRaMac maximum number of bands
*/
#define AU915_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define AU915_BAND0 { 1, AU915_MAX_TX_POWER, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for US band
*/
#define AU915_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 )
/*!
* Defines the last channel for RX window 1 for US band
*/
#define AU915_LAST_RX1_CHANNEL ( (uint32_t) 927500000 )
/*!
* Defines the step width of the channels for RX window 1
*/
#define AU915_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 )
/*!
* Data rates table definition
*/
static const uint8_t DataratesAU915[] = { 12, 11, 10, 9, 8, 7, 8, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsAU915[] = { 125000, 125000, 125000, 125000, 125000, 125000, 500000, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 };
/*!
* Up/Down link data rates offset definition
*/
static const int8_t DatarateOffsetsAU915[7][6] =
{
{ DR_8 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_0
{ DR_9 , DR_8 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_1
{ DR_10, DR_9 , DR_8 , DR_8 , DR_8 , DR_8 }, // DR_2
{ DR_11, DR_10, DR_9 , DR_8 , DR_8 , DR_8 }, // DR_3
{ DR_12, DR_11, DR_10, DR_9 , DR_8 , DR_8 }, // DR_4
{ DR_13, DR_12, DR_11, DR_10, DR_9 , DR_8 }, // DR_5
{ DR_13, DR_13, DR_12, DR_11, DR_10, DR_9 }, // DR_6
};
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateAU915[] = { 51, 51, 51, 115, 242, 242, 242, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterAU915[] = { 51, 51, 51, 115, 222, 222, 222, 0, 33, 109, 222, 222, 222, 222, 0, 0 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionAU915GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionAU915SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionAU915InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionAU915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionAU915ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionAU915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionAU915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionAU915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionAU915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionAU915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionAU915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionAU915DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionAU915AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionAU915CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionAU915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionAU915ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionAU915ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionAU915SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionAU915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONAU915 */
#endif // __REGION_AU915_H__

View file

@ -0,0 +1,816 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC region CN470 implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
*/
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include "radio.h"
//#include "timer.h"
#include "timeServer.h"
#include "LoRaMac.h"
#include "utilities.h"
#include "Region.h"
#include "RegionCommon.h"
#include "RegionCN470.h"
#include "debug.h"
// Definitions
#define CHANNELS_MASK_SIZE 6
// Global attributes
/*!
* LoRaMAC channels
*/
static ChannelParams_t Channels[CN470_MAX_NB_CHANNELS];
/*!
* LoRaMac bands
*/
static Band_t Bands[CN470_MAX_NB_BANDS] =
{
CN470_BAND0
};
/*!
* LoRaMac channels mask
*/
static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
/*!
* LoRaMac channels default mask
*/
static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
// Static functions
static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
{
uint8_t nextLowerDr = 0;
if( dr == minDr )
{
nextLowerDr = minDr;
}
else
{
nextLowerDr = dr - 1;
}
return nextLowerDr;
}
static uint32_t GetBandwidth( uint32_t drIndex )
{
switch( BandwidthsCN470[drIndex] )
{
default:
case 125000:
return 0;
case 250000:
return 1;
case 500000:
return 2;
}
}
static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
{
int8_t txPowerResult = txPower;
// Limit tx power to the band max
txPowerResult = MAX( txPower, maxBandTxPower );
return txPowerResult;
}
static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTransmission = 0;
for( uint8_t i = 0, k = 0; i < CN470_MAX_NB_CHANNELS; i += 16, k++ )
{
for( uint8_t j = 0; j < 16; j++ )
{
if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
{
if( channels[i + j].Frequency == 0 )
{ // Check if the channel is enabled
continue;
}
if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
channels[i + j].DrRange.Fields.Max ) == false )
{ // Check if the current channel selection supports the given datarate
continue;
}
if( bands[channels[i + j].Band].TimeOff > 0 )
{ // Check if the band is available for transmission
delayTransmission++;
continue;
}
enabledChannels[nbEnabledChannels++] = i + j;
}
}
}
*delayTx = delayTransmission;
return nbEnabledChannels;
}
PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy )
{
PhyParam_t phyParam = { 0 };
switch( getPhy->Attribute )
{
case PHY_MIN_RX_DR:
{
phyParam.Value = CN470_RX_MIN_DATARATE;
break;
}
case PHY_MIN_TX_DR:
{
phyParam.Value = CN470_TX_MIN_DATARATE;
break;
}
case PHY_DEF_TX_DR:
{
phyParam.Value = CN470_DEFAULT_DATARATE;
break;
}
case PHY_NEXT_LOWER_TX_DR:
{
phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, CN470_TX_MIN_DATARATE );
break;
}
case PHY_DEF_TX_POWER:
{
phyParam.Value = CN470_DEFAULT_TX_POWER;
break;
}
case PHY_MAX_PAYLOAD:
{
phyParam.Value = MaxPayloadOfDatarateCN470[getPhy->Datarate];
break;
}
case PHY_MAX_PAYLOAD_REPEATER:
{
phyParam.Value = MaxPayloadOfDatarateRepeaterCN470[getPhy->Datarate];
break;
}
case PHY_DUTY_CYCLE:
{
phyParam.Value = CN470_DUTY_CYCLE_ENABLED;
break;
}
case PHY_MAX_RX_WINDOW:
{
phyParam.Value = CN470_MAX_RX_WINDOW;
break;
}
case PHY_RECEIVE_DELAY1:
{
phyParam.Value = CN470_RECEIVE_DELAY1;
break;
}
case PHY_RECEIVE_DELAY2:
{
phyParam.Value = CN470_RECEIVE_DELAY2;
break;
}
case PHY_JOIN_ACCEPT_DELAY1:
{
phyParam.Value = CN470_JOIN_ACCEPT_DELAY1;
break;
}
case PHY_JOIN_ACCEPT_DELAY2:
{
phyParam.Value = CN470_JOIN_ACCEPT_DELAY2;
break;
}
case PHY_MAX_FCNT_GAP:
{
phyParam.Value = CN470_MAX_FCNT_GAP;
break;
}
case PHY_ACK_TIMEOUT:
{
phyParam.Value = ( CN470_ACKTIMEOUT + randr( -CN470_ACK_TIMEOUT_RND, CN470_ACK_TIMEOUT_RND ) );
break;
}
case PHY_DEF_DR1_OFFSET:
{
phyParam.Value = CN470_DEFAULT_RX1_DR_OFFSET;
break;
}
case PHY_DEF_RX2_FREQUENCY:
{
phyParam.Value = CN470_RX_WND_2_FREQ;
break;
}
case PHY_DEF_RX2_DR:
{
phyParam.Value = CN470_RX_WND_2_DR;
break;
}
case PHY_CHANNELS_MASK:
{
phyParam.ChannelsMask = ChannelsMask;
break;
}
case PHY_CHANNELS_DEFAULT_MASK:
{
phyParam.ChannelsMask = ChannelsDefaultMask;
break;
}
case PHY_MAX_NB_CHANNELS:
{
phyParam.Value = CN470_MAX_NB_CHANNELS;
break;
}
case PHY_CHANNELS:
{
phyParam.Channels = Channels;
break;
}
case PHY_DEF_UPLINK_DWELL_TIME:
case PHY_DEF_DOWNLINK_DWELL_TIME:
{
phyParam.Value = 0;
break;
}
case PHY_DEF_MAX_EIRP:
{
phyParam.fValue = CN470_DEFAULT_MAX_EIRP;
break;
}
case PHY_DEF_ANTENNA_GAIN:
{
phyParam.fValue = CN470_DEFAULT_ANTENNA_GAIN;
break;
}
case PHY_NB_JOIN_TRIALS:
case PHY_DEF_NB_JOIN_TRIALS:
{
phyParam.Value = 48;
break;
}
default:
{
break;
}
}
return phyParam;
}
void RegionCN470SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
}
void RegionCN470InitDefaults( InitType_t type )
{
switch( type )
{
case INIT_TYPE_INIT:
{
// Channels
// 125 kHz channels
for( uint8_t i = 0; i < CN470_MAX_NB_CHANNELS; i++ )
{
Channels[i].Frequency = 470300000 + i * 200000;
Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0;
Channels[i].Band = 0;
}
// Initialize the channels default mask
ChannelsDefaultMask[0] = 0xFFFF;
ChannelsDefaultMask[1] = 0xFFFF;
ChannelsDefaultMask[2] = 0xFFFF;
ChannelsDefaultMask[3] = 0xFFFF;
ChannelsDefaultMask[4] = 0xFFFF;
ChannelsDefaultMask[5] = 0xFFFF;
// Update the channels mask
RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
break;
}
case INIT_TYPE_RESTORE:
{
// Restore channels default mask
RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
break;
}
default:
{
break;
}
}
}
bool RegionCN470Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
case PHY_TX_DR:
case PHY_DEF_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, CN470_TX_MIN_DATARATE, CN470_TX_MAX_DATARATE );
}
case PHY_RX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE );
}
case PHY_DEF_TX_POWER:
case PHY_TX_POWER:
{
// Remark: switched min and max!
return RegionCommonValueInRange( verify->TxPower, CN470_MAX_TX_POWER, CN470_MIN_TX_POWER );
}
case PHY_DUTY_CYCLE:
{
return CN470_DUTY_CYCLE_ENABLED;
}
case PHY_NB_JOIN_TRIALS:
{
if( verify->NbJoinTrials < 48 )
{
return false;
}
break;
}
default:
return false;
}
return true;
}
void RegionCN470ApplyCFList( ApplyCFListParams_t* applyCFList )
{
return;
}
bool RegionCN470ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
{
switch( chanMaskSet->ChannelsMaskType )
{
case CHANNELS_MASK:
{
RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 6 );
break;
}
case CHANNELS_DEFAULT_MASK:
{
RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6 );
break;
}
default:
return false;
}
return true;
}
bool RegionCN470AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
{
bool adrAckReq = false;
int8_t datarate = adrNext->Datarate;
int8_t txPower = adrNext->TxPower;
GetPhyParams_t getPhy;
PhyParam_t phyParam;
// Report back the adr ack counter
*adrAckCounter = adrNext->AdrAckCounter;
if( adrNext->AdrEnabled == true )
{
if( datarate == CN470_TX_MIN_DATARATE )
{
*adrAckCounter = 0;
adrAckReq = false;
}
else
{
if( adrNext->AdrAckCounter >= CN470_ADR_ACK_LIMIT )
{
adrAckReq = true;
txPower = CN470_MAX_TX_POWER;
}
else
{
adrAckReq = false;
}
if( adrNext->AdrAckCounter >= ( CN470_ADR_ACK_LIMIT + CN470_ADR_ACK_DELAY ) )
{
if( ( adrNext->AdrAckCounter % CN470_ADR_ACK_DELAY ) == 1 )
{
// Decrease the datarate
getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
getPhy.Datarate = datarate;
getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
phyParam = RegionCN470GetPhyParam( &getPhy );
datarate = phyParam.Value;
if( datarate == CN470_TX_MIN_DATARATE )
{
// We must set adrAckReq to false as soon as we reach the lowest datarate
adrAckReq = false;
if( adrNext->UpdateChanMask == true )
{
// Re-enable default channels
ChannelsMask[0] = 0xFFFF;
ChannelsMask[1] = 0xFFFF;
ChannelsMask[2] = 0xFFFF;
ChannelsMask[3] = 0xFFFF;
ChannelsMask[4] = 0xFFFF;
ChannelsMask[5] = 0xFFFF;
}
}
}
}
}
}
*drOut = datarate;
*txPowOut = txPower;
return adrAckReq;
}
void RegionCN470ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
{
double tSymbol = 0.0;
uint32_t radioWakeUpTime;
rxConfigParams->Datarate = datarate;
rxConfigParams->Bandwidth = GetBandwidth( datarate );
tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesCN470[datarate], BandwidthsCN470[datarate] );
radioWakeUpTime = Radio.GetRadioWakeUpTime( );
RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, radioWakeUpTime, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
}
bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
if( Radio.GetStatus( ) != RF_IDLE )
{
return false;
}
if( rxConfig->Window == 0 )
{
// Apply window 1 frequency
frequency = CN470_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 48 ) * CN470_STEPWIDTH_RX1_CHANNEL;
}
// Read the physical datarate from the datarates table
phyDr = DataratesCN470[dr];
Radio.SetChannel( frequency );
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
if( rxConfig->RepeaterSupport == true )
{
maxPayload = MaxPayloadOfDatarateRepeaterCN470[dr];
}
else
{
maxPayload = MaxPayloadOfDatarateCN470[dr];
}
Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
*datarate = (uint8_t) dr;
return true;
}
bool RegionCN470TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
{
int8_t phyDr = DataratesCN470[txConfig->Datarate];
int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
int8_t phyTxPower = 0;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
// Setup the radio frequency
Radio.SetChannel( Channels[txConfig->Channel].Frequency );
Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, 0, phyDr, 1, 8, false, true, 0, 0, false, 3000 );
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
// Get the time-on-air of the next tx frame
*txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
*txPower = txConfig->TxPower;
return true;
}
uint8_t RegionCN470LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
{
uint8_t status = 0x07;
LinkAdrParams_t linkAdrParams;
uint8_t nextIndex = 0;
uint8_t bytesProcessed = 0;
uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
// Initialize local copy of channels mask
RegionCommonChanMaskCopy( channelsMask, ChannelsMask, 6 );
while( bytesProcessed < linkAdrReq->PayloadSize )
{
// Get ADR request parameters
nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
if( nextIndex == 0 )
break; // break loop, since no more request has been found
// Update bytes processed
bytesProcessed += nextIndex;
// Revert status, as we only check the last ADR request for the channel mask KO
status = 0x07;
if( linkAdrParams.ChMaskCtrl == 6 )
{
// Enable all 125 kHz channels
channelsMask[0] = 0xFFFF;
channelsMask[1] = 0xFFFF;
channelsMask[2] = 0xFFFF;
channelsMask[3] = 0xFFFF;
channelsMask[4] = 0xFFFF;
channelsMask[5] = 0xFFFF;
}
else if( linkAdrParams.ChMaskCtrl == 7 )
{
status &= 0xFE; // Channel mask KO
}
else
{
for( uint8_t i = 0; i <CN470_MAX_NB_CHANNELS; i++ ) //perry 2017/7/24
//for( uint8_t i = 0; i < 16; i++ )
{
if( ( ( linkAdrParams.ChMask & ( 1 << i ) ) != 0 ) &&
( Channels[linkAdrParams.ChMaskCtrl * 16 + i].Frequency == 0 ) )
{// Trying to enable an undefined channel
status &= 0xFE; // Channel mask KO
}
}
channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
}
}
// Verify datarate
if( RegionCommonChanVerifyDr( CN470_MAX_NB_CHANNELS, channelsMask, linkAdrParams.Datarate, CN470_TX_MIN_DATARATE, CN470_TX_MAX_DATARATE, Channels ) == false )
{
status &= 0xFD; // Datarate KO
}
// Verify tx power
if( RegionCommonValueInRange( linkAdrParams.TxPower, CN470_MAX_TX_POWER, CN470_MIN_TX_POWER ) == 0 )
{
// Verify if the maximum TX power is exceeded
if( CN470_MAX_TX_POWER > linkAdrParams.TxPower )
{ // Apply maximum TX power. Accept TX power.
linkAdrParams.TxPower = CN470_MAX_TX_POWER;
}
else
{
status &= 0xFB; // TxPower KO
}
}
// Update channelsMask if everything is correct
if( status == 0x07 )
{
if( linkAdrParams.NbRep == 0 )
{ // Value of 0 is not allowed, revert to default.
linkAdrParams.NbRep = 1;
}
// Copy Mask
RegionCommonChanMaskCopy( ChannelsMask, channelsMask, 6 );
}
// Update status variables
*drOut = linkAdrParams.Datarate;
*txPowOut = linkAdrParams.TxPower;
*nbRepOut = linkAdrParams.NbRep;
*nbBytesParsed = bytesProcessed;
return status;
}
uint8_t RegionCN470RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
{
uint8_t status = 0x07;
uint32_t freq = rxParamSetupReq->Frequency;
// Verify radio frequency
if( ( Radio.CheckRfFrequency( freq ) == false ) ||
( freq < CN470_FIRST_RX1_CHANNEL ) ||
( freq > CN470_LAST_RX1_CHANNEL ) ||
( ( ( freq - ( uint32_t ) CN470_FIRST_RX1_CHANNEL ) % ( uint32_t ) CN470_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
{
status &= 0xFE; // Channel frequency KO
}
// Verify datarate
if( RegionCommonValueInRange( rxParamSetupReq->Datarate, CN470_RX_MIN_DATARATE, CN470_RX_MAX_DATARATE ) == false )
{
status &= 0xFD; // Datarate KO
}
// Verify datarate offset
if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, CN470_MIN_RX1_DR_OFFSET, CN470_MAX_RX1_DR_OFFSET ) == false )
{
status &= 0xFB; // Rx1DrOffset range KO
}
return status;
}
uint8_t RegionCN470NewChannelReq( NewChannelReqParams_t* newChannelReq )
{
// Datarate and frequency KO
return 0;
}
int8_t RegionCN470TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
{
return -1;
}
uint8_t RegionCN470DlChannelReq( DlChannelReqParams_t* dlChannelReq )
{
return 0;
}
int8_t RegionCN470AlternateDr( AlternateDrParams_t* alternateDr )
{
int8_t datarate = 0;
if( ( alternateDr->NbTrials % 48 ) == 0 )
{
datarate = DR_0;
}
else if( ( alternateDr->NbTrials % 32 ) == 0 )
{
datarate = DR_1;
}
else if( ( alternateDr->NbTrials % 24 ) == 0 )
{
datarate = DR_2;
}
else if( ( alternateDr->NbTrials % 16 ) == 0 )
{
datarate = DR_3;
}
else if( ( alternateDr->NbTrials % 8 ) == 0 )
{
datarate = DR_4;
}
else
{
datarate = DR_5;
}
return datarate;
}
void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff )
{
uint8_t channel = calcBackOff->Channel;
uint16_t joinDutyCycle = 0;
if( calcBackOff->Joined == false )
{
// Get the join duty cycle
joinDutyCycle = RegionCommonGetJoinDc( calcBackOff->ElapsedTime );
// Apply band time-off.
Bands[Channels[channel].Band].TimeOff = calcBackOff->TxTimeOnAir * joinDutyCycle - calcBackOff->TxTimeOnAir;
}
else
{
Bands[Channels[channel].Band].TimeOff = 0;
}
}
bool RegionCN470NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTx = 0;
uint8_t enabledChannels[CN470_MAX_NB_CHANNELS] = { 0 };
TimerTime_t nextTxDelay = 0;
// Count 125kHz channels
if( RegionCommonCountChannels( ChannelsMask, 0, 6 ) == 0 )
{ // Reactivate default channels
ChannelsMask[0] = 0xFFFF;
ChannelsMask[1] = 0xFFFF;
ChannelsMask[2] = 0xFFFF;
ChannelsMask[3] = 0xFFFF;
ChannelsMask[4] = 0xFFFF;
ChannelsMask[5] = 0xFFFF;
}
if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
{
// Reset Aggregated time off
*aggregatedTimeOff = 0;
// Update bands Time OFF
nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, CN470_MAX_NB_BANDS );
// Search how many channels are enabled
nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
ChannelsMask, Channels,
Bands, enabledChannels, &delayTx );
}
else
{
delayTx++;
nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
}
if( nbEnabledChannels > 0 )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
*time = 0;
return true;
}
else
{
if( delayTx > 0 )
{
// Delay transmission due to AggregatedTimeOff or to a band time off
*time = nextTxDelay;
return true;
}
// Datarate not supported by any channel
*time = 0;
return false;
}
}
LoRaMacStatus_t RegionCN470ChannelAdd( ChannelAddParams_t* channelAdd )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
bool RegionCN470ChannelsRemove( ChannelRemoveParams_t* channelRemove )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
void RegionCN470SetContinuousWave( ContinuousWaveParams_t* continuousWave )
{
int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
int8_t phyTxPower = 0;
uint32_t frequency = Channels[continuousWave->Channel].Frequency;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, continuousWave->MaxEirp, continuousWave->AntennaGain );
Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
}
uint8_t RegionCN470ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
{
int8_t datarate = dr - drOffset;
if( datarate < 0 )
{
datarate = DR_0;
}
return datarate;
}

View file

@ -0,0 +1,445 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionCN470.h
*
* \brief Region definition for CN470
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONCN470 Region CN470
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_CN470_H__
#define __REGION_CN470_H__
/*!
* LoRaMac maximum number of channels
*/
#define CN470_MAX_NB_CHANNELS 8
/*!
* Minimal datarate that can be used by the node
*/
#define CN470_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define CN470_TX_MAX_DATARATE DR_5
/*!
* Minimal datarate that can be used by the node
*/
#define CN470_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define CN470_RX_MAX_DATARATE DR_5
/*!
* Default datarate used by the node
*/
#define CN470_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define CN470_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define CN470_MAX_RX1_DR_OFFSET 3
/*!
* Default Rx1 receive datarate offset
*/
#define CN470_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define CN470_MIN_TX_POWER TX_POWER_7
/*!
* Maximal Tx output power that can be used by the node
*/
#define CN470_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define CN470_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP
*/
#define CN470_DEFAULT_MAX_EIRP 19.15f
/*!
* Default antenna gain
*/
#define CN470_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define CN470_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define CN470_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define CN470_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
*/
#define CN470_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define CN470_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define CN470_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define CN470_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define CN470_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define CN470_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define CN470_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define CN470_ACK_TIMEOUT_RND 1000
/*!
* Second reception window channel frequency definition.
*/
#define CN470_RX_WND_2_FREQ 505300000
/*!
* Second reception window channel datarate definition.
*/
#define CN470_RX_WND_2_DR DR_0
/*!
* LoRaMac maximum number of bands
*/
#define CN470_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define CN470_BAND0 { 1, CN470_MAX_TX_POWER, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for CN470 band
*/
#define CN470_FIRST_RX1_CHANNEL ( (uint32_t) 500.3e6 )
/*!
* Defines the last channel for RX window 1 for CN470 band
*/
#define CN470_LAST_RX1_CHANNEL ( (uint32_t) 509.7e6 )
/*!
* Defines the step width of the channels for RX window 1
*/
#define CN470_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 200e3 )
/*!
* Data rates table definition
*/
static const uint8_t DataratesCN470[] = { 12, 11, 10, 9, 8, 7 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsCN470[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateCN470[] = { 51, 51, 51, 115, 222, 222 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterCN470[] = { 51, 51, 51, 115, 222, 222 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionCN470GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionCN470SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionCN470InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionCN470Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionCN470ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionCN470ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionCN470AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionCN470ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionCN470RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionCN470TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionCN470TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN470DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionCN470AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionCN470CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionCN470NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionCN470ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionCN470ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionCN470SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionCN470ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONCN470 */
#endif // __REGION_CN470_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,469 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionCN779.h
*
* \brief Region definition for CN779
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONCN779 Region CN779
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_CN779_H__
#define __REGION_CN779_H__
/*!
* LoRaMac maximum number of channels
*/
#define CN779_MAX_NB_CHANNELS 16
/*!
* Number of default channels
*/
#define CN779_NUMB_DEFAULT_CHANNELS 3
/*!
* Number of channels to apply for the CF list
*/
#define CN779_NUMB_CHANNELS_CF_LIST 5
/*!
* Minimal datarate that can be used by the node
*/
#define CN779_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define CN779_TX_MAX_DATARATE DR_7
/*!
* Minimal datarate that can be used by the node
*/
#define CN779_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define CN779_RX_MAX_DATARATE DR_7
/*!
* Default datarate used by the node
*/
#define CN779_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define CN779_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define CN779_MAX_RX1_DR_OFFSET 5
/*!
* Default Rx1 receive datarate offset
*/
#define CN779_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define CN779_MIN_TX_POWER TX_POWER_5
/*!
* Maximal Tx output power that can be used by the node
*/
#define CN779_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define CN779_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP
*/
#define CN779_DEFAULT_MAX_EIRP 12.15f
/*!
* Default antenna gain
*/
#define CN779_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define CN779_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define CN779_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define CN779_DUTY_CYCLE_ENABLED 1
/*!
* Maximum RX window duration
*/
#define CN779_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define CN779_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define CN779_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define CN779_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define CN779_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define CN779_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define CN779_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define CN779_ACK_TIMEOUT_RND 1000
/*!
* Verification of default datarate
*/
#if ( CN779_DEFAULT_DATARATE > DR_5 )
#error "A default DR higher than DR_5 may lead to connectivity loss."
#endif
/*!
* Second reception window channel frequency definition.
*/
#define CN779_RX_WND_2_FREQ 786000000
/*!
* Second reception window channel datarate definition.
*/
#define CN779_RX_WND_2_DR DR_0
/*!
* LoRaMac maximum number of bands
*/
#define CN779_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define CN779_BAND0 { 100, CN779_MAX_TX_POWER, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN779_LC1 { 779500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 2
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN779_LC2 { 779700000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 3
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define CN779_LC3 { 779900000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac channels which are allowed for the join procedure
*/
#define CN779_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
/*!
* Data rates table definition
*/
static const uint8_t DataratesCN779[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsCN779[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateCN779[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterCN779[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionCN779GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionCN779SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionCN779InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionCN779Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionCN779ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionCN779ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionCN779AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionCN779ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionCN779RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionCN779TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN779LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN779RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN779NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionCN779TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionCN779DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionCN779AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionCN779CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionCN779NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionCN779ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionCN779ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionCN779SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionCN779ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONCN779 */
#endif // __REGION_CN779_H__

View file

@ -0,0 +1,248 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC common region implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel
Jaeckle ( STACKFORCE )
*/
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
//#include "timer.h"
#include "timeServer.h"
#include "utilities.h"
#include "LoRaMac.h"
#include "RegionCommon.h"
#define BACKOFF_DC_1_HOUR 100
#define BACKOFF_DC_10_HOURS 1000
#define BACKOFF_DC_24_HOURS 10000
static uint8_t CountChannels(uint16_t mask, uint8_t nbBits)
{
uint8_t nbActiveBits = 0;
for (uint8_t j = 0; j < nbBits; j++) {
if ((mask & (1 << j)) == (1 << j)) {
nbActiveBits++;
}
}
return nbActiveBits;
}
uint16_t RegionCommonGetJoinDc(TimerTime_t elapsedTime)
{
uint16_t dutyCycle = 0;
if (elapsedTime < 3600000) {
dutyCycle = BACKOFF_DC_1_HOUR;
} else if (elapsedTime < (3600000 + 36000000)) {
dutyCycle = BACKOFF_DC_10_HOURS;
} else {
dutyCycle = BACKOFF_DC_24_HOURS;
}
return dutyCycle;
}
bool RegionCommonChanVerifyDr(uint8_t nbChannels, uint16_t *channelsMask,
int8_t dr, int8_t minDr, int8_t maxDr,
ChannelParams_t *channels)
{
if (RegionCommonValueInRange(dr, minDr, maxDr) == 0) {
return false;
}
for (uint8_t i = 0, k = 0; i < nbChannels; i += 16, k++) {
for (uint8_t j = 0; j < 16; j++) {
if (((channelsMask[k] & (1 << j)) !=
0)) { // Check datarate validity for enabled channels
if (RegionCommonValueInRange(
dr, (channels[i + j].DrRange.Fields.Min & 0x0F),
(channels[i + j].DrRange.Fields.Max & 0x0F)) == 1) {
// At least 1 channel has been found we can return OK.
return true;
}
}
}
}
return false;
}
uint8_t RegionCommonValueInRange(int8_t value, int8_t min, int8_t max)
{
if ((value >= min) && (value <= max)) {
return 1;
}
return 0;
}
bool RegionCommonChanDisable(uint16_t *channelsMask, uint8_t id,
uint8_t maxChannels)
{
uint8_t index = id / 16;
if ((index > (maxChannels / 16)) || (id >= maxChannels)) {
return false;
}
// Deactivate channel
channelsMask[index] &= ~(1 << (id % 16));
return true;
}
uint8_t RegionCommonCountChannels(uint16_t *channelsMask, uint8_t startIdx,
uint8_t stopIdx)
{
uint8_t nbChannels = 0;
if (channelsMask == NULL) {
return 0;
}
for (uint8_t i = startIdx; i < stopIdx; i++) {
nbChannels += CountChannels(channelsMask[i], 16);
}
return nbChannels;
}
void RegionCommonChanMaskCopy(uint16_t *channelsMaskDest,
uint16_t *channelsMaskSrc, uint8_t len)
{
if ((channelsMaskDest != NULL) && (channelsMaskSrc != NULL)) {
for (uint8_t i = 0; i < len; i++) {
channelsMaskDest[i] = channelsMaskSrc[i];
}
}
}
void RegionCommonSetBandTxDone(bool joined, Band_t *band,
TimerTime_t lastTxDone)
{
if (joined == true) {
band->LastTxDoneTime = lastTxDone;
} else {
band->LastTxDoneTime = lastTxDone;
band->LastJoinTxDoneTime = lastTxDone;
}
}
TimerTime_t RegionCommonUpdateBandTimeOff(bool joined, bool dutyCycle,
Band_t *bands, uint8_t nbBands)
{
TimerTime_t nextTxDelay = (TimerTime_t)(-1);
// Update bands Time OFF
for (uint8_t i = 0; i < nbBands; i++) {
if (joined == false) {
uint32_t txDoneTime = MAX(
TimerGetElapsedTime(bands[i].LastJoinTxDoneTime),
(dutyCycle == true) ? TimerGetElapsedTime(bands[i].LastTxDoneTime)
: 0);
if (bands[i].TimeOff <= txDoneTime) {
bands[i].TimeOff = 0;
}
if (bands[i].TimeOff != 0) {
nextTxDelay = MIN(bands[i].TimeOff - txDoneTime, nextTxDelay);
}
} else {
if (dutyCycle == true) {
if (bands[i].TimeOff <=
TimerGetElapsedTime(bands[i].LastTxDoneTime)) {
bands[i].TimeOff = 0;
}
if (bands[i].TimeOff != 0) {
nextTxDelay =
MIN(bands[i].TimeOff -
TimerGetElapsedTime(bands[i].LastTxDoneTime),
nextTxDelay);
}
} else {
nextTxDelay = 0;
bands[i].TimeOff = 0;
}
}
}
return nextTxDelay;
}
uint8_t RegionCommonParseLinkAdrReq(uint8_t *payload,
LinkAdrParams_t *linkAdrParams)
{
uint8_t retIndex = 0;
if (payload[0] == SRV_MAC_LINK_ADR_REQ) {
// Parse datarate and tx power
linkAdrParams->Datarate = payload[1];
linkAdrParams->TxPower = linkAdrParams->Datarate & 0x0F;
linkAdrParams->Datarate = (linkAdrParams->Datarate >> 4) & 0x0F;
// Parse ChMask
linkAdrParams->ChMask = (uint16_t)payload[2];
linkAdrParams->ChMask |= (uint16_t)payload[3] << 8;
// Parse ChMaskCtrl and nbRep
linkAdrParams->NbRep = payload[4];
linkAdrParams->ChMaskCtrl = (linkAdrParams->NbRep >> 4) & 0x07;
linkAdrParams->NbRep &= 0x0F;
// LinkAdrReq has 4 bytes length + 1 byte CMD
retIndex = 5;
}
return retIndex;
}
DECIMAL RegionCommonComputeSymbolTimeLoRa(uint8_t phyDr, uint32_t bandwidth)
{
return ((DECIMAL)(1 << phyDr) / (DECIMAL)bandwidth) * 1000;
}
DECIMAL RegionCommonComputeSymbolTimeFsk(uint8_t phyDr)
{
return ((DECIMAL)8.0 / (DECIMAL)phyDr); // 1 symbol equals 1 byte
}
void RegionCommonComputeRxWindowParameters(
DECIMAL tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime,
uint32_t *windowTimeout, int32_t *windowOffset)
{
*windowTimeout =
MAX((uint32_t)ceilf(((2 * minRxSymbols - 8) * tSymbol + 2 * rxError) /
tSymbol),
minRxSymbols); // Computed number of symbols
*windowOffset = (int32_t)ceilf(
(4.0f * tSymbol) - ((*windowTimeout * tSymbol) / 2.0f) - wakeUpTime);
}
int8_t RegionCommonComputeTxPower(int8_t txPowerIndex, float maxEirp,
float antennaGain)
{
int8_t phyTxPower = 0;
phyTxPower = (int8_t)floorf((maxEirp - (txPowerIndex * 2U)) - antennaGain);
return phyTxPower;
}

View file

@ -0,0 +1,267 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionCommon.h
*
* \brief Region independent implementations which are common to all
* regions.
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONCOMMON Common region implementation
* Region independent implementations which are common to all
* regions.
* \{
*/
#ifndef __REGIONCOMMON_H__
#define __REGIONCOMMON_H__
#include "precision.h"
typedef struct sLinkAdrParams
{
/*!
* Number of repetitions.
*/
uint8_t NbRep;
/*!
* Datarate.
*/
int8_t Datarate;
/*!
* Tx power.
*/
int8_t TxPower;
/*!
* Channels mask control field.
*/
uint8_t ChMaskCtrl;
/*!
* Channels mask field.
*/
uint16_t ChMask;
} LinkAdrParams_t;
/*!
* \brief Calculates the join duty cycle.
* This is a generic function and valid for all regions.
*
* \param [IN] elapsedTime Elapsed time since the start of the device.
*
* \retval Duty cycle restriction.
*/
uint16_t RegionCommonGetJoinDc(TimerTime_t elapsedTime);
/*!
* \brief Verifies, if a value is in a given range.
* This is a generic function and valid for all regions.
*
* \param [IN] value Value to verify, if it is in range.
*
* \param [IN] min Minimum possible value.
*
* \param [IN] max Maximum possible value.
*
* \retval Returns 1 if the value is in range, otherwise 0.
*/
uint8_t RegionCommonValueInRange(int8_t value, int8_t min, int8_t max);
/*!
* \brief Verifies, if a datarate is available on an active channel.
* This is a generic function and valid for all regions.
*
* \param [IN] nbChannels Number of channels.
*
* \param [IN] channelsMask The channels mask of the region.
*
* \param [IN] dr The datarate to verify.
*
* \param [IN] minDr Minimum datarate.
*
* \param [IN] maxDr Maximum datarate.
*
* \param [IN] channels The channels of the region.
*
* \retval Returns true if the datarate is supported, false if not.
*/
bool RegionCommonChanVerifyDr(uint8_t nbChannels, uint16_t *channelsMask,
int8_t dr, int8_t minDr, int8_t maxDr,
ChannelParams_t *channels);
/*!
* \brief Disables a channel in a given channels mask.
* This is a generic function and valid for all regions.
*
* \param [IN] channelsMask The channels mask of the region.
*
* \param [IN] id The id of the channels mask to disable.
*
* \param [IN] maxChannels Maximum number of channels.
*
* \retval Returns true if the channel could be disabled, false if not.
*/
bool RegionCommonChanDisable(uint16_t *channelsMask, uint8_t id,
uint8_t maxChannels);
/*!
* \brief Counts the number of active channels in a given channels mask.
* This is a generic function and valid for all regions.
*
* \param [IN] channelsMask The channels mask of the region.
*
* \param [IN] startIdx Start index.
*
* \param [IN] stopIdx Stop index ( the channels of this index will not be
* counted ).
*
* \retval Returns the number of active channels.
*/
uint8_t RegionCommonCountChannels(uint16_t *channelsMask, uint8_t startIdx,
uint8_t stopIdx);
/*!
* \brief Copy a channels mask.
* This is a generic function and valid for all regions.
*
* \param [IN] channelsMaskDest The destination channels mask.
*
* \param [IN] channelsMaskSrc The source channels mask.
*
* \param [IN] len The index length to copy.
*/
void RegionCommonChanMaskCopy(uint16_t *channelsMaskDest,
uint16_t *channelsMaskSrc, uint8_t len);
/*!
* \brief Sets the last tx done property.
* This is a generic function and valid for all regions.
*
* \param [IN] joined Set to true, if the node has joined the network
*
* \param [IN] band The band to be updated.
*
* \param [IN] lastTxDone The time of the last TX done.
*/
void RegionCommonSetBandTxDone(bool joined, Band_t *band,
TimerTime_t lastTxDone);
/*!
* \brief Updates the time-offs of the bands.
* This is a generic function and valid for all regions.
*
* \param [IN] joined Set to true, if the node has joined the network
*
* \param [IN] dutyCycle Set to true, if the duty cycle is enabled.
*
* \param [IN] bands A pointer to the bands.
*
* \param [IN] nbBands The number of bands available.
*
* \retval Returns the time which must be waited to perform the next uplink.
*/
TimerTime_t RegionCommonUpdateBandTimeOff(bool joined, bool dutyCycle,
Band_t *bands, uint8_t nbBands);
/*!
* \brief Parses the parameter of an LinkAdrRequest.
* This is a generic function and valid for all regions.
*
* \param [IN] payload Pointer to the payload containing the MAC commands. The
* payload must contain the CMD identifier, following by the parameters.
*
* \param [OUT] parseLinkAdr The function fills the structure with the ADR
* parameters.
*
* \retval Returns the length of the ADR request, if a request was found.
* Otherwise, the function returns 0.
*/
uint8_t RegionCommonParseLinkAdrReq(uint8_t *payload,
LinkAdrParams_t *parseLinkAdr);
/*!
* \brief Computes the symbol time for LoRa modulation.
*
* \param [IN] phyDr Physical datarate to use.
*
* \param [IN] bandwidth Bandwidth to use.
*
* \retval Returns the symbol time.
*/
DECIMAL RegionCommonComputeSymbolTimeLoRa(uint8_t phyDr, uint32_t bandwidth);
/*!
* \brief Computes the symbol time for FSK modulation.
*
* \param [IN] phyDr Physical datarate to use.
*
* \param [IN] bandwidth Bandwidth to use.
*
* \retval Returns the symbol time.
*/
DECIMAL RegionCommonComputeSymbolTimeFsk(uint8_t phyDr);
/*!
* \brief Computes the RX window timeout and the RX window offset.
*
* \param [IN] tSymbol Symbol timeout.
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx
* frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In
* milliseconds The receiver will turn on in a [-rxError : +rxError] ms interval
* around RxOffset.
*
* \param [IN] wakeUpTime Wakeup time of the system.
*
* \param [OUT] windowTimeout RX window timeout.
*
* \param [OUT] windowOffset RX window time offset to be applied to the RX
* delay.
*/
void RegionCommonComputeRxWindowParameters(
DECIMAL tSymbol, uint8_t minRxSymbols, uint32_t rxError, uint32_t wakeUpTime,
uint32_t *windowTimeout, int32_t *windowOffset);
/*!
* \brief Computes the txPower, based on the max EIRP and the antenna gain.
*
* \param [IN] txPower TX power index.
*
* \param [IN] maxEirp Maximum EIRP.
*
* \param [IN] antennaGain Antenna gain.
*
* \retval Returns the physical TX power.
*/
int8_t RegionCommonComputeTxPower(int8_t txPowerIndex, float maxEirp,
float antennaGain);
/*! \} defgroup REGIONCOMMON */
#endif // __REGIONCOMMON_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,470 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionEU433.h
*
* \brief Region definition for EU433
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONEU433 Region EU433
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_EU433_H__
#define __REGION_EU433_H__
/*!
* LoRaMac maximum number of channels
*/
#define EU433_MAX_NB_CHANNELS 16
/*!
* Number of default channels
*/
#define EU433_NUMB_DEFAULT_CHANNELS 3
/*!
* Number of channels to apply for the CF list
*/
#define EU433_NUMB_CHANNELS_CF_LIST 5
/*!
* Minimal datarate that can be used by the node
*/
#define EU433_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define EU433_TX_MAX_DATARATE DR_7
/*!
* Minimal datarate that can be used by the node
*/
#define EU433_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define EU433_RX_MAX_DATARATE DR_7
/*!
* Default datarate used by the node
*/
#define EU433_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define EU433_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define EU433_MAX_RX1_DR_OFFSET 5
/*!
* Default Rx1 receive datarate offset
*/
#define EU433_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define EU433_MIN_TX_POWER TX_POWER_5
/*!
* Maximal Tx output power that can be used by the node
*/
#define EU433_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define EU433_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP
*/
#define EU433_DEFAULT_MAX_EIRP 12.15f
/*!
* Default antenna gain
*/
#define EU433_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define EU433_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define EU433_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define EU433_DUTY_CYCLE_ENABLED 1
/*!
* Maximum RX window duration
*/
#define EU433_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define EU433_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define EU433_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define EU433_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define EU433_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define EU433_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define EU433_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define EU433_ACK_TIMEOUT_RND 1000
/*!
* Verification of default datarate
*/
#if ( EU433_DEFAULT_DATARATE > DR_5 )
#error "A default DR higher than DR_5 may lead to connectivity loss."
#endif
/*!
* Second reception window channel frequency definition.
*/
#define EU433_RX_WND_2_FREQ 434665000
/*!
* Second reception window channel datarate definition.
*/
#define EU433_RX_WND_2_DR DR_0
/*!
* LoRaMac maximum number of bands
*/
#define EU433_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define EU433_BAND0 { 100, EU433_MAX_TX_POWER, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define EU433_LC1 { 433175000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 2
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define EU433_LC2 { 433375000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 3
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define EU433_LC3 { 433575000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac channels which are allowed for the join procedure
*/
#define EU433_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
/*!
* Data rates table definition
*/
static const uint8_t DataratesEU433[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsEU433[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateEU433[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterEU433[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionEU433GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionEU433SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionEU433InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionEU433Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionEU433ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionEU433ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionEU433AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionEU433ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionEU433RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionEU433TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU433LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU433RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU433NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionEU433TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU433DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionEU433AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionEU433CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionEU433NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionEU433ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionEU433ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionEU433SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionEU433ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONEU433 */
#endif // __REGION_EU433_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,491 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionEU868.h
*
* \brief Region definition for EU868
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONEU868 Region EU868
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_EU868_H__
#define __REGION_EU868_H__
/*!
* LoRaMac maximum number of channels
*/
#define EU868_MAX_NB_CHANNELS 16
/*!
* Number of default channels
*/
#define EU868_NUMB_DEFAULT_CHANNELS 3
/*!
* Number of channels to apply for the CF list
*/
#define EU868_NUMB_CHANNELS_CF_LIST 5
/*!
* Minimal datarate that can be used by the node
*/
#define EU868_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define EU868_TX_MAX_DATARATE DR_7
/*!
* Minimal datarate that can be used by the node
*/
#define EU868_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define EU868_RX_MAX_DATARATE DR_7
/*!
* Default datarate used by the node
*/
#define EU868_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define EU868_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define EU868_MAX_RX1_DR_OFFSET 5
/*!
* Default Rx1 receive datarate offset
*/
#define EU868_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define EU868_MIN_TX_POWER TX_POWER_7
/*!
* Maximal Tx output power that can be used by the node
*/
#define EU868_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define EU868_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP
*/
#define EU868_DEFAULT_MAX_EIRP 16.0f
/*!
* Default antenna gain
*/
#define EU868_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define EU868_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define EU868_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define EU868_DUTY_CYCLE_ENABLED 1
/*!
* Maximum RX window duration
*/
#define EU868_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define EU868_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define EU868_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define EU868_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define EU868_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define EU868_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define EU868_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define EU868_ACK_TIMEOUT_RND 1000
#if ( EU868_DEFAULT_DATARATE > DR_5 )
#error "A default DR higher than DR_5 may lead to connectivity loss."
#endif
/*!
* Second reception window channel frequency definition.
*/
#define EU868_RX_WND_2_FREQ 869525000
/*!
* Second reception window channel datarate definition.
*/
#define EU868_RX_WND_2_DR DR_0
/*!
* Maximum number of bands
*/
#define EU868_MAX_NB_BANDS 5
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define EU868_BAND0 { 100 , EU868_MAX_TX_POWER, 0, 0 } // 1.0 %
/*!
* Band 1 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define EU868_BAND1 { 100 , EU868_MAX_TX_POWER, 0, 0 } // 1.0 %
/*!
* Band 2 definition
* Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define EU868_BAND2 { 1000, EU868_MAX_TX_POWER, 0, 0 } // 0.1 %
/*!
* Band 2 definition
* Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define EU868_BAND3 { 10 , EU868_MAX_TX_POWER, 0, 0 } // 10.0 %
/*!
* Band 2 definition
* Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define EU868_BAND4 { 100 , EU868_MAX_TX_POWER, 0, 0 } // 1.0 %
/*!
* LoRaMac default channel 1
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define EU868_LC1 { 868100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
/*!
* LoRaMac default channel 2
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define EU868_LC2 { 868300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
/*!
* LoRaMac default channel 3
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define EU868_LC3 { 868500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
/*!
* LoRaMac channels which are allowed for the join procedure
*/
#define EU868_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
/*!
* Data rates table definition
*/
static const uint8_t DataratesEU868[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsEU868[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateEU868[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterEU868[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionEU868GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionEU868SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionEU868InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionEU868Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionEU868ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionEU868ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionEU868AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionEU868ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionEU868RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionEU868TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU868LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU868RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU868NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionEU868TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionEU868DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionEU868AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionEU868CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionEU868NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionEU868ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionEU868ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionEU868SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionEU868ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONEU868 */
#endif // __REGION_EU868_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,472 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionIN865.h
*
* \brief Region definition for IN865
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONIN865 Region IN865
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_IN865_H__
#define __REGION_IN865_H__
/*!
* LoRaMac maximum number of channels
*/
#define IN865_MAX_NB_CHANNELS 16
/*!
* Number of default channels
*/
#define IN865_NUMB_DEFAULT_CHANNELS 3
/*!
* Number of channels to apply for the CF list
*/
#define IN865_NUMB_CHANNELS_CF_LIST 5
/*!
* Minimal datarate that can be used by the node
*/
#define IN865_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define IN865_TX_MAX_DATARATE DR_7
/*!
* Minimal datarate that can be used by the node
*/
#define IN865_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define IN865_RX_MAX_DATARATE DR_7
/*!
* Default datarate used by the node
*/
#define IN865_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define IN865_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define IN865_MAX_RX1_DR_OFFSET 7
/*!
* Default Rx1 receive datarate offset
*/
#define IN865_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define IN865_MIN_TX_POWER TX_POWER_10
/*!
* Maximal Tx output power that can be used by the node
*/
#define IN865_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define IN865_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP
*/
#define IN865_DEFAULT_MAX_EIRP 30.0f
/*!
* Default antenna gain
*/
#define IN865_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define IN865_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define IN865_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define IN865_DUTY_CYCLE_ENABLED 1
/*!
* Maximum RX window duration
*/
#define IN865_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define IN865_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define IN865_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define IN865_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define IN865_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define IN865_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define IN865_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define IN865_ACK_TIMEOUT_RND 1000
#if ( IN865_DEFAULT_DATARATE > DR_5 )
#error "A default DR higher than DR_5 may lead to connectivity loss."
#endif
/*!
* Second reception window channel frequency definition.
*/
#define IN865_RX_WND_2_FREQ 866550000
/*!
* Second reception window channel datarate definition.
*/
#define IN865_RX_WND_2_DR DR_2
/*!
* Maximum number of bands
*/
#define IN865_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define IN865_BAND0 { 1 , IN865_MAX_TX_POWER, 0, 0 } // 100.0 %
/*!
* LoRaMac default channel 1
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define IN865_LC1 { 865062500, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 2
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define IN865_LC2 { 865402500, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 3
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define IN865_LC3 { 865985000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac channels which are allowed for the join procedure
*/
#define IN865_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
/*!
* Data rates table definition
*/
static const uint8_t DataratesIN865[] = { 12, 11, 10, 9, 8, 7, 7, 50 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsIN865[] = { 125000, 125000, 125000, 125000, 125000, 125000, 250000, 0 };
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateIN865[] = { 51, 51, 51, 115, 242, 242, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterIN865[] = { 51, 51, 51, 115, 222, 222, 222, 222 };
/*!
* Effective datarate offsets for receive window 1.
*/
static const int8_t EffectiveRx1DrOffsetIN865[] = { 0, 1, 2, 3, 4, 5, -1, -2 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionIN865GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionIN865SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionIN865InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionIN865Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionIN865ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionIN865ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionIN865AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionIN865ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionIN865RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionIN865TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionIN865LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionIN865RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionIN865NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionIN865TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionIN865DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionIN865AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionIN865CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionIN865NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionIN865ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionIN865ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionIN865SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionIN865ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONIN865 */
#endif // __REGION_IN865_H__

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,482 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionKR920.h
*
* \brief Region definition for KR920
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONKR920 Region KR920
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_KR920_H__
#define __REGION_KR920_H__
/*!
* LoRaMac maximum number of channels
*/
#define KR920_MAX_NB_CHANNELS 16
/*!
* Number of default channels
*/
#define KR920_NUMB_DEFAULT_CHANNELS 3
/*!
* Number of channels to apply for the CF list
*/
#define KR920_NUMB_CHANNELS_CF_LIST 5
/*!
* Minimal datarate that can be used by the node
*/
#define KR920_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define KR920_TX_MAX_DATARATE DR_5
/*!
* Minimal datarate that can be used by the node
*/
#define KR920_RX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define KR920_RX_MAX_DATARATE DR_5
/*!
* Default datarate used by the node
*/
#define KR920_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define KR920_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define KR920_MAX_RX1_DR_OFFSET 5
/*!
* Default Rx1 receive datarate offset
*/
#define KR920_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define KR920_MIN_TX_POWER TX_POWER_7
/*!
* Maximal Tx output power that can be used by the node
*/
#define KR920_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define KR920_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max EIRP for frequency 920.9 MHz - 921.9 MHz
*/
#define KR920_DEFAULT_MAX_EIRP_LOW 10.0f
/*!
* Default Max EIRP for frequency 922.1 MHz - 923.3 MHz
*/
#define KR920_DEFAULT_MAX_EIRP_HIGH 14.0f
/*!
* Default antenna gain
*/
#define KR920_DEFAULT_ANTENNA_GAIN 2.15f
/*!
* ADR Ack limit
*/
#define KR920_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define KR920_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define KR920_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
*/
#define KR920_MAX_RX_WINDOW 4000
/*!
* Receive delay 1
*/
#define KR920_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define KR920_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define KR920_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define KR920_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define KR920_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define KR920_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define KR920_ACK_TIMEOUT_RND 1000
#if ( KR920_DEFAULT_DATARATE > DR_5 )
#error "A default DR higher than DR_5 may lead to connectivity loss."
#endif
/*!
* Second reception window channel frequency definition.
*/
#define KR920_RX_WND_2_FREQ 921900000
/*!
* Second reception window channel datarate definition.
*/
#define KR920_RX_WND_2_DR DR_0
/*!
* Maximum number of bands
*/
#define KR920_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define KR920_BAND0 { 1 , KR920_MAX_TX_POWER, 0, 0 } // 100.0 %
/*!
* LoRaMac default channel 1
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define KR920_LC1 { 922100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 2
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define KR920_LC2 { 922300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac default channel 3
* Channel = { Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
*/
#define KR920_LC3 { 922500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
/*!
* LoRaMac channels which are allowed for the join procedure
*/
#define KR920_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
/*!
* RSSI threshold for a free channel [dBm]
*/
#define KR920_RSSI_FREE_TH -65
/*!
* Specifies the time the node performs a carrier sense
*/
#define KR920_CARRIER_SENSE_TIME 6
/*!
* Data rates table definition
*/
static const uint8_t DataratesKR920[] = { 12, 11, 10, 9, 8, 7 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsKR920[] = { 125000, 125000, 125000, 125000, 125000, 125000 };
/*!
* Maximum payload with respect to the datarate index. Can operate with and without a repeater.
*/
static const uint8_t MaxPayloadOfDatarateKR920[] = { 51, 51, 51, 115, 242, 242 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterKR920[] = { 51, 51, 51, 115, 222, 222 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionKR920GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionKR920SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionKR920InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionKR920Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionKR920ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionKR920ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionKR920AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionKR920ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionKR920RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionKR920TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionKR920LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionKR920RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionKR920NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionKR920TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionKR920DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionKR920AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionKR920CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionKR920NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionKR920ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionKR920ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionKR920SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionKR920ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONKR920 */
#endif // __REGION_KR920_H__

View file

@ -0,0 +1,972 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC region US915 Hybrid implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
*/
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include "radio.h"
//#include "timer.h"
#include "timeServer.h"
#include "LoRaMac.h"
#include "utilities.h"
#include "Region.h"
#include "RegionCommon.h"
#include "RegionUS915-Hybrid.h"
#include "debug.h"
// Definitions
#define CHANNELS_MASK_SIZE 6
// Global attributes
/*!
* LoRaMAC channels
*/
static ChannelParams_t Channels[US915_HYBRID_MAX_NB_CHANNELS];
/*!
* LoRaMac bands
*/
static Band_t Bands[US915_HYBRID_MAX_NB_BANDS] =
{
US915_HYBRID_BAND0
};
/*!
* LoRaMac channels mask
*/
static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
/*!
* LoRaMac channels remaining
*/
static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE];
/*!
* LoRaMac channels default mask
*/
static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
// Static functions
static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
{
uint8_t nextLowerDr = 0;
if( dr == minDr )
{
nextLowerDr = minDr;
}
else
{
nextLowerDr = dr - 1;
}
return nextLowerDr;
}
static uint32_t GetBandwidth( uint32_t drIndex )
{
switch( BandwidthsUS915_HYBRID[drIndex] )
{
default:
case 125000:
return 0;
case 250000:
return 1;
case 500000:
return 2;
}
}
static void ReenableChannels( uint16_t mask, uint16_t* channelsMask )
{
uint16_t blockMask = mask;
for( uint8_t i = 0, j = 0; i < 4; i++, j += 2 )
{
channelsMask[i] = 0;
if( ( blockMask & ( 1 << j ) ) != 0 )
{
channelsMask[i] |= 0x00FF;
}
if( ( blockMask & ( 1 << ( j + 1 ) ) ) != 0 )
{
channelsMask[i] |= 0xFF00;
}
}
channelsMask[4] = blockMask;
channelsMask[5] = 0x0000;
}
static uint8_t CountBits( uint16_t mask, uint8_t nbBits )
{
uint8_t nbActiveBits = 0;
for( uint8_t j = 0; j < nbBits; j++ )
{
if( ( mask & ( 1 << j ) ) == ( 1 << j ) )
{
nbActiveBits++;
}
}
return nbActiveBits;
}
static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
{
int8_t txPowerResult = txPower;
// Limit tx power to the band max
txPowerResult = MAX( txPower, maxBandTxPower );
if( datarate == DR_4 )
{// Limit tx power to max 26dBm
txPowerResult = MAX( txPower, TX_POWER_2 );
}
else
{
if( RegionCommonCountChannels( channelsMask, 0, 4 ) < 50 )
{// Limit tx power to max 21dBm
txPowerResult = MAX( txPower, TX_POWER_5 );
}
}
return txPowerResult;
}
static bool ValidateChannelsMask( uint16_t* channelsMask )
{
bool chanMaskState = false;
uint16_t block1 = 0;
uint16_t block2 = 0;
uint8_t index = 0;
uint16_t channelsMaskCpy[6];
// Copy channels mask to not change the input
for( uint8_t i = 0; i < 4; i++ )
{
channelsMaskCpy[i] = channelsMask[i];
}
for( uint8_t i = 0; i < 4; i++ )
{
block1 = channelsMaskCpy[i] & 0x00FF;
block2 = channelsMaskCpy[i] & 0xFF00;
if( CountBits( block1, 16 ) > 5 )
{
channelsMaskCpy[i] &= block1;
channelsMaskCpy[4] = 1 << ( i * 2 );
chanMaskState = true;
index = i;
break;
}
else if( CountBits( block2, 16 ) > 5 )
{
channelsMaskCpy[i] &= block2;
channelsMaskCpy[4] = 1 << ( i * 2 + 1 );
chanMaskState = true;
index = i;
break;
}
}
// Do only change the channel mask, if we have found a valid block.
if( chanMaskState == true )
{
// Copy channels mask back again
for( uint8_t i = 0; i < 4; i++ )
{
channelsMask[i] = channelsMaskCpy[i];
if( i != index )
{
channelsMask[i] = 0;
}
}
channelsMask[4] = channelsMaskCpy[4];
}
return chanMaskState;
}
static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTransmission = 0;
for( uint8_t i = 0, k = 0; i < US915_HYBRID_MAX_NB_CHANNELS; i += 16, k++ )
{
for( uint8_t j = 0; j < 16; j++ )
{
if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
{
if( channels[i + j].Frequency == 0 )
{ // Check if the channel is enabled
continue;
}
if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
channels[i + j].DrRange.Fields.Max ) == false )
{ // Check if the current channel selection supports the given datarate
continue;
}
if( bands[channels[i + j].Band].TimeOff > 0 )
{ // Check if the band is available for transmission
delayTransmission++;
continue;
}
enabledChannels[nbEnabledChannels++] = i + j;
}
}
}
*delayTx = delayTransmission;
return nbEnabledChannels;
}
PhyParam_t RegionUS915HybridGetPhyParam( GetPhyParams_t* getPhy )
{
PhyParam_t phyParam = { 0 };
switch( getPhy->Attribute )
{
case PHY_MIN_RX_DR:
{
phyParam.Value = US915_HYBRID_RX_MIN_DATARATE;
break;
}
case PHY_MIN_TX_DR:
{
phyParam.Value = US915_HYBRID_TX_MIN_DATARATE;
break;
}
case PHY_DEF_TX_DR:
{
phyParam.Value = US915_HYBRID_DEFAULT_DATARATE;
break;
}
case PHY_NEXT_LOWER_TX_DR:
{
phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, US915_HYBRID_TX_MIN_DATARATE );
break;
}
case PHY_DEF_TX_POWER:
{
phyParam.Value = US915_HYBRID_DEFAULT_TX_POWER;
break;
}
case PHY_MAX_PAYLOAD:
{
phyParam.Value = MaxPayloadOfDatarateUS915_HYBRID[getPhy->Datarate];
break;
}
case PHY_MAX_PAYLOAD_REPEATER:
{
phyParam.Value = MaxPayloadOfDatarateRepeaterUS915_HYBRID[getPhy->Datarate];
break;
}
case PHY_DUTY_CYCLE:
{
phyParam.Value = US915_HYBRID_DUTY_CYCLE_ENABLED;
break;
}
case PHY_MAX_RX_WINDOW:
{
phyParam.Value = US915_HYBRID_MAX_RX_WINDOW;
break;
}
case PHY_RECEIVE_DELAY1:
{
phyParam.Value = US915_HYBRID_RECEIVE_DELAY1;
break;
}
case PHY_RECEIVE_DELAY2:
{
phyParam.Value = US915_HYBRID_RECEIVE_DELAY2;
break;
}
case PHY_JOIN_ACCEPT_DELAY1:
{
phyParam.Value = US915_HYBRID_JOIN_ACCEPT_DELAY1;
break;
}
case PHY_JOIN_ACCEPT_DELAY2:
{
phyParam.Value = US915_HYBRID_JOIN_ACCEPT_DELAY2;
break;
}
case PHY_MAX_FCNT_GAP:
{
phyParam.Value = US915_HYBRID_MAX_FCNT_GAP;
break;
}
case PHY_ACK_TIMEOUT:
{
phyParam.Value = ( US915_HYBRID_ACKTIMEOUT + randr( -US915_HYBRID_ACK_TIMEOUT_RND, US915_HYBRID_ACK_TIMEOUT_RND ) );
break;
}
case PHY_DEF_DR1_OFFSET:
{
phyParam.Value = US915_HYBRID_DEFAULT_RX1_DR_OFFSET;
break;
}
case PHY_DEF_RX2_FREQUENCY:
{
phyParam.Value = US915_HYBRID_RX_WND_2_FREQ;
break;
}
case PHY_DEF_RX2_DR:
{
phyParam.Value = US915_HYBRID_RX_WND_2_DR;
break;
}
case PHY_CHANNELS_MASK:
{
phyParam.ChannelsMask = ChannelsMask;
break;
}
case PHY_CHANNELS_DEFAULT_MASK:
{
phyParam.ChannelsMask = ChannelsDefaultMask;
break;
}
case PHY_MAX_NB_CHANNELS:
{
phyParam.Value = US915_HYBRID_MAX_NB_CHANNELS;
break;
}
case PHY_CHANNELS:
{
phyParam.Channels = Channels;
break;
}
case PHY_DEF_UPLINK_DWELL_TIME:
case PHY_DEF_DOWNLINK_DWELL_TIME:
{
phyParam.Value = 0;
break;
}
case PHY_DEF_MAX_EIRP:
case PHY_DEF_ANTENNA_GAIN:
{
phyParam.fValue = 0;
break;
}
case PHY_NB_JOIN_TRIALS:
case PHY_DEF_NB_JOIN_TRIALS:
{
phyParam.Value = 2;
break;
}
default:
{
break;
}
}
return phyParam;
}
void RegionUS915HybridSetBandTxDone( SetBandTxDoneParams_t* txDone )
{
RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
}
void RegionUS915HybridInitDefaults( InitType_t type )
{
switch( type )
{
case INIT_TYPE_INIT:
{
// Channels
// 125 kHz channels
for( uint8_t i = 0; i < US915_HYBRID_MAX_NB_CHANNELS - 8; i++ )
{
Channels[i].Frequency = 902300000 + i * 200000;
Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0;
Channels[i].Band = 0;
}
// 500 kHz channels
for( uint8_t i = US915_HYBRID_MAX_NB_CHANNELS - 8; i < US915_HYBRID_MAX_NB_CHANNELS; i++ )
{
Channels[i].Frequency = 903000000 + ( i - ( US915_HYBRID_MAX_NB_CHANNELS - 8 ) ) * 1600000;
Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4;
Channels[i].Band = 0;
}
// ChannelsMask
ChannelsDefaultMask[0] = 0x00FF;
ChannelsDefaultMask[1] = 0x0000;
ChannelsDefaultMask[2] = 0x0000;
ChannelsDefaultMask[3] = 0x0000;
ChannelsDefaultMask[4] = 0x0001;
ChannelsDefaultMask[5] = 0x0000;
// Copy channels default mask
RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
// Copy into channels mask remaining
RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 6 );
break;
}
case INIT_TYPE_RESTORE:
{
ReenableChannels( ChannelsDefaultMask[4], ChannelsMask );
for( uint8_t i = 0; i < 6; i++ )
{ // Copy-And the channels mask
ChannelsMaskRemaining[i] &= ChannelsMask[i];
}
}
default:
{
break;
}
}
}
bool RegionUS915HybridVerify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, US915_HYBRID_TX_MIN_DATARATE, US915_HYBRID_TX_MAX_DATARATE );
}
case PHY_DEF_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
}
case PHY_RX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, US915_HYBRID_RX_MIN_DATARATE, US915_HYBRID_RX_MAX_DATARATE );
}
case PHY_DEF_TX_POWER:
case PHY_TX_POWER:
{
// Remark: switched min and max!
return RegionCommonValueInRange( verify->TxPower, US915_HYBRID_MAX_TX_POWER, US915_HYBRID_MIN_TX_POWER );
}
case PHY_DUTY_CYCLE:
{
return US915_HYBRID_DUTY_CYCLE_ENABLED;
}
case PHY_NB_JOIN_TRIALS:
{
if( verify->NbJoinTrials < 2 )
{
return false;
}
break;
}
default:
return false;
}
return true;
}
void RegionUS915HybridApplyCFList( ApplyCFListParams_t* applyCFList )
{
return;
}
bool RegionUS915HybridChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
{
uint8_t nbChannels = RegionCommonCountChannels( chanMaskSet->ChannelsMaskIn, 0, 4 );
// Check the number of active channels
if( ( nbChannels < 2 ) &&
( nbChannels > 0 ) )
{
return false;
}
// Validate the channels mask
if( ValidateChannelsMask( chanMaskSet->ChannelsMaskIn ) == false )
{
return false;
}
switch( chanMaskSet->ChannelsMaskType )
{
case CHANNELS_MASK:
{
RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 6 );
for( uint8_t i = 0; i < 6; i++ )
{ // Copy-And the channels mask
ChannelsMaskRemaining[i] &= ChannelsMask[i];
}
break;
}
case CHANNELS_DEFAULT_MASK:
{
RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6 );
break;
}
default:
return false;
}
return true;
}
bool RegionUS915HybridAdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
{
bool adrAckReq = false;
int8_t datarate = adrNext->Datarate;
int8_t txPower = adrNext->TxPower;
GetPhyParams_t getPhy;
PhyParam_t phyParam;
// Report back the adr ack counter
*adrAckCounter = adrNext->AdrAckCounter;
if( adrNext->AdrEnabled == true )
{
if( datarate == US915_HYBRID_TX_MIN_DATARATE )
{
*adrAckCounter = 0;
adrAckReq = false;
}
else
{
if( adrNext->AdrAckCounter >= US915_HYBRID_ADR_ACK_LIMIT )
{
adrAckReq = true;
txPower = US915_HYBRID_MAX_TX_POWER;
}
else
{
adrAckReq = false;
}
if( adrNext->AdrAckCounter >= ( US915_HYBRID_ADR_ACK_LIMIT + US915_HYBRID_ADR_ACK_DELAY ) )
{
if( ( adrNext->AdrAckCounter % US915_HYBRID_ADR_ACK_DELAY ) == 1 )
{
// Decrease the datarate
getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
getPhy.Datarate = datarate;
getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
phyParam = RegionUS915HybridGetPhyParam( &getPhy );
datarate = phyParam.Value;
if( datarate == US915_HYBRID_TX_MIN_DATARATE )
{
// We must set adrAckReq to false as soon as we reach the lowest datarate
adrAckReq = false;
if( adrNext->UpdateChanMask == true )
{
// Re-enable default channels
ReenableChannels( ChannelsMask[4], ChannelsMask );
}
}
}
}
}
}
*drOut = datarate;
*txPowOut = txPower;
return adrAckReq;
}
void RegionUS915HybridComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
{
double tSymbol = 0.0;
uint32_t radioWakeUpTime;
rxConfigParams->Datarate = datarate;
rxConfigParams->Bandwidth = GetBandwidth( datarate );
if( datarate == DR_7 )
{ // FSK
tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesUS915_HYBRID[datarate] );
}
else
{ // LoRa
tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesUS915_HYBRID[datarate], BandwidthsUS915_HYBRID[datarate] );
}
radioWakeUpTime = Radio.GetRadioWakeUpTime( );
RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, radioWakeUpTime, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
}
bool RegionUS915HybridRxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
if( Radio.GetStatus( ) != RF_IDLE )
{
return false;
}
if( rxConfig->Window == 0 )
{
// Apply window 1 frequency
frequency = US915_HYBRID_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 8 ) * US915_HYBRID_STEPWIDTH_RX1_CHANNEL;
}
// Read the physical datarate from the datarates table
phyDr = DataratesUS915_HYBRID[dr];
Radio.SetChannel( frequency );
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
if( rxConfig->RepeaterSupport == true )
{
maxPayload = MaxPayloadOfDatarateRepeaterUS915_HYBRID[dr];
}
else
{
maxPayload = MaxPayloadOfDatarateUS915_HYBRID[dr];
}
Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
DBG_PRINTF("RX on freq %d Hz at DR %d\n\r", frequency, dr);
*datarate = (uint8_t) dr;
return true;
}
bool RegionUS915HybridTxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
{
int8_t phyDr = DataratesUS915_HYBRID[txConfig->Datarate];
int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
int8_t phyTxPower = 0;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, US915_HYBRID_DEFAULT_MAX_ERP, 0 );
Radio.SetChannel( Channels[txConfig->Channel].Frequency );
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3e3 );
DBG_PRINTF("TX on freq %d Hz at DR %d\n\r", Channels[txConfig->Channel].Frequency, txConfig->Datarate);
*txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
}
uint8_t RegionUS915HybridLinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
{
uint8_t status = 0x07;
LinkAdrParams_t linkAdrParams;
uint8_t nextIndex = 0;
uint8_t bytesProcessed = 0;
uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
// Initialize local copy of channels mask
RegionCommonChanMaskCopy( channelsMask, ChannelsMask, 6 );
while( bytesProcessed < linkAdrReq->PayloadSize )
{
nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
if( nextIndex == 0 )
break; // break loop, since no more request has been found
// Update bytes processed
bytesProcessed += nextIndex;
// Revert status, as we only check the last ADR request for the channel mask KO
status = 0x07;
if( linkAdrParams.ChMaskCtrl == 6 )
{
// Enable all 125 kHz channels
channelsMask[0] = 0xFFFF;
channelsMask[1] = 0xFFFF;
channelsMask[2] = 0xFFFF;
channelsMask[3] = 0xFFFF;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask;
}
else if( linkAdrParams.ChMaskCtrl == 7 )
{
// Disable all 125 kHz channels
channelsMask[0] = 0x0000;
channelsMask[1] = 0x0000;
channelsMask[2] = 0x0000;
channelsMask[3] = 0x0000;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask;
}
else if( linkAdrParams.ChMaskCtrl == 5 )
{
// RFU
status &= 0xFE; // Channel mask KO
}
else
{
channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
}
}
// FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
if( ( linkAdrParams.Datarate < DR_4 ) && ( RegionCommonCountChannels( channelsMask, 0, 4 ) < 2 ) )
{
status &= 0xFE; // Channel mask KO
}
if( ValidateChannelsMask( channelsMask ) == false )
{
status &= 0xFE; // Channel mask KO
}
// Verify datarate
if( RegionCommonChanVerifyDr( US915_HYBRID_MAX_NB_CHANNELS, channelsMask, linkAdrParams.Datarate, US915_HYBRID_TX_MIN_DATARATE, US915_HYBRID_TX_MAX_DATARATE, Channels ) == false )
{
status &= 0xFD; // Datarate KO
}
// Verify tx power
if( RegionCommonValueInRange( linkAdrParams.TxPower, US915_HYBRID_MAX_TX_POWER, US915_HYBRID_MIN_TX_POWER ) == 0 )
{
// Verify if the maximum TX power is exceeded
if( US915_HYBRID_MAX_TX_POWER > linkAdrParams.TxPower )
{ // Apply maximum TX power. Accept TX power.
linkAdrParams.TxPower = US915_HYBRID_MAX_TX_POWER;
}
else
{
status &= 0xFB; // TxPower KO
}
}
// Update channelsMask if everything is correct
if( status == 0x07 )
{
if( linkAdrParams.NbRep == 0 )
{ // Value of 0 is not allowed, revert to default.
linkAdrParams.NbRep = 1;
}
// Copy Mask
RegionCommonChanMaskCopy( ChannelsMask, channelsMask, 6 );
ChannelsMaskRemaining[0] &= ChannelsMask[0];
ChannelsMaskRemaining[1] &= ChannelsMask[1];
ChannelsMaskRemaining[2] &= ChannelsMask[2];
ChannelsMaskRemaining[3] &= ChannelsMask[3];
ChannelsMaskRemaining[4] = ChannelsMask[4];
ChannelsMaskRemaining[5] = ChannelsMask[5];
}
// Update status variables
*drOut = linkAdrParams.Datarate;
*txPowOut = linkAdrParams.TxPower;
*nbRepOut = linkAdrParams.NbRep;
*nbBytesParsed = bytesProcessed;
return status;
}
uint8_t RegionUS915HybridRxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
{
uint8_t status = 0x07;
uint32_t freq = rxParamSetupReq->Frequency;
// Verify radio frequency
if( ( Radio.CheckRfFrequency( freq ) == false ) ||
( freq < US915_HYBRID_FIRST_RX1_CHANNEL ) ||
( freq > US915_HYBRID_LAST_RX1_CHANNEL ) ||
( ( ( freq - ( uint32_t ) US915_HYBRID_FIRST_RX1_CHANNEL ) % ( uint32_t ) US915_HYBRID_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
{
status &= 0xFE; // Channel frequency KO
}
// Verify datarate
if( RegionCommonValueInRange( rxParamSetupReq->Datarate, US915_HYBRID_RX_MIN_DATARATE, US915_HYBRID_RX_MAX_DATARATE ) == false )
{
status &= 0xFD; // Datarate KO
}
if( ( RegionCommonValueInRange( rxParamSetupReq->Datarate, DR_5, DR_7 ) == true ) ||
( rxParamSetupReq->Datarate > DR_13 ) )
{
status &= 0xFD; // Datarate KO
}
// Verify datarate offset
if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, US915_HYBRID_MIN_RX1_DR_OFFSET, US915_HYBRID_MAX_RX1_DR_OFFSET ) == false )
{
status &= 0xFB; // Rx1DrOffset range KO
}
return status;
}
uint8_t RegionUS915HybridNewChannelReq( NewChannelReqParams_t* newChannelReq )
{
// Datarate and frequency KO
return 0;
}
int8_t RegionUS915HybridTxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
{
return -1;
}
uint8_t RegionUS915HybridDlChannelReq( DlChannelReqParams_t* dlChannelReq )
{
return 0;
}
int8_t RegionUS915HybridAlternateDr( AlternateDrParams_t* alternateDr )
{
int8_t datarate = 0;
// Re-enable 500 kHz default channels
ReenableChannels( ChannelsMask[4], ChannelsMask );
if( ( alternateDr->NbTrials & 0x01 ) == 0x01 )
{
datarate = DR_4;
}
else
{
datarate = DR_0;
}
return datarate;
}
void RegionUS915HybridCalcBackOff( CalcBackOffParams_t* calcBackOff )
{
uint8_t channel = calcBackOff->Channel;
uint16_t joinDutyCycle = 0;
if( calcBackOff->Joined == false )
{
// Get the join duty cycle
joinDutyCycle = RegionCommonGetJoinDc( calcBackOff->ElapsedTime );
// Apply band time-off.
Bands[Channels[channel].Band].TimeOff = calcBackOff->TxTimeOnAir * joinDutyCycle - calcBackOff->TxTimeOnAir;
}
else
{
Bands[Channels[channel].Band].TimeOff = 0;
}
}
bool RegionUS915HybridNextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTx = 0;
uint8_t enabledChannels[US915_HYBRID_MAX_NB_CHANNELS] = { 0 };
TimerTime_t nextTxDelay = 0;
// Count 125kHz channels
if( RegionCommonCountChannels( ChannelsMaskRemaining, 0, 4 ) == 0 )
{ // Reactivate default channels
RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 4 );
}
// Check other channels
if( nextChanParams->Datarate >= DR_4 )
{
if( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 )
{
ChannelsMaskRemaining[4] = ChannelsMask[4];
}
}
if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
{
// Reset Aggregated time off
*aggregatedTimeOff = 0;
// Update bands Time OFF
nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, US915_HYBRID_MAX_NB_BANDS );
// Search how many channels are enabled
nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
ChannelsMaskRemaining, Channels,
Bands, enabledChannels, &delayTx );
}
else
{
delayTx++;
nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
}
if( nbEnabledChannels > 0 )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
// Disable the channel in the mask
RegionCommonChanDisable( ChannelsMaskRemaining, *channel, US915_HYBRID_MAX_NB_CHANNELS - 8 );
*time = 0;
return true;
}
else
{
if( delayTx > 0 )
{
// Delay transmission due to AggregatedTimeOff or to a band time off
*time = nextTxDelay;
return true;
}
// Datarate not supported by any channel
*time = 0;
return false;
}
}
LoRaMacStatus_t RegionUS915HybridChannelAdd( ChannelAddParams_t* channelAdd )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
bool RegionUS915HybridChannelsRemove( ChannelRemoveParams_t* channelRemove )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
void RegionUS915HybridSetContinuousWave( ContinuousWaveParams_t* continuousWave )
{
int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
int8_t phyTxPower = 0;
uint32_t frequency = Channels[continuousWave->Channel].Frequency;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, US915_HYBRID_DEFAULT_MAX_ERP, 0 );
Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
}
uint8_t RegionUS915HybridApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
{
int8_t datarate = DatarateOffsetsUS915_HYBRID[dr][drOffset];
if( datarate < 0 )
{
datarate = DR_0;
}
return datarate;
}

View file

@ -0,0 +1,452 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionUS915Hybrid-Hybrid.h
*
* \brief Region definition for US915
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONUS915HYB Region US915 in hybrid mode
* This is a hybrid implementation for US915, supporting 16 uplink channels only.
* \{
*/
#ifndef __REGION_US915_HYBRID_H__
#define __REGION_US915_HYBRID_H__
/*!
* LoRaMac maximum number of channels
*/
#define US915_HYBRID_MAX_NB_CHANNELS 72
/*!
* Minimal datarate that can be used by the node
*/
#define US915_HYBRID_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define US915_HYBRID_TX_MAX_DATARATE DR_4
/*!
* Minimal datarate that can be used by the node
*/
#define US915_HYBRID_RX_MIN_DATARATE DR_8
/*!
* Maximal datarate that can be used by the node
*/
#define US915_HYBRID_RX_MAX_DATARATE DR_13
/*!
* Default datarate used by the node
*/
#define US915_HYBRID_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define US915_HYBRID_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define US915_HYBRID_MAX_RX1_DR_OFFSET 3
/*!
* Default Rx1 receive datarate offset
*/
#define US915_HYBRID_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define US915_HYBRID_MIN_TX_POWER TX_POWER_10
/*!
* Maximal Tx output power that can be used by the node
*/
#define US915_HYBRID_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define US915_HYBRID_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max ERP
*/
#define US915_HYBRID_DEFAULT_MAX_ERP 30.0f
/*!
* ADR Ack limit
*/
#define US915_HYBRID_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define US915_HYBRID_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define US915_HYBRID_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
*/
#define US915_HYBRID_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define US915_HYBRID_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define US915_HYBRID_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define US915_HYBRID_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define US915_HYBRID_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define US915_HYBRID_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define US915_HYBRID_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define US915_HYBRID_ACK_TIMEOUT_RND 1000
/*!
* Second reception window channel frequency definition.
*/
#define US915_HYBRID_RX_WND_2_FREQ 923300000
/*!
* Second reception window channel datarate definition.
*/
#define US915_HYBRID_RX_WND_2_DR DR_8
/*!
* LoRaMac maximum number of bands
*/
#define US915_HYBRID_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define US915_HYBRID_BAND0 { 1, US915_HYBRID_MAX_TX_POWER, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for US band
*/
#define US915_HYBRID_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 )
/*!
* Defines the last channel for RX window 1 for US band
*/
#define US915_HYBRID_LAST_RX1_CHANNEL ( (uint32_t) 927500000 )
/*!
* Defines the step width of the channels for RX window 1
*/
#define US915_HYBRID_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 )
/*!
* Data rates table definition
*/
static const uint8_t DataratesUS915_HYBRID[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsUS915_HYBRID[] = { 125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 };
/*!
* Up/Down link data rates offset definition
*/
static const int8_t DatarateOffsetsUS915_HYBRID[5][4] =
{
{ DR_10, DR_9 , DR_8 , DR_8 }, // DR_0
{ DR_11, DR_10, DR_9 , DR_8 }, // DR_1
{ DR_12, DR_11, DR_10, DR_9 }, // DR_2
{ DR_13, DR_12, DR_11, DR_10 }, // DR_3
{ DR_13, DR_13, DR_12, DR_11 }, // DR_4
};
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateUS915_HYBRID[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterUS915_HYBRID[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionUS915HybridGetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionUS915HybridSetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionUS915HybridInitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionUS915HybridVerify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionUS915HybridApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionUS915HybridChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionUS915HybridAdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionUS915HybridComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionUS915HybridRxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionUS915HybridTxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915HybridLinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915HybridRxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915HybridNewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionUS915HybridTxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915HybridDlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionUS915HybridAlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionUS915HybridCalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionUS915HybridNextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionUS915HybridChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionUS915HybridChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionUS915HybridSetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionUS915HybridApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONUS915HYB */
#endif // __REGION_US915_HYBRID_H__

View file

@ -0,0 +1,879 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC region US915 implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
*/
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <math.h>
#include "radio.h"
//#include "timer.h"
#include "timeServer.h"
#include "LoRaMac.h"
#include "utilities.h"
#include "Region.h"
#include "RegionCommon.h"
#include "RegionUS915.h"
#include "debug.h"
// Definitions
#define CHANNELS_MASK_SIZE 6
// Global attributes
/*!
* LoRaMAC channels
*/
static ChannelParams_t Channels[US915_MAX_NB_CHANNELS];
/*!
* LoRaMac bands
*/
static Band_t Bands[US915_MAX_NB_BANDS] =
{
US915_BAND0
};
/*!
* LoRaMac channels mask
*/
static uint16_t ChannelsMask[CHANNELS_MASK_SIZE];
/*!
* LoRaMac channels remaining
*/
static uint16_t ChannelsMaskRemaining[CHANNELS_MASK_SIZE];
/*!
* LoRaMac channels default mask
*/
static uint16_t ChannelsDefaultMask[CHANNELS_MASK_SIZE];
// Static functions
static int8_t GetNextLowerTxDr( int8_t dr, int8_t minDr )
{
uint8_t nextLowerDr = 0;
if( dr == minDr )
{
nextLowerDr = minDr;
}
else
{
nextLowerDr = dr - 1;
}
return nextLowerDr;
}
static uint32_t GetBandwidth( uint32_t drIndex )
{
switch( BandwidthsUS915[drIndex] )
{
default:
case 125000:
return 0;
case 250000:
return 1;
case 500000:
return 2;
}
}
static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower, int8_t datarate, uint16_t* channelsMask )
{
int8_t txPowerResult = txPower;
// Limit tx power to the band max
txPowerResult = MAX( txPower, maxBandTxPower );
if( datarate == DR_4 )
{// Limit tx power to max 26dBm
txPowerResult = MAX( txPower, TX_POWER_2 );
}
else
{
if( RegionCommonCountChannels( channelsMask, 0, 4 ) < 50 )
{// Limit tx power to max 21dBm
txPowerResult = MAX( txPower, TX_POWER_5 );
}
}
return txPowerResult;
}
static uint8_t CountNbOfEnabledChannels( uint8_t datarate, uint16_t* channelsMask, ChannelParams_t* channels, Band_t* bands, uint8_t* enabledChannels, uint8_t* delayTx )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTransmission = 0;
for( uint8_t i = 0, k = 0; i < US915_MAX_NB_CHANNELS; i += 16, k++ )
{
for( uint8_t j = 0; j < 16; j++ )
{
if( ( channelsMask[k] & ( 1 << j ) ) != 0 )
{
if( channels[i + j].Frequency == 0 )
{ // Check if the channel is enabled
continue;
}
if( RegionCommonValueInRange( datarate, channels[i + j].DrRange.Fields.Min,
channels[i + j].DrRange.Fields.Max ) == false )
{ // Check if the current channel selection supports the given datarate
continue;
}
if( bands[channels[i + j].Band].TimeOff > 0 )
{ // Check if the band is available for transmission
delayTransmission++;
continue;
}
enabledChannels[nbEnabledChannels++] = i + j;
}
}
}
*delayTx = delayTransmission;
return nbEnabledChannels;
}
PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy )
{
PhyParam_t phyParam = { 0 };
switch( getPhy->Attribute )
{
case PHY_MIN_RX_DR:
{
phyParam.Value = US915_RX_MIN_DATARATE;
break;
}
case PHY_MIN_TX_DR:
{
phyParam.Value = US915_TX_MIN_DATARATE;
break;
}
case PHY_DEF_TX_DR:
{
phyParam.Value = US915_DEFAULT_DATARATE;
break;
}
case PHY_NEXT_LOWER_TX_DR:
{
phyParam.Value = GetNextLowerTxDr( getPhy->Datarate, US915_TX_MIN_DATARATE );
break;
}
case PHY_DEF_TX_POWER:
{
phyParam.Value = US915_DEFAULT_TX_POWER;
break;
}
case PHY_MAX_PAYLOAD:
{
phyParam.Value = MaxPayloadOfDatarateUS915[getPhy->Datarate];
break;
}
case PHY_MAX_PAYLOAD_REPEATER:
{
phyParam.Value = MaxPayloadOfDatarateRepeaterUS915[getPhy->Datarate];
break;
}
case PHY_DUTY_CYCLE:
{
phyParam.Value = US915_DUTY_CYCLE_ENABLED;
break;
}
case PHY_MAX_RX_WINDOW:
{
phyParam.Value = US915_MAX_RX_WINDOW;
break;
}
case PHY_RECEIVE_DELAY1:
{
phyParam.Value = US915_RECEIVE_DELAY1;
break;
}
case PHY_RECEIVE_DELAY2:
{
phyParam.Value = US915_RECEIVE_DELAY2;
break;
}
case PHY_JOIN_ACCEPT_DELAY1:
{
phyParam.Value = US915_JOIN_ACCEPT_DELAY1;
break;
}
case PHY_JOIN_ACCEPT_DELAY2:
{
phyParam.Value = US915_JOIN_ACCEPT_DELAY2;
break;
}
case PHY_MAX_FCNT_GAP:
{
phyParam.Value = US915_MAX_FCNT_GAP;
break;
}
case PHY_ACK_TIMEOUT:
{
phyParam.Value = ( US915_ACKTIMEOUT + randr( -US915_ACK_TIMEOUT_RND, US915_ACK_TIMEOUT_RND ) );
break;
}
case PHY_DEF_DR1_OFFSET:
{
phyParam.Value = US915_DEFAULT_RX1_DR_OFFSET;
break;
}
case PHY_DEF_RX2_FREQUENCY:
{
phyParam.Value = US915_RX_WND_2_FREQ;
break;
}
case PHY_DEF_RX2_DR:
{
phyParam.Value = US915_RX_WND_2_DR;
break;
}
case PHY_CHANNELS_MASK:
{
phyParam.ChannelsMask = ChannelsMask;
break;
}
case PHY_CHANNELS_DEFAULT_MASK:
{
phyParam.ChannelsMask = ChannelsDefaultMask;
break;
}
case PHY_MAX_NB_CHANNELS:
{
phyParam.Value = US915_MAX_NB_CHANNELS;
break;
}
case PHY_CHANNELS:
{
phyParam.Channels = Channels;
break;
}
case PHY_DEF_UPLINK_DWELL_TIME:
case PHY_DEF_DOWNLINK_DWELL_TIME:
{
phyParam.Value = 0;
break;
}
case PHY_DEF_MAX_EIRP:
case PHY_DEF_ANTENNA_GAIN:
{
phyParam.fValue = 0;
break;
}
case PHY_NB_JOIN_TRIALS:
case PHY_DEF_NB_JOIN_TRIALS:
{
phyParam.Value = 2;
break;
}
default:
{
break;
}
}
return phyParam;
}
void RegionUS915SetBandTxDone( SetBandTxDoneParams_t* txDone )
{
RegionCommonSetBandTxDone( txDone->Joined, &Bands[Channels[txDone->Channel].Band], txDone->LastTxDoneTime );
}
void RegionUS915InitDefaults( InitType_t type )
{
switch( type )
{
case INIT_TYPE_INIT:
{
// Channels
// 125 kHz channels
for( uint8_t i = 0; i < US915_MAX_NB_CHANNELS - 8; i++ )
{
Channels[i].Frequency = 902300000 + i * 200000;
Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0;
Channels[i].Band = 0;
}
// 500 kHz channels
for( uint8_t i = US915_MAX_NB_CHANNELS - 8; i < US915_MAX_NB_CHANNELS; i++ )
{
Channels[i].Frequency = 903000000 + ( i - ( US915_MAX_NB_CHANNELS - 8 ) ) * 1600000;
Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4;
Channels[i].Band = 0;
}
// ChannelsMask
ChannelsDefaultMask[0] = 0xFFFF;
ChannelsDefaultMask[1] = 0xFFFF;
ChannelsDefaultMask[2] = 0xFFFF;
ChannelsDefaultMask[3] = 0xFFFF;
ChannelsDefaultMask[4] = 0x00FF;
ChannelsDefaultMask[5] = 0x0000;
// Copy channels default mask
RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
// Copy into channels mask remaining
RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 6 );
break;
}
case INIT_TYPE_RESTORE:
{
// Copy channels default mask
RegionCommonChanMaskCopy( ChannelsMask, ChannelsDefaultMask, 6 );
for( uint8_t i = 0; i < 6; i++ )
{ // Copy-And the channels mask
ChannelsMaskRemaining[i] &= ChannelsMask[i];
}
break;
}
default:
{
break;
}
}
}
bool RegionUS915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute )
{
switch( phyAttribute )
{
case PHY_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, US915_TX_MIN_DATARATE, US915_TX_MAX_DATARATE );
}
case PHY_DEF_TX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, DR_0, DR_5 );
}
case PHY_RX_DR:
{
return RegionCommonValueInRange( verify->DatarateParams.Datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE );
}
case PHY_DEF_TX_POWER:
case PHY_TX_POWER:
{
// Remark: switched min and max!
return RegionCommonValueInRange( verify->TxPower, US915_MAX_TX_POWER, US915_MIN_TX_POWER );
}
case PHY_DUTY_CYCLE:
{
return US915_DUTY_CYCLE_ENABLED;
}
case PHY_NB_JOIN_TRIALS:
{
if( verify->NbJoinTrials < 2 )
{
return false;
}
break;
}
default:
return false;
}
return true;
}
void RegionUS915ApplyCFList( ApplyCFListParams_t* applyCFList )
{
return;
}
bool RegionUS915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet )
{
uint8_t nbChannels = RegionCommonCountChannels( chanMaskSet->ChannelsMaskIn, 0, 4 );
// Check the number of active channels
if( ( nbChannels < 2 ) &&
( nbChannels > 0 ) )
{
return false;
}
switch( chanMaskSet->ChannelsMaskType )
{
case CHANNELS_MASK:
{
RegionCommonChanMaskCopy( ChannelsMask, chanMaskSet->ChannelsMaskIn, 6 );
for( uint8_t i = 0; i < 6; i++ )
{ // Copy-And the channels mask
ChannelsMaskRemaining[i] &= ChannelsMask[i];
}
break;
}
case CHANNELS_DEFAULT_MASK:
{
RegionCommonChanMaskCopy( ChannelsDefaultMask, chanMaskSet->ChannelsMaskIn, 6 );
break;
}
default:
return false;
}
return true;
}
bool RegionUS915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter )
{
bool adrAckReq = false;
int8_t datarate = adrNext->Datarate;
int8_t txPower = adrNext->TxPower;
GetPhyParams_t getPhy;
PhyParam_t phyParam;
// Report back the adr ack counter
*adrAckCounter = adrNext->AdrAckCounter;
if( adrNext->AdrEnabled == true )
{
if( datarate == US915_TX_MIN_DATARATE )
{
*adrAckCounter = 0;
adrAckReq = false;
}
else
{
if( adrNext->AdrAckCounter >= US915_ADR_ACK_LIMIT )
{
adrAckReq = true;
txPower = US915_MAX_TX_POWER;
}
else
{
adrAckReq = false;
}
if( adrNext->AdrAckCounter >= ( US915_ADR_ACK_LIMIT + US915_ADR_ACK_DELAY ) )
{
if( ( adrNext->AdrAckCounter % US915_ADR_ACK_DELAY ) == 1 )
{
// Decrease the datarate
getPhy.Attribute = PHY_NEXT_LOWER_TX_DR;
getPhy.Datarate = datarate;
getPhy.UplinkDwellTime = adrNext->UplinkDwellTime;
phyParam = RegionUS915GetPhyParam( &getPhy );
datarate = phyParam.Value;
if( datarate == US915_TX_MIN_DATARATE )
{
// We must set adrAckReq to false as soon as we reach the lowest datarate
adrAckReq = false;
if( adrNext->UpdateChanMask == true )
{
// Re-enable default channels
ChannelsMask[0] = 0xFFFF;
ChannelsMask[1] = 0xFFFF;
ChannelsMask[2] = 0xFFFF;
ChannelsMask[3] = 0xFFFF;
ChannelsMask[4] = 0x00FF;
ChannelsMask[5] = 0x0000;
}
}
}
}
}
}
*drOut = datarate;
*txPowOut = txPower;
return adrAckReq;
}
void RegionUS915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams )
{
double tSymbol = 0.0;
uint32_t radioWakeUpTime;
rxConfigParams->Datarate = datarate;
rxConfigParams->Bandwidth = GetBandwidth( datarate );
if( datarate == DR_7 )
{ // FSK
tSymbol = RegionCommonComputeSymbolTimeFsk( DataratesUS915[datarate] );
}
else
{ // LoRa
tSymbol = RegionCommonComputeSymbolTimeLoRa( DataratesUS915[datarate], BandwidthsUS915[datarate] );
}
radioWakeUpTime = Radio.GetRadioWakeUpTime( );
RegionCommonComputeRxWindowParameters( tSymbol, minRxSymbols, rxError, radioWakeUpTime, &rxConfigParams->WindowTimeout, &rxConfigParams->WindowOffset );
}
bool RegionUS915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
int8_t dr = rxConfig->Datarate;
uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
if( Radio.GetStatus( ) != RF_IDLE )
{
return false;
}
if( rxConfig->Window == 0 )
{
// Apply window 1 frequency
frequency = US915_FIRST_RX1_CHANNEL + ( rxConfig->Channel % 8 ) * US915_STEPWIDTH_RX1_CHANNEL;
}
// Read the physical datarate from the datarates table
phyDr = DataratesUS915[dr];
Radio.SetChannel( frequency );
// Radio configuration
Radio.SetRxConfig( MODEM_LORA, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
if( rxConfig->RepeaterSupport == true )
{
maxPayload = MaxPayloadOfDatarateRepeaterUS915[dr];
}
else
{
maxPayload = MaxPayloadOfDatarateUS915[dr];
}
Radio.SetMaxPayloadLength( MODEM_LORA, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
DBG_PRINTF("RX on freq %d Hz at DR %d\n\r", frequency, dr);
*datarate = (uint8_t) dr;
return true;
}
bool RegionUS915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
{
int8_t phyDr = DataratesUS915[txConfig->Datarate];
int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, Bands[Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, ChannelsMask );
uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
int8_t phyTxPower = 0;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, US915_DEFAULT_MAX_ERP, 0 );
Radio.SetChannel( Channels[txConfig->Channel].Frequency );
Radio.SetMaxPayloadLength( MODEM_LORA, txConfig->PktLen );
Radio.SetTxConfig( MODEM_LORA, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 3e3 );
DBG_PRINTF("TX on freq %d Hz at DR %d\n\r", Channels[txConfig->Channel].Frequency, txConfig->Datarate);
*txTimeOnAir = Radio.TimeOnAir( MODEM_LORA, txConfig->PktLen );
*txPower = txPowerLimited;
return true;
}
uint8_t RegionUS915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed )
{
uint8_t status = 0x07;
LinkAdrParams_t linkAdrParams;
uint8_t nextIndex = 0;
uint8_t bytesProcessed = 0;
uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 };
// Initialize local copy of channels mask
RegionCommonChanMaskCopy( channelsMask, ChannelsMask, 6 );
while( bytesProcessed < linkAdrReq->PayloadSize )
{
nextIndex = RegionCommonParseLinkAdrReq( &( linkAdrReq->Payload[bytesProcessed] ), &linkAdrParams );
if( nextIndex == 0 )
break; // break loop, since no more request has been found
// Update bytes processed
bytesProcessed += nextIndex;
// Revert status, as we only check the last ADR request for the channel mask KO
status = 0x07;
if( linkAdrParams.ChMaskCtrl == 6 )
{
// Enable all 125 kHz channels
channelsMask[0] = 0xFFFF;
channelsMask[1] = 0xFFFF;
channelsMask[2] = 0xFFFF;
channelsMask[3] = 0xFFFF;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask;
}
else if( linkAdrParams.ChMaskCtrl == 7 )
{
// Disable all 125 kHz channels
channelsMask[0] = 0x0000;
channelsMask[1] = 0x0000;
channelsMask[2] = 0x0000;
channelsMask[3] = 0x0000;
// Apply chMask to channels 64 to 71
channelsMask[4] = linkAdrParams.ChMask;
}
else if( linkAdrParams.ChMaskCtrl == 5 )
{
// RFU
status &= 0xFE; // Channel mask KO
}
else
{
channelsMask[linkAdrParams.ChMaskCtrl] = linkAdrParams.ChMask;
}
}
// FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels
if( ( linkAdrParams.Datarate < DR_4 ) && ( RegionCommonCountChannels( channelsMask, 0, 4 ) < 2 ) )
{
status &= 0xFE; // Channel mask KO
}
// Verify datarate
if( RegionCommonChanVerifyDr( US915_MAX_NB_CHANNELS, channelsMask, linkAdrParams.Datarate, US915_TX_MIN_DATARATE, US915_TX_MAX_DATARATE, Channels ) == false )
{
status &= 0xFD; // Datarate KO
}
// Verify tx power
if( RegionCommonValueInRange( linkAdrParams.TxPower, US915_MAX_TX_POWER, US915_MIN_TX_POWER ) == 0 )
{
// Verify if the maximum TX power is exceeded
if( US915_MAX_TX_POWER > linkAdrParams.TxPower )
{ // Apply maximum TX power. Accept TX power.
linkAdrParams.TxPower = US915_MAX_TX_POWER;
}
else
{
status &= 0xFB; // TxPower KO
}
}
// Update channelsMask if everything is correct
if( status == 0x07 )
{
if( linkAdrParams.NbRep == 0 )
{ // Value of 0 is not allowed, revert to default.
linkAdrParams.NbRep = 1;
}
// Copy Mask
RegionCommonChanMaskCopy( ChannelsMask, channelsMask, 6 );
ChannelsMaskRemaining[0] &= ChannelsMask[0];
ChannelsMaskRemaining[1] &= ChannelsMask[1];
ChannelsMaskRemaining[2] &= ChannelsMask[2];
ChannelsMaskRemaining[3] &= ChannelsMask[3];
ChannelsMaskRemaining[4] = ChannelsMask[4];
ChannelsMaskRemaining[5] = ChannelsMask[5];
}
// Update status variables
*drOut = linkAdrParams.Datarate;
*txPowOut = linkAdrParams.TxPower;
*nbRepOut = linkAdrParams.NbRep;
*nbBytesParsed = bytesProcessed;
return status;
}
uint8_t RegionUS915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq )
{
uint8_t status = 0x07;
uint32_t freq = rxParamSetupReq->Frequency;
// Verify radio frequency
if( ( Radio.CheckRfFrequency( freq ) == false ) ||
( freq < US915_FIRST_RX1_CHANNEL ) ||
( freq > US915_LAST_RX1_CHANNEL ) ||
( ( ( freq - ( uint32_t ) US915_FIRST_RX1_CHANNEL ) % ( uint32_t ) US915_STEPWIDTH_RX1_CHANNEL ) != 0 ) )
{
status &= 0xFE; // Channel frequency KO
}
// Verify datarate
if( RegionCommonValueInRange( rxParamSetupReq->Datarate, US915_RX_MIN_DATARATE, US915_RX_MAX_DATARATE ) == false )
{
status &= 0xFD; // Datarate KO
}
if( ( RegionCommonValueInRange( rxParamSetupReq->Datarate, DR_5, DR_7 ) == true ) ||
( rxParamSetupReq->Datarate > DR_13 ) )
{
status &= 0xFD; // Datarate KO
}
// Verify datarate offset
if( RegionCommonValueInRange( rxParamSetupReq->DrOffset, US915_MIN_RX1_DR_OFFSET, US915_MAX_RX1_DR_OFFSET ) == false )
{
status &= 0xFB; // Rx1DrOffset range KO
}
return status;
}
uint8_t RegionUS915NewChannelReq( NewChannelReqParams_t* newChannelReq )
{
// Datarate and frequency KO
return 0;
}
int8_t RegionUS915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq )
{
return -1;
}
uint8_t RegionUS915DlChannelReq( DlChannelReqParams_t* dlChannelReq )
{
return 0;
}
int8_t RegionUS915AlternateDr( AlternateDrParams_t* alternateDr )
{
int8_t datarate = 0;
// Re-enable 500 kHz default channels
ChannelsMask[4] = 0x00FF;
if( ( alternateDr->NbTrials & 0x01 ) == 0x01 )
{
datarate = DR_4;
}
else
{
datarate = DR_0;
}
return datarate;
}
void RegionUS915CalcBackOff( CalcBackOffParams_t* calcBackOff )
{
uint8_t channel = calcBackOff->Channel;
uint16_t joinDutyCycle = 0;
if( calcBackOff->Joined == false )
{
// Get the join duty cycle
joinDutyCycle = RegionCommonGetJoinDc( calcBackOff->ElapsedTime );
// Apply band time-off.
Bands[Channels[channel].Band].TimeOff = calcBackOff->TxTimeOnAir * joinDutyCycle - calcBackOff->TxTimeOnAir;
}
else
{
Bands[Channels[channel].Band].TimeOff = 0;
}
}
bool RegionUS915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTx = 0;
uint8_t enabledChannels[US915_MAX_NB_CHANNELS] = { 0 };
TimerTime_t nextTxDelay = 0;
// Count 125kHz channels
if( RegionCommonCountChannels( ChannelsMaskRemaining, 0, 4 ) == 0 )
{ // Reactivate default channels
RegionCommonChanMaskCopy( ChannelsMaskRemaining, ChannelsMask, 4 );
}
// Check other channels
if( nextChanParams->Datarate >= DR_4 )
{
if( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 )
{
ChannelsMaskRemaining[4] = ChannelsMask[4];
}
}
if( nextChanParams->AggrTimeOff <= TimerGetElapsedTime( nextChanParams->LastAggrTx ) )
{
// Reset Aggregated time off
*aggregatedTimeOff = 0;
// Update bands Time OFF
nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, Bands, US915_MAX_NB_BANDS );
// Search how many channels are enabled
nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Datarate,
ChannelsMaskRemaining, Channels,
Bands, enabledChannels, &delayTx );
}
else
{
delayTx++;
nextTxDelay = nextChanParams->AggrTimeOff - TimerGetElapsedTime( nextChanParams->LastAggrTx );
}
if( nbEnabledChannels > 0 )
{
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];
// Disable the channel in the mask
RegionCommonChanDisable( ChannelsMaskRemaining, *channel, US915_MAX_NB_CHANNELS - 8 );
*time = 0;
return true;
}
else
{
if( delayTx > 0 )
{
// Delay transmission due to AggregatedTimeOff or to a band time off
*time = nextTxDelay;
return true;
}
// Datarate not supported by any channel
*time = 0;
return false;
}
}
LoRaMacStatus_t RegionUS915ChannelAdd( ChannelAddParams_t* channelAdd )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
bool RegionUS915ChannelsRemove( ChannelRemoveParams_t* channelRemove )
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
void RegionUS915SetContinuousWave( ContinuousWaveParams_t* continuousWave )
{
int8_t txPowerLimited = LimitTxPower( continuousWave->TxPower, Bands[Channels[continuousWave->Channel].Band].TxMaxPower, continuousWave->Datarate, ChannelsMask );
int8_t phyTxPower = 0;
uint32_t frequency = Channels[continuousWave->Channel].Frequency;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, US915_DEFAULT_MAX_ERP, 0 );
Radio.SetTxContinuousWave( frequency, phyTxPower, continuousWave->Timeout );
}
uint8_t RegionUS915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset )
{
int8_t datarate = DatarateOffsetsUS915[dr][drOffset];
if( datarate < 0 )
{
datarate = DR_0;
}
return datarate;
}

View file

@ -0,0 +1,452 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*!
* \file RegionUS915.h
*
* \brief Region definition for US915
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup REGIONUS915 Region US915
* Implementation according to LoRaWAN Specification v1.0.2.
* \{
*/
#ifndef __REGION_US915_H__
#define __REGION_US915_H__
/*!
* LoRaMac maximum number of channels
*/
#define US915_MAX_NB_CHANNELS 72
/*!
* Minimal datarate that can be used by the node
*/
#define US915_TX_MIN_DATARATE DR_0
/*!
* Maximal datarate that can be used by the node
*/
#define US915_TX_MAX_DATARATE DR_4
/*!
* Minimal datarate that can be used by the node
*/
#define US915_RX_MIN_DATARATE DR_8
/*!
* Maximal datarate that can be used by the node
*/
#define US915_RX_MAX_DATARATE DR_13
/*!
* Default datarate used by the node
*/
#define US915_DEFAULT_DATARATE DR_0
/*!
* Minimal Rx1 receive datarate offset
*/
#define US915_MIN_RX1_DR_OFFSET 0
/*!
* Maximal Rx1 receive datarate offset
*/
#define US915_MAX_RX1_DR_OFFSET 3
/*!
* Default Rx1 receive datarate offset
*/
#define US915_DEFAULT_RX1_DR_OFFSET 0
/*!
* Minimal Tx output power that can be used by the node
*/
#define US915_MIN_TX_POWER TX_POWER_10
/*!
* Maximal Tx output power that can be used by the node
*/
#define US915_MAX_TX_POWER TX_POWER_0
/*!
* Default Tx output power used by the node
*/
#define US915_DEFAULT_TX_POWER TX_POWER_0
/*!
* Default Max ERP
*/
#define US915_DEFAULT_MAX_ERP 30.0f
/*!
* ADR Ack limit
*/
#define US915_ADR_ACK_LIMIT 64
/*!
* ADR Ack delay
*/
#define US915_ADR_ACK_DELAY 32
/*!
* Enabled or disabled the duty cycle
*/
#define US915_DUTY_CYCLE_ENABLED 0
/*!
* Maximum RX window duration
*/
#define US915_MAX_RX_WINDOW 3000
/*!
* Receive delay 1
*/
#define US915_RECEIVE_DELAY1 1000
/*!
* Receive delay 2
*/
#define US915_RECEIVE_DELAY2 2000
/*!
* Join accept delay 1
*/
#define US915_JOIN_ACCEPT_DELAY1 5000
/*!
* Join accept delay 2
*/
#define US915_JOIN_ACCEPT_DELAY2 6000
/*!
* Maximum frame counter gap
*/
#define US915_MAX_FCNT_GAP 16384
/*!
* Ack timeout
*/
#define US915_ACKTIMEOUT 2000
/*!
* Random ack timeout limits
*/
#define US915_ACK_TIMEOUT_RND 1000
/*!
* Second reception window channel frequency definition.
*/
#define US915_RX_WND_2_FREQ 923300000
/*!
* Second reception window channel datarate definition.
*/
#define US915_RX_WND_2_DR DR_8
/*!
* LoRaMac maximum number of bands
*/
#define US915_MAX_NB_BANDS 1
/*!
* Band 0 definition
* { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff }
*/
#define US915_BAND0 { 1, US915_MAX_TX_POWER, 0, 0 } // 100.0 %
/*!
* Defines the first channel for RX window 1 for US band
*/
#define US915_FIRST_RX1_CHANNEL ( (uint32_t) 923300000 )
/*!
* Defines the last channel for RX window 1 for US band
*/
#define US915_LAST_RX1_CHANNEL ( (uint32_t) 927500000 )
/*!
* Defines the step width of the channels for RX window 1
*/
#define US915_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600000 )
/*!
* Data rates table definition
*/
static const uint8_t DataratesUS915[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 };
/*!
* Bandwidths table definition in Hz
*/
static const uint32_t BandwidthsUS915[] = { 125000, 125000, 125000, 125000, 500000, 0, 0, 0, 500000, 500000, 500000, 500000, 500000, 500000, 0, 0 };
/*!
* Up/Down link data rates offset definition
*/
static const int8_t DatarateOffsetsUS915[5][4] =
{
{ DR_10, DR_9 , DR_8 , DR_8 }, // DR_0
{ DR_11, DR_10, DR_9 , DR_8 }, // DR_1
{ DR_12, DR_11, DR_10, DR_9 }, // DR_2
{ DR_13, DR_12, DR_11, DR_10 }, // DR_3
{ DR_13, DR_13, DR_12, DR_11 }, // DR_4
};
/*!
* Maximum payload with respect to the datarate index. Cannot operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateUS915[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 };
/*!
* Maximum payload with respect to the datarate index. Can operate with repeater.
*/
static const uint8_t MaxPayloadOfDatarateRepeaterUS915[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 };
/*!
* \brief The function gets a value of a specific phy attribute.
*
* \param [IN] getPhy Pointer to the function parameters.
*
* \retval Returns a structure containing the PHY parameter.
*/
PhyParam_t RegionUS915GetPhyParam( GetPhyParams_t* getPhy );
/*!
* \brief Updates the last TX done parameters of the current channel.
*
* \param [IN] txDone Pointer to the function parameters.
*/
void RegionUS915SetBandTxDone( SetBandTxDoneParams_t* txDone );
/*!
* \brief Initializes the channels masks and the channels.
*
* \param [IN] type Sets the initialization type.
*/
void RegionUS915InitDefaults( InitType_t type );
/*!
* \brief Verifies a parameter.
*
* \param [IN] verify Pointer to the function parameters.
*
* \param [IN] type Sets the initialization type.
*
* \retval Returns true, if the parameter is valid.
*/
bool RegionUS915Verify( VerifyParams_t* verify, PhyAttribute_t phyAttribute );
/*!
* \brief The function parses the input buffer and sets up the channels of the
* CF list.
*
* \param [IN] applyCFList Pointer to the function parameters.
*/
void RegionUS915ApplyCFList( ApplyCFListParams_t* applyCFList );
/*!
* \brief Sets a channels mask.
*
* \param [IN] chanMaskSet Pointer to the function parameters.
*
* \retval Returns true, if the channels mask could be set.
*/
bool RegionUS915ChanMaskSet( ChanMaskSetParams_t* chanMaskSet );
/*!
* \brief Calculates the next datarate to set, when ADR is on or off.
*
* \param [IN] adrNext Pointer to the function parameters.
*
* \param [OUT] drOut The calculated datarate for the next TX.
*
* \param [OUT] txPowOut The TX power for the next TX.
*
* \param [OUT] adrAckCounter The calculated ADR acknowledgement counter.
*
* \retval Returns true, if an ADR request should be performed.
*/
bool RegionUS915AdrNext( AdrNextParams_t* adrNext, int8_t* drOut, int8_t* txPowOut, uint32_t* adrAckCounter );
/*!
* Computes the Rx window timeout and offset.
*
* \param [IN] datarate Rx window datarate index to be used
*
* \param [IN] minRxSymbols Minimum required number of symbols to detect an Rx frame.
*
* \param [IN] rxError System maximum timing error of the receiver. In milliseconds
* The receiver will turn on in a [-rxError : +rxError] ms
* interval around RxOffset
*
* \param [OUT]rxConfigParams Returns updated WindowTimeout and WindowOffset fields.
*/
void RegionUS915ComputeRxWindowParameters( int8_t datarate, uint8_t minRxSymbols, uint32_t rxError, RxConfigParams_t *rxConfigParams );
/*!
* \brief Configuration of the RX windows.
*
* \param [IN] rxConfig Pointer to the function parameters.
*
* \param [OUT] datarate The datarate index which was set.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionUS915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate );
/*!
* \brief TX configuration.
*
* \param [IN] txConfig Pointer to the function parameters.
*
* \param [OUT] txPower The tx power index which was set.
*
* \param [OUT] txTimeOnAir The time-on-air of the frame.
*
* \retval Returns true, if the configuration was applied successfully.
*/
bool RegionUS915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir );
/*!
* \brief The function processes a Link ADR Request.
*
* \param [IN] linkAdrReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915LinkAdrReq( LinkAdrReqParams_t* linkAdrReq, int8_t* drOut, int8_t* txPowOut, uint8_t* nbRepOut, uint8_t* nbBytesParsed );
/*!
* \brief The function processes a RX Parameter Setup Request.
*
* \param [IN] rxParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915RxParamSetupReq( RxParamSetupReqParams_t* rxParamSetupReq );
/*!
* \brief The function processes a Channel Request.
*
* \param [IN] newChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915NewChannelReq( NewChannelReqParams_t* newChannelReq );
/*!
* \brief The function processes a TX ParamSetup Request.
*
* \param [IN] txParamSetupReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
* Returns -1, if the functionality is not implemented. In this case, the end node
* shall not process the command.
*/
int8_t RegionUS915TxParamSetupReq( TxParamSetupReqParams_t* txParamSetupReq );
/*!
* \brief The function processes a DlChannel Request.
*
* \param [IN] dlChannelReq Pointer to the function parameters.
*
* \retval Returns the status of the operation, according to the LoRaMAC specification.
*/
uint8_t RegionUS915DlChannelReq( DlChannelReqParams_t* dlChannelReq );
/*!
* \brief Alternates the datarate of the channel for the join request.
*
* \param [IN] alternateDr Pointer to the function parameters.
*
* \retval Datarate to apply.
*/
int8_t RegionUS915AlternateDr( AlternateDrParams_t* alternateDr );
/*!
* \brief Calculates the back-off time.
*
* \param [IN] calcBackOff Pointer to the function parameters.
*/
void RegionUS915CalcBackOff( CalcBackOffParams_t* calcBackOff );
/*!
* \brief Searches and set the next random available channel
*
* \param [OUT] channel Next channel to use for TX.
*
* \param [OUT] time Time to wait for the next transmission according to the duty
* cycle.
*
* \param [OUT] aggregatedTimeOff Updates the aggregated time off.
*
* \retval Function status [1: OK, 0: Unable to find a channel on the current datarate]
*/
bool RegionUS915NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff );
/*!
* \brief Adds a channel.
*
* \param [IN] channelAdd Pointer to the function parameters.
*
* \retval Status of the operation.
*/
LoRaMacStatus_t RegionUS915ChannelAdd( ChannelAddParams_t* channelAdd );
/*!
* \brief Removes a channel.
*
* \param [IN] channelRemove Pointer to the function parameters.
*
* \retval Returns true, if the channel was removed successfully.
*/
bool RegionUS915ChannelsRemove( ChannelRemoveParams_t* channelRemove );
/*!
* \brief Sets the radio into continuous wave mode.
*
* \param [IN] continuousWave Pointer to the function parameters.
*/
void RegionUS915SetContinuousWave( ContinuousWaveParams_t* continuousWave );
/*!
* \brief Computes new datarate according to the given offset
*
* \param [IN] downlinkDwellTime Downlink dwell time configuration. 0: No limit, 1: 400ms
*
* \param [IN] dr Current datarate
*
* \param [IN] drOffset Offset to be applied
*
* \retval newDr Computed datarate.
*/
uint8_t RegionUS915ApplyDrOffset( uint8_t downlinkDwellTime, int8_t dr, int8_t drOffset );
/*! \} defgroup REGIONUS915 */
#endif // __REGION_US915_H__

View file

@ -0,0 +1,359 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Generic radio driver definition
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
#ifndef __RADIO_H__
#define __RADIO_H__
/*!
* Radio driver supported modems
*/
typedef enum
{
MODEM_FSK = 0,
MODEM_LORA,
}RadioModems_t;
/*!
* Radio driver internal state machine states definition
*/
typedef enum
{
RF_IDLE = 0, //!< The radio is idle
RF_RX_RUNNING, //!< The radio is in reception state
RF_TX_RUNNING, //!< The radio is in transmission state
RF_CAD, //!< The radio is doing channel activity detection
}RadioState_t;
/*!
* \brief Radio driver callback functions
*/
typedef struct
{
/*!
* \brief Tx Done callback prototype.
*/
void ( *TxDone )( void );
/*!
* \brief Tx Timeout callback prototype.
*/
void ( *TxTimeout )( void );
/*!
* \brief Rx Done callback prototype.
*
* \param [IN] payload Received buffer pointer
* \param [IN] size Received buffer size
* \param [IN] rssi RSSI value computed while receiving the frame [dBm]
* \param [IN] snr Raw SNR value given by the radio hardware
* FSK : N/A ( set to 0 )
* LoRa: SNR value in dB
*/
void ( *RxDone )( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
/*!
* \brief Rx Timeout callback prototype.
*/
void ( *RxTimeout )( void );
/*!
* \brief Rx Error callback prototype.
*/
void ( *RxError )( void );
/*!
* \brief FHSS Change Channel callback prototype.
*
* \param [IN] currentChannel Index number of the current channel
*/
void ( *FhssChangeChannel )( uint8_t currentChannel );
/*!
* \brief CAD Done callback prototype.
*
* \param [IN] channelDetected Channel Activity detected during the CAD
*/
void ( *CadDone ) ( bool channelActivityDetected );
}RadioEvents_t;
/*!
* \brief Radio driver definition
*/
struct Radio_s
{
/*!
* \brief Initializes the radio
*
* \param [IN] events Structure containing the driver callback functions
*/
void ( *IoInit )( void );
/*!
* \brief Initializes the radio
*
* \param [IN] events Structure containing the driver callback functions
*/
void ( *IoDeInit )( void );
/*!
* \brief Initializes the radio
*
* \param [IN] events Structure containing the driver callback functions
* \param [OUT] returns radioWakeUpTime
*/
uint32_t ( *Init )( RadioEvents_t *events );
/*!
* Return current radio status
*
* \param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
*/
RadioState_t ( *GetStatus )( void );
/*!
* \brief Configures the radio with the given modem
*
* \param [IN] modem Modem to be used [0: FSK, 1: LoRa]
*/
void ( *SetModem )( RadioModems_t modem );
/*!
* \brief Sets the channel frequency
*
* \param [IN] freq Channel RF frequency
*/
void ( *SetChannel )( uint32_t freq );
/*!
* \brief Sets the channels configuration
*
* \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [IN] freq Channel RF frequency
* \param [IN] rssiThresh RSSI threshold
* \param [IN] maxCarrierSenseTime Max time while the RSSI is measured
*
* \retval isFree [true: Channel is free, false: Channel is not free]
*/
bool ( *IsChannelFree )( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
/*!
* \brief Generates a 32 bits random value based on the RSSI readings
*
* \remark This function sets the radio in LoRa modem mode and disables
* all interrupts.
* After calling this function either Radio.SetRxConfig or
* Radio.SetTxConfig functions must be called.
*
* \retval randomValue 32 bits random value
*/
uint32_t ( *Random )( void );
/*!
* \brief Sets the reception parameters
*
* \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [IN] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [IN] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [IN] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only)
* FSK : >= 2600 and <= 250000 Hz
* LoRa: N/A ( set to 0 )
* \param [IN] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [IN] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [IN] payloadLen Sets payload length when fixed length is used
* \param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [IN] HopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [IN] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [IN] rxContinuous Sets the reception in continuous mode
* [false: single mode, true: continuous mode]
*/
void ( *SetRxConfig )( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint32_t bandwidthAfc, uint16_t preambleLen,
uint16_t symbTimeout, bool fixLen,
uint8_t payloadLen,
bool crcOn, bool FreqHopOn, uint8_t HopPeriod,
bool iqInverted, bool rxContinuous );
/*!
* \brief Sets the transmission parameters
*
* \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [IN] power Sets the output power [dBm]
* \param [IN] fdev Sets the frequency deviation (FSK only)
* FSK : [Hz]
* LoRa: 0
* \param [IN] bandwidth Sets the bandwidth (LoRa only)
* FSK : 0
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \param [IN] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \param [IN] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \param [IN] preambleLen Sets the preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
* \param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON]
* \param [IN] FreqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \param [IN] HopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \param [IN] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \param [IN] timeout Transmission timeout [ms]
*/
void ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev,
uint32_t bandwidth, uint32_t datarate,
uint8_t coderate, uint16_t preambleLen,
bool fixLen, bool crcOn, bool FreqHopOn,
uint8_t HopPeriod, bool iqInverted, uint32_t timeout );
/*!
* \brief Checks if the given RF frequency is supported by the hardware
*
* \param [IN] frequency RF frequency to be checked
* \retval isSupported [true: supported, false: unsupported]
*/
bool ( *CheckRfFrequency )( uint32_t frequency );
/*!
* \brief Computes the packet time on air in ms for the given payload
*
* \Remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [IN] pktLen Packet payload length
*
* \retval airTime Computed airTime (ms) for the given packet payload length
*/
uint32_t ( *TimeOnAir )( RadioModems_t modem, uint8_t pktLen );
/*!
* \brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
*
* \param [IN]: buffer Buffer pointer
* \param [IN]: size Buffer size
*/
void ( *Send )( uint8_t *buffer, uint8_t size );
/*!
* \brief Sets the radio in sleep mode
*/
void ( *Sleep )( void );
/*!
* \brief Sets the radio in standby mode
*/
void ( *Standby )( void );
/*!
* \brief Sets the radio in reception mode for the given time
* \param [IN] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
void ( *Rx )( uint32_t timeout );
/*!
* \brief Start a Channel Activity Detection
*/
void ( *StartCad )( void );
/*!
* \brief Sets the radio in continuous wave transmission mode
*
* \param [IN]: freq Channel RF frequency
* \param [IN]: power Sets the output power [dBm]
* \param [IN]: time Transmission mode timeout [s]
*/
void ( *SetTxContinuousWave )( uint32_t freq, int8_t power, uint16_t time );
/*!
* \brief Reads the current RSSI value
*
* \retval rssiValue Current RSSI value in [dBm]
*/
int16_t ( *Rssi )( RadioModems_t modem );
/*!
* \brief Writes the radio register at the specified address
*
* \param [IN]: addr Register address
* \param [IN]: data New register value
*/
void ( *Write )( uint8_t addr, uint8_t data );
/*!
* \brief Reads the radio register at the specified address
*
* \param [IN]: addr Register address
* \retval data Register value
*/
uint8_t ( *Read )( uint8_t addr );
/*!
* \brief Writes multiple radio registers starting at address
*
* \param [IN] addr First Radio register address
* \param [IN] buffer Buffer containing the new register's values
* \param [IN] size Number of registers to be written
*/
void ( *WriteBuffer )( uint8_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Reads multiple radio registers starting at address
*
* \param [IN] addr First Radio register address
* \param [OUT] buffer Buffer where to copy the registers data
* \param [IN] size Number of registers to be read
*/
void ( *ReadBuffer )( uint8_t addr, uint8_t *buffer, uint8_t size );
/*!
* \brief Set synchro word in radio
*
* \param [IN] data THe syncword
*/
void ( *SetSyncWord )( uint8_t data );
/*!
* \brief Sets the maximum payload length.
*
* \param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \param [IN] max Maximum payload length in bytes
*/
void ( *SetMaxPayloadLength )( RadioModems_t modem, uint8_t max );
/*!
* \brief Service to get the radio wake-up time.
*
* \retval Value of the radio wake-up time.
*/
uint32_t ( *GetRadioWakeUpTime ) ( void );
};
/*!
* \brief Radio driver
*
* \remark This variable is defined and initialized in the specific radio
* board implementation
*/
extern const struct Radio_s Radio;
#endif // __RADIO_H__

View file

@ -0,0 +1,723 @@
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
LoRaWAN endpoint stack implementation and example projects.
=====================================
1. Introduction
----------------
The aim of this project is to show an example of the endpoint LoRaWAN stack implementation.
This LoRaWAN stack is an EU868 and US915 bands Class A and Class C endpoint implementation
fully compatible with LoRaWAN 1.0.1 specification.
Each LoRaWAN application example includes the LoRaWAN certification protocol implementation.
SX1272/76 radio drivers are also provided.
In case only point to point links are required a Ping-Pong application is provided as example.
*The LoRaWAN stack API documentation can be found at: http://stackforce.github.io/LoRaMac-doc/*
**Note 1:**
*A port of this project can be found on [MBED Semtech Team page](http://developer.mbed.org/teams/Semtech/)*
*The example projects are:*
1. [LoRaWAN-demo-72](http://developer.mbed.org/teams/Semtech/code/LoRaWAN-demo-72/)
2. [LoRaWAN-demo-76](http://developer.mbed.org/teams/Semtech/code/LoRaWAN-demo-76/)
2. System schematic and definitions
------------------------------------
The available supported hardware platforms schematics can be found in the Doc directory.
3. Acknowledgments
-------------------
The mbed (https://mbed.org/) project was used at the beginning as source of
inspiration.
This program uses the AES algorithm implementation (http://www.gladman.me.uk/)
by Brian Gladman.
This program uses the CMAC algorithm implementation
(http://www.cse.chalmers.se/research/group/dcs/masters/contikisec/) by
Lander Casado, Philippas Tsigas.
4. Dependencies
----------------
This program depends on specific hardware platforms. Currently the supported
platforms are:
- LoRaMote
MCU : STM32L151CB - 128K FLASH, 10K RAM, Timers, SPI, I2C,
USART,
USB 2.0 full-speed device/host/OTG controller,
DAC, ADC, DMA
RADIO : SX1272
ANTENNA : Printed circuit antenna
BUTTONS : No
LEDS : 3
SENSORS : Proximity, Magnetic, 3 axis Accelerometer, Pressure,
Temperature
GPS : Yes, UP501 module
EXTENSION HEADER : Yes, 20 pins
REMARK : The MCU and Radio are on an IMST iM880A module
- MoteII
MCU : STM32L051C8 - 64K FLASH, 8K RAM, Timers, SPI, I2C,
USART,
USB 2.0 full-speed device/host/OTG controller (Not used),
DAC, ADC, DMA
RADIO : SX1272
ANTENNA : Printed circuit antenna
BUTTONS : 3
LEDS : 3
SENSORS : Magnetic, 3 axis Accelerometer, Pressure,
Temperature
GPS : Yes, PAM7Q module
Display : OLED
ST-Link : Yes, MBED like
EXTENSION HEADER : Yes, 20 pins
REMARK : The MCU and Radio are on an IMST iM881A module
- NAMote72
MCU : STM32L152RC - 256K FLASH, 32K RAM, Timers, SPI, I2C,
USART,
USB 2.0 full-speed device/host/OTG controller (Not used),
DAC, ADC, DMA
RADIO : SX1272
ANTENNA : Printed circuit antenna
BUTTONS : No
LEDS : 4
SENSORS : Magnetic, 3 axis Accelerometer, Pressure,
Temperature
GPS : Yes, SIM39EA module
Display : OLED
ST-Link : Yes, MBED like
EXTENSION HEADER : Yes, Arduino connectors
REMARK : None
- SensorNode
MCU : STM32L151CBU6 - 128K FLASH, 16K RAM, Timers, SPI, I2C,
USART,
USB 2.0 full-speed device/host/OTG controller,
DAC, ADC, DMA
RADIO : SX1276
ANTENNA : Printed circuit antenna
BUTTONS : Power ON/OFF, General purpose button
LEDS : 3
SENSORS : Proximity, Magnetic, 3 axis Accelerometer, Pressure,
Temperature
GPS : Yes, SIM39EA module
EXTENSION No
REMARK : The MCU and Radio are on an NYMTEK Cherry-LCC module
- SK-iM880A ( IMST starter kit )
MCU : STM32L151CB - 128K FLASH, 10K RAM, Timers, SPI, I2C,
USART,
USB 2.0 full-speed device/host/OTG controller,
DAC, ADC, DMA
RADIO : SX1272
ANTENNA : Connector for external antenna
BUTTONS : 1 Reset, 3 buttons + 2 DIP-Switch
LEDS : 3
SENSORS : Potentiometer
GPS : Possible through pin header GPS module connection
SDCARD : No
EXTENSION HEADER : Yes, all IMST iM880A module pins
REMARK : None
5. Usage
---------
Projects for CooCox-CoIDE and Keil Integrated Development Environments are available.
One project is available per application and for each hardware platform in each
development environment. Different targets/configurations have been created in
the different projects in order to select different options such as the usage or
not of a bootloader and the radio frequency band to be used.
6. Changelog
-------------
2017-04-19, V4.3.2
* General (Last release based on LoRaWAN specification 1.0.1)
1. This version has passed EU868 and US915 LoRa-Alliance compliance tests.
2. GitHub reported issues corrections.
3. Added an algorithm to automatically compute the Rx windows parameters. (Window symbolTimeout and Offset from downlink expected time)
4. Added a workaround to reset the radio in case a TxTimeout occurs.
5. Modified FSK modem handling to use the provided symbolTimeout (1 symbol equals 1 byte) when in RxSingle mode.
6. Added newly defined TxCw(Tx Continuous Wave) certification protocol command.
7. Added a fix for an overflow issue that could happen with NmeaStringSize variable.
8. Improved GpioMcuInit function to first configure the output pin state before activating the pin.
* LoRaWAN
1. GitHub reported issues corrections.
2. Changed the AdrAckCounter handling as expected by the test houses.
3. Fix an issue where the node stopped transmitting.
4. Removed useless LoRaMacPayload buffer.
5. MAC layer indications handling simplification.
6. Relocate parameter settings from ResetMacParameters to the initialization.
2017-02-27, V4.3.1
* General
1. This version has passed EU868 and US915 LoRa-Alliance compliance tests.
2. Update the MAC layer in order to be LoRaWAN version 1.0.1 compliant (Mainly US915 bug fixes)
3. Removed api-v3 support from the project.
4. GitHub reported issues corrections.
5. Updated SensorNode projects according to the new MCU reference STM32L151CBU6. Bigger memories.
6. Addition of MoteII platform based on the IMST module iM881A (STM32L051C8)
7. Addition of NAMote72 platform
8. Correct compliance test protocol command 0x06 behaviour
9. Added TxCw (Tx continuous wave) LoRaWAN compliance protocol command.
10. Added TxContinuousWave support to the radio drivers.
11. Updated ST HAL drivers.
- STM32L1xx_HAL-Driver : V1.2.0
- STM32L0xx_HAL_Driver : V1.7.0
* LoRaWAN
1. US band corrections in order to pass the LoRaWAN certification.
2. GitHub reported issues corrections.
3. Add region CN470 support.
2016-06-22, V4.3.0
* General
1. This version has passed all LoRa-Alliance compliance tests.
2. Update the MAC layer in order to be LoRaWAN version 1.0.1 compliant
3. Applied to all application files the certification protocol change for LoRaWAN 1.0.1 compliance tests.
**REMARK**: api-v3 application files aren't updated.
4. Add radio RX_TIMEOUT irq clear into the irq handler.
5. Removed the end less loop from HAL_UART_ErrorCallback.
6. Update of the STM32L0 HAL to version 1.6.0
7. Consolidated the line endings across all project files.
Windows line endings has been choose for almost every file.
* LoRaWAN
1. Updated maximum payload size for US band.
2. Update datarate offset table for US band.
3. Make MAC commands sticky
4. Add retransmission back-off
5. Remove the TxPower limitation for US band on LoRaMacMibSetRequestConfirm function. The power will be limited anyway when the SendFrameOnChannel functions is called.
6. Issue(#81): Bug fix in function LoRaMacMlmeRequest case MLME_JOIN. Function will return LORAMAC_STATUS_BUSY in case the MAC is in status MAC_TX_DELAYED.
7. Add debug pin support to LoRaMote platform.
8. Updated and improved MPL3115 device driver.
9. Issue(#83): Bug fix in parameter validation
10. Issue(#84): Fix issue of CalibrateTimer function.
11. RTC driver major update
12. Applied pull request #87.
13. Add a function to verify the RX frequency of window 2 for US band.
14. Issue(#88): Bug fix in function PrepareFrame where repeated MAC commands were not handled correctly.
15. Bug fix in OnRadioRxDone. Node now drops frames on port 0 with fOpts > 0.
16. Bug fix in OnRadioRxDone. Node now receives frames with fOpts > 0 when no payload is present.
2016-05-13, V4.2.0
* General
1. This version has passed all LoRa-Alliance compliance tests.
2. Update STM32L1xx_HAL_Driver version to 1.5. Update related drivers and implementations accordingly.
**REMARK**: This change implies that the time base had to be changed from microseconds to milliseconds.
3. Corrected the frequency check condition for // ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth
4. Optimize radio drivers regarding FSK PER
5. Resolve issue when calling SX127xInit function more than once
6. Add a definition for the LoRaWAN device address. Add an IEEE_OUI for the LoRaWAN device EUI.
7. Add a definition for the default datarate.
8. Issue(#66) correction of functions SX1276SetOpMode and SX1272SetOpMode.
9. Issue(#68): Fix for low level RF switch control.
10. Increase RTC tick frequency for higher resolution.
11. Update the radio wake up time.
* LoRaWAN
1. Issue(#56) correction
2. Update channel mask handling for US915 hybrid mode to support any block in the channel mask.
3. Issue(#63) correct the maximum payload length in RX mode.
4. Fix Tx power setting loss for repeated join requests on US band.
5. Introduce individual MIN and MAX datarates for RX and TX.
6. Add the possibility to set and get the ChannelsDefaultDatarate.
7. Optimization of the RX symbol timeout.
8. Issue(#59): Add the possibility to set the uplink and downlink counter.
9. Replace definition LORAMAC_DEFAULT_DATARATE by ChannelsDefaultDatarate in LoRaMacChannelAdd.
10. Issue(#72): Fix of possible array overrun in LoRaMacChannelRemove.
11. Introduce a new status MAC_RX_ABORT. Reset MAC_TX_RUNNING only in OnMacStateCheckTimerEvent.
12. Accept MAC information of duplicated, confirmed downlinks.
13. Issue(#74): Drop frames with a downlink counter difference greater or equal to MAX_FCNT_GAP.
2016-03-10, V4.1.0
* General
1. This version has passed all mandatory LoRa-Alliance compliance tests.
*One of the optional tests is unsuccessful (FSK downlinks PER on Rx1 and Rx2 windows) and is currently under investigation.*
2. Removed support for Raisonance Ride7 IDE (Reduces the amount of work to be done at each new release)
3. Removed the Bleeper-72 and Bleeper-76 platforms support as these are now deprecated.
4. Application state machine. Relocate setting sleep state and update the duty cycle in compliance test mode.
5. Bug fix in TimerIrqHandler. Now, it is possible to insert timers in callback.
6. Changed TimerHwDelayMs function to be re-entrant.
7. Corrected FSK modem packets bigger than 64 bytes handling (Issue #36)
* LoRaWAN
1. Rename attribute nbRetries to NbTrials in structure McpsReqConfirmed_t. (Issue #37)
2. Updated implementation of SetNextChannel. Added enabling default channels in case of join request. (Issue #39)
3. Add missing documentation about MIB_REPEATER_SUPPORT. (Issue #42).
4. Add a new LoRaMacState to allow adding channels during TX procedure. (Issue #43)
5. Relocate the activation of LoRaMacFlags.Bits.McpsInd in OnRadioRxDone.
6. Add a new function PrepareRxDoneAbort to prepare a break-out of OnRadioRxDone in case of an error
7. Activate default channels in case all others are disabled. (Issue #39)
8. Bug fix in setting the default channel in case none is enabled.
9. SRV_MAC_NEW_CHANNEL_REQ MAC command added a fix to the macIndex variable on US915 band.
10. Start the MacStateCheckTimer in OnRxDone and related error cases with a short interval to handle events promptly. (Issue #44)
11. Reset status of NodeAckRequested if we received an ACK or in case of timeout.
12. Removed additional EU868 channels from the LoRaWAN implementation files. GitHub (Issue #49)
The creation of these additional channels has been moved to the application example.
13. Improved and corrected AdrNextDr function.
2015-12-18, V4.0.0
* General
1. STACKFORCE new API integration
2. Reverse the EUIs arrays in the MAC layer.
3. LoRaWAN certification protocol implementation
4. All reported issues and Pull requests have been addressed.
2015-10-06, V3.4.1
* General
1. Bug fixes
* LoRaWAN
1. Corrected downlink counter roll over management when several downlinks were missed.
2. Corrected the Radio maximum payload length management. Radio was filtering received frames with a length bigger than the transmitted one.
3. Applied Pull request #22 solution proposition.
2015-10-30, V3.4.0
* General
1. Changed all applications in order to have preprocessing definitions on top of the files and added relevant comments
2. Applications LED control is no more done into the timer callback functions but instead on the main while loop.
3. Added TimerStop function calls to each timer event callback.
4. Corrected timings comments. Timing values are most of the time us based.
5. Changed types names for stdint.h names. Helps on code portability
6. Renamed rand and srand to rand1 and srand1. Helps on code portability
7. Added some missing variables casts. Helps on code portability
8. Removed NULL definition from board.h
9. Added const variable attribute when necessary to functions prototypes
10. Moved ID1, ID2 and ID3 definition from board.h to board.c, usb-cdc-board.c and usb-dfu-board.c
11. Removed the definition of RAND_SEED. It has been replaced by a function named BoardGetRandomSeed
12. Renamed BoardMeasureBatterieLevel to BoardGetBatteryLevel
13. Added SetMaxPayloadLength API function to SX1272 and SX1276 radio drivers
14. Changed the name of Radio API Status function to GetStatus
15. AES/CMAC Changed types names for stdint.h names. Helps on code portability (Issue #20)
16. Moved __ffs function from utilities.h to spi-board.c. This function is only used there.
17. Utilities.c removed fputc function redefinition.
18. Replaced the usage of __IO attribute by volatile.
* LoRaWAN
1. Added support for the US915 band (Normal mode and hybrid mode. Hybrid mode is a temporary configuration up until servers support it automatically) (Issue #16)
2. Corrected and simplified the downlink sequence counter management.
3. Removed the usage of PACKED attribute for data structures.
4. Renamed LoRaMacEvent_t into LoRaMacCallbacks_t and added a function pointer for getting battery level status
5. Renamed LoRaMacSetDutyCycleOn into LoRaMacSetTestDutyCycleOn
6. Renamed LoRaMacSetMicTest into LoRaMacTestSetMic
7. Increased the PHY buffer size to 250
8. Removed IsChannelFree check on LoRaMacSetNextChannel function. LoRaWAN is an ALHOA protocol. (Pull request #8)
9. LoRaMacEventInfo.TxDatarate now returns LoRaWAN datarate (DR0 -> DR7) instead of (SF12 -> DF7)
10. Corrected channel mask management for EU868 band.
11. Corrected LoRaMacPrepareFrame behavior function when no applicative payload is present.
12. LoRaMac-board.h now implements the settings for the PHY layers specified by LoRaWAN 1.0 specification. ( EU433, CN780, EU868, US915 ) (Issue #19)
13. Added LORAMAC_MIN_RX1_DR_OFFSET and LORAMAC_MAX_RX1_DR_OFFSET definitions to LoRaMac-board.h. Can be different upon used PHY layer
14. Added the limitation of output power according to the number of enabled channels for US915 band.
15. Added the limitation of the applicative payload length according to the datarate. Does not yet take in account the MAC commands buffer. (Issue #15)
16. Corrected MacCommandBufferIndex management. (Issue #18)
2015-08-07, v3.3.0
* General
1. Added the support for LoRaWAN Class C devices.
2. Implemented the radios errata note workarounds. SX1276 errata 2.3 "Receiver Spurious Reception of a LoRa Signal" is not yet implemented.
3. Increased FSK SyncWord timeout value in order to listen for longer time if a down link is available or not. Makes FSK downlink more reliable.
4. Increased the UART USB FIFO buffer size in order to handle bigger chunks of data.
* LoRaWAN
1. Renamed data rates as per LoRaWAN specification.
2. Added the support for LoRaWAN Class C devices.
3. Handling of the MAC commands was done incorrectly the condition to verify the length of the buffer has changed from < to <=.
4. Added the possibility to change the channel mask and number of repetitions trough SRV_MAC_LINK_ADR_REQ command when ADR is disabled.
5. Corrected Rx1DrOffset management. In previous version DR1 was missing for all offsets.
6. Changed confirmed messages function to use default datarate when ADR control is off.
7. After a Join accept the node falls back to the default datarate. Enables the user to Join a network using a different datarate from its own default one.
8. Corrected default FSK channel frequency.
9. Solved a firmware freezing when one of the following situations arrived in OnRxDone callback: bad address, bad MIC, bad frame. (Pull request #10)
10. Moved the MAC commands processing to the right places. FOpts field before the Payload and Port 0 just after the decryption. (Pull request #9)
11. Weird conditions to check datarate on cmd mac SRV_MAC_NEW_CHANNEL_REQ (Pull request #7)
12. Ignore join accept message if already joined (Pull request #6)
13. Channel index verification should use OR on SRV_MAC_NEW_CHANNEL_REQ command (Pull request #5)
14. Corrected the CFList management on JoinAccept. The for loop indexes were wrong. (Pull request #4)
15. Correction of AES key size (Pull request #3)
2015-04-30, v3.2.0
* General
1. Updated LoRaMac implementation according to LoRaWAN R1.0 specification
2. General cosmetics corrections
3. Added the support of packed structures when using IAR tool chain
4. Timers: Added a function to get the time in us.
5. Timers: Added a typedef for time variables (TimerTime_t)
6. Radios: Changed the TimeOnAir radio function to return a uint32_t value instead of a double. The value is in us.
7. Radios: Corrected the 250 kHz bandwidth choice for the FSK modem
8. GPS: Added a function that returns if the GPS has a fix or not.
9. GPS: Changed the GetPosition functions to return a latitude and longitude of 0 and altitude of 65535 when no GPS fix.
* LoRaWAN
1. Removed support for previous LoRaMac/LoRaWAN specifications
2. Added missing MAC commands and updated others when necessary
* Corrected the Port 0 MAC commands decryption
* Changed the way the upper layer is notified. Now it is only notified
when all the operations are finished.
When a ClassA Tx cycle starts a timer is launched to check every second if everything is finished.
* Added a new parameter to LoRaMacEventFlags structure that indicates on which Rx window the data has been received.
* Added a new parameter to LoRaMacEventFlags structure that indicates if there is applicative data on the received payload.
* Corrected ADR MAC command behavior
* DutyCycle enforcement implementation (EU868 PHY only)
**REMARK 1** *The regulatory duty cycle enforcement is enabled by default
which means that for lower data rates the node may not transmit a new
frame as quickly as requested.
The formula used to compute the node idle time is*
*Toff = TimeOnAir / DutyCycle - TxTimeOnAir*
*Example:*
*A device just transmitted a 0.5 s long frame on one default channel.
This channel is in a sub-band allowing 1% duty-cycle. Therefore this
whole sub-band (868 MHz - 868.6 MHz) will be unavailable for 49.5 s.*
**REMARK 2** *The duty cycle enforcement can be disabled for test
purposes by calling the LoRaMacSetDutyCycleOn function with false
parameter.*
* Implemented aggregated duty cycle management
* Added a function to create new channels
* Implemented the missing features on the JoinAccept MAC command
* Updated LoRaMacJoinDecrypt function to handle the CFList field.
3. Due to duty cycle management the applicative API has changed.
All applications must be updated accordingly.
4. Added the possibility to chose to use either public or private networks
2015-01-30, v3.1.0
* General
1. Started to add support for CooCox CoIDE Integrated Development Environment.
Currently only LoRaMote and SensorNode platform projects are available.
2. Updated GCC compiler linker scripts.
3. Added the support of different tool chains for the HardFault_Handler function.
4. Corrected Radio drivers I&Q signals inversion to be possible in Rx and in Tx.
Added some missing radio state machine initialization.
5. Changed the RSSI values type from int8_t to int16_t. We can have RSSI values below -128 dBm.
6. Corrected SNR computation on RxDone interrupt.
7. Updated radio API to support FHSS and CAD handling.
8. Corrected in SetRxConfig function the FSK modem preamble register name.
9. Added an invalid bandwidth to the Bandwidths table in order to avoid an error
when selecting 250 kHz bandwidth when using FSK modem.
10. Corrected RTC alarm setup which could be set to an invalid date.
11. Added another timer in order increment the tick counter without blocking the normal timer count.
12. Added the possibility to switch between low power timers and normal timers on the fly.
13. I2C driver corrected the 2 bytes internal address management.
Corrected buffer read function when more that 1 byte was to be read.
Added a function to wait for the I2C bus to become IDLE.
14. Added an I2C EEPROM driver.
15. Corrected and improved USB Virtual COM Port management files.
Corrected the USB CDC and USB UART drivers.
16. Added the possibility to analyze a hard fault interrupt.
* LoRaMac
1. Corrected RxWindow2 Datarate management.
2. SrvAckRequested variable was never reset.
3. Corrected tstIndoor applications for LoRaMac R3.0 support.
4. LoRaMac added the possibility to configure almost all the MAC parameters.
5. Corrected the LoRaMacSetNextChannel function.
6. Corrected the port 0 MAC command decoding.
7. Changed all structures declarations to be packed.
8. Corrected the Acknowledgment retries management when only 1 trial is needed.
Before the device was issuing at least 2 trials.
9. Corrected server mac new channel req answer.
10. Added the functions to read the Up and Down Link sequence counters.
11. Corrected SRV_MAC_RX2_SETUP_REQ frequency handling. Added a 100 multiplication.
12. Corrected SRV_MAC_NEW_CHANNEL_REQ. Removed the DutyCycle parameter decoding.
13. Automatically activate the channel once it is created.
14. Corrected NbRepTimeoutTimer initial value. RxWindow2Delay already contains RxWindow1Delay in it.
2014-07-18, v3.0.0
* General
1. Added to Radio API the possibility to select the modem.
2. Corrected RSSI reading formulas as well as changed the RSSI and SNR values from double to int8_t type.
3. Changed radio callbacks events to timeout when it is a timeout event and error when it is a CRC error.
4. Radio API updated.
5. Updated ping-pong applications.
6. Updated tx-cw applications.
7. Updated LoRaMac applications in order to handle LoRaMac returned functions calls status.
8. Updated LoRaMac applications to toggle LED2 each time there is an application payload down link.
9. Updated tstIndoor application to handle correctly more than 6 channels.
10. Changed the MPL3115 altitude variable from unsigned to signed value.
11. Replaced the usage of pow(2, n) by defining POW2 functions. Saves ~2 KBytes of code.
12. Corrected an issue potentially arriving when LOW_POWER_MODE_ENABLE wasn't defined.
A timer interrupt could be generated while the TimerList could already be emptied.
* LoRaMac
1. Implemented LoRaMac specification R3.0 changes.
2. MAC commands implemented
* LinkCheckReq **YES**
* LinkCheckAns **YES**
* LinkADRReq **YES**
* LinkADRAns **YES**
* DutyCycleReq **YES**
* DutyCycleAns **YES**
* Rx2SetupReq **YES**
* Rx2SetupAns **YES**
* DevStatusReq **YES**
* DevStatusAns **YES**
* JoinReq **YES**
* JoinAccept **YES**
* NewChannelReq **YES**
* NewChannelAns **YES**
3. Features implemented
* Possibility to shut-down the device **YES**
Possible by issuing DutyCycleReq MAC command.
* Duty cycle management enforcement **NO**
* Acknowledgments retries **YES**
* Unconfirmed messages retries **YES**
2014-07-10, v2.3.RC2
* General
1. Corrected all radios antenna switch low power mode handling.
2. SX1276: Corrected antenna switch control.
2014-06-06, v2.3.RC1
* General
1. Added the support for SX1276 radio.
2. Radio continuous reception mode correction.
3. Radio driver RxDone callback function API has changed ( size parameter is no more a pointer).
Previous function prototype:
void ( *RxDone )( uint8_t *payload, uint16_t *size, double rssi, double snr, uint8_t rawSnr );
New function prototype:
void ( *RxDone )( uint8_t *payload, uint16_t size, double rssi, double snr, uint8_t rawSnr );
4. Added Bleeper-76 and SensorNode platforms support.
5. Added to the radio drivers a function that generates a random value from
RSSI readings.
6. Added a project to transmit a continuous wave and a project to measure the
the radio sensitivity.
7. Added a bootloader project for the LoRaMote and SensorNode platforms.
8. The LoRaMac application for Bleeper platforms now sends the Selector and LED status plus the sensors values.
* The application payload for the Bleeper platforms is as follows:
LoRaMac port 1:
{ 0xX0/0xX1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
---------- ---------- ---------- ---------- ----
| | | | |
SELECTOR/LED PRESSURE TEMPERATURE ALTITUDE BATTERY
MSB nibble = SELECTOR (barometric)
LSB bit = LED
9. Redefined rand() and srand() standard C functions. These functions are
redefined in order to get the same behavior across different compiler
tool chains implementations.
10. GPS driver improvements. Made independent of the board platform.
11. Simplified the RTC management.
12. Added a function to the timer driver that checks if a timer is already in
the list or not.
13. Added the UART Overrun bit exception handling to the UART driver.
14. Removed dependency of spi-board files to the "__builtin_ffs" function.
This function is only available on GNU compiler tool suite. Removed --gnu
compiler option from Keil projects. Added own __ffs function
implementation to utilities.h file.
15. Removed obsolete class1 devices support.
16. Known bugs correction.
* LoRaMac
1. MAC commands implemented
* LinkCheckReq **YES**
* LinkCheckAns **YES**
* LinkADRReq **YES**
* LinkADRAns **YES**
* DutyCycleReq **YES** (LoRaMac specification R2.2.1)
* DutyCycleAns **YES** (LoRaMac specification R2.2.1)
* Rx2SetupReq **YES** (LoRaMac specification R2.2.1)
* Rx2SetupAns **YES** (LoRaMac specification R2.2.1)
* DevStatusReq **YES**
* DevStatusAns **YES**
* JoinReq **YES**
* JoinAccept **YES** (LoRaMac specification R2.2.1)
* NewChannelReq **YES** (LoRaMac specification R2.2.1)
* NewChannelAns **YES** (LoRaMac specification R2.2.1)
2. Features implemented
* Possibility to shut-down the device **YES**
Possible by issuing DutyCycleReq MAC command.
* Duty cycle management enforcement **NO**
* Acknowledgments retries **WORK IN PROGRESS**
Not fully debugged. Disabled by default.
* Unconfirmed messages retries **WORK IN PROGRESS** (LoRaMac specification R2.2.1)
3. Implemented LoRaMac specification R2.2.1 changes.
4. Due to new specification the LoRaMacInitNwkIds LoRaMac API function had
to be modified.
Previous function prototype:
void LoRaMacInitNwkIds( uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey );
New function prototype:
void LoRaMacInitNwkIds( uint32_t netID, uint32_t devAddr, uint8_t *nwkSKey, uint8_t *appSKey );
5. Changed the LoRaMac channels management.
6. LoRaMac channels definition has been moved to LoRaMac-board.h file
located in each specific board directory.
2014-04-07, v2.2.0
* General
1. Added IMST SK-iM880A starter kit board support to the project.
* The application payload for the SK-iM880A platform is as follows:
LoRaMac port 3:
{ 0x00/0x01, 0x00, 0x00, 0x00 }
---------- ----- ----------
| | |
LED POTI VDD
2. Ping-Pong applications have been split per supported board.
3. Corrected the SX1272 output power management.
Added a variable to store the current Radio channel.
Added missing FSK bit definition.
4. Made fifo functions coding style coherent with the project.
5. UART driver is now independent of the used MCU
2014-03-28, v2.1.0
* General
1. The timers and RTC management has been rewritten.
2. Improved the UART and UP501 GPS drivers.
3. Corrected GPIO pin names management.
4. Corrected the antenna switch management in the SX1272 driver.
5. Added to the radio driver the possibility to choose the preamble length
and rxSingle symbol timeout in reception.
6. Added Hex coder selector driver for the Bleeper board.
7. Changed copyright Unicode character to (C) in all source files.
* LoRaMac
1. MAC commands implemented
* LinkCheckReq **YES**
* LinkCheckAns **YES**
* LinkADRReq **YES**
* LinkADRAns **YES**
* DevStatusReq **YES**
* DevStatusAns **YES**
* JoinReq **YES**
* JoinAccept **YES**
2. Added acknowledgments retries management.
Split the LoRaMacSendOnChannel function in LoRaMacPrepareFrame and
LoRaMacSendFrameOnChannel. LoRaMacSendOnChannel now calls the 2 newly
defined functions.
**WARNING**: By default the acknowledgment retries specific code isn't
enabled. The current http://iot.semtech.com server version doesn't support
it.
3. Corrected issues on JoinRequest and JoinAccept MAC commands.
Added LORAMAC_EVENT_INFO_STATUS_MAC_ERROR event info status.
2014-02-21, v2.0.0
* General
1. The LoRaMac applications now sends the LED status plus the sensors values.
For the LoRaMote platform the application also sends the GPS coordinates.
* The application payload for the Bleeper platform is as follows:
LoRaMac port 1:
{ 0x00/0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
---------- ---------- ---------- ---------- ----
| | | | |
LED PRESSURE TEMPERATURE ALTITUDE BATTERY
(barometric)
* The application payload for the LoRaMote platform is as follows:
LoRaMac port 2:
{ 0x00/0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
---------- ---------- ---------- ---------- ---- ---------------- ---------------- ----------
| | | | | | | |
LED PRESSURE TEMPERATURE ALTITUDE BATTERY LATITUDE LONGITUDE ALTITUDE
(barometric) (gps)
2. Adapted applications to the new MAC layer API.
3. Added sensors drivers implementation.
4. Corrected new or known issues.
* LoRaMac
1. MAC commands implemented
* LinkCheckReq **YES**
* LinkCheckAns **YES**
* LinkADRReq **YES**
* LinkADRAns **YES**
* DevStatusReq **YES**
* DevStatusAns **YES**
* JoinReq **YES (Not tested)**
* JoinAccept **YES (Not tested)**
2. New MAC layer application API implementation.
* Timers and RTC.
1. Still some issues. They will be corrected on next revisions of the firmware.
2014-01-24, v1.1.0
* LoRaMac
1. MAC commands implemented
* LinkCheckReq **NO**
* LinkCheckAns **NO**
* LinkADRReq **YES**
* LinkADRAns **YES**
* DevStatusReq **YES**
* DevStatusAns **YES**
2. Implemented an application LED control
If the server sends on port 1 an application payload of one byte with
the following contents:
0: LED off
1: LED on
The node transmits periodically on port 1 the LED status on 1st byte and
the message "Hello World!!!!" the array looks like:
{ 0, 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '!', '!', '!' }
* Timers and RTC.
1. Corrected issues existing in the previous version
2. Known bugs are:
* There is an issue when launching an asynchronous Timer. Will be solved
in a future version
2014-01-20, v1.1.RC1
* Added Doc directory. The directory contains:
1. LoRa MAC specification
2. Bleeper board schematic
* LoRaMac has been updated according to Release1 of the specification. Main changes are:
1. MAC API changed.
2. Frame format.
3. ClassA first ADR implementation.
4. MAC commands implemented
* LinkCheckReq **NO**
* LinkCheckAns **NO**
* LinkADRReq **YES**
* LinkADRAns **NO**
* DevStatusReq **NO**
* DevStatusAns **NO**
* Timers and RTC rewriting. Known bugs are:
1. The Radio wakeup time is taken in account for all timings.
2. When opening the second reception window the microcontroller sometimes doesn't enter in low power mode.
2013-11-28, v1.0.0
* Initial version of the LoRa MAC node firmware implementation.

View file

@ -0,0 +1,936 @@
/*
---------------------------------------------------------------------------
Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The redistribution and use of this software (with or without changes)
is allowed without the payment of fees or royalties provided that:
1. source code distributions include the above copyright notice, this
list of conditions and the following disclaimer;
2. binary distributions include the above copyright notice, this list
of conditions and the following disclaimer in their documentation;
3. the name of the copyright holder is not used to endorse products
built using this software without specific written permission.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue 09/09/2006
This is an AES implementation that uses only 8-bit byte operations on the
cipher state (there are options to use 32-bit types if available).
The combination of mix columns and byte substitution used here is based on
that developed by Karl Malbrain. His contribution is acknowledged.
*/
/* define if you have a fast memcpy function on your system */
#if 0
# define HAVE_MEMCPY
# include <string.h>
# if defined( _MSC_VER )
# include <intrin.h>
# pragma intrinsic( memcpy )
# endif
#endif
#include <stdlib.h>
#include <stdint.h>
/* define if you have fast 32-bit types on your system */
#if 0
# define HAVE_UINT_32T
#endif
/* define if you don't want any tables */
#if 1
# define USE_TABLES
#endif
/* On Intel Core 2 duo VERSION_1 is faster */
/* alternative versions (test for performance on your system) */
#if 1
# define VERSION_1
#endif
#include "aes.h"
//#if defined( HAVE_UINT_32T )
// typedef unsigned long uint32_t;
//#endif
/* functions for finite field multiplication in the AES Galois field */
#define WPOLY 0x011b
#define BPOLY 0x1b
#define DPOLY 0x008d
#define f1(x) (x)
#define f2(x) ((x << 1) ^ (((x >> 7) & 1) * WPOLY))
#define f4(x) ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY))
#define f8(x) ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \
^ (((x >> 5) & 4) * WPOLY))
#define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0))
#define f3(x) (f2(x) ^ x)
#define f9(x) (f8(x) ^ x)
#define fb(x) (f8(x) ^ f2(x) ^ x)
#define fd(x) (f8(x) ^ f4(x) ^ x)
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
#if defined( USE_TABLES )
#define sb_data(w) { /* S Box data values */ \
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
#define isb_data(w) { /* inverse S Box data values */ \
w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
#define mm_data(w) { /* basic data for forming finite field tables */ \
w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
static const uint8_t sbox[256] = sb_data(f1);
#if defined( AES_DEC_PREKEYED )
static const uint8_t isbox[256] = isb_data(f1);
#endif
static const uint8_t gfm2_sbox[256] = sb_data(f2);
static const uint8_t gfm3_sbox[256] = sb_data(f3);
#if defined( AES_DEC_PREKEYED )
static const uint8_t gfmul_9[256] = mm_data(f9);
static const uint8_t gfmul_b[256] = mm_data(fb);
static const uint8_t gfmul_d[256] = mm_data(fd);
static const uint8_t gfmul_e[256] = mm_data(fe);
#endif
#define s_box(x) sbox[(x)]
#if defined( AES_DEC_PREKEYED )
#define is_box(x) isbox[(x)]
#endif
#define gfm2_sb(x) gfm2_sbox[(x)]
#define gfm3_sb(x) gfm3_sbox[(x)]
#if defined( AES_DEC_PREKEYED )
#define gfm_9(x) gfmul_9[(x)]
#define gfm_b(x) gfmul_b[(x)]
#define gfm_d(x) gfmul_d[(x)]
#define gfm_e(x) gfmul_e[(x)]
#endif
#else
/* this is the high bit of x right shifted by 1 */
/* position. Since the starting polynomial has */
/* 9 bits (0x11b), this right shift keeps the */
/* values of all top bits within a byte */
static uint8_t hibit(const uint8_t x)
{ uint8_t r = (uint8_t)((x >> 1) | (x >> 2));
r |= (r >> 2);
r |= (r >> 4);
return (r + 1) >> 1;
}
/* return the inverse of the finite field element x */
static uint8_t gf_inv(const uint8_t x)
{ uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
if(x < 2)
return x;
for( ; ; )
{
if(n1)
while(n2 >= n1) /* divide polynomial p2 by p1 */
{
n2 /= n1; /* shift smaller polynomial left */
p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
v2 ^= (v1 * n2); /* shift accumulated value and */
n2 = hibit(p2); /* add into result */
}
else
return v1;
if(n2) /* repeat with values swapped */
while(n1 >= n2)
{
n1 /= n2;
p1 ^= p2 * n1;
v1 ^= v2 * n1;
n1 = hibit(p1);
}
else
return v2;
}
}
/* The forward and inverse affine transformations used in the S-box */
uint8_t fwd_affine(const uint8_t x)
{
#if defined( HAVE_UINT_32T )
uint32_t w = x;
w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
#else
return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4)
^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4);
#endif
}
uint8_t inv_affine(const uint8_t x)
{
#if defined( HAVE_UINT_32T )
uint32_t w = x;
w = (w << 1) ^ (w << 3) ^ (w << 6);
return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
#else
return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6)
^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
#endif
}
#define s_box(x) fwd_affine(gf_inv(x))
#define is_box(x) gf_inv(inv_affine(x))
#define gfm2_sb(x) f2(s_box(x))
#define gfm3_sb(x) f3(s_box(x))
#define gfm_9(x) f9(x)
#define gfm_b(x) fb(x)
#define gfm_d(x) fd(x)
#define gfm_e(x) fe(x)
#endif
#if defined( HAVE_MEMCPY )
# define block_copy_nn(d, s, l) memcpy(d, s, l)
# define block_copy(d, s) memcpy(d, s, N_BLOCK)
#else
# define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
# define block_copy(d, s) copy_block(d, s)
#endif
static void copy_block( void *d, const void *s )
{
#if defined( HAVE_UINT_32T )
((uint32_t*)d)[ 0] = ((uint32_t*)s)[ 0];
((uint32_t*)d)[ 1] = ((uint32_t*)s)[ 1];
((uint32_t*)d)[ 2] = ((uint32_t*)s)[ 2];
((uint32_t*)d)[ 3] = ((uint32_t*)s)[ 3];
#else
((uint8_t*)d)[ 0] = ((uint8_t*)s)[ 0];
((uint8_t*)d)[ 1] = ((uint8_t*)s)[ 1];
((uint8_t*)d)[ 2] = ((uint8_t*)s)[ 2];
((uint8_t*)d)[ 3] = ((uint8_t*)s)[ 3];
((uint8_t*)d)[ 4] = ((uint8_t*)s)[ 4];
((uint8_t*)d)[ 5] = ((uint8_t*)s)[ 5];
((uint8_t*)d)[ 6] = ((uint8_t*)s)[ 6];
((uint8_t*)d)[ 7] = ((uint8_t*)s)[ 7];
((uint8_t*)d)[ 8] = ((uint8_t*)s)[ 8];
((uint8_t*)d)[ 9] = ((uint8_t*)s)[ 9];
((uint8_t*)d)[10] = ((uint8_t*)s)[10];
((uint8_t*)d)[11] = ((uint8_t*)s)[11];
((uint8_t*)d)[12] = ((uint8_t*)s)[12];
((uint8_t*)d)[13] = ((uint8_t*)s)[13];
((uint8_t*)d)[14] = ((uint8_t*)s)[14];
((uint8_t*)d)[15] = ((uint8_t*)s)[15];
#endif
}
static void copy_block_nn( uint8_t * d, const uint8_t *s, uint8_t nn )
{
while( nn-- )
//*((uint8_t*)d)++ = *((uint8_t*)s)++;
*d++ = *s++;
}
static void xor_block( void *d, const void *s )
{
#if defined( HAVE_UINT_32T )
((uint32_t*)d)[ 0] ^= ((uint32_t*)s)[ 0];
((uint32_t*)d)[ 1] ^= ((uint32_t*)s)[ 1];
((uint32_t*)d)[ 2] ^= ((uint32_t*)s)[ 2];
((uint32_t*)d)[ 3] ^= ((uint32_t*)s)[ 3];
#else
((uint8_t*)d)[ 0] ^= ((uint8_t*)s)[ 0];
((uint8_t*)d)[ 1] ^= ((uint8_t*)s)[ 1];
((uint8_t*)d)[ 2] ^= ((uint8_t*)s)[ 2];
((uint8_t*)d)[ 3] ^= ((uint8_t*)s)[ 3];
((uint8_t*)d)[ 4] ^= ((uint8_t*)s)[ 4];
((uint8_t*)d)[ 5] ^= ((uint8_t*)s)[ 5];
((uint8_t*)d)[ 6] ^= ((uint8_t*)s)[ 6];
((uint8_t*)d)[ 7] ^= ((uint8_t*)s)[ 7];
((uint8_t*)d)[ 8] ^= ((uint8_t*)s)[ 8];
((uint8_t*)d)[ 9] ^= ((uint8_t*)s)[ 9];
((uint8_t*)d)[10] ^= ((uint8_t*)s)[10];
((uint8_t*)d)[11] ^= ((uint8_t*)s)[11];
((uint8_t*)d)[12] ^= ((uint8_t*)s)[12];
((uint8_t*)d)[13] ^= ((uint8_t*)s)[13];
((uint8_t*)d)[14] ^= ((uint8_t*)s)[14];
((uint8_t*)d)[15] ^= ((uint8_t*)s)[15];
#endif
}
static void copy_and_key( void *d, const void *s, const void *k )
{
#if defined( HAVE_UINT_32T )
((uint32_t*)d)[ 0] = ((uint32_t*)s)[ 0] ^ ((uint32_t*)k)[ 0];
((uint32_t*)d)[ 1] = ((uint32_t*)s)[ 1] ^ ((uint32_t*)k)[ 1];
((uint32_t*)d)[ 2] = ((uint32_t*)s)[ 2] ^ ((uint32_t*)k)[ 2];
((uint32_t*)d)[ 3] = ((uint32_t*)s)[ 3] ^ ((uint32_t*)k)[ 3];
#elif 1
((uint8_t*)d)[ 0] = ((uint8_t*)s)[ 0] ^ ((uint8_t*)k)[ 0];
((uint8_t*)d)[ 1] = ((uint8_t*)s)[ 1] ^ ((uint8_t*)k)[ 1];
((uint8_t*)d)[ 2] = ((uint8_t*)s)[ 2] ^ ((uint8_t*)k)[ 2];
((uint8_t*)d)[ 3] = ((uint8_t*)s)[ 3] ^ ((uint8_t*)k)[ 3];
((uint8_t*)d)[ 4] = ((uint8_t*)s)[ 4] ^ ((uint8_t*)k)[ 4];
((uint8_t*)d)[ 5] = ((uint8_t*)s)[ 5] ^ ((uint8_t*)k)[ 5];
((uint8_t*)d)[ 6] = ((uint8_t*)s)[ 6] ^ ((uint8_t*)k)[ 6];
((uint8_t*)d)[ 7] = ((uint8_t*)s)[ 7] ^ ((uint8_t*)k)[ 7];
((uint8_t*)d)[ 8] = ((uint8_t*)s)[ 8] ^ ((uint8_t*)k)[ 8];
((uint8_t*)d)[ 9] = ((uint8_t*)s)[ 9] ^ ((uint8_t*)k)[ 9];
((uint8_t*)d)[10] = ((uint8_t*)s)[10] ^ ((uint8_t*)k)[10];
((uint8_t*)d)[11] = ((uint8_t*)s)[11] ^ ((uint8_t*)k)[11];
((uint8_t*)d)[12] = ((uint8_t*)s)[12] ^ ((uint8_t*)k)[12];
((uint8_t*)d)[13] = ((uint8_t*)s)[13] ^ ((uint8_t*)k)[13];
((uint8_t*)d)[14] = ((uint8_t*)s)[14] ^ ((uint8_t*)k)[14];
((uint8_t*)d)[15] = ((uint8_t*)s)[15] ^ ((uint8_t*)k)[15];
#else
block_copy(d, s);
xor_block(d, k);
#endif
}
static void add_round_key( uint8_t d[N_BLOCK], const uint8_t k[N_BLOCK] )
{
xor_block(d, k);
}
static void shift_sub_rows( uint8_t st[N_BLOCK] )
{ uint8_t tt;
st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]);
st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]);
tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]);
st[ 9] = s_box(st[13]); st[13] = s_box( tt );
tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt );
tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt );
tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]);
st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt );
}
#if defined( AES_DEC_PREKEYED )
static void inv_shift_sub_rows( uint8_t st[N_BLOCK] )
{ uint8_t tt;
st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]);
st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]);
tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]);
st[ 5] = is_box(st[1]); st[ 1] = is_box( tt );
tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt );
tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt );
tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]);
st[11] = is_box(st[15]); st[15] = is_box( tt );
}
#endif
#if defined( VERSION_1 )
static void mix_sub_columns( uint8_t dt[N_BLOCK] )
{ uint8_t st[N_BLOCK];
block_copy(st, dt);
#else
static void mix_sub_columns( uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK] )
{
#endif
dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
}
#if defined( AES_DEC_PREKEYED )
#if defined( VERSION_1 )
static void inv_mix_sub_columns( uint8_t dt[N_BLOCK] )
{ uint8_t st[N_BLOCK];
block_copy(st, dt);
#else
static void inv_mix_sub_columns( uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK] )
{
#endif
dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3]));
dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3]));
dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3]));
dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3]));
dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7]));
dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7]));
dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7]));
dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7]));
dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
}
#endif
#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
/* Set the cipher key for the pre-keyed version */
return_type aes_set_key( const uint8_t key[], length_type keylen, aes_context ctx[1] )
{
uint8_t cc, rc, hi;
switch( keylen )
{
case 16:
case 24:
case 32:
break;
default:
ctx->rnd = 0;
return ( uint8_t )-1;
}
block_copy_nn(ctx->ksch, key, keylen);
hi = (keylen + 28) << 2;
ctx->rnd = (hi >> 4) - 1;
for( cc = keylen, rc = 1; cc < hi; cc += 4 )
{ uint8_t tt, t0, t1, t2, t3;
t0 = ctx->ksch[cc - 4];
t1 = ctx->ksch[cc - 3];
t2 = ctx->ksch[cc - 2];
t3 = ctx->ksch[cc - 1];
if( cc % keylen == 0 )
{
tt = t0;
t0 = s_box(t1) ^ rc;
t1 = s_box(t2);
t2 = s_box(t3);
t3 = s_box(tt);
rc = f2(rc);
}
else if( keylen > 24 && cc % keylen == 16 )
{
t0 = s_box(t0);
t1 = s_box(t1);
t2 = s_box(t2);
t3 = s_box(t3);
}
tt = cc - keylen;
ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
}
return 0;
}
#endif
#if defined( AES_ENC_PREKEYED )
/* Encrypt a single block of 16 bytes */
return_type aes_encrypt( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], const aes_context ctx[1] )
{
if( ctx->rnd )
{
uint8_t s1[N_BLOCK], r;
copy_and_key( s1, in, ctx->ksch );
for( r = 1 ; r < ctx->rnd ; ++r )
#if defined( VERSION_1 )
{
mix_sub_columns( s1 );
add_round_key( s1, ctx->ksch + r * N_BLOCK);
}
#else
{ uint8_t s2[N_BLOCK];
mix_sub_columns( s2, s1 );
copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK);
}
#endif
shift_sub_rows( s1 );
copy_and_key( out, s1, ctx->ksch + r * N_BLOCK );
}
else
return ( uint8_t )-1;
return 0;
}
/* CBC encrypt a number of blocks (input and return an IV) */
return_type aes_cbc_encrypt( const uint8_t *in, uint8_t *out,
int32_t n_block, uint8_t iv[N_BLOCK], const aes_context ctx[1] )
{
while(n_block--)
{
xor_block(iv, in);
if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
return EXIT_FAILURE;
//memcpy(out, iv, N_BLOCK);
block_copy(out, iv);
in += N_BLOCK;
out += N_BLOCK;
}
return EXIT_SUCCESS;
}
#endif
#if defined( AES_DEC_PREKEYED )
/* Decrypt a single block of 16 bytes */
return_type aes_decrypt( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], const aes_context ctx[1] )
{
if( ctx->rnd )
{
uint8_t s1[N_BLOCK], r;
copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK );
inv_shift_sub_rows( s1 );
for( r = ctx->rnd ; --r ; )
#if defined( VERSION_1 )
{
add_round_key( s1, ctx->ksch + r * N_BLOCK );
inv_mix_sub_columns( s1 );
}
#else
{ uint8_t s2[N_BLOCK];
copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK );
inv_mix_sub_columns( s1, s2 );
}
#endif
copy_and_key( out, s1, ctx->ksch );
}
else
return -1;
return 0;
}
/* CBC decrypt a number of blocks (input and return an IV) */
return_type aes_cbc_decrypt( const uint8_t *in, uint8_t *out,
int32_t n_block, uint8_t iv[N_BLOCK], const aes_context ctx[1] )
{
while(n_block--)
{ uint8_t tmp[N_BLOCK];
//memcpy(tmp, in, N_BLOCK);
block_copy(tmp, in);
if(aes_decrypt(in, out, ctx) != EXIT_SUCCESS)
return EXIT_FAILURE;
xor_block(out, iv);
//memcpy(iv, tmp, N_BLOCK);
block_copy(iv, tmp);
in += N_BLOCK;
out += N_BLOCK;
}
return EXIT_SUCCESS;
}
#endif
#if defined( AES_ENC_128_OTFK )
/* The 'on the fly' encryption key update for for 128 bit keys */
static void update_encrypt_key_128( uint8_t k[N_BLOCK], uint8_t *rc )
{ uint8_t cc;
k[0] ^= s_box(k[13]) ^ *rc;
k[1] ^= s_box(k[14]);
k[2] ^= s_box(k[15]);
k[3] ^= s_box(k[12]);
*rc = f2( *rc );
for(cc = 4; cc < 16; cc += 4 )
{
k[cc + 0] ^= k[cc - 4];
k[cc + 1] ^= k[cc - 3];
k[cc + 2] ^= k[cc - 2];
k[cc + 3] ^= k[cc - 1];
}
}
/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
void aes_encrypt_128( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK] )
{ uint8_t s1[N_BLOCK], r, rc = 1;
if(o_key != key)
block_copy( o_key, key );
copy_and_key( s1, in, o_key );
for( r = 1 ; r < 10 ; ++r )
#if defined( VERSION_1 )
{
mix_sub_columns( s1 );
update_encrypt_key_128( o_key, &rc );
add_round_key( s1, o_key );
}
#else
{ uint8_t s2[N_BLOCK];
mix_sub_columns( s2, s1 );
update_encrypt_key_128( o_key, &rc );
copy_and_key( s1, s2, o_key );
}
#endif
shift_sub_rows( s1 );
update_encrypt_key_128( o_key, &rc );
copy_and_key( out, s1, o_key );
}
#endif
#if defined( AES_DEC_128_OTFK )
/* The 'on the fly' decryption key update for for 128 bit keys */
static void update_decrypt_key_128( uint8_t k[N_BLOCK], uint8_t *rc )
{ uint8_t cc;
for( cc = 12; cc > 0; cc -= 4 )
{
k[cc + 0] ^= k[cc - 4];
k[cc + 1] ^= k[cc - 3];
k[cc + 2] ^= k[cc - 2];
k[cc + 3] ^= k[cc - 1];
}
*rc = d2(*rc);
k[0] ^= s_box(k[13]) ^ *rc;
k[1] ^= s_box(k[14]);
k[2] ^= s_box(k[15]);
k[3] ^= s_box(k[12]);
}
/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
void aes_decrypt_128( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK] )
{
uint8_t s1[N_BLOCK], r, rc = 0x6c;
if(o_key != key)
block_copy( o_key, key );
copy_and_key( s1, in, o_key );
inv_shift_sub_rows( s1 );
for( r = 10 ; --r ; )
#if defined( VERSION_1 )
{
update_decrypt_key_128( o_key, &rc );
add_round_key( s1, o_key );
inv_mix_sub_columns( s1 );
}
#else
{ uint8_t s2[N_BLOCK];
update_decrypt_key_128( o_key, &rc );
copy_and_key( s2, s1, o_key );
inv_mix_sub_columns( s1, s2 );
}
#endif
update_decrypt_key_128( o_key, &rc );
copy_and_key( out, s1, o_key );
}
#endif
#if defined( AES_ENC_256_OTFK )
/* The 'on the fly' encryption key update for for 256 bit keys */
static void update_encrypt_key_256( uint8_t k[2 * N_BLOCK], uint8_t *rc )
{ uint8_t cc;
k[0] ^= s_box(k[29]) ^ *rc;
k[1] ^= s_box(k[30]);
k[2] ^= s_box(k[31]);
k[3] ^= s_box(k[28]);
*rc = f2( *rc );
for(cc = 4; cc < 16; cc += 4)
{
k[cc + 0] ^= k[cc - 4];
k[cc + 1] ^= k[cc - 3];
k[cc + 2] ^= k[cc - 2];
k[cc + 3] ^= k[cc - 1];
}
k[16] ^= s_box(k[12]);
k[17] ^= s_box(k[13]);
k[18] ^= s_box(k[14]);
k[19] ^= s_box(k[15]);
for( cc = 20; cc < 32; cc += 4 )
{
k[cc + 0] ^= k[cc - 4];
k[cc + 1] ^= k[cc - 3];
k[cc + 2] ^= k[cc - 2];
k[cc + 3] ^= k[cc - 1];
}
}
/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
void aes_encrypt_256( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK] )
{
uint8_t s1[N_BLOCK], r, rc = 1;
if(o_key != key)
{
block_copy( o_key, key );
block_copy( o_key + 16, key + 16 );
}
copy_and_key( s1, in, o_key );
for( r = 1 ; r < 14 ; ++r )
#if defined( VERSION_1 )
{
mix_sub_columns(s1);
if( r & 1 )
add_round_key( s1, o_key + 16 );
else
{
update_encrypt_key_256( o_key, &rc );
add_round_key( s1, o_key );
}
}
#else
{ uint8_t s2[N_BLOCK];
mix_sub_columns( s2, s1 );
if( r & 1 )
copy_and_key( s1, s2, o_key + 16 );
else
{
update_encrypt_key_256( o_key, &rc );
copy_and_key( s1, s2, o_key );
}
}
#endif
shift_sub_rows( s1 );
update_encrypt_key_256( o_key, &rc );
copy_and_key( out, s1, o_key );
}
#endif
#if defined( AES_DEC_256_OTFK )
/* The 'on the fly' encryption key update for for 256 bit keys */
static void update_decrypt_key_256( uint8_t k[2 * N_BLOCK], uint8_t *rc )
{ uint8_t cc;
for(cc = 28; cc > 16; cc -= 4)
{
k[cc + 0] ^= k[cc - 4];
k[cc + 1] ^= k[cc - 3];
k[cc + 2] ^= k[cc - 2];
k[cc + 3] ^= k[cc - 1];
}
k[16] ^= s_box(k[12]);
k[17] ^= s_box(k[13]);
k[18] ^= s_box(k[14]);
k[19] ^= s_box(k[15]);
for(cc = 12; cc > 0; cc -= 4)
{
k[cc + 0] ^= k[cc - 4];
k[cc + 1] ^= k[cc - 3];
k[cc + 2] ^= k[cc - 2];
k[cc + 3] ^= k[cc - 1];
}
*rc = d2(*rc);
k[0] ^= s_box(k[29]) ^ *rc;
k[1] ^= s_box(k[30]);
k[2] ^= s_box(k[31]);
k[3] ^= s_box(k[28]);
}
/* Decrypt a single block of 16 bytes with 'on the fly'
256 bit keying
*/
void aes_decrypt_256( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK] )
{
uint8_t s1[N_BLOCK], r, rc = 0x80;
if(o_key != key)
{
block_copy( o_key, key );
block_copy( o_key + 16, key + 16 );
}
copy_and_key( s1, in, o_key );
inv_shift_sub_rows( s1 );
for( r = 14 ; --r ; )
#if defined( VERSION_1 )
{
if( ( r & 1 ) )
{
update_decrypt_key_256( o_key, &rc );
add_round_key( s1, o_key + 16 );
}
else
add_round_key( s1, o_key );
inv_mix_sub_columns( s1 );
}
#else
{ uint8_t s2[N_BLOCK];
if( ( r & 1 ) )
{
update_decrypt_key_256( o_key, &rc );
copy_and_key( s2, s1, o_key + 16 );
}
else
copy_and_key( s2, s1, o_key );
inv_mix_sub_columns( s1, s2 );
}
#endif
copy_and_key( out, s1, o_key );
}
#endif

View file

@ -0,0 +1,160 @@
/*
---------------------------------------------------------------------------
Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The redistribution and use of this software (with or without changes)
is allowed without the payment of fees or royalties provided that:
1. source code distributions include the above copyright notice, this
list of conditions and the following disclaimer;
2. binary distributions include the above copyright notice, this list
of conditions and the following disclaimer in their documentation;
3. the name of the copyright holder is not used to endorse products
built using this software without specific written permission.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue 09/09/2006
This is an AES implementation that uses only 8-bit byte operations on the
cipher state.
*/
#ifndef AES_H
#define AES_H
#if 1
# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */
#endif
#if 0
# define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */
#endif
#if 0
# define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */
#endif
#if 0
# define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */
#endif
#if 0
# define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */
#endif
#if 0
# define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */
#endif
#define N_ROW 4
#define N_COL 4
#define N_BLOCK (N_ROW * N_COL)
#define N_MAX_ROUNDS 14
typedef uint8_t return_type;
/* Warning: The key length for 256 bit keys overflows a byte
(see comment below)
*/
typedef uint8_t length_type;
typedef struct
{ uint8_t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK];
uint8_t rnd;
} aes_context;
/* The following calls are for a precomputed key schedule
NOTE: If the length_type used for the key length is an
unsigned 8-bit character, a key length of 256 bits must
be entered as a length in bytes (valid inputs are hence
128, 192, 16, 24 and 32).
*/
#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
return_type aes_set_key( const uint8_t key[],
length_type keylen,
aes_context ctx[1] );
#endif
#if defined( AES_ENC_PREKEYED )
return_type aes_encrypt( const uint8_t in[N_BLOCK],
uint8_t out[N_BLOCK],
const aes_context ctx[1] );
return_type aes_cbc_encrypt( const uint8_t *in,
uint8_t *out,
int32_t n_block,
uint8_t iv[N_BLOCK],
const aes_context ctx[1] );
#endif
#if defined( AES_DEC_PREKEYED )
return_type aes_decrypt( const uint8_t in[N_BLOCK],
uint8_t out[N_BLOCK],
const aes_context ctx[1] );
return_type aes_cbc_decrypt( const uint8_t *in,
uint8_t *out,
int32_t n_block,
uint8_t iv[N_BLOCK],
const aes_context ctx[1] );
#endif
/* The following calls are for 'on the fly' keying. In this case the
encryption and decryption keys are different.
The encryption subroutines take a key in an array of bytes in
key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
192, and 256 bits respectively. They then encrypts the input
data, in[] with this key and put the reult in the output array
out[]. In addition, the second key array, o_key[L], is used
to output the key that is needed by the decryption subroutine
to reverse the encryption operation. The two key arrays can
be the same array but in this case the original key will be
overwritten.
In the same way, the decryption subroutines output keys that
can be used to reverse their effect when used for encryption.
Only 128 and 256 bit keys are supported in these 'on the fly'
modes.
*/
#if defined( AES_ENC_128_OTFK )
void aes_encrypt_128( const uint8_t in[N_BLOCK],
uint8_t out[N_BLOCK],
const uint8_t key[N_BLOCK],
uint8_t o_key[N_BLOCK] );
#endif
#if defined( AES_DEC_128_OTFK )
void aes_decrypt_128( const uint8_t in[N_BLOCK],
uint8_t out[N_BLOCK],
const uint8_t key[N_BLOCK],
uint8_t o_key[N_BLOCK] );
#endif
#if defined( AES_ENC_256_OTFK )
void aes_encrypt_256( const uint8_t in[N_BLOCK],
uint8_t out[N_BLOCK],
const uint8_t key[2 * N_BLOCK],
uint8_t o_key[2 * N_BLOCK] );
#endif
#if defined( AES_DEC_256_OTFK )
void aes_decrypt_256( const uint8_t in[N_BLOCK],
uint8_t out[N_BLOCK],
const uint8_t key[2 * N_BLOCK],
uint8_t o_key[2 * N_BLOCK] );
#endif
#endif

View file

@ -0,0 +1,153 @@
/**************************************************************************
Copyright (C) 2009 Lander Casado, Philippas Tsigas
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal with the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers. Redistributions in
binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimers in the documentation and/or
other materials provided with the distribution.
In no event shall the authors or copyright holders be liable for any special,
incidental, indirect or consequential damages of any kind, or any damages
whatsoever resulting from loss of use, data or profits, whether or not
advised of the possibility of damage, and on any theory of liability,
arising out of or in connection with the use or performance of this software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS WITH THE SOFTWARE
*****************************************************************************/
//#include <sys/param.h>
//#include <sys/systm.h>
#include <stdint.h>
#include "aes.h"
#include "cmac.h"
#include "utilities.h"
#define LSHIFT(v, r) do { \
int32_t i; \
for (i = 0; i < 15; i++) \
(r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7; \
(r)[15] = (v)[15] << 1; \
} while (0)
#define XOR(v, r) do { \
int32_t i; \
for (i = 0; i < 16; i++) \
{ \
(r)[i] = (r)[i] ^ (v)[i]; \
} \
} while (0) \
void AES_CMAC_Init(AES_CMAC_CTX *ctx)
{
memset1(ctx->X, 0, sizeof ctx->X);
ctx->M_n = 0;
memset1(ctx->rijndael.ksch, '\0', 240);
}
void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH])
{
//rijndael_set_key_enc_only(&ctx->rijndael, key, 128);
aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael);
}
void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len)
{
uint32_t mlen;
uint8_t in[16];
if (ctx->M_n > 0) {
mlen = MIN(16 - ctx->M_n, len);
memcpy1(ctx->M_last + ctx->M_n, data, mlen);
ctx->M_n += mlen;
if (ctx->M_n < 16 || len == mlen)
return;
XOR(ctx->M_last, ctx->X);
//rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
aes_encrypt( ctx->X, ctx->X, &ctx->rijndael);
data += mlen;
len -= mlen;
}
while (len > 16) { /* not last block */
XOR(data, ctx->X);
//rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
aes_encrypt( in, in, &ctx->rijndael);
memcpy1(&ctx->X[0], in, 16);
data += 16;
len -= 16;
}
/* potential last block, save it */
memcpy1(ctx->M_last, data, len);
ctx->M_n = len;
}
void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx)
{
uint8_t K[16];
uint8_t in[16];
/* generate subkey K1 */
memset1(K, '\0', 16);
//rijndael_encrypt(&ctx->rijndael, K, K);
aes_encrypt( K, K, &ctx->rijndael);
if (K[0] & 0x80) {
LSHIFT(K, K);
K[15] ^= 0x87;
} else
LSHIFT(K, K);
if (ctx->M_n == 16) {
/* last block was a complete block */
XOR(K, ctx->M_last);
} else {
/* generate subkey K2 */
if (K[0] & 0x80) {
LSHIFT(K, K);
K[15] ^= 0x87;
} else
LSHIFT(K, K);
/* padding(M_last) */
ctx->M_last[ctx->M_n] = 0x80;
while (++ctx->M_n < 16)
ctx->M_last[ctx->M_n] = 0;
XOR(K, ctx->M_last);
}
XOR(ctx->M_last, ctx->X);
//rijndael_encrypt(&ctx->rijndael, ctx->X, digest);
memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
aes_encrypt(in, digest, &ctx->rijndael);
memset1(K, 0, sizeof K);
}

View file

@ -0,0 +1,63 @@
/**************************************************************************
Copyright (C) 2009 Lander Casado, Philippas Tsigas
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal with the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers. Redistributions in
binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimers in the documentation and/or
other materials provided with the distribution.
In no event shall the authors or copyright holders be liable for any special,
incidental, indirect or consequential damages of any kind, or any damages
whatsoever resulting from loss of use, data or profits, whether or not
advised of the possibility of damage, and on any theory of liability,
arising out of or in connection with the use or performance of this software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS WITH THE SOFTWARE
*****************************************************************************/
#ifndef _CMAC_H_
#define _CMAC_H_
#include "aes.h"
#define AES_CMAC_KEY_LENGTH 16
#define AES_CMAC_DIGEST_LENGTH 16
typedef struct _AES_CMAC_CTX {
uint32_t M_n;
uint8_t X[16];
uint8_t M_last[16];
aes_context rijndael;
} AES_CMAC_CTX;
//#include <sys/cdefs.h>
//__BEGIN_DECLS
void AES_CMAC_Init(AES_CMAC_CTX * ctx);
void AES_CMAC_SetKey(AES_CMAC_CTX * ctx, const uint8_t key[AES_CMAC_KEY_LENGTH]);
void AES_CMAC_Update(AES_CMAC_CTX * ctx, const uint8_t * data, uint32_t len);
// __attribute__((__bounded__(__string__,2,3)));
void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX * ctx);
// __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH)));
//__END_DECLS
#endif /* _CMAC_H_ */

View file

@ -0,0 +1,77 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Delay functions implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
/******************************************************************************
* @file delay.c
* @author MCD Application Team
* @version V1.1.1
* @date 01-June-2017
* @brief Delay function
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "hw.h"
#include "timeServer.h"
#include "lorawan_port.h"
void DelayMs( uint32_t ms )
{
aos_lrwan_time_itf.delay_ms(ms);
}
void Delay( float s )
{
DelayMs( (uint32_t) (s * 1000.0f) );
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Delay functions implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
#ifndef __DELAY_H__
#define __DELAY_H__
/*!
* Blocking delay of "s" seconds
*/
void Delay( float s );
/*!
* Blocking delay of "ms" milliseconds
*/
void DelayMs( uint32_t ms );
#endif // __DELAY_H__

View file

@ -0,0 +1,130 @@
/*******************************************************************************
* @file low_power.c
* @author MCD Application Team
* @version V1.1.1
* @date 01-June-2017
* @brief driver for low power
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "hw.h"
#include "low_power.h"
#include "lorawan_port.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/**
* \brief Flag to indicate if MCU can go to low power mode
* When 0, MCU is authorized to go in low power mode
*/
static uint32_t LowPower_State = 0;
/* Private function prototypes -----------------------------------------------*/
/* Exported functions ---------------------------------------------------------*/
/**
* \brief API to set flag allowing power mode
*
* \param [IN] enum e_LOW_POWER_State_Id_t
*/
void LowPower_Disable( e_LOW_POWER_State_Id_t state )
{
CPSR_ALLOC();
RHINO_CPU_INTRPT_DISABLE();
LowPower_State |= state;
RHINO_CPU_INTRPT_ENABLE();
}
/**
* \brief API to reset flag allowing power mode
*
* \param [IN] enum e_LOW_POWER_State_Id_t
*/
void LowPower_Enable( e_LOW_POWER_State_Id_t state )
{
CPSR_ALLOC();
RHINO_CPU_INTRPT_DISABLE();
LowPower_State &= ~state;
RHINO_CPU_INTRPT_ENABLE();
}
/**
* \brief API to get flag allowing power mode
* \note When flag is 0, low power mode is allowed
* \param [IN] state
* \retval flag state
*/
uint32_t LowPower_GetState( void )
{
return LowPower_State;
}
/**
* @brief Handle Low Power
* @param None
* @retval None
*/
void LowPower_Handler( void )
{
CPSR_ALLOC();
RHINO_CPU_INTRPT_DISABLE();
if (LowPower_State == 0) {
aos_lrwan_chg_mode.enter_stop_mode();
/* mcu dependent. to be implemented by user*/
aos_lrwan_chg_mode.exit_stop_mode();
aos_lrwan_time_itf.set_uc_wakeup_time();
} else {
aos_lrwan_chg_mode.enter_sleep_mode();
}
RHINO_CPU_INTRPT_ENABLE();
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,98 @@
/******************************************************************************
* @file low_power.h
* @author MCD Application Team
* @version V1.1.1
* @date 01-June-2017
* @brief Header for driver low_power.c module
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __LOW_POWER_H__
#define __LOW_POWER_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/*!
* @brief API to set flag allowing power mode
*
* @param [IN] enum e_LOW_POWER_State_Id_t
*/
void LowPower_Disable( e_LOW_POWER_State_Id_t state );
/*!
* @brief API to reset flag allowing power mode
*
* @param [IN] enum e_LOW_POWER_State_Id_t
*/
void LowPower_Enable( e_LOW_POWER_State_Id_t state );
/*!
* @brief API to get flag allowing power mode
* @note When flag is 0, low power mode is allowed
* @param [IN] non
* @retval flag state
*/
uint32_t LowPower_GetState( void );
/*!
* @brief Manages the entry into ARM cortex deep-sleep mode
* @param none
* @retval none
*/
void LowPower_Handler( void );
#ifdef __cplusplus
}
#endif
#endif /* __LOW_POWER_H__ */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,10 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
#ifndef LORAWAN_SYSTEM_PRECISION_H
#define LORAWAN_SYSTEM_PRECISION_H
#define DECIMAL float
#endif // LORAWAN_SYSTEM_PRECISION_H

View file

@ -0,0 +1,378 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Generic lora driver implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis, Gregory Cristian and Wael Guibene
*/
/******************************************************************************
* @file timeserver.c
* @author MCD Application Team
* @version V1.1.1
* @date 01-June-2017
* @brief Time server infrastructure
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <time.h>
#include "hw.h"
#include "timeServer.h"
#include "lorawan_port.h"
/*!
* safely execute call back
*/
#define exec_cb( _callback_ ) \
do \
{ \
if( _callback_ == NULL ) \
{ \
while(1); \
} \
else \
{ \
_callback_( ); \
} \
} while(0);
/*!
* Timers list head pointer
*/
static TimerEvent_t *TimerListHead = NULL;
/*!
* \brief Adds or replace the head timer of the list.
*
* \remark The list is automatically sorted. The list head always contains the
* next timer to expire.
*
* \param [IN] obj Timer object to be become the new head
* \param [IN] remainingTime Remaining time of the previous head to be replaced
*/
static void TimerInsertNewHeadTimer( TimerEvent_t *obj );
/*!
* \brief Adds a timer to the list.
*
* \remark The list is automatically sorted. The list head always contains the
* next timer to expire.
*
* \param [IN] obj Timer object to be added to the list
* \param [IN] remainingTime Remaining time of the running head after which the object may be added
*/
static void TimerInsertTimer( TimerEvent_t *obj );
/*!
* \brief Sets a timeout with the duration "timestamp"
*
* \param [IN] timestamp Delay duration
*/
static void TimerSetTimeout( TimerEvent_t *obj );
/*!
* \brief Check if the Object to be added is not already in the list
*
* \param [IN] timestamp Delay duration
* \retval true (the object is already in the list) or false
*/
static bool TimerExists( TimerEvent_t *obj );
void TimerInit( TimerEvent_t *obj, void ( *callback )( void ) )
{
obj->Timestamp = 0;
obj->ReloadValue = 0;
obj->IsRunning = false;
obj->Callback = callback;
obj->Next = NULL;
}
void TimerStart( TimerEvent_t *obj )
{
uint32_t elapsedTime = 0;
CPSR_ALLOC();
RHINO_CPU_INTRPT_DISABLE();
if( ( obj == NULL ) || ( TimerExists( obj ) == true ) )
{
RHINO_CPU_INTRPT_ENABLE();
return;
}
obj->Timestamp = obj->ReloadValue;
obj->IsRunning = false;
if( TimerListHead == NULL )
{
aos_lrwan_time_itf.set_timer_context();
TimerInsertNewHeadTimer( obj ); // insert a timeout at now+obj->Timestamp
}
else
{
elapsedTime = aos_lrwan_time_itf.get_timer_elapsed_time();
obj->Timestamp += elapsedTime;
if( obj->Timestamp < TimerListHead->Timestamp )
{
TimerInsertNewHeadTimer( obj);
}
else
{
TimerInsertTimer( obj);
}
}
RHINO_CPU_INTRPT_ENABLE();
}
static void TimerInsertTimer( TimerEvent_t *obj)
{
TimerEvent_t* cur = TimerListHead;
TimerEvent_t* next = TimerListHead->Next;
while (cur->Next != NULL )
{
if( obj->Timestamp > next->Timestamp )
{
cur = next;
next = next->Next;
}
else
{
cur->Next = obj;
obj->Next = next;
return;
}
}
cur->Next = obj;
obj->Next = NULL;
}
static void TimerInsertNewHeadTimer( TimerEvent_t *obj )
{
TimerEvent_t* cur = TimerListHead;
if( cur != NULL )
{
cur->IsRunning = false;
}
obj->Next = cur;
TimerListHead = obj;
TimerSetTimeout( TimerListHead );
}
void TimerIrqHandler( void )
{
TimerEvent_t* cur;
TimerEvent_t* next;
uint32_t old = aos_lrwan_time_itf.get_timer_context();
uint32_t now = aos_lrwan_time_itf.set_timer_context();
uint32_t DeltaContext = now - old; //intentionnal wrap around
/* update timeStamp based upon new Time Reference*/
/* beacuse delta context should never exceed 2^32*/
if ( TimerListHead != NULL )
{
for (cur=TimerListHead; cur->Next != NULL; cur= cur->Next)
{
next =cur->Next;
if (next->Timestamp > DeltaContext)
{
next->Timestamp -= DeltaContext;
}
else
{
next->Timestamp = 0 ;
}
}
}
/* execute imediately the alarm callback */
if ( TimerListHead != NULL )
{
cur = TimerListHead;
TimerListHead = TimerListHead->Next;
exec_cb( cur->Callback );
}
// remove all the expired object from the list
while( ( TimerListHead != NULL ) && ( TimerListHead->Timestamp < aos_lrwan_time_itf.get_timer_elapsed_time( ) ))
{
cur = TimerListHead;
TimerListHead = TimerListHead->Next;
exec_cb( cur->Callback );
}
/* start the next TimerListHead if it exists AND NOT running */
if(( TimerListHead != NULL ) && (TimerListHead->IsRunning == false))
{
TimerSetTimeout( TimerListHead );
}
}
void TimerStop( TimerEvent_t *obj )
{
CPSR_ALLOC();
RHINO_CPU_INTRPT_DISABLE();
TimerEvent_t* prev = TimerListHead;
TimerEvent_t* cur = TimerListHead;
// List is empty or the Obj to stop does not exist
if( ( TimerListHead == NULL ) || ( obj == NULL ) )
{
RHINO_CPU_INTRPT_ENABLE();
return;
}
if( TimerListHead == obj ) // Stop the Head
{
if( TimerListHead->IsRunning == true ) // The head is already running
{
if( TimerListHead->Next != NULL )
{
TimerListHead->IsRunning = false;
TimerListHead = TimerListHead->Next;
TimerSetTimeout( TimerListHead );
}
else
{
aos_lrwan_time_itf.stop_alarm( );
TimerListHead = NULL;
}
}
else // Stop the head before it is started
{
if( TimerListHead->Next != NULL )
{
TimerListHead = TimerListHead->Next;
}
else
{
TimerListHead = NULL;
}
}
}
else // Stop an object within the list
{
while( cur != NULL )
{
if( cur == obj )
{
if( cur->Next != NULL )
{
cur = cur->Next;
prev->Next = cur;
}
else
{
cur = NULL;
prev->Next = cur;
}
break;
}
else
{
prev = cur;
cur = cur->Next;
}
}
}
RHINO_CPU_INTRPT_ENABLE();
}
static bool TimerExists( TimerEvent_t *obj )
{
TimerEvent_t* cur = TimerListHead;
while( cur != NULL )
{
if( cur == obj )
{
return true;
}
cur = cur->Next;
}
return false;
}
void TimerReset( TimerEvent_t *obj )
{
TimerStop( obj );
TimerStart( obj );
}
void TimerSetValue( TimerEvent_t *obj, uint32_t value )
{
TimerStop( obj );
aos_lrwan_time_itf.set_timer_val(obj, value);
}
TimerTime_t TimerGetCurrentTime( void )
{
return aos_lrwan_time_itf.get_current_time();
}
TimerTime_t TimerGetElapsedTime( TimerTime_t past )
{
return aos_lrwan_time_itf.compute_elapsed_time(past);
}
static void TimerSetTimeout( TimerEvent_t *obj )
{
aos_lrwan_time_itf.set_timeout(obj);
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,164 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Timer objects and scheduling management
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
/******************************************************************************
* @file timeServer.h
* @author MCD Application Team
* @version V1.1.1
* @date 01-June-2017
* @brief is the timer server driver
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TIMESERVER_H__
#define __TIMESERVER_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "utilities.h"
/* Exported types ------------------------------------------------------------*/
/*!
* \brief Timer object description
*/
typedef struct TimerEvent_s
{
uint32_t Timestamp; //! Expiring timer value in ticks from TimerContext
uint32_t ReloadValue; //! Reload Value when Timer is restarted
bool IsRunning; //! Is the timer currently running
void ( *Callback )( void ); //! Timer IRQ callback function
struct TimerEvent_s *Next; //! Pointer to the next Timer object.
} TimerEvent_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/*!
* \brief Initializes the timer object
*
* \remark TimerSetValue function must be called before starting the timer.
* this function initializes timestamp and reload value at 0.
*
* \param [IN] obj Structure containing the timer object parameters
* \param [IN] callback Function callback called at the end of the timeout
*/
void TimerInit( TimerEvent_t *obj, void ( *callback )( void ) );
/*!
* \brief Timer IRQ event handler
*
* \note Head Timer Object is automaitcally removed from the List
*
* \note e.g. it is snot needded to stop it
*/
void TimerIrqHandler( void );
/*!
* \brief Starts and adds the timer object to the list of timer events
*
* \param [IN] obj Structure containing the timer object parameters
*/
void TimerStart( TimerEvent_t *obj );
/*!
* \brief Stops and removes the timer object from the list of timer events
*
* \param [IN] obj Structure containing the timer object parameters
*/
void TimerStop( TimerEvent_t *obj );
/*!
* \brief Resets the timer object
*
* \param [IN] obj Structure containing the timer object parameters
*/
void TimerReset( TimerEvent_t *obj );
/*!
* \brief Set timer new timeout value
*
* \param [IN] obj Structure containing the timer object parameters
* \param [IN] value New timer timeout value
*/
void TimerSetValue( TimerEvent_t *obj, uint32_t value );
/*!
* \brief Read the current time
*
* \retval returns current time in ms
*/
TimerTime_t TimerGetCurrentTime( void );
/*!
* \brief Return the Time elapsed since a fix moment in Time
*
* \param [IN] savedTime fix moment in Time
* \retval time returns elapsed time in ms
*/
TimerTime_t TimerGetElapsedTime( TimerTime_t savedTime );
#ifdef __cplusplus
}
#endif
#endif /* __TIMESERVER_H__*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,86 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Timer objects and scheduling management
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
/******************************************************************************
* @file timer.h
* @author MCD Application Team
* @version V1.1.1
* @date 01-June-2017
* @brief wrapper to timer server
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TIMER_H__
#define __TIMER_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "timeServer.h"
/* Exported types ------------------------------------------------------------*/
/*!
* \brief Timer object description
*/
#ifdef __cplusplus
}
#endif
#endif /* __TIMER_H__*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,91 @@
/*
* Copyright (C) 2015-2017 Alibaba Group Holding Limited
*/
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Helper functions implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "utilities.h"
/*!
* Redefinition of rand() and srand() standard C functions.
* These functions are redefined in order to get the same behavior across
* different compiler toolchains implementations.
*/
// Standard random functions redefinition start
#define RAND_LOCAL_MAX 2147483647L
static uint32_t next = 1;
int32_t rand1( void )
{
return ( ( next = next * 1103515245L + 12345L ) % RAND_LOCAL_MAX );
}
void srand1( uint32_t seed )
{
next = seed;
}
// Standard random functions redefinition end
int32_t randr( int32_t min, int32_t max )
{
return ( int32_t )rand1( ) % ( max - min + 1 ) + min;
}
void memcpy1( uint8_t *dst, const uint8_t *src, uint16_t size )
{
while( size-- )
{
*dst++ = *src++;
}
}
void memcpyr( uint8_t *dst, const uint8_t *src, uint16_t size )
{
dst = dst + ( size - 1 );
while( size-- )
{
*dst-- = *src++;
}
}
void memset1( uint8_t *dst, uint8_t value, uint16_t size )
{
while( size-- )
{
*dst++ = value;
}
}
int8_t Nibble2HexChar( uint8_t a )
{
if( a < 10 )
{
return '0' + a;
}
else if( a < 16 )
{
return 'A' + ( a - 10 );
}
else
{
return '?';
}
}

View file

@ -0,0 +1,149 @@
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
Description: Helper functions implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis and Gregory Cristian
*/
/******************************************************************************
* @file utilities.h
* @author MCD Application Team
* @version V1.1.1
* @date 01-June-2017
* @brief Header for driver utilities.c module
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
#ifndef __UTILITIES_H__
#define __UTILITIES_H__
/* prepocessor directive to align buffer*/
#define ALIGN(n) __attribute__((aligned(n)))
typedef uint32_t TimerTime_t;
/*!
* \brief Returns the minimum value between a and b
*
* \param [IN] a 1st value
* \param [IN] b 2nd value
* \retval minValue Minimum value
*/
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
/*!
* \brief Returns the maximum value between a and b
*
* \param [IN] a 1st value
* \param [IN] b 2nd value
* \retval maxValue Maximum value
*/
#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
/*!
* \brief Returns 2 raised to the power of n
*
* \param [IN] n power value
* \retval result of raising 2 to the power n
*/
#define POW2( n ) ( 1 << n )
/*!
* \brief Initializes the pseudo random generator initial value
*
* \param [IN] seed Pseudo random generator initial value
*/
void srand1( uint32_t seed );
/*!
* \brief Computes a random number between min and max
*
* \param [IN] min range minimum value
* \param [IN] max range maximum value
* \retval random random value in range min..max
*/
int32_t randr( int32_t min, int32_t max );
/*!
* \brief Copies size elements of src array to dst array
*
* \remark STM32 Standard memcpy function only works on pointers that are aligned
*
* \param [OUT] dst Destination array
* \param [IN] src Source array
* \param [IN] size Number of bytes to be copied
*/
void memcpy1( uint8_t *dst, const uint8_t *src, uint16_t size );
/*!
* \brief Copies size elements of src array to dst array reversing the byte order
*
* \param [OUT] dst Destination array
* \param [IN] src Source array
* \param [IN] size Number of bytes to be copied
*/
void memcpyr( uint8_t *dst, const uint8_t *src, uint16_t size );
/*!
* \brief Set size elements of dst array with value
*
* \remark STM32 Standard memset function only works on pointers that are aligned
*
* \param [OUT] dst Destination array
* \param [IN] value Default value
* \param [IN] size Number of bytes to be copied
*/
void memset1( uint8_t *dst, uint8_t value, uint16_t size );
/*!
* \brief Converts a nibble to an hexadecimal character
*
* \param [IN] a Nibble to be converted
* \retval hexChar Converted hexadecimal character
*/
int8_t Nibble2HexChar( uint8_t a );
#endif // __UTILITIES_H__

View file

@ -0,0 +1,49 @@
NAME := lorawan
$(NAME)_SOURCES := lora/system/crypto/aes.c \
lora/system/crypto/cmac.c \
lora/system/timeServer.c \
lora/system/low_power.c \
lora/system/utilities.c \
lora/system/delay.c \
lora/mac/region/Region.c \
lora/mac/region/RegionCommon.c \
lora/mac/LoRaMac.c \
lora/mac/LoRaMacCrypto.c
GLOBAL_INCLUDES += . \
lora/system/crypto \
lora/radio \
lora/mac \
lora/mac/region \
lora/system
linkwan?=0
ifeq ($(linkwan), 1)
GLOBAL_DEFINES += CONFIG_LINKWAN
GLOBAL_DEFINES += CONFIG_DEBUG_LINKWAN
GLOBAL_DEFINES += CONFIG_AOS_DISABLE_TICK
GLOBAL_DEFINES += REGION_CN470A
$(NAME)_SOURCES += linkwan/region/RegionCN470A.c
$(NAME)_SOURCES += linkwan/linkwan.c
GLOBAL_INCLUDES += linkwan/include
GLOBAL_INCLUDES += linkwan/region
linkwanat ?= 0
ifeq ($(linkwanat), 1)
GLOBAL_DEFINES += CONFIG_LINKWAN_AT
$(NAME)_SOURCES += linkwan/linkwan_at.c
endif
else
$(NAME)_SOURCES += lora/mac/region/RegionAS923.c \
lora/mac/region/RegionAU915.c \
lora/mac/region/RegionCN470.c \
lora/mac/region/RegionCN779.c \
lora/mac/region/RegionEU433.c \
lora/mac/region/RegionEU868.c \
lora/mac/region/RegionIN865.c \
lora/mac/region/RegionKR920.c \
lora/mac/region/RegionUS915.c \
lora/mac/region/RegionUS915-Hybrid.c
endif