Example programs for MultiTech Dot devices demonstrating how to use the Dot devices and the Dot libraries for LoRa communication.

Dependencies:   ISL29011

Dependents:   Dot-Examples-delujoc

This project has moved to github

Please see GitHub Dot-Examples

Dot Library Not Included!

Because these example programs can be used for both mDot and xDot devices, the LoRa stack is not included. The libmDot library should be imported if building for mDot devices. The libxDot library should be imported if building for xDot devices.

Dot Library Limitations

Commit messages in Dot Library repositories specify the version of the library and the version of mbed-os it was compiled against. We recommend building your application with the version of mbed-os specified in the commit message of the version of the Dot library you're using. This will ensure that you don't run into any runtime issues caused by differences in the mbed-os versions.

Example Programs Description

This application contains multiple example programs. Each example demonstrates a different way to configure and use a Dot. A short summary of each example is provided below. Common code used by multiple examples is in the dot_utils.cpp file.

All examples print logging, including RX data, on the USB debug port at 115200 baud. Each example defaults the Dot's configuration and saves the new configuration to NVM.

OTA Example

This example demonstrates configuring the Dot for OTA join mode and entering sleep or deepsleep mode between transactions with the gateway. If deepsleep mode is used, the session is saved and restored so that a rejoin is not necessary after waking up even though RAM contents have been lost. ACKs are disabled, but network link checks are configured - if enough link checks are missed, the Dot will no longer be considered joined to the network and will attempt to rejoin before transmitting more data.

AUTO_OTA Example

This example demonstrates configuring the Dot for AUTO_OTA join mode and entering sleep or deepsleep mode between transactions with the gateway. AUTO_OTA join mode automatically saves and restores the session when deepsleep mode is used, so the manual saving and restoring of the session is not necessary. ACKs are disabled, but network link checks are configured - if enough link checks are missed, the Dot will no longer be considered joined to the network and will attempt to rejoin before transmitting more data.

Manual Example

This example demonstrates configuring the Dot for MANUAL join mode and entering sleep or deepsleep mode between transactions with the gateway. The Dot must be provisioned on the gateway before its packets will be accepted! Follow these steps to provision the Dot on a Conduit gateway:

  • ssh into the conduit
  • use the lorq-query application to provision the Dot on the gateway
    • lora-query -a 01020304 A 0102030401020304 <your Dot's device ID> 01020304010203040102030401020304 01020304010203040102030401020304
    • if any of the credentials change on the Dot side, they must be updated on the gateway side as well

To provision a Dot on a third-party gateway, see the gateway or network provider documentation.

Class B Example

This example demonstrates how to configure the dot for an OTA join, how to acquire a lock on a GPS synchronized beacon, and then to subsequently enter class B mode of operation. After a successful join, the device will request to the dot-library to switch to class B. When this happens, the library will send an uplink to the network server (hence we must be joined first before entering this mode) requesting the GPS time to calculate when the next beacon is expected. Once this time elapses, the dot will open an rx window to demodulate the broadcasted beacon and fire an mDotEvent::BeaconRx event upon successful reception. After the beacon is received, the example sends an uplink which will have the class B bit in the packet's frame control set to indicate to the network server that downlinks may now be scheduled on ping slots. The lora-query application can be used to configure a Conduit gateway to communicate with a Dot in class B mode. For information on how to inform a third-party gateway that a Dot is operating in class B mode, see the gateway or network provider documentation.

Class C Example

This example demonstrates configuring the Dot for OTA join mode and communicating with the gateway using class C mode. In class C mode the gateway can send a packet to the Dot at any time, so it must be listening whenever it is not transmitting. This means that the Dot cannot enter sleep or deepsleep mode. The gateway will not immediately send packets to the Dot (outside the receive windows following a transmission from the Dot) until it is informed that the Dot is operating in class C mode. The lora-query application can be used to configure a Conduit gateway to communicate with a Dot in class C mode. For information on how to inform a third-party gateway that a Dot is operating in class C mode, see the gateway or network provider documentation.

FOTA Example

Full FOTA support is available on mDot and on xDot with external flash. See this article for details on adding external flash for xDot FOTA.

Without external flash xDot can use the FOTA example to dynamically join a multicast session only. After joining the multicast session the received Fragmentation packets could be handed to a host MCU for processing and at completion the firmware can be loaded into the xDot using the bootloader and y-modem. See xDot Developer Guide.

This example demonstrates how to incorporate over-the-air updates to an application. The example uses a Class C application. Class A or B functionality could also be used. The device will automatically enter into Class C operation for the FOTA operation, Class B would be disabled during the FOTA transfer.

  • Add the following code to allow Fota to use the Dot instance

examples/src/fota_example.cpp

    // Initialize FOTA singleton
    Fota::getInstance(dot);
  • Add fragmentation and multicast handling the the PacketRx event

examples/inc/RadioEvent.h

    virtual void PacketRx(uint8_t port, uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot, uint8_t retries, uint32_t address, uint32_t fcnt, bool dupRx) {
        mDotEvent::PacketRx(port, payload, size, rssi, snr, ctrl, slot, retries, address, fcnt, dupRx);

#if ACTIVE_EXAMPLE == FOTA_EXAMPLE
        if(port == 200 || port == 201 || port == 202) {
            Fota::getInstance()->processCmd(payload, port, size);
        }
#endif
    }

A definition is needed to enable FOTA.

mbed_app.json

{
    "macros": [
        "FOTA=1"
    ]
}


Peer to Peer Example

This example demonstrates configuring Dots for peer to peer communication without a gateway. It should be compiled and run on two Dots. Peer to peer communication uses LoRa modulation but uses a single higher throughput (usually 500kHz or 250kHz) datarate. It is similar to class C operation - when a Dot isn't transmitting, it's listening for packets from the other Dot. Both Dots must be configured exactly the same for peer to peer communication to be successful.


Choosing An Example Program and Channel Plan

Only the active example is compiled. The active example can be updated by changing the ACTIVE_EXAMPLE definition in the examples/example_config.h file.

By default the OTA_EXAMPLE will be compiled and the US915 channel plan will be used.

example_config.h

#ifndef __EXAMPLE__CONFIG_H__
#define __EXAMPLE__CONFIG_H__

#define OTA_EXAMPLE              1  // see ota_example.cpp
#define AUTO_OTA_EXAMPLE         2  // see auto_ota_example.cpp
#define MANUAL_EXAMPLE           3  // see manual_example.cpp
#define PEER_TO_PEER_EXAMPLE     4  // see peer_to_peer_example.cpp
#define CLASS_C_EXAMPLE          5  // see class_c_example.cpp

// the active example is the one that will be compiled
#if !defined(ACTIVE_EXAMPLE)
#define ACTIVE_EXAMPLE  OTA_EXAMPLE
#endif

// the active channel plan is the one that will be compiled
// options are :
//      CP_US915
//      CP_AU915
//      CP_EU868
//      CP_KR920
//      CP_AS923
//      CP_AS923_JAPAN
#if !defined(CHANNEL_PLAN)
#define CHANNEL_PLAN CP_US915
#endif

#endif


Compile the AUTO_OTA_EXAMPLE and use the EU868 channel plan instead.

example_config.h

#ifndef __EXAMPLE__CONFIG_H__
#define __EXAMPLE__CONFIG_H__

#define OTA_EXAMPLE              1  // see ota_example.cpp
#define AUTO_OTA_EXAMPLE         2  // see auto_ota_example.cpp
#define MANUAL_EXAMPLE           3  // see manual_example.cpp
#define PEER_TO_PEER_EXAMPLE     4  // see peer_to_peer_example.cpp
#define CLASS_C_EXAMPLE          5  // see class_c_example.cpp

// the active example is the one that will be compiled
#if !defined(ACTIVE_EXAMPLE)
#define ACTIVE_EXAMPLE  AUTO_OTA_EXAMPLE
#endif

// the active channel plan is the one that will be compiled
// options are :
//      CP_US915
//      CP_AU915
//      CP_EU868
//      CP_KR920
//      CP_AS923
//      CP_AS923_JAPAN
#if !defined(CHANNEL_PLAN)
#define CHANNEL_PLAN CP_EU868
#endif

#endif



Dot Libraries

Stable and development libraries are available for both mDot and xDot platforms. The library chosen must match the target platform. Compiling for the mDot platform with the xDot library or vice versa will not succeed.

mDot Library

Development library for mDot.

libmDot-dev

Stable library for mDot.

libmDot-stable


For mbed-os 5 use:

Import librarylibmDot-mbed5

Stable version of the mDot library for mbed 5. This version of the library is suitable for deployment scenarios. See lastest commit message for version of mbed-os library that has been tested against.

xDot Library

Development library for xDot.

libxDot-dev

Stable library for xDot.

libxDot-stable


For mbed-os 5 use:

Import librarylibxDot-mbed5

Stable version of the xDot library for mbed 5. This version of the library is suitable for deployment scenarios.

Committer:
Mike Fiore
Date:
Mon Oct 10 15:04:22 2016 -0500
Revision:
10:4d0b765f7b9e
Parent:
8:e667f4a507b1
Child:
11:d2e31743433a
add class C example, clean up configuration display

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mfiore 0:a151a6350d7f 1 #include "dot_util.h"
Mike Fiore 7:724cb82a113e 2 #if defined(TARGET_XDOT_L151CC)
Mike Fiore 7:724cb82a113e 3 #include "xdot_low_power.h"
Mike Fiore 7:724cb82a113e 4 #endif
Mike Fiore 7:724cb82a113e 5
Mike Fiore 7:724cb82a113e 6 #if defined(TARGET_MTS_MDOT_F411RE)
Mike Fiore 7:724cb82a113e 7 uint32_t portA[6];
Mike Fiore 7:724cb82a113e 8 uint32_t portB[6];
Mike Fiore 7:724cb82a113e 9 uint32_t portC[6];
Mike Fiore 7:724cb82a113e 10 uint32_t portD[6];
Mike Fiore 7:724cb82a113e 11 uint32_t portH[6];
Mike Fiore 7:724cb82a113e 12 #endif
Mike Fiore 7:724cb82a113e 13
mfiore 0:a151a6350d7f 14
mfiore 0:a151a6350d7f 15 void display_config() {
mfiore 0:a151a6350d7f 16 // display configuration and library version information
Mike Fiore 10:4d0b765f7b9e 17 logInfo("=====================");
mfiore 0:a151a6350d7f 18 logInfo("general configuration");
Mike Fiore 10:4d0b765f7b9e 19 logInfo("=====================");
Mike Fiore 10:4d0b765f7b9e 20 logInfo("version ------------------ %s", dot->getId().c_str());
Mike Fiore 10:4d0b765f7b9e 21 logInfo("device ID/EUI ------------ %s", mts::Text::bin2hexString(dot->getDeviceId()).c_str());
Mike Fiore 10:4d0b765f7b9e 22 logInfo("frequency band ----------- %s", mDot::FrequencyBandStr(dot->getFrequencyBand()).c_str());
mfiore 2:ffac7b141b72 23 if (dot->getFrequencySubBand() != mDot::FB_EU868) {
Mike Fiore 10:4d0b765f7b9e 24 logInfo("frequency sub band ------- %u", dot->getFrequencySubBand());
mfiore 1:c4915e00d2ce 25 }
Mike Fiore 10:4d0b765f7b9e 26 logInfo("public network ----------- %s", dot->getPublicNetwork() ? "on" : "off");
Mike Fiore 10:4d0b765f7b9e 27 logInfo("=========================");
mfiore 0:a151a6350d7f 28 logInfo("credentials configuration");
Mike Fiore 10:4d0b765f7b9e 29 logInfo("=========================");
Mike Fiore 10:4d0b765f7b9e 30 logInfo("device class ------------- %s", dot->getClass().c_str());
Mike Fiore 10:4d0b765f7b9e 31 logInfo("network join mode -------- %s", mDot::JoinModeStr(dot->getJoinMode()).c_str());
Mike Fiore 8:e667f4a507b1 32 if (dot->getJoinMode() == mDot::MANUAL) {
Mike Fiore 10:4d0b765f7b9e 33 logInfo("network address ---------- %s", mts::Text::bin2hexString(dot->getNetworkAddress()).c_str());
Mike Fiore 10:4d0b765f7b9e 34 logInfo("network session key------- %s", mts::Text::bin2hexString(dot->getNetworkSessionKey()).c_str());
Mike Fiore 10:4d0b765f7b9e 35 logInfo("data session key---------- %s", mts::Text::bin2hexString(dot->getDataSessionKey()).c_str());
Mike Fiore 8:e667f4a507b1 36 } else {
Mike Fiore 10:4d0b765f7b9e 37 logInfo("network name ------------- %s", dot->getNetworkName().c_str());
Mike Fiore 10:4d0b765f7b9e 38 logInfo("network phrase ----------- %s", dot->getNetworkPassphrase().c_str());
Mike Fiore 10:4d0b765f7b9e 39 logInfo("network EUI -------------- %s", mts::Text::bin2hexString(dot->getNetworkId()).c_str());
Mike Fiore 10:4d0b765f7b9e 40 logInfo("network KEY -------------- %s", mts::Text::bin2hexString(dot->getNetworkKey()).c_str());
Mike Fiore 8:e667f4a507b1 41 }
Mike Fiore 10:4d0b765f7b9e 42 logInfo("========================");
mfiore 0:a151a6350d7f 43 logInfo("communication parameters");
Mike Fiore 10:4d0b765f7b9e 44 logInfo("========================");
Mike Fiore 10:4d0b765f7b9e 45 logInfo("acks --------------------- %s, %u attempts", dot->getAck() > 0 ? "on" : "off", dot->getAck());
Mike Fiore 10:4d0b765f7b9e 46 logInfo("TX datarate -------------- %s", mDot::DataRateStr(dot->getTxDataRate()).c_str());
Mike Fiore 10:4d0b765f7b9e 47 logInfo("TX power ----------------- %lu dBm", dot->getTxPower());
Mike Fiore 10:4d0b765f7b9e 48 logInfo("atnenna gain ------------- %u dBm", dot->getAntennaGain());
mfiore 0:a151a6350d7f 49 }
mfiore 0:a151a6350d7f 50
Mike Fiore 5:97ed5f2f099e 51 void update_ota_config_name_phrase(std::string network_name, std::string network_passphrase, uint8_t frequency_sub_band, bool public_network, uint8_t ack) {
mfiore 0:a151a6350d7f 52 std::string current_network_name = dot->getNetworkName();
mfiore 0:a151a6350d7f 53 std::string current_network_passphrase = dot->getNetworkPassphrase();
mfiore 0:a151a6350d7f 54 uint8_t current_frequency_sub_band = dot->getFrequencySubBand();
mfiore 0:a151a6350d7f 55 bool current_public_network = dot->getPublicNetwork();
mfiore 0:a151a6350d7f 56 uint8_t current_ack = dot->getAck();
mfiore 0:a151a6350d7f 57
mfiore 0:a151a6350d7f 58 if (current_network_name != network_name) {
mfiore 0:a151a6350d7f 59 logInfo("changing network name from \"%s\" to \"%s\"", current_network_name.c_str(), network_name.c_str());
mfiore 0:a151a6350d7f 60 if (dot->setNetworkName(network_name) != mDot::MDOT_OK) {
mfiore 0:a151a6350d7f 61 logError("failed to set network name to \"%s\"", network_name.c_str());
mfiore 0:a151a6350d7f 62 }
mfiore 0:a151a6350d7f 63 }
mfiore 0:a151a6350d7f 64
mfiore 0:a151a6350d7f 65 if (current_network_passphrase != network_passphrase) {
mfiore 0:a151a6350d7f 66 logInfo("changing network passphrase from \"%s\" to \"%s\"", current_network_passphrase.c_str(), network_passphrase.c_str());
mfiore 0:a151a6350d7f 67 if (dot->setNetworkPassphrase(network_passphrase) != mDot::MDOT_OK) {
mfiore 0:a151a6350d7f 68 logError("failed to set network passphrase to \"%s\"", network_passphrase.c_str());
mfiore 0:a151a6350d7f 69 }
mfiore 0:a151a6350d7f 70 }
mfiore 0:a151a6350d7f 71
mfiore 0:a151a6350d7f 72 if (current_frequency_sub_band != frequency_sub_band) {
mfiore 0:a151a6350d7f 73 logInfo("changing frequency sub band from %u to %u", current_frequency_sub_band, frequency_sub_band);
mfiore 0:a151a6350d7f 74 if (dot->setFrequencySubBand(frequency_sub_band) != mDot::MDOT_OK) {
mfiore 0:a151a6350d7f 75 logError("failed to set frequency sub band to %u", frequency_sub_band);
mfiore 0:a151a6350d7f 76 }
mfiore 0:a151a6350d7f 77 }
mfiore 0:a151a6350d7f 78
mfiore 0:a151a6350d7f 79 if (current_public_network != public_network) {
Mike Fiore 10:4d0b765f7b9e 80 logInfo("changing public network from %s to %s", current_public_network ? "on" : "off", public_network ? "on" : "off");
mfiore 0:a151a6350d7f 81 if (dot->setPublicNetwork(public_network) != mDot::MDOT_OK) {
Mike Fiore 10:4d0b765f7b9e 82 logError("failed to set public network to %s", public_network ? "on" : "off");
mfiore 0:a151a6350d7f 83 }
mfiore 0:a151a6350d7f 84 }
mfiore 0:a151a6350d7f 85
mfiore 0:a151a6350d7f 86 if (current_ack != ack) {
mfiore 0:a151a6350d7f 87 logInfo("changing acks from %u to %u", current_ack, ack);
mfiore 0:a151a6350d7f 88 if (dot->setAck(ack) != mDot::MDOT_OK) {
mfiore 0:a151a6350d7f 89 logError("failed to set acks to %u", ack);
mfiore 0:a151a6350d7f 90 }
mfiore 0:a151a6350d7f 91 }
mfiore 0:a151a6350d7f 92 }
mfiore 0:a151a6350d7f 93
Mike Fiore 5:97ed5f2f099e 94 void update_ota_config_id_key(uint8_t *network_id, uint8_t *network_key, uint8_t frequency_sub_band, bool public_network, uint8_t ack) {
Mike Fiore 5:97ed5f2f099e 95 std::vector<uint8_t> current_network_id = dot->getNetworkId();
Mike Fiore 5:97ed5f2f099e 96 std::vector<uint8_t> current_network_key = dot->getNetworkKey();
Mike Fiore 5:97ed5f2f099e 97 uint8_t current_frequency_sub_band = dot->getFrequencySubBand();
Mike Fiore 5:97ed5f2f099e 98 bool current_public_network = dot->getPublicNetwork();
Mike Fiore 5:97ed5f2f099e 99 uint8_t current_ack = dot->getAck();
Mike Fiore 5:97ed5f2f099e 100
Mike Fiore 5:97ed5f2f099e 101 std::vector<uint8_t> network_id_vector(network_id, network_id + 8);
Mike Fiore 5:97ed5f2f099e 102 std::vector<uint8_t> network_key_vector(network_key, network_key + 16);
Mike Fiore 5:97ed5f2f099e 103
Mike Fiore 5:97ed5f2f099e 104 if (current_network_id != network_id_vector) {
Mike Fiore 5:97ed5f2f099e 105 logInfo("changing network ID from \"%s\" to \"%s\"", mts::Text::bin2hexString(current_network_id).c_str(), mts::Text::bin2hexString(network_id_vector).c_str());
Mike Fiore 5:97ed5f2f099e 106 if (dot->setNetworkId(network_id_vector) != mDot::MDOT_OK) {
Mike Fiore 5:97ed5f2f099e 107 logError("failed to set network ID to \"%s\"", mts::Text::bin2hexString(network_id_vector).c_str());
Mike Fiore 5:97ed5f2f099e 108 }
Mike Fiore 5:97ed5f2f099e 109 }
Mike Fiore 5:97ed5f2f099e 110
Mike Fiore 5:97ed5f2f099e 111 if (current_network_key != network_key_vector) {
Mike Fiore 5:97ed5f2f099e 112 logInfo("changing network KEY from \"%s\" to \"%s\"", mts::Text::bin2hexString(current_network_key).c_str(), mts::Text::bin2hexString(network_key_vector).c_str());
Mike Fiore 5:97ed5f2f099e 113 if (dot->setNetworkKey(network_key_vector) != mDot::MDOT_OK) {
Mike Fiore 5:97ed5f2f099e 114 logError("failed to set network KEY to \"%s\"", mts::Text::bin2hexString(network_key_vector).c_str());
Mike Fiore 5:97ed5f2f099e 115 }
Mike Fiore 5:97ed5f2f099e 116 }
Mike Fiore 5:97ed5f2f099e 117
Mike Fiore 5:97ed5f2f099e 118 if (current_frequency_sub_band != frequency_sub_band) {
Mike Fiore 5:97ed5f2f099e 119 logInfo("changing frequency sub band from %u to %u", current_frequency_sub_band, frequency_sub_band);
Mike Fiore 5:97ed5f2f099e 120 if (dot->setFrequencySubBand(frequency_sub_band) != mDot::MDOT_OK) {
Mike Fiore 5:97ed5f2f099e 121 logError("failed to set frequency sub band to %u", frequency_sub_band);
Mike Fiore 5:97ed5f2f099e 122 }
Mike Fiore 5:97ed5f2f099e 123 }
Mike Fiore 5:97ed5f2f099e 124
Mike Fiore 5:97ed5f2f099e 125 if (current_public_network != public_network) {
Mike Fiore 10:4d0b765f7b9e 126 logInfo("changing public network from %s to %s", current_public_network ? "on" : "off", public_network ? "on" : "off");
Mike Fiore 5:97ed5f2f099e 127 if (dot->setPublicNetwork(public_network) != mDot::MDOT_OK) {
Mike Fiore 10:4d0b765f7b9e 128 logError("failed to set public network to %s", public_network ? "on" : "off");
Mike Fiore 5:97ed5f2f099e 129 }
Mike Fiore 5:97ed5f2f099e 130 }
Mike Fiore 5:97ed5f2f099e 131
Mike Fiore 5:97ed5f2f099e 132 if (current_ack != ack) {
Mike Fiore 5:97ed5f2f099e 133 logInfo("changing acks from %u to %u", current_ack, ack);
Mike Fiore 5:97ed5f2f099e 134 if (dot->setAck(ack) != mDot::MDOT_OK) {
Mike Fiore 5:97ed5f2f099e 135 logError("failed to set acks to %u", ack);
Mike Fiore 5:97ed5f2f099e 136 }
Mike Fiore 5:97ed5f2f099e 137 }
Mike Fiore 5:97ed5f2f099e 138 }
Mike Fiore 5:97ed5f2f099e 139
Mike Fiore 8:e667f4a507b1 140 void update_manual_config(uint8_t *network_address, uint8_t *network_session_key, uint8_t *data_session_key, uint8_t frequency_sub_band, bool public_network, uint8_t ack) {
Mike Fiore 8:e667f4a507b1 141 std::vector<uint8_t> current_network_address = dot->getNetworkAddress();
Mike Fiore 8:e667f4a507b1 142 std::vector<uint8_t> current_network_session_key = dot->getNetworkSessionKey();
Mike Fiore 8:e667f4a507b1 143 std::vector<uint8_t> current_data_session_key = dot->getDataSessionKey();
Mike Fiore 8:e667f4a507b1 144 uint8_t current_frequency_sub_band = dot->getFrequencySubBand();
Mike Fiore 8:e667f4a507b1 145 bool current_public_network = dot->getPublicNetwork();
Mike Fiore 8:e667f4a507b1 146 uint8_t current_ack = dot->getAck();
Mike Fiore 8:e667f4a507b1 147
Mike Fiore 8:e667f4a507b1 148 std::vector<uint8_t> network_address_vector(network_address, network_address + 4);
Mike Fiore 8:e667f4a507b1 149 std::vector<uint8_t> network_session_key_vector(network_session_key, network_session_key + 16);
Mike Fiore 8:e667f4a507b1 150 std::vector<uint8_t> data_session_key_vector(data_session_key, data_session_key + 16);
Mike Fiore 8:e667f4a507b1 151
Mike Fiore 8:e667f4a507b1 152 if (current_network_address != network_address_vector) {
Mike Fiore 8:e667f4a507b1 153 logInfo("changing network address from \"%s\" to \"%s\"", mts::Text::bin2hexString(current_network_address).c_str(), mts::Text::bin2hexString(network_address_vector).c_str());
Mike Fiore 8:e667f4a507b1 154 if (dot->setNetworkAddress(network_address_vector) != mDot::MDOT_OK) {
Mike Fiore 8:e667f4a507b1 155 logError("failed to set network address to \"%s\"", mts::Text::bin2hexString(network_address_vector).c_str());
Mike Fiore 8:e667f4a507b1 156 }
Mike Fiore 8:e667f4a507b1 157 }
Mike Fiore 8:e667f4a507b1 158
Mike Fiore 8:e667f4a507b1 159 if (current_network_session_key != network_session_key_vector) {
Mike Fiore 8:e667f4a507b1 160 logInfo("changing network session key from \"%s\" to \"%s\"", mts::Text::bin2hexString(current_network_session_key).c_str(), mts::Text::bin2hexString(network_session_key_vector).c_str());
Mike Fiore 8:e667f4a507b1 161 if (dot->setNetworkSessionKey(network_session_key_vector) != mDot::MDOT_OK) {
Mike Fiore 8:e667f4a507b1 162 logError("failed to set network session key to \"%s\"", mts::Text::bin2hexString(network_session_key_vector).c_str());
Mike Fiore 8:e667f4a507b1 163 }
Mike Fiore 8:e667f4a507b1 164 }
Mike Fiore 8:e667f4a507b1 165
Mike Fiore 8:e667f4a507b1 166 if (current_data_session_key != data_session_key_vector) {
Mike Fiore 8:e667f4a507b1 167 logInfo("changing data session key from \"%s\" to \"%s\"", mts::Text::bin2hexString(current_data_session_key).c_str(), mts::Text::bin2hexString(data_session_key_vector).c_str());
Mike Fiore 8:e667f4a507b1 168 if (dot->setDataSessionKey(data_session_key_vector) != mDot::MDOT_OK) {
Mike Fiore 8:e667f4a507b1 169 logError("failed to set data session key to \"%s\"", mts::Text::bin2hexString(data_session_key_vector).c_str());
Mike Fiore 8:e667f4a507b1 170 }
Mike Fiore 8:e667f4a507b1 171 }
Mike Fiore 8:e667f4a507b1 172
Mike Fiore 8:e667f4a507b1 173 if (current_frequency_sub_band != frequency_sub_band) {
Mike Fiore 8:e667f4a507b1 174 logInfo("changing frequency sub band from %u to %u", current_frequency_sub_band, frequency_sub_band);
Mike Fiore 8:e667f4a507b1 175 if (dot->setFrequencySubBand(frequency_sub_band) != mDot::MDOT_OK) {
Mike Fiore 8:e667f4a507b1 176 logError("failed to set frequency sub band to %u", frequency_sub_band);
Mike Fiore 8:e667f4a507b1 177 }
Mike Fiore 8:e667f4a507b1 178 }
Mike Fiore 8:e667f4a507b1 179
Mike Fiore 8:e667f4a507b1 180 if (current_public_network != public_network) {
Mike Fiore 10:4d0b765f7b9e 181 logInfo("changing public network from %s to %s", current_public_network ? "on" : "off", public_network ? "on" : "off");
Mike Fiore 8:e667f4a507b1 182 if (dot->setPublicNetwork(public_network) != mDot::MDOT_OK) {
Mike Fiore 10:4d0b765f7b9e 183 logError("failed to set public network to %s", public_network ? "on" : "off");
Mike Fiore 8:e667f4a507b1 184 }
Mike Fiore 8:e667f4a507b1 185 }
Mike Fiore 8:e667f4a507b1 186
Mike Fiore 8:e667f4a507b1 187 if (current_ack != ack) {
Mike Fiore 8:e667f4a507b1 188 logInfo("changing acks from %u to %u", current_ack, ack);
Mike Fiore 8:e667f4a507b1 189 if (dot->setAck(ack) != mDot::MDOT_OK) {
Mike Fiore 8:e667f4a507b1 190 logError("failed to set acks to %u", ack);
Mike Fiore 8:e667f4a507b1 191 }
Mike Fiore 8:e667f4a507b1 192 }
Mike Fiore 8:e667f4a507b1 193 }
Mike Fiore 8:e667f4a507b1 194
mfiore 0:a151a6350d7f 195 void join_network() {
mfiore 0:a151a6350d7f 196 int32_t j_attempts = 0;
mfiore 0:a151a6350d7f 197 int32_t ret = mDot::MDOT_ERROR;
mfiore 0:a151a6350d7f 198
mfiore 0:a151a6350d7f 199 // attempt to join the network
mfiore 0:a151a6350d7f 200 while (ret != mDot::MDOT_OK) {
mfiore 0:a151a6350d7f 201 logInfo("attempt %d to join network", ++j_attempts);
mfiore 0:a151a6350d7f 202 ret = dot->joinNetwork();
mfiore 0:a151a6350d7f 203 if (ret != mDot::MDOT_OK) {
mfiore 0:a151a6350d7f 204 logError("failed to join network %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
mfiore 0:a151a6350d7f 205 // in some frequency bands we need to wait until another channel is available before transmitting again
mfiore 0:a151a6350d7f 206 uint32_t delay_s = (dot->getNextTxMs() / 1000) + 1;
mfiore 0:a151a6350d7f 207 if (delay_s < 2) {
mfiore 0:a151a6350d7f 208 logInfo("waiting %lu s until next free channel", delay_s);
mfiore 0:a151a6350d7f 209 wait(delay_s);
mfiore 0:a151a6350d7f 210 } else {
mfiore 0:a151a6350d7f 211 logInfo("sleeping %lu s until next free channel", delay_s);
mfiore 0:a151a6350d7f 212 dot->sleep(delay_s, mDot::RTC_ALARM, false);
mfiore 0:a151a6350d7f 213 }
mfiore 0:a151a6350d7f 214 }
mfiore 0:a151a6350d7f 215 }
mfiore 0:a151a6350d7f 216 }
mfiore 0:a151a6350d7f 217
mfiore 0:a151a6350d7f 218 void sleep_wake_rtc_only(bool deepsleep) {
mfiore 0:a151a6350d7f 219 // in some frequency bands we need to wait until another channel is available before transmitting again
mfiore 0:a151a6350d7f 220 // wait at least 10s between transmissions
mfiore 0:a151a6350d7f 221 uint32_t delay_s = dot->getNextTxMs() / 1000;
mfiore 0:a151a6350d7f 222 if (delay_s < 10) {
mfiore 0:a151a6350d7f 223 delay_s = 10;
mfiore 0:a151a6350d7f 224 }
mfiore 0:a151a6350d7f 225
mfiore 0:a151a6350d7f 226 logInfo("%ssleeping %lus", deepsleep ? "deep" : "", delay_s);
mfiore 0:a151a6350d7f 227 logInfo("application will %s after waking up", deepsleep ? "execute from beginning" : "resume");
Mike Fiore 7:724cb82a113e 228
Mike Fiore 7:724cb82a113e 229 // lowest current consumption in sleep mode can only be achieved by configuring IOs as analog inputs with no pull resistors
Mike Fiore 7:724cb82a113e 230 // the library handles all internal IOs automatically, but the external IOs are the application's responsibility
Mike Fiore 7:724cb82a113e 231 // certain IOs may require internal pullup or pulldown resistors because leaving them floating would cause extra current consumption
Mike Fiore 7:724cb82a113e 232 // for xDot: UART_*, I2C_*, SPI_*, GPIO*, WAKE
Mike Fiore 7:724cb82a113e 233 // for mDot: XBEE_*, USBTX, USBRX, PB_0, PB_1
Mike Fiore 7:724cb82a113e 234 // steps are:
Mike Fiore 7:724cb82a113e 235 // * save IO configuration
Mike Fiore 7:724cb82a113e 236 // * configure IOs to reduce current consumption
Mike Fiore 7:724cb82a113e 237 // * sleep
Mike Fiore 7:724cb82a113e 238 // * restore IO configuration
Mike Fiore 7:724cb82a113e 239 if (! deepsleep) {
Mike Fiore 7:724cb82a113e 240 // save the GPIO state.
Mike Fiore 7:724cb82a113e 241 sleep_save_io();
Mike Fiore 7:724cb82a113e 242
Mike Fiore 7:724cb82a113e 243 // configure GPIOs for lowest current
Mike Fiore 7:724cb82a113e 244 sleep_configure_io();
Mike Fiore 7:724cb82a113e 245 }
mfiore 0:a151a6350d7f 246
mfiore 0:a151a6350d7f 247 // go to sleep/deepsleep for delay_s seconds and wake using the RTC alarm
mfiore 0:a151a6350d7f 248 dot->sleep(delay_s, mDot::RTC_ALARM, deepsleep);
Mike Fiore 7:724cb82a113e 249
Mike Fiore 7:724cb82a113e 250 if (! deepsleep) {
Mike Fiore 7:724cb82a113e 251 // restore the GPIO state.
Mike Fiore 7:724cb82a113e 252 sleep_restore_io();
Mike Fiore 7:724cb82a113e 253 }
mfiore 0:a151a6350d7f 254 }
mfiore 0:a151a6350d7f 255
mfiore 0:a151a6350d7f 256 void sleep_wake_interrupt_only(bool deepsleep) {
mfiore 0:a151a6350d7f 257 #if defined (TARGET_XDOT_L151CC)
mfiore 0:a151a6350d7f 258 if (deepsleep) {
mfiore 0:a151a6350d7f 259 // for xDot, WAKE pin (connected to S2 on xDot-DK) is the only pin that can wake the processor from deepsleep
mfiore 0:a151a6350d7f 260 // it is automatically configured when INTERRUPT or RTC_ALARM_OR_INTERRUPT is the wakeup source and deepsleep is true in the mDot::sleep call
mfiore 0:a151a6350d7f 261 } else {
mfiore 0:a151a6350d7f 262 // configure WAKE pin (connected to S2 on xDot-DK) as the pin that will wake the xDot from low power modes
mfiore 0:a151a6350d7f 263 // other pins can be confgured instead: GPIO0-3 or UART_RX
mfiore 0:a151a6350d7f 264 dot->setWakePin(WAKE);
mfiore 0:a151a6350d7f 265 }
mfiore 0:a151a6350d7f 266
mfiore 2:ffac7b141b72 267 logInfo("%ssleeping until interrupt on %s pin", deepsleep ? "deep" : "", deepsleep ? "WAKE" : mDot::pinName2Str(dot->getWakePin()).c_str());
mfiore 0:a151a6350d7f 268 #else
Mike Fiore 7:724cb82a113e 269
mfiore 0:a151a6350d7f 270 if (deepsleep) {
mfiore 0:a151a6350d7f 271 // for mDot, XBEE_DIO7 pin is the only pin that can wake the processor from deepsleep
mfiore 0:a151a6350d7f 272 // it is automatically configured when INTERRUPT or RTC_ALARM_OR_INTERRUPT is the wakeup source and deepsleep is true in the mDot::sleep call
mfiore 0:a151a6350d7f 273 } else {
mfiore 0:a151a6350d7f 274 // configure XBEE_DIO7 pin as the pin that will wake the mDot from low power modes
mfiore 0:a151a6350d7f 275 // other pins can be confgured instead: XBEE_DIO2-6, XBEE_DI8, XBEE_DIN
mfiore 0:a151a6350d7f 276 dot->setWakePin(XBEE_DIO7);
mfiore 0:a151a6350d7f 277 }
mfiore 0:a151a6350d7f 278
mfiore 2:ffac7b141b72 279 logInfo("%ssleeping until interrupt on %s pin", deepsleep ? "deep" : "", deepsleep ? "DIO7" : mDot::pinName2Str(dot->getWakePin()).c_str());
mfiore 0:a151a6350d7f 280 #endif
mfiore 0:a151a6350d7f 281
mfiore 0:a151a6350d7f 282 logInfo("application will %s after waking up", deepsleep ? "execute from beginning" : "resume");
Mike Fiore 7:724cb82a113e 283
Mike Fiore 7:724cb82a113e 284 // lowest current consumption in sleep mode can only be achieved by configuring IOs as analog inputs with no pull resistors
Mike Fiore 7:724cb82a113e 285 // the library handles all internal IOs automatically, but the external IOs are the application's responsibility
Mike Fiore 7:724cb82a113e 286 // certain IOs may require internal pullup or pulldown resistors because leaving them floating would cause extra current consumption
Mike Fiore 7:724cb82a113e 287 // for xDot: UART_*, I2C_*, SPI_*, GPIO*, WAKE
Mike Fiore 7:724cb82a113e 288 // for mDot: XBEE_*, USBTX, USBRX, PB_0, PB_1
Mike Fiore 7:724cb82a113e 289 // steps are:
Mike Fiore 7:724cb82a113e 290 // * save IO configuration
Mike Fiore 7:724cb82a113e 291 // * configure IOs to reduce current consumption
Mike Fiore 7:724cb82a113e 292 // * sleep
Mike Fiore 7:724cb82a113e 293 // * restore IO configuration
Mike Fiore 7:724cb82a113e 294 if (! deepsleep) {
Mike Fiore 7:724cb82a113e 295 // save the GPIO state.
Mike Fiore 7:724cb82a113e 296 sleep_save_io();
Mike Fiore 7:724cb82a113e 297
Mike Fiore 7:724cb82a113e 298 // configure GPIOs for lowest current
Mike Fiore 7:724cb82a113e 299 sleep_configure_io();
Mike Fiore 7:724cb82a113e 300 }
mfiore 0:a151a6350d7f 301
mfiore 0:a151a6350d7f 302 // go to sleep/deepsleep and wake on rising edge of configured wake pin (only the WAKE pin in deepsleep)
mfiore 0:a151a6350d7f 303 // since we're not waking on the RTC alarm, the interval is ignored
mfiore 0:a151a6350d7f 304 dot->sleep(0, mDot::INTERRUPT, deepsleep);
Mike Fiore 7:724cb82a113e 305
Mike Fiore 7:724cb82a113e 306 if (! deepsleep) {
Mike Fiore 7:724cb82a113e 307 // restore the GPIO state.
Mike Fiore 7:724cb82a113e 308 sleep_restore_io();
Mike Fiore 7:724cb82a113e 309 }
mfiore 0:a151a6350d7f 310 }
mfiore 0:a151a6350d7f 311
mfiore 0:a151a6350d7f 312 void sleep_wake_rtc_or_interrupt(bool deepsleep) {
mfiore 0:a151a6350d7f 313 // in some frequency bands we need to wait until another channel is available before transmitting again
mfiore 0:a151a6350d7f 314 // wait at least 10s between transmissions
mfiore 0:a151a6350d7f 315 uint32_t delay_s = dot->getNextTxMs() / 1000;
mfiore 0:a151a6350d7f 316 if (delay_s < 10) {
mfiore 0:a151a6350d7f 317 delay_s = 10;
mfiore 0:a151a6350d7f 318 }
mfiore 0:a151a6350d7f 319
mfiore 0:a151a6350d7f 320 #if defined (TARGET_XDOT_L151CC)
mfiore 0:a151a6350d7f 321 if (deepsleep) {
mfiore 0:a151a6350d7f 322 // for xDot, WAKE pin (connected to S2 on xDot-DK) is the only pin that can wake the processor from deepsleep
mfiore 0:a151a6350d7f 323 // it is automatically configured when INTERRUPT or RTC_ALARM_OR_INTERRUPT is the wakeup source and deepsleep is true in the mDot::sleep call
mfiore 0:a151a6350d7f 324 } else {
mfiore 0:a151a6350d7f 325 // configure WAKE pin (connected to S2 on xDot-DK) as the pin that will wake the xDot from low power modes
mfiore 0:a151a6350d7f 326 // other pins can be confgured instead: GPIO0-3 or UART_RX
mfiore 0:a151a6350d7f 327 dot->setWakePin(WAKE);
mfiore 0:a151a6350d7f 328 }
mfiore 0:a151a6350d7f 329
mfiore 2:ffac7b141b72 330 logInfo("%ssleeping %lus or until interrupt on %s pin", deepsleep ? "deep" : "", delay_s, deepsleep ? "WAKE" : mDot::pinName2Str(dot->getWakePin()).c_str());
mfiore 0:a151a6350d7f 331 #else
mfiore 0:a151a6350d7f 332 if (deepsleep) {
mfiore 0:a151a6350d7f 333 // for mDot, XBEE_DIO7 pin is the only pin that can wake the processor from deepsleep
mfiore 0:a151a6350d7f 334 // it is automatically configured when INTERRUPT or RTC_ALARM_OR_INTERRUPT is the wakeup source and deepsleep is true in the mDot::sleep call
mfiore 0:a151a6350d7f 335 } else {
mfiore 0:a151a6350d7f 336 // configure XBEE_DIO7 pin as the pin that will wake the mDot from low power modes
mfiore 0:a151a6350d7f 337 // other pins can be confgured instead: XBEE_DIO2-6, XBEE_DI8, XBEE_DIN
mfiore 0:a151a6350d7f 338 dot->setWakePin(XBEE_DIO7);
mfiore 0:a151a6350d7f 339 }
mfiore 0:a151a6350d7f 340
mfiore 2:ffac7b141b72 341 logInfo("%ssleeping %lus or until interrupt on %s pin", deepsleep ? "deep" : "", delay_s, deepsleep ? "DIO7" : mDot::pinName2Str(dot->getWakePin()).c_str());
mfiore 0:a151a6350d7f 342 #endif
mfiore 0:a151a6350d7f 343
mfiore 0:a151a6350d7f 344 logInfo("application will %s after waking up", deepsleep ? "execute from beginning" : "resume");
mfiore 0:a151a6350d7f 345
Mike Fiore 7:724cb82a113e 346 // lowest current consumption in sleep mode can only be achieved by configuring IOs as analog inputs with no pull resistors
Mike Fiore 7:724cb82a113e 347 // the library handles all internal IOs automatically, but the external IOs are the application's responsibility
Mike Fiore 7:724cb82a113e 348 // certain IOs may require internal pullup or pulldown resistors because leaving them floating would cause extra current consumption
Mike Fiore 7:724cb82a113e 349 // for xDot: UART_*, I2C_*, SPI_*, GPIO*, WAKE
Mike Fiore 7:724cb82a113e 350 // for mDot: XBEE_*, USBTX, USBRX, PB_0, PB_1
Mike Fiore 7:724cb82a113e 351 // steps are:
Mike Fiore 7:724cb82a113e 352 // * save IO configuration
Mike Fiore 7:724cb82a113e 353 // * configure IOs to reduce current consumption
Mike Fiore 7:724cb82a113e 354 // * sleep
Mike Fiore 7:724cb82a113e 355 // * restore IO configuration
Mike Fiore 7:724cb82a113e 356 if (! deepsleep) {
Mike Fiore 7:724cb82a113e 357 // save the GPIO state.
Mike Fiore 7:724cb82a113e 358 sleep_save_io();
Mike Fiore 7:724cb82a113e 359
Mike Fiore 7:724cb82a113e 360 // configure GPIOs for lowest current
Mike Fiore 7:724cb82a113e 361 sleep_configure_io();
Mike Fiore 7:724cb82a113e 362 }
Mike Fiore 7:724cb82a113e 363
mfiore 0:a151a6350d7f 364 // 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)
mfiore 0:a151a6350d7f 365 // whichever comes first will wake the xDot
mfiore 0:a151a6350d7f 366 dot->sleep(delay_s, mDot::RTC_ALARM_OR_INTERRUPT, deepsleep);
Mike Fiore 7:724cb82a113e 367
Mike Fiore 7:724cb82a113e 368 if (! deepsleep) {
Mike Fiore 7:724cb82a113e 369 // restore the GPIO state.
Mike Fiore 7:724cb82a113e 370 sleep_restore_io();
Mike Fiore 7:724cb82a113e 371 }
Mike Fiore 7:724cb82a113e 372 }
Mike Fiore 7:724cb82a113e 373
Mike Fiore 7:724cb82a113e 374 void sleep_save_io() {
Mike Fiore 7:724cb82a113e 375 #if defined(TARGET_XDOT_L151CC)
Mike Fiore 7:724cb82a113e 376 xdot_save_gpio_state();
Mike Fiore 7:724cb82a113e 377 #else
Mike Fiore 7:724cb82a113e 378 portA[0] = GPIOA->MODER;
Mike Fiore 7:724cb82a113e 379 portA[1] = GPIOA->OTYPER;
Mike Fiore 7:724cb82a113e 380 portA[2] = GPIOA->OSPEEDR;
Mike Fiore 7:724cb82a113e 381 portA[3] = GPIOA->PUPDR;
Mike Fiore 7:724cb82a113e 382 portA[4] = GPIOA->AFR[0];
Mike Fiore 7:724cb82a113e 383 portA[5] = GPIOA->AFR[1];
Mike Fiore 7:724cb82a113e 384
Mike Fiore 7:724cb82a113e 385 portB[0] = GPIOB->MODER;
Mike Fiore 7:724cb82a113e 386 portB[1] = GPIOB->OTYPER;
Mike Fiore 7:724cb82a113e 387 portB[2] = GPIOB->OSPEEDR;
Mike Fiore 7:724cb82a113e 388 portB[3] = GPIOB->PUPDR;
Mike Fiore 7:724cb82a113e 389 portB[4] = GPIOB->AFR[0];
Mike Fiore 7:724cb82a113e 390 portB[5] = GPIOB->AFR[1];
Mike Fiore 7:724cb82a113e 391
Mike Fiore 7:724cb82a113e 392 portC[0] = GPIOC->MODER;
Mike Fiore 7:724cb82a113e 393 portC[1] = GPIOC->OTYPER;
Mike Fiore 7:724cb82a113e 394 portC[2] = GPIOC->OSPEEDR;
Mike Fiore 7:724cb82a113e 395 portC[3] = GPIOC->PUPDR;
Mike Fiore 7:724cb82a113e 396 portC[4] = GPIOC->AFR[0];
Mike Fiore 7:724cb82a113e 397 portC[5] = GPIOC->AFR[1];
Mike Fiore 7:724cb82a113e 398
Mike Fiore 7:724cb82a113e 399 portD[0] = GPIOD->MODER;
Mike Fiore 7:724cb82a113e 400 portD[1] = GPIOD->OTYPER;
Mike Fiore 7:724cb82a113e 401 portD[2] = GPIOD->OSPEEDR;
Mike Fiore 7:724cb82a113e 402 portD[3] = GPIOD->PUPDR;
Mike Fiore 7:724cb82a113e 403 portD[4] = GPIOD->AFR[0];
Mike Fiore 7:724cb82a113e 404 portD[5] = GPIOD->AFR[1];
Mike Fiore 7:724cb82a113e 405
Mike Fiore 7:724cb82a113e 406 portH[0] = GPIOH->MODER;
Mike Fiore 7:724cb82a113e 407 portH[1] = GPIOH->OTYPER;
Mike Fiore 7:724cb82a113e 408 portH[2] = GPIOH->OSPEEDR;
Mike Fiore 7:724cb82a113e 409 portH[3] = GPIOH->PUPDR;
Mike Fiore 7:724cb82a113e 410 portH[4] = GPIOH->AFR[0];
Mike Fiore 7:724cb82a113e 411 portH[5] = GPIOH->AFR[1];
Mike Fiore 7:724cb82a113e 412 #endif
Mike Fiore 7:724cb82a113e 413 }
Mike Fiore 7:724cb82a113e 414
Mike Fiore 7:724cb82a113e 415 void sleep_configure_io() {
Mike Fiore 7:724cb82a113e 416 #if defined(TARGET_XDOT_L151CC)
Mike Fiore 7:724cb82a113e 417 // GPIO Ports Clock Enable
Mike Fiore 7:724cb82a113e 418 __GPIOA_CLK_ENABLE();
Mike Fiore 7:724cb82a113e 419 __GPIOB_CLK_ENABLE();
Mike Fiore 7:724cb82a113e 420 __GPIOC_CLK_ENABLE();
Mike Fiore 7:724cb82a113e 421 __GPIOH_CLK_ENABLE();
Mike Fiore 7:724cb82a113e 422
Mike Fiore 7:724cb82a113e 423 GPIO_InitTypeDef GPIO_InitStruct;
Mike Fiore 7:724cb82a113e 424
Mike Fiore 7:724cb82a113e 425 // UART1_TX, UART1_RTS & UART1_CTS to analog nopull - RX could be a wakeup source
Mike Fiore 7:724cb82a113e 426 GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_11 | GPIO_PIN_12;
Mike Fiore 7:724cb82a113e 427 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 428 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 429 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 430
Mike Fiore 7:724cb82a113e 431 // I2C_SDA & I2C_SCL to analog nopull
Mike Fiore 7:724cb82a113e 432 GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
Mike Fiore 7:724cb82a113e 433 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 434 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 435 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 436
Mike Fiore 7:724cb82a113e 437 // SPI_MOSI, SPI_MISO, SPI_SCK, & SPI_NSS to analog nopull
Mike Fiore 7:724cb82a113e 438 GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
Mike Fiore 7:724cb82a113e 439 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 440 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 441 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 442
Mike Fiore 7:724cb82a113e 443 // iterate through potential wake pins - leave the configured wake pin alone if one is needed
Mike Fiore 7:724cb82a113e 444 if (dot->getWakePin() != WAKE || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 445 GPIO_InitStruct.Pin = GPIO_PIN_0;
Mike Fiore 7:724cb82a113e 446 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 447 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 448 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 449 }
Mike Fiore 7:724cb82a113e 450 if (dot->getWakePin() != GPIO0 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 451 GPIO_InitStruct.Pin = GPIO_PIN_4;
Mike Fiore 7:724cb82a113e 452 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 453 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 454 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 455 }
Mike Fiore 7:724cb82a113e 456 if (dot->getWakePin() != GPIO1 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 457 GPIO_InitStruct.Pin = GPIO_PIN_5;
Mike Fiore 7:724cb82a113e 458 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 459 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 460 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 461 }
Mike Fiore 7:724cb82a113e 462 if (dot->getWakePin() != GPIO2 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 463 GPIO_InitStruct.Pin = GPIO_PIN_0;
Mike Fiore 7:724cb82a113e 464 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 465 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 466 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 467 }
Mike Fiore 7:724cb82a113e 468 if (dot->getWakePin() != GPIO3 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 469 GPIO_InitStruct.Pin = GPIO_PIN_2;
Mike Fiore 7:724cb82a113e 470 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 471 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 472 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 473 }
Mike Fiore 7:724cb82a113e 474 if (dot->getWakePin() != UART1_RX || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 475 GPIO_InitStruct.Pin = GPIO_PIN_10;
Mike Fiore 7:724cb82a113e 476 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 477 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 478 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 479 }
Mike Fiore 7:724cb82a113e 480 #else
Mike Fiore 7:724cb82a113e 481 /* GPIO Ports Clock Enable */
Mike Fiore 7:724cb82a113e 482 __GPIOA_CLK_ENABLE();
Mike Fiore 7:724cb82a113e 483 __GPIOB_CLK_ENABLE();
Mike Fiore 7:724cb82a113e 484 __GPIOC_CLK_ENABLE();
Mike Fiore 7:724cb82a113e 485
Mike Fiore 7:724cb82a113e 486 GPIO_InitTypeDef GPIO_InitStruct;
Mike Fiore 7:724cb82a113e 487
Mike Fiore 7:724cb82a113e 488 // XBEE_DOUT, XBEE_DIN, XBEE_DO8, XBEE_RSSI, USBTX, USBRX, PA_12, PA_13, PA_14 & PA_15 to analog nopull
Mike Fiore 7:724cb82a113e 489 GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_6 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10
Mike Fiore 7:724cb82a113e 490 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
Mike Fiore 7:724cb82a113e 491 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 492 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 493 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 494
Mike Fiore 7:724cb82a113e 495 // PB_0, PB_1, PB_3 & PB_4 to analog nopull
Mike Fiore 7:724cb82a113e 496 GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4;
Mike Fiore 7:724cb82a113e 497 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 498 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 499 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 500
Mike Fiore 7:724cb82a113e 501 // PC_9 & PC_13 to analog nopull
Mike Fiore 7:724cb82a113e 502 GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_13;
Mike Fiore 7:724cb82a113e 503 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 504 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 505 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 506
Mike Fiore 7:724cb82a113e 507 // iterate through potential wake pins - leave the configured wake pin alone if one is needed
Mike Fiore 7:724cb82a113e 508 // XBEE_DIN - PA3
Mike Fiore 7:724cb82a113e 509 // XBEE_DIO2 - PA5
Mike Fiore 7:724cb82a113e 510 // XBEE_DIO3 - PA4
Mike Fiore 7:724cb82a113e 511 // XBEE_DIO4 - PA7
Mike Fiore 7:724cb82a113e 512 // XBEE_DIO5 - PC1
Mike Fiore 7:724cb82a113e 513 // XBEE_DIO6 - PA1
Mike Fiore 7:724cb82a113e 514 // XBEE_DIO7 - PA0
Mike Fiore 7:724cb82a113e 515 // XBEE_SLEEPRQ - PA11
Mike Fiore 7:724cb82a113e 516
Mike Fiore 7:724cb82a113e 517 if (dot->getWakePin() != XBEE_DIN || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 518 GPIO_InitStruct.Pin = GPIO_PIN_3;
Mike Fiore 7:724cb82a113e 519 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 520 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 521 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 522 }
Mike Fiore 7:724cb82a113e 523
Mike Fiore 7:724cb82a113e 524 if (dot->getWakePin() != XBEE_DIO2 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 525 GPIO_InitStruct.Pin = GPIO_PIN_5;
Mike Fiore 7:724cb82a113e 526 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 527 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 528 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 529 }
Mike Fiore 7:724cb82a113e 530
Mike Fiore 7:724cb82a113e 531 if (dot->getWakePin() != XBEE_DIO3 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 532 GPIO_InitStruct.Pin = GPIO_PIN_4;
Mike Fiore 7:724cb82a113e 533 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 534 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 535 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 536 }
Mike Fiore 7:724cb82a113e 537
Mike Fiore 7:724cb82a113e 538 if (dot->getWakePin() != XBEE_DIO4 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 539 GPIO_InitStruct.Pin = GPIO_PIN_7;
Mike Fiore 7:724cb82a113e 540 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 541 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 542 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 543 }
Mike Fiore 7:724cb82a113e 544
Mike Fiore 7:724cb82a113e 545 if (dot->getWakePin() != XBEE_DIO5 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 546 GPIO_InitStruct.Pin = GPIO_PIN_1;
Mike Fiore 7:724cb82a113e 547 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 548 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 549 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 550 }
Mike Fiore 7:724cb82a113e 551
Mike Fiore 7:724cb82a113e 552 if (dot->getWakePin() != XBEE_DIO6 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 553 GPIO_InitStruct.Pin = GPIO_PIN_1;
Mike Fiore 7:724cb82a113e 554 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 555 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 556 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 557 }
Mike Fiore 7:724cb82a113e 558
Mike Fiore 7:724cb82a113e 559 if (dot->getWakePin() != XBEE_DIO7 || dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 560 GPIO_InitStruct.Pin = GPIO_PIN_0;
Mike Fiore 7:724cb82a113e 561 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 562 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 563 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 564 }
Mike Fiore 7:724cb82a113e 565
Mike Fiore 7:724cb82a113e 566 if (dot->getWakePin() != XBEE_SLEEPRQ|| dot->getWakeMode() == mDot::RTC_ALARM) {
Mike Fiore 7:724cb82a113e 567 GPIO_InitStruct.Pin = GPIO_PIN_11;
Mike Fiore 7:724cb82a113e 568 GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
Mike Fiore 7:724cb82a113e 569 GPIO_InitStruct.Pull = GPIO_NOPULL;
Mike Fiore 7:724cb82a113e 570 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Mike Fiore 7:724cb82a113e 571 }
Mike Fiore 7:724cb82a113e 572 #endif
Mike Fiore 7:724cb82a113e 573 }
Mike Fiore 7:724cb82a113e 574
Mike Fiore 7:724cb82a113e 575 void sleep_restore_io() {
Mike Fiore 7:724cb82a113e 576 #if defined(TARGET_XDOT_L151CC)
Mike Fiore 7:724cb82a113e 577 xdot_restore_gpio_state();
Mike Fiore 7:724cb82a113e 578 #else
Mike Fiore 7:724cb82a113e 579 GPIOA->MODER = portA[0];
Mike Fiore 7:724cb82a113e 580 GPIOA->OTYPER = portA[1];
Mike Fiore 7:724cb82a113e 581 GPIOA->OSPEEDR = portA[2];
Mike Fiore 7:724cb82a113e 582 GPIOA->PUPDR = portA[3];
Mike Fiore 7:724cb82a113e 583 GPIOA->AFR[0] = portA[4];
Mike Fiore 7:724cb82a113e 584 GPIOA->AFR[1] = portA[5];
Mike Fiore 7:724cb82a113e 585
Mike Fiore 7:724cb82a113e 586 GPIOB->MODER = portB[0];
Mike Fiore 7:724cb82a113e 587 GPIOB->OTYPER = portB[1];
Mike Fiore 7:724cb82a113e 588 GPIOB->OSPEEDR = portB[2];
Mike Fiore 7:724cb82a113e 589 GPIOB->PUPDR = portB[3];
Mike Fiore 7:724cb82a113e 590 GPIOB->AFR[0] = portB[4];
Mike Fiore 7:724cb82a113e 591 GPIOB->AFR[1] = portB[5];
Mike Fiore 7:724cb82a113e 592
Mike Fiore 7:724cb82a113e 593 GPIOC->MODER = portC[0];
Mike Fiore 7:724cb82a113e 594 GPIOC->OTYPER = portC[1];
Mike Fiore 7:724cb82a113e 595 GPIOC->OSPEEDR = portC[2];
Mike Fiore 7:724cb82a113e 596 GPIOC->PUPDR = portC[3];
Mike Fiore 7:724cb82a113e 597 GPIOC->AFR[0] = portC[4];
Mike Fiore 7:724cb82a113e 598 GPIOC->AFR[1] = portC[5];
Mike Fiore 7:724cb82a113e 599
Mike Fiore 7:724cb82a113e 600 GPIOD->MODER = portD[0];
Mike Fiore 7:724cb82a113e 601 GPIOD->OTYPER = portD[1];
Mike Fiore 7:724cb82a113e 602 GPIOD->OSPEEDR = portD[2];
Mike Fiore 7:724cb82a113e 603 GPIOD->PUPDR = portD[3];
Mike Fiore 7:724cb82a113e 604 GPIOD->AFR[0] = portD[4];
Mike Fiore 7:724cb82a113e 605 GPIOD->AFR[1] = portD[5];
Mike Fiore 7:724cb82a113e 606
Mike Fiore 7:724cb82a113e 607 GPIOH->MODER = portH[0];
Mike Fiore 7:724cb82a113e 608 GPIOH->OTYPER = portH[1];
Mike Fiore 7:724cb82a113e 609 GPIOH->OSPEEDR = portH[2];
Mike Fiore 7:724cb82a113e 610 GPIOH->PUPDR = portH[3];
Mike Fiore 7:724cb82a113e 611 GPIOH->AFR[0] = portH[4];
Mike Fiore 7:724cb82a113e 612 GPIOH->AFR[1] = portH[5];
Mike Fiore 7:724cb82a113e 613 #endif
mfiore 0:a151a6350d7f 614 }
mfiore 0:a151a6350d7f 615
mfiore 0:a151a6350d7f 616 void send_data(std::vector<uint8_t> data) {
mfiore 0:a151a6350d7f 617 uint32_t ret;
mfiore 0:a151a6350d7f 618
mfiore 0:a151a6350d7f 619 ret = dot->send(data);
mfiore 0:a151a6350d7f 620 if (ret != mDot::MDOT_OK) {
mfiore 2:ffac7b141b72 621 logError("failed to send data to gateway [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
mfiore 0:a151a6350d7f 622 } else {
mfiore 2:ffac7b141b72 623 logInfo("successfully sent data to gateway");
mfiore 0:a151a6350d7f 624 }
mfiore 0:a151a6350d7f 625 }