Added esp-idf hook to capture panic log and save it to sd card
This copies (to the RTC memor)y what the panic handler sends over serial. That way we can save it to crash.log on the SD Card after the restart. I'm still testing but so far it doesn't seem to interfer with anything
This commit is contained in:
parent
45702937ce
commit
394bd6d259
@ -107,35 +107,23 @@ static DRAM_ATTR const ili_init_cmd_t ili_init_cmds[] = {
|
||||
static void
|
||||
backlight_init()
|
||||
{
|
||||
// Initial backlight percent
|
||||
int percent = backlightLevels[displayConfig.backlight % RG_BACKLIGHT_LEVEL_COUNT];
|
||||
|
||||
//configure timer0
|
||||
ledc_timer_config_t ledc_timer;
|
||||
memset(&ledc_timer, 0, sizeof(ledc_timer));
|
||||
ledc_timer_config_t ledc_timer = {
|
||||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
.freq_hz = 5000,
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
};
|
||||
|
||||
ledc_timer.duty_resolution = LEDC_TIMER_13_BIT; //set timer counter bit number
|
||||
ledc_timer.freq_hz = 5000; //set frequency of pwm
|
||||
ledc_timer.speed_mode = LEDC_LOW_SPEED_MODE; //timer mode,
|
||||
ledc_timer.timer_num = LEDC_TIMER_0; //timer index
|
||||
|
||||
//set the configuration
|
||||
ledc_channel_config_t ledc_channel;
|
||||
memset(&ledc_channel, 0, sizeof(ledc_channel));
|
||||
|
||||
//set LEDC channel 0
|
||||
ledc_channel.channel = LEDC_CHANNEL_0;
|
||||
//set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
|
||||
ledc_channel.duty = BACKLIGHT_DUTY_MAX * (percent * 0.01f);
|
||||
//GPIO number
|
||||
ledc_channel.gpio_num = RG_GPIO_LCD_BCKL;
|
||||
//GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
|
||||
ledc_channel.intr_type = LEDC_INTR_FADE_END;
|
||||
//set LEDC mode, from ledc_mode_t
|
||||
ledc_channel.speed_mode = LEDC_LOW_SPEED_MODE;
|
||||
//set LEDC timer source, if different channel use one timer,
|
||||
//the frequency and bit_num of these channels should be the same
|
||||
ledc_channel.timer_sel = LEDC_TIMER_0;
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.channel = LEDC_CHANNEL_0,
|
||||
.duty = BACKLIGHT_DUTY_MAX * (percent * 0.01f),
|
||||
.gpio_num = RG_GPIO_LCD_BCKL,
|
||||
.hpoint = 0,
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.timer_sel = LEDC_TIMER_0,
|
||||
};
|
||||
|
||||
ledc_timer_config(&ledc_timer);
|
||||
ledc_channel_config(&ledc_channel);
|
||||
@ -145,7 +133,7 @@ backlight_init()
|
||||
static void
|
||||
backlight_deinit()
|
||||
{
|
||||
ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0, 100);
|
||||
ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, 0, 50);
|
||||
ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_WAIT_DONE);
|
||||
ledc_fade_func_uninstall();
|
||||
}
|
||||
@ -155,7 +143,7 @@ backlight_set_level(int percent)
|
||||
{
|
||||
int duty = BACKLIGHT_DUTY_MAX * (RG_MIN(RG_MAX(percent, 5), 100) * 0.01f);
|
||||
|
||||
ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty, 10);
|
||||
ledc_set_fade_with_time(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty, 50);
|
||||
ledc_fade_start(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, LEDC_FADE_NO_WAIT);
|
||||
|
||||
RG_LOGI("backlight set to %d%%\n", percent);
|
||||
@ -216,11 +204,10 @@ spi_put_transaction(spi_transaction_t* t)
|
||||
xSemaphoreGive(spi_count_semaphore);
|
||||
}
|
||||
|
||||
//This function is called (in irq context!) just before a transmission starts. It will
|
||||
//set the D/C line to the value indicated in the user field.
|
||||
IRAM_ATTR static void
|
||||
spi_pre_transfer_callback(spi_transaction_t *t)
|
||||
{
|
||||
// Set the data/command line accordingly
|
||||
gpio_set_level(RG_GPIO_LCD_DC, (int)t->user & 0x01);
|
||||
}
|
||||
|
||||
@ -244,10 +231,7 @@ spi_task(void *arg)
|
||||
spi_put_buffer((uint16_t*)t->tx_buffer);
|
||||
}
|
||||
|
||||
if (xQueueSend(spi_queue, &t, portMAX_DELAY) != pdPASS)
|
||||
{
|
||||
RG_PANIC("display");
|
||||
}
|
||||
xQueueSend(spi_queue, &t, portMAX_DELAY);
|
||||
|
||||
// if (uxQueueSpacesAvailable(spi_queue) == 0)
|
||||
if (uxQueueMessagesWaiting(spi_count_semaphore) == 0)
|
||||
@ -274,24 +258,23 @@ spi_initialize()
|
||||
xQueueSend(spi_queue, ¶m, portMAX_DELAY);
|
||||
}
|
||||
|
||||
spi_bus_config_t buscfg;
|
||||
memset(&buscfg, 0, sizeof(buscfg));
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = RG_GPIO_LCD_MISO,
|
||||
.mosi_io_num = RG_GPIO_LCD_MOSI,
|
||||
.sclk_io_num = RG_GPIO_LCD_CLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
|
||||
buscfg.miso_io_num = RG_GPIO_LCD_MISO;
|
||||
buscfg.mosi_io_num = RG_GPIO_LCD_MOSI;
|
||||
buscfg.sclk_io_num = RG_GPIO_LCD_CLK;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset(&devcfg, 0, sizeof(devcfg));
|
||||
|
||||
devcfg.clock_speed_hz = SPI_MASTER_FREQ_40M; // 80Mhz causes glitches unfortunately
|
||||
devcfg.mode = 0; // SPI mode 0
|
||||
devcfg.spics_io_num = RG_GPIO_LCD_CS; // CS pin
|
||||
devcfg.queue_size = SPI_TRANSACTION_COUNT; // We want to be able to queue 5 transactions at a time
|
||||
devcfg.pre_cb = spi_pre_transfer_callback; // Specify pre-transfer callback to handle D/C line
|
||||
devcfg.flags = SPI_DEVICE_NO_DUMMY; // SPI_DEVICE_HALFDUPLEX;
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = SPI_MASTER_FREQ_40M, // 80Mhz causes glitches unfortunately
|
||||
.mode = 0, // SPI mode 0
|
||||
.spics_io_num = RG_GPIO_LCD_CS, // CS pin
|
||||
.queue_size = SPI_TRANSACTION_COUNT, // We want to be able to queue 5 transactions at a time
|
||||
.pre_cb = spi_pre_transfer_callback, // Specify pre-transfer callback to handle D/C line and SPI lock
|
||||
// .post_cb = spi_post_transfer_callback, // Specify post-transfer callback to handle SPI lock
|
||||
.flags = SPI_DEVICE_NO_DUMMY, // SPI_DEVICE_HALFDUPLEX;
|
||||
};
|
||||
|
||||
//Initialize the SPI bus
|
||||
spi_bus_initialize(HSPI_HOST, &buscfg, 1);
|
||||
@ -344,8 +327,8 @@ ili9341_init()
|
||||
{
|
||||
ili9341_cmd(ili_init_cmds[i].cmd);
|
||||
ili9341_data(ili_init_cmds[i].data, ili_init_cmds[i].databytes & 0x7F);
|
||||
if (ili_init_cmds[i].databytes & 0x80)
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// if (ili_init_cmds[i].databytes & 0x80)
|
||||
// vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,8 +339,8 @@ ili9341_deinit()
|
||||
{
|
||||
ili9341_cmd(ili_sleep_cmds[i].cmd);
|
||||
ili9341_data(ili_sleep_cmds[i].data, ili_sleep_cmds[i].databytes & 0x7F);
|
||||
if (ili_init_cmds[i].databytes & 0x80)
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// if (ili_init_cmds[i].databytes & 0x80)
|
||||
// vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -374,22 +374,27 @@ int rg_gui_dialog(const char *header, const dialog_option_t *options_const, int
|
||||
int last_key = -1;
|
||||
|
||||
// We create a copy of options because the callbacks might modify it (ie option->value)
|
||||
|
||||
dialog_option_t options[options_count + 1];
|
||||
|
||||
for (int i = 0; i <= options_count; i++)
|
||||
{
|
||||
options[i] = options_const[i];
|
||||
char value_buffer[128] = {0xFF, 0};
|
||||
|
||||
if (options[i].value)
|
||||
{
|
||||
options[i].value = calloc(1, strlen(options[i].value) + 32);
|
||||
strcpy(options[i].value, options_const[i].value);
|
||||
}
|
||||
options[i] = options_const[i];
|
||||
|
||||
if (options[i].update_cb)
|
||||
{
|
||||
options[i].value = value_buffer;
|
||||
options[i].update_cb(&options[i], RG_DIALOG_INIT);
|
||||
if (value_buffer[0] == 0xFF) // Not updated, reset ptr
|
||||
options[i].value = options_const[i].value;
|
||||
}
|
||||
|
||||
if (options[i].value)
|
||||
{
|
||||
char *new_value = malloc(strlen(options[i].value) + 16);
|
||||
strcpy(new_value, options[i].value);
|
||||
options[i].value = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -16,6 +16,7 @@ typedef enum {
|
||||
RG_DIALOG_IGNORE,
|
||||
RG_DIALOG_SELECT,
|
||||
RG_DIALOG_CANCEL,
|
||||
RG_DIALOG_UPDATE,
|
||||
} dialog_return_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@ -35,17 +35,23 @@
|
||||
#define INPUT_TIMEOUT 5000000
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magicWord;
|
||||
char output[2048];
|
||||
size_t cursor;
|
||||
} panic_console_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t magicWord;
|
||||
char message[256];
|
||||
char function[64];
|
||||
char file[256];
|
||||
char context[128];
|
||||
} panic_trace_t;
|
||||
|
||||
// This is a direct pointer to rtc slow ram which isn't cleared on
|
||||
// panic. We don't use this region so we can point anywhere in it.
|
||||
static panic_trace_t *panicTrace = (void *)0x50001000;
|
||||
// These will survive a software reset
|
||||
static RTC_NOINIT_ATTR panic_trace_t panicTrace;
|
||||
static RTC_NOINIT_ATTR panic_console_t panicConsole;
|
||||
|
||||
static rg_app_desc_t currentApp;
|
||||
static runtime_stats_t statistics;
|
||||
@ -59,6 +65,21 @@ static spi_lock_res_t spiMutexOwner;
|
||||
#endif
|
||||
|
||||
|
||||
void esp_panic_putchar_hook(char c)
|
||||
{
|
||||
if (panicConsole.magicWord != PANIC_TRACE_MAGIC)
|
||||
{
|
||||
panicConsole.magicWord = PANIC_TRACE_MAGIC;
|
||||
panicConsole.cursor = 0;
|
||||
}
|
||||
|
||||
if (panicConsole.cursor < sizeof(panicConsole.output) - 1)
|
||||
{
|
||||
panicConsole.output[panicConsole.cursor++] = c;
|
||||
panicConsole.output[panicConsole.cursor] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void system_monitor_task(void *arg)
|
||||
{
|
||||
runtime_counters_t current = {0};
|
||||
@ -298,36 +319,61 @@ void rg_system_init(int appId, int sampleRate)
|
||||
currentApp.refreshRate = 1;
|
||||
currentApp.mainTaskHandle = xTaskGetCurrentTaskHandle();
|
||||
|
||||
// sdcard init must be before rg_display_init()
|
||||
// and rg_settings_init() if JSON is used
|
||||
// This must be before rg_display_init() and rg_settings_init()
|
||||
bool sd_init = rg_sdcard_mount();
|
||||
|
||||
rg_system_gpio_init();
|
||||
rg_settings_init();
|
||||
rg_gui_init();
|
||||
rg_input_init();
|
||||
rg_audio_init(sampleRate);
|
||||
rg_display_init();
|
||||
rg_display_clear(0);
|
||||
rg_gui_init();
|
||||
rg_gui_draw_hourglass();
|
||||
rg_audio_init(sampleRate);
|
||||
rg_input_init();
|
||||
rg_system_time_init();
|
||||
|
||||
if (esp_reset_reason() == ESP_RST_PANIC)
|
||||
{
|
||||
if (panicTrace->magicWord == PANIC_TRACE_MAGIC)
|
||||
RG_LOGX(" *** PREVIOUS PANIC: %s *** \n", panicTrace->message);
|
||||
else // Presumably abort()
|
||||
strcpy(panicTrace->message, "Application crashed");
|
||||
panicTrace->magicWord = 0;
|
||||
rg_audio_deinit();
|
||||
char message[400] = "Application crashed";
|
||||
|
||||
if (panicTrace.magicWord == PANIC_TRACE_MAGIC)
|
||||
{
|
||||
RG_LOGX(" *** PANIC TRACE: %s (%s) *** \n", panicTrace.message, panicTrace.context);
|
||||
strcpy(message, panicTrace.message);
|
||||
}
|
||||
|
||||
if (panicConsole.magicWord == PANIC_TRACE_MAGIC)
|
||||
{
|
||||
RG_LOGI("Panic log found, saving to sdcard...\n");
|
||||
FILE *fp = fopen(RG_BASE_PATH "/crash.log", "w");
|
||||
if (fp)
|
||||
{
|
||||
fprintf(fp, "Application: %s %s\n", app->project_name, app->version);
|
||||
fprintf(fp, "Build date: %s %s\n", app->date, app->time);
|
||||
if (panicTrace.magicWord == PANIC_TRACE_MAGIC)
|
||||
{
|
||||
fprintf(fp, "Message: %.256s\n", panicTrace.message);
|
||||
fprintf(fp, "Context: %.256s\n", panicTrace.context);
|
||||
}
|
||||
fputs("\nConsole:\n", fp);
|
||||
fputs(panicConsole.output, fp);
|
||||
fputs("\n\nEnd of log\n", fp);
|
||||
fclose(fp);
|
||||
}
|
||||
strcat(message, "\n Log saved to SD Card");
|
||||
}
|
||||
|
||||
rg_display_clear(C_BLUE);
|
||||
rg_gui_set_font_size(12);
|
||||
rg_gui_alert("System Panic!", panicTrace->message);
|
||||
rg_gui_alert("System Panic!", message);
|
||||
rg_sdcard_unmount();
|
||||
rg_audio_deinit();
|
||||
rg_system_switch_app(RG_APP_LAUNCHER);
|
||||
}
|
||||
|
||||
if (esp_reset_reason() != ESP_RST_SW)
|
||||
else
|
||||
{
|
||||
rg_display_clear(0);
|
||||
rg_gui_draw_hourglass();
|
||||
panicConsole.magicWord = 0;
|
||||
panicTrace.magicWord = 0;
|
||||
}
|
||||
|
||||
if (!sd_init)
|
||||
@ -360,7 +406,6 @@ void rg_system_init(int appId, int sampleRate)
|
||||
|
||||
xTaskCreate(&system_monitor_task, "sysmon", 2048, NULL, 7, NULL);
|
||||
|
||||
panicTrace->magicWord = 0;
|
||||
initialized = true;
|
||||
|
||||
RG_LOGI("Retro-Go init done.\n");
|
||||
@ -612,15 +657,14 @@ void rg_system_set_boot_app(const char *app)
|
||||
RG_LOGI("Boot partition set to %d '%s'\n", partition->subtype, partition->label);
|
||||
}
|
||||
|
||||
void rg_system_panic(const char *reason, const char *function, const char *file)
|
||||
void rg_system_panic(const char *message, const char *context)
|
||||
{
|
||||
RG_LOGX("*** PANIC: %s\n *** FUNCTION: %s\n *** FILE: %s\n", reason, function, file);
|
||||
strcpy(panicTrace.message, message ? message : "");
|
||||
strcpy(panicTrace.context, context ? context : "");
|
||||
panicTrace.magicWord = PANIC_TRACE_MAGIC;
|
||||
|
||||
strcpy(panicTrace->message, reason);
|
||||
strcpy(panicTrace->file, file);
|
||||
strcpy(panicTrace->function, function);
|
||||
|
||||
panicTrace->magicWord = PANIC_TRACE_MAGIC;
|
||||
RG_LOGX("*** PANIC : %s\n", panicTrace.message);
|
||||
RG_LOGX("*** CONTEXT: %s\n", panicTrace.context);
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ typedef struct
|
||||
} runtime_stats_t;
|
||||
|
||||
void rg_system_init(int app_id, int sampleRate);
|
||||
void rg_system_panic(const char *reason, const char *function, const char *file) __attribute__((noreturn));
|
||||
void rg_system_panic(const char *reason, const char *context) __attribute__((noreturn));
|
||||
void rg_system_halt() __attribute__((noreturn));
|
||||
void rg_system_sleep() __attribute__((noreturn));
|
||||
void rg_system_restart() __attribute__((noreturn));
|
||||
@ -157,8 +157,8 @@ extern uint32_t crc32_le(uint32_t crc, const uint8_t * buf, uint32_t len);
|
||||
#define RG_MAX(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b);_a > _b ? _a : _b; })
|
||||
|
||||
// This should really support printf format...
|
||||
#define RG_PANIC(x) rg_system_panic(x, __FUNCTION__, __FILE__)
|
||||
#define RG_ASSERT(cond, x) do { if (!(cond)) rg_system_panic(x, __FUNCTION__, __FILE__); } while(0);
|
||||
#define RG_PANIC(x) rg_system_panic(x, __FUNCTION__)
|
||||
#define RG_ASSERT(cond, x) while (!(cond)) { RG_PANIC(x); }
|
||||
|
||||
#define RG_LOGX(x, ...) printf(x, ## __VA_ARGS__)
|
||||
#define RG_LOGE(x, ...) printf("!! %s: " x, __func__, ## __VA_ARGS__)
|
||||
|
||||
18
tools/patches/esp-idf-4.0-panic-hook.diff
Normal file
18
tools/patches/esp-idf-4.0-panic-hook.diff
Normal file
@ -0,0 +1,18 @@
|
||||
--- a/components/esp32/panic.c
|
||||
+++ b/components/esp32/panic.c
|
||||
@@ -65,10 +65,15 @@
|
||||
|
||||
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
//printf may be broken, so we fix our own printing fns...
|
||||
+void __attribute__((weak)) esp_panic_putchar_hook(char c)
|
||||
+{
|
||||
+ // nothing
|
||||
+}
|
||||
static void panicPutChar(char c)
|
||||
{
|
||||
while (((READ_PERI_REG(UART_STATUS_REG(CONFIG_ESP_CONSOLE_UART_NUM)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ;
|
||||
WRITE_PERI_REG(UART_FIFO_REG(CONFIG_ESP_CONSOLE_UART_NUM), c);
|
||||
+ esp_panic_putchar_hook(c);
|
||||
}
|
||||
|
||||
static void panicPutStr(const char *c)
|
||||
Loading…
x
Reference in New Issue
Block a user