mirror of
https://github.com/opentx/opentx.git
synced 2025-07-23 16:25:16 +03:00
Refactoring of startup code, mainly dealing with detection of unexpec… (#4275)
* Refactoring of startup code, mainly dealing with detection of unexpected restart/shutdown
* Added g_FATFS_Obj initialization [Horus]
* Fix normal startup
* Use g_eeGeneral.unexpectedShutdown only on radios that have PWRMANAGE defined
Fixes for radios that don't have power control.
Other fixes
* CLI test for new()
* [Horus] Reboot protection reworked to also handle non-WDT events
(cherry picked from commit fe9a52779d
)
Conflicts:
radio/src/targets/horus/board.h
* Reverting most of the changes
* Cleanup
* Added comment that explains apparent non usage of the wdt_disable() function
* More cleanup
* Missing include
* Compilation fix
This commit is contained in:
parent
bf15410bf1
commit
b3f4870da7
9 changed files with 651 additions and 525 deletions
|
@ -22,6 +22,7 @@
|
|||
#include "diskio.h"
|
||||
#include <ctype.h>
|
||||
#include <malloc.h>
|
||||
#include <new>
|
||||
|
||||
#define CLI_COMMAND_MAX_ARGS 8
|
||||
#define CLI_COMMAND_MAX_LEN 256
|
||||
|
@ -302,6 +303,62 @@ int cliTestSD(const char ** argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int cliTestNew()
|
||||
{
|
||||
char * tmp = 0;
|
||||
serialPrint("Allocating 1kB with new()");
|
||||
CoTickDelay(100);
|
||||
tmp = new char[1024];
|
||||
if (tmp) {
|
||||
serialPrint("\tsuccess");
|
||||
delete[] tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
else {
|
||||
serialPrint("\tFAILURE");
|
||||
}
|
||||
|
||||
serialPrint("Allocating 10MB with (std::nothrow) new()");
|
||||
CoTickDelay(100);
|
||||
tmp = new (std::nothrow) char[1024*1024*10];
|
||||
if (tmp) {
|
||||
serialPrint("\tFAILURE, tmp = %p", tmp);
|
||||
delete[] tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
else {
|
||||
serialPrint("\tsuccess, allocaton failed, tmp = 0");
|
||||
}
|
||||
|
||||
serialPrint("Allocating 10MB with new()");
|
||||
CoTickDelay(100);
|
||||
tmp = new char[1024*1024*10];
|
||||
if (tmp) {
|
||||
serialPrint("\tFAILURE, tmp = %p", tmp);
|
||||
delete[] tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
else {
|
||||
serialPrint("\tsuccess, allocaton failed, tmp = 0");
|
||||
}
|
||||
serialPrint("Test finished");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliTest(const char ** argv)
|
||||
{
|
||||
if (!strcmp(argv[1], "new")) {
|
||||
return cliTestNew();
|
||||
}
|
||||
else if (!strcmp(argv[1], "std::exception")) {
|
||||
serialPrint("Not implemented");
|
||||
}
|
||||
else {
|
||||
serialPrint("%s: Invalid argument \"%s\"", argv[0], argv[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cliTrace(const char ** argv)
|
||||
{
|
||||
if (!strcmp(argv[1], "on")) {
|
||||
|
@ -509,7 +566,7 @@ void printTaskSwitchLog()
|
|||
uint32_t * tsl = new uint32_t[DEBUG_TASKS_LOG_SIZE];
|
||||
if (!tsl) {
|
||||
serialPrint("Not enough memory");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
memcpy(tsl, taskSwitchLog, sizeof(taskSwitchLog));
|
||||
uint32_t * p = tsl + taskSwitchLogPos;
|
||||
|
@ -892,6 +949,7 @@ const CliCommand cliCommands[] = {
|
|||
{ "set", cliSet, "<what> <value>" },
|
||||
{ "stackinfo", cliStackInfo, "" },
|
||||
{ "meminfo", cliMemoryInfo, "" },
|
||||
{ "test", cliTest, "new | std::exception" },
|
||||
{ "trace", cliTrace, "on | off" },
|
||||
#if defined(PCBFLAMENCO)
|
||||
{ "read_bq24195", cliReadBQ24195, "<register>" },
|
||||
|
|
|
@ -41,6 +41,12 @@
|
|||
#define __SDRAM __DMA
|
||||
#endif
|
||||
|
||||
#if defined(PCBHORUS) && !defined(SIMU)
|
||||
#define __NOINIT __attribute__((section(".noinit")))
|
||||
#else
|
||||
#define __NOINIT
|
||||
#endif
|
||||
|
||||
#if defined(SIMU) || defined(CPUARM) || GCC_VERSION < 472
|
||||
typedef int32_t int24_t;
|
||||
#else
|
||||
|
|
|
@ -2443,24 +2443,42 @@ void opentxInit(OPENTX_INIT_ARGS)
|
|||
storageReadAll();
|
||||
#endif
|
||||
|
||||
// Radios handle UNEXPECTED_SHUTDOWN() differently:
|
||||
// * radios with WDT and EEPROM and CPU controlled power use Reset status register
|
||||
// and eeGeneral.unexpectedShutdown
|
||||
// * radios with SDCARD model storage use Reset status register and special
|
||||
// variables in RAM. They can not use eeGeneral.unexpectedShutdown
|
||||
// * radios without CPU controlled power can only use Reset status register (if available)
|
||||
if (UNEXPECTED_SHUTDOWN()) {
|
||||
TRACE("Unexpected Shutdown detected");
|
||||
unexpectedShutdown = 1;
|
||||
}
|
||||
else {
|
||||
|
||||
#if defined(SDCARD) && !defined(PCBMEGA2560)
|
||||
// SDCARD related stuff, only done if not unexpectedShutdown
|
||||
if (!unexpectedShutdown) {
|
||||
sdInit();
|
||||
logsInit();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
if (!unexpectedShutdown) {
|
||||
// g_model.topbarData is still zero here (because it was not yet read from SDCARD),
|
||||
// but we only remember the pointer to in in constructor.
|
||||
// The storageReadAll() needs topbar object, so it must be created here
|
||||
topbar = new Topbar(&g_model.topbarData);
|
||||
// lua widget state must also be prepared before the call to storageReadAll()
|
||||
LUA_INIT_THEMES_AND_WIDGETS();
|
||||
}
|
||||
#endif
|
||||
|
||||
// handling of storage for radios that have no EEPROM
|
||||
#if !defined(EEPROM)
|
||||
#if defined(RAMBACKUP)
|
||||
if (UNEXPECTED_SHUTDOWN()) {
|
||||
if (unexpectedShutdown) {
|
||||
// SDCARD not available, try to restore last model from RAM
|
||||
TRACE("rambackupRestore");
|
||||
rambackupRestore();
|
||||
}
|
||||
else {
|
||||
|
@ -2469,7 +2487,7 @@ void opentxInit(OPENTX_INIT_ARGS)
|
|||
#else
|
||||
storageReadAll();
|
||||
#endif
|
||||
#endif
|
||||
#endif // #if !defined(EEPROM)
|
||||
|
||||
#if defined(SERIAL2)
|
||||
serial2Init(g_eeGeneral.serial2Mode, MODEL_TELEMETRY_PROTOCOL());
|
||||
|
@ -2515,11 +2533,12 @@ void opentxInit(OPENTX_INIT_ARGS)
|
|||
|
||||
if (g_eeGeneral.backlightMode != e_backlight_mode_off) backlightOn(); // on Tx start turn the light on
|
||||
|
||||
if (!UNEXPECTED_SHUTDOWN()) {
|
||||
if (!unexpectedShutdown) {
|
||||
opentxStart();
|
||||
}
|
||||
|
||||
#if defined(CPUARM) || defined(CPUM2560)
|
||||
// TODO Horus does not need this
|
||||
if (!g_eeGeneral.unexpectedShutdown) {
|
||||
g_eeGeneral.unexpectedShutdown = 1;
|
||||
storageDirty(EE_GENERAL);
|
||||
|
@ -2667,7 +2686,7 @@ int main()
|
|||
drawSleepBitmap();
|
||||
opentxClose();
|
||||
boardOff(); // Only turn power off if necessary
|
||||
wdt_disable();
|
||||
wdt_disable(); // this function is provided by AVR Libc
|
||||
while(1); // never return from main() - there is no code to return back, if any delays occurs in physical power it does dead loop.
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
/*----------------------------------------------------------------------------
|
||||
* Exported variables
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
@ -50,11 +50,12 @@ extern int _heap_end;
|
|||
/*----------------------------------------------------------------------------
|
||||
* Exported functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
extern void _exit( int status ) ;
|
||||
extern void _kill( int pid, int sig ) ;
|
||||
extern int _getpid ( void ) ;
|
||||
// extern void _exit( int status ) ;
|
||||
// extern void _kill( int pid, int sig ) ;
|
||||
// extern int _getpid ( void ) ;
|
||||
|
||||
unsigned char * heap = (unsigned char *)&_end;
|
||||
|
||||
extern caddr_t _sbrk(int nbytes)
|
||||
{
|
||||
if (heap + nbytes < (unsigned char *)&_heap_end) {
|
||||
|
@ -70,84 +71,68 @@ extern caddr_t _sbrk(int nbytes)
|
|||
|
||||
extern int _gettimeofday(void *p1, void *p2)
|
||||
{
|
||||
return 0 ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int _link( char *old, char *nw )
|
||||
extern int _link(char *old, char *nw)
|
||||
{
|
||||
return -1 ;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int _unlink (const char *path)
|
||||
extern int _unlink(const char *path)
|
||||
{
|
||||
return -1 ;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int _open(const char *name, int flags, int mode)
|
||||
{
|
||||
return -1 ;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int _close( int file )
|
||||
extern int _close(int file)
|
||||
{
|
||||
return -1 ;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int _fstat( int file, struct stat *st )
|
||||
extern int _fstat(int file, struct stat * st)
|
||||
{
|
||||
st->st_mode = S_IFCHR ;
|
||||
|
||||
return 0 ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int _isatty( int file )
|
||||
extern int _isatty(int file)
|
||||
{
|
||||
return 1 ;
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern int _lseek( int file, int ptr, int dir )
|
||||
extern int _lseek(int file, int ptr, int dir)
|
||||
{
|
||||
return 0 ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int _read(int file, char *ptr, int len)
|
||||
{
|
||||
return 0 ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int _write( int file, char *ptr, int len )
|
||||
extern int _write(int file, char *ptr, int len)
|
||||
{
|
||||
int iIndex ;
|
||||
|
||||
|
||||
// for ( ; *ptr != 0 ; ptr++ )
|
||||
for ( iIndex=0 ; iIndex < len ; iIndex++, ptr++ )
|
||||
{
|
||||
// TODO UART_PutChar( *ptr ) ;
|
||||
}
|
||||
|
||||
return iIndex ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void _exit( int status )
|
||||
extern void _exit(int status)
|
||||
{
|
||||
#if defined(SIMU)
|
||||
printf( "Exiting with status %d.\n", status ) ;
|
||||
#endif
|
||||
for ( ; ; ) ;
|
||||
TRACE("_exit(%d)", status);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
extern void _kill( int pid, int sig )
|
||||
extern void _kill(int pid, int sig)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
extern int _getpid ( void )
|
||||
extern int _getpid()
|
||||
{
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
//void _init (void)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
|
|
@ -156,6 +156,11 @@ void boardInit()
|
|||
__enable_irq();
|
||||
|
||||
TRACE("\nHorus board started :)");
|
||||
TRACE("RCC->CSR = %08x", RCC->CSR);
|
||||
|
||||
// we need to initialize g_FATFS_Obj here, because it is in .ram section (because of DMA access)
|
||||
// and this section is un-initialized
|
||||
memset(&g_FATFS_Obj, 0, sizeof(g_FATFS_Obj));
|
||||
|
||||
keysInit();
|
||||
adcInit();
|
||||
|
|
|
@ -281,18 +281,33 @@ void checkRotaryEncoder(void);
|
|||
|
||||
// WDT driver
|
||||
#define WDTO_500MS 500
|
||||
extern uint32_t powerupReason;
|
||||
|
||||
#define SHUTDOWN_REQUEST 0xDEADBEEF
|
||||
#define NO_SHUTDOWN_REQUEST ~SHUTDOWN_REQUEST
|
||||
#define DIRTY_SHUTDOWN 0xCAFEDEAD
|
||||
#define NORMAL_POWER_OFF ~DIRTY_SHUTDOWN
|
||||
|
||||
#define wdt_disable()
|
||||
void watchdogInit(unsigned int duration);
|
||||
#if defined(WATCHDOG_DISABLED) || defined(SIMU)
|
||||
#if defined(SIMU)
|
||||
#define WAS_RESET_BY_WATCHDOG() (false)
|
||||
#define WAS_RESET_BY_SOFTWARE() (false)
|
||||
#define WAS_RESET_BY_WATCHDOG_OR_SOFTWARE() (false)
|
||||
#define wdt_enable(x)
|
||||
#define wdt_reset()
|
||||
#else
|
||||
#if defined(WATCHDOG_DISABLED)
|
||||
#define wdt_enable(x)
|
||||
#define wdt_reset()
|
||||
#else
|
||||
#define wdt_enable(x) watchdogInit(x)
|
||||
#define wdt_reset() IWDG->KR = 0xAAAA
|
||||
#endif
|
||||
#define WAS_RESET_BY_WATCHDOG() (RCC->CSR & (RCC_CSR_WDGRSTF | RCC_CSR_WWDGRSTF))
|
||||
#define WAS_RESET_BY_SOFTWARE() (RCC->CSR & RCC_CSR_SFTRSTF)
|
||||
#define WAS_RESET_BY_WATCHDOG_OR_SOFTWARE() (RCC->CSR & (RCC_CSR_WDGRSTF | RCC_CSR_WWDGRSTF | RCC_CSR_SFTRSTF))
|
||||
#endif
|
||||
#define WAS_RESET_BY_WATCHDOG() (RCC->CSR & (RCC_CSR_WDGRSTF | RCC_CSR_WWDGRSTF))
|
||||
#define WAS_RESET_BY_SOFTWARE() (RCC->CSR & RCC_CSR_SFTRSTF)
|
||||
#define WAS_RESET_BY_WATCHDOG_OR_SOFTWARE() (RCC->CSR & (RCC_CSR_WDGRSTF | RCC_CSR_WWDGRSTF | RCC_CSR_SFTRSTF))
|
||||
|
||||
// ADC driver
|
||||
#define NUM_POTS 3
|
||||
|
@ -338,7 +353,11 @@ void pwrResetHandler(void);
|
|||
uint32_t pwrPressed(void);
|
||||
uint32_t pwrPressedDuration(void);
|
||||
#define pwroffPressed() pwrPressed()
|
||||
#define UNEXPECTED_SHUTDOWN() (WAS_RESET_BY_WATCHDOG() || g_eeGeneral.unexpectedShutdown)
|
||||
#if defined(SIMU)
|
||||
#define UNEXPECTED_SHUTDOWN() (false)
|
||||
#else
|
||||
#define UNEXPECTED_SHUTDOWN() (powerupReason == DIRTY_SHUTDOWN)
|
||||
#endif
|
||||
|
||||
// Led driver
|
||||
void ledOff(void);
|
||||
|
|
|
@ -308,7 +308,7 @@ DRESULT disk_ioctl (
|
|||
|
||||
// TODO everything here should not be in the driver layer ...
|
||||
|
||||
FATFS g_FATFS_Obj __DMA;
|
||||
FATFS g_FATFS_Obj __DMA; // initialized in boardInit()
|
||||
#if defined(LOG_TELEMETRY)
|
||||
FIL g_telemetryFile = {};
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
#include "pwr.h"
|
||||
#include "board.h"
|
||||
|
||||
uint32_t shutdownRequest; // Stores intentional shutdown to avoid reboot loop
|
||||
uint32_t shutdownReason; // Used for detecting unexpected reboots regardless of reason
|
||||
uint32_t powerupReason __NOINIT; // Stores power up reason beyond initialization for emergency mode activation
|
||||
|
||||
void pwrInit()
|
||||
{
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
@ -70,6 +74,8 @@ void pwrInit()
|
|||
void pwrOn()
|
||||
{
|
||||
GPIO_SetBits(PWR_GPIO, PWR_ON_GPIO_PIN);
|
||||
shutdownRequest = NO_SHUTDOWN_REQUEST;
|
||||
shutdownReason = DIRTY_SHUTDOWN;
|
||||
}
|
||||
|
||||
void pwrOff()
|
||||
|
@ -87,6 +93,8 @@ void pwrOff()
|
|||
// Shutdown the Haptic
|
||||
hapticDone();
|
||||
|
||||
shutdownRequest = SHUTDOWN_REQUEST;
|
||||
shutdownReason = NORMAL_POWER_OFF;
|
||||
GPIO_ResetBits(PWR_GPIO, PWR_ON_GPIO_PIN);
|
||||
}
|
||||
|
||||
|
@ -104,13 +112,28 @@ void pwrResetHandler()
|
|||
__ASM volatile ("nop");
|
||||
__ASM volatile ("nop");
|
||||
|
||||
// Turn soft power ON now, but only if we got started because of the watchdog
|
||||
// or software reset. If the radio was started by user pressing the power button
|
||||
// then that button is providing power and we don't need to enable it here.
|
||||
// We get here whether we are powering up normally, we had an unexpected reboot or we have just powered down normally.
|
||||
// We want:
|
||||
// - In the 2nd case, to power ON as soon as possible if an unexpected reboot happened
|
||||
// (we get there running on remaining capacitor charge, soft power having been cut by the RESET).
|
||||
// - In the 3rd case, NOT power on as that would prevent from turning the system off.
|
||||
// - The 1st case does not need to be handled here, but will be as a result of the handling for the 3rd case, see below.
|
||||
//
|
||||
// If we were to turn it on here indiscriminately, then the radio can go into the
|
||||
// power on/off loop after being powered off by the user. (issue #2790)
|
||||
if (WAS_RESET_BY_WATCHDOG_OR_SOFTWARE()) {
|
||||
// shutdownRequest is used to handle the 3rd case. If we really powered down on purpose this will still be set to SHUTDOWN_REQUEST
|
||||
// as we left it in pwrOff(). If however we had an unexpected reboot, it would be set to NO_SHUTDOWN_REQUEST as we set it in pwrOn().
|
||||
// Any other value (e.g. resulting from data corruption) would also keep power on for safety, so this variable can NOT be used
|
||||
// to detect an unexpected reboot (on a normal power on the contents of the variable are random).
|
||||
//
|
||||
// shutdownReason is used to differentiate between an unexpected reboot and a normal power on. We set it to DIRTY_SHUTDOWN in pwrOn()
|
||||
// in anticipation of a potential reboot. Should there be one the value should be preserved and signal below that we rebooted unexpectedly.
|
||||
// If it is NOT set to DIRTY_SHUTDOWN we likely had a normal boot and its contents are random. Due to the need to initialize it to detect a
|
||||
// potential failure ASAP we cannot use it to determine in the firmware why we got there, it has to be buffered.
|
||||
//
|
||||
// powerupReason is there to cater for that, and is what is used in the firmware to decide whether we have to enter emergency mode.
|
||||
// This variable needs to be in a RAM section that is not initialized or zeroed, since once we exit this pwrResetHandler() function the
|
||||
// C runtime would otherwise overwrite it during program init.
|
||||
|
||||
if (shutdownRequest != SHUTDOWN_REQUEST) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
GPIO_InitStructure.GPIO_Pin = PWR_ON_GPIO_PIN;
|
||||
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
|
||||
|
@ -119,6 +142,10 @@ void pwrResetHandler()
|
|||
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
|
||||
GPIO_Init(PWR_GPIO, &GPIO_InitStructure);
|
||||
|
||||
if (shutdownReason == DIRTY_SHUTDOWN) {
|
||||
powerupReason = DIRTY_SHUTDOWN;
|
||||
}
|
||||
|
||||
pwrOn();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,6 +127,13 @@ SECTIONS
|
|||
_ebss = .; /* define a global symbol at bss end */
|
||||
} >CCM
|
||||
|
||||
/* Non-zeroed data section */
|
||||
. = ALIGN(4);
|
||||
.noinit (NOLOAD) :
|
||||
{
|
||||
*(.noinit)
|
||||
} >CCM
|
||||
|
||||
/* collect all uninitialized .ccm sections */
|
||||
.ram (NOLOAD) :
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue