#include <Arduino.h>
#include <aes.h>
#include <board.h>
#include <cmac.h>
#include <Commissioning.h>
#include <delay.h>
#include <dht11.h>
#include <fifo.h>
#include <LoRa.h>
#include <LoRaMac-definitions.h>
#include <LoRaMac.h>
#include <LoRaMacCrypto.h>
#include <LoRaMacTest.h>
#include <Mcu.h>
#include <OLEDDisplay.h>
#include <OLEDDisplayFonts.h>
#include <OLEDDisplayUi.h>
#include <pinName-board.h>
#include <pinName-ioe.h>
#include <radio.h>
#include <rtc-board.h>
#include <RTE_Components.h>
#include <SSD1306.h>
#include <SSD1306Wire.h>
#include <sx1276-board.h>
#include <sx1276.h>
#include <sx1276Regs-Fsk.h>
#include <sx1276Regs-LoRa.h>
#include <timer.h>
#include <utilities.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <BLE2902.h>
/*
BASADO EN:
HelTec Automation™ LoRaWAN 1.0.2 OTAA example use OTAA, CLASS A
- Only ESP32 + LoRa series boards can use this library, need a license
to make the code run(check you license here: http://www.heltec.cn/search/);
You can change some definition in “Commissioning.h” and “LoRaMac-definitions.h”
BLE:
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with “WRITE”
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with “NOTIFY”
The design of creating the BLE server is:
- Create a BLE Server
- Create a BLE Service
- Create a BLE Characteristic on the Service
- Create a BLE Descriptor on the characteristic
- Start the service.
- Start advertising.
In this example rxValue is the data received (only accessible inside that function).
And txValue is the data to be sent, in this example just a byte incremented every second.
*/
#define V2
#define CLASS CLASS_A
#define BOTON 0
#ifdef V2 //WIFI Kit series V1 not support Vext control
#define DIO1 35 // GPIO35 – SX127x’s IRQ(Interrupt Request) V2
#else
#define DIO1 33 // GPIO33 – SX127x’s IRQ(Interrupt Request) V1
#endif
#define Vext 21
#if defined Wireless_Stick
#define DISPLAY_FUENTE DejaVu_Sans_Mono_8 //DialogInput_plain_8
#define DISPLAY_GEOMETRY GEOMETRY_64_32
#define DIPLAY_H_CENTER 32
#define DISPLAY_V_CENTER (16-4)
#define DIPLAY_LINEA_0 0
#define DIPLAY_LINEA_1 10
#define DIPLAY_LINEA_2 20
#else
#define DISPLAY_FUENTE ArialMT_Plain_16
#define DISPLAY_GEOMETRY GEOMETRY_128_64
#define DIPLAY_H_CENTER 64
#define DISPLAY_V_CENTER (32-8)
#define DIPLAY_LINEA_0 10
#define DIPLAY_LINEA_1 30
#define DIPLAY_LINEA_2 48
#endif
#define SERVICE_UUID “6E400001-B5A3-F393-E0A9-E50E24DCCA9E” // UART service UUID
#define CHARACTERISTIC_UUID_RX “6E400002-B5A3-F393-E0A9-E50E24DCCA9E”
#define CHARACTERISTIC_UUID_TX “6E400003-B5A3-F393-E0A9-E50E24DCCA9E”
bool OVER_THE_AIR_ACTIVATION = true;
uint8_t DevEui[] = { 0x22,0x32,0x33, 0x00, 0x00, 0x88, 0x88, 0x33 };
uint8_t AppEui[] = { 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x04 };
uint8_t AppKey[] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x66, 0x01 };
//LICENSE
uint32_t LICENSE[4] = {0x5A78D2C3, 0x2691AD3D, 0x9DECB5B4, 0x7E0BCFF8}; //470v2
//ABP
uint32_t ABP_DevAddr = ( uint32_t )0x26011713 ;
RTC_DATA_ATTR uint8_t ABP_NwkSKey[] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x66, 0x02 };
RTC_DATA_ATTR uint8_t ABP_AppSKey[] = { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x66, 0x01 };
SSD1306 display(0x3c, SDA, SCL, RST_LED, DISPLAY_GEOMETRY);
BLECharacteristic *pCharacteristic;
BLEServer *pServer;
bool deviceConnected = false;
bool oldDeviceConnected = false;
bool BTRxData = false;
std::string BTRxStringValue;
float txValue = 0;
const int readPin = 32; // Use GPIO number. See ESP32 board pinouts
extern McpsIndication_t McpsIndication;
//Delivery of data on port 2
void app(uint8_t data)
{
lora_printf(“data:%d\r\n”, data);
}
/*
BLUETOOTH CALLBACKS
/
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
//std::string rxValue = pCharacteristic->getValue();
BTRxStringValue = pCharacteristic->getValue();
//BTRxValue = pCharacteristic->getData();
BTRxData = true;
}
};
void BTRespuestaACK()
{
char txString[] = {“ACK”};
pCharacteristic->setValue(txString);
pCharacteristic->notify(); // Send the value to the app!
lora_printf(“Bluetooth - ACK\n”);
}
void BTRespuestaNACK()
{
char txString[] = {“NACK”};
pCharacteristic->setValue(txString);
pCharacteristic->notify(); // Send the value to the app!
lora_printf(“Bluetooth - NACK!!!\n”);
}
void BTSendJoinOK()
{
char txString[] = {“Joined”};
pCharacteristic->setValue(txString);
pCharacteristic->notify(); // Send the value to the app!
lora_printf(“Bluetooth - Joined\n”);
}
void BTSendJoinError()
{
char txString[] = {“Join ERROR”};
pCharacteristic->setValue(txString);
pCharacteristic->notify(); // Send the value to the app!
lora_printf(“Bluetooth - Join Error\n”);
}
void BTSendACK()
{
char txString[] = {“Frame ACKED”};
pCharacteristic->setValue(txString);
pCharacteristic->notify(); // Send the value to the app!
lora_printf(“Bluetooth - Frame ACKED\n”);
}
void BTSendNoACK()
{
char txString[] = {“Frame NOT ACKED”};
pCharacteristic->setValue(txString);
pCharacteristic->notify(); // Send the value to the app!
lora_printf(“Bluetooth - Frame NOT ACKED\n”);
}
/*
/
pTxCharacteristic->setValue(&txValue, 1);
pTxCharacteristic->notify();
txValue++;
*/
/*
NOTIFICACIONES LORAWAN
*/
void LEDdisplayJOINING()
{
digitalWrite(Vext, LOW);
delay(50);
display.wakeup();
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(DIPLAY_H_CENTER, DISPLAY_V_CENTER, “JOINING…”);
display.display();
}
void LEDdisplayJOINED()
{
digitalWrite(Vext, LOW);
delay(50);
display.wakeup();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.clear();
display.drawString(DIPLAY_H_CENTER, DISPLAY_V_CENTER, “JOINED”);
display.display();
delay(2000);
display.sleep();
digitalWrite(Vext, HIGH);
}
void LEDdisplayJOINERROR()
{
digitalWrite(Vext, LOW);
delay(50);
display.wakeup();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.clear();
display.drawString(DIPLAY_H_CENTER, DISPLAY_V_CENTER, “JOIN ERROR”);
display.display();
delay(2000);
display.sleep();
digitalWrite(Vext, HIGH);
}
void LEDdisplaySENDING()
{
digitalWrite(Vext, LOW);
delay(10);
display.wakeup();
display.init();
delay(50);
display.flipScreenVertically();
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(DISPLAY_FUENTE);
display.drawString(DIPLAY_H_CENTER, DISPLAY_V_CENTER, “SENDING…”);
display.display();
}
void LEDdisplayACKED()
{
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(DIPLAY_H_CENTER, DIPLAY_LINEA_0, “ACK RECEIVED”);
display.drawString(DIPLAY_H_CENTER, DIPLAY_LINEA_1, "rssi= " + String(McpsIndication.Rssi) + “dBm”);
display.drawString(DIPLAY_H_CENTER, DIPLAY_LINEA_2, “DR=” + String(McpsIndication.RxDatarate));
display.display();
if (CLASS == CLASS_A)
{
delay(5000);
display.sleep();
digitalWrite(Vext, HIGH);
}
}
void LEDdisplayNOACK()
{
display.setTextAlignment(TEXT_ALIGN_CENTER);
#if defined Wireless_Stick
display.drawString(DIPLAY_H_CENTER, DIPLAY_LINEA_1, “NO ACK RECEIVED”);
#else
display.clear();
display.drawString(DIPLAY_H_CENTER, DISPLAY_V_CENTER, “NO ACK RECEIVED”);
#endif
display.display();
}
/*
DISPLAY
*/
void LEDdisplaySTART()
{
display.wakeup();
display.init();
delay(100);
display.flipScreenVertically();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.clear();
display.setFont(DISPLAY_FUENTE);
display.drawString(DIPLAY_H_CENTER, DIPLAY_LINEA_0, “STARTING”);
display.drawString(DIPLAY_H_CENTER, DIPLAY_LINEA_1, “LORAWAN”);
display.display();
}
/*
SETUP
*/
void setup()
{
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW); // OLED USE Vext as power supply, must turn ON Vext before OLED init
pinMode(BOTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
Serial.begin(115200);
while (!Serial);
delay(100);
// DISPLAY
LEDdisplaySTART();
// LORA
SPI.begin(SCK, MISO, MOSI, SS);
Mcu.begin(SS, RST_SX127x, DIO0, DIO1, LICENSE);
DeviceState = DEVICE_STATE_INIT;
LoRa.DeviceStateInit(CLASS);
// BLUETOOTH
// Create the BLE Device
BLEDevice::init(“LoRaWAN Test”); // Give it a name
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
//pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println(“Bluetooth - Waiting a client connection to notify…”);
State = STATE_INIT;
}
bool JoinAttempt = false;
bool SendAttempt = false;
bool PararLoRa = false;
void loop()
{
// BLUETOOTH
if (deviceConnected) {
if (BTRxData)
{
switch (BTRxStringValue[0])
{
case ‘J’:
{
if ((DeviceState != DEVICE_STATE_INIT) || (IsLoRaMacNetworkJoined == true))
BTRespuestaNACK();
else
{
DeviceState = DEVICE_STATE_JOIN;
BTRespuestaACK();
}
break;
}
case ‘S’:
{
if ((DeviceState != DEVICE_STATE_INIT) || (IsLoRaMacNetworkJoined == false))
BTRespuestaNACK();
else
{
DeviceState = DEVICE_STATE_SEND;
BTRespuestaACK();
}
break;
}
}
BTRxData = 0;
}
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
lora_printf(“Bluetooth - Desconectado\n”);
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
lora_printf(“Bluetooth - start advertising”);
oldDeviceConnected = deviceConnected;
PararLoRa = true;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
lora_printf(“Bluetooth - Conectado\n”);
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
// LORAWAN
switch ( DeviceState )
{
case DEVICE_STATE_INIT: // Espera a que desde el bluetooth se cambie de estado
{
if (PararLoRa)
{
LoRa.DeviceStateInit(CLASS);
PararLoRa = false;
}
break;
}
case DEVICE_STATE_JOIN:
{
if (JoinAttempt == true) // Error en el intento de join
{
LEDdisplayJOINERROR();
BTSendJoinError();
DeviceState = DEVICE_STATE_INIT;
JoinAttempt = false;
}
else
{
JoinAttempt = true;
LoRa.DeviceStateInit(CLASS);
LEDdisplayJOINING();
LoRa.DeviceStateJion(OVER_THE_AIR_ACTIVATION); // Si hace el join correcto, acaba con estado DEVICE_STATE_SEND. Si falla, vuelve con estado DEVICE_STATE_JOIN
}
break;
}
case DEVICE_STATE_SEND:
{
if (JoinAttempt == true) // Intentando join
{ // Join correcto
if (isJioned == 1)
{
isJioned--;
LEDdisplayJOINED();
BTSendJoinOK();
}
JoinAttempt = false;
DeviceState = DEVICE_STATE_INIT;
}
else if (SendAttempt == true) // Se ha enviado trama: si vuelve a este estado es que no ha habido respuesta
{
LEDdisplayNOACK();
SendAttempt = false;
BTSendNoACK();
DeviceState = DEVICE_STATE_INIT;
}
else // Enviar la trama recibida del Bluetooth
{
LEDdisplaySENDING();
lora_printf("Into send state\n");
// void PrepareMsgFrame( uint8_t port, uint8_t Msg2Send[], uint8_t length )
PrepareMsgFrame( BTRxStringValue[1],(uint8_t *) &BTRxStringValue[2] , BTRxStringValue.length()-2);
LoRa.DeviceStateSend();
DeviceState = DEVICE_STATE_CYCLE;
}
break;
}
case DEVICE_STATE_CYCLE:
{
// Schedule next packet transmission
//TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
TimerSetValue( &TxNextPacketTimer, 5000 ); // Al acabar el tiempo se despierta con estado DEVICE_STATE_SEND o DEVICE_STATE_JOIN
TimerStart( &TxNextPacketTimer );
DeviceState = DEVICE_STATE_SLEEP;
break;
}
case DEVICE_STATE_SLEEP:
{
if (isAckReceived == 1)
{
SendAttempt=false;
isAckReceived--;
LEDdisplayACKED();
BTSendACK();
lora_printf("DownLink msg : %s\n", msgRx.isDwn ? "true" : "false"); // debug
if ( msgRx.isDwn == true ) // something received
{
lora_printf("Msg received: %s\n", msgRx.msg);
}
DeviceState = DEVICE_STATE_INIT;
}
LoRa.DeviceSleep(CLASS, DebugLevel);
break;
}
default:
{
DeviceState = DEVICE_STATE_INIT;
break;
}
}
}