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          5void RegionEU868ApplyCFList( ApplyCFListParams_t* applyCFList )
{ChannelParams_t newChannel;ChannelAddParams_t channelAdd;ChannelRemoveParams_t channelRemove;// Setup default datarate rangenewChannel.DrRange.Value = ( DR_5 << 4 ) | DR_0; //设置数据速率范围 DR_0 ~ DR_5 // Size of the optional CF listif( applyCFList->Size != 16 ) //Lorawan规范中CFList是可选项,长度为16字节,具体的定义在【区域参数文档】中{return;}// Last byte is RFU, don't take it into account// EU868 的CFList设置通道不会修改默认通道EU868_NUMB_DEFAULT_CHANNELSfor( 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 frequencynewChannel.Frequency = (uint32_t) applyCFList->Payload[i];//每个通道频率占用3个字节,单位:100HznewChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 1] << 8 );newChannel.Frequency |= ( (uint32_t) applyCFList->Payload[i + 2] << 16 );newChannel.Frequency *= 100;// Initialize alternative frequency to 0newChannel.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 channelsRegionEU868ChannelAdd( &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 );// ChannelsNvmCtx.Channels[0] = ( ChannelParams_t ) EU868_LC1;//通道参数设置NvmCtx.Channels[1] = ( ChannelParams_t ) EU868_LC2;NvmCtx.Channels[2] = ( ChannelParams_t ) EU868_LC3;// Initialize the channels default maskNvmCtx.ChannelsDefaultMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); //缺省使能通道,这3个通道必须开启// Update the channels maskRegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 1 );//使用缺省使能通道 更新使能通道break;}...case INIT_TYPE_RESTORE_DEFAULT_CHANNELS:{// Restore channels default maskNvmCtx.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 channelsNvmCtx.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[] 为 16bitfor( 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 enabledcontinue;}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;}...
}

LoraWAN源码学习(1)--通道选择详解相关推荐

  1. php get 返回源码,php源码 fsockopen获取网页内容实例详解

    PHP fsockopen函数说明: Open Internet or Unix domain socket connection(打开套接字链接) Initiates a socket connec ...

  2. UVM源码分析之factory机制详解

    前言 作者在学习了一段时间的UVM factory源码之后写下此文,旨在记录自己的学习成果,毕竟好记性不如烂笔头嘛,当然如果能帮助到对这部分有疑惑的同仁就更好了.作者是在笔记本电脑上的windows环 ...

  3. Java API源码在哪里找_详解查看JAVA API及JAVA源码的方法

    在java的日常学习中,我们有时候会需要看java的api说明,或者是查看java的源码,使我们更好的了解java,接下来我就来说说如何查看java的api以及java源码 对于java的api,一般 ...

  4. FreeRTOS 之一 源码目录文件 及 移植详解

    写在前面 2018/1/15更新了文章中的部分错误. FreeRTOS源码为最新版的10.0.1.FreeRTOS 10包含两个重要的新功能:流缓冲区和消息缓冲区. 从10.0.0开始,FreeRTO ...

  5. Android进阶——Small源码分析之启动流程详解

    前言 插件化现在已经是Android工程师必备的技能之一,只是学会怎么使用是不行的,所以蹭有时间研究一下Small的源码.对于插件化主要解决的问题是四大组件的加载和资源的加载,读懂所有Small源码需 ...

  6. Android内核开发:源码的版本与分支详解

    我想很多初学者或许跟我一样,看完Android源码下载相关的文章以后,就开始兴致勃勃地去下载Android源码了,但是下载完了源码后,有没有像我一样产生如下几个困惑呢? (1) Android版本有哪 ...

  7. linux设备驱动开发详解源码,linux设备驱动开发详解光盘源码.rar

    压缩包 : linux设备驱动开发详解光盘源码.rar 列表 19/busybox源代码/busybox-1.2.1.tar.bz2 19/MTD工具/mtd-utils-1.0.0.tar.gz 1 ...

  8. Android源码中的目录结构详解

    由于自己从事与底层开发,一开始对项目结构不是很清楚,然后就百度找到了源码结构,我觉得讲的很清楚.Android 2.1源码结构 |-- Makefile |-- bionic              ...

  9. STL源码剖析---红黑树原理详解上

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7740956 一.红黑树概述 红黑树和我们以前学过的AVL树类似,都是在进 ...

  10. STL源码剖析---红黑树原理详解下

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7760584       算法导论书上给出的红黑树的性质如下,跟STL源码 ...

最新文章

  1. 爬虫之selenium对cookie的处理
  2. C 语言编程 — 数据类型转换
  3. boost::math::quadrature::daubechies_wavelet_transform用法的测试程序
  4. 剑指offer 栈的压入、弹出序列
  5. CRM订单上状态字段在UI的显示逻辑
  6. neo4j / cypher:悬挂查询参数
  7. 面试题24 二叉搜索树的后序遍历序列
  8. mysql配置连接远程_MySql配置远程访问
  9. 最简单的基于FFmpeg的移动端例子附件:IOS自带播放器
  10. 《高性能javascript》随笔
  11. Idea导入MySQL驱动包
  12. 安徽自招大专计算机,2021年安徽自主招生学校名单有哪些,安徽自主招生大专院校名单【详细版】...
  13. 服务器的硬件设备及raid
  14. 计算机术语alu,计算机术语大全
  15. 计算机类的毕业论文是怎么查重的,论文检测软件是如何实现查重功能的
  16. python3 爬虫 爬取华为应用市场 APP应用评论(一)爬取全部评论——学霸君
  17. BUAA-2023软件工程——团队成员介绍
  18. H5 直播的疯狂点赞动画是如何实现的?(附完整源码)
  19. Web前端之样式继承与其他概念
  20. vector erase操作

热门文章

  1. 复制网站zencart模板的方法
  2. Android车载蓝牙相关开发1:概述及准备
  3. ue4 改变枢轴位置_在UE4引擎中做卡通描边的一点心得
  4. (官网)虚幻3--基础游戏快速入门
  5. 蓝牙Beacon广播数据包格式以及解析
  6. php简述微信支付接口开发流程,php微信支付接口开发程序(流程已通)
  7. Makefile:14: config-host.mak: No such file or directory
  8. 测试管理工具的基本功能有哪些?
  9. 个人电脑组策略应用全攻略
  10. netty报错Force-closing a channel whose registration task was not accepted by an event loop处理办法