ttn-esp32/src/TheThingsNetwork.cpp

244 lines
5.6 KiB
C++
Raw Normal View History

2018-07-15 22:11:11 +02:00
/*******************************************************************************
2018-07-21 21:54:29 +02:00
*
* ttn-esp32 - The Things Network device library for ESP-IDF / SX127x
*
2018-07-15 22:11:11 +02:00
* Copyright (c) 2018 Manuel Bleichenbacher
*
2018-07-21 21:54:29 +02:00
* Licensed under MIT License
* https://opensource.org/licenses/MIT
2018-07-15 22:11:11 +02:00
*
2018-07-23 17:59:07 +02:00
* High-level API for ttn-esp32.
2018-07-15 22:11:11 +02:00
*******************************************************************************/
#include "freertos/FreeRTOS.h"
#include "esp_event.h"
2018-07-15 22:11:11 +02:00
#include "esp_log.h"
#include "TheThingsNetwork.h"
#include "config.h"
2018-07-15 22:11:11 +02:00
#include "hal.h"
#include "hal_esp32.h"
#include "lmic.h"
#include "provisioning.h"
2018-07-15 22:11:11 +02:00
2018-07-19 21:19:32 +02:00
enum ClientAction
{
eActionUnrelated,
eActionJoining,
eActionSending
};
2018-07-15 22:11:11 +02:00
static const char *TAG = "ttn";
static TheThingsNetwork* ttnInstance;
2018-07-19 21:19:32 +02:00
static QueueHandle_t resultQueue;
static ClientAction clientAction = eActionUnrelated;
2018-07-15 22:11:11 +02:00
TheThingsNetwork::TheThingsNetwork()
: messageCallback(NULL)
2018-07-15 22:11:11 +02:00
{
#if defined(TTN_IS_DISABLED)
ESP_LOGE(TAG, "TTN is disabled. Configure a frequency plan using 'make menuconfig'");
ASSERT(0);
esp_restart();
#endif
ASSERT(ttnInstance == NULL);
2018-07-15 22:11:11 +02:00
ttnInstance = this;
hal_initCriticalSection();
}
TheThingsNetwork::~TheThingsNetwork()
{
// nothing to do
}
void TheThingsNetwork::configurePins(spi_host_device_t spi_host, uint8_t nss, uint8_t rxtx, uint8_t rst, uint8_t dio0, uint8_t dio1)
{
lmic_pins.spi_host = spi_host;
lmic_pins.nss = nss;
lmic_pins.rxtx = rxtx;
lmic_pins.rst = rst;
lmic_pins.dio0 = dio0;
lmic_pins.dio1 = dio1;
os_init();
reset();
2018-07-19 21:19:32 +02:00
resultQueue = xQueueCreate(12, sizeof(int));
2018-07-20 21:19:53 +02:00
ASSERT(resultQueue != NULL);
2018-07-15 22:11:11 +02:00
hal_startBgTask();
}
void TheThingsNetwork::reset()
{
hal_enterCriticalSection();
LMIC_reset();
hal_leaveCriticalSection();
}
bool TheThingsNetwork::provision(const char *devEui, const char *appEui, const char *appKey)
2018-07-15 22:11:11 +02:00
{
if (!provisioning_decode_keys(devEui, appEui, appKey))
2018-07-20 21:19:53 +02:00
return false;
return provisioning_save_keys();
2018-07-15 22:11:11 +02:00
}
void TheThingsNetwork::startProvisioningTask()
2018-07-15 22:11:11 +02:00
{
#if !defined(CONFIG_TTN_PROVISION_UART_NONE)
provisioning_start_task();
#endif
2018-07-15 22:11:11 +02:00
}
void TheThingsNetwork::waitForProvisioning()
{
#if !defined(CONFIG_TTN_PROVISION_UART_NONE)
if (isProvisioned())
{
ESP_LOGI(TAG, "Device is already provisioned");
return;
}
while (!provisioning_have_keys())
vTaskDelay(1000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Device successfully provisioned");
#endif
}
bool TheThingsNetwork::join(const char *devEui, const char *appEui, const char *appKey)
2018-07-15 22:11:11 +02:00
{
if (!provisioning_decode_keys(devEui, appEui, appKey))
2018-07-15 22:11:11 +02:00
return false;
2018-07-20 21:19:53 +02:00
return joinCore();
2018-07-15 22:11:11 +02:00
}
bool TheThingsNetwork::join()
2018-07-15 22:11:11 +02:00
{
if (!provisioning_have_keys())
2018-07-20 21:19:53 +02:00
{
if (!provisioning_restore_keys(false))
2018-07-20 21:19:53 +02:00
return false;
}
return joinCore();
}
bool TheThingsNetwork::joinCore()
{
if (!provisioning_have_keys())
2018-07-20 21:19:53 +02:00
{
ESP_LOGW(TAG, "Device EUI, App EUI and/or App key have not been provided");
return false;
}
2018-07-15 22:11:11 +02:00
hal_enterCriticalSection();
2018-07-19 21:19:32 +02:00
clientAction = eActionJoining;
2018-07-15 22:11:11 +02:00
LMIC_startJoining();
hal_wakeUp();
hal_leaveCriticalSection();
2018-07-19 21:19:32 +02:00
int result = 0;
xQueueReceive(resultQueue, &result, portMAX_DELAY);
return result == EV_JOINED;
2018-07-15 22:11:11 +02:00
}
2018-07-21 18:07:36 +02:00
TTNResponseCode TheThingsNetwork::transmitMessage(const uint8_t *payload, size_t length, port_t port, bool confirm)
2018-07-15 22:11:11 +02:00
{
hal_enterCriticalSection();
if (LMIC.opmode & OP_TXRXPEND)
{
hal_leaveCriticalSection();
2018-07-19 22:04:32 +02:00
return kTTNErrorTransmissionFailed;
2018-07-15 22:11:11 +02:00
}
2018-07-19 21:19:32 +02:00
clientAction = eActionSending;
2018-07-15 22:11:11 +02:00
LMIC_setTxData2(port, (xref2u1_t)payload, length, confirm);
hal_wakeUp();
hal_leaveCriticalSection();
2018-07-19 21:19:32 +02:00
int result = 0;
xQueueReceive(resultQueue, &result, portMAX_DELAY);
2018-07-19 16:16:40 +02:00
if (result == EV_TXCOMPLETE)
{
bool hasRecevied = (LMIC.txrxFlags & (TXRX_DNW1 | TXRX_DNW2)) != 0;
if (hasRecevied && messageCallback != NULL)
{
port_t port = 0;
if ((LMIC.txrxFlags & TXRX_PORT))
port = LMIC.frame[LMIC.dataBeg - 1];
2018-07-19 22:04:32 +02:00
const uint8_t* msg = NULL;
if (LMIC.dataLen > 0)
msg = LMIC.frame + LMIC.dataBeg;
messageCallback(msg, LMIC.dataLen, port);
2018-07-19 16:16:40 +02:00
}
2018-07-19 22:04:32 +02:00
return kTTNSuccessfulTransmission;
2018-07-19 16:16:40 +02:00
}
2018-07-19 22:04:32 +02:00
return kTTNErrorTransmissionFailed;
2018-07-19 16:16:40 +02:00
}
2018-07-19 22:04:32 +02:00
void TheThingsNetwork::onMessage(TTNMessageCallback callback)
2018-07-19 16:16:40 +02:00
{
messageCallback = callback;
2018-07-15 22:11:11 +02:00
}
2018-07-20 21:19:53 +02:00
bool TheThingsNetwork::isProvisioned()
{
if (provisioning_have_keys())
2018-07-20 21:19:53 +02:00
return true;
return provisioning_restore_keys(true);
2018-07-20 21:19:53 +02:00
}
2018-07-15 22:11:11 +02:00
// --- LMIC functions ---
#if CONFIG_LOG_DEFAULT_LEVEL >= 3
static const char *eventNames[] = {
NULL,
"EV_SCAN_TIMEOUT", "EV_BEACON_FOUND",
"EV_BEACON_MISSED", "EV_BEACON_TRACKED", "EV_JOINING",
"EV_JOINED", "EV_RFU1", "EV_JOIN_FAILED", "EV_REJOIN_FAILED",
"EV_TXCOMPLETE", "EV_LOST_TSYNC", "EV_RESET",
"EV_RXCOMPLETE", "EV_LINK_DEAD", "EV_LINK_ALIVE"
};
#endif
void onEvent (ev_t ev) {
#if CONFIG_LOG_DEFAULT_LEVEL >= 3
ESP_LOGI(TAG, "event %s", eventNames[ev]);
2018-07-15 22:11:11 +02:00
#endif
if (ev == EV_TXCOMPLETE) {
if (LMIC.txrxFlags & TXRX_ACK)
2018-07-19 16:16:40 +02:00
ESP_LOGI(TAG, "ACK received\n");
2018-07-15 22:11:11 +02:00
}
2018-07-19 21:19:32 +02:00
if (clientAction == eActionUnrelated)
{
return;
}
else if (clientAction == eActionJoining)
{
2018-07-23 15:29:37 +02:00
if (ev != EV_JOINED && ev != EV_REJOIN_FAILED && ev != EV_RESET)
2018-07-19 21:19:32 +02:00
return;
}
else
{
2018-07-23 15:29:37 +02:00
if (ev != EV_TXCOMPLETE && ev != EV_LINK_DEAD && ev != EV_RESET)
2018-07-19 21:19:32 +02:00
return;
}
int result = ev;
2018-07-19 21:19:32 +02:00
clientAction = eActionUnrelated;
xQueueSend(resultQueue, &result, 100 / portTICK_PERIOD_MS);
2018-07-15 22:11:11 +02:00
}