mDot AT-Firmware for testing

Dependencies:   MTS-Serial libmDot-mbed5

Fork of Dot-AT-Firmware by MultiTech

Revision:
1:e52ae6584f1c
Child:
2:e5eebd74d36d
diff -r e2b8246361bc -r e52ae6584f1c CommandTerminal/CommandTerminal.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandTerminal/CommandTerminal.cpp	Thu Jun 25 10:23:41 2015 -0500
@@ -0,0 +1,684 @@
+#include "ctype.h"
+#include "CommandTerminal.h"
+#include "Command.h"
+#include <cstdarg>
+
+extern "C" {
+#include "wakeup.h"
+    extern void pin_function(PinName pin, int data);
+}
+
+const char CommandTerminal::banner[] = "\r\n\nMultiTech Systems LoRa XBee Module\r\n\n";
+const char CommandTerminal::helpline[] = "Enter '?' for help\r\n";
+
+const char CommandTerminal::newline[] = "\r\n";
+
+// Command error text...
+const char CommandTerminal::command_error[] = "Command not found!\r\n";
+
+// Response texts...
+const char CommandTerminal::help[] = "\r\nHelp\r\n";
+const char CommandTerminal::cmd_error[] = "Invalid command\r\n";
+const char CommandTerminal::done[] = "\r\nOK\r\n";
+const char CommandTerminal::error[] = "\r\nERROR\r\n";
+
+// Escape sequence...
+const char CommandTerminal::escape_sequence[] = "+++";
+
+mts::MTSSerial* CommandTerminal::_serialp = NULL;
+
+void CommandTerminal::addCommand(Command* cmd) {
+    _commands.push_back(cmd);
+}
+
+CommandTerminal::CommandTerminal(mts::MTSSerial& serial, mDot* dot)
+:
+  _serial(serial),
+  _dot(dot),
+  _mode(mDot::COMMAND_MODE),
+  _sleep_standby(false),
+  _xbee_on_sleep(XBEE_ON_SLEEP),
+  _serial_up(false) {
+
+    _serialp = &serial;
+
+    wakeup_init(_dot->getSerialWakeInterval());
+
+    addCommand(new CmdAttention(_dot));
+    addCommand(new CmdIdentification(_dot, serial));
+    addCommand(new CmdResetCpu(_dot, serial));
+    addCommand(new CmdDummy(_dot, "Enable/Disable Echo", "ATE0/1", "ATE0: disable, ATE1: enable"));
+    addCommand(new CmdDummy(_dot, "Enable/Disable Verbose", "ATV0/1", "ATV0: disable, ATV1: enable"));
+
+    addCommand(new CmdFactoryDefault(_dot));
+    addCommand(new CmdSaveConfig(_dot));
+    addCommand(new CmdDisplayConfig(_dot, serial));
+    addCommand(new CmdDisplayStats(_dot, serial));
+    addCommand(new CmdSerialBaudRate(_dot, serial));
+    addCommand(new CmdDebugBaudRate(_dot, serial));
+    addCommand(new CmdStartUpMode(_dot, serial));
+
+    addCommand(new CmdFrequencyBand(_dot, serial));
+    addCommand(new CmdFrequencySubBand(_dot, serial));
+    addCommand(new CmdPublicNetwork(_dot, serial));
+    addCommand(new CmdDeviceId(_dot, serial));
+
+    addCommand(new CmdNetworkAddress(_dot, serial));
+    addCommand(new CmdNetworkSessionKey(_dot, serial));
+    addCommand(new CmdDataSessionKey(_dot, serial));
+    addCommand(new CmdNetworkKey(_dot, serial));
+    addCommand(new CmdNetworkId(_dot, serial));
+
+    addCommand(new CmdJoinRequest(_dot, serial));
+    addCommand(new CmdJoinRetries(_dot, serial));
+    addCommand(new CmdNetworkJoinMode(_dot, serial));
+    addCommand(new CmdNetworkJoinStatus(_dot, serial));
+    addCommand(new CmdNetworkLinkCheck(_dot, serial));
+    addCommand(new CmdLinkCheckCount(_dot, serial));
+    addCommand(new CmdLinkCheckThreshold(_dot, serial));
+    addCommand(new CmdEncryption(_dot, serial));
+
+    addCommand(new CmdRssi(_dot, serial));
+    addCommand(new CmdSnr(_dot, serial));
+    addCommand(new CmdDataPending(_dot, serial));
+
+    addCommand(new CmdTxDataRate(_dot, serial));
+    addCommand(new CmdTxPower(_dot, serial));
+    addCommand(new CmdTxFrequency(_dot, serial));
+    addCommand(new CmdTxInverted(_dot, serial));
+    addCommand(new CmdTxWait(_dot, serial));
+    addCommand(new CmdTxChannel(_dot, serial));
+    addCommand(new CmdTxNextMs(_dot, serial));
+    addCommand(new CmdTimeOnAir(_dot, serial));
+
+    addCommand(new CmdRxDataRate(_dot, serial));
+    addCommand(new CmdRxFrequency(_dot, serial));
+    addCommand(new CmdRxOutput(_dot, serial));
+    addCommand(new CmdRxInverted(_dot, serial));
+
+    addCommand(new CmdErrorCorrection(_dot, serial));
+    addCommand(new CmdCRC(_dot, serial));
+    addCommand(new CmdAdaptiveDataRate(_dot, serial));
+
+    addCommand(new CmdACKAttempts(_dot, serial));
+
+    addCommand(new CmdSendString(_dot, serial));
+    addCommand(new CmdSendStringHighBW(_dot, serial));
+    addCommand(new CmdSendBinary(_dot, serial));
+    addCommand(new CmdSendStringOnInterval(_dot, serial));
+    addCommand(new CmdReceiveOnce(_dot, serial));
+    addCommand(new CmdReceiveContinuous(_dot, serial));
+
+    addCommand(new CmdDummy(_dot, "Serial Data Mode", "AT+SD", "Reads serial data and sends Lora packets (escape sequence: +++)"));
+    addCommand(new CmdSerialWakeInterval(_dot, serial));
+    addCommand(new CmdSerialWakeDelay(_dot, serial));
+    addCommand(new CmdSerialReceiveTimeout(_dot, serial));
+    addCommand(new CmdPing(_dot, serial));
+    addCommand(new CmdLogLevel(_dot, serial));
+}
+
+void CommandTerminal::printHelp() {
+    const char* name = NULL;
+    const char* text = NULL;
+    const char* desc = NULL;
+    const char* tab = "\t";
+
+    std::string header("Command");
+    header.append(tab);
+    header.append(tab);
+    header.append("Name");
+    header.append(tab);
+    header.append(tab);
+    header.append(tab);
+    header.append("Description");
+
+    write(newline);
+    write(header.c_str());
+    write(newline);
+    write(newline);
+    for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end(); ++it) {
+        name = (*it)->name();
+        text = (*it)->text();
+        desc = (*it)->desc();
+        write(text);
+        if (strlen(text) < 8)
+            write(tab);
+        write(tab);
+        write(name);
+        if (strlen(name) < 8)
+            write(tab);
+        if (strlen(name) < 16)
+            write(tab);
+        write(tab);
+        write(desc);
+        write(newline);
+    }
+
+    write(newline);
+}
+
+bool CommandTerminal::writeable() {
+    return _serial.writeable();
+}
+
+bool CommandTerminal::readable() {
+    return _serial.readable();
+}
+
+char CommandTerminal::read() {
+    char ch;
+    _serial.read(&ch, 1);
+    return ch;
+}
+
+void CommandTerminal::write(const char* message) {
+    while (!writeable())
+        ;
+    _serial.write(message, strlen(message));
+}
+
+void CommandTerminal::writef(const char* format, ...) {
+    char buff[256];
+
+    va_list ap;
+    va_start(ap, format);
+    int size = vsnprintf(buff, 256, format, ap);
+    while (!writeable())
+        ;
+    _serial.write(buff, size);
+    va_end(ap);
+}
+
+void CommandTerminal::serial_loop() {
+    Timer serial_read_timer;
+    std::vector<uint8_t> serial_buffer;
+    std::string escape_buffer;
+    Timer escape_timer;
+    int escape_delay = 100;
+    uint8_t max_send_size;
+
+    _serial_up = true;
+    _xbee_on_sleep = GPIO_PIN_SET;
+
+    if (_dot->getFrequencyBand() == mDot::FB_915)
+        max_send_size = mDot::MaxLengths_915[_dot->getTxDataRate()];
+    else
+        max_send_size = mDot::MaxLengths_868[_dot->getTxDataRate()];
+
+    DEBUG_PRINTF("Awake\r\n");
+    wakeup(_sleep_standby);
+
+    char ch;
+
+    if (readable()) {
+        ch = read();
+        serial_buffer.push_back(ch);
+
+        if (escape_timer.read_ms() > escape_delay && ch == '+') {
+            escape_buffer += ch;
+            escape_timer.reset();
+        } else {
+            _serial_up = true;
+            escape_buffer.clear();
+        }
+
+        if (escape_buffer.length() == 3 && escape_buffer.find(escape_sequence) == 0) {
+            _mode = mDot::COMMAND_MODE;
+            DEBUG_PRINTF("Exit serial mode\r\n");
+            escape_timer.stop();
+            escape_buffer.clear();
+            write(done);
+            return;
+        }
+    }
+
+    if (_serial_up) {
+        osDelay(_dot->getSerialWakeDelay());
+
+        serial_read_timer.start();
+        while (_serial_up && serial_read_timer.read_ms() < _dot->getSerialReceiveTimeout()) {
+            while (readable() && serial_buffer.size() < max_send_size) {
+                serial_buffer.push_back(read());
+                serial_read_timer.reset();
+            }
+        }
+        serial_read_timer.stop(), serial_read_timer.reset();
+
+        if (!serial_buffer.empty()) {
+            _serial_up = false;
+            _xbee_on_sleep = GPIO_PIN_RESET;
+            if (!_dot->getIsTransmitting()) {
+                std::vector<uint8_t> recv_buffer;
+                DEBUG_PRINTF("Received serial data, sending out radio.\r\n");
+
+                if (!_dot->send(serial_buffer))
+                    DEBUG_PRINTF("Send failed.\r\n");
+                if (_dot->recv(recv_buffer))
+                    _serial.writef("%s\r\n", formatPacketData(recv_buffer, _dot->getRxOutput()).c_str());
+            } else {
+                DEBUG_PRINTF("Radio is busy, cannot send.\r\n");
+            }
+
+            serial_buffer.clear();
+        } else {
+            DEBUG_PRINTF("No data received from serial to send.\r\n");
+        }
+        _serial_up = false;
+    }
+    sleep(_sleep_standby);
+}
+
+bool CommandTerminal::autoJoinCheck() {
+
+    std::string escape_buffer;
+    char ch;
+    int sleep = 1000;
+    int escape_timeout = 1000;
+    Timer tmr;
+    Timer escape_tmr;
+    int cnt = 0;
+
+    while (!_dot->getNetworkJoinStatus()) {
+        wakeup(_sleep_standby);
+        write("\r\nJoining network... ");
+
+        // wait one second for possible escape
+        tmr.reset();
+        tmr.start();
+        escape_tmr.reset();
+        escape_tmr.start();
+        while (tmr.read_ms() < 1000) {
+            if (_serial.readable()) {
+                _serial.read(&ch, 1);
+                escape_buffer += ch;
+            }
+
+            if (escape_buffer.find(escape_sequence) != std::string::npos) {
+                _mode = mDot::COMMAND_MODE;
+                write("Join Canceled\r\n");
+                write(done);
+                return true;
+            }
+
+            if (escape_tmr.read_ms() > escape_timeout)
+                escape_buffer.clear();
+        }
+
+        if (_dot->joinNetworkOnce() == mDot::MDOT_OK) {
+            write("Network Joined\r\n");
+            write(done);
+            return false;
+        }
+
+        write("Network Join failed\r\n");
+        write(error);
+
+        if (cnt++ > _dot->getJoinRetries()) {
+            cnt = 0;
+
+            if (_dot->getFrequencyBand() == mDot::FB_915) {
+                uint8_t band = ((_dot->getFrequencySubBand()) % 8) + 1;
+                DEBUG_PRINTF("Join retries exhausted, switching to sub band %u\r\n", band);
+                _dot->setFrequencySubBand(band);
+            }
+
+            if (sleep < 60 * 60 * 1000)
+                sleep *= 2;
+        }
+
+        tmr.reset();
+        tmr.start();
+        escape_tmr.reset();
+        escape_tmr.start();
+        while (tmr.read_ms() < sleep) {
+            if (_serial.readable()) {
+                _serial.read(&ch, 1);
+                escape_buffer += ch;
+            }
+
+            if (escape_buffer.find(escape_sequence) != std::string::npos) {
+                _mode = mDot::COMMAND_MODE;
+                return true;
+            }
+
+            if (escape_tmr.read_ms() > escape_timeout)
+                escape_buffer.clear();
+        }
+
+    }
+
+    return false;
+}
+
+void CommandTerminal::start() {
+
+    _dot->resetNetworkSession();
+
+    char ch;
+    bool running = true;
+    bool echo = _dot->getEcho();
+    std::string command;
+    std::vector<std::string> args;
+
+    if (_dot->getStartUpMode() == mDot::SERIAL_MODE) {
+        command = "AT+SD\n";
+
+        std::string escape_buffer;
+        char ch;
+
+        int escape_timeout = 1000;
+        Timer tmr;
+        Timer escape_tmr;
+
+        // wait one second for possible escape
+        tmr.reset();
+        tmr.start();
+        escape_tmr.reset();
+        escape_tmr.start();
+        while (tmr.read_ms() < escape_timeout) {
+            if (_serial.readable()) {
+                _serial.read(&ch, 1);
+                escape_buffer += ch;
+            }
+
+            if (escape_buffer.find(escape_sequence) != std::string::npos) {
+                _mode = mDot::COMMAND_MODE;
+                command.clear();
+                break;
+            }
+
+            if (escape_tmr.read_ms() > escape_timeout)
+                escape_buffer.clear();
+
+            osDelay(1);
+        }
+
+    }
+
+    bool join_canceled = false;
+
+    //Run terminal session
+    while (running) {
+        if (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA) {
+            join_canceled = autoJoinCheck();
+            if (join_canceled)
+                command.clear();
+        }
+
+        if (_dot->getJoinMode() != mDot::AUTO_OTA || (!join_canceled && _dot->getJoinMode() == mDot::AUTO_OTA)) {
+            switch (_mode) {
+                case mDot::SERIAL_MODE:
+                    // signal wakeup, read serial and output to radio
+                    serial_loop();
+                    continue;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        ch = '\0';
+
+        // read characters
+        if (readable()) {
+            ch = read();
+
+            if (ch == '\b') {
+                if (!command.empty()) {
+                    writef("\b \b");
+                    command.erase(command.size() - 1);
+                }
+                continue;
+            } else {
+                command += ch;
+            }
+
+            // echo chars if enabled
+            if (echo && !(ch == '\r' || ch == '\n'))
+                writef("%c", ch);
+        }
+
+        // look for end of command line
+        if (command.find("\n") != std::string::npos || command.find("\r") != std::string::npos) {
+            // remove new line or cr character
+            command.erase(command.size() - 1);
+            write("\r"); // match standard modem output
+            write(newline);
+        } else {
+            continue;
+        }
+
+        // trim whitespace from command
+        mts::Text::trim(command, "\r\n\t ");
+
+        if (command.size() < 1) {
+            command.clear();
+            continue;
+        }
+
+        // parse command and args
+        args.clear();
+
+        // find first '=' character
+        size_t delim_index = command.find("=");
+        if (delim_index != std::string::npos) {
+            args.push_back(command.substr(0, delim_index));
+        } else {
+            // find first ' ' character
+            delim_index = command.find(" ");
+            if (delim_index != std::string::npos) {
+                args.push_back(command.substr(0, delim_index));
+            } else {
+                args.push_back(command);
+            }
+        }
+
+        if (delim_index != std::string::npos) {
+            std::vector<std::string> params = mts::Text::split(command.substr(delim_index + 1), ",");
+            args.insert(args.end(), params.begin(), params.end());
+        }
+
+        args[0] = mts::Text::toUpper(args[0]);
+
+        // print help
+        if ((args[0].find("?") == 0 || args[0].find("HELP") == 0) && args.size() == 1) {
+            printHelp();
+            command.clear();
+        } else if (args[0].find("ATE0") == 0 && args[0].length() == 4) {
+            _dot->setEcho(false);
+            write(done);
+            echo = _dot->getEcho();
+        } else if (args[0].find("ATE1") == 0 && args[0].length() == 4) {
+            _dot->setEcho(true);
+            write(done);
+            echo = _dot->getEcho();
+        } else if (args[0].find("ATV0") == 0 && args[0].length() == 4) {
+            _dot->setVerbose(false);
+            write(done);
+        } else if (args[0].find("ATV1") == 0 && args[0].length() == 4) {
+            _dot->setVerbose(true);
+            write(done);
+        } else if (args[0] == "AT+SD") {
+            DEBUG_PRINTF("Enter Serial Mode\r\n");
+            _mode = mDot::SERIAL_MODE;
+        } else {
+            bool found = false;
+            bool query = false;
+
+            std::string lookfor = args[0];
+
+            // per command help
+            if ((args[0].find("?") == 0 || args[0].find("HELP") == 0))
+                lookfor = mts::Text::toUpper(args[1]);
+
+            // trim off any trailing '?' and mark as a query command
+            if (args[0].rfind("?") == args[0].length() - 1) {
+                query = true;
+                lookfor = args[0].substr(0, args[0].length() - 1);
+            }
+
+            // search for command
+            for (std::vector<Command*>::iterator it = _commands.begin(); it != _commands.end() && !found; ++it) {
+                Command* cmd = *it;
+
+                // match CMD or CMD? syntax if command is queryable
+                if (lookfor == cmd->text() && (!query || (query && cmd->queryable()))) {
+                    found = true;
+                    if (args[0] == "HELP") {
+                        writef("%s%s", cmd->help(), newline);
+                        write(done);
+                    }
+
+                    else if (args.size() > 1 && args[1] == "?") {
+                        writef("%s%s", cmd->usage().c_str(), newline);
+                        write(done);
+                    } else if (!cmd->verify(args)) {
+                        writef("%s%s", cmd->errorMessage().c_str(), newline);
+                        writef("%s", error);
+                    } else {
+                        if (cmd->action(args) == 0) {
+                            writef("%s", done);
+                        } else {
+                            writef("%s%s", cmd->errorMessage().c_str(), newline);
+                            writef("%s", error);
+                        }
+                    }
+                }
+            }
+
+            if (!found) {
+                writef("%s", command_error);
+                writef("%s", error);
+            }
+        }
+
+        command.clear();
+
+    }
+}
+
+std::string CommandTerminal::formatPacketData(const std::vector<uint8_t>& data, const uint8_t& format) {
+    if (format == mDot::HEXADECIMAL) {
+        return mts::Text::bin2hexString(data);
+    } else {
+        std::string data_str;
+        for (int i = 0; i < data.size(); i++)
+            data_str.append((const char*)data[i], 1);
+        return data_str;
+    }
+}
+
+void CommandTerminal::sleep(bool standby) {
+    _serial_up = false;
+    _xbee_on_sleep = GPIO_PIN_RESET;
+
+    HAL_PWREx_EnableMainRegulatorLowVoltage();
+    HAL_PWREx_EnableFlashPowerDown();
+    HAL_PWREx_EnableLowRegulatorLowVoltage();
+
+    DEBUG_PRINTF("Sleep\r\n");
+    _dot->sleep();
+
+    if (standby) {
+
+        DEBUG_PRINTF("RECORD UPLINK: %lu\r\n", _dot->getUpLinkCounter());
+
+        RTC_WriteBackupRegister(RTC_BKP_DR0, _dot->getUpLinkCounter());
+
+        HAL_PWR_EnableBkUpAccess();
+
+        HAL_EnableDBGStandbyMode();
+
+        HAL_PWR_DisableWakeUpPin (PWR_WAKEUP_PIN1);
+
+        __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); // InterruptIn wakeon_serial(XBEE_DIN);
+        // Application is reloaded after wake-up from standby
+HAL_PWR_EnterSTANDBYMode        ();
+
+    } else {
+        pin_function(PA_0, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_3, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_4, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_5, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_6, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_7, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_8, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_9, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PA_10, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_11, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_12, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PA_15, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        pin_function(PB_0, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PB_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PB_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        pin_function(PC_1, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PC_4, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PC_5, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        pin_function(PC_9, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+        // pin_function(PC_13, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        pin_function(PD_2, STM_PIN_DATA(STM_MODE_ANALOG, GPIO_NOPULL, 0));
+
+        HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
+    }
+
+    wakeup_clear();
+    EXTI->PR = (1 << 22);
+
+    // After wake-up from STOP reconfigure the PLL
+    SetSysClock();
+}
+
+bool CommandTerminal::waitForEscape(int timeout, mDot* dot, WaitType wait) {
+    Timer timer;
+    Timer escape_timer;
+    std::string escape_buffer;
+    int escape_timeout = 1000;
+
+    timer.start();
+    while (timer.read_ms() < timeout) {
+
+        if (dot != NULL) {
+            if (wait == WAIT_SEND && (!dot->getIsTransmitting())) {
+                return false;
+            }
+        }
+
+        if (_serialp != NULL && _serialp->readable()) {
+            if (escape_buffer == "")
+                escape_timer.start();
+            char ch;
+            _serialp->read(&ch, 1);
+            escape_buffer += ch;
+            if (escape_buffer == CommandTerminal::escape_sequence)
+                return true;
+        }
+        if (escape_timer.read_ms() > escape_timeout) {
+            escape_buffer = "";
+            escape_timer.stop(), escape_timer.reset();
+        }
+
+        osDelay(10);
+    }
+
+    return false;
+}
+
+void CommandTerminal::wakeup(bool standby) {
+    HAL_PWREx_DisableMainRegulatorLowVoltage();
+    HAL_PWREx_DisableFlashPowerDown();
+    HAL_PWREx_DisableLowRegulatorLowVoltage();
+
+    if (standby) {
+        HAL_DisableDBGStandbyMode();
+
+        HAL_PWR_EnableWakeUpPin (PWR_WAKEUP_PIN1);
+    }
+
+    _dot->wakeup();
+
+}