西安网站建设制作需要哪些费用,商标注册查询app,个人网站的设计与实现的主要内容,wordpress无法下载LoRa 是LPWAN通信技术中的一种#xff0c;是美国Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输方案。这一方案改变了以往关于传输距离与功耗的折衷考虑方式为用户提供一种简单的能实现远距离、长电池寿命、大容量的系统#xff0c;进而扩展传感网络。目前…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指令连接腾讯云物联网开发平台指令如下 ATPKTFWDloragw.things.qcloud.com,1700,1700 ATCH0,486.3,A ATCH1,486.5,A ATCH2,486.7,A ATCH3,486.9,A ATCH4,487.1,B ATCH5,487.3,B ATCH6,487.5,B ATCH7,487.7,B ATCH8,OFF ATCH9,OFF ATlogon 此条很重要可以看到网关与云平台与节点的通讯情况 ATReset 复位网关则开始服务器连接了。 以上就是节点移植前准备工作了 正文 初始化 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; }