Skip to content

Commit

Permalink
Implement double reset detection
Browse files Browse the repository at this point in the history
Closes #5
  • Loading branch information
krzmaz committed Nov 6, 2022
1 parent 883b1b6 commit dd4c097
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ file(RENAME fsdata.c my_fsdata.c)

add_executable(${PROGRAM_NAME}
main.cpp
double_reset_detector.cpp
)
target_compile_definitions(${PROGRAM_NAME} PRIVATE
WIFI_SSID=\"${WIFI_SSID}\"
Expand Down
58 changes: 58 additions & 0 deletions src/double_reset_detector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Double reset logic based on pico_bootsel_via_double_reset.c from pico sdk

#include "pico.h"
#include "pico/time.h"
#include "pico/bootrom.h"
#include "pico/binary_info.h"
#include "pico/stdlib.h"

namespace double_reset_detector {

bool double_reset_detected = false;

// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS, Window of opportunity for a second press of a reset button to enter BOOTSEL mode (milliseconds), type=int, default=200, group=pico_bootsel_via_double_reset
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS 500
#endif

// Doesn't make any sense for a RAM only binary
#if !PICO_NO_FLASH
static const uint32_t magic_token[] = {
0xf01681de, 0xbd729b29, 0xd359be7a,
};

static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];

/* Check for double reset and enter AP mode if detected
*
* This function is registered to run automatically before main(). The
* algorithm is:
*
* 1. Check for magic token in memory; enter AP mode if found.
* 2. Initialise that memory with that magic token.
* 3. Do nothing for a short while (few hundred ms).
* 4. Clear the magic token.
* 5. Continue with normal boot.
*
* Resetting the device twice quickly will interrupt step 3, leaving the token
* in place so that the second boot will go to the bootloader.
*/
static void __attribute__((constructor)) boot_double_tap_check(void) {
for (uint i = 0; i < count_of(magic_token); i++) {
if (magic_location[i] != magic_token[i]) {
// Arm, wait, then disarm and continue booting
for (i = 0; i < count_of(magic_token); i++) {
magic_location[i] = magic_token[i];
}
busy_wait_us(PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000);
magic_location[0] = 0;
return;
}
}
// Detected a double reset
magic_location[0] = 0;
double_reset_detected = true;
}

#endif
} // namespace double_reset_detector
57 changes: 38 additions & 19 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,12 @@

#include "lwipopts.h"
#include "ssi.h"

void run_server() {
httpd_init();
ssi_init();
printf("Http server initialized.\n");
// infinite loop for now
for (;;) {}
namespace double_reset_detector {
extern bool double_reset_detected;
}

int main() {
stdio_init_all();

if (cyw43_arch_init()) {
printf("failed to initialise\n");
return 1;
}
// turn on LED to distinguish from BOOTSEL mode
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);

cyw43_arch_enable_sta_mode();
void connect_to_wifi() {
cyw43_arch_enable_sta_mode();
// this seems to be the best be can do using the predefined `cyw43_pm_value` macro:
// cyw43_wifi_pm(&cyw43_state, CYW43_PERFORMANCE_PM);
// however it doesn't use the `CYW43_NO_POWERSAVE_MODE` value, so we do this instead:
Expand All @@ -43,6 +29,39 @@ int main() {
auto ip_addr = cyw43_state.netif[CYW43_ITF_STA].ip_addr.addr;
printf("IP Address: %lu.%lu.%lu.%lu\n", ip_addr & 0xFF, (ip_addr >> 8) & 0xFF, (ip_addr >> 16) & 0xFF, ip_addr >> 24);
}

}

void run_server() {
connect_to_wifi();
httpd_init();
ssi_init();
printf("Http server initialized.\n");
// infinite loop for now
for (;;) {}
}

void setup() {
if (double_reset_detector::double_reset_detected) {
printf("Double reset detected!");
// just blink the LED for now
while (true) {
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
sleep_ms(500);
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);
sleep_ms(500);
}
}
}

int main() {
stdio_init_all();

if (cyw43_arch_init()) {
printf("failed to initialise\n");
return 1;
}
// turn on LED to distinguish from BOOTSEL mode
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
setup();
run_server();
}

0 comments on commit dd4c097

Please sign in to comment.