日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LoRa节点开发:4、代码详解 LoRaWAN节点入网

發(fā)布時(shí)間:2023/12/15 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LoRa节点开发:4、代码详解 LoRaWAN节点入网 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本文主要結(jié)合LoRaNode SDK v4.4.2和LoRaWAN規(guī)范1.0.3來展開。

1、入網(wǎng)(激活)方式

可以看出,兩種入網(wǎng)(激活)方式:

OTAA(Over-The-Air Activation):空中激活

ABP(Activation By Personalization):手動激活

2、空中激活

空中激活的過程,其實(shí)就是和服務(wù)器數(shù)據(jù)交換的過程,且當(dāng)上行或下行消息丟失時(shí),需要重新交換一次數(shù)據(jù)。

入網(wǎng)的過程,設(shè)備需要以下3個(gè)參數(shù):

DevEUI:設(shè)備ID;

AppEUI:應(yīng)用ID;

AppKey:128位的跟密鑰,用于產(chǎn)生網(wǎng)絡(luò)會話密鑰NwkSKey 和應(yīng)用會話密鑰AppSKey。

2.1、入網(wǎng)過程

從節(jié)點(diǎn)的角度看,入網(wǎng)過程是與服務(wù)器的兩次數(shù)據(jù)交換,分別是入網(wǎng)請求入網(wǎng)回復(fù)

2.2、入網(wǎng)請求信息

入網(wǎng)信息包含AppEUI、DevEUI、DevNone,DevNone是一個(gè)隨機(jī)值 、入網(wǎng)請求是不加密的。

2.3、入網(wǎng)回復(fù)信息

如果設(shè)備被允許入網(wǎng),網(wǎng)絡(luò)服務(wù)器將會回復(fù)一個(gè)“入網(wǎng)回復(fù)”信息給到“入網(wǎng)請求”信息。

“入網(wǎng)回復(fù)”信息包括AppNonce、NetID、DevAddr、DLSettings、RxDelay、CFList字段。

AppNonce是服務(wù)器產(chǎn)生的隨機(jī)值或者是以某種形式產(chǎn)生的唯一ID,用于終端設(shè)備計(jì)算NwkSKey和AppSKey。

3、手動激活

手動激活方式,沒有“入網(wǎng)請求”和“入網(wǎng)回復(fù)”的過程。DevAddr、NwkSKey、AppSKey直接存儲在終端設(shè)備中。手動激活的時(shí)候

必須確保NwkSKey和AppSkey是唯一的。

4、代碼分析

我們很容易看出,SDK工程用狀態(tài)機(jī)在調(diào)度。

定義了6種狀態(tài),如下:

static enum eDeviceState {DEVICE_STATE_RESTORE,DEVICE_STATE_START,DEVICE_STATE_JOIN,DEVICE_STATE_SEND,DEVICE_STATE_CYCLE,DEVICE_STATE_SLEEP }DeviceState;

由于代碼量很大,我們只截取main中while(1)中的代碼:

while( 1 ) {// Process Radio IRQif( Radio.IrqProcess != NULL ){Radio.IrqProcess( );}// Processes the LoRaMac eventsLoRaMacProcess( );switch( DeviceState ){case DEVICE_STATE_RESTORE:{// Try to restore from NVM and query the mac if possible.if( NvmCtxMgmtRestore( ) == NVMCTXMGMT_STATUS_SUCCESS ) //1.1.x以后才支持存儲管理{printf( "\r\n###### ===== CTXS RESTORED ==== ######\r\n\r\n" );}else{ #if( OVER_THE_AIR_ACTIVATION == 0 ) //不使用otaa// Tell the MAC layer which network server version are we connecting too.mibReq.Type = MIB_ABP_LORAWAN_VERSION;mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION;LoRaMacMibSetRequestConfirm( &mibReq ); #endif#if( ABP_ACTIVATION_LRWAN_VERSION == ABP_ACTIVATION_LRWAN_VERSION_V10x )mibReq.Type = MIB_GEN_APP_KEY;mibReq.Param.GenAppKey = GenAppKey;LoRaMacMibSetRequestConfirm( &mibReq ); #elsemibReq.Type = MIB_APP_KEY;mibReq.Param.AppKey = AppKey;LoRaMacMibSetRequestConfirm( &mibReq ); #endifmibReq.Type = MIB_NWK_KEY;mibReq.Param.NwkKey = NwkKey;LoRaMacMibSetRequestConfirm( &mibReq );// Initialize LoRaMac device unique ID if not already defined in Commissioning.hif( ( devEui[0] == 0 ) && ( devEui[1] == 0 ) &&( devEui[2] == 0 ) && ( devEui[3] == 0 ) &&( devEui[4] == 0 ) && ( devEui[5] == 0 ) &&( devEui[6] == 0 ) && ( devEui[7] == 0 ) ){BoardGetUniqueId( devEui );}mibReq.Type = MIB_DEV_EUI;mibReq.Param.DevEui = devEui;LoRaMacMibSetRequestConfirm( &mibReq );mibReq.Type = MIB_JOIN_EUI;mibReq.Param.JoinEui = joinEui;LoRaMacMibSetRequestConfirm( &mibReq );#if( OVER_THE_AIR_ACTIVATION == 0 ) //ABP方式,使用終端和服務(wù)器約定好的參數(shù)// Choose a random device address if not already defined in Commissioning.hif( DevAddr == 0 ){// Random seed initializationsrand1( BoardGetRandomSeed( ) );// Choose a random device addressDevAddr = randr( 0, 0x01FFFFFF );}mibReq.Type = MIB_NET_ID;mibReq.Param.NetID = LORAWAN_NETWORK_ID;LoRaMacMibSetRequestConfirm( &mibReq );mibReq.Type = MIB_DEV_ADDR;mibReq.Param.DevAddr = DevAddr;LoRaMacMibSetRequestConfirm( &mibReq );mibReq.Type = MIB_F_NWK_S_INT_KEY;mibReq.Param.FNwkSIntKey = FNwkSIntKey;LoRaMacMibSetRequestConfirm( &mibReq );mibReq.Type = MIB_S_NWK_S_INT_KEY;mibReq.Param.SNwkSIntKey = SNwkSIntKey;LoRaMacMibSetRequestConfirm( &mibReq );mibReq.Type = MIB_NWK_S_ENC_KEY;mibReq.Param.NwkSEncKey = NwkSEncKey;LoRaMacMibSetRequestConfirm( &mibReq );mibReq.Type = MIB_APP_S_KEY;mibReq.Param.AppSKey = AppSKey;LoRaMacMibSetRequestConfirm( &mibReq ); #endif}DeviceState = DEVICE_STATE_START;break;}case DEVICE_STATE_START:{TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );TimerInit( &Led1Timer, OnLed1TimerEvent );TimerSetValue( &Led1Timer, 25 );TimerInit( &Led2Timer, OnLed2TimerEvent );TimerSetValue( &Led2Timer, 25 );mibReq.Type = MIB_PUBLIC_NETWORK;mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;LoRaMacMibSetRequestConfirm( &mibReq );mibReq.Type = MIB_ADR;mibReq.Param.AdrEnable = LORAWAN_ADR_ON;LoRaMacMibSetRequestConfirm( &mibReq );#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 )LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON ); #endifmibReq.Type = MIB_SYSTEM_MAX_RX_ERROR;mibReq.Param.SystemMaxRxError = 20;LoRaMacMibSetRequestConfirm( &mibReq );LoRaMacStart( );mibReq.Type = MIB_NETWORK_ACTIVATION;status = LoRaMacMibGetRequestConfirm( &mibReq );if( status == LORAMAC_STATUS_OK ){if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE ) //沒有激活{DeviceState = DEVICE_STATE_JOIN;}else{DeviceState = DEVICE_STATE_SEND;NextTx = true;}}break;}case DEVICE_STATE_JOIN:{mibReq.Type = MIB_DEV_EUI;LoRaMacMibGetRequestConfirm( &mibReq );printf( "DevEui : %02X", mibReq.Param.DevEui[0] );for( int i = 1; i < 8; i++ ){printf( "-%02X", mibReq.Param.DevEui[i] );}printf( "\r\n" );mibReq.Type = MIB_JOIN_EUI; //其實(shí)就是appeuiLoRaMacMibGetRequestConfirm( &mibReq );printf( "AppEui : %02X", mibReq.Param.JoinEui[0] );for( int i = 1; i < 8; i++ ){printf( "-%02X", mibReq.Param.JoinEui[i] );}printf( "\r\n" );printf( "AppKey : %02X", NwkKey[0] );for( int i = 1; i < 16; i++ ){printf( " %02X", NwkKey[i] );}printf( "\n\r\n" ); #if( OVER_THE_AIR_ACTIVATION == 0 )printf( "###### ===== JOINED ==== ######\r\n" );printf( "\r\nABP\r\n\r\n" );printf( "DevAddr : %08lX\r\n", DevAddr );printf( "NwkSKey : %02X", FNwkSIntKey[0] );for( int i = 1; i < 16; i++ ){printf( " %02X", FNwkSIntKey[i] );}printf( "\r\n" );printf( "AppSKey : %02X", AppSKey[0] );for( int i = 1; i < 16; i++ ){printf( " %02X", AppSKey[i] );}printf( "\n\r\n" );mibReq.Type = MIB_NETWORK_ACTIVATION;mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP;LoRaMacMibSetRequestConfirm( &mibReq );DeviceState = DEVICE_STATE_SEND; #elseJoinNetwork( ); //入網(wǎng)操作 #endifbreak;}case DEVICE_STATE_SEND:{if( NextTx == true ){PrepareTxFrame( AppPort );NextTx = SendFrame( );}DeviceState = DEVICE_STATE_CYCLE;break;}case DEVICE_STATE_CYCLE:{DeviceState = DEVICE_STATE_SLEEP;if( ComplianceTest.Running == true ){// Schedule next packet transmissionTxDutyCycleTime = 5000; // 5000 ms}else{// Schedule next packet transmissionTxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND );}// Schedule next packet transmissionTimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );TimerStart( &TxNextPacketTimer );break;}case DEVICE_STATE_SLEEP:{if( NvmCtxMgmtStore( ) == NVMCTXMGMT_STATUS_SUCCESS ){printf( "\r\n###### ===== CTXS STORED ==== ######\r\n" );}CRITICAL_SECTION_BEGIN( );if( IsMacProcessPending == 1 ){// Clear flag and prevent MCU to go into low power modes.IsMacProcessPending = 0;}else{// The MCU wakes up through eventsBoardLowPowerHandler( );}CRITICAL_SECTION_END( );break;}default:{DeviceState = DEVICE_STATE_START;break;}}

依照上面的主循環(huán)里面的代碼,我們畫了一個(gè)流程圖,如下:

可以看出:OTAA入網(wǎng)需要執(zhí)行DEVICE_STATE_JOIN這個(gè)過程,入網(wǎng)之后上報(bào)數(shù)據(jù);ABP是沒有入網(wǎng)過程的,直接就上報(bào)數(shù)據(jù)了。最終在3個(gè)狀態(tài)之間切換:

我們跟蹤一下DEVICE_STATE_JOIN這個(gè)狀態(tài),看一下這個(gè)入網(wǎng)的過程:

函數(shù)體太長,我們僅列出函數(shù)名:

JoinNetwork——>LoRaMacMlmeRequest——>SendReJoinReq——>ScheduleTx——>SecureFrame——>LoRaMacCryptoPrepareJoinRequest——>LoRaMacSerializerJoinRequest——>SendFrameOnChannel——>Radio.Send

至此,入網(wǎng)請求消息,就通過射頻發(fā)送出去了。

上述做了一系列的操作,其實(shí)就是封裝數(shù)據(jù)包、加密數(shù)據(jù),由此也可以看出LoRaWAN就是純軟件層面的東西。

我們重點(diǎn)看一下,LoRaMacSerializerJoinRequest這個(gè)函數(shù):我們列出函數(shù)的原型如下:

LoRaMacSerializerStatus_t LoRaMacSerializerJoinRequest( LoRaMacMessageJoinRequest_t* macMsg ) {if( ( macMsg == 0 ) || ( macMsg->Buffer == 0 ) ){return LORAMAC_SERIALIZER_ERROR_NPE;}uint16_t bufItr = 0;// Check macMsg->BufSizeif( macMsg->BufSize < LORAMAC_JOIN_REQ_MSG_SIZE ){return LORAMAC_SERIALIZER_ERROR_BUF_SIZE;}macMsg->Buffer[bufItr++] = macMsg->MHDR.Value;memcpyr( &macMsg->Buffer[bufItr], macMsg->JoinEUI, LORAMAC_JOIN_EUI_FIELD_SIZE );bufItr += LORAMAC_JOIN_EUI_FIELD_SIZE;memcpyr( &macMsg->Buffer[bufItr], macMsg->DevEUI, LORAMAC_DEV_EUI_FIELD_SIZE );bufItr += LORAMAC_DEV_EUI_FIELD_SIZE;macMsg->Buffer[bufItr++] = macMsg->DevNonce & 0xFF;macMsg->Buffer[bufItr++] = ( macMsg->DevNonce >> 8 ) & 0xFF;macMsg->Buffer[bufItr++] = macMsg->MIC & 0xFF;macMsg->Buffer[bufItr++] = ( macMsg->MIC >> 8 ) & 0xFF;macMsg->Buffer[bufItr++] = ( macMsg->MIC >> 16 ) & 0xFF;macMsg->Buffer[bufItr++] = ( macMsg->MIC >> 24 ) & 0xFF;macMsg->BufSize = bufItr;return LORAMAC_SERIALIZER_SUCCESS; }

在這個(gè)函數(shù)里面實(shí)現(xiàn)了數(shù)據(jù)的封裝,我們看到了MHDR、JoinEUI(特別說明一下JoinEUI和APPEUI是同一個(gè)東西)、DevEUI、

DevNonce、MIC字段,MHDR是Mac數(shù)據(jù)頭、MIC是數(shù)據(jù)一致性校驗(yàn),剩下的3個(gè)字段,與我們上面從LoRaWAN規(guī)范join

request一節(jié)中看到的一樣。

我們再來看看,LoRaWAN規(guī)范里面講的MAC消息格式:

這個(gè)圖中小藍(lán)框框起來的地方,正是我們這函數(shù)中數(shù)據(jù)封裝的各個(gè)字段。

至此我們可以總結(jié)一下,入網(wǎng)請求數(shù)據(jù)包的格式:

MHDR

JoinEUI

DevEUI

DevNone

MIC

1byte

8byte

8byte

2byte

4byte

可以看出,入網(wǎng)請求包長度是1+8+8+2+4=23byte。

關(guān)于“入網(wǎng)回復(fù)”,我們先不管機(jī)制是怎么樣的,我們暫時(shí)只查看相應(yīng)的數(shù)據(jù)解包過程,我們類比發(fā)包的過程:先封包再發(fā)送,收

包剛好和這個(gè)相反,收到數(shù)據(jù)包,再解包,查看每個(gè)字段。

static void ProcessRadioRxDone( void )這個(gè)函數(shù)就是對射頻接收到的數(shù)據(jù)的處理了,可以看到使用switch case語句,通過

macHdr.Bits.MType字段對接收到的數(shù)據(jù)包進(jìn)行了區(qū)分,FRAME_TYPE_JOIN_ACCEPT這個(gè)類型的包,正是我們的“入網(wǎng)回復(fù)”

數(shù)據(jù),順著往下跟蹤LoRaMacCryptoHandleJoinAccept——>LoRaMacParserJoinAccept,正是在LoRaMacParserJoinAccept這個(gè)

函數(shù)里面解析“入網(wǎng)回復(fù)”數(shù)據(jù)的,我們列出這個(gè)函數(shù)的原型如下:

LoRaMacParserStatus_t LoRaMacParserJoinAccept( LoRaMacMessageJoinAccept_t* macMsg ) {if( ( macMsg == 0 ) || ( macMsg->Buffer == 0 ) ){return LORAMAC_PARSER_ERROR_NPE;}uint16_t bufItr = 0;macMsg->MHDR.Value = macMsg->Buffer[bufItr++];memcpy1( macMsg->JoinNonce, &macMsg->Buffer[bufItr], 3 );bufItr = bufItr + 3;memcpy1( macMsg->NetID, &macMsg->Buffer[bufItr], 3 );bufItr = bufItr + 3;macMsg->DevAddr = ( uint32_t ) macMsg->Buffer[bufItr++];macMsg->DevAddr |= ( ( uint32_t ) macMsg->Buffer[bufItr++] << 8 );macMsg->DevAddr |= ( ( uint32_t ) macMsg->Buffer[bufItr++] << 16 );macMsg->DevAddr |= ( ( uint32_t ) macMsg->Buffer[bufItr++] << 24 );macMsg->DLSettings.Value = macMsg->Buffer[bufItr++];macMsg->RxDelay = macMsg->Buffer[bufItr++];if( ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE - bufItr ) == LORAMAC_C_FLIST_FIELD_SIZE ){memcpy1( macMsg->CFList, &macMsg->Buffer[bufItr], LORAMAC_C_FLIST_FIELD_SIZE );bufItr = bufItr + LORAMAC_C_FLIST_FIELD_SIZE;}else if( ( macMsg->BufSize - LORAMAC_MIC_FIELD_SIZE - bufItr ) > 0 ){return LORAMAC_PARSER_FAIL;}macMsg->MIC = ( uint32_t ) macMsg->Buffer[bufItr++];macMsg->MIC |= ( ( uint32_t ) macMsg->Buffer[bufItr++] << 8 );macMsg->MIC |= ( ( uint32_t ) macMsg->Buffer[bufItr++] << 16 );macMsg->MIC |= ( ( uint32_t ) macMsg->Buffer[bufItr++] << 24 );return LORAMAC_PARSER_SUCCESS; }

我們依次可以看到MHDR、JoinNonce(和規(guī)范中的AppNonce是同一個(gè)東西)、NetID、DevAddr、DLSettings、RxDelay、

CFList、MIC字段,這也與我們上面在LoRaWAN規(guī)范里面看到的數(shù)據(jù)包吻合。

我們現(xiàn)在來總結(jié)一下數(shù)據(jù)入網(wǎng)回復(fù)數(shù)據(jù)包的格式:

MHDR

JoinNonce

NetID

DevAddr

DLSettings

RxDelay

CFList

MIC

1byte

3byte

3byte

4byte

1byte

1byte

nbyte

4byte

其中CFList這個(gè)字段是可選的,如果沒有的話,就是0。

我們測試一下,看看“入網(wǎng)請求”和“入網(wǎng)回復(fù)”,如下:

入網(wǎng)請求的數(shù)據(jù)幀為:00 01 00 00 00 00 00 00 00 DF 46 00 00 10 FF FF FF 0F A6 C4 38 42 A7

剛好是23個(gè)字節(jié),可以看出,入網(wǎng)請求是沒有加密的,每個(gè)代表字段含義如下:

00:MHDR

01 00 00 00 00 00 00 00:JoinEUI

DE 46 00 00 10 FF FF FF:DevEUI

0F A6:DevNone

C4 38 42 A7:MIC

入網(wǎng)回復(fù)的數(shù)據(jù)幀為:20 69 e1 e7 2b 3e 0b 52 c9 c5 de 36 4f e2 69 41 25

是17+(0或16)個(gè)字節(jié),20是MHDR,之后的數(shù)據(jù)是經(jīng)過加密的

經(jīng)過解密之后的數(shù)據(jù)如下:7d c4 83 03 02 01 92 c5 f1 07 00 00 e4 5b 50 1b

7d c4 83 :JoinNonce

03 02 01 :NetID

92 c5 f1 07:DevAddr

00 :DLSettings

00 :RxDelay

e4 5b 50 1b:MIC

5、總結(jié)

OTAA入網(wǎng):有入網(wǎng)過程,入網(wǎng)之后服務(wù)器分配DevAddr,節(jié)點(diǎn)計(jì)算出NwkSKey、AppSKey兩個(gè)加密密鑰。

ABP入網(wǎng):無入網(wǎng)過程,DevAddr、NwkSKey、AppSKey直接存儲在終端設(shè)備中(說直白一點(diǎn)就是,節(jié)點(diǎn)和服務(wù)器提前約定好了參數(shù))。

???????????????????? ==========================end========================================

推薦閱讀:

LoRa節(jié)點(diǎn)開發(fā)——初始SDK

LoRa節(jié)點(diǎn)開發(fā)——構(gòu)建keil工程

LoRa節(jié)點(diǎn)開發(fā)——SDK整體設(shè)計(jì)思路

歡迎關(guān)注公眾號:“物聯(lián)網(wǎng)思考”,獲取更多開發(fā)資料、經(jīng)驗(yàn)。

總結(jié)

以上是生活随笔為你收集整理的LoRa节点开发:4、代码详解 LoRaWAN节点入网的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。