Skip to content

Instantly share code, notes, and snippets.

@MMI
Created January 27, 2022 17:08
Show Gist options
  • Save MMI/978fbc41de95c0c7106449ad457696cd to your computer and use it in GitHub Desktop.
Save MMI/978fbc41de95c0c7106449ad457696cd to your computer and use it in GitHub Desktop.
Mac only C code to reboot an ESP32 device into bootloader mode
/*
* This code works on my Mac, developed in conjuntion with a logic analyzer.
*/
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <time.h>
static char *prog;
void usage(void)
{
fprintf(stderr, "Usage: %s <device>\n", prog);
exit(1);
}
int main(int ac, char **av)
{
prog = av[0];
if (ac < 2) {
fprintf(stderr, "%s: requires device path argument\n", prog);
usage();
}
int fd = open(av[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd < 0) {
fprintf(stderr, "%s: failed to open %s because: %s\n", prog, av[1], strerror(errno));
usage();
}
struct termios options;
fcntl(fd, F_SETFL, 0);
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
printf("Configuring port now\n");
options.c_cflag |= (CLOCAL | CREAD | CRTSCTS);
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_oflag &= ~OPOST;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
tcsetattr(fd, TCSANOW, &options);
int status;
if (ioctl(fd, TIOCMGET, &status)) {
fprintf(stderr, "%s: TIOCMGET failed because %s\n", prog, strerror(errno));
usage();
}
printf("got status: %x\n", status);
printf("status & TIOCM_DTR: %d\n", status & TIOCM_DTR);
printf("status & TIOCM_DSR: %d\n", status & TIOCM_DSR);
printf("status & TIOCM_RTS: %d\n", status & TIOCM_RTS);
printf("status & TIOCM_CTS: %d\n", status & TIOCM_CTS);
sleep(1);
// Step | DTR | RTS
// 1 | 1 | 1
// 2 | 0 | 0
// 3 | 1 | 0
// 4 | 0 | 1
// Logic analyzer shows that set bits in the ioctl
// are actually digital low -- thus the XORing
// These same steps without the XORing will do a regular
// reboot
status = 6; // step 1: DTR & RTS high
status ^= 6;
ioctl(fd, TIOCMSET, &status);
status = 0; // step 2: DTR & RTS low
status ^= 6;
ioctl(fd, TIOCMSET, &status);
status = 2; // step 3: DTR high, RTS low
status ^= 6;
ioctl(fd, TIOCMSET, &status);
status = 4; // step 4: DTR low, RTS high
status ^= 6;
ioctl(fd, TIOCMSET, &status);
usleep(50000);
status = 6; // normal state: DTR & RTS high
status ^= 6;
ioctl(fd, TIOCMSET, &status);
printf("The device should be in bootloader mode\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment