使用 STM32 通过 LoRaWAN 发送消息
Sending messages through LoRaWAN using STM32
如何通过 LoRaWAN 发送消息?
static void PrepareTxFrame( uint8_t port )
{
switch( port ) {
case 10: {
int pos = 0;
pc.printf("Prepare message\n");
#if 0
uint32_t tempValue = ( uint32_t )( LightValue * 1000000.0 );
AppData[0] = LightMode;
AppData[1] = ( ( tempValue & 0xFF000000 ) >> 24 ) & 0xFF;
AppData[2] = ( ( tempValue & 0x00FF0000 ) >> 16 ) & 0xFF;
AppData[3] = ( ( tempValue & 0x0000FF00 ) >> 8 ) & 0xFF;
AppData[4] = ( tempValue & 0x000000FF );
#else
AppData[pos] = count;
pc.printf("\n\r");
pc.printf("The value of the counter is : %d", count);
count++;
pc.printf("\n\r");
time_t seconds = time(NULL);
printf("The time is %s", ctime(&seconds));
AppData[++pos] = seconds;
pc.printf("%d \n %d", AppData[0], AppData[1]);
pc.printf("\n\r");
#endif
pc.printf("Message Ready\n");
}
break;
case 15: {
int pos = 0;
AppData[pos++] = AppLedStateOn;
#if 0
if( IsTxConfirmed == true )
{
AppData[pos++] = LoRaMacDownlinkStatus.DownlinkCounter >> 8;
AppData[pos++] = LoRaMacDownlinkStatus.DownlinkCounter;
AppData[pos++] = LoRaMacDownlinkStatus.Rssi >> 8;
AppData[pos++] = LoRaMacDownlinkStatus.Rssi;
AppData[pos++] = LoRaMacDownlinkStatus.Snr;
}
#endif
AppDataSize = pos;
}
break;
case 224:
if( ComplianceTest.LinkCheck == true ) {
ComplianceTest.LinkCheck = false;
AppDataSize = 3;
AppData[0] = 5;
AppData[1] = ComplianceTest.DemodMargin;
AppData[2] = ComplianceTest.NbGateways;
ComplianceTest.State = 1;
} else {
switch( ComplianceTest.State ) {
case 4:
ComplianceTest.State = 1;
break;
case 1:
AppDataSize = 2;
AppData[0] = ComplianceTest.DownLinkCounter >> 8;
AppData[1] = ComplianceTest.DownLinkCounter;
break;
}
}
break;
default:
break;
}
}
/*!
* \brief
*
* Prepares the pay-load of the frame
*
* \retval [0: frame could be send, 1: error]
*/
static bool SendFrame( void )
{
McpsReq_t mcpsReq;
LoRaMacTxInfo_t txInfo;
if( LoRaMacQueryTxPossible( AppDataSize, &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 = LORAWAN_DEFAULT_DATARATE;
LoRaMacUplinkStatus.Acked = false;
LoRaMacUplinkStatus.Port = 0;
LoRaMacUplinkStatus.Buffer = NULL;
LoRaMacUplinkStatus.BufferSize = 0;
SerialDisplayUpdateFrameType( false );
} else {
LoRaMacUplinkStatus.Acked = false;
LoRaMacUplinkStatus.Port = AppPort;
LoRaMacUplinkStatus.Buffer = AppData;
LoRaMacUplinkStatus.BufferSize = AppDataSize;
SerialDisplayUpdateFrameType( IsTxConfirmed );
if( IsTxConfirmed == false ) {
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fPort = AppPort;
mcpsReq.Req.Unconfirmed.fBuffer = AppData;
mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
} else {
mcpsReq.Type = MCPS_CONFIRMED;
mcpsReq.Req.Confirmed.fPort = AppPort;
mcpsReq.Req.Confirmed.fBuffer = AppData;
mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Confirmed.NbTrials = 8;
mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
}
if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK ) {
return false;
}
return true;
}
会发送计数器数据和时间吗? AppData中的数据也是要传输的数据吗?我希望每次 LoRa 设备传输时都发送计数和时间戳。
要发送的有效负载(AppData
)通过 MCPS(MAC 公共部分子层)请求提供给 LoRaMAC 层,例如对于未确认的帧:
mcpsReq.Req.Unconfirmed.fBuffer = AppData;
因此物理上(即通过RF),AppData
被发送但之前被加密和封装。
PrepareFrame()
函数根据 PHYPayload
方案构建要发送的帧(请参阅 LoRaWAN™ 规范 1.0.2 文档中的 "MAC Message Formats" 部分),遵循以下字段:
MHDR
(1 字节)Macheader
DevAddr
(4 字节)end-device 的地址
FCtrl
(1字节)帧控制
FCnt
(2 字节)帧计数器
FOpts
(0 - 15 字节)帧选项
FPort
(0 - 1 字节)端口字段
FRMPayload
(0 - N 字节)MAC 帧负载加密,您的 AppData
已加密
MIC
(4 字节)消息完整性代码
FRMPayload
按照FPort加密。加密算法基于AES 128.
如果 FPort
= [1..255],AppSKey
密钥将用于加密您的负载。
否则 (FPort
= 0),使用 NwkSKey
密钥加密。
有关详细信息,请参阅 LoRaMacPayloadEncrypt()
函数。
PHYPayload
会被Radio PHY Layer
封装并通过RF发送。
如何通过 LoRaWAN 发送消息?
static void PrepareTxFrame( uint8_t port )
{
switch( port ) {
case 10: {
int pos = 0;
pc.printf("Prepare message\n");
#if 0
uint32_t tempValue = ( uint32_t )( LightValue * 1000000.0 );
AppData[0] = LightMode;
AppData[1] = ( ( tempValue & 0xFF000000 ) >> 24 ) & 0xFF;
AppData[2] = ( ( tempValue & 0x00FF0000 ) >> 16 ) & 0xFF;
AppData[3] = ( ( tempValue & 0x0000FF00 ) >> 8 ) & 0xFF;
AppData[4] = ( tempValue & 0x000000FF );
#else
AppData[pos] = count;
pc.printf("\n\r");
pc.printf("The value of the counter is : %d", count);
count++;
pc.printf("\n\r");
time_t seconds = time(NULL);
printf("The time is %s", ctime(&seconds));
AppData[++pos] = seconds;
pc.printf("%d \n %d", AppData[0], AppData[1]);
pc.printf("\n\r");
#endif
pc.printf("Message Ready\n");
}
break;
case 15: {
int pos = 0;
AppData[pos++] = AppLedStateOn;
#if 0
if( IsTxConfirmed == true )
{
AppData[pos++] = LoRaMacDownlinkStatus.DownlinkCounter >> 8;
AppData[pos++] = LoRaMacDownlinkStatus.DownlinkCounter;
AppData[pos++] = LoRaMacDownlinkStatus.Rssi >> 8;
AppData[pos++] = LoRaMacDownlinkStatus.Rssi;
AppData[pos++] = LoRaMacDownlinkStatus.Snr;
}
#endif
AppDataSize = pos;
}
break;
case 224:
if( ComplianceTest.LinkCheck == true ) {
ComplianceTest.LinkCheck = false;
AppDataSize = 3;
AppData[0] = 5;
AppData[1] = ComplianceTest.DemodMargin;
AppData[2] = ComplianceTest.NbGateways;
ComplianceTest.State = 1;
} else {
switch( ComplianceTest.State ) {
case 4:
ComplianceTest.State = 1;
break;
case 1:
AppDataSize = 2;
AppData[0] = ComplianceTest.DownLinkCounter >> 8;
AppData[1] = ComplianceTest.DownLinkCounter;
break;
}
}
break;
default:
break;
}
}
/*!
* \brief
*
* Prepares the pay-load of the frame
*
* \retval [0: frame could be send, 1: error]
*/
static bool SendFrame( void )
{
McpsReq_t mcpsReq;
LoRaMacTxInfo_t txInfo;
if( LoRaMacQueryTxPossible( AppDataSize, &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 = LORAWAN_DEFAULT_DATARATE;
LoRaMacUplinkStatus.Acked = false;
LoRaMacUplinkStatus.Port = 0;
LoRaMacUplinkStatus.Buffer = NULL;
LoRaMacUplinkStatus.BufferSize = 0;
SerialDisplayUpdateFrameType( false );
} else {
LoRaMacUplinkStatus.Acked = false;
LoRaMacUplinkStatus.Port = AppPort;
LoRaMacUplinkStatus.Buffer = AppData;
LoRaMacUplinkStatus.BufferSize = AppDataSize;
SerialDisplayUpdateFrameType( IsTxConfirmed );
if( IsTxConfirmed == false ) {
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fPort = AppPort;
mcpsReq.Req.Unconfirmed.fBuffer = AppData;
mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
} else {
mcpsReq.Type = MCPS_CONFIRMED;
mcpsReq.Req.Confirmed.fPort = AppPort;
mcpsReq.Req.Confirmed.fBuffer = AppData;
mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
mcpsReq.Req.Confirmed.NbTrials = 8;
mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
}
}
if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK ) {
return false;
}
return true;
}
会发送计数器数据和时间吗? AppData中的数据也是要传输的数据吗?我希望每次 LoRa 设备传输时都发送计数和时间戳。
要发送的有效负载(AppData
)通过 MCPS(MAC 公共部分子层)请求提供给 LoRaMAC 层,例如对于未确认的帧:
mcpsReq.Req.Unconfirmed.fBuffer = AppData;
因此物理上(即通过RF),AppData
被发送但之前被加密和封装。
PrepareFrame()
函数根据 PHYPayload
方案构建要发送的帧(请参阅 LoRaWAN™ 规范 1.0.2 文档中的 "MAC Message Formats" 部分),遵循以下字段:
MHDR
(1 字节)MacheaderDevAddr
(4 字节)end-device 的地址
FCtrl
(1字节)帧控制FCnt
(2 字节)帧计数器FOpts
(0 - 15 字节)帧选项FPort
(0 - 1 字节)端口字段FRMPayload
(0 - N 字节)MAC 帧负载加密,您的AppData
已加密MIC
(4 字节)消息完整性代码
FRMPayload
按照FPort加密。加密算法基于AES 128.
如果 FPort
= [1..255],AppSKey
密钥将用于加密您的负载。
否则 (FPort
= 0),使用 NwkSKey
密钥加密。
有关详细信息,请参阅 LoRaMacPayloadEncrypt()
函数。
PHYPayload
会被Radio PHY Layer
封装并通过RF发送。