// Enable pin remapping in this file, so pin constants are meaningful #undef ARDUINO_CORE_BUILD #include "Arduino.h" #include "double_tap.h" #include #include #include extern "C" { void initVariant() { // nothing to do } } // global, accessible from recovery sketch bool _recovery_marker_found; // double tap detected bool _recovery_active; // running from factory partition #define DELAY_US 10000 #define FADESTEP 8 static void rgb_pulse_delay(void) { // Bv R^ G x int widths[4] = {192, 64, 0, 0}; int dec_led = 0; // initialize RGB signals from weak pinstraps pinMode(LED_RED, OUTPUT); pinMode(LED_GREEN, OUTPUT); pinMode(LED_BLUE, OUTPUT); while (dec_led < 3) { widths[dec_led] -= FADESTEP; widths[dec_led + 1] += FADESTEP; if (widths[dec_led] <= 0) { widths[dec_led] = 0; dec_led = dec_led + 1; widths[dec_led] = 255; } analogWrite(LED_RED, 255 - widths[1]); analogWrite(LED_GREEN, 255 - widths[2]); analogWrite(LED_BLUE, 255 - widths[0]); delayMicroseconds(DELAY_US); } // reset pins to digital HIGH before leaving digitalWrite(LED_RED, HIGH); digitalWrite(LED_GREEN, HIGH); digitalWrite(LED_BLUE, HIGH); } static void NANO_ESP32_enter_bootloader(void) { if (!_recovery_active) { // check for valid partition scheme const esp_partition_t *ota_part = esp_ota_get_next_update_partition(NULL); const esp_partition_t *fact_part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL); if (ota_part && fact_part) { // set tokens so the recovery FW will find them double_tap_mark(); // invalidate other OTA image esp_partition_erase_range(ota_part, 0, 4096); // activate factory partition esp_ota_set_boot_partition(fact_part); } } esp_restart(); } static void boot_double_tap_logic() { const esp_partition_t *part = esp_ota_get_running_partition(); _recovery_active = (part->subtype == ESP_PARTITION_SUBTYPE_APP_FACTORY); double_tap_init(); _recovery_marker_found = double_tap_check_match(); if (_recovery_marker_found && !_recovery_active) { // double tap detected in user application, reboot to factory NANO_ESP32_enter_bootloader(); } // delay with mark set then proceed // - for normal startup, to detect first double tap // - in recovery mode, to ignore several short presses double_tap_mark(); rgb_pulse_delay(); double_tap_invalidate(); } namespace { class DoubleTap { public: DoubleTap() { boot_double_tap_logic(); } }; DoubleTap dt __attribute__((init_priority(101))); } // namespace