work1
Dependencies: mbed MAX44009 mbed-os Si7021
Diff: app/AppLora.cpp
- Revision:
- 1:3656b45f17a8
- Parent:
- 0:d3e390d62607
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/AppLora.cpp Wed May 27 12:34:37 2020 +0000 @@ -0,0 +1,377 @@ + +#include <stdio.h> + +#include "lorawan/LoRaWANInterface.h" +#include "lorawan/system/lorawan_data_structures.h" +#include "events/EventQueue.h" + +#include "mbed.h" +#include "AppLora.h" +#include "AppMain.h" +#include "tools.h" + +// Application helpers +//#include "trace_helper.h" +#include "lora_radio_helper.h" +#include "hal/pinmap.h" +#include "PeripheralPins.h" +#include "board/PowerManager.h" + +#include "mbed_trace.h" +#define TRACE_GROUP "lora" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "tools.h" + +#ifdef __cplusplus +} +#endif + + +using namespace events; +EventQueue * AppLora::_queue; +Callback<void(AppLora::EVENT)> AppLora::_lora_callback; +DigitalInOut AppLora::_txco(LORA_TXCO); + +// Max payload size can be LORAMAC_PHY_MAXPAYLOAD. +// This example only communicates with much shorter messages (<30 bytes). +// If longer messages are used, these buffers must be changed accordingly. +uint8_t tx_buffer[30]; +uint8_t rx_buffer[30]; + + +/** + * Maximum number of retries for CONFIRMED messages before giving up + */ +#define CONFIRMED_MSG_RETRY_COUNTER 3 + +/** + * Constructing Mbed LoRaWANInterface and passing it down the radio object. + */ +static LoRaWANInterface lorawan(radio); + +/** + * Application specific callbacks + */ +lorawan_app_callbacks_t AppLora::_callbacks; + +void AppLora::_pin_active_mode(void){ + + // enable MOSI pin + pinmap_pinout(LORA_SPI_MOSI, PinMap_SPI_MOSI); + pinmap_pinout(LORA_SPI_MISO, PinMap_SPI_MISO); + pinmap_pinout(LORA_SPI_SCLK, PinMap_SPI_SCLK); + + // enable high precision oscillator (around 500uA) + _txco.mode(PullNone); + _txco = 1; + _txco.output(); +} + +void AppLora::_pin_lowpower_mode(void){ + DigitalIn lora_spi_miso(LORA_SPI_MISO); + DigitalIn lora_spi_mosi(LORA_SPI_MOSI); + + // That was a big mistake that consume 30µA + // It must be corrected on tag + //DigitalIn lora_spi_cs(SPI_MOSI); + //lora_spi_cs.mode(PullNone); + + lora_spi_miso.mode(PullNone); + lora_spi_mosi.mode(PullNone); +#if 0 + GPIO_InitTypeDef GPIO_InitStruct; + + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + + // for whatever reason the mosi pin draw approximatly 300uA. + // So it need to be disabled when loRa is not used + // disable LORA_MOSI_SPI + GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7 /* GPIO_PIN_7 | | GPIO_PIN_15*/; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_3; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + +#endif + + // disable high precision oscillator + _txco = 0; + _txco.input(); +} + +void AppLora::_enter_lowpower_mode(void){ + _pin_lowpower_mode(); + PowerManager *pm= PowerManager::get_instance(); + pm->sleep_mode(); +} + +void AppLora::_enter_active_mode(void){ + PowerManager *pm= PowerManager::get_instance(); + pm->run_mode(); + _pin_active_mode(); +} + +void AppLora::initialize(EventQueue *queue) +{ + _queue = queue; + + _enter_active_mode(); + + tr_debug("setting voltage to 3V"); + // setup tracing + //setup_trace(); + + // Initialize LoRaWAN stack + if (lorawan.initialize(_queue) != LORAWAN_STATUS_OK) { + tr_err("LoRa initialization failed!"); + //return -1; + } + + tr_info("mbed LoRaWANStack initialized"); + + // prepare application callbacks + _callbacks.events = mbed::callback(AppLora::_lora_event_handler); + lorawan.add_app_callbacks(&_callbacks); + + // Set number of retries in case of CONFIRMED messages + if (lorawan.set_confirmed_msg_retries(CONFIRMED_MSG_RETRY_COUNTER) + != LORAWAN_STATUS_OK) { + tr_err("set_confirmed_msg_retries failed!"); + //return -1; + } + + tr_debug("confirmed message retries : %d", CONFIRMED_MSG_RETRY_COUNTER); + + // Enable adaptive data rate + /* + if (lorawan.enable_adaptive_datarate() != LORAWAN_STATUS_OK) { + PRINT("\r\n enable_adaptive_datarate failed! \r\n"); + //return -1; + } + */ + + //PRINT("\r\n Adaptive data rate (ADR) - Enabled \r\n"); + + _enter_lowpower_mode(); + +} +u32 AppLora::get_random(void){ + u32 rand; + _enter_active_mode(); + rand = radio.random(); + _enter_lowpower_mode(); + return rand; + +} + +u8 AppLora::get_next_transmission_max_size(void){ + /* + * find a better way to get the max payload size + */ +#if 0 + lorawan_tx_metadata meta; + lorawan.get_tx_metadata(meta); + return meta.max_payload; +#else + return 51; // minimum payload size +#endif + + +} + +void AppLora::connect(void){ + lorawan_status_t retcode; + _enter_active_mode(); + retcode = lorawan.connect(); + + if (retcode == LORAWAN_STATUS_OK || + retcode == LORAWAN_STATUS_CONNECT_IN_PROGRESS) { + } else { + tr_err("connection error, code = %d", retcode); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_CONNECTION_ERROR); + //return -1; + return; + } + + tr_info("connection - in progress..."); +} + +void AppLora::disconnect(void){ + lorawan.cancel_sending(); + lorawan.disconnect(); +} + +/** + * Sends a message to the Network Server + */ +s16 AppLora::send_message(u8 *data, u8 data_size, u8 app_port, bool confirmed) +{ + s16 retcode; + static u8 would_block_error_count = 0; + + int flags = MSG_UNCONFIRMED_FLAG; + tr_info("sending message"); + tr_debug("\t confirmed: %d", confirmed); + tr_debug("\t port: 0x%02x", app_port); + tr_debug("\t size: %d", data_size); + tr_info("\t data: "); + tools_print_to_hex(data, data_size); + if(confirmed){ + flags = MSG_CONFIRMED_FLAG; + } + _enter_active_mode(); + + retcode = lorawan.send(app_port, data, data_size, flags); + if(retcode < 0){ + /* + * LoRa error code are between -1000 and -1024 + * -(retcode+1000) convert the error in a number between + * 1 and 24 + * + * Then the value 1 is saved @ the virtual address va between 1 and 24 + */ + tr_warn("\t error : %d", retcode); + } + + if(retcode == LORAWAN_STATUS_WOULD_BLOCK){ + ++would_block_error_count; + // Reset only if this error appear three time in a row + // Because in some case this error can appear during the join and this + // is the expected behaviour + if(would_block_error_count > 2){ + NVIC_SystemReset(); + } + } + else if(retcode >= 0){ + would_block_error_count = 0; + } + + return retcode; + +} + +/** + * Receive a message from the Network Server + */ +s16 AppLora::get_rx_message(u8 *data, u16 data_size, u8 &app_port) +{ + s16 received_size; + int flags; + received_size = lorawan.receive(data, data_size, app_port, flags); + + if (received_size < 0) { + tr_err("receive() - Error code %d", received_size); + // return; + } + else{ + tr_info("received message"); + tr_debug("\t flags: %d", flags); + tr_debug("\t port: %d", app_port); + tr_debug("\t max size: %d", data_size); + tr_debug("\t received size: %d", received_size); + tr_info("\t data: "); + tools_print_to_hex(data, received_size); + } + return received_size; + +} + +void AppLora::_send_empty_uplink(void){ + int retcode; + _enter_active_mode(); + //wait(0.05); + wait_us(50000); + // we could add more information in this frame + retcode = lorawan.send(1, NULL, 0, MSG_CONFIRMED_FLAG); + if (retcode < 0) { + tr_err("uplink send() - Error code %d", retcode); + _enter_lowpower_mode(); + + // return; + } + //_enter_lowpower_mode(); + +} + +void AppLora::set_lora_callback(Callback<void(AppLora::EVENT)> lora_callback){ + _lora_callback = lora_callback; +} + +void AppLora::_call_callback(AppLora::EVENT lora_event){ + if(_lora_callback){ + _lora_callback(lora_event); + } +} +/** + * Event handler + */ +void AppLora::_lora_event_handler(lorawan_event_t event) +{ + switch (event) { + case CONNECTED: + tr_info("connection - successful"); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_CONNECTED); + + break; + case DISCONNECTED: + //AppLora::_queue->break_dispatch(); + tr_info("disconnected successfully"); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_DISCONNECTED); + break; + case TX_DONE: + tr_info("message sent to network server"); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_TX_DONE); + break; + case UPLINK_REQUIRED: + // Uplink are requested when the pending bit is set + // or when more downlink messages are waiting + // ACK seems to be handled directly by the stack + tr_info("LoRaStack requesting uplink"); + _send_empty_uplink(); + _call_callback(AppLora::EVENT_UPLINK_REQUIERED); + break; + case TX_TIMEOUT: + case TX_ERROR: + case TX_CRYPTO_ERROR: + case TX_SCHEDULING_ERROR: + tr_err("transmission error - event code = %d", event); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_TX_ERROR); + break; + case RX_DONE: + tr_info("received message from network server"); + AppMain::incoming_lora_message_callback(); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_RX_DONE); + //receive_message(); + break; + case RX_TIMEOUT: + case RX_ERROR: + tr_err("error in reception - code = %d", event); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_RX_ERROR); + break; + case JOIN_FAILURE: + tr_err("OTAA failed - check keys"); + _enter_lowpower_mode(); + _call_callback(AppLora::EVENT_JOIN_FAILURE); + break; + default: + MBED_ASSERT("Unknown Event"); + _enter_lowpower_mode(); + } +} + +// EOF + +