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.5MHz)。入网成功后,join accept消息中CFList对通道设置,需要说明的是CFList不会对默认通道做修改,设置通道分别是CH4~8
    每个通道占用3个字节,单位:100Hz

    在这里插入图片描述
  • 下面是join acceptCFList代码解析
//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;
    }
}
  • 获取可以发送的通道
    1. 发送通道未被使能
    2. 未入网情况下,入网通道未使能
    3. 数据速率不在范围内
    4. 发送占空比关闭时间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;
        }
	...
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ORB-SLAM2是一种用于实时单目、双目和RGB-D相机的视觉SLAM系统,是由西班牙国家研究委员会(CSIC)领导的研究团队开发的。它使用了ORB( Oriented FAST and Rotated BRIEF,基于FAST角点检测和BRIEF描述子的改进算法)上的特征,并使用Bundle Adjustment优化算法来提高相机姿态的估计精度。ORB-SLAM2码中文详解pdf,主要是对ORB-SLAM2算法进行详细的解析,方便了解该算法并进行修改定制。以下是本人对具体内容的一些观点: 首先,该pdf分为5部分,分别是ORB-SLAM2算法的总体介绍、系统设计、系统架构与流程、实验结果与分析和码解读。其中,总体介绍部分介绍了ORB-SLAM2系统的功能和应用场景,并提出了该系统的优势和不足点。系统设计部分详细介绍了系统的设计思路和实现方式,主要包括相机模型、特征提取、特征匹配、姿态估计和位姿优化等方面。系统架构与流程部分则重点介绍了ORB-SLAM2实现过程中的整体架构和流程。 接着,实验结果与分析部分介绍了ORB-SLAM2在Kitti数据集、EuRoC MAV数据集和TUM RGB-D SLAM dataset等公共的数据集上的实验结果,分析了系统的性能和稳定性,并在实验过程中解决了一些系统出现的问题。最后,码解读部分是对ORB-SLAM2代码的详细解释,方便参考者了解和修改该算法。该部分包括ORB-SLAM2的主要模块(包括System、Tracker、LoopClosing、Map和Optimizer等模块)的代码解释和功能说明。同时,该部分还详细介绍了ORB特征提取和尺度恢复、相机运动估计、位姿优化和闭环检测等关键技术的代码实现和运行原理。 总的来说,ORB-SLAM2码中文详解pdf系统性地介绍了ORB-SLAM2算法的原理、设计思路和实现流程,方便参考者了解该算法并进行修改优化。同时,该文还详细介绍了ORB-SLAM2的代码实现和关键技术,对学习和研究计算机视觉和SLAM技术的人士都有很大的参考价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值