1
0
Fork 0
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:
Damjan Adamic 2017-01-24 07:52:33 +01:00 committed by Bertrand Songis
parent bf15410bf1
commit b3f4870da7
9 changed files with 651 additions and 525 deletions

View file

@ -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>" },

View file

@ -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

View file

@ -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

View file

@ -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)
//{
//}

View file

@ -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();

View file

@ -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);

View file

@ -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

View file

@ -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();
}
}

View file

@ -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) :
{