More comments

This commit is contained in:
Manuel Bl 2019-10-12 00:02:31 +02:00
parent a8fd68ca5e
commit 43080636bc
4 changed files with 103 additions and 53 deletions

View File

@ -21,9 +21,15 @@
#include "TTNLogging.h" #include "TTNLogging.h"
#define NUM_RINGBUF_MSG 50
static const char* const TAG = "lmic"; static const char* const TAG = "lmic";
static TTNLogging ttnLog; static TTNLogging ttnLog;
/**
* @brief Message structure used in ring buffer
*
* The structure is sent from the LMIC task to the logging task.
*/
struct TTNLogMessage { struct TTNLogMessage {
const char* message; const char* message;
uint32_t datum; uint32_t datum;
@ -43,6 +49,7 @@ struct TTNLogMessage {
u1_t saveIrqFlags; u1_t saveIrqFlags;
}; };
// Constants for formatting LORA values
static const char* const SF_NAMES[] = { "FSK", "SF7", "SF8", "SF9", "SF10", "SF11", "SF12", "SFrfu" }; static const char* const SF_NAMES[] = { "FSK", "SF7", "SF8", "SF9", "SF10", "SF11", "SF12", "SFrfu" };
static const char* const BW_NAMES[] = { "BW125", "BW250", "BW500", "BWrfu" }; static const char* const BW_NAMES[] = { "BW125", "BW250", "BW500", "BWrfu" };
static const char* const CR_NAMES[] = { "CR 4/5", "CR 4/6", "CR 4/7", "CR 4/8" }; static const char* const CR_NAMES[] = { "CR 4/5", "CR 4/6", "CR 4/7", "CR 4/8" };
@ -54,15 +61,17 @@ static void printEvtJoinFailed(TTNLogMessage* log);
static void bin2hex(const uint8_t* bin, unsigned len, char* buf, char sep = 0); static void bin2hex(const uint8_t* bin, unsigned len, char* buf, char sep = 0);
// Create singleton instance
TTNLogging* TTNLogging::initInstance() TTNLogging* TTNLogging::initInstance()
{ {
ttnLog.init(); ttnLog.init();
return &ttnLog; return &ttnLog;
} }
// Initialize logging
void TTNLogging::init() void TTNLogging::init()
{ {
ringBuffer = xRingbufferCreate(50 * sizeof(TTNLogMessage), RINGBUF_TYPE_NOSPLIT); ringBuffer = xRingbufferCreate(NUM_RINGBUF_MSG * sizeof(TTNLogMessage), RINGBUF_TYPE_NOSPLIT);
if (ringBuffer == nullptr) { if (ringBuffer == nullptr) {
ESP_LOGE(TAG, "Failed to create ring buffer"); ESP_LOGE(TAG, "Failed to create ring buffer");
ASSERT(0); ASSERT(0);
@ -72,6 +81,7 @@ void TTNLogging::init()
hal_set_failure_handler(logFatal); hal_set_failure_handler(logFatal);
} }
// Record a logging event for later output
void TTNLogging::logEvent(int event, const char* message, uint32_t datum) void TTNLogging::logEvent(int event, const char* message, uint32_t datum)
{ {
if (ringBuffer == nullptr) if (ringBuffer == nullptr)
@ -100,20 +110,22 @@ void TTNLogging::logEvent(int event, const char* message, uint32_t datum)
xRingbufferSend(ringBuffer, &log, sizeof(log), 0); xRingbufferSend(ringBuffer, &log, sizeof(log), 0);
} }
// record a fatal event (failed assert) for later output
void TTNLogging::logFatal(const char* file, uint16_t line) void TTNLogging::logFatal(const char* file, uint16_t line)
{ {
ttnLog.logEvent(-3, file, line); ttnLog.logEvent(-3, file, line);
} }
// Record an informational message for later output
// The message must not be freed.
extern "C" void LMICOS_logEvent(const char *pMessage) extern "C" void LMICOS_logEvent(const char *pMessage)
{ {
ttnLog.logEvent(-1, pMessage, 0); ttnLog.logEvent(-1, pMessage, 0);
} }
// Record an information message with an integer value for later output
// The message must not be freed.
extern "C" void LMICOS_logEventUint32(const char *pMessage, uint32_t datum) extern "C" void LMICOS_logEventUint32(const char *pMessage, uint32_t datum)
{ {
ttnLog.logEvent(-2, pMessage, datum); ttnLog.logEvent(-2, pMessage, datum);
@ -123,6 +135,7 @@ extern "C" void LMICOS_logEventUint32(const char *pMessage, uint32_t datum)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Log output // Log output
// Tasks that receiveds the recorded messages, formats and outputs them.
void TTNLogging::loggingTask(void* param) void TTNLogging::loggingTask(void* param)
{ {
RingbufHandle_t ringBuffer = (RingbufHandle_t)param; RingbufHandle_t ringBuffer = (RingbufHandle_t)param;
@ -140,6 +153,7 @@ void TTNLogging::loggingTask(void* param)
} }
// Format and output a log message
void printMessage(TTNLogMessage* log) void printMessage(TTNLogMessage* log)
{ {
switch((int)log->event) switch((int)log->event)
@ -173,6 +187,7 @@ void printMessage(TTNLogMessage* log)
} }
// Format and output the detail of a successful network join
void printEvtJoined(TTNLogMessage* log) void printEvtJoined(TTNLogMessage* log)
{ {
ESP_LOGI(TAG, "%s: ch=%d", log->message, (unsigned)log->txChnl); ESP_LOGI(TAG, "%s: ch=%d", log->message, (unsigned)log->txChnl);
@ -196,6 +211,7 @@ void printEvtJoined(TTNLogMessage* log)
} }
// Format and output the detail of a failed network join
void printEvtJoinFailed(TTNLogMessage* log) void printEvtJoinFailed(TTNLogMessage* log)
{ {
rps_t rps = log->rps; rps_t rps = log->rps;
@ -215,6 +231,14 @@ void printEvtJoinFailed(TTNLogMessage* log)
static const char* HEX_DIGITS = "0123456789ABCDEF"; static const char* HEX_DIGITS = "0123456789ABCDEF";
/**
* @brief Convert binary data to hexadecimal representation.
*
* @param bin start of binary data
* @param len length of binary data (in bytes)
* @param buf buffer for hexadecimal result
* @param sep separator used between bytes (or 0 for none)
*/
void bin2hex(const uint8_t* bin, unsigned len, char* buf, char sep) void bin2hex(const uint8_t* bin, unsigned len, char* buf, char sep)
{ {
int tgt = 0; int tgt = 0;

View File

@ -20,6 +20,22 @@
#include <freertos/ringbuf.h> #include <freertos/ringbuf.h>
/**
* @brief Logging class.
*
* Logs internal information from LMIC in an asynchrnous fashion in order
* not to distrub the sensitive LORA timing.
*
* A ring buffer and a separate logging task is ued. The LMIC core records
* relevant values from the current LORA settings and writes them to a ring
* buffer. The logging tasks receives the message and the values, formats
* them and outputs them via the regular ESP-IDF logging mechanism.
*
* In order to activate the detailed logging, set the macro
* `LMIC_ENABLE_event_logging` to 1.
*
* This class is not to be used directly.
*/
class TTNLogging { class TTNLogging {
public: public:
static TTNLogging* initInstance(); static TTNLogging* initInstance();

View File

@ -286,7 +286,7 @@ void TTNProvisioning::processLine()
ttn_hal.enterCriticalSection(); ttn_hal.enterCriticalSection();
LMIC_reset(); LMIC_reset();
ttn_hal.leaveCriticalSection(); ttn_hal.leaveCriticalSection();
onEvent(EV_RESET); LMIC.client.eventCb(LMIC.client.eventUserData, EV_RESET);
} }
uart_write_bytes(UART_NUM, is_ok ? "OK\r\n" : "ERROR\r\n", is_ok ? 4 : 7); uart_write_bytes(UART_NUM, is_ok ? "OK\r\n" : "ERROR\r\n", is_ok ? 4 : 7);

View File

@ -20,36 +20,45 @@
#include "TTNLogging.h" #include "TTNLogging.h"
enum TTNClientAction /**
* @brief Reason the user code is waiting
*/
enum TTNWaitingReason
{ {
eActionUnrelated, eWaitingNone,
eActionJoining, eWaitingForJoin,
eActionTransmission eWaitingForTransmission
}; };
/**
* @brief Event type
*/
enum TTNEvent { enum TTNEvent {
EvtNone, eEvtNone,
EvtJoinCompleted, eEvtJoinCompleted,
EvtJoinFailed, eEvtJoinFailed,
EvtMessageReceived, eEvtMessageReceived,
EvtTransmissionCompleted, eEvtTransmissionCompleted,
EvtTransmissionFailed eEvtTransmissionFailed
}; };
struct TTNResult { /**
TTNResult(TTNEvent ev = EvtNone): event(ev) { } * @brief Event message sent from LMIC task to waiting client task
*/
struct TTNLmicEvent {
TTNLmicEvent(TTNEvent ev = eEvtNone): event(ev) { }
TTNEvent event; TTNEvent event;
uint8_t port; uint8_t port;
const uint8_t *message; const uint8_t* message;
size_t messageSize; size_t messageSize;
}; };
static const char *TAG = "ttn"; static const char *TAG = "ttn";
static TheThingsNetwork* ttnInstance; static TheThingsNetwork* ttnInstance;
static QueueHandle_t resultQueue; static QueueHandle_t lmicEventQueue = nullptr;
static TTNClientAction clientAction = eActionUnrelated; static TTNWaitingReason waitingReason = eWaitingNone;
static TTNProvisioning provisioning; static TTNProvisioning provisioning;
#if LMIC_ENABLE_event_logging #if LMIC_ENABLE_event_logging
static TTNLogging* logging; static TTNLogging* logging;
@ -66,7 +75,6 @@ TheThingsNetwork::TheThingsNetwork()
#if defined(TTN_IS_DISABLED) #if defined(TTN_IS_DISABLED)
ESP_LOGE(TAG, "TTN is disabled. Configure a frequency plan using 'make menuconfig'"); ESP_LOGE(TAG, "TTN is disabled. Configure a frequency plan using 'make menuconfig'");
ASSERT(0); ASSERT(0);
esp_restart();
#endif #endif
ASSERT(ttnInstance == nullptr); ASSERT(ttnInstance == nullptr);
@ -93,8 +101,8 @@ void TheThingsNetwork::configurePins(spi_host_device_t spi_host, uint8_t nss, ui
os_init_ex(nullptr); os_init_ex(nullptr);
reset(); reset();
resultQueue = xQueueCreate(4, sizeof(TTNResult)); lmicEventQueue = xQueueCreate(4, sizeof(TTNLmicEvent));
ASSERT(resultQueue != nullptr); ASSERT(lmicEventQueue != nullptr);
ttn_hal.startBackgroundTask(); ttn_hal.startBackgroundTask();
} }
@ -102,6 +110,11 @@ void TheThingsNetwork::reset()
{ {
ttn_hal.enterCriticalSection(); ttn_hal.enterCriticalSection();
LMIC_reset(); LMIC_reset();
waitingReason = eWaitingNone;
if (lmicEventQueue != nullptr)
{
xQueueReset(lmicEventQueue);
}
ttn_hal.leaveCriticalSection(); ttn_hal.leaveCriticalSection();
} }
@ -181,26 +194,26 @@ bool TheThingsNetwork::joinCore()
} }
ttn_hal.enterCriticalSection(); ttn_hal.enterCriticalSection();
clientAction = eActionJoining; waitingReason = eWaitingForJoin;
LMIC_startJoining(); LMIC_startJoining();
ttn_hal.wakeUp(); ttn_hal.wakeUp();
ttn_hal.leaveCriticalSection(); ttn_hal.leaveCriticalSection();
TTNResult result; TTNLmicEvent event;
xQueueReceive(resultQueue, &result, portMAX_DELAY); xQueueReceive(lmicEventQueue, &event, portMAX_DELAY);
return result.event == EvtJoinCompleted; return event.event == eEvtJoinCompleted;
} }
TTNResponseCode TheThingsNetwork::transmitMessage(const uint8_t *payload, size_t length, port_t port, bool confirm) TTNResponseCode TheThingsNetwork::transmitMessage(const uint8_t *payload, size_t length, port_t port, bool confirm)
{ {
ttn_hal.enterCriticalSection(); ttn_hal.enterCriticalSection();
if (LMIC.opmode & OP_TXRXPEND) if (waitingReason != eWaitingNone || (LMIC.opmode & OP_TXRXPEND) != 0)
{ {
ttn_hal.leaveCriticalSection(); ttn_hal.leaveCriticalSection();
return kTTNErrorTransmissionFailed; return kTTNErrorTransmissionFailed;
} }
clientAction = eActionTransmission; waitingReason = eWaitingForTransmission;
LMIC.client.txMessageCb = messageTransmittedCallback; LMIC.client.txMessageCb = messageTransmittedCallback;
LMIC.client.txMessageUserData = nullptr; LMIC.client.txMessageUserData = nullptr;
LMIC_setTxData2(port, (xref2u1_t)payload, length, confirm); LMIC_setTxData2(port, (xref2u1_t)payload, length, confirm);
@ -209,20 +222,20 @@ TTNResponseCode TheThingsNetwork::transmitMessage(const uint8_t *payload, size_t
while (true) while (true)
{ {
TTNResult result; TTNLmicEvent result;
xQueueReceive(resultQueue, &result, portMAX_DELAY); xQueueReceive(lmicEventQueue, &result, portMAX_DELAY);
switch (result.event) switch (result.event)
{ {
case EvtMessageReceived: case eEvtMessageReceived:
if (messageCallback != nullptr) if (messageCallback != nullptr)
messageCallback(result.message, result.messageSize, result.port); messageCallback(result.message, result.messageSize, result.port);
break; break;
case EvtTransmissionCompleted: case eEvtTransmissionCompleted:
return kTTNSuccessfulTransmission; return kTTNSuccessfulTransmission;
case EvtTransmissionFailed: case eEvtTransmissionFailed:
return kTTNErrorTransmissionFailed; return kTTNErrorTransmissionFailed;
default: default:
@ -260,7 +273,7 @@ const char *eventNames[] = { LMIC_EVENT_NAME_TABLE__INIT };
#endif #endif
// Called by LMIC when an LMIC event (join, join failed, reset etc.) occurs
void eventCallback(void* userData, ev_t event) void eventCallback(void* userData, ev_t event)
{ {
#if LMIC_ENABLE_event_logging #if LMIC_ENABLE_event_logging
@ -269,45 +282,42 @@ void eventCallback(void* userData, ev_t event)
ESP_LOGI(TAG, "event %s", eventNames[event]); ESP_LOGI(TAG, "event %s", eventNames[event]);
#endif #endif
if (event == EV_TXCOMPLETE) { TTNEvent ttnEvent = eEvtNone;
if (LMIC.txrxFlags & TXRX_ACK)
ESP_LOGI(TAG, "ACK received\n");
}
TTNEvent ttnEvent = EvtNone; if (waitingReason == eWaitingForJoin)
if (clientAction == eActionJoining)
{ {
if (event == EV_JOINED) if (event == EV_JOINED)
{ {
ttnEvent = EvtJoinCompleted; ttnEvent = eEvtJoinCompleted;
} }
else if (event == EV_REJOIN_FAILED || event == EV_RESET) else if (event == EV_REJOIN_FAILED || event == EV_RESET)
{ {
ttnEvent = EvtJoinFailed; ttnEvent = eEvtJoinFailed;
} }
} }
if (ttnEvent == EvtNone) if (ttnEvent == eEvtNone)
return; return;
TTNResult result(ttnEvent); TTNLmicEvent result(ttnEvent);
clientAction = eActionUnrelated; waitingReason = eWaitingNone;
xQueueSend(resultQueue, &result, 100 / portTICK_PERIOD_MS); xQueueSend(lmicEventQueue, &result, 100 / portTICK_PERIOD_MS);
} }
// Called by LMIC when a message has been received
void messageReceivedCallback(void *userData, uint8_t port, const uint8_t *message, size_t nMessage) void messageReceivedCallback(void *userData, uint8_t port, const uint8_t *message, size_t nMessage)
{ {
TTNResult result(EvtMessageReceived); TTNLmicEvent result(eEvtMessageReceived);
result.port = port; result.port = port;
result.message = message; result.message = message;
result.messageSize = nMessage; result.messageSize = nMessage;
xQueueSend(resultQueue, &result, 100 / portTICK_PERIOD_MS); xQueueSend(lmicEventQueue, &result, 100 / portTICK_PERIOD_MS);
} }
// Called by LMIC when a message has been transmitted (or the transmission failed)
void messageTransmittedCallback(void *userData, int success) void messageTransmittedCallback(void *userData, int success)
{ {
clientAction = eActionUnrelated; waitingReason = eWaitingNone;
TTNResult result(success ? EvtTransmissionCompleted : EvtTransmissionFailed); TTNLmicEvent result(success ? eEvtTransmissionCompleted : eEvtTransmissionFailed);
xQueueSend(resultQueue, &result, 100 / portTICK_PERIOD_MS); xQueueSend(lmicEventQueue, &result, 100 / portTICK_PERIOD_MS);
} }