ttn-esp32/src/TheThingsNetwork.cpp

255 lines
5.9 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"
2018-10-02 20:25:40 +02:00
#include "hal/hal_esp32.h"
#include "lmic/lmic.h"
2018-10-27 14:45:55 +02:00
#include "TTNProvisioning.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-10-27 14:45:55 +02:00
static TTNProvisioning provisioning;
2018-07-15 22:11:11 +02:00
TheThingsNetwork::TheThingsNetwork()
2018-10-27 14:45:55 +02:00
: messageCallback(nullptr)
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
2018-10-27 14:45:55 +02:00
ASSERT(ttnInstance == nullptr);
2018-07-15 22:11:11 +02:00
ttnInstance = this;
2018-10-27 23:55:36 +02:00
ttn_hal.initCriticalSection();
2018-07-15 22:11:11 +02:00
}
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)
{
2019-10-06 21:49:25 +02:00
ttn_hal.configurePins(spi_host, nss, rxtx, rst, dio0, dio1);
os_init_ex(NULL);
2018-07-15 22:11:11 +02:00
reset();
2018-07-19 21:19:32 +02:00
resultQueue = xQueueCreate(12, sizeof(int));
2018-10-27 14:45:55 +02:00
ASSERT(resultQueue != nullptr);
2018-10-27 23:55:36 +02:00
ttn_hal.startBackgroundTask();
2018-07-15 22:11:11 +02:00
}
void TheThingsNetwork::reset()
{
2018-10-27 23:55:36 +02:00
ttn_hal.enterCriticalSection();
2018-07-15 22:11:11 +02:00
LMIC_reset();
2018-10-27 23:55:36 +02:00
ttn_hal.leaveCriticalSection();
2018-07-15 22:11:11 +02:00
}
bool TheThingsNetwork::provision(const char *devEui, const char *appEui, const char *appKey)
2018-07-15 22:11:11 +02:00
{
2018-10-27 14:45:55 +02:00
if (!provisioning.decodeKeys(devEui, appEui, appKey))
2018-07-20 21:19:53 +02:00
return false;
2018-10-27 14:45:55 +02:00
return provisioning.saveKeys();
2018-07-15 22:11:11 +02:00
}
2018-09-17 22:50:15 +02:00
bool TheThingsNetwork::provisionWithMAC(const char *appEui, const char *appKey)
{
2018-10-27 14:45:55 +02:00
if (!provisioning.fromMAC(appEui, appKey))
2018-09-17 22:50:15 +02:00
return false;
2018-10-27 14:45:55 +02:00
return provisioning.saveKeys();
2018-09-17 22:50:15 +02:00
}
void TheThingsNetwork::startProvisioningTask()
2018-07-15 22:11:11 +02:00
{
#if defined(TTN_HAS_AT_COMMANDS)
2018-10-27 14:45:55 +02:00
provisioning.startTask();
#else
ESP_LOGE(TAG, "AT commands are disabled. Change the configuration using 'make menuconfig'");
ASSERT(0);
esp_restart();
#endif
2018-07-15 22:11:11 +02:00
}
void TheThingsNetwork::waitForProvisioning()
{
#if defined(TTN_HAS_AT_COMMANDS)
if (isProvisioned())
{
ESP_LOGI(TAG, "Device is already provisioned");
return;
}
2018-10-27 14:45:55 +02:00
while (!provisioning.haveKeys())
vTaskDelay(1000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Device successfully provisioned");
#else
ESP_LOGE(TAG, "AT commands are disabled. Change the configuration using 'make menuconfig'");
ASSERT(0);
esp_restart();
#endif
}
bool TheThingsNetwork::join(const char *devEui, const char *appEui, const char *appKey)
2018-07-15 22:11:11 +02:00
{
2018-10-27 14:45:55 +02:00
if (!provisioning.decodeKeys(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
{
2018-10-27 14:45:55 +02:00
if (!provisioning.haveKeys())
2018-07-20 21:19:53 +02:00
{
2018-10-27 14:45:55 +02:00
if (!provisioning.restoreKeys(false))
2018-07-20 21:19:53 +02:00
return false;
}
return joinCore();
}
bool TheThingsNetwork::joinCore()
{
2018-10-27 14:45:55 +02:00
if (!provisioning.haveKeys())
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-10-27 23:55:36 +02:00
ttn_hal.enterCriticalSection();
2018-07-19 21:19:32 +02:00
clientAction = eActionJoining;
2018-07-15 22:11:11 +02:00
LMIC_startJoining();
2018-10-27 23:55:36 +02:00
ttn_hal.wakeUp();
ttn_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
{
2018-10-27 23:55:36 +02:00
ttn_hal.enterCriticalSection();
2018-07-15 22:11:11 +02:00
if (LMIC.opmode & OP_TXRXPEND)
{
2018-10-27 23:55:36 +02:00
ttn_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);
2018-10-27 23:55:36 +02:00
ttn_hal.wakeUp();
ttn_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;
2018-10-27 14:45:55 +02:00
if (hasRecevied && messageCallback != nullptr)
2018-07-19 16:16:40 +02:00
{
port_t port = 0;
if ((LMIC.txrxFlags & TXRX_PORT))
port = LMIC.frame[LMIC.dataBeg - 1];
2018-10-27 14:45:55 +02:00
const uint8_t* msg = nullptr;
2018-07-19 22:04:32 +02:00
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()
{
2018-10-27 14:45:55 +02:00
if (provisioning.haveKeys())
2018-07-20 21:19:53 +02:00
return true;
2018-10-27 14:45:55 +02:00
provisioning.restoreKeys(true);
2018-07-28 22:13:59 +02:00
2018-10-27 14:45:55 +02:00
return provisioning.haveKeys();
2018-07-20 21:19:53 +02:00
}
2019-10-06 21:49:25 +02:00
void TheThingsNetwork::setRSSICal(int8_t rssiCal)
{
ttn_hal.rssiCal = rssiCal;
}
2018-07-15 22:11:11 +02:00
// --- LMIC functions ---
#if CONFIG_LOG_DEFAULT_LEVEL >= 3
2019-10-06 21:49:25 +02:00
static const char *eventNames[] = { LMIC_EVENT_NAME_TABLE__INIT };
2018-07-15 22:11:11 +02:00
#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
}