LoRa节点开发——加入打印调试LoRaWAN
时间:2022-07-25
本文章向大家介绍LoRa节点开发——加入打印调试LoRaWAN,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一般调试我们用两种方法,断点和打印,考虑到射频和RTC,我们主要用打印调试的方法。
1、实现串口打印
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)PUTCHAR_PROTOTYPE{ HAL_UART_Transmit(&UartHandle, (uint8_t *)&ch, 1, 0xFFFF);
return ch;}
2、分等级打印调试信息
typedef enum
{
LOG_LEVEL_OFF=0,
LOG_LEVEL_INFO,
LOG_LEVEL_DEVELOP,
LOG_LEVEL_ALL,
}LOG_LEVEL;
#define log_develop(level,...)
do {
if(level>=LOG_LEVEL_DEVELOP)
{
printf("nFILE:%s LINE:%d,FUNC:%s ", __FILE__, __LINE__ ,__func__);
printf(##__VA_ARGS__);
}
} while (0)
#define log_info(level, ...)
do {
if(level>=LOG_LEVEL_INFO)
printf(##__VA_ARGS__ );
} while (0)
#define log_debug(level, ...)
do {
if(level>=LOG_LEVEL_ALL)
printf(##__VA_ARGS__ );
} while (0)
3、定义调试等级
LOG_LEVEL loglevel;
//定义打印等级,可以根据自己的实际设定,一般在调试阶段我们设定为LOG_LEVEL_ALL,即所有信息可见。
4、源码关键部分加入打印
以US915频段说明,其余频段类似。
4.1、在RegionUS915TxConfig函数打印发送的参数
bool RegionUS915TxConfig( TxConfigParams_t* txConfig, int8_t* txPower, TimerTime_t* txTimeOnAir )
{
RadioModems_t modem;
int8_t phyDr = DataratesUS915[txConfig->Datarate];
int8_t txPowerLimited = LimitTxPower( txConfig->TxPower, NvmCtx.Bands[NvmCtx.Channels[txConfig->Channel].Band].TxMaxPower, txConfig->Datarate, NvmCtx.ChannelsMask );
uint32_t bandwidth = GetBandwidth( txConfig->Datarate );
int8_t phyTxPower = 0;
// Calculate physical TX power
phyTxPower = RegionCommonComputeTxPower( txPowerLimited, txConfig->MaxEirp, txConfig->AntennaGain );
// Setup the radio frequency
Radio.SetChannel( NvmCtx.Channels[txConfig->Channel].Frequency );
if( txConfig->Datarate == DR_7 )
{ // High Speed FSK channel
modem = MODEM_FSK;
Radio.SetTxConfig( modem, phyTxPower, 25000, bandwidth, phyDr * 1000, 0, 5, false, true, 0, 0, false, 4000 );
}
else
{
modem = MODEM_LORA;
Radio.SetTxConfig( modem, phyTxPower, 0, bandwidth, phyDr, 1, 8, false, true, 0, 0, false, 4000 );
}
// Setup maximum payload lenght of the radio driver
Radio.SetMaxPayloadLength( modem, txConfig->PktLen );
// Get the time-on-air of the next tx frame
*txTimeOnAir = Radio.TimeOnAir( modem, txConfig->PktLen );
*txPower = txPowerLimited;
log_info (loglevel, "[%.3fMHz, SF%d ,%ddBm ,%dbyte]",
Channels[txConfig->Channel].Frequency/1e6,
phyDr,
phyTxPower,
txConfig->PktLen );
return true;
}
4.2、在SendFrameOnChannel函数里面打印发送的数据(加密之后的)
LoRaMacStatus_t SendFrameOnChannel( uint8_t channel )
{
TxConfigParams_t txConfig;
int8_t txPower = 0;
txConfig.Channel = channel;
txConfig.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
txConfig.TxPower = MacCtx.NvmCtx->MacParams.ChannelsTxPower;
txConfig.MaxEirp = MacCtx.NvmCtx->MacParams.MaxEirp;
txConfig.AntennaGain = MacCtx.NvmCtx->MacParams.AntennaGain;
txConfig.PktLen = MacCtx.PktBufferLen;
RegionTxConfig( MacCtx.NvmCtx->Region, &txConfig, &txPower, &MacCtx.TxTimeOnAir );
MacCtx.McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
MacCtx.McpsConfirm.Datarate = MacCtx.NvmCtx->MacParams.ChannelsDatarate;
MacCtx.McpsConfirm.TxPower = txPower;
MacCtx.McpsConfirm.Channel = channel;
// Store the time on air
MacCtx.McpsConfirm.TxTimeOnAir = MacCtx.TxTimeOnAir;
MacCtx.MlmeConfirm.TxTimeOnAir = MacCtx.TxTimeOnAir;
if( LoRaMacClassBIsBeaconModeActive( ) == true )
{
// Currently, the Time-On-Air can only be computed when the radio is configured with
// the TX configuration
TimerTime_t collisionTime = LoRaMacClassBIsUplinkCollision( MacCtx.TxTimeOnAir );
if( collisionTime > 0 )
{
return LORAMAC_STATUS_BUSY_UPLINK_COLLISION;
}
}
if( MacCtx.NvmCtx->DeviceClass == CLASS_B )
{
// Stop slots for class b
LoRaMacClassBStopRxSlots( );
}
LoRaMacClassBHaltBeaconing( );
MacCtx.MacState |= LORAMAC_TX_RUNNING;
if( MacCtx.NodeAckRequested == false )
{
MacCtx.ChannelsNbTransCounter++;
}
// Send now
Radio.Send( MacCtx.PktBuffer, MacCtx.PktBufferLen );
for( uint16_t i = 0; i < MacCtx.PktBufferLen; i++ )
{
log_info(loglevel," %02X",MacCtx.PktBuffer[i]);
}
log_info(loglevel,"rn");
return LORAMAC_STATUS_OK;
}
4.3、在RegionUS915RxConfig函数里面打印接收参数
bool RegionUS915RxConfig( RxConfigParams_t* rxConfig, int8_t* datarate )
{
RadioModems_t modem;
int8_t dr = rxConfig->Datarate;
uint8_t maxPayload = 0;
int8_t phyDr = 0;
uint32_t frequency = rxConfig->Frequency;
if( Radio.GetStatus( ) != RF_IDLE )
{
return false;
}
if( rxConfig->RxSlot == RX_SLOT_WIN_1 )
{
// Apply window 1 frequency
frequency = NvmCtx.Channels[rxConfig->Channel].Frequency;
// Apply the alternative RX 1 window frequency, if it is available
if( NvmCtx.Channels[rxConfig->Channel].Rx1Frequency != 0 )
{
frequency = NvmCtx.Channels[rxConfig->Channel].Rx1Frequency;
}
}
// Read the physical datarate from the datarates table
phyDr = DataratesUS915[dr];
Radio.SetChannel( frequency );
// Radio configuration
if( dr == DR_7 )
{
modem = MODEM_FSK;
Radio.SetRxConfig( modem, 50000, phyDr * 1000, 0, 83333, 5, rxConfig->WindowTimeout, false, 0, true, 0, 0, false, rxConfig->RxContinuous );
}
else
{
modem = MODEM_LORA;
Radio.SetRxConfig( modem, rxConfig->Bandwidth, phyDr, 1, 0, 8, rxConfig->WindowTimeout, false, 0, false, 0, 0, true, rxConfig->RxContinuous );
}
if( rxConfig->RepeaterSupport == true )
{
maxPayload = MaxPayloadOfDatarateRepeaterEU868[dr];
}
else
{
maxPayload = MaxPayloadOfDatarateEU868[dr];
}
Radio.SetMaxPayloadLength( modem, maxPayload + LORA_MAC_FRMPAYLOAD_OVERHEAD );
*datarate = (uint8_t) dr;
log_info( loglevel,"Recv[%.3fMHz, SF%d %dK, st:%d]... rn",
frequency/1e6,
phyDr,
( rxConfig->Bandwidth == 0 ) ? 125 : ( rxConfig->Bandwidth == 1 ) ? 250 : 500,
rxConfig->WindowTimeout );
return true;
}
4.4、在OnRadioRxDone函数里面打印接收到的数据(未解密的数据)
static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
RxDoneParams.LastRxDone = TimerGetCurrentTime( );
RxDoneParams.Payload = payload;
RxDoneParams.Size = size;
RxDoneParams.Rssi = rssi;
RxDoneParams.Snr = snr;
log_info(loglevel,"rnRecv data:%d byte,rssi:%d,snr:%d,data[",size,rssi,snr);
for(uint8_t i=0;i<size;i++)
{
log_info(loglevel," %02x",payload[i]);
}
log_info(loglevel,"]rn");
LoRaMacRadioEvents.Events.RxDone = 1;
if( ( MacCtx.MacCallbacks != NULL ) && ( MacCtx.MacCallbacks->MacProcessNotify != NULL ) )
{
MacCtx.MacCallbacks->MacProcessNotify( );
}
}
5、运行调试
入网调试打印:
发送数据打印调试:
加入打印之后,可以方便的调试,还可以打印入网之后、发送超时、接收超时等,可以根据自己的需要添加。
————END————
- 利用回归模型预测数值型数据(代码)
- 关于ORA-00020问题的反思(r2笔记第3天)
- 查看空间使用情况的脚本(r2笔记第2天)
- 使用dbms_parallel_execute来完成DML的并行(r3笔记第1天)
- 有趣的linux命令总结(78天)
- 生产环境sql语句调优实战第七篇(r2笔记99天)
- 一个普通数据库用户所能查到的"意料之外"的信息(r2笔记98天)
- 查看并行进程的一些简单信息(r3笔记第17天)
- 多行数据的批处理之bulk collect(r3笔记第16天)
- pl/sql中错误的异常处理 (r3笔记第15天)
- 关于session leak的问题分析(r3笔记第13天)
- 执行计划的偏差导致的性能问题(r3笔记第12天)
- 关于评审开发人员的sql语句(r3笔记第11天)
- 性能下降的不定时炸弹_过旧的sql_profile(r3笔记第9天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Hadoop框架:集群模式下分布式环境搭建
- 微服务 Hystrix 实现服务熔断
- 微服务 Gateway 的基本配置
- 有赞营销逆向域的探索与实践
- RabbitMQ 启动报错:Error: unable to perform an operation on node ‘rabbit@***‘. Please see diagnostics...
- MySQL|查询字段数量多少对查询效率的影响
- 如果MySQL事务中发生了网络异常?
- MySQL|update字段为相同的值是否会记录binlog
- 微服务配置 Config 与消息总线
- 贷款违约预测-Task5 模型融合
- Python字符串
- MYSQL logstash 同步数据到es的几种方案对比以及每种方案数据丢失原因分析。
- 手写“SpringBoot”:几十行代码基于Netty搭建一个 HTTP Server
- SpringCloud Sleuth 分布式请求链路追踪
- StarUML 使用方法