1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-12 20:08:48 +01:00
LibrePilot/flight/OpenPilot/Modules/System/systemmod.c

326 lines
9.6 KiB
C
Raw Normal View History

/**
******************************************************************************
* @addtogroup OpenPilotModules OpenPilot Modules
* @brief The OpenPilot Modules do the majority of the control in OpenPilot. The
* @ref SystemModule "System Module" starts all the other modules that then take care
* of all the telemetry and control algorithms and such. This is done through the @ref PIOS
* "PIOS Hardware abstraction layer" which then contains hardware specific implementations
* (currently only STM32 supported)
*
* @{
* @addtogroup SystemModule System Module
* @brief Initializes PIOS and other modules runs monitoring
* After initializing all the modules (currently selected by Makefile but in
* future controlled by configuration on SD card) runs basic monitoring and
* alarms.
* @{
*
* @file systemmod.c
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @brief System module
*
* @see The GNU Public License (GPL) Version 3
*
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "openpilot.h"
#include "systemmod.h"
#include "objectpersistence.h"
#include "manualcontrolcommand.h"
#include "systemstats.h"
PiOS/I2C: Lots of small changes. Added a few weird bus events that are sometimes thrown, and made errors not lock it up by default. It works for me, but since this has historically been associated with lots of lock ups please check your systems carefully. PiOS/I2C: Make the bus by default try to recover from errors instead of locking up PiOS/I2C: After a bus error and clocking all previous data create a STOP condition to make sure bus is released (note, this also requires creating a START condition first) PiOS/I2C: If the same event hits the I2C bus twice in a row then disregard second one, there is no situation where we should get the same event multiple times that matters and this gets us out really quickly to catch the real events. I was seeing this with repeated 0x70084 which means byte transmitted. This is related to STM32 bugs in the IRQ timings I believe. PiOS/I2C: 1) Mask out some bits we don't care about in the event flags 2) Don't lock up if the give semaphore fails, although why it does is strange 3) Recover from bus failure through the "auto" state path instead of just coding state PiOS/I2C: Change the reset bus code to follow http://www.analog.com/static/imported-files/application_notes/54305147357414AN686_0.pdf (thanks for the reference Neontangerine). Although this may actually NOT clear the bus the first time through, subsequent bus errors should eventually clock it out. The up side is it is less likely to clock a bunch of 1s into an ESC and make it run up. PiOS/I2C: Some cleaned up code for getting a snippet of the history when something strange happens PiOS/I2C: Export logging information from I2C through a UAV object PiOS/I2C: Improve the diagnostic information PiOS/I2C: Need to handle the event 0x30084. This seems to happen between a byte transmitted and new byte started PiOS/I2C: Handle the NACK condition by simply going to the stopping state. PiOS/I2C: Add a new NACK state to handle sending the STOP signal after a NACK following the STM documentation. Other error conditions still are not dealt with. PiOS/I2C: Should handle the NACK condition from all the write cases. Need to think about read cases git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2239 ebee16cc-31ac-478f-84a7-5cbb03baadba
2010-12-17 08:01:58 +01:00
#include "i2cstats.h"
// Private constants
#define SYSTEM_UPDATE_PERIOD_MS 1000
#define IDLE_COUNTS_PER_SEC_AT_NO_LOAD 995998 // calibrated by running tests/test_cpuload.c
// must be updated if the FreeRTOS or compiler
// optimisation options are changed.
#define STACK_SIZE configMINIMAL_STACK_SIZE
#define TASK_PRIORITY (tskIDLE_PRIORITY+3)
#define HEAP_LIMIT_WARNING 4000
#define HEAP_LIMIT_CRITICAL 1000
#define CPULOAD_LIMIT_WARNING 80
#define CPULOAD_LIMIT_CRITICAL 95
// Private types
// Private variables
static uint32_t idleCounter;
static uint32_t idleCounterClear;
static xTaskHandle systemTaskHandle;
static int32_t stackOverflow;
// Private functions
static void objectUpdatedCb(UAVObjEvent * ev);
static void updateStats();
PiOS/I2C: Lots of small changes. Added a few weird bus events that are sometimes thrown, and made errors not lock it up by default. It works for me, but since this has historically been associated with lots of lock ups please check your systems carefully. PiOS/I2C: Make the bus by default try to recover from errors instead of locking up PiOS/I2C: After a bus error and clocking all previous data create a STOP condition to make sure bus is released (note, this also requires creating a START condition first) PiOS/I2C: If the same event hits the I2C bus twice in a row then disregard second one, there is no situation where we should get the same event multiple times that matters and this gets us out really quickly to catch the real events. I was seeing this with repeated 0x70084 which means byte transmitted. This is related to STM32 bugs in the IRQ timings I believe. PiOS/I2C: 1) Mask out some bits we don't care about in the event flags 2) Don't lock up if the give semaphore fails, although why it does is strange 3) Recover from bus failure through the "auto" state path instead of just coding state PiOS/I2C: Change the reset bus code to follow http://www.analog.com/static/imported-files/application_notes/54305147357414AN686_0.pdf (thanks for the reference Neontangerine). Although this may actually NOT clear the bus the first time through, subsequent bus errors should eventually clock it out. The up side is it is less likely to clock a bunch of 1s into an ESC and make it run up. PiOS/I2C: Some cleaned up code for getting a snippet of the history when something strange happens PiOS/I2C: Export logging information from I2C through a UAV object PiOS/I2C: Improve the diagnostic information PiOS/I2C: Need to handle the event 0x30084. This seems to happen between a byte transmitted and new byte started PiOS/I2C: Handle the NACK condition by simply going to the stopping state. PiOS/I2C: Add a new NACK state to handle sending the STOP signal after a NACK following the STM documentation. Other error conditions still are not dealt with. PiOS/I2C: Should handle the NACK condition from all the write cases. Need to think about read cases git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2239 ebee16cc-31ac-478f-84a7-5cbb03baadba
2010-12-17 08:01:58 +01:00
static void updateI2Cstats();
static void updateSystemAlarms();
static void systemTask(void *parameters);
/**
* Initialise the module, called on startup.
* \returns 0 on success or -1 if initialisation failed
*/
int32_t SystemModInitialize(void)
{
// Initialize vars
stackOverflow = 0;
// Create system task
xTaskCreate(systemTask, (signed char *)"System", STACK_SIZE, NULL, TASK_PRIORITY, &systemTaskHandle);
return 0;
}
/**
* System task, periodically executes every SYSTEM_UPDATE_PERIOD_MS
*/
static void systemTask(void *parameters)
{
portTickType lastSysTime;
// System initialization
OpenPilotInit();
// Initialize vars
idleCounter = 0;
idleCounterClear = 0;
lastSysTime = xTaskGetTickCount();
// Listen for SettingPersistance object updates, connect a callback function
ObjectPersistenceConnectCallback(&objectUpdatedCb);
// Main system loop
while (1) {
// Update the system statistics
updateStats();
// Update the system alarms
updateSystemAlarms();
PiOS/I2C: Lots of small changes. Added a few weird bus events that are sometimes thrown, and made errors not lock it up by default. It works for me, but since this has historically been associated with lots of lock ups please check your systems carefully. PiOS/I2C: Make the bus by default try to recover from errors instead of locking up PiOS/I2C: After a bus error and clocking all previous data create a STOP condition to make sure bus is released (note, this also requires creating a START condition first) PiOS/I2C: If the same event hits the I2C bus twice in a row then disregard second one, there is no situation where we should get the same event multiple times that matters and this gets us out really quickly to catch the real events. I was seeing this with repeated 0x70084 which means byte transmitted. This is related to STM32 bugs in the IRQ timings I believe. PiOS/I2C: 1) Mask out some bits we don't care about in the event flags 2) Don't lock up if the give semaphore fails, although why it does is strange 3) Recover from bus failure through the "auto" state path instead of just coding state PiOS/I2C: Change the reset bus code to follow http://www.analog.com/static/imported-files/application_notes/54305147357414AN686_0.pdf (thanks for the reference Neontangerine). Although this may actually NOT clear the bus the first time through, subsequent bus errors should eventually clock it out. The up side is it is less likely to clock a bunch of 1s into an ESC and make it run up. PiOS/I2C: Some cleaned up code for getting a snippet of the history when something strange happens PiOS/I2C: Export logging information from I2C through a UAV object PiOS/I2C: Improve the diagnostic information PiOS/I2C: Need to handle the event 0x30084. This seems to happen between a byte transmitted and new byte started PiOS/I2C: Handle the NACK condition by simply going to the stopping state. PiOS/I2C: Add a new NACK state to handle sending the STOP signal after a NACK following the STM documentation. Other error conditions still are not dealt with. PiOS/I2C: Should handle the NACK condition from all the write cases. Need to think about read cases git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2239 ebee16cc-31ac-478f-84a7-5cbb03baadba
2010-12-17 08:01:58 +01:00
updateI2Cstats();
// Flash the heartbeat LED
PIOS_LED_Toggle(LED1);
// Turn on the error LED if an alarm is set
if (AlarmsHasWarnings()) {
PIOS_LED_On(LED2);
} else {
PIOS_LED_Off(LED2);
}
ManualControlCommandData manualControlCommandData;
ManualControlCommandGet(&manualControlCommandData);
// Wait until next period
if(manualControlCommandData.Armed == MANUALCONTROLCOMMAND_ARMED_TRUE) {
vTaskDelayUntil(&lastSysTime, SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS / 2);
} else {
vTaskDelayUntil(&lastSysTime, SYSTEM_UPDATE_PERIOD_MS / portTICK_RATE_MS);
}
}
}
/**
* Function called in response to object updates
*/
static void objectUpdatedCb(UAVObjEvent * ev)
{
ObjectPersistenceData objper;
UAVObjHandle obj;
// If the object updated was the ObjectPersistence execute requested action
if (ev->obj == ObjectPersistenceHandle()) {
// Get object data
ObjectPersistenceGet(&objper);
// Execute action
if (objper.Operation == OBJECTPERSISTENCE_OPERATION_LOAD) {
if (objper.Selection == OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT) {
// Get selected object
obj = UAVObjGetByID(objper.ObjectID);
if (obj == 0) {
return;
}
// Load selected instance
UAVObjLoad(obj, objper.InstanceID);
} else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
UAVObjLoadSettings();
} else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
UAVObjLoadMetaobjects();
}
} else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_SAVE) {
if (objper.Selection == OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT) {
// Get selected object
obj = UAVObjGetByID(objper.ObjectID);
if (obj == 0) {
return;
}
// Save selected instance
UAVObjSave(obj, objper.InstanceID);
} else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
UAVObjSaveSettings();
} else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
UAVObjSaveMetaobjects();
}
} else if (objper.Operation == OBJECTPERSISTENCE_OPERATION_DELETE) {
if (objper.Selection == OBJECTPERSISTENCE_SELECTION_SINGLEOBJECT) {
// Get selected object
obj = UAVObjGetByID(objper.ObjectID);
if (obj == 0) {
return;
}
// Delete selected instance
UAVObjDelete(obj, objper.InstanceID);
} else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLSETTINGS
|| objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
UAVObjDeleteSettings();
} else if (objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLMETAOBJECTS
|| objper.Selection == OBJECTPERSISTENCE_SELECTION_ALLOBJECTS) {
UAVObjDeleteMetaobjects();
}
}
}
}
PiOS/I2C: Lots of small changes. Added a few weird bus events that are sometimes thrown, and made errors not lock it up by default. It works for me, but since this has historically been associated with lots of lock ups please check your systems carefully. PiOS/I2C: Make the bus by default try to recover from errors instead of locking up PiOS/I2C: After a bus error and clocking all previous data create a STOP condition to make sure bus is released (note, this also requires creating a START condition first) PiOS/I2C: If the same event hits the I2C bus twice in a row then disregard second one, there is no situation where we should get the same event multiple times that matters and this gets us out really quickly to catch the real events. I was seeing this with repeated 0x70084 which means byte transmitted. This is related to STM32 bugs in the IRQ timings I believe. PiOS/I2C: 1) Mask out some bits we don't care about in the event flags 2) Don't lock up if the give semaphore fails, although why it does is strange 3) Recover from bus failure through the "auto" state path instead of just coding state PiOS/I2C: Change the reset bus code to follow http://www.analog.com/static/imported-files/application_notes/54305147357414AN686_0.pdf (thanks for the reference Neontangerine). Although this may actually NOT clear the bus the first time through, subsequent bus errors should eventually clock it out. The up side is it is less likely to clock a bunch of 1s into an ESC and make it run up. PiOS/I2C: Some cleaned up code for getting a snippet of the history when something strange happens PiOS/I2C: Export logging information from I2C through a UAV object PiOS/I2C: Improve the diagnostic information PiOS/I2C: Need to handle the event 0x30084. This seems to happen between a byte transmitted and new byte started PiOS/I2C: Handle the NACK condition by simply going to the stopping state. PiOS/I2C: Add a new NACK state to handle sending the STOP signal after a NACK following the STM documentation. Other error conditions still are not dealt with. PiOS/I2C: Should handle the NACK condition from all the write cases. Need to think about read cases git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2239 ebee16cc-31ac-478f-84a7-5cbb03baadba
2010-12-17 08:01:58 +01:00
/**
* Called periodically to update the I2C statistics
*/
static void updateI2Cstats()
{
I2CStatsData i2cStats;
I2CStatsGet(&i2cStats);
struct pios_i2c_fault_history history;
PIOS_I2C_GetDiagnostics(&history, &i2cStats.event_errors);
PiOS/I2C: Lots of small changes. Added a few weird bus events that are sometimes thrown, and made errors not lock it up by default. It works for me, but since this has historically been associated with lots of lock ups please check your systems carefully. PiOS/I2C: Make the bus by default try to recover from errors instead of locking up PiOS/I2C: After a bus error and clocking all previous data create a STOP condition to make sure bus is released (note, this also requires creating a START condition first) PiOS/I2C: If the same event hits the I2C bus twice in a row then disregard second one, there is no situation where we should get the same event multiple times that matters and this gets us out really quickly to catch the real events. I was seeing this with repeated 0x70084 which means byte transmitted. This is related to STM32 bugs in the IRQ timings I believe. PiOS/I2C: 1) Mask out some bits we don't care about in the event flags 2) Don't lock up if the give semaphore fails, although why it does is strange 3) Recover from bus failure through the "auto" state path instead of just coding state PiOS/I2C: Change the reset bus code to follow http://www.analog.com/static/imported-files/application_notes/54305147357414AN686_0.pdf (thanks for the reference Neontangerine). Although this may actually NOT clear the bus the first time through, subsequent bus errors should eventually clock it out. The up side is it is less likely to clock a bunch of 1s into an ESC and make it run up. PiOS/I2C: Some cleaned up code for getting a snippet of the history when something strange happens PiOS/I2C: Export logging information from I2C through a UAV object PiOS/I2C: Improve the diagnostic information PiOS/I2C: Need to handle the event 0x30084. This seems to happen between a byte transmitted and new byte started PiOS/I2C: Handle the NACK condition by simply going to the stopping state. PiOS/I2C: Add a new NACK state to handle sending the STOP signal after a NACK following the STM documentation. Other error conditions still are not dealt with. PiOS/I2C: Should handle the NACK condition from all the write cases. Need to think about read cases git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2239 ebee16cc-31ac-478f-84a7-5cbb03baadba
2010-12-17 08:01:58 +01:00
for(uint8_t i = 0; (i < I2C_LOG_DEPTH) && (i < I2CSTATS_EVENT_LOG_NUMELEM); i++) {
i2cStats.event_log[i] = history.event[i];
i2cStats.state_log[i] = history.state[i];
}
i2cStats.last_error_type = history.type;
I2CStatsSet(&i2cStats);
}
/**
* Called periodically to update the system stats
*/
static void updateStats()
{
SystemStatsData stats;
// Get stats and update
SystemStatsGet(&stats);
stats.FlightTime = xTaskGetTickCount() * portTICK_RATE_MS;
#if defined(ARCH_POSIX) || defined(ARCH_WIN32)
// POSIX port of FreeRTOS doesn't have xPortGetFreeHeapSize()
stats.HeapRemaining = 10240;
#else
stats.HeapRemaining = xPortGetFreeHeapSize();
#endif
stats.CPULoad =
100 - (uint8_t) round(100.0 * ((float)idleCounter / (float)(SYSTEM_UPDATE_PERIOD_MS / 1000)) / (float)IDLE_COUNTS_PER_SEC_AT_NO_LOAD);
idleCounterClear = 1;
SystemStatsSet(&stats);
}
/**
* Update system alarms
*/
static void updateSystemAlarms()
{
SystemStatsData stats;
UAVObjStats objStats;
EventStats evStats;
SystemStatsGet(&stats);
// Check heap
if (stats.HeapRemaining < HEAP_LIMIT_CRITICAL) {
AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_CRITICAL);
} else if (stats.HeapRemaining < HEAP_LIMIT_WARNING) {
AlarmsSet(SYSTEMALARMS_ALARM_OUTOFMEMORY, SYSTEMALARMS_ALARM_WARNING);
} else {
AlarmsClear(SYSTEMALARMS_ALARM_OUTOFMEMORY);
}
// Check CPU load
if (stats.CPULoad > CPULOAD_LIMIT_CRITICAL) {
AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_CRITICAL);
} else if (stats.CPULoad > CPULOAD_LIMIT_WARNING) {
AlarmsSet(SYSTEMALARMS_ALARM_CPUOVERLOAD, SYSTEMALARMS_ALARM_WARNING);
} else {
AlarmsClear(SYSTEMALARMS_ALARM_CPUOVERLOAD);
}
// Check for stack overflow
if (stackOverflow == 1) {
AlarmsSet(SYSTEMALARMS_ALARM_STACKOVERFLOW, SYSTEMALARMS_ALARM_CRITICAL);
} else {
AlarmsClear(SYSTEMALARMS_ALARM_STACKOVERFLOW);
}
// Check for SD card
if (POIS_SDCARD_IsMounted() == 0) {
AlarmsSet(SYSTEMALARMS_ALARM_SDCARD, SYSTEMALARMS_ALARM_WARNING);
} else {
AlarmsClear(SYSTEMALARMS_ALARM_SDCARD);
}
// Check for event errors
UAVObjGetStats(&objStats);
EventGetStats(&evStats);
UAVObjClearStats();
EventClearStats();
if (objStats.eventErrors > 0 || evStats.eventErrors > 0) {
AlarmsSet(SYSTEMALARMS_ALARM_EVENTSYSTEM, SYSTEMALARMS_ALARM_WARNING);
} else {
AlarmsClear(SYSTEMALARMS_ALARM_EVENTSYSTEM);
}
}
/**
* Called by the RTOS when the CPU is idle, used to measure the CPU idle time.
*/
void vApplicationIdleHook(void)
{
// Called when the scheduler has no tasks to run
if (idleCounterClear == 0) {
++idleCounter;
} else {
idleCounter = 0;
idleCounterClear = 0;
}
}
/**
* Called by the RTOS when a stack overflow is detected.
*/
void vApplicationStackOverflowHook(xTaskHandle * pxTask, signed portCHAR * pcTaskName)
{
stackOverflow = 1;
}
/**
* @}
* @}
*/