work1

Dependencies:   mbed MAX44009 mbed-os Si7021

app/AppLora.cpp

Committer:
danaeb
Date:
2020-05-28
Revision:
2:25f27478fdf9
Parent:
1:3656b45f17a8

File content as of revision 2:25f27478fdf9:


#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