| /* |
| * 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 |
| */ |