Multitech xDot Utils

MultitechDot.cpp

Committer:
Lucian Corduneanu
Date:
2018-05-21
Revision:
4:db99b2a7d062
Parent:
3:7fa5603c10dc
Child:
6:febbdd0d0e55

File content as of revision 4:db99b2a7d062:

#include "ChannelPlan.h"
#include "plans/ChannelPlan_EU868.h"
#include "MultitechDot.h"

MultitechDot *MultitechDot::get_instance(struct dot_config *config) {
    using namespace lora;

    ChannelPlan *plan = new ChannelPlan_EU868();
    MultitechDot *dot = (MultitechDot *) mDot::getInstance(plan);

    dot->config(config);

    return dot;
}

void MultitechDot::config(struct dot_config *config) {
    _config = config;

    this->setLogLevel(config->log_level);
    this->setDisableDutyCycle(config->disable_duty_cycle);

    logInfo("Start configuring the device");
    if (!this->getStandbyFlag()) {
        logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);

        // start from a well-known state
        logInfo("defaulting Dot configuration");
        this->resetConfig();
        this->resetNetworkSession();

        // update configuration if necessary
        if (this->getJoinMode() != this->MANUAL) {
            logInfo("changing network join mode to MANUAL");
            if (this->setJoinMode(this->MANUAL) != this->MDOT_OK) {
                logError("failed to set network join mode to MANUAL");
            }
        }
        // in MANUAL join mode there is no join request/response transaction
        // as long as the Dot is configured correctly and provisioned correctly on the gateway, it should be able to communicate
        // network address - 4 bytes (00000001 - FFFFFFFE)
        // network session key - 16 bytes
        // data session key - 16 bytes
        // to provision your Dot with a Conduit gateway, follow the following steps
        //   * ssh into the Conduit
        //   * provision the Dot using the lora-query application: http://www.multitech.net/developer/software/lora/lora-network-server/
        //      lora-query -a 01020304 A 0102030401020304 <your Dot's device ID> 01020304010203040102030401020304 01020304010203040102030401020304
        //   * if you change the network address, network session key, or data session key, make sure you update them on the gateway
        // to provision your Dot with a 3rd party gateway, see the gateway or network provider documentation
        this->update_manual_config(config);

        // enable or disable Adaptive Data Rate
        this->setAdr(config->adr);

        // save changes to configuration
        logInfo("saving configuration");
        if (!this->saveConfig()) {
            logError("failed to save configuration");
        }

        // display configuration
        this->display_config();
    } else {
        // restore the saved session if the dot woke from deepsleep mode
        // useful to use with deepsleep because session info is otherwise lost when the dot enters deepsleep
        logInfo("restoring network session from NVM");
        this->restoreNetworkSession();
    }
}

struct dot_config *MultitechDot::get_config() {
    return _config;
}


void MultitechDot::update_manual_config(struct dot_config *config) {
    BaseDot::update_manual_config(
            config->network_address,
            config->network_session_key,
            config->data_session_key,
            config->frequency_sub_band,
            config->public_network,
            config->ack
    );
}

void MultitechDot::sleep_wake_rtc_or_interrupt(uint32_t delay_s, bool deepsleep) {
    if (deepsleep) {
        // for xDot, WAKE pin (connected to S2 on xDot-DK) is the only pin that can wake the processor from deepsleep
        // it is automatically configured when INTERRUPT or RTC_ALARM_OR_INTERRUPT is the wakeup source and deepsleep is true in the this->sleep call
    } else {
        // configure WAKE pin (connected to S2 on xDot-DK) as the pin that will wake the xDot from low power modes
        // other pins can be configured instead: GPIO0-3 or UART_RX
        this->setWakePin(WAKE);
    }

    logInfo("%s sleeping %lus or until interrupt on %s pin", deepsleep ? "deep" : "", delay_s,
            deepsleep ? "WAKE" : this->pinName2Str(this->getWakePin()).c_str());

    logInfo("application will %s after waking up", deepsleep ? "execute from beginning" : "resume");

    // lowest current consumption in sleep mode can only be achieved by configuring IOs as analog inputs with no pull resistors
    // the library handles all internal IOs automatically, but the external IOs are the application's responsibility
    // certain IOs may require internal pullup or pulldown resistors because leaving them floating would cause extra current consumption
    // for xDot: UART_*, I2C_*, SPI_*, GPIO*, WAKE
    // for mDot: XBEE_*, USBTX, USBRX, PB_0, PB_1
    // steps are:
    //   * save IO configuration
    //   * configure IOs to reduce current consumption
    //   * sleep
    //   * restore IO configuration
    if (!deepsleep) {
        // save the GPIO state.
        this->sleep_save_io();

        // configure GPIOs for lowest current
        this->sleep_configure_io();
    }

    // go to sleep/deepsleep and wake using the RTC alarm after delay_s seconds or rising edge of configured wake pin (only the WAKE pin in deepsleep)
    // whichever comes first will wake the xDot
    this->sleep(delay_s, this->RTC_ALARM_OR_INTERRUPT, deepsleep);

    if (!deepsleep) {
        // restore the GPIO state.
        this->sleep_restore_io();
        this->sleep_reset_hsi();
    }
}

void MultitechDot::sleep_reset_hsi() {
    // Enable the HSI (to clock the ADC)
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);
}