LoRaWan – Enlaces Up/Down Archivo.ino

Preparación de trama

La trama se configura usando los parametros obtenidos en el dispositivo con una trama de confirmación de subida (Ack). El primer valor enviado será cero, puesto que no se dispone de parámetros iniciales.

  • Rssi Downlink (1 byte)
  • Snr Downlink (1 byte)
  • Datarate Downlink (1 byte)
  • Voltaje de bateria (2 bytes)
// Ack parametros de recepción
uint8_t confirmaRssi = 0;
uint8_t confirmaSnr = 0;
uint8_t confirmaDatarate = 0;

A Septiembre del 2021, se usan las librerías publicadas para el módulo HELTEC Cubecell Board-Plus HTCC-AB02. Para obtener los parámetros de la trama de confirmación de recibido (Ack) el gateway para una trama de subida de datos (Uplink) se sustituye el procedimiento:

downLinkAckHandle(McpsIndication_t *mcpsIndication)

Las instrucciones para el manejo de LoraWan se pueden revisar en:

https://github.com/HelTecAutomation/CubeCell-Arduino/blob/master/libraries/LoRa/src/LoRaWan_APP.cpp

El archivo LoRaWan_APP.cpp se encuentra instalado en el directorio de windows:

C:\Users\MiUsuario\AppData\Local\Arduino15\packages
  \CubeCell\hardware\CubeCell\1.3.0\libraries\LoRa\src

desde donde es posible complementar las instrucciones usando un editor de texto en las líneas corespondientes:

void __attribute__((weak)) downLinkAckHandle()
{
	//printf("ack received\r\n");
}

para indicar los parámetros a usar al recibir la trama Ack:

void __attribute__((weak)) downLinkAckHandle(McpsIndication_t *mcpsIndication)
{
	//printf("ack received\r\n");
}

adicionalmente, en el mismo archivo, más adelante:

static void McpsIndication( McpsIndication_t *mcpsIndication )
....
	if(mcpsIndication->AckReceived)
	{
		downLinkAckHandle(mcpsIndication);
	}

con lo que es posible usar las instrucciones del dispositivo para obtener los parámetros indicados para la trama de confirmación de recibo (Ack)

Parámetros de trama de confirmación de recibido – Ack

void downLinkAckHandle(McpsIndication_t *mcpsIndication){
  confirmaRssi = uint8_t(abs(mcpsIndication->Rssi));
  confirmaSnr  = uint8_t(mcpsIndication->Snr);
  confirmaDatarate = uint8_t(mcpsIndication->RxDoneDatarate);
  Serial.print(" ack received(rssi,snd,datarate): -");
  Serial.print(confirmaRssi);Serial.print(" ,");
  Serial.print(confirmaSnr);Serial.print(" ,");
  Serial.println(confirmaDatarate);
}

con los parámetros obtenidos y añadiendo el voltaje de la batería, se conforma la trama a enviar.

/* Prepares the payload of the frame */
static void prepareTxFrame( uint8_t port ) {
  // enciende sensor
  pinMode(Vext, OUTPUT);
  digitalWrite(Vext, LOW);
  
  //Lectura de Sensor

  // apaga sensor
  digitalWrite(Vext, HIGH);
  
  // lectura de bateria  
  uint16_t batteryVoltage = getBatteryVoltage();
  unsigned char *puc;

  // trama
  appDataSize = 5;
  appData[0] = confirmaRssi; //Ack leido en dispositivo
  appData[1] = confirmaSnr;
  appData[2] = confirmaDatarate;
  appData[3] = (uint8_t)batteryVoltage;
  appData[4] = (uint8_t)(batteryVoltage>>8);

  Serial.print("%, Bateria = ");
  Serial.println(batteryVoltage);
}

Instrucciones Principales

#include "LoRaWan_APP.h"
#include "Arduino.h"

/* set LoraWan_RGB to Active,the RGB active in loraWan
 * red   |sending;   purple | joined done;
 * blue  |RxWindow1; yellow | means RxWindow2;
 * green | received done;
 */
/* Conexión LoRa: OTAA parametros*/
uint8_t devEui[] = { 0xa6, 0x17, 0x74, 0xe9, 0x5c, 0x1c, 0x98, 0xbd };
uint8_t appEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t appKey[] = { 0x76, 0x9d, 0x1b, 0xc3, 0xf9, 0xe6, 0x7b, 0xbd,
                     0xa3, 0x4d, 0xe3, 0xcf, 0xbc, 0x8e, 0x35, 0x8f };
/* ABP parametros*/
uint8_t nwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe,
                      0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda,0x85 };
uint8_t appSKey[] = { 0x47, 0xdc, 0xac, 0x5f, 0xc2, 0x32, 0x24, 0x31, 
                      0xdf, 0xf1, 0xff, 0xf9, 0x46, 0xe5, 0x2e, 0x17 };
uint32_t devAddr =  ( uint32_t )0x007bc4af;
/*LoraWan channelsmask, default channels 0-7*/ 
uint16_t userChannelsMask[6]={ 0x00FF,0x0000,0x0000,0x0000,0x0000,0x0000 };

/*Select in arduino IDE tools*/
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;
DeviceClass_t  loraWanClass = LORAWAN_CLASS;
bool overTheAirActivation = LORAWAN_NETMODE;
bool loraWanAdr = LORAWAN_ADR;
bool keepNet = LORAWAN_NET_RESERVE;
bool isTxConfirmed = LORAWAN_UPLINKMODE;

uint32_t appTxDutyCycle = 1*15*1000;
uint8_t appPort = 2; /* Application port */
/* trials to transmit frame, if didn't receive ack.
 * The MAC performs a datarate adaptation,
 * Tx nb|Data Rate
 * -----|----------
 * 1    |DR           * 5    | max(DR-2,0)
 * 2    |DR           * 6    | max(DR-2,0)
 * 3    |max(DR-1,0)  * 7    | max(DR-3,0)
 * 4    |max(DR-1,0)  * 8    | max(DR-3,0)
*/
uint8_t confirmedNbTrials = 4;

// Ack parametros de recepción
uint8_t confirmaRssi = 0;
uint8_t confirmaSnr = 0;
uint8_t confirmaDatarate = 0;

uint8_t itera = 0;

void setup() {
	Serial.begin(115200);
#if(AT_SUPPORT)
	enableAt();
#endif
  LoRaWAN.displayMcuInit();
	deviceState = DEVICE_STATE_INIT;
	LoRaWAN.ifskipjoin(); //if joinned,skip
}

void loop() {
  Serial.print(".");
  itera = itera + 1;
  if (itera>6){
    itera = 0;
    Serial.println(" ");
  }
	switch( deviceState ) {
		case DEVICE_STATE_INIT: {
#if(LORAWAN_DEVEUI_AUTO)
			LoRaWAN.generateDeveuiByChipID();
#endif
#if(AT_SUPPORT)
			getDevParam();
#endif
			printDevParam();
			LoRaWAN.init(loraWanClass,loraWanRegion);
			deviceState = DEVICE_STATE_JOIN;
			break;
		}
		case DEVICE_STATE_JOIN: {
      LoRaWAN.displayJoining();
			LoRaWAN.join();
			break;
		}
		case DEVICE_STATE_SEND:	{
      LoRaWAN.displaySending();
			prepareTxFrame( appPort );
			LoRaWAN.send();
			deviceState = DEVICE_STATE_CYCLE;
			break;
		}
		case DEVICE_STATE_CYCLE: {
			// Schedule next packet transmission
			txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND );
			LoRaWAN.cycle(txDutyCycleTime);
			deviceState = DEVICE_STATE_SLEEP;
			break;
		}
		case DEVICE_STATE_SLEEP: {
      LoRaWAN.displayAck();
			LoRaWAN.sleep();
			break;
		}
		default: {
			deviceState = DEVICE_STATE_INIT;
			break;
		}
	}
}

y en el caso de recibir instrucciones para el dispositivo, se dispone de un ejemplo:

//downlink data handle function example
void downLinkDataHandle(McpsIndication_t *mcpsIndication){
  // revisa parametros
  Serial.print("\nLLEGo un mensaje para dispositivo...");
  Serial.print("Rssi: ");
  Serial.println(mcpsIndication->Rssi);
  
  Serial.printf("+REV DATA:%s,RXSIZE %d,PORT %d\r\n",
  mcpsIndication->RxSlot?"RXWIN2":"RXWIN1",
  mcpsIndication->BufferSize,mcpsIndication->Port);
  Serial.print("+REV DATA:");
  for(uint8_t i=0;i<mcpsIndication->BufferSize;i++)
  {
    Serial.printf("%02X",mcpsIndication->Buffer[i]);
  }
  Serial.println();
  uint32_t color=mcpsIndication->Buffer[0]<<16|mcpsIndication->Buffer[1]<<8|mcpsIndication->Buffer[2];
#if(LoraWan_RGB==1)
  turnOnRGB(color,5000);
  turnOffRGB();
#endif
}