STM32移植lorawan协议栈连接腾讯云物联网开发平台(IoT Explorer)
前言
开发环境的准备
正文
初始化
入网
发送与接收
前言
在移植协议之前,先给大家科普一下Lora 和 lorawan 的区别。

LoRa 是LPWAN通信技术中的一种,是美国Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输方案。这一方案改变了以往关于传输距离与功耗的折衷考虑方式为用户提供一种简单的能实现远距离、长电池寿命、大容量的系统,进而扩展传感网络。目前,LoRa 主要在全球免费频段运行,各个国家和地区不一样,中国区运行在470MHZ和779MHZ。

LoRaWAN是一个开放标准,它定义了基于LoRa芯片的LPWAN技术的通信协议。 LoRaWAN在数据链路层定义媒体访问控制(MAC),专为具有单一运营商的大型公共网络而设计,具体而言,每个节点将数据传输到网关或多个网关。然后网关将数据转发到网络服务器,在网络服务器上执行冗余检测,安全检查和消息调度,LoRaWAN现在由LoRa联盟维护(link)。

总体而言,LoRa仅包含链路层协议,并且非常适用于节点间的P2P通信;同时,LoRa模块(立创商城上20块左右)也比LoRaWAN(某宝30到40块)便宜一点;
LoRaWAN包含网络层,因此可以将信息发送到任何已连接到云平台的基站。只需将正确的天线连接到其插座,LoRaWAN模块就可以以不同的频率工作。

one picture wins thoustands words(如图所示)
LoRaWAN = MAC Layer
LoRa = PHY Layer
LoRa + LoRaWAN = LPWAN

正是因为lorawan,成千上万个节点的连网变得可能,本次移植的STM32 节点所连接的网关(SX1301)理论上能连接62500个节点。

开发环境的准备
Nucleo-F746ZG Board and ST Nucleo LoRa GW Module 如下图

Nucleo-L073R8 Board and ST Nucleo LoRa Sensor V2

因为 ST Nucleo LoRa Sensor V2 上的RHF0M003 模块已经集成了lorawan 协议了,只需MCU通过UART发送AT指令就能实现lorawan通讯(上文所说较贵的一类模块)

安信可ra-02(sx1278)

模块通过杜邦线连接开发板的SPI1 GPIO(PA0-reset脚, PA10-中断脚) ,VCC和地,连接好如下图所示:

PC通过串口连接网关,通过AT指令连接腾讯云物联网开发平台,指令如下
AT+PKTFWD=loragw.things.qcloud.com,1700,1700
AT+CH=0,486.3,A
AT+CH=1,486.5,A
AT+CH=2,486.7,A
AT+CH=3,486.9,A
AT+CH=4,487.1,B
AT+CH=5,487.3,B
AT+CH=6,487.5,B
AT+CH=7,487.7,B
AT+CH=8,OFF
AT+CH=9,OFF
AT+log=on (此条很重要,可以看到网关与云平台,与节点的通讯情况)
AT+Reset 复位网关,则开始服务器连接了。
以上就是节点移植前准备工作了

正文
初始化
void LORA_Init (LoRaMainCallback_t *callbacks, LoRaParam_t* LoRaParam )
{
 uint8_t devEui[] = LORAWAN_DEVICE_EUI;
  uint8_t joinEui[] = LORAWAN_JOIN_EUI;    //连接腾讯云平台用不到这个参数
  
  /* init the Tx Duty Cycle*/
  LoRaParamInit = LoRaParam;
  
  /* init the main call backs*/
  LoRaMainCallbacks = callbacks;
  
#if (STATIC_DEVICE_EUI != 1)
  LoRaMainCallbacks->BoardGetUniqueId( devEui );  
#endif
  
#if( OVER_THE_AIR_ACTIVATION != 0 )

PPRINTF( "OTAA\n\r"); 
  PPRINTF( "DevEui= %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n\r", HEX8(devEui));
  PPRINTF( "AppEui= %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n\r", HEX8(joinEui));
  PPRINTF( "AppKey= %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n\r", HEX16(AppKey));
#else

#if (STATIC_DEVICE_ADDRESS != 1)
  // Random seed initialization
  srand1( LoRaMainCallbacks->BoardGetRandomSeed( ) );
  // Choose a random device address
  DevAddr = randr( 0, 0x01FFFFFF );
#endif
  PPRINTF( "ABP\n\r"); 
  PPRINTF( "DevEui= %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n\r", HEX8(devEui));
  PPRINTF( "DevAdd=  %08X\n\r", DevAddr) ;
  PPRINTF( "NwkSKey= %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n\r", HEX16(NwkSEncKey));
  PPRINTF( "AppSKey= %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n\r", HEX16(AppSKey));
#endif
.
.
.
#elif defined( REGION_CN470 )
  LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_CN470 );
 .
 .
 .
  mibReq.Param.DevEui = devEui;
  mibReq.Param.AppKey = AppKey;
  mibReq.Param.NwkKey = NwkKey; //这几个参数很重要一定要设对,我就  
  mibReq.Param.Class= CLASS_A;  // 因为没设Nwkkey 导致入不网,
  //Lorawan 1.0.x 也要设置,具体原因在下文会详细分析
  .
  .
  .
  LoRaMacStart( );
}

可以看出,初始化就是根据我们设置的一些宏 如入网方式,使用地区等等进行初始化。

入网
void LORA_Join( void)
{
    MlmeReq_t mlmeReq;
  
    mlmeReq.Type = MLME_JOIN;
    mlmeReq.Req.Join.Datarate = LoRaParamInit->TxDatarate;
  
    JoinParameters = mlmeReq.Req.Join;

#if( OVER_THE_AIR_ACTIVATION != 0 )
    LoRaMacMlmeRequest( &mlmeReq );    //腾讯云物联网平台要求空中入网的方式,所以定义了这个宏为1,于是调用了这个函数;                                                                       
#else
.
.
.
#endif
}

LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t* mlmeRequest )
{
    LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN;
    MlmeConfirmQueue_t queueElement;
    uint8_t macCmdPayload[2] = { 0x00, 0x00 };

if( mlmeRequest == NULL )
    {
        return LORAMAC_STATUS_PARAMETER_INVALID;
    }
    if( LoRaMacIsBusy( ) == true )
    {
        return LORAMAC_STATUS_BUSY;
    }
    if( LoRaMacConfirmQueueIsFull( ) == true )
    {
        return LORAMAC_STATUS_BUSY;
    }
    .
    .
    .
    switch( mlmeRequest->Type )   //通过入参来判断我们这是是入网请求MLME_JOIN
    {
        case MLME_JOIN:
        {
            if( ( MacCtx.MacState & LORAMAC_TX_DELAYED ) == LORAMAC_TX_DELAYED )
            {
                return LORAMAC_STATUS_BUSY;
            }

ResetMacParameters( );

MacCtx.NvmCtx->MacParams.ChannelsDatarate = RegionAlternateDr( MacCtx.NvmCtx->Region, mlmeRequest->Req.Join.Datarate, ALTERNATE_DR );

queueElement.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;

status = SendReJoinReq( JOIN_REQ );     //我们再进去看这个函数

if( status != LORAMAC_STATUS_OK )    
            {
                    PPRINTF( "joinreq ok\n\r");
                // Revert back the previous datarate ( mainly used for US915 like regions )
                MacCtx.NvmCtx->MacParams.ChannelsDatarate = RegionAlternateDr( MacCtx.NvmCtx->Region, mlmeRequest->Req.Join.Datarate, ALTERNATE_DR_RESTORE );
            }
                        else
                        {
                            PPRINTF( "joinreq not ok\n\r");
                        }
            break;
        }
        .
        .
        .
        return status;
}

LoRaMacStatus_t SendReJoinReq( JoinReqIdentifier_t joinReqType )
{
    LoRaMacStatus_t status = LORAMAC_STATUS_OK;
    LoRaMacHeader_t macHdr;
    macHdr.Value = 0;
    bool allowDelayedTx = true;

// Setup join/rejoin message
    switch( joinReqType )
    {
        case JOIN_REQ:
        {
         .
         .
         .
        }
    }

// Schedule frame
    status = ScheduleTx( allowDelayedTx );  //再看这个函数
    return status;
}
//谜底快解开了....
static LoRaMacStatus_t ScheduleTx( bool allowDelayedTx )
{
   LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID;
    TimerTime_t dutyCycleTimeOff = 0;
    NextChanParams_t nextChan;
    size_t macCmdsSize = 0;

// Update back-off
    CalculateBackOff( MacCtx.NvmCtx->LastTxChannel );
    .
    .
    .
     if( MacCtx.NvmCtx->NetworkActivation == ACTIVATION_TYPE_NONE )
    {
        MacCtx.RxWindow1Delay = MacCtx.NvmCtx->MacParams.JoinAcceptDelay1 +   MacCtx.RxWindow1Config.WindowOffset;
        MacCtx.RxWindow2Delay = MacCtx.NvmCtx->MacParams.JoinAcceptDelay2 + MacCtx.RxWindow2Config.WindowOffset;
        PPRINTF( "MacCtx.RxWindow1Delay is %d\n\r",MacCtx.RxWindow1Delay);
    }
     //这里也重点说一下,很多人入不了网的原因是因为接收窗口的时间不对,从发出入 
    //请求到从网关接收入网应答这个时间间隔是5秒,这个和腾讯云物联网平台的工程师确
    //确认过
 .
 .
 .
     // Secure frame
     //谜底就在这个函数里
    LoRaMacStatus_t retval = SecureFrame( MacCtx.NvmCtx->MacParams.ChannelsDatarate, MacCtx.Channel ); 
    if( retval != LORAMAC_STATUS_OK )
    {
        return retval;
    }

// Try to send now
    return SendFrameOnChannel( MacCtx.Channel );  
}

== 之前一直入网不成功,联系腾讯云的夏云飞老师,得到的回复是MIC错误,夏老师说MIC错误只有两个原因,一是key错了,二是算法错了。 ==

我确信算法不会错,因为我没有改过源码,所以我再次确认了AppKey 和 devEui,没错。经过了一段时间的折腾和腾讯云的两位大神夏云飞老师和twowinter(真名不知道啊,哈哈)的指导和提示,再次去看代码,答案如下

static LoRaMacStatus_t SecureFrame( uint8_t txDr, uint8_t txCh )
{
    LoRaMacCryptoStatus_t macCryptoStatus = LORAMAC_CRYPTO_ERROR;
    uint32_t fCntUp = 0;

switch( MacCtx.TxMsg.Type )
    {
        case LORAMAC_MSG_TYPE_JOIN_REQUEST:  
           //我们来看看下面的函数 LoRaMacCryptoPrepareJoinRequest
            macCryptoStatus = LoRaMacCryptoPrepareJoinRequest( &MacCtx.TxMsg.Message.JoinReq );
            if( LORAMAC_CRYPTO_SUCCESS != macCryptoStatus )
            {
                return LORAMAC_STATUS_CRYPTO_ERROR;
            }
            MacCtx.PktBufferLen = MacCtx.TxMsg.Message.JoinReq.BufSize;
            break;
      .
      .
      .
    return LORAMAC_STATUS_OK;
}

LoRaMacCryptoStatus_t LoRaMacCryptoPrepareJoinRequest( LoRaMacMessageJoinRequest_t* macMsg )     
{
    if( macMsg == 0 )
    {
        return LORAMAC_CRYPTO_ERROR_NPE;
    }
    //这里加密用的是NWK_KEY,  但是我没有设置,所以加密错误,这就是原因,我也打印再次确认过,就是nwk_key。 破案了
    KeyIdentifier_t micComputationKeyID = NWK_KEY;

// Add device nonce
#if ( USE_RANDOM_DEV_NONCE == 1 )
    uint32_t devNonce = 0;
    SecureElementRandomNumber( &devNonce );
    CryptoCtx.NvmCtx->DevNonce = devNonce;
#else
    CryptoCtx.NvmCtx->DevNonce++;
#endif
    CryptoCtx.EventCryptoNvmCtxChanged( );
    macMsg->DevNonce = CryptoCtx.NvmCtx->DevNonce;

#if( USE_LRWAN_1_1_X_CRYPTO == 1 )   //这里是USE_LRWAN_1_1_X 的宏,但是我的是1_0_X, 所以为零
    // Derive lifetime session keys
    if( DeriveLifeTimeSessionKey( J_S_INT_KEY, macMsg->DevEUI ) != LORAMAC_CRYPTO_SUCCESS )
    {
        return LORAMAC_CRYPTO_ERROR;
    }
    if( DeriveLifeTimeSessionKey( J_S_ENC_KEY, macMsg->DevEUI ) != LORAMAC_CRYPTO_SUCCESS )
    {
        return LORAMAC_CRYPTO_ERROR;
    }
#endif

// Serialize message
    if( LoRaMacSerializerJoinRequest( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
    {
        return LORAMAC_CRYPTO_ERROR_SERIALIZER;
    }

// Compute mic   这里计算用到了上面的nwk_key,破案了
    if( SecureElementComputeAesCmac( NULL, macMsg->Buffer, ( LORAMAC_JOIN_REQ_MSG_SIZE - LORAMAC_MIC_FIELD_SIZE ), micComputationKeyID, &macMsg->MIC ) != SECURE_ELEMENT_SUCCESS )
    {
        return LORAMAC_CRYPTO_ERROR_SECURE_ELEMENT_FUNC;
    }

// Reserialize message to add the MIC
    if( LoRaMacSerializerJoinRequest( macMsg ) != LORAMAC_SERIALIZER_SUCCESS )
    {
        return LORAMAC_CRYPTO_ERROR_SERIALIZER;
    }

return LORAMAC_CRYPTO_SUCCESS;
}

发送与接收
发送和接收因为没遇到什么困难,直接调用发送函数就行,因为是class A 设备,会在发送后,打开接收窗口接收;贴一个发送函数吧

bool LORA_send(lora_AppData_t* AppData, LoraConfirm_t IsTxConfirmed)
{
    McpsReq_t mcpsReq;
    LoRaMacTxInfo_t txInfo;
  
    /*if certification test are on going, application data is not sent*/
    if (certif_running() == true)
    {
            PPRINTF("certif_run\r\n");
      return false;
    }
    
    if( LoRaMacQueryTxPossible( AppData->BuffSize, &txInfo ) != LORAMAC_STATUS_OK )
    {
        // Send empty frame in order to flush MAC commands
        mcpsReq.Type = MCPS_UNCONFIRMED;
        mcpsReq.Req.Unconfirmed.fBuffer = NULL;
        mcpsReq.Req.Unconfirmed.fBufferSize = 0;
        mcpsReq.Req.Unconfirmed.Datarate = LoRaParamInit->TxDatarate;
    }
    else
    {
        if( IsTxConfirmed == LORAWAN_UNCONFIRMED_MSG )
        {
            mcpsReq.Type = MCPS_UNCONFIRMED;
            mcpsReq.Req.Unconfirmed.fPort = AppData->Port;
            mcpsReq.Req.Unconfirmed.fBufferSize = AppData->BuffSize;
            mcpsReq.Req.Unconfirmed.fBuffer = AppData->Buff;
            mcpsReq.Req.Unconfirmed.Datarate = LoRaParamInit->TxDatarate;
        }
        else
        {
            mcpsReq.Type = MCPS_CONFIRMED;
            mcpsReq.Req.Confirmed.fPort = AppData->Port;
            mcpsReq.Req.Confirmed.fBufferSize = AppData->BuffSize;
            mcpsReq.Req.Confirmed.fBuffer = AppData->Buff;
            mcpsReq.Req.Confirmed.NbTrials = 8;
            mcpsReq.Req.Confirmed.Datarate = LoRaParamInit->TxDatarate;
        }
    }
    if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
    {
        return false;
    }
    return true;
}

还是贴个图吧

以上就是全部内容。
最后再次感谢腾讯云的夏云飞老师和twowinter。
大家如果对Lora有兴趣可以看看twowinter 的文章,会很有帮助的,链接如下
link
http://blog.csdn.net/iotisan/

代码下载链接
link
https://download.csdn.net/download/lintonxie/12265246
————————————————
版权声明:本文为CSDN博主「lintonxie」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lintonxie/java/article/details/105038547

STM32节点移植lorawan协议连接腾讯云物联网开发平台(IoT Explorer)相关推荐

  1. 腾讯云物联网开发平台 IoT Explorer 全面指引

    文章目录 * 1 设备侧开发教程 * 1.1 [腾讯云](https://l.gushuji.site/tencent)端侧资源 1.2 LoRa 设备 * LoRaWAN 节点接入 LoRaWAN ...

  2. 腾讯云-物联网开发平台IoT Explorer

    应用场景 腾讯云的物联网开发平台能做什么?举一个简单的例子,作者就经常有这样的场景:三十度高温的广州,每当你刚踏进家门便急不可耐的寻找空调遥控器把温度调到最低,然后站在空调前迎面吹着冷风:但也可以是这 ...

  3. 【STM32+ESP-12S连接腾讯云物联网开发平台 1】云平台的创建和AT固件烧录

    腾讯云物联网开发平台创建和ESP-12S的固件烧录 前言 一.腾讯云物联网开发平台的创建 1. 创建产品 2. 配置产品和创建设备 3. 设备三元组说明 二.ESP-12S固件烧录 1.固件获取 2. ...

  4. 【STM32+ESP8266连接腾讯云物联网开发平台 2】STM32+ESP8266-01S连接腾讯云

    文章目录 前言 一.硬件准备 1.ESP8266-01S 2. STM32F103C8T6核心板或者小开发板及其程序下载器 二.软件准备 1.STM32CubeMX 2. MDK (Keil v5) ...

  5. RAK7258 LoRaWAN 网关接入腾讯云物联网开发平台

    文章目录 前言 1 控制台操作 LoRa 网关 2 RAK 7258 LoRa网关实物操作 连接配置 网络配置 LoRa参数配置 网关上线确认 END 前言 这篇笔记记录采用 RAK7258 LoRa ...

  6. 使用创思通信4G Cat1 DTU基于TencentOS-tiny对接腾讯云物联网开发平台

    一.简介 本文档主要讲述如何使用创思通信4G Cat1 DTU开发板,基于TencentOS-tiny对接腾讯云物联网开发平台IoT Explorer,演示温度数据上报平台.平台下发控制指令控制继电器 ...

  7. 腾讯云物联网开发平台 LoRaWAN 透传接入 更新版

    前言 之前有一篇文章介绍LoRaWAN透传数据,不过还是用物模型+云端数据解析脚本,不是真正的透传.腾讯云物联网开发平台也支持对LoRaWAN原始数据的透传.转发.今天来介绍下. 腾讯云 IoT Ex ...

  8. ESP32接入腾讯云物联网开发平台

    文章目录 前言 1 资料参考 2 对接总体思路 3 代码移植 3.1 component qcloud_iot 3.2 项目顶层处理 3.3 component main 4 移植问题备忘 CMake ...

  9. 腾讯云-物联网开发平台测试(联合mqtt.fx 1.7.1)

    腾讯云-物联网开发平台测试(联合mqtt.fx 1.7.1) 文章目录 腾讯云-物联网开发平台测试(联合mqtt.fx 1.7.1) 环境介绍: 实验目的: 1.新建产品 2.新建功能 3.设备开发 ...

最新文章

  1. windows部署微服务jar包 yml_杰克布开源项目,低代码开发框架,Docker快速部署
  2. hdu5955 Guessing the Dice Roll【AC自动机】【高斯消元】【概率】
  3. 分享你的见解与经验|RocketMQ Summit 2022 议题征集中
  4. java new java.text.SimpleDateFormat(yyyyMM01).format(date)
  5. Eclipse中JBOSS莫名其妙自动关闭
  6. SAP CRM附件上传的一种增强实现
  7. Java并发编程实战~Condition
  8. python 第三方绘图库_D3py首页、文档和下载 - 基于 D3 的 Python 绘图库 - OSCHINA - 中文开源技术交流社区...
  9. pandas 散布矩阵
  10. Java 窗口菜单
  11. 好系统U盘启动教您win7系统怎么安装其他语言
  12. 输入卡号生成银行卡图片python_python 模拟贷个卡号生成规则过程解析
  13. 哪家的服务器cpu性能高,服务器cpu排行
  14. 2022年终总结(脚踏实地,仰望星空)
  15. CentOS上使用docker安装redis
  16. 如何搭建网站?第二步:购买服务器域名
  17. vue实现input输入模糊查询(三种方式)
  18. Handlebars 介绍
  19. python海龟绘图-奥运五环
  20. 新版Chrome自动禁用第三方插件的解决办法

热门文章

  1. 最小二乘估计矩阵形式的推导
  2. 阿里云ECS服务器开放端口号
  3. win7 下jlink v8固件修复
  4. 城市公交线路查询系统mysql_网上公交线路查询系统网站(sqlserver2000)
  5. HTML监测异常退出,HtmlUnit请求页面抛出异常
  6. Xming显示远程服务器GUI的最简单配置
  7. 分享一个能爬取所有百度贴吧图片的爬虫代码
  8. 移动护理信息系统闭环管理概念
  9. VLAN的概念和作用
  10. 落寞身影,光影抹去,烟花寂凉:伤感日志