Hello, 又来饮茶哈

加张台啊!

【Device】入网参数的保存

ST 适配的 LoRaWAN 协议栈 stm32-mw-lorawan 当前版本:2.6.2 由于是 ST 适配过,所以和 Semtech 开源的 LoRaMac-node 协议栈还是有差别的 一、OTAA 1. 参数 OTAA 主要参数如下: DevAddr AppSKey NwkSKey NetworkActivation 2. 入网保存参数的流程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 /* Mac/LoRaMac.c */ static void ProcessRadioRxDone( void ) { ... switch( macHdr.Bits.MType ) { case FRAME_TYPE_JOIN_ACCEPT: { ... SecureElementGetJoinEui( joinEui ); /* 解密 */ macCryptoStatus = LoRaMacCryptoHandleJoinAccept( JOIN_REQ, joinEui, &macMsgJoinAccept ); ... ... /** * 更新设备地址 DevAddr * 1. Nvm.MacGroup2.DevAddr * 2. Nvm.SecureElement.SeNvmDevJoinKey.DevAddrOTAA */ Nvm.MacGroup2.DevAddr = macMsgJoinAccept.DevAddr; SecureElementSetDevAddr( ACTIVATION_TYPE_OTAA, Nvm.MacGroup2.DevAddr ); ... /* 更新激活状态 NetworkActivation */ Nvm.MacGroup2.NetworkActivation = ACTIVATION_TYPE_OTAA; ... ... break; } ... } ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 /* Mac/LoRaMacCrypto.c */ LoRaMacCryptoStatus_t LoRaMacCryptoHandleJoinAccept( JoinReqIdentifier_t joinReqType, uint8_t* joinEUI, LoRaMacMessageJoinAccept_t* macMsg ) { ... { ... /** * 生成密钥 AppSKey * 1. Nvm.SecureElement.KeyList[], 对应的 key id 是 APP_S_KEY */ retval = DeriveSessionKey10x( APP_S_KEY, currentJoinNonce, netID, nonce ); ... #if (defined( LORAMAC_VERSION ) && ( LORAMAC_VERSION == 0x01010100 )) ... #else /** * 生成密钥 NwKSKey * 1. Nvm.SecureElement.KeyList[], 对应的 key id 是 NWK_S_KEY */ retval = DeriveSessionKey10x( NWK_S_KEY, currentJoinNonce, netID, nonce ); #endif ... } ... /** * FCnt 相关统计清零 * CryptoNvm 指向的是 Nvm.Crypto, 实际是 * 1. Nvm.Crypto.FCntList.FCntUp * 2. Nvm.Crypto.FCntList.FCntDown * 3. Nvm.Crypto.FCntList.NFCntDown * 4. Nvm.Crypto.FCntList.AFCntDown */ CryptoNvm->FCntList.FCntUp = 0; CryptoNvm->FCntList.FCntDown = FCNT_DOWN_INITIAL_VALUE; CryptoNvm->FCntList.NFCntDown = FCNT_DOWN_INITIAL_VALUE; CryptoNvm->FCntList.AFCntDown = FCNT_DOWN_INITIAL_VALUE; return LORAMAC_CRYPTO_SUCCESS; } 二、ABP 1. 参数 ABP 要预先配置的参数如下: ...

January 25, 2026 · 11 min · 2329 words

【SonarQube】Cyclomatic Complexity 圈复杂度

Cyclomatic Complexity 来自 SonarQube 函数的复杂度是通过函数体中的逻辑运算符(&&、||)和条件控制语句(if、while、do-while、for、?:、catch、case、default)的数量来衡量的。 计算规则: 默认复杂度是 1,每遇到一次上述符号,复杂度增加 1。 复杂度在 1 到 10 之间的方法被认为是简单的,易于理解和测试。 复杂度在 10 到 20 之间的值表示代码更复杂,但仍然可以理解;然而,由于代码可能包含更多的分支,测试变得更加困难。 复杂度在 20 及以上是典型的具有大量潜在执行路径的代码,只有经过极大的困难和努力才能完全掌握和测试。 复杂度大于 50,肯定是不可维护的,或者说非常然维护的。 错误提示 The Cyclomatic Complexity of this function is 31 which is greater than 20 authorized. The Cyclomatic Complexity of this function is 23 which is greater than 20 authorized. 分析 其中: +1: function definition 表示定义函数时,复杂度默认为 1。 +1: if statement 表示识别到 if 语句,复杂度加 1。 +1: while loop ...

January 18, 2026 · 2 min · 358 words

【SonarQube】Cognitive Complexity 认知复杂度

Cognitive Complexity 来自 SonarQube 认知复杂度旨在弥补传统的圈复杂度在衡量代码可维护性方面的不足: 对于不同结构的代码,即使圈复杂度相同,但是理解难度可能差异很大。 不适合现代的编程语言结构。 计算规则: 忽略简化写法 不计算那些使代码更简洁、已读的结构。 结构增量(Structural Increment) for、while、do-while、if、?:、#if、#ifdef 会增加 1 分。 catch 语句会增加 1 分。 try 和 finally 则不会加入统计。 switch 语句会增加 1 分。 switch 里面的 case 语句则不会加入统计。 同类型的运算符会增加 1 分,但是不同类型的运算符会增加 n 分(n 取决于实际个数)。 if (a && b && c && d) 会增加 1 分,if (a || b || c || d) 会增加 1 分。 if (a && b || c) 会增加 2 分,if (a || (b && c) || d) 会增加 3 分。 ...

January 18, 2026 · 2 min · 338 words

【PyOCD】使用 Vscode 调试

一、安装 PyOCD OpenOCD,Open On-Chip Debugger,主要使用 C 编写。 PyOCD,Python On-Chip Debugger,主要使用 Python 编写。 当前最新版本的 PyOCD 是 v0.42,其依赖的 Python 版本是 >= 3.8.0。 1 2 3 4 5 $ python --version Python 3.12.5 $ pip --version pip 25.3 from C:\Users\Zeepunt\AppData\Roaming\Python\Python312\site-packages\pip (python 3.12) 这里我们使用 pip 工具安装即可。 1 2 3 4 5 6 7 8 $ python -mpip install -U pyocd ... Installing collected packages: pyocd Attempting uninstall: pyocd Found existing installation: pyocd 0.41.0 Uninstalling pyocd-0.41.0: Successfully uninstalled pyocd-0.41.0 Successfully installed pyocd-0.42.0 查看版本信息: ...

January 3, 2026 · 3 min · 506 words

【MT2500A】相关信息

一、产品信息 MT2500A 是金属外壳。 厂商:GL.iNet CPU:MediaTek MT7981B,Dual-core @ 1.3GHz ARMv8 Processor rev 4 Cortex-A53 内存:1GB DDR4 南亚 NT5AD512M16C4-JR 存储:8GB eMMC 三星 KLM8G1GETF-B041 供电:Type-C,5V / 2A PHY 芯片:MediaTek MT7981 内置 PHY 2.5G 芯片:MXL SLNW8 二、硬件引脚 版权声明 本文为「Zeepunt 日常随笔」的原创文章,遵循 CC BY-NC-ND 4.0 许可协议。允许在署名作者、注明原文链接且不作任何更改的前提下非商业性地分享本文。 原文链接:https://zeepunt.github.io/article/router/mt2500a%E7%9B%B8%E5%85%B3%E4%BF%A1%E6%81%AF/ ...

December 28, 2025 · 1 min · 41 words

【Gateway】射频芯片通信

芯片:ESP32-S3(v0.2) IDF 版本:ESP-IDF-v5.5.0 一、SX125x SX125x 指的是 SX1255 和 SX1257。 1. SPI 通信格式 在硬件上,SX125x 的 SPI 引脚连接的是 SX1302 Radio A/B 的 SPI 接口,所以主控是通过 SX1302 来控制 SX125x 的。 对于 SX1302 未提供。 对于 SX125x 1 2 3 4 5 6 7 8 9 10 11 12 13 NSS -----+ +----- | | +-----------------------------------------------------+ SCK ... MOSI +-----+-----------+-----------------+-----------------+-----+ | W/R | Addr[6:0] | Data Write[7:0] | Data Write[7:0] | ... | -----+-----+-----------+-----------------+-----------------+-----+----- MISO +-----------------+-----------------+-----------------+-----+ | xxx | Data Read[7:0] | Data Read[7:0] | ... | -----+-----------------+-----------------+-----------------+-----+----- 寄存器地址范围在 0x00 - 0x13 2. SPI 通信函数 单字节的写操作 ...

December 16, 2025 · 4 min · 849 words

【Node】占空比机制

协议栈代码:LoRaMac-node v4.7.0 参考文档 《RP002-1.0.4 LoRaWAN® Regional Parameters》 《TS001-1.0.4 LoRaWAN® L2 1.0.4 Specification》 一、占空比 1. 区域和占空比 参考《RP002-1.0.4 LoRaWAN® Regional Parameters》1.3 Regional Parameters Summary Tables 有些 Region 是有占空比限制,有些 Region 是没有占空比限制的。 对于动态频点的 Region: 对于固定频点的 Region: 2. 占空比规则 参考《TS001-1.0.4 LoRaWAN® L2 1.0.4 Specification》7 Retransmissions Backoff 3. 占空比代码 占空比代码涉及到两个概念: 时间信用(Time Credit) 不同的时间段内,都有一个最大可花费的时间信用,每次发送数据都会消耗一笔时间信用,当时间信用不满足下一次发送的花费时,则不允许发送数据。 观察时间(Observation Time) 当出现当时间信用不满足下一次发送的花费这种情况时,则会计算到达下一个时间段的观察时间,在下一个时间段内所花费的时间信息会清零。 3.1. 占空比参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /* src/mac/region/RegionCommon.c */ /* Duty Cycle 1% */ #define BACKOFF_DC_1_HOUR 100 #define BACKOFF_DUTY_CYCLE_1_HOUR_IN_S 3600 #define BACKOFF_DUTY_CYCLE_10_HOURS_IN_S (BACKOFF_DUTY_CYCLE_1_HOUR_IN_S + (BACKOFF_DUTY_CYCLE_1_HOUR_IN_S * 10)) #define BACKOFF_DUTY_CYCLE_24_HOURS_IN_S (BACKOFF_DUTY_CYCLE_10_HOURS_IN_S + (BACKOFF_DUTY_CYCLE_1_HOUR_IN_S * 24)) #define BACKOFF_24_HOURS_IN_S (BACKOFF_DUTY_CYCLE_1_HOUR_IN_S * 24) #ifndef DUTY_CYCLE_TIME_PERIOD /* Default duty cycle observation time period is 1 hour (3600000 ms) according to ETSI. */ #define DUTY_CYCLE_TIME_PERIOD 3600000 #endif #ifndef DUTY_CYCLE_TIME_PERIOD_JOIN_BACKOFF_24H /* Time credits for the join backoff algorithm for the 24H period. */ #define DUTY_CYCLE_TIME_PERIOD_JOIN_BACKOFF_24H 870000 #endif 3.2. 更新占空比最大值 更新时间信用和观察时间: ...

November 11, 2025 · 8 min · 1492 words

【Go】结构体的内存布局

测试环境:go1.25.3 windows/amd64 1. 结构体布局 Go 语言中,结构体和它所包含的数据在内存中是以连续块的形式存在的,即使结构体中嵌套有其他的结构体。 2. 示例 2.1. 结构体 定义的结构体如下: 1 2 3 4 5 6 type studentInfo struct { id int // 学号 name string // 姓名 sorce float32 // 总分 rank int // 年纪排名 } 2.2. 示意图 1 2 3 4 5 6 7 8 9 10 Bytes 8 16 4 4 8 +----+------+--------+---------+------+ | id | name | source | padding | rank | +----+------+--------+---------+------+ / \ / \ +-----+--------+ | ptr | length | +-----+--------+ 8 8 由于结构体是 8 字节对齐,所以 source 有 4 字节填充,那么总共是 40 字节。 ...

November 9, 2025 · 3 min · 489 words

【Blog】支持网站访问统计

一、网站访问统计 对于静态网站来说,不好统计访问这些动态数据。 这里使用的是Vercount提供的网站访问统计功能(感谢大佬)。 具体操作就是:每次打开网站时,都会运行 vercount 提供的脚本,往 vercount 的服务器发送和接收数据。 这里我使用的是 PaperMod 主题。 1、新建 extend_head.html 文件 新建 layouts/partials/extend_head.html。 如果没有子目录的话,需要自己新建。 其目的是在网站里引入 vercount 的 js 脚本。 在该 HTML 文件添加以下内容: 1 <script defer src="https://cn.vercount.one/js"></script> 2. 新建 extend_footer.html 文件 新建 layouts/partials/extend_footer.html.html。 如果没有子目录的话,需要自己新建。 其目的是在网站底部添加显示访问信息。 在该 HTML 文件添加以下内容: 1 2 3 4 5 6 7 8 {{- if not (.Param "hideFooter") }} <footer class="footer"> <div> 网站总访客数<span id="vercount_value_site_uv"></span>次 网站总访问量<span id="vercount_value_site_pv"></span>人次 </div> </footer> {{- end }} 3. 新建 single.html 文件 将 themes/PaperMod/layouts/_default/single.html 拷贝一份到 layouts/_default/single.html。 ...

November 2, 2025 · 1 min · 181 words

【Go】命名规范

一些关键的命名规范。 一、包 对于包的命名,建议是以小写形式的单个单词命名。 在 Go 里面,包的名称不要求是唯一的。 包的名称尽量和包的导入路径里面的最后一个路径一致。 每个包的导入路径是唯一的。 比如 Go 的 Web 框架 Gin,包的名称是 gin,导入路径是: 1 import "github.com/gin-gonic/gin" 对于包的导出标识符的命令,在名字中不要再包含包的名称。 假如有个名为 github.com/zeepunt/lora 的包,对于包的导出标识符: 1 2 3 4 5 6 7 import "github.com/zeepunt/lora" // 推荐 lora.Sx126xOpen() // 不推荐, 因为 LoraSx126xOpen 携带了包的名称 lora.LoraSx126xOpen() 二、标识符 标识符的命名采用驼峰命名法(CamelCase)。 标识符可以指的是变量名称、函数名称、接口名称等。 小驼峰拼写法(lowerCamelCase) 第一个单词的首字母小写,后面每个单词的首字母大写。 大驼峰拼写法(UpperCamelCas) 又称为帕斯卡拼写法(PascalCase)。 每个单词的首字母都需大写。 注意 Go 里面默认大驼峰拼写法的标识符用于包导出标识符。 比如,在 lora 包里面有两个函数,分别是 Sx126xOpen 和 sx1262Info,那么只有 Sx126xOpen 函数可以被外部访问,sx1262Info 只能被包的内部访问。 如果缩略词的首字母是大写的,那么其他的字母也要大写。 比如,HTTP 不要写成 Http。 ...

November 2, 2025 · 1 min · 175 words