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:
Taylor Heck
Date:
Tue May 25 09:54:33 2021 -0500
Revision:
42:20f6b29a9903
Parent:
33:15ea8f985c54
Target mbed-os 6 and Dot Library version 4.

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