STM32 transplant lorawan protocol connection node Things Tencent cloud development platform (IoT Explorer)

STM32 transplant lorawan stack things connected Tencent cloud development platform (IoT Explorer)

Foreword

Before transplant protocol, give us about the difference between science and lorawan of Lora.

LoRa LPWAN is a communication technology, adoption of the United States and promote Semtech a long distance wireless transmission scheme based on spread spectrum technology. This conventional scheme is changed on the way of a compromise with the power transmission from the user to provide a simpler system can achieve long-distance, long battery life, large-capacity, and then extended sensor networks. Currently, LoRa major global free frequency bands and various countries and regions are not the same, China is running at 470MHZ area and 779MHZ.

LoRaWAN is an open standard that defines a communication protocol based LPWAN LoRa chip technology. LoRaWAN defined in the data link layer media access control (the MAC), designed for a single operator network designed for large public, specifically, each node transmits the data to the gateway or more gateways. The gateway then forwards the data to a network server, performs redundancy check, security check, and message schedule on a network server, LoRaWAN Union and now maintained by LoRa ( Link ).

In general, the link layer protocol comprises Lora only, and is very suitable for P2P communication between the nodes; the same time, Lora module (Li Chong the mall about 20) than LoRaWAN (a treasure 30-40) cheaper;
LoRaWAN comprising the network layer, it is possible to send information to the base station connected to any cloud platform. Only the correct antenna is connected to its outlet, LoRaWAN module can work at different frequencies.

Here Insert Picture Description
one picture wins thoustands words (shown in FIG.)
LoRaWAN = the MAC Layer
Lora = a PHY Layer
Lora + = LPWAN LoRaWAN

It is because of networking lorawan, thousands of nodes becomes possible, this time gateway transplant STM32 connected nodes (SX1301) can theoretically connect 62500 nodes.

Ready development environment

Nucleo-F746ZG Board and ST Nucleo LoRa GW Module below
Here Insert Picture Description
Nucleo-L073R8 Board and ST Nucleo LoRa Sensor V2
Here Insert Picture Description
because RHF0M003 module on ST Nucleo LoRa Sensor V2 has integrated lorawan protocol, the MCU simply send AT commands can be realized by UART lorawan communications (a more expensive above said class module)

Shun can ra-02 (sx1278)
Here Insert Picture Description
module connector plate developed by Dupont line SPI1 GPIO (PA0-reset pin, PA10- interrupt pin), the VCC and ground, connected as shown below:
Here Insert Picture Description
the PC via a serial connection gateway, through AT commands things connected Tencent cloud development platform, the instruction following
the AT + PKTFWD = loragw.things.qcloud.com, 1700,1700
the AT CH + = 0,486.3, A
the AT CH + = 1,486.5, A
the AT CH + = 2,486.7, A
the AT + CH = 3,486.9, A
the AT + CH = 4,487.1, B
the AT + CH = 5,487.3, B
the AT + CH = 6,487.5, B
the AT + CH = 7,487.7, B
the AT + CH =. 8, OFF
the AT + CH =. 9, OFF
the AT + log = ON (This entry is very important, you can see the situation of communication gateways and the cloud platform, with nodes)
AT + the reset reset the gateway, then start the server connection.
These are the preparations for the transplant before node

text

initialization

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( );
}

As can be seen, according to some initialization is the way our network as macro settings, and so the use of regional initialized.

Network

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 );  
}

== before the network has been unsuccessful, contact Tencent cloud Xia Yunfei teacher, get back is wrong MIC, MIC error summer teacher said only two reasons, first, the wrong key, the second is wrong algorithm. ==

I am sure that the algorithm can not be wrong, because I did not turn over the source code, so I reconfirmed AppKey and devEui, yes. After a period of time tossing and Tencent two large cloud of God Xia Yunfei teachers and twowinter (real name not know ah, ha ha) guidance and tips, see the code again, the answer is as follows

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;
}

Transmission and reception

Send and receive because of what did not encounter difficulties, send a direct call function on the line, because it is a class A device will after sending, receiving open window receives; it posted a send function

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;
}

It still posted a map
Here Insert Picture Description
of all content is above.
Finally, thanks Tencent cloud Xia Yunfei teachers and twowinter again.
If you are interested in Lora can look twowinter articles, can be very helpful at the following link
Link
http://blog.csdn.net/iotisan/

Download link

Published an original article · won praise 0 · Views 150

Guess you like

Origin blog.csdn.net/lintonxie/article/details/105038547