Receive downlink messages

This commit is contained in:
Manuel Bleichenbacher 2018-07-19 16:16:40 +02:00
parent 6378c17e39
commit b8221a614e
8 changed files with 161 additions and 15 deletions

View File

@ -1,4 +1,2 @@
CFLAGS += -Wno-error=maybe-uninitialized -Wno-error=unused-value
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_SRCDIRS := src COMPONENT_SRCDIRS := src

View File

@ -0,0 +1,3 @@
PROJECT_NAME := hello_world
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1 @@
../../../../ttn-esp32/

View File

View File

@ -0,0 +1,87 @@
/*******************************************************************************
* Copyright (c) 2018 Manuel Bleichenbacher
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Sample program showing how to send a test message every 30 second.
*******************************************************************************/
#include "freertos/FreeRTOS.h"
#include "esp_event.h"
#include "TheThingsNetwork.h"
// NOTE:
// The LoRaWAN frequency and the radio chip must be configured by running 'make menuconfig'.
// Go to Components / The Things Network, select the appropriate values and save.
// Copy the below hex string from the "Device EUI" field
// on your device's overview page in the TTN console.
const char *devEui = "????????????????";;
// Copy the below two lines from bottom of the same page
const char *appEui = "????????????????";
const char *appKey = "????????????????????????????????";
static TheThingsNetwork ttn;
const unsigned TX_INTERVAL = 30;
static uint8_t msgData[] = "Hello, world";
void sendMessages(void* pvParameter)
{
while (1) {
printf("Sending message...\n");
ttn_response_t res = ttn.sendBytes(msgData, sizeof(msgData) - 1);
if (res == TTN_SUCCESSFUL_TRANSMISSION)
printf("Message sent.\n");
else if (res == TTN_SUCCESSFUL_RECEIVE)
printf("Message sent and message received\n");
else
printf("Message transmission failed.\n");
vTaskDelay(TX_INTERVAL * 1000 / portTICK_PERIOD_MS);
}
}
void messageReceived(const uint8_t* message, size_t length, port_t port)
{
printf("Message of %d bytes received on port %d:", length, port);
for (int i = 0; i < length; i++)
printf(" %02x", message[i]);
printf("\n");
}
extern "C" void app_main(void)
{
gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
// Initialize SPI bus
spi_bus_config_t spi_bus_config;
spi_bus_config.miso_io_num = 19;
spi_bus_config.mosi_io_num = 27;
spi_bus_config.sclk_io_num = 5;
spi_bus_config.quadwp_io_num = -1;
spi_bus_config.quadhd_io_num = -1;
spi_bus_config.max_transfer_sz = 0;
esp_err_t ret = spi_bus_initialize(HSPI_HOST, &spi_bus_config, 1);
assert(ret == ESP_OK);
ttn.configurePins(HSPI_HOST, 18, TTN_NOT_CONNECTED, 14, 26, 33);
ttn.provision(devEui, appEui, appKey);
ttn.onMessage(messageReceived);
printf("Joining...\n");
ttn.join();
printf("Joined.\n");
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, NULL);
}

View File

@ -15,9 +15,6 @@
#include <stdint.h> #include <stdint.h>
#include "driver/spi_master.h" #include "driver/spi_master.h"
#define TTN_DEFAULT_SF 7
#define TTN_DEFAULT_FSB 2
/** /**
* @brief Constant for indicating that a pin is not connected * @brief Constant for indicating that a pin is not connected
*/ */
@ -37,6 +34,14 @@ enum ttn_response_t
TTN_SUCCESSFUL_RECEIVE = 2 TTN_SUCCESSFUL_RECEIVE = 2
}; };
/**
* @brief Callback for recieved messages
*
* @param payload pointer to the received bytes
* @param length number of received bytes
* @param port port the message was received on
*/
typedef void (*message_cb_t)(const uint8_t* payload, size_t length, port_t port);
/** /**
* @brief TTN device * @brief TTN device
@ -114,11 +119,35 @@ public:
*/ */
bool join(); bool join();
/**
* @brief Send a message
*
* @param payload bytes to be sent
* @param length number of bytes to be sent
* @param port port (default to 1)
* @param confirm flag indicating if a confirmation should be requested. Default to 'false'
* @return TTTN_SUCCESSFUL_TRANSMISSION Successful transmission
* @return TTTN_SUCCESSFUL_RECEIVE Successful transmission and a message has been received
* @return TTN_ERROR_SEND_COMMAND_FAILED Transmission failed
* @return TTTN_ERROR_UNEXPECTED_RESPONSE Unexpected response
*/
ttn_response_t sendBytes(const uint8_t *payload, size_t length, port_t port = 1, bool confirm = false); ttn_response_t sendBytes(const uint8_t *payload, size_t length, port_t port = 1, bool confirm = false);
/**
* @brief Set the function to be called when a message is received
*
* When a message is received, the specified function is called. The
* message, its length and the port is was received on are provided as
* parameters. The values are only valid during the duration of the
* callback. So they must be immediately processed or copied.
*
* @param callback the callback function
*/
void onMessage(message_cb_t callback);
private: private:
uint8_t spreadingFactor = TTN_DEFAULT_SF; message_cb_t messageCallback;
uint8_t frequencySubband = TTN_DEFAULT_FSB;
bool decodeKeys(const char *devEui, const char *appEui, const char *appKey); bool decodeKeys(const char *devEui, const char *appEui, const char *appKey);
}; };

View File

@ -112,12 +112,16 @@ bool TheThingsNetwork::join(const char *devEui, const char *appEui, const char *
bool TheThingsNetwork::join() bool TheThingsNetwork::join()
{ {
int result = 0;
// empty queue
while (xQueueReceive(result_queue, &result, 0) == pdTRUE)
;
hal_enterCriticalSection(); hal_enterCriticalSection();
LMIC_startJoining(); LMIC_startJoining();
hal_wakeUp(); hal_wakeUp();
hal_leaveCriticalSection(); hal_leaveCriticalSection();
int result = 0;
while (true) while (true)
{ {
xQueueReceive(result_queue, &result, portMAX_DELAY); xQueueReceive(result_queue, &result, portMAX_DELAY);
@ -130,6 +134,11 @@ bool TheThingsNetwork::join()
ttn_response_t TheThingsNetwork::sendBytes(const uint8_t *payload, size_t length, port_t port, bool confirm) ttn_response_t TheThingsNetwork::sendBytes(const uint8_t *payload, size_t length, port_t port, bool confirm)
{ {
int result = 0;
// empty queue
while (xQueueReceive(result_queue, &result, 0) == pdTRUE)
;
hal_enterCriticalSection(); hal_enterCriticalSection();
if (LMIC.opmode & OP_TXRXPEND) if (LMIC.opmode & OP_TXRXPEND)
{ {
@ -141,9 +150,28 @@ ttn_response_t TheThingsNetwork::sendBytes(const uint8_t *payload, size_t length
hal_wakeUp(); hal_wakeUp();
hal_leaveCriticalSection(); hal_leaveCriticalSection();
int result = 0;
xQueueReceive(result_queue, &result, portMAX_DELAY); xQueueReceive(result_queue, &result, portMAX_DELAY);
return result == EV_TXCOMPLETE ? TTN_SUCCESSFUL_TRANSMISSION : TTN_ERROR_SEND_COMMAND_FAILED;
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];
messageCallback(LMIC.frame + LMIC.dataBeg, LMIC.dataLen, port);
}
return hasRecevied ? TTN_SUCCESSFUL_RECEIVE : TTN_SUCCESSFUL_TRANSMISSION;
}
return TTN_ERROR_SEND_COMMAND_FAILED;
}
void TheThingsNetwork::onMessage(message_cb_t callback)
{
messageCallback = callback;
} }
@ -190,9 +218,7 @@ void onEvent (ev_t ev) {
if (ev == EV_TXCOMPLETE) { if (ev == EV_TXCOMPLETE) {
if (LMIC.txrxFlags & TXRX_ACK) if (LMIC.txrxFlags & TXRX_ACK)
ESP_LOGI(TAG, "Received ack\n"); ESP_LOGI(TAG, "ACK received\n");
if (LMIC.dataLen)
ESP_LOGI(TAG, "Received %d bytes of payload\n", LMIC.dataLen);
} }
int result = ev; int result = ev;

View File

@ -25,6 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "rom/ets_sys.h"
#include "lmic.h" #include "lmic.h"
// ---------------------------------------- // ----------------------------------------
@ -500,13 +501,14 @@ static void txlora () {
// select LoRa modem (from sleep mode) // select LoRa modem (from sleep mode)
//writeReg(RegOpMode, OPMODE_LORA); //writeReg(RegOpMode, OPMODE_LORA);
opmodeLora(); opmodeLora();
// can take a moment to change; so try five times // can take a moment to change; so try ten times
u1_t reg; u1_t reg;
for (int i = 0; i < 5; i++) for (int i = 0; i < 10; i++)
{ {
reg = readReg(RegOpMode); reg = readReg(RegOpMode);
if ((reg & OPMODE_LORA) != 0) if ((reg & OPMODE_LORA) != 0)
break; break;
ets_delay_us(100);
} }
ASSERT((reg & OPMODE_LORA) != 0); ASSERT((reg & OPMODE_LORA) != 0);