LoRaWAN实战 LinkADR命令的源码分析

前言

LinkADR是LoRaWAN网络管理中相当重要的一个MAC命令,其解析占用了183行。索性专门写篇源码解析,记录下。

阅读此文前,最好再把第五章的这个命令好好翻一翻,代码和协议才能对应上。

我正在陆续对协议的各个章节进行翻译,具体其他章节的译文,以及译文之外的代码解析,可点此查看帖子LoRa学习笔记_汇总

本文作者twowinter,转载请注明作者:http://blog.csdn.net/iotisan/

LinkADRReq 的源码解析

按照代码思路走一遍。

1.解析 DataRate_TXPower 字段

datarate = payload[macIndex++];
txPower = datarate & 0x0F;
datarate = ( datarate >> 4 ) & 0x0F;

if( ( AdrCtrlOn == false ) &&
    ( ( LoRaMacParams.ChannelsDatarate != datarate ) || ( LoRaMacParams.ChannelsTxPower != txPower ) ) )
{ // ADR disabled don‘t handle ADR requests if server tries to change datarate or txpower
    // Answer the server with fail status
    // Power ACK     = 0
    // Data rate ACK = 0
    // Channel mask  = 0
    AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 );
    macIndex += 3;  // Skip over the remaining bytes of the request
    break;
}

如果终端ADR没开,那么就立即丢弃本命令处理。这里的macIndex += 3是对应LinkADRReq的剩余命令长度3而言的。

2.解析 ChMask 字段

chMask = ( uint16_t )payload[macIndex++];
chMask |= ( uint16_t )payload[macIndex++] << 8;

3.解析 Redundancy 字段

nbRep = payload[macIndex++];
chMaskCntl = ( nbRep >> 4 ) & 0x07;
nbRep &= 0x0F;
if( nbRep == 0 )
{
    nbRep = 1;
}

把字段中的 chMaskCntl 和 nbRep 都给解析了出来。

4.按地区规定处理 chMaskCntl ,及判断 ChMask 有效性

#elif defined( USE_BAND_470 )
    if( chMaskCntl == 6 )
    {
        // Enable all 125 kHz channels
        for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ )
        {
            for( uint8_t j = 0; j < 16; j++ )
            {
                if( Channels[i + j].Frequency != 0 )
                {
                    channelsMask[k] |= 1 << j;
                }
            }
        }
    }
    else if( chMaskCntl == 7 )
    {
        status &= 0xFE; // Channel mask KO
    }
    else
    {
        for( uint8_t i = 0; i < 16; i++ )
        {
            if( ( ( chMask & ( 1 << i ) ) != 0 ) &&
                ( Channels[chMaskCntl * 16 + i].Frequency == 0 ) )
            {// Trying to enable an undefined channel
                status &= 0xFE; // Channel mask KO
            }
        }
        channelsMask[chMaskCntl] = chMask;
    }

如果 chMaskCntl 为6,则所有信道都使能。如果 chMaskCntl 为7,则由于未定义返回失败。

其他有效 chMaskCntl 情况下,先检查是否有未定义的频点,如果没问题则更新对应的channelsMask。

5.判断速率有效性

if( ValidateDatarate( datarate, channelsMask ) == false )
{
    status &= 0xFD; // Datarate KO
}

6.判断发射功率有效性

if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false )
{
    status &= 0xFB; // TxPower KO
}

7.全部判断通过后更新参数

if( ( status & 0x07 ) == 0x07 )
{
    LoRaMacParams.ChannelsDatarate = datarate;
    LoRaMacParams.ChannelsTxPower = txPower;

    memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )channelsMask, sizeof( LoRaMacParams.ChannelsMask ) );

    LoRaMacParams.ChannelsNbRep = nbRep;
}

8.回复MAC命令 LinkADRAns

AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 );

突然发现 AddMacCommand 的形参只有CID加2字节的回复,我是太无聊,把终端所有MAC命令都翻了一遍,确认所有payload确实是小于2字节。再次赞扬LoRaWAN协议的精简作风。

End



时间: 2024-12-14 18:17:43

LoRaWAN实战 LinkADR命令的源码分析的相关文章

【Android实战】----从Retrofit源码分析到Java网络编程以及HTTP权威指南想到的

一.简介 接上一篇[Android实战]----基于Retrofit实现多图片/文件.图文上传中曾说非常想搞明白为什么Retrofit那么屌.最近也看了一些其源码分析的文章以及亲自查看了源码,发现其对Java网络编程及HTTP权威指南有了一个很好的诠释.一直以来,都信奉一个原则,在这个新技术日新月异的时代,如何在Java界立足,凭借的就两点: 1.基本功,包括:Java基本知识,(Java编程思想.Effective Java),Java进阶(Java虚拟机.Java设计模式).网络相关(这个时

第10课:[实战] Redis 网络通信模块源码分析(3)

redis-server 接收到客户端的第一条命令 redis-cli 给 redis-server 发送的第一条数据是 *1\r\n\$7\r\nCOMMAND\r\n .我们来看下对于这条数据如何处理,单步调试一下 readQueryFromClient 调用 read 函数收取完数据,接着继续处理 c→querybuf 的代码即可.经实际跟踪调试,调用的是 processInputBuffer 函数,位于 networking.c 文件中: /* This function is call

Linux c 开发 - Memcached源码分析之命令解析(2)

前言 从我们上一章<Linux c 开发 - Memcached源码分析之基于Libevent的网络模型>我们基本了解了Memcached的网络模型.这一章节,我们需要详细解读Memcached的命令解析. 我们回顾上一章发现Memcached会分成主线程和N个工作线程.主线程主要用于监听accpet客户端的Socket连接,而工作线程主要用于接管具体的客户端连接. 主线程和工作线程之间主要通过基于Libevent的pipe的读写事件来监听,当有连接练上来的时候,主线程会将连接交个某一个工作线

docker stats 命令源码分析

本文是基于docker 1.10.3版本的源码,对docker stats命令进行源码分析,看看docker stats命令输出的数据是从cgroups fs中怎么怎么计算出来的. docker client相关代码入口可参考:/docker/docker/api/client/stats.go#141 docker daemon相关代码入口可参考:/docker/docker/daemon/daemon.go#1474 源码分析结果 Cpu数据: docker daemon会记录这次读取/sy

S5PV210-uboot源码分析-uboot环境变量

9.1.uboot的环境变量 1.环境变量的作用 (1)在我们不改变uboot源代码的情况下,只需要改变环境变量的值就可以改变uboot运行时的数据和一些特性.比如说,通过修改bootdelay环境变量,就可以更改开机倒数的秒数. 2.环境变量的优先级 (1)uboot代码当中有一个值,环境变量(DDR 环境变量的分区中)中也有一个值,uboot程序实际运行时,规则是,如果环境变量(DDR中环境变量的分区)为空,则使用代码中的环境变量的值,如果环境变量不为空,优先使用环境变对应的值. (2)比如

zeromq源码分析笔记之线程间收发命令(2)

在zeromq源码分析笔记之架构说到了zmq的整体架构,可以看到线程间通信包括两类,一类是用于收发命令,告知对象该调用什么方法去做什么事情,命令的结构由command_t结构体确定:另一类是socket_base_t实例与session的消息通信,消息的结构由msg_t确定.命令的发送与存储是通过mailbox_t实现的,消息的发送和存储是通过pipe_t实现的,这两个结构都会详细说到,今天先说一下线程间的收发命令. zeromq的线程可分为两类,一类是io线程,像reaper_t.io_thr

Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机

文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多"开箱即用"的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内藏玄机 Spring Boot提供了很多"开箱即用"的依赖模块,都是以spring-boot-starter-xx作为命名的.例如,之前提到的 spring-boot-starter-redis.spring-boot-starter-data-mongodb.spri

Docker源码分析之——Docker Client的启动与命令执行

在上文Docker源码分析之--Docker Daemon的启动 中,介绍了Docker Daemon进程的启动.Docker Daemon可以认为是一个Docker作为Server的运行载体,而真正发送关于docker container操作的请求的载体,在于Docker Client.本文从Docker源码的角度,分析Docker Client启动与执行请求的过程. Docker Client启动的流程与Docker Daemon启动的过程相仿.首先执行reexec.Init():随后解析f

nginx源码分析--nginx外部信号 命令参数

nginx命令行参数 不像许多其他软件系统,Nginx 仅有几个命令行参数,完全通过配置文件来配置 -c </path/to/config> 为 Nginx 指定一个配置文件,来代替缺省的. -t 不运行,而仅仅测试配置文件.nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件. -v 显示 nginx 的版本. -V 显示 nginx 的版本,编译器版本和配置参数. nginx控制信号 可以使用信号系统来控制主进程.默认,nginx 将其主进程的 pid 写入到 /u