Skip to content

File Esp32Manager.cpp

File List > fw > rbcx-coprocessor > src > Esp32Manager.cpp

Go to the documentation of this file.

#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_gpio.h"

#include "FreeRTOS.h"
#include "task.h"

#include "Bsp.hpp"
#include "utils/Debug.hpp"

#include "Esp32Manager.hpp"

// https://github.com/espressif/esptool/blob/4a1e87d290e9ba2870b4d092baf7b9ae15e4095d/esptool.py#L469

// Bootloader
// [   1441314][src/UsbCdcLink.c:205]: CONTROL_LINE_STATE DTR 0 RTS 1 <-- 0
// [   1441414][src/UsbCdcLink.c:205]: CONTROL_LINE_STATE DTR 1 RTS 1 <-- 1
// [   1441415][src/UsbCdcLink.c:205]: CONTROL_LINE_STATE DTR 1 RTS 0 <-- 2
// [   1441465][src/UsbCdcLink.c:205]: CONTROL_LINE_STATE DTR 0 RTS 0

// Reboot
//                                    (don't care)          DTR 0       <-- 0
// [    444506][src/UsbCdcLink.cpp:205]: CONTROL_LINE_STATE DTR 0 RTS 1 <-- 1
// [    444607][src/UsbCdcLink.cpp:205]: CONTROL_LINE_STATE DTR 0 RTS 0 <-- 2

static constexpr uint32_t Esp32WatchdogTimeoutMs = 150;

Esp32Manager sEsp32Manager;

Esp32Manager::Esp32Manager()
    : m_enPinHolders {}
    , m_queuedReset(RstNormal)
    , m_previousEnEdge(false)
    , m_inBootloader(false)
    , m_watchdogInhibit(true) {}

Esp32Manager::~Esp32Manager() {}

void Esp32Manager::init() {
    pinInit(espEnPin, GPIO_MODE_INPUT, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW);
    m_previousEnEdge = pinRead(espEnPin);
}

void Esp32Manager::poll() {
    if (m_queuedReset != RstNone) {
        holdReset(EnSwReset);
        releaseReset(EnSwReset, m_queuedReset == RstBootloader);
        m_queuedReset = RstNone;
    }

    if (m_unstrapTimer.poll()) {
        unstrapPins();
    }

    if (m_checkBreakTimer.poll()) {
        if (m_lastRts && !m_lastDtr) {
            holdReset(EnSerialBreaks);
        } else {
            releaseReset(EnSerialBreaks, m_lastDtr && !m_lastRts);
        }
    }

    if (!m_watchdogInhibit && m_watchdogTimer.poll() && !m_inBootloader
        && m_previousEnEdge && m_enPinHolders == 0) {
        DEBUG("Esp32 watchdog timed out, resetting.\n");
        queueReset();
    }
}

void Esp32Manager::holdReset(EnHolderType typ) {
    if (m_enPinHolders == 0) {
        pinInit(espEnPin, GPIO_MODE_OUTPUT_OD, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW,
            true);
        pinWrite(espEnPin, 0);
        softReset();
    }
    m_enPinHolders |= (1 << typ);
}

void Esp32Manager::releaseReset(EnHolderType typ, bool strapForBootloader) {
    const uint32_t mask = (1 << typ);
    if (m_enPinHolders == mask) {
        strapPins(strapForBootloader);
        pinInit(espEnPin, GPIO_MODE_IT_RISING_FALLING, GPIO_NOPULL,
            GPIO_SPEED_FREQ_LOW, true);
        m_unstrapTimer.restart(2);
    }
    m_enPinHolders &= ~mask;
}

void Esp32Manager::queueReset(bool bootloader) {
    m_queuedReset = !bootloader ? RstNormal : RstBootloader;
}

void Esp32Manager::strapPins(bool bootloader) {
    //DEBUG("Straping pins, bootloader: %d\n", bootloader);
    pinInit(esp0Pin, GPIO_MODE_OUTPUT_OD, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW);
    pinInit(esp12Pin, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL,
        GPIO_SPEED_FREQ_LOW); // TODO: set pin 12 to OD on RBCX v1.1, v1.0 has HW bug
    pinInit(esp15Pin, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW);

    pinWrite(esp12Pin, 0); // 3.3v flash
    pinWrite(esp15Pin, 1); // Do not silence bootloader messages

    if (!bootloader) {
        pinWrite(esp0Pin, 1); // normal
    } else {
        pinWrite(esp0Pin, 0); // bootloader

        pinInit(esp2Pin, GPIO_MODE_OUTPUT_OD, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW);
        pinWrite(esp2Pin, 0); // bootloader confirm
    }

    m_inBootloader = bootloader;

    if (bootloader) {
        m_watchdogTimer.stop();
    } else {
        m_watchdogTimer.restart(Esp32WatchdogTimeoutMs * 5);
    }
}

void Esp32Manager::unstrapPins() { reinitEspStrappingPins(); }

void Esp32Manager::onEnRisingInIrq() {
    const bool currentEdge = pinRead(espEnPin);
    if (currentEdge && !m_previousEnEdge && m_enPinHolders == 0) {
        queueReset(m_lastDtr && !m_lastRts);
    } else if (!currentEdge && m_previousEnEdge) {
        softReset();
    }
    m_previousEnEdge = currentEdge;
}

void Esp32Manager::onSerialBreakInIrq(bool dtr, bool rts) {
    m_lastDtr = dtr;
    m_lastRts = rts;
    m_checkBreakTimer.restart(25);
}

void Esp32Manager::resetWatchdog() {
    m_watchdogTimer.restart(Esp32WatchdogTimeoutMs);
}

void Esp32Manager::setWatchdogInhibit(bool inhibit) {
    if (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) {
        DEBUG("Watchdog is always inhibited with debugger attached, ignoring "
              "setWatchdogInhibit\n");
        m_watchdogInhibit = true;
    } else {
        m_watchdogInhibit = inhibit;
    }
}

void Esp32Manager::handleSettings(
    const CoprocReq_EspWatchdogSettings& settings) {
    setWatchdogInhibit(settings.disable);
}