LoraWAN源码学习(1)–通道选择详解
文章目录
- LoraWAN源码学习(1)--通道选择详解
- 入网通道配置
- 收发通道配置
- 应用层设置通道/缺省通道接口
本篇代码以EU868为例。
入网通道配置
#define EU868_JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) )
EU868
入网默认打开CH1/2/3
(分别对应频点868.1/868.3/868.5
MHz)。入网成功后,join accept
消息中CFList
对通道设置,需要说明的是CFList不会对默认通道做修改,设置通道分别是CH4~8
每个通道占用3个字节,单位:100Hz- 下面是
join accept
中CFList
代码解析
//EU868默认3个通道
#define EU868_NUMB_DEFAULT_CHANNELS 3
//CFList 支持修改的通道数,EU868默认最多5个通道
#define EU868_NUMB_CHANNELS_CF_LIST 5
void RegionEU868ApplyCFList( ApplyCFListParams_t* applyCFList )
{
ChannelParams_t newChannel;
ChannelAddParams_t channelAdd;
ChannelRemoveParams_t channelRemove;
// Setup default datarate range
newChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0; //设置数据速率范围 DR_0 ~ DR_5
// Size of the optional CF list
if( applyCFList->Size != 16 ) //Lorawan规范中CFList是可选项,长度为16字节,具体的定义在【区域参数文档】中
{
return;
}
// Last byte is RFU, don't take it into account
// EU868 的CFList设置通道不会修改默认通道EU868_NUMB_DEFAULT_CHANNELS
for( uint8_t i = 0, chanIdx = EU868_NUMB_DEFAULT_CHANNELS; chanIdx < EU868_MAX_NB_CHANNELS; i+=3, chanIdx++ )
{
if( chanIdx < ( EU868_NUMB_CHANNELS_CF_LIST + EU868_NUMB_DEFAULT_CHANNELS ) )
{
// Channel frequency
newChannel.Frequency = (uint32_t) applyCFList->Payload[i];//每个通道频率占用3个字节,单位:100Hz
newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );
newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );
newChannel.Frequency *= 100;
// Initialize alternative frequency to 0
newChannel.Rx1Frequency = 0;
}
else
{
newChannel.Frequency = 0;
newChannel.DrRange.Value = 0;
newChannel.Rx1Frequency = 0;
}
if( newChannel.Frequency != 0 )
{
channelAdd.NewChannel = &newChannel;
channelAdd.ChannelId = chanIdx;
// Try to add all channels
RegionEU868ChannelAdd( &channelAdd );//频率不为0,添加通道
}
else
{
channelRemove.ChannelId = chanIdx;
RegionEU868ChannelsRemove( &channelRemove );//频率为0,删除通道
}
}
}
收发通道配置
- 参数初始化
EU868与入网一样默认打开
CH1/2/3(分别对应频点
868.1/868.3/868.5`MHz),且这3个通道必须开启
void RegionEU868InitDefaults( InitDefaultsParams_t* params )
{
Band_t bands[EU868_MAX_NB_BANDS] =
{
EU868_BAND0,
EU868_BAND1,
EU868_BAND2,
EU868_BAND3,
EU868_BAND4,
};
switch( params->Type )
{
case INIT_TYPE_INIT:
{
// Initialize bands
//初始化bands, 结构为 { DutyCycle, TxMaxPower, LastJoinTxDoneTime, LastTxDoneTime, TimeOff }
//实际使用组根据通道Channels[x].Band选择,例如通道0中Band=1,EU868_LC1中定义如下:
//{ Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
//#define EU868_LC1 { 868100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
memcpy1( ( uint8_t* )NvmCtx.Bands, ( uint8_t* )bands, sizeof( Band_t ) * EU868_MAX_NB_BANDS );
// Channels
NvmCtx.Channels[0] = ( ChannelParams_t ) EU868_LC1;//通道参数设置
NvmCtx.Channels[1] = ( ChannelParams_t ) EU868_LC2;
NvmCtx.Channels[2] = ( ChannelParams_t ) EU868_LC3;
// Initialize the channels default mask
NvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); //缺省使能通道,这3个通道必须开启
// Update the channels mask
RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 );//使用缺省使能通道 更新使能通道
break;
}
...
case INIT_TYPE_RESTORE_DEFAULT_CHANNELS:
{
// Restore channels default mask
NvmCtx.ChannelsMask[0] |= NvmCtx.ChannelsDefaultMask[0];//这里只是从新使能缺省通道,缺省通道之外的通道不受影响
break;
}
default:
{
break;
}
}
}
- 上边只是协议栈针对每个区域初始化的配置,实际上lorawan每次发射前会调用
RegionNextChannel()
选择发射的信道及根据上次发射时长和发送占空比(DutyCycle)计算发射关闭时间(dutyCycleTimeOff),还是以EU868为例。
LoRaMacStatus_t RegionEU868NextChannel( NextChanParams_t* nextChanParams, uint8_t* channel, TimerTime_t* time, TimerTime_t* aggregatedTimeOff )
{
uint8_t nbEnabledChannels = 0;
uint8_t delayTx = 0;
uint8_t enabledChannels[EU868_MAX_NB_CHANNELS] = { 0 };
TimerTime_t nextTxDelay = 0;
if( RegionCommonCountChannels( NvmCtx.ChannelsMask, 0, 1 ) == 0 )//计算使能的信道数,为0则恢复默认通道
{ // Reactivate default channels
NvmCtx.ChannelsMask[0] |= LC( 1 ) + LC( 2 ) + LC( 3 );
}
TimerTime_t elapsed = TimerGetElapsedTime( nextChanParams->LastAggrTx );
if( ( nextChanParams->LastAggrTx == 0 ) || ( nextChanParams->AggrTimeOff <= elapsed ) )
{
// Reset Aggregated time off
*aggregatedTimeOff = 0;
// Update bands Time OFF
// 根据NvmCtx.Bands参数计算 发送延时时间【详细计算源码单独一篇讲解】
nextTxDelay = RegionCommonUpdateBandTimeOff( nextChanParams->Joined, nextChanParams->DutyCycleEnabled, NvmCtx.Bands, EU868_MAX_NB_BANDS );
// Search how many channels are enabled
// 获取所有使能的通道,enabledChannels[]存放使能通道的索引,nbEnabledChannels返回使能通道的个数
nbEnabledChannels = CountNbOfEnabledChannels( nextChanParams->Joined, nextChanParams->Datarate,
NvmCtx.ChannelsMask, NvmCtx.Channels,
NvmCtx.Bands, enabledChannels, &delayTx );
}
...
if( nbEnabledChannels > 0 )
{//如果有使能的通道,则随机选择一个,立即发送
// We found a valid channel
*channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )];//在使能通道数组中随机返回获取一个 使能通道索引
*time = 0;
return LORAMAC_STATUS_OK;
}
...
return LORAMAC_STATUS_NO_CHANNEL_FOUND;
}
}
- 获取可以发送的通道
- 发送通道未被使能
- 未入网情况下,入网通道未使能
- 数据速率不在范围内
- 发送占空比关闭时间
TimeOff
不为0
static uint8_t CountNbOfEnabledChannels( bool joined, 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 < EU868_MAX_NB_CHANNELS; i += 16, k++ )
{//每一组通道 channelsMask[] 为 16bit
for( uint8_t j = 0; j < 16; j++ )
{
if( ( channelsMask[k] & ( 1 << j ) ) != 0 )//通道第k组 j位 使能
{
if( channels[i + j].Frequency == 0 )
{ // Check if the channel is enabled
continue;
}
if( joined == false )
{//没入网
if( ( EU868_JOIN_CHANNELS & ( 1 << j ) ) == 0 )
{//通道第k组j位 入网通道未使能
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
//检查数据速率DR是否合法,每个通道的DR范围都有独立配置,如下两个通道范围均为 DR_0 ~ DR_5:
//{ Frequency [Hz], RX1 Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band }
//#define EU868_LC1 { 868100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
//#define EU868_LC2 { 868300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 }
continue;
}
if( bands[channels[i + j].Band].TimeOff > 0 )
{ // Check if the band is available for transmission
//检查通道 TimeOff 如果不为0,则需要延时发送,不计入使能通道
delayTransmission++; //延时发送通道计数
continue;
}
enabledChannels[nbEnabledChannels++] = i + j; //
}
}
}
*delayTx = delayTransmission;
return nbEnabledChannels;
}
应用层设置通道/缺省通道接口
LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
{
...
case MIB_CHANNELS_DEFAULT_MASK: {
chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
chanMaskSet.ChannelsMaskType = CHANNELS_DEFAULT_MASK;
if ( RegionChanMaskSet( LoRaMacRegion, &chanMaskSet ) == false ) {
status = LORAMAC_STATUS_PARAMETER_INVALID;
}
break;
}
case MIB_CHANNELS_MASK: {
chanMaskSet.ChannelsMaskIn = mibSet->Param.ChannelsMask;
chanMaskSet.ChannelsMaskType = CHANNELS_MASK;
if ( RegionChanMaskSet( LoRaMacRegion, &chanMaskSet ) == false ) {
status = LORAMAC_STATUS_PARAMETER_INVALID;
}
break;
}
...
}