Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/app watchdog #860

Merged
merged 5 commits into from
Feb 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions hal/src/electron/include.mk
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,9 @@ ifdef UBLOX_PHONE_NUM
CFLAGS += -DUBLOX_PHONE_NUM='"$(UBLOX_PHONE_NUM)"'
endif

# if we are being compiled with platform as a dependency, then also include
# implementation headers.
ifneq (,$(findstring platform,$(DEPENDENCIES)))
INCLUDE_DIRS += $(HAL_SRC_ELECTRON_INCL_PATH)
INCLUDE_DIRS += $(HAL_INCL_STM32F2XX_PATH)
INCLUDE_DIRS += $(HAL_INCL_STM32_PATH)
endif

HAL_LINK ?= $(findstring hal,$(MAKE_DEPENDENCIES))

Expand Down
2 changes: 1 addition & 1 deletion hal/src/stm32/concurrent_hal_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
extern "C" {
#endif


// This code is used by HAL-clients which don't have access to the FreeRTOS sources
// so we cannot directly define __gthread_t as TaskHandle_t, however, we define it
// here and statically assert that it is the same size.
Expand All @@ -18,6 +17,7 @@ typedef int32_t os_result_t;
typedef uint8_t os_thread_prio_t;
/* Default priority is the same as the application thread */
const os_thread_prio_t OS_THREAD_PRIORITY_DEFAULT = 2;
const os_thread_prio_t OS_THREAD_PRIORITY_CRITICAL = 9;
const size_t OS_THREAD_STACK_SIZE_DEFAULT = 3*1024;

typedef void* os_mutex_t;
Expand Down
2 changes: 1 addition & 1 deletion modules/shared/stm32f2xx/inc/user_part_export.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ void module_user_setup() {

void module_user_loop() {
loop();
serialEventRun();
_post_loop();
}

#include "user_dynalib.h"
Expand Down
1 change: 1 addition & 0 deletions system/inc/system_user.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extern "C" {
void setup();
void loop();

void _post_loop();
void serialEventRun();

/**
Expand Down
5 changes: 4 additions & 1 deletion system/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,9 @@ void app_loop(bool threaded)
if (system_mode()!=SAFE_MODE)
setup();
SPARK_WIRING_APPLICATION = 1;
#if !MODULAR_FIRMWARE
_post_loop();
#endif
}

//Execute user application loop
Expand All @@ -508,7 +511,7 @@ void app_loop(bool threaded)
loop();
DECLARE_SYS_HEALTH(RAN_Loop);
#if !MODULAR_FIRMWARE
serialEventRun();
_post_loop();
#endif
#if Wiring_Cellular == 1
system_power_management_update();
Expand Down
3 changes: 0 additions & 3 deletions system/src/system_threading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,6 @@ namespace std {
thread_startup startup;
startup.call = base.get();
startup.started = false;
// FIXME: if the priority of the new thread is low enough not to cause `os_thread_create` to
// preempt the current thread to run the thread start function, by the time `invoke_thread`
// executes `call->_M_run()` will cause a pure virtual error
if (os_thread_create(&_M_id._M_thread, "std::thread", OS_THREAD_PRIORITY_DEFAULT, invoke_thread, &startup, 1024*3)) {
PANIC(AssertionFailure, "%s %s", __FILE__, __LINE__);
}
Expand Down
1 change: 1 addition & 0 deletions user/inc/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include "spark_wiring_tone.h"
#include "spark_wiring_eeprom.h"
#include "spark_wiring_version.h"
#include "spark_wiring_watchdog.h"
#include "spark_wiring_thread.h"
#include "fast_pin.h"
#include "string_convert.h"
Expand Down
9 changes: 9 additions & 0 deletions user/tests/wiring/api/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,13 @@ test(api_atomic_section) {
API_COMPILE(AtomicSection as);
}

test(api_application_watchdog)
{
unsigned stack_size = 512;
application_checkin();
ApplicationWatchdog wd(30000, System.reset);
ApplicationWatchdog wd2(30000, System.reset, stack_size);
}


#endif
49 changes: 49 additions & 0 deletions user/tests/wiring/no_fixture/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,53 @@ test(thread_try_lock)
// todo - test for SingleThreadedSection



volatile bool timeout_called = 0;
void timeout()
{
timeout_called++;
}

void waitForComplete(ApplicationWatchdog& wd)
{
while (!wd.isComplete()) {
HAL_Delay_Milliseconds(10);
}
}


test(application_watchdog_fires_timeout)
{
timeout_called = 0;
ApplicationWatchdog wd(5, timeout);
HAL_Delay_Milliseconds(10);

assertEqual(timeout_called, 1);
waitForComplete(wd);
}

test(application_watchdog_doesnt_fire_when_app_checks_in)
{
timeout_called = 0;
unsigned t = 100;
ApplicationWatchdog wd(t, timeout);

for (int i=0; i<10; i++) {
assertEqual(timeout_called, 0);
application_checkin();
os_thread_yield();
}
HAL_Delay_Milliseconds(t);
assertEqual(timeout_called, 1);
waitForComplete(wd);
}

#endif

void init_tests()
{
Test::exclude("*");
Test::include("application_watchdog*");
}

STARTUP(init_tests());
6 changes: 5 additions & 1 deletion wiring/inc/spark_wiring_cloud.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "system_sleep.h"
#include "spark_protocol_functions.h"
#include "spark_wiring_system.h"
#include "spark_wiring_watchdog.h"
#include "interrupts_hal.h"
#include <functional>

Expand Down Expand Up @@ -241,7 +242,10 @@ class CloudClass {
static bool disconnected(void) { return !connected(); }
static void connect(void) { spark_connect(); }
static void disconnect(void) { spark_disconnect(); }
static void process(void) { spark_process(); }
static void process(void) {
application_checkin();
spark_process();
}
static String deviceID(void) { return SystemClass::deviceID(); }

private:
Expand Down
3 changes: 2 additions & 1 deletion wiring/inc/spark_wiring_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ class Thread

static os_thread_return_t call_wiring_handler(void *param) {
auto wrapper = (wiring_thread_fn_t*)(param);
return (*wrapper)();
(*wrapper)();
os_thread_cleanup(nullptr);
}
};

Expand Down
90 changes: 90 additions & 0 deletions wiring/inc/spark_wiring_watchdog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
******************************************************************************
Copyright (c) 2015 Particle Industries, Inc. All rights reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either
version 3 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
******************************************************************************
*/

#pragma once

#include "spark_wiring_thread.h"
#include "delay_hal.h"
#include "timer_hal.h"

#if PLATFORM_THREADING


class ApplicationWatchdog
{
volatile system_tick_t timeout;
static volatile system_tick_t last_checkin;

std::function<void(void)> timeout_fn;

Thread thread;

static void start(void* pointer);

void loop();

public:

ApplicationWatchdog(unsigned timeout_ms, std::function<void(void)> fn, unsigned stack_size=512) : timeout(timeout_ms), timeout_fn(fn),
thread("appwdt", start, this, OS_THREAD_PRIORITY_CRITICAL, stack_size)
{
checkin();
}

bool isComplete()
{
return !timeout_fn;
}

static inline system_tick_t current_time()
{
return HAL_Timer_Get_Milli_Seconds();
}

bool has_timedout()
{
return (current_time()-last_checkin)>=timeout;
}

/**
* Dispose of this thread next time it wakes up.
*/
void dispose()
{
timeout = 0;
}

/**
* Lifesign that the application is still working normally.
*/
static void checkin()
{
last_checkin = current_time();
}

};

inline void application_checkin() { ApplicationWatchdog::checkin(); }

#else

inline void application_checkin() { }

#endif

6 changes: 6 additions & 0 deletions wiring/src/user.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "spark_wiring_platform.h"
#include "spark_wiring_usbserial.h"
#include "spark_wiring_usartserial.h"
#include "spark_wiring_watchdog.h"
#include "rng_hal.h"


Expand Down Expand Up @@ -83,6 +84,11 @@ void serialEvent4() __attribute__((weak));
void serialEvent5() __attribute__((weak));
#endif

void _post_loop()
{
serialEventRun();
application_checkin();
}

/**
* Provides background processing of serial data.
Expand Down
32 changes: 32 additions & 0 deletions wiring_globals/src/spark_wiring_watchdog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

#include "spark_wiring_watchdog.h"

#if PLATFORM_THREADING

volatile system_tick_t ApplicationWatchdog::last_checkin;

os_thread_return_t ApplicationWatchdog::start(void* pointer)
{
ApplicationWatchdog& wd = *(ApplicationWatchdog*)pointer;
wd.loop();
os_thread_cleanup(nullptr);
}

void ApplicationWatchdog::loop()
{
bool done = false;
system_tick_t now;
while (!done) {
HAL_Delay_Milliseconds(timeout);
now = current_time();
done = (now-last_checkin)>=timeout;
}

if (timeout>0 && timeout_fn) {
timeout_fn();
timeout_fn = std::function<void(void)>();
}
}


#endif