blob: 3a3c8e991e7836d0f723b0c2a76a08afedfd4861 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <assert.h>
#include "os/mynewt.h"
#include "os_priv.h"
#include "hal/hal_os_tick.h"
#include "hal/hal_bsp.h"
#include "hal/hal_watchdog.h"
#if MYNEWT_VAL(RTT)
#include "rtt/SEGGER_RTT.h"
#endif
/**
* @defgroup OSKernel Operating System Kernel
* @brief This section contains documentation for the core operating system kernel
* of Apache Mynewt.
* @{
* @addtogroup OSGeneral General Functions
* @{
*/
struct os_task g_idle_task;
OS_TASK_STACK_DEFINE(g_idle_task_stack, OS_IDLE_STACK_SIZE);
uint32_t g_os_idle_ctr;
static struct os_task os_main_task;
OS_TASK_STACK_DEFINE(os_main_stack, OS_MAIN_STACK_SIZE);
#if MYNEWT_VAL(OS_WATCHDOG_MONITOR)
/*
* This should fire just before hal watchdog would.
* The timer fires 2 seconds before hardware watchdog; adjust this if
* more time is needed to write the corefile.
*/
#define OS_WDOG_MONITOR_TMO ((MYNEWT_VAL(WATCHDOG_INTERVAL) - 2000) * 1000)
#if MYNEWT_VAL(WATCHDOG_INTERVAL) < 4000
#error "Watchdog interval too small, must be at least 4000m"
#endif
static struct hal_timer os_wdog_monitor;
#endif
#if MYNEWT_VAL(WATCHDOG_INTERVAL) - 200 < MYNEWT_VAL(SANITY_INTERVAL)
#error "Watchdog interval - 200 < sanity interval"
#endif
/* Default zero. Set by the architecture specific code when os is started.
*/
int g_os_started;
#define MIN_IDLE_TICKS (MYNEWT_VAL(OS_IDLE_TICKLESS_MS_MIN) * OS_TICKS_PER_SEC / 1000)
#define MAX_IDLE_TICKS (MYNEWT_VAL(OS_IDLE_TICKLESS_MS_MAX) * OS_TICKS_PER_SEC / 1000)
/**
* Idle operating system task, runs when no other tasks are running.
* The idle task operates in tickless mode, which means it looks for
* the next time an event in the system needs to run, and then tells
* the architecture specific functions to sleep until that time.
*
* @param arg unused
*/
void
os_idle_task(void *arg)
{
os_sr_t sr;
os_time_t now;
os_time_t iticks, sticks, cticks;
os_time_t sanity_last;
os_time_t sanity_itvl_ticks;
sanity_itvl_ticks = (MYNEWT_VAL(SANITY_INTERVAL) * OS_TICKS_PER_SEC) / 1000;
sanity_last = 0;
hal_watchdog_tickle();
#if MYNEWT_VAL(OS_WATCHDOG_MONITOR)
os_cputime_timer_stop(&os_wdog_monitor);
os_cputime_timer_relative(&os_wdog_monitor, OS_WDOG_MONITOR_TMO);
#endif
while (1) {
++g_os_idle_ctr;
now = os_time_get();
if (OS_TIME_TICK_GT(now, sanity_last + sanity_itvl_ticks)) {
os_sanity_run();
/* Tickle the watchdog after successfully running sanity */
hal_watchdog_tickle();
#if MYNEWT_VAL(OS_WATCHDOG_MONITOR)
os_cputime_timer_stop(&os_wdog_monitor);
os_cputime_timer_relative(&os_wdog_monitor, OS_WDOG_MONITOR_TMO);
#endif
sanity_last = now;
}
OS_ENTER_CRITICAL(sr);
now = os_time_get();
sticks = os_sched_wakeup_ticks(now);
cticks = os_callout_wakeup_ticks(now);
iticks = min(sticks, cticks);
/* Wakeup in time to run sanity as well from the idle context,
* as the idle task does not schedule itself.
*/
iticks = min(iticks, ((sanity_last + sanity_itvl_ticks) - now));
if (iticks < MIN_IDLE_TICKS) {
iticks = 0;
} else if (iticks > MAX_IDLE_TICKS) {
iticks = MAX_IDLE_TICKS;
} else {
/* NOTHING */
}
/* Tell the architecture specific support to put the processor to sleep
* for 'n' ticks.
*/
os_trace_idle();
os_tick_idle(iticks);
OS_EXIT_CRITICAL(sr);
}
}
/**
* Has the operating system started.
*
* @return 1 if the operating system has started, 0 if it hasn't
*/
int
os_started(void)
{
return (g_os_started);
}
static void
os_main(void *arg)
{
int (*fn)(int argc, char **argv) = arg;
#if !MYNEWT_VAL(SELFTEST)
fn(0, NULL);
#else
(void)fn;
while (1) {
os_eventq_run(os_eventq_dflt_get());
}
#endif
assert(0);
}
#if MYNEWT_VAL(OS_WATCHDOG_MONITOR)
static void
os_wdog_monitor_tmo(void *arg)
{
/*
* Hardware watchdog about to fire.
* Stop in debugger/coredump/fault printout.
*/
assert(0);
while(1);
}
#endif
void
os_init_idle_task(void)
{
int rc;
rc = os_task_init(&g_idle_task, "idle", os_idle_task, NULL,
OS_IDLE_PRIO, OS_WAIT_FOREVER, g_idle_task_stack,
OS_STACK_ALIGN(OS_IDLE_STACK_SIZE));
assert(rc == 0);
/* Initialize sanity */
rc = os_sanity_init();
assert(rc == 0);
rc = hal_watchdog_init(MYNEWT_VAL(WATCHDOG_INTERVAL));
assert(rc == 0);
#if MYNEWT_VAL(OS_WATCHDOG_MONITOR)
os_cputime_timer_init(&os_wdog_monitor, os_wdog_monitor_tmo, NULL);
os_cputime_timer_relative(&os_wdog_monitor, OS_WDOG_MONITOR_TMO);
#endif
}
void
os_init(int (*main_fn)(int argc, char **arg))
{
os_error_t err;
#if MYNEWT_VAL(RTT)
memset(&_SEGGER_RTT, 0, sizeof(_SEGGER_RTT));
SEGGER_RTT_Init();
#endif
TAILQ_INIT(&g_callout_list);
STAILQ_INIT(&g_os_task_list);
os_eventq_init(os_eventq_dflt_get());
/* Initialize device list. */
os_dev_reset();
err = os_arch_os_init();
assert(err == OS_OK);
if (main_fn) {
err = os_task_init(&os_main_task, "main", os_main, main_fn,
OS_MAIN_TASK_PRIO, OS_WAIT_FOREVER, os_main_stack,
OS_STACK_ALIGN(OS_MAIN_STACK_SIZE));
assert(err == 0);
}
/* Call bsp related OS initializations */
hal_bsp_init();
err = (os_error_t) os_dev_initialize_all(OS_DEV_INIT_PRIMARY);
assert(err == OS_OK);
err = (os_error_t) os_dev_initialize_all(OS_DEV_INIT_SECONDARY);
assert(err == OS_OK);
}
void
os_start(void)
{
#if MYNEWT_VAL(OS_SCHEDULING)
os_error_t err;
/* Enable the watchdog prior to starting the OS */
hal_watchdog_enable();
err = os_arch_os_start();
assert(err == OS_OK);
#else
assert(0);
#endif
}
void
os_pkg_init(void)
{
os_error_t err;
/* Ensure this function only gets called by sysinit. */
SYSINIT_ASSERT_ACTIVE();
err = os_dev_initialize_all(OS_DEV_INIT_KERNEL);
assert(err == OS_OK);
os_msys_init();
}
/**
* }@ General OS functions
* }@ OS Kernel
*/