From f1dba08467410f0e30e75b6cf8be7961fbddd86d Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 6 Dec 2017 10:36:40 +0100 Subject: [PATCH] porting: Add FreeRTOS port (based on nRF5 SDK) This patch adds port of Nimble stack to FreeRTOS based on nRF5 SDK. It's split into 'common' part which can be used a base for porting to any other platform and 'freertos_nrf5_sdk' which has FreeRTOS-specific files and makefile. Building and flashing is similar to other demo apps from nRF5 SDK: $ make -C porting/freertos_nrf5_sdk The resulting image can be flashed on nRF52 DK: $ make -C porting/freertos_nrf5_sdk flash Location of nRF5 SDK is set by NRF5_SDK_ROOT variable. By default it is set to 'nrf5_sdk' subdirectory so a symlink would work just fine: $ ln -s /nRF5_SDK_12.3.0_d7731ad porting/freertos_nrf5_sdk/nrf5_sdk --- .gitignore | 3 + porting/common/include/bsp/bsp.h | 14 + porting/common/include/console/console.h | 116 ++ porting/common/include/hal/hal_timer.h | 105 ++ porting/common/include/log/ignore.h | 64 + porting/common/include/log/log.h | 89 ++ porting/common/include/mem/mem.h | 66 + porting/common/include/nimble_port.h | 35 + porting/common/include/os/endian.h | 225 +++ porting/common/include/os/os.h | 99 ++ porting/common/include/os/os_arch.h | 26 + porting/common/include/os/os_callout.h | 62 + porting/common/include/os/os_cfg.h | 33 + porting/common/include/os/os_cputime.h | 242 +++ porting/common/include/os/os_dev.h | 123 ++ porting/common/include/os/os_error.h | 52 + porting/common/include/os/os_eventq.h | 68 + porting/common/include/os/os_fault.h | 34 + porting/common/include/os/os_heap.h | 38 + porting/common/include/os/os_malloc.h | 42 + porting/common/include/os/os_mbuf.h | 305 ++++ porting/common/include/os/os_mempool.h | 108 ++ porting/common/include/os/os_mutex.h | 67 + porting/common/include/os/os_sanity.h | 64 + porting/common/include/os/os_sched.h | 54 + porting/common/include/os/os_sem.h | 66 + porting/common/include/os/os_task.h | 128 ++ porting/common/include/os/os_test.h | 33 + porting/common/include/os/os_time.h | 120 ++ porting/common/include/os/os_trace_api.h | 84 + porting/common/include/os/queue.h | 522 +++++++ porting/common/include/stats/stats.h | 83 + porting/common/include/sysinit/sysinit.h | 128 ++ porting/common/src/mem/mem.c | 245 +++ porting/common/src/nimble_port.c | 65 + porting/common/src/os/endian.c | 218 +++ porting/common/src/os/os.c | 240 +++ porting/common/src/os/os_callout.c | 230 +++ porting/common/src/os/os_cputime.c | 215 +++ porting/common/src/os/os_cputime_1mhz.c | 52 + porting/common/src/os/os_cputime_high.c | 84 + porting/common/src/os/os_cputime_pwr2.c | 90 ++ porting/common/src/os/os_dev.c | 346 +++++ porting/common/src/os/os_eventq.c | 354 +++++ porting/common/src/os/os_heap.c | 124 ++ porting/common/src/os/os_mbuf.c | 1368 +++++++++++++++++ porting/common/src/os/os_mempool.c | 321 ++++ porting/common/src/os/os_msys_init.c | 88 ++ porting/common/src/os/os_mutex.c | 262 ++++ porting/common/src/os/os_priv.h | 41 + porting/common/src/os/os_sanity.c | 250 +++ porting/common/src/os/os_sched.c | 377 +++++ porting/common/src/os/os_sem.c | 225 +++ porting/common/src/os/os_task.c | 284 ++++ porting/common/src/os/os_time.c | 268 ++++ porting/common/src/sysinit/sysinit.c | 64 + porting/freertos_nrf5_sdk/Makefile | 257 ++++ .../freertos_nrf5_sdk/config/FreeRTOSConfig.h | 229 +++ porting/freertos_nrf5_sdk/config/sdk_config.h | 699 +++++++++ .../include/bsp/cmsis_nvic.h | 29 + .../freertos_nrf5_sdk/include/mcu/nrf52_hal.h | 70 + .../freertos_nrf5_sdk/include/os/os_arch.h | 25 + .../freertos_nrf5_sdk/include/os/os_callout.h | 52 + .../freertos_nrf5_sdk/include/os/os_eventq.h | 67 + .../freertos_nrf5_sdk/include/os/os_mutex.h | 46 + porting/freertos_nrf5_sdk/include/os/os_sem.h | 27 + .../freertos_nrf5_sdk/include/syscfg/syscfg.h | 967 ++++++++++++ .../nimble_FreeRTOS_gcc_nrf52.ld | 35 + porting/freertos_nrf5_sdk/src/ble_task.c | 175 +++ porting/freertos_nrf5_sdk/src/cmsis_nvic.c | 73 + porting/freertos_nrf5_sdk/src/hal_timer.c | 932 +++++++++++ porting/freertos_nrf5_sdk/src/main.c | 60 + porting/freertos_nrf5_sdk/src/os_port.c | 348 +++++ 73 files changed, 13200 insertions(+) create mode 100644 .gitignore create mode 100644 porting/common/include/bsp/bsp.h create mode 100644 porting/common/include/console/console.h create mode 100644 porting/common/include/hal/hal_timer.h create mode 100644 porting/common/include/log/ignore.h create mode 100644 porting/common/include/log/log.h create mode 100644 porting/common/include/mem/mem.h create mode 100755 porting/common/include/nimble_port.h create mode 100644 porting/common/include/os/endian.h create mode 100644 porting/common/include/os/os.h create mode 100755 porting/common/include/os/os_arch.h create mode 100644 porting/common/include/os/os_callout.h create mode 100644 porting/common/include/os/os_cfg.h create mode 100644 porting/common/include/os/os_cputime.h create mode 100644 porting/common/include/os/os_dev.h create mode 100644 porting/common/include/os/os_error.h create mode 100644 porting/common/include/os/os_eventq.h create mode 100644 porting/common/include/os/os_fault.h create mode 100644 porting/common/include/os/os_heap.h create mode 100644 porting/common/include/os/os_malloc.h create mode 100644 porting/common/include/os/os_mbuf.h create mode 100644 porting/common/include/os/os_mempool.h create mode 100644 porting/common/include/os/os_mutex.h create mode 100644 porting/common/include/os/os_sanity.h create mode 100644 porting/common/include/os/os_sched.h create mode 100644 porting/common/include/os/os_sem.h create mode 100644 porting/common/include/os/os_task.h create mode 100644 porting/common/include/os/os_test.h create mode 100644 porting/common/include/os/os_time.h create mode 100644 porting/common/include/os/os_trace_api.h create mode 100755 porting/common/include/os/queue.h create mode 100644 porting/common/include/stats/stats.h create mode 100644 porting/common/include/sysinit/sysinit.h create mode 100644 porting/common/src/mem/mem.c create mode 100644 porting/common/src/nimble_port.c create mode 100644 porting/common/src/os/endian.c create mode 100644 porting/common/src/os/os.c create mode 100644 porting/common/src/os/os_callout.c create mode 100644 porting/common/src/os/os_cputime.c create mode 100644 porting/common/src/os/os_cputime_1mhz.c create mode 100644 porting/common/src/os/os_cputime_high.c create mode 100644 porting/common/src/os/os_cputime_pwr2.c create mode 100644 porting/common/src/os/os_dev.c create mode 100644 porting/common/src/os/os_eventq.c create mode 100644 porting/common/src/os/os_heap.c create mode 100644 porting/common/src/os/os_mbuf.c create mode 100644 porting/common/src/os/os_mempool.c create mode 100644 porting/common/src/os/os_msys_init.c create mode 100644 porting/common/src/os/os_mutex.c create mode 100644 porting/common/src/os/os_priv.h create mode 100644 porting/common/src/os/os_sanity.c create mode 100644 porting/common/src/os/os_sched.c create mode 100644 porting/common/src/os/os_sem.c create mode 100644 porting/common/src/os/os_task.c create mode 100644 porting/common/src/os/os_time.c create mode 100644 porting/common/src/sysinit/sysinit.c create mode 100644 porting/freertos_nrf5_sdk/Makefile create mode 100644 porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h create mode 100644 porting/freertos_nrf5_sdk/config/sdk_config.h create mode 100644 porting/freertos_nrf5_sdk/include/bsp/cmsis_nvic.h create mode 100755 porting/freertos_nrf5_sdk/include/mcu/nrf52_hal.h create mode 100755 porting/freertos_nrf5_sdk/include/os/os_arch.h create mode 100644 porting/freertos_nrf5_sdk/include/os/os_callout.h create mode 100644 porting/freertos_nrf5_sdk/include/os/os_eventq.h create mode 100644 porting/freertos_nrf5_sdk/include/os/os_mutex.h create mode 100644 porting/freertos_nrf5_sdk/include/os/os_sem.h create mode 100644 porting/freertos_nrf5_sdk/include/syscfg/syscfg.h create mode 100644 porting/freertos_nrf5_sdk/nimble_FreeRTOS_gcc_nrf52.ld create mode 100644 porting/freertos_nrf5_sdk/src/ble_task.c create mode 100644 porting/freertos_nrf5_sdk/src/cmsis_nvic.c create mode 100644 porting/freertos_nrf5_sdk/src/hal_timer.c create mode 100644 porting/freertos_nrf5_sdk/src/main.c create mode 100644 porting/freertos_nrf5_sdk/src/os_port.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..dfb676a40 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# note: no / at the end since it could be either symlink or directory +/porting/freertos_nrf5_sdk/nrf5_sdk +/porting/freertos_nrf5_sdk/_build/ diff --git a/porting/common/include/bsp/bsp.h b/porting/common/include/bsp/bsp.h new file mode 100644 index 000000000..60f8a3c3e --- /dev/null +++ b/porting/common/include/bsp/bsp.h @@ -0,0 +1,14 @@ +#ifndef H_BSP_H +#define H_BSP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define bssnz_t + +#ifdef __cplusplus +} +#endif + +#endif /* H_BSP_H */ diff --git a/porting/common/include/console/console.h b/porting/common/include/console/console.h new file mode 100644 index 000000000..7f9f0ed37 --- /dev/null +++ b/porting/common/include/console/console.h @@ -0,0 +1,116 @@ +/* + * 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. + */ +#ifndef __CONSOLE_H__ +#define __CONSOLE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_eventq; + +struct console_input { + char line[0]; +}; + +typedef void (*console_rx_cb)(void); +typedef int (*console_append_char_cb)(char *line, uint8_t byte); +typedef void (*completion_cb)(char *str, console_append_char_cb cb); + +static int inline +console_is_init(void) +{ + return 0; +} + +static int inline +console_init(console_rx_cb rx_cb) +{ + return 0; +} + +static void inline +console_write(const char *str, int cnt) +{ +} + +static int inline +console_read(char *str, int cnt, int *newline) +{ + *newline = 0; + return 0; +} + +static void inline +console_blocking_mode(void) +{ +} + +static void inline +console_non_blocking_mode(void) +{ +} + +static void inline +console_echo(int on) +{ +} + +static int inline console_printf(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static int inline +console_printf(const char *fmt, ...) +{ + return 0; +} + +static void inline +console_set_queues(struct os_eventq *avail_queue, + struct os_eventq *cmd_queue) +{ +} + +static void inline +console_set_completion_cb(void (*completion)(char *str, console_append_char_cb cb)) +{ +} + +static int inline +console_handle_char(uint8_t byte) +{ + return 0; +} + +static int inline +console_out(int character) +{ + return 0; +} + +#define console_is_midline (0) + +#ifdef __cplusplus +} +#endif + +#endif /* __CONSOLE__ */ + diff --git a/porting/common/include/hal/hal_timer.h b/porting/common/include/hal/hal_timer.h new file mode 100644 index 000000000..19371308a --- /dev/null +++ b/porting/common/include/hal/hal_timer.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#ifndef H_HAL_TIMER_ +#define H_HAL_TIMER_ + +#include +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "os/queue.h" + +/* HAL timer struct */ +typedef void (*hal_timer_cb)(void *arg); + +/** + * The HAL timer structure. The user can declare as many of these structures + * as desired. They are enqueued on a particular HW timer queue when the user + * calls the hal_timer_start or hal_timer_start_at API. The user must have + * called hal_timer_set_cb before starting a timer. + * + * NOTE: the user should not have to modify/examine the contents of this + * structure; the hal timer API should be used. + */ +struct hal_timer +{ + void *bsp_timer; /* Internal platform specific pointer */ + hal_timer_cb cb_func; /* Callback function */ + void *cb_arg; /* Callback argument */ + uint32_t expiry; /* Tick at which timer should expire */ + TAILQ_ENTRY(hal_timer) link; /* Queue linked list structure */ +}; + +/* Initialize a HW timer. */ +int hal_timer_init(int timer_num, void *cfg); + +/* Un-initialize a HW timer. */ +int hal_timer_deinit(int timer_num); + +/* + * Config a HW timer at the given frequency and start it. If the exact + * frequency is not obtainable the closest obtainable frequency is set. + */ +int hal_timer_config(int timer_num, uint32_t freq_hz); + +/* + * Returns the resolution of the HW timer. NOTE: the frequency may not be + * obtainable so the caller can use this to determine the resolution. + * Returns resolution in nanoseconds. A return value of 0 indicates an invalid + * timer was used. + */ +uint32_t hal_timer_get_resolution(int timer_num); + +/* Returns the HW timer current tick value */ +uint32_t hal_timer_read(int timer_num); + +/* Perform a blocking delay for a number of ticks. */ +int hal_timer_delay(int timer_num, uint32_t ticks); + +/* + * Set the timer structure prior to use. Should not be called if the timer + * is running. Must be called at least once prior to using timer. + */ +int hal_timer_set_cb(int timer_num, struct hal_timer *tmr, hal_timer_cb cb_func, + void *arg); + +/* Start a timer that will expire in 'ticks' ticks. Ticks cannot be 0 */ +int hal_timer_start(struct hal_timer *, uint32_t ticks); + +/* + * Start a timer that will expire when the timer reaches 'tick'. If tick + * has already passed the timer callback will be called "immediately" (at + * interrupt context). + */ +int hal_timer_start_at(struct hal_timer *, uint32_t tick); + +/* Stop a currently running timer; associated callback will NOT be called */ +int hal_timer_stop(struct hal_timer *); + +#ifdef __cplusplus +} +#endif + +#endif /* H_HAL_TIMER_ */ diff --git a/porting/common/include/log/ignore.h b/porting/common/include/log/ignore.h new file mode 100644 index 000000000..46282a029 --- /dev/null +++ b/porting/common/include/log/ignore.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef H_IGNORE_ +#define H_IGNORE_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * These macros prevent the "set but not used" warnings for log writes below + * the log level. + */ + +#define IGN_1(X) ((void)(X)) +#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__) +#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__) +#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__) +#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__) +#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__) +#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__) +#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__) +#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__) +#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__) +#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__) +#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__) +#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__) +#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__) +#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__) +#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__) +#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__) +#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__) +#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__) +#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__) + +#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \ + _13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME +#define IGNORE(...) \ + GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \ + IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \ + IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/include/log/log.h b/porting/common/include/log/log.h new file mode 100644 index 000000000..ac4d7e7f1 --- /dev/null +++ b/porting/common/include/log/log.h @@ -0,0 +1,89 @@ +/* + * 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. + */ +#ifndef __SYS_LOG_STUB_H__ +#define __SYS_LOG_STUB_H__ + +#include +#include "syscfg/syscfg.h" +#include "log/ignore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LOG_DEBUG(__l, __mod, ...) IGNORE(__VA_ARGS__) +#define LOG_INFO(__l, __mod, ...) IGNORE(__VA_ARGS__) +#define LOG_WARN(__l, __mod, ...) IGNORE(__VA_ARGS__) +#define LOG_ERROR(__l, __mod, ...) IGNORE(__VA_ARGS__) +#define LOG_CRITICAL(__l, __mod, ...) IGNORE(__VA_ARGS__) + +#define LOG_LEVEL_DEBUG 0 +#define LOG_LEVEL_INFO 1 +#define LOG_LEVEL_WARN 2 +#define LOG_LEVEL_ERROR 3 +#define LOG_LEVEL_CRITICAL 4 +/* Up to 7 custom log levels. */ +#define LOG_LEVEL_MAX UINT8_MAX +#define LOG_SYSLEVEL UINT8_MAX + +/* Logging medium */ +#define LOG_STORE_CONSOLE 1 +#define LOG_STORE_CBMEM 2 +#define LOG_STORE_FCB 3 + +/* Global log info */ +struct log_info { + uint32_t li_next_index; + uint8_t li_version; +}; + +struct log_info g_log_info; + +struct log { +}; + +struct log_handler { +}; + +static inline int +log_register(char *name, struct log *log, const struct log_handler *h, + void *arg, uint8_t level) +{ + return 0; +} + +static inline void +log_init(void) +{ +} + +#define log_printf(...) + +/* + * Dummy handler exports. + */ +const struct log_handler log_console_handler; +const struct log_handler log_cbmem_handler; +const struct log_handler log_fcb_handler; + +#ifdef __cplusplus +} +#endif + +#endif /* __SYS_LOG_STUB_H__ */ diff --git a/porting/common/include/mem/mem.h b/porting/common/include/mem/mem.h new file mode 100644 index 000000000..18461b6e4 --- /dev/null +++ b/porting/common/include/mem/mem.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef H_UTIL_MEM_ +#define H_UTIL_MEM_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_mempool; +struct os_mbuf_pool; + +int mem_malloc_mempool(struct os_mempool *mempool, int num_blocks, + int block_size, char *name, void **out_buf); + +int mem_malloc_mbuf_pool(struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, int num_blocks, + int block_size, char *name, + void **out_buf); +int mem_malloc_mbufpkt_pool(struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, int num_blocks, + int block_size, char *name, + void **out_buf); +int mem_init_mbuf_pool(void *mem, struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, int num_blocks, + int block_size, char *name); + +/** + * Specifies a function used as a callback. Functions of this type allocate an + * mbuf chain meant to hold a packet fragment. The resulting mbuf must contain + * a pkthdr. + * + * @param frag_size The number of data bytes that the mbuf will + * eventually contain. + * @param arg A generic parameter. + * + * @return An allocated mbuf chain on success; + * NULL on failure. + */ +typedef struct os_mbuf *mem_frag_alloc_fn(uint16_t frag_size, void *arg); + +struct os_mbuf *mem_split_frag(struct os_mbuf **om, uint16_t max_frag_sz, + mem_frag_alloc_fn *alloc_cb, void *cb_arg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/include/nimble_port.h b/porting/common/include/nimble_port.h new file mode 100755 index 000000000..6d5e2141a --- /dev/null +++ b/porting/common/include/nimble_port.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef __NIMBLE_PORT_H__ +#define __NIMBLE_PORT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +void nimble_init(void); + +void nimble_run(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __NIMBLE_PORT_H__ */ diff --git a/porting/common/include/os/endian.h b/porting/common/include/os/endian.h new file mode 100644 index 000000000..ca8698d43 --- /dev/null +++ b/porting/common/include/os/endian.h @@ -0,0 +1,225 @@ +/* + * 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. + */ + +#ifndef H_ENDIAN_ +#define H_ENDIAN_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Internal helpers */ +#ifndef os_bswap_64 +#define os_bswap_64(x) ((uint64_t) \ + ((((x) & 0xff00000000000000ull) >> 56) | \ + (((x) & 0x00ff000000000000ull) >> 40) | \ + (((x) & 0x0000ff0000000000ull) >> 24) | \ + (((x) & 0x000000ff00000000ull) >> 8) | \ + (((x) & 0x00000000ff000000ull) << 8) | \ + (((x) & 0x0000000000ff0000ull) << 24) | \ + (((x) & 0x000000000000ff00ull) << 40) | \ + (((x) & 0x00000000000000ffull) << 56))) +#endif + +#ifndef os_bswap_32 +#define os_bswap_32(x) ((uint32_t) \ + ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24))) +#endif + +#ifndef os_bswap_16 +#define os_bswap_16(x) ((uint16_t) \ + ((((x) & 0xff00) >> 8) | \ + (((x) & 0x00ff) << 8))) +#endif + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + +#ifndef ntohll +#define ntohll(x) ((uint64_t)(x)) +#endif + +#ifndef htonll +#define htonll(x) ((uint64_t)(x)) +#endif + +#ifndef ntohl +#define ntohl(x) ((uint32_t)(x)) +#endif + +#ifndef htonl +#define htonl(x) ((uint32_t)(x)) +#endif + +#ifndef ntohs +#define ntohs(x) ((uint16_t)(x)) +#endif + +#ifndef htons +#define htons(x) ((uint16_t)(x)) +#endif + +#ifndef htobe16 +#define htobe16(x) ((uint16_t)(x)) +#endif + +#ifndef htole16 +#define htole16(x) os_bswap_16 (x) +#endif + +#ifndef be16toh +#define be16toh(x) ((uint16_t)(x)) +#endif + +#ifndef le16toh +#define le16toh(x) os_bswap_16 (x) +#endif + +#ifndef htobe32 +#define htobe32(x) ((uint32_t)(x)) +#endif + +#ifndef htole32 +#define htole32(x) os_bswap_32 (x) +#endif + +#ifndef be32toh +#define be32toh(x) ((uint32_t)(x)) +#endif + +#ifndef le32toh +#define le32toh(x) os_bswap_32 (x) +#endif + +#ifndef htobe64 +#define htobe64(x) ((uint64_t)(x)) +#endif + +#ifndef htole64 +#define htole64(x) os_bswap_64 (x) +#endif + +#ifndef be64toh +#define be64toh(x) ((uint64_t)(x)) +#endif + +#ifndef le64toh +#define le64toh(x) os_bswap_64 (x) +#endif + +#else + +#ifndef ntohll +#define ntohll(x) os_bswap_64(x) +#endif + +#ifndef htonll +#define htonll ntohll +#endif + +#ifndef ntohl +#define ntohl(x) os_bswap_32(x) +#endif + +#ifndef htonl +#define htonl ntohl +#endif + +#ifndef htons +#define htons(x) os_bswap_16(x) +#endif + +#ifndef ntohs +#define ntohs htons +#endif + +#ifndef htobe16 +#define htobe16(x) os_bswap_16(x) +#endif + +#ifndef htole16 +#define htole16(x) ((uint16_t)(x)) +#endif + +#ifndef be16toh +#define be16toh(x) os_bswap_16(x) +#endif + +#ifndef le16toh +#define le16toh(x) ((uint16_t)(x)) +#endif + +#ifndef htobe32 +#define htobe32(x) os_bswap_32(x) +#endif + +#ifndef htole32 +#define htole32(x) ((uint32_t)(x)) +#endif + +#ifndef be32toh +#define be32toh(x) os_bswap_32(x) +#endif + +#ifndef le32toh +#define le32toh(x) ((uint32_t)(x)) +#endif + +#ifndef htobe64 +#define htobe64(x) os_bswap64(x) +#endif + +#ifndef htole64 +#define htole64(x) ((uint64_t)(x)) +#endif + +#ifndef be64toh +#define be64toh(x) os_bswap64(x) +#endif + +#ifndef le64toh +#define le64toh(x) ((uint64_t)(x)) +#endif + +#endif + +void put_le16(void *buf, uint16_t x); +void put_le32(void *buf, uint32_t x); +void put_le64(void *buf, uint64_t x); +uint16_t get_le16(const void *buf); +uint32_t get_le32(const void *buf); +uint64_t get_le64(const void *buf); +void put_be16(void *buf, uint16_t x); +void put_be32(void *buf, uint32_t x); +void put_be64(void *buf, uint64_t x); +uint16_t get_be16(const void *buf); +uint32_t get_be32(const void *buf); +uint64_t get_be64(const void *buf); +void swap_in_place(void *buf, int len); +void swap_buf(uint8_t *dst, const uint8_t *src, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/include/os/os.h b/porting/common/include/os/os.h new file mode 100644 index 000000000..9ff6ed58e --- /dev/null +++ b/porting/common/include/os/os.h @@ -0,0 +1,99 @@ +/* + * 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. + */ + +#ifndef _OS_H +#define _OS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef min +#define min(a, b) ((a)<(b)?(a):(b)) +#endif + +#ifndef max +#define max(a, b) ((a)>(b)?(a):(b)) +#endif + +#define os_get_return_addr() (__builtin_return_address(0)) + +#define OS_ALIGN(__n, __a) ( \ + (((__n) & ((__a) - 1)) == 0) ? \ + (__n) : \ + ((__n) + ((__a) - ((__n) & ((__a) - 1)))) \ + ) + + +#define CTASSERT(x) typedef int __ctasssert ## __LINE__[(x) ? 1 : -1] + + +/** + * Whether or not the operating system has been started. Set to + * 1 right before first task is run. + */ +extern int g_os_started; + +int os_info_init(void); + +/** + * Returns 1 if the OS has been started, 0 if it has not yet been + * been started. + */ +int os_started(void); + +#define OS_WAIT_FOREVER (-1) + +#define OS_IDLE_PRIO (0xff) +#define OS_MAIN_TASK_PRIO MYNEWT_VAL(OS_MAIN_TASK_PRIO) +#define OS_MAIN_STACK_SIZE MYNEWT_VAL(OS_MAIN_STACK_SIZE) + +void os_init(int (*fn)(int argc, char **argv)); +void os_start(void); + +/* XXX: Not sure if this should go here; I want to differentiate API that + * should be called by application developers as those that should not. */ +void os_init_idle_task(void); + +#include "os/endian.h" +#include "os/os_arch.h" +#include "os/os_callout.h" +#include "os/os_cputime.h" +#include "os/os_dev.h" +#include "os/os_error.h" +#include "os/os_eventq.h" +#include "os/os_heap.h" +#include "os/os_fault.h" +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "os/os_mutex.h" +#include "os/os_sanity.h" +#include "os/os_sched.h" +#include "os/os_sem.h" +#include "os/os_task.h" +#include "os/os_time.h" + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_H */ diff --git a/porting/common/include/os/os_arch.h b/porting/common/include/os/os_arch.h new file mode 100755 index 000000000..22d47f7ad --- /dev/null +++ b/porting/common/include/os/os_arch.h @@ -0,0 +1,26 @@ +#ifndef _OS_ARCH_H +#define _OS_ARCH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int os_sr_t; +typedef int os_stack_t; + +#define OS_ALIGNMENT (4) +#define OS_TICKS_PER_SEC (1000) + +extern void vPortEnterCritical(void); +extern void vPortExitCritical(void); + +#define OS_ENTER_CRITICAL(unused) do { (void)unused; vPortEnterCritical(); } while (0) +#define OS_EXIT_CRITICAL(unused) do { (void)unused; vPortExitCritical(); } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_ARCH_H */ diff --git a/porting/common/include/os/os_callout.h b/porting/common/include/os/os_callout.h new file mode 100644 index 000000000..254d7a4ee --- /dev/null +++ b/porting/common/include/os/os_callout.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + + +#ifndef _OS_CALLOUT_H +#define _OS_CALLOUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define OS_CALLOUT_F_QUEUED (0x01) + +#include "os/os_eventq.h" + +struct os_callout { + struct os_event c_ev; + struct os_eventq *c_evq; + uint32_t c_ticks; + TAILQ_ENTRY(os_callout) c_next; +}; + +TAILQ_HEAD(os_callout_list, os_callout); + +void os_callout_init(struct os_callout *cf, struct os_eventq *evq, + os_event_fn *ev_cb, void *ev_arg); +void os_callout_stop(struct os_callout *); +int os_callout_reset(struct os_callout *, int32_t); +void os_callout_tick(void); +os_time_t os_callout_wakeup_ticks(os_time_t now); +os_time_t os_callout_remaining_ticks(struct os_callout *c, os_time_t now); + +static inline int +os_callout_queued(struct os_callout *c) +{ + return c->c_next.tqe_prev != NULL; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_CALLOUT_H */ + + + diff --git a/porting/common/include/os/os_cfg.h b/porting/common/include/os/os_cfg.h new file mode 100644 index 000000000..15f43d541 --- /dev/null +++ b/porting/common/include/os/os_cfg.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + + +#ifndef _OS_CFG_H_ +#define _OS_CFG_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_CFG_H_ */ diff --git a/porting/common/include/os/os_cputime.h b/porting/common/include/os/os_cputime.h new file mode 100644 index 000000000..fc3b8817a --- /dev/null +++ b/porting/common/include/os/os_cputime.h @@ -0,0 +1,242 @@ +/* + * 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. + */ + +#ifndef H_OS_CPUTIME_ +#define H_OS_CPUTIME_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "syscfg/syscfg.h" +#include "os/queue.h" +#include "hal/hal_timer.h" + +/* + * NOTE: these definitions allow one to override the cputime frequency used. + * The reason these definitions exist is to make the code more + * efficient/smaller when CPUTIME counts at 1 MHz. + * + * For those who want a different cputime frequency, you can set the config + * definition for OS_CPUTIME_FREQ to the desired frequency in your project, + * target or bsp. + */ +#if (MYNEWT_VAL(OS_CPUTIME_FREQ) == 1000000) + +#define OS_CPUTIME_FREQ_1MHZ + +#elif MYNEWT_VAL(OS_CPUTIME_FREQ) == 256 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 512 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 1024 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 2048 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 4096 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 8192 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 16384 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 65536 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 131072 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 262144 || \ + MYNEWT_VAL(OS_CPUTIME_FREQ) == 524288 + +#define OS_CPUTIME_FREQ_PWR2 + +#elif MYNEWT_VAL(OS_CPUTIME_FREQ) > 1000000 + +#define OS_CPUTIME_FREQ_HIGH + +#else + +#error "Invalid OS_CPUTIME_FREQ value. Value must be one of a) a power of 2" \ + ">= 256Hz, or b) any value >= 1MHz" + +#endif + +#if defined(OS_CPUTIME_FREQ_HIGH) +/* CPUTIME data. */ +struct os_cputime_data +{ + uint32_t ticks_per_usec; /* number of ticks per usec */ +}; +extern struct os_cputime_data g_os_cputime; +#endif + +/* Helpful macros to compare cputimes */ +#define CPUTIME_LT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) < 0) +#define CPUTIME_GT(__t1, __t2) ((int32_t) ((__t1) - (__t2)) > 0) +#define CPUTIME_GEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) >= 0) +#define CPUTIME_LEQ(__t1, __t2) ((int32_t) ((__t1) - (__t2)) <= 0) + +/** + * os cputime init + * + * Initialize the cputime module. This must be called after os_init is called + * and before any other timer API are used. This should be called only once + * and should be called before the hardware timer is used. + * + * @param clock_freq The desired cputime frequency, in hertz (Hz). + * + * @return int 0 on success; -1 on error. + */ +int os_cputime_init(uint32_t clock_freq); + +/** + * os cputime get32 + * + * Returns the low 32 bits of cputime. + * + * @return uint32_t The lower 32 bits of cputime + */ +uint32_t os_cputime_get32(void); + +#if !defined(OS_CPUTIME_FREQ_PWR2) +/** + * os cputime nsecs to ticks + * + * Converts the given number of nanoseconds into cputime ticks. + * + * @param usecs The number of nanoseconds to convert to ticks + * + * @return uint32_t The number of ticks corresponding to 'nsecs' + */ +uint32_t os_cputime_nsecs_to_ticks(uint32_t nsecs); + +/** + * os cputime ticks to nsecs + * + * Convert the given number of ticks into nanoseconds. + * + * @param ticks The number of ticks to convert to nanoseconds. + * + * @return uint32_t The number of nanoseconds corresponding to 'ticks' + */ +uint32_t os_cputime_ticks_to_nsecs(uint32_t ticks); + +/** + * os cputime delay nsecs + * + * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay. + * + * @param nsecs The number of nanoseconds to wait. + */ +void os_cputime_delay_nsecs(uint32_t nsecs); +#endif + +#if defined(OS_CPUTIME_FREQ_1MHZ) +#define os_cputime_usecs_to_ticks(x) (x) +#define os_cputime_ticks_to_usecs(x) (x) +#else +/** + * os cputime usecs to ticks + * + * Converts the given number of microseconds into cputime ticks. + * + * @param usecs The number of microseconds to convert to ticks + * + * @return uint32_t The number of ticks corresponding to 'usecs' + */ +uint32_t os_cputime_usecs_to_ticks(uint32_t usecs); + +/** + * os cputime ticks to usecs + * + * Convert the given number of ticks into microseconds. + * + * @param ticks The number of ticks to convert to microseconds. + * + * @return uint32_t The number of microseconds corresponding to 'ticks' + */ +uint32_t os_cputime_ticks_to_usecs(uint32_t ticks); +#endif + +/** + * os cputime delay ticks + * + * Wait until the number of ticks has elapsed. This is a blocking delay. + * + * @param ticks The number of ticks to wait. + */ +void os_cputime_delay_ticks(uint32_t ticks); + +/** + * os cputime delay usecs + * + * Wait until 'usecs' microseconds has elapsed. This is a blocking delay. + * + * @param usecs The number of usecs to wait. + */ +void os_cputime_delay_usecs(uint32_t usecs); + +/** + * os cputime timer init + * + * @param timer The timer to initialize. Cannot be NULL. + * @param fp The timer callback function. Cannot be NULL. + * @param arg Pointer to data object to pass to timer. + */ +void os_cputime_timer_init(struct hal_timer *timer, hal_timer_cb fp, void *arg); + +/** + * os cputime timer start + * + * Start a cputimer that will expire at 'cputime'. If cputime has already + * passed, the timer callback will still be called (at interrupt context). + * + * NOTE: This must be called when the timer is stopped. + * + * @param timer Pointer to timer to start. Cannot be NULL. + * @param cputime The cputime at which the timer should expire. + * + * @return int 0 on success; EINVAL if timer already started or timer struct + * invalid + * + */ +int os_cputime_timer_start(struct hal_timer *timer, uint32_t cputime); + +/** + * os cputimer timer relative + * + * Sets a cpu timer that will expire 'usecs' microseconds from the current + * cputime. + * + * NOTE: This must be called when the timer is stopped. + * + * @param timer Pointer to timer. Cannot be NULL. + * @param usecs The number of usecs from now at which the timer will expire. + * + * @return int 0 on success; EINVAL if timer already started or timer struct + * invalid + */ +int os_cputime_timer_relative(struct hal_timer *timer, uint32_t usecs); + +/** + * os cputime timer stop + * + * Stops a cputimer from running. The timer is removed from the timer queue + * and interrupts are disabled if no timers are left on the queue. Can be + * called even if timer is not running. + * + * @param timer Pointer to cputimer to stop. Cannot be NULL. + */ +void os_cputime_timer_stop(struct hal_timer *timer); + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_CPUTIME_ */ diff --git a/porting/common/include/os/os_dev.h b/porting/common/include/os/os_dev.h new file mode 100644 index 000000000..ed65a0873 --- /dev/null +++ b/porting/common/include/os/os_dev.h @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#ifndef _OS_DEV_H +#define _OS_DEV_H + +#include + +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_dev; + +/* + * Initialization order, defines when a device should be initialized + * by the Mynewt kernel. + * + */ +#define OS_DEV_INIT_PRIMARY (1) +#define OS_DEV_INIT_SECONDARY (2) +#define OS_DEV_INIT_KERNEL (3) + +#define OS_DEV_INIT_F_CRITICAL (1 << 0) + + +#define OS_DEV_INIT_PRIO_DEFAULT (0xff) + +/** + * Device status, so functions can ensure device is called in a + * consistent state. + */ +#define OS_DEV_F_STATUS_READY (1 << 0) +#define OS_DEV_F_STATUS_OPEN (1 << 1) +#define OS_DEV_F_STATUS_SUSPENDED (1 << 2) +#define OS_DEV_F_INIT_CRITICAL (1 << 3) + +typedef int (*os_dev_init_func_t)(struct os_dev *, void *); +typedef int (*os_dev_open_func_t)(struct os_dev *, uint32_t, + void *); +typedef int (*os_dev_suspend_func_t)(struct os_dev *, os_time_t, int); +typedef int (*os_dev_resume_func_t)(struct os_dev *); +typedef int (*os_dev_close_func_t)(struct os_dev *); + +struct os_dev_handlers { + os_dev_open_func_t od_open; + os_dev_suspend_func_t od_suspend; + os_dev_resume_func_t od_resume; + os_dev_close_func_t od_close; +}; + +/* + * Device structure. + */ +struct os_dev { + struct os_dev_handlers od_handlers; + os_dev_init_func_t od_init; + void *od_init_arg; + uint8_t od_stage; + uint8_t od_priority; + uint8_t od_open_ref; + uint8_t od_flags; + char *od_name; + STAILQ_ENTRY(os_dev) od_next; +}; + +#define OS_DEV_SETHANDLERS(__dev, __open, __close) \ + (__dev)->od_handlers.od_open = (__open); \ + (__dev)->od_handlers.od_close = (__close); + +static inline int +os_dev_suspend(struct os_dev *dev, os_time_t suspend_t, uint8_t force) +{ + if (dev->od_handlers.od_suspend == NULL) { + return (0); + } else { + return (dev->od_handlers.od_suspend(dev, suspend_t, force)); + } +} + +static inline int +os_dev_resume(struct os_dev *dev) +{ + if (dev->od_handlers.od_resume == NULL) { + return (0); + } else { + return (dev->od_handlers.od_resume(dev)); + } +} + +int os_dev_create(struct os_dev *dev, char *name, uint8_t stage, + uint8_t priority, os_dev_init_func_t od_init, void *arg); +struct os_dev *os_dev_lookup(char *name); +int os_dev_initialize_all(uint8_t stage); +int os_dev_suspend_all(os_time_t, uint8_t); +int os_dev_resume_all(void); +struct os_dev *os_dev_open(char *devname, uint32_t timo, void *arg); +int os_dev_close(struct os_dev *dev); +void os_dev_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_DEV_H */ diff --git a/porting/common/include/os/os_error.h b/porting/common/include/os/os_error.h new file mode 100644 index 000000000..01df389be --- /dev/null +++ b/porting/common/include/os/os_error.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef H_OS_ERROR_ +#define H_OS_ERROR_ + +#include "syscfg/syscfg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* OS error enumerations */ +enum os_error { + OS_OK = 0, + OS_ENOMEM = 1, + OS_EINVAL = 2, + OS_INVALID_PARM = 3, + OS_MEM_NOT_ALIGNED = 4, + OS_BAD_MUTEX = 5, + OS_TIMEOUT = 6, + OS_ERR_IN_ISR = 7, /* Function cannot be called from ISR */ + OS_ERR_PRIV = 8, /* Privileged access error */ + OS_NOT_STARTED = 9, /* OS must be started to call this function, but isn't */ + OS_ENOENT = 10, /* No such thing */ + OS_EBUSY = 11, /* Resource busy */ + OS_ERROR = 12, /* Generic Error */ +}; + +typedef enum os_error os_error_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/include/os/os_eventq.h b/porting/common/include/os/os_eventq.h new file mode 100644 index 000000000..b0c3abdb2 --- /dev/null +++ b/porting/common/include/os/os_eventq.h @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#ifndef _OS_EVENTQ_H +#define _OS_EVENTQ_H + +#include +#include "os/os_time.h" +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_event; +typedef void os_event_fn(struct os_event *ev); + +struct os_event { + uint8_t ev_queued; + os_event_fn *ev_cb; + void *ev_arg; + STAILQ_ENTRY(os_event) ev_next; +}; + +#define OS_EVENT_QUEUED(__ev) ((__ev)->ev_queued) + +struct os_eventq { + struct os_task *evq_owner; /* owner task */ + struct os_task *evq_task; /* sleeper; must be either NULL, or the owner */ + STAILQ_HEAD(, os_event) evq_list; +}; + +void os_eventq_init(struct os_eventq *); +int os_eventq_inited(const struct os_eventq *evq); +void os_eventq_put(struct os_eventq *, struct os_event *); +struct os_event *os_eventq_get_no_wait(struct os_eventq *evq); +struct os_event *os_eventq_get(struct os_eventq *); +void os_eventq_run(struct os_eventq *evq); +struct os_event *os_eventq_poll(struct os_eventq **, int, os_time_t); +void os_eventq_remove(struct os_eventq *, struct os_event *); +struct os_eventq *os_eventq_dflt_get(void); + +/* [DEPRECATED] */ +void os_eventq_designate(struct os_eventq **dst, struct os_eventq *val, + struct os_event *start_ev); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_EVENTQ_H */ + diff --git a/porting/common/include/os/os_fault.h b/porting/common/include/os/os_fault.h new file mode 100644 index 000000000..4ce34c26f --- /dev/null +++ b/porting/common/include/os/os_fault.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#ifndef _OS_FAULT_H +#define _OS_FAULT_H + +#ifdef __cplusplus +extern "c" { +#endif + +void __assert_func(const char *, int, const char *, const char *) + __attribute((noreturn)); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_FAULT_H */ diff --git a/porting/common/include/os/os_heap.h b/porting/common/include/os/os_heap.h new file mode 100644 index 000000000..4413568e4 --- /dev/null +++ b/porting/common/include/os/os_heap.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef H_OS_HEAP_ +#define H_OS_HEAP_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void *os_malloc(size_t size); +void os_free(void *mem); +void *os_realloc(void *ptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/porting/common/include/os/os_malloc.h b/porting/common/include/os/os_malloc.h new file mode 100644 index 000000000..32b72c2a6 --- /dev/null +++ b/porting/common/include/os/os_malloc.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#ifndef H_OS_MALLOC_ +#define H_OS_MALLOC_ + +#include "os/os_heap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#undef malloc +#define malloc os_malloc + +#undef free +#define free os_free + +#undef realloc +#define realloc os_realloc + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/include/os/os_mbuf.h b/porting/common/include/os/os_mbuf.h new file mode 100644 index 000000000..314a2ebe7 --- /dev/null +++ b/porting/common/include/os/os_mbuf.h @@ -0,0 +1,305 @@ +/* + * 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. + */ + +#ifndef _OS_MBUF_H +#define _OS_MBUF_H + +#include "os/queue.h" +#include "os/os_eventq.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A mbuf pool from which to allocate mbufs. This contains a pointer to the os + * mempool to allocate mbufs out of, the total number of elements in the pool, + * and the amount of "user" data in a non-packet header mbuf. The total pool + * size, in bytes, should be: + * os_mbuf_count * (omp_databuf_len + sizeof(struct os_mbuf)) + */ +struct os_mbuf_pool { + /** + * Total length of the databuf in each mbuf. This is the size of the + * mempool block, minus the mbuf header + */ + uint16_t omp_databuf_len; + /** + * Total number of memblock's allocated in this mempool. + */ + uint16_t omp_mbuf_count; + /** + * The memory pool which to allocate mbufs out of + */ + struct os_mempool *omp_pool; + + /** + * Link to the next mbuf pool for system memory pools. + */ + STAILQ_ENTRY(os_mbuf_pool) omp_next; +}; + + +/** + * A packet header structure that preceeds the mbuf packet headers. + */ +struct os_mbuf_pkthdr { + /** + * Overall length of the packet. + */ + uint16_t omp_len; + /** + * Flags + */ + uint16_t omp_flags; + /** + * Next packet in the mbuf chain. + */ + STAILQ_ENTRY(os_mbuf_pkthdr) omp_next; +}; + +/** + * Chained memory buffer. + */ +struct os_mbuf { + /** + * Current pointer to data in the structure + */ + uint8_t *om_data; + /** + * Flags associated with this buffer, see OS_MBUF_F_* defintions + */ + uint8_t om_flags; + /** + * Length of packet header + */ + uint8_t om_pkthdr_len; + /** + * Length of data in this buffer + */ + uint16_t om_len; + + /** + * The mbuf pool this mbuf was allocated out of + */ + struct os_mbuf_pool *om_omp; + + /** + * Pointer to next entry in the chained memory buffer + */ + SLIST_ENTRY(os_mbuf) om_next; + + /** + * Pointer to the beginning of the data, after this buffer + */ + uint8_t om_databuf[0]; +}; + +struct os_mqueue { + STAILQ_HEAD(, os_mbuf_pkthdr) mq_head; + struct os_event mq_ev; +}; + +/* + * Given a flag number, provide the mask for it + * + * @param __n The number of the flag in the mask + */ +#define OS_MBUF_F_MASK(__n) (1 << (__n)) + +/* + * Checks whether a given mbuf is a packet header mbuf + * + * @param __om The mbuf to check + */ +#define OS_MBUF_IS_PKTHDR(__om) \ + ((__om)->om_pkthdr_len >= sizeof (struct os_mbuf_pkthdr)) + +/* Get a packet header pointer given an mbuf pointer */ +#define OS_MBUF_PKTHDR(__om) ((struct os_mbuf_pkthdr *) \ + ((uint8_t *)&(__om)->om_data + sizeof(struct os_mbuf))) + +/* Given a mbuf packet header pointer, return a pointer to the mbuf */ +#define OS_MBUF_PKTHDR_TO_MBUF(__hdr) \ + (struct os_mbuf *)((uint8_t *)(__hdr) - sizeof(struct os_mbuf)) + +/** + * Gets the length of an entire mbuf chain. The specified mbuf must have a + * packet header. + */ +#define OS_MBUF_PKTLEN(__om) (OS_MBUF_PKTHDR(__om)->omp_len) + +/* + * Access the data of a mbuf, and cast it to type + * + * @param __om The mbuf to access, and cast + * @param __type The type to cast it to + */ +#define OS_MBUF_DATA(__om, __type) \ + (__type) ((__om)->om_data) + +/** + * Access the "user header" in the head of an mbuf chain. + * + * @param om Pointer to the head of an mbuf chain. + */ +#define OS_MBUF_USRHDR(om) \ + (void *)((uint8_t *)om + sizeof (struct os_mbuf) + \ + sizeof (struct os_mbuf_pkthdr)) + +/** + * Retrieves the length of the user header in an mbuf. + * + * @param om Pointer to the mbuf to query. + */ +#define OS_MBUF_USRHDR_LEN(om) \ + ((om)->om_pkthdr_len - sizeof (struct os_mbuf_pkthdr)) + +/* + * Called by OS_MBUF_LEADINGSPACE() macro + */ +static inline uint16_t +_os_mbuf_leadingspace(struct os_mbuf *om) +{ + uint16_t startoff; + uint16_t leadingspace; + + startoff = 0; + if (OS_MBUF_IS_PKTHDR(om)) { + startoff = om->om_pkthdr_len; + } + + leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) - + ((uint8_t *) &om->om_databuf[0] + startoff)); + + return (leadingspace); +} + +/** + * Returns the leading space (space at the beginning) of the mbuf. + * Works on both packet header, and regular mbufs, as it accounts + * for the additional space allocated to the packet header. + * + * @param __omp Is the mbuf pool (which contains packet header length.) + * @param __om Is the mbuf in that pool to get the leadingspace for + * + * @return Amount of leading space available in the mbuf + */ +#define OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om) + +/* Called by OS_MBUF_TRAILINGSPACE() macro. */ +static inline uint16_t +_os_mbuf_trailingspace(struct os_mbuf *om) +{ + struct os_mbuf_pool *omp; + + omp = om->om_omp; + + return (&om->om_databuf[0] + omp->omp_databuf_len) - + (om->om_data + om->om_len); +} + +/** + * Returns the trailing space (space at the end) of the mbuf. + * Works on both packet header and regular mbufs. + * + * @param __omp The mbuf pool for this mbuf + * @param __om Is the mbuf in that pool to get trailing space for + * + * @return The amount of trailing space available in the mbuf + */ +#define OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om) + +/* Mbuf queue functions */ + +/* Initialize a mbuf queue */ +int os_mqueue_init(struct os_mqueue *mq, os_event_fn *ev_cb, void *arg); + +/* Get an element from a mbuf queue */ +struct os_mbuf *os_mqueue_get(struct os_mqueue *); + +/* Put an element in a mbuf queue */ +int os_mqueue_put(struct os_mqueue *, struct os_eventq *, struct os_mbuf *); + +/* Register an mbuf pool with the system pool registry */ +int os_msys_register(struct os_mbuf_pool *); + +/* Return a mbuf from the system pool, given an indicative mbuf size */ +struct os_mbuf *os_msys_get(uint16_t dsize, uint16_t leadingspace); + +/* De-registers all mbuf pools from msys. */ +void os_msys_reset(void); + +/* Return a packet header mbuf from the system pool */ +struct os_mbuf *os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len); + +int os_msys_count(void); +int os_msys_num_free(void); + +/* Initialize a mbuf pool */ +int os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp, + uint16_t, uint16_t); + +/* Allocate a new mbuf out of the os_mbuf_pool */ +struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t); + +/* Allocate a new packet header mbuf out of the os_mbuf_pool */ +struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, + uint8_t pkthdr_len); + +/* Duplicate a mbuf from the pool */ +struct os_mbuf *os_mbuf_dup(struct os_mbuf *m); + +struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off, + uint16_t *out_off); + +/* Copy data from an mbuf to a flat buffer. */ +int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst); + +/* Append data onto a mbuf */ +int os_mbuf_append(struct os_mbuf *m, const void *, uint16_t); + +int os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src, + uint16_t src_off, uint16_t len); + +/* Free a mbuf */ +int os_mbuf_free(struct os_mbuf *mb); + +/* Free a mbuf chain */ +int os_mbuf_free_chain(struct os_mbuf *om); + +void os_mbuf_adj(struct os_mbuf *mp, int req_len); +int os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len); +int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1, + const struct os_mbuf *om2, uint16_t offset2, + uint16_t len); + +struct os_mbuf *os_mbuf_prepend(struct os_mbuf *om, int len); +struct os_mbuf *os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len); +int os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len); +void os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second); +void *os_mbuf_extend(struct os_mbuf *om, uint16_t len); +struct os_mbuf *os_mbuf_pullup(struct os_mbuf *om, uint16_t len); +struct os_mbuf *os_mbuf_trim_front(struct os_mbuf *om); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_MBUF_H */ diff --git a/porting/common/include/os/os_mempool.h b/porting/common/include/os/os_mempool.h new file mode 100644 index 000000000..0f5cca96d --- /dev/null +++ b/porting/common/include/os/os_mempool.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +#ifndef _OS_MEMPOOL_H_ +#define _OS_MEMPOOL_H_ + +#include +#include "os/os.h" +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * A memory block structure. This simply contains a pointer to the free list + * chain and is only used when the block is on the free list. When the block + * has been removed from the free list the entire memory block is usable by the + * caller. + */ +struct os_memblock { + SLIST_ENTRY(os_memblock) mb_next; +}; + +/* XXX: Change this structure so that we keep the first address in the pool? */ +/* XXX: add memory debug structure and associated code */ +/* XXX: Change how I coded the SLIST_HEAD here. It should be named: + SLIST_HEAD(,os_memblock) mp_head; */ + +/* Memory pool */ +struct os_mempool { + int mp_block_size; /* Size of the memory blocks, in bytes. */ + int mp_num_blocks; /* The number of memory blocks. */ + int mp_num_free; /* The number of free blocks left */ + int mp_min_free; /* The lowest number of free blocks seen */ + uint32_t mp_membuf_addr; /* Address of memory buffer used by pool */ + STAILQ_ENTRY(os_mempool) mp_list; + SLIST_HEAD(,os_memblock); /* Pointer to list of free blocks */ + char *name; /* Name for memory block */ +}; + +#define OS_MEMPOOL_INFO_NAME_LEN (32) + +struct os_mempool_info { + int omi_block_size; + int omi_num_blocks; + int omi_num_free; + int omi_min_free; + char omi_name[OS_MEMPOOL_INFO_NAME_LEN]; +}; + +struct os_mempool *os_mempool_info_get_next(struct os_mempool *, + struct os_mempool_info *); + +/* + * To calculate size of the memory buffer needed for the pool. NOTE: This size + * is NOT in bytes! The size is the number of os_membuf_t elements required for + * the memory pool. + */ +#if (OS_CFG_ALIGNMENT == OS_CFG_ALIGN_4) +#define OS_MEMPOOL_SIZE(n,blksize) ((((blksize) + 3) / 4) * (n)) +typedef uint32_t os_membuf_t; +#else +#define OS_MEMPOOL_SIZE(n,blksize) ((((blksize) + 7) / 8) * (n)) +typedef uint64_t os_membuf_t; +#endif + +/** Calculates the number of bytes required to initialize a memory pool. */ +#define OS_MEMPOOL_BYTES(n,blksize) \ + (sizeof (os_membuf_t) * OS_MEMPOOL_SIZE((n), (blksize))) + +/* Initialize a memory pool */ +os_error_t os_mempool_init(struct os_mempool *mp, int blocks, int block_size, + void *membuf, char *name); + +/* Performs an integrity check of the specified mempool. */ +bool os_mempool_is_sane(const struct os_mempool *mp); + +/* Checks if a memory block was allocated from the specified mempool. */ +int os_memblock_from(const struct os_mempool *mp, const void *block_addr); + +/* Get a memory block from the pool */ +void *os_memblock_get(struct os_mempool *mp); + +/* Put the memory block back into the pool */ +os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_MEMPOOL_H_ */ diff --git a/porting/common/include/os/os_mutex.h b/porting/common/include/os/os_mutex.h new file mode 100644 index 000000000..2964edb88 --- /dev/null +++ b/porting/common/include/os/os_mutex.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef _OS_MUTEX_H_ +#define _OS_MUTEX_H_ + +#include "os/os.h" +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_mutex +{ + SLIST_HEAD(, os_task) mu_head; /* chain of waiting tasks */ + uint8_t _pad; + uint8_t mu_prio; /* owner's default priority*/ + uint16_t mu_level; /* call nesting level */ + struct os_task *mu_owner; /* owners task */ +}; + +/* + XXX: NOTES + -> Should we add a magic number or flag to the mutex structure so + that we know that this is a mutex? We can use it for double checking + that a proper mutex was passed in to the API. + -> What debug information should we add to this structure? Who last + acquired the mutex? File/line where it was released? + -> Should we add a name to the mutex? + -> Should we add a "os_mutex_inspect() api? +*/ + +/* XXX: api to create +os_mutex_inspect(); +*/ + +/* Initialize a mutex */ +os_error_t os_mutex_init(struct os_mutex *mu); + +/* Release a mutex */ +os_error_t os_mutex_release(struct os_mutex *mu); + +/* Pend (wait) for a mutex */ +os_error_t os_mutex_pend(struct os_mutex *mu, uint32_t timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_MUTEX_H_ */ diff --git a/porting/common/include/os/os_sanity.h b/porting/common/include/os/os_sanity.h new file mode 100644 index 000000000..e74f2f9f9 --- /dev/null +++ b/porting/common/include/os/os_sanity.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef _OS_SANITY_H +#define _OS_SANITY_H + +#include + +#include "os/os_time.h" +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_sanity_check; +typedef int (*os_sanity_check_func_t)(struct os_sanity_check *, void *); + +struct os_sanity_check { + os_time_t sc_checkin_last; + os_time_t sc_checkin_itvl; + os_sanity_check_func_t sc_func; + void *sc_arg; + + SLIST_ENTRY(os_sanity_check) sc_next; + +}; + +#define OS_SANITY_CHECK_SETFUNC(__sc, __f, __arg, __itvl) \ + (__sc)->sc_func = (__f); \ + (__sc)->sc_arg = (__arg); \ + (__sc)->sc_checkin_itvl = (__itvl) * OS_TICKS_PER_SEC; + +int os_sanity_init(void); +void os_sanity_run(void); + +struct os_task; +int os_sanity_task_checkin(struct os_task *); + +int os_sanity_check_init(struct os_sanity_check *); +int os_sanity_check_register(struct os_sanity_check *); +int os_sanity_check_reset(struct os_sanity_check *); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_SANITY_H */ diff --git a/porting/common/include/os/os_sched.h b/porting/common/include/os/os_sched.h new file mode 100644 index 000000000..be6b7fda2 --- /dev/null +++ b/porting/common/include/os/os_sched.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef _OS_SCHED_H +#define _OS_SCHED_H + +#include "os/os_task.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_task; + +TAILQ_HEAD(os_task_list, os_task); + +extern struct os_task *g_current_task; +extern struct os_task_list g_os_run_list; +extern struct os_task_list g_os_sleep_list; + +void os_sched_ctx_sw_hook(struct os_task *); +struct os_task *os_sched_get_current_task(void); +void os_sched_set_current_task(struct os_task *); +struct os_task *os_sched_next_task(void); +void os_sched(struct os_task *); +void os_sched_os_timer_exp(void); +os_error_t os_sched_insert(struct os_task *); +int os_sched_sleep(struct os_task *, os_time_t nticks); +int os_sched_wakeup(struct os_task *); +int os_sched_remove(struct os_task *); +void os_sched_resort(struct os_task *); +os_time_t os_sched_wakeup_ticks(os_time_t now); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_SCHED_H */ diff --git a/porting/common/include/os/os_sem.h b/porting/common/include/os/os_sem.h new file mode 100644 index 000000000..d5451ab3d --- /dev/null +++ b/porting/common/include/os/os_sem.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef _OS_SEM_H_ +#define _OS_SEM_H_ + +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_sem +{ + SLIST_HEAD(, os_task) sem_head; /* chain of waiting tasks */ + uint16_t _pad; + uint16_t sem_tokens; /* # of tokens */ +}; + +/* + XXX: NOTES + -> Should we add a magic number or flag to the semaphore structure so + that we know that this is a semaphore? We can use it for double checking + that a proper semaphore was passed in to the API. + -> What debug information should we add to this structure? Who last + acquired the semaphore? File/line where it was released? + -> Should we add a name to the semaphore? + -> Should we add a "os_sem_inspect() api, like ucos? +*/ + +/* Create a semaphore */ +os_error_t os_sem_init(struct os_sem *sem, uint16_t tokens); + +/* Release a semaphore */ +os_error_t os_sem_release(struct os_sem *sem); + +/* Pend (wait) for a semaphore */ +os_error_t os_sem_pend(struct os_sem *sem, uint32_t timeout); + +/* Get current semaphore's count */ +static inline uint16_t os_sem_get_count(struct os_sem *sem) +{ + return sem->sem_tokens; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_SEM_H_ */ diff --git a/porting/common/include/os/os_task.h b/porting/common/include/os/os_task.h new file mode 100644 index 000000000..a9e420f5e --- /dev/null +++ b/porting/common/include/os/os_task.h @@ -0,0 +1,128 @@ +/* + * 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. + */ + +#ifndef _OS_TASK_H +#define _OS_TASK_H + +#include "os/os.h" +#include "os/os_sanity.h" +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* The highest and lowest task priorities */ +#define OS_TASK_PRI_HIGHEST (0) +#define OS_TASK_PRI_LOWEST (0xff) + +/* + * Generic "object" structure. All objects that a task can wait on must + * have a SLIST_HEAD(, os_task) head_name as the first element in the object + * structure. The element 'head_name' can be any name. See os_mutex.h or + * os_sem.h for an example. + */ +struct os_task_obj { + SLIST_HEAD(, os_task) obj_head; /* chain of waiting tasks */ +}; + +/* Task states */ +typedef enum os_task_state { + OS_TASK_READY = 1, + OS_TASK_SLEEP = 2, +} os_task_state_t; + +/* Task flags */ +#define OS_TASK_FLAG_NO_TIMEOUT (0x01U) +#define OS_TASK_FLAG_SEM_WAIT (0x02U) +#define OS_TASK_FLAG_MUTEX_WAIT (0x04U) +#define OS_TASK_FLAG_EVQ_WAIT (0x08U) + +typedef void (*os_task_func_t)(void *); + +#define OS_TASK_MAX_NAME_LEN (32) + +struct os_task { + os_stack_t *t_stackptr; + os_stack_t *t_stacktop; + + uint16_t t_stacksize; + uint8_t t_taskid; + uint8_t t_prio; + + uint8_t t_state; + uint8_t t_flags; + uint8_t t_lockcnt; + uint8_t t_pad; + + const char *t_name; + os_task_func_t t_func; + void *t_arg; + + void *t_obj; + + struct os_sanity_check t_sanity_check; + + os_time_t t_next_wakeup; + os_time_t t_run_time; + uint32_t t_ctx_sw_cnt; + + /* Global list of all tasks, irrespective of run or sleep lists */ + STAILQ_ENTRY(os_task) t_os_task_list; + + /* Used to chain task to either the run or sleep list */ + TAILQ_ENTRY(os_task) t_os_list; + + /* Used to chain task to an object such as a semaphore or mutex */ + SLIST_ENTRY(os_task) t_obj_list; +}; + +STAILQ_HEAD(os_task_stailq, os_task); + +extern struct os_task_stailq g_os_task_list; + +int os_task_init(struct os_task *, const char *, os_task_func_t, void *, + uint8_t, os_time_t, os_stack_t *, uint16_t); + +int os_task_remove(struct os_task *t); + +uint8_t os_task_count(void); + +struct os_task_info { + uint8_t oti_prio; + uint8_t oti_taskid; + uint8_t oti_state; + uint16_t oti_stkusage; + uint16_t oti_stksize; + uint32_t oti_cswcnt; + uint32_t oti_runtime; + os_time_t oti_last_checkin; + os_time_t oti_next_checkin; + + char oti_name[OS_TASK_MAX_NAME_LEN]; +}; + +struct os_task *os_task_info_get_next(const struct os_task *, + struct os_task_info *); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_TASK_H */ diff --git a/porting/common/include/os/os_test.h b/porting/common/include/os/os_test.h new file mode 100644 index 000000000..b71d60889 --- /dev/null +++ b/porting/common/include/os/os_test.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#ifndef H_OS_TEST_ +#define H_OS_TEST_ + +#ifdef __cplusplus +extern "C" { +#endif + +int os_test_all(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/include/os/os_time.h b/porting/common/include/os/os_time.h new file mode 100644 index 000000000..2fa07e93a --- /dev/null +++ b/porting/common/include/os/os_time.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)time.h 8.5 (Berkeley) 5/4/95 + * $FreeBSD$ + */ + +#ifndef _OS_TIME_H +#define _OS_TIME_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef UINT32_MAX +#define UINT32_MAX 0xFFFFFFFFU +#endif + +typedef uint32_t os_time_t; +typedef int32_t os_stime_t; +#define OS_TIME_MAX UINT32_MAX + +/* Used to wait forever for events and mutexs */ +#define OS_TIMEOUT_NEVER (UINT32_MAX) + +os_time_t os_time_get(void); +void os_time_advance(int ticks); +void os_time_delay(int32_t osticks); + +#define OS_TIME_TICK_LT(__t1, __t2) ((os_stime_t) ((__t1) - (__t2)) < 0) +#define OS_TIME_TICK_GT(__t1, __t2) ((os_stime_t) ((__t1) - (__t2)) > 0) +#define OS_TIME_TICK_GEQ(__t1, __t2) ((os_stime_t) ((__t1) - (__t2)) >= 0) + +struct os_timeval { + int64_t tv_sec; /* seconds since Jan 1 1970 */ + int32_t tv_usec; /* microseconds within the second */ +}; + +struct os_timezone { + int16_t tz_minuteswest; /* with respect to GMT */ + int16_t tz_dsttime; /* daylight savings time correction (if any) */ +}; + +#define os_timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) + +#define os_timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + +int os_settimeofday(struct os_timeval *utctime, struct os_timezone *tz); +int os_gettimeofday(struct os_timeval *utctime, struct os_timezone *tz); +int64_t os_get_uptime_usec(void); +int os_time_ms_to_ticks(uint32_t ms, uint32_t *out_ticks); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_TIME_H */ diff --git a/porting/common/include/os/os_trace_api.h b/porting/common/include/os/os_trace_api.h new file mode 100644 index 000000000..e01ff2022 --- /dev/null +++ b/porting/common/include/os/os_trace_api.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#ifndef OS_TRACE_API_H +#define OS_TRACE_API_H + +#include + +#include "syscfg/syscfg.h" +#include "os/os.h" + +#define OS_TRACE_ID_OFFSET (32u) + +#define OS_TRACE_ID_EVQ_PUT (1u + OS_TRACE_ID_OFFSET) +#define OS_TRACE_ID_EVQ_GET (2u + OS_TRACE_ID_OFFSET) +#define OS_TRACE_ID_MUTEX_INIT (3u + OS_TRACE_ID_OFFSET) +#define OS_TRACE_ID_MUTEX_RELEASE (4u + OS_TRACE_ID_OFFSET) +#define OS_TRACE_ID_MUTEX_PEND (5u + OS_TRACE_ID_OFFSET) + +#if MYNEWT_VAL(OS_SYSVIEW) +void os_trace_enter_isr(void); +void os_trace_exit_isr(void); +void os_trace_exit_isr_to_scheduler(void); +void os_trace_task_info(const struct os_task *p_task); +void os_trace_task_create(uint32_t task_id); +void os_trace_task_start_exec(uint32_t task_id); +void os_trace_task_stop_exec(void); +void os_trace_task_start_ready(uint32_t task_id); +void os_trace_task_stop_ready(uint32_t task_id, unsigned reason); +void os_trace_idle(void); + +void os_trace_void(unsigned id); +void os_trace_u32(unsigned id, uint32_t para0); +void os_trace_u32x2(unsigned id, uint32_t para0, uint32_t para1); +void os_trace_u32x3(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2); +void os_trace_u32x4(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3); +void os_trace_u32x5(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3, uint32_t para4); +void os_trace_enter_timer(uint32_t timer_id); +void os_trace_exit_timer(void); + +void os_trace_end_call(unsigned id); +void os_trace_end_call_return_value(unsigned id, uint32_t return_value); + +#else + +static inline void os_trace_enter_isr(void){} +static inline void os_trace_exit_isr(void){} +static inline void os_trace_exit_isr_to_scheduler(void){} +static inline void os_trace_task_info(const struct os_task *p_task){} +static inline void os_trace_task_create(uint32_t task_id){} +static inline void os_trace_task_start_exec(uint32_t task_id){} +static inline void os_trace_task_stop_exec(void){} +static inline void os_trace_task_start_ready(uint32_t task_id){} +static inline void os_trace_task_stop_ready(uint32_t task_id, unsigned reason){} +static inline void os_trace_idle(void){} +static inline void os_trace_void(unsigned id){} +static inline void os_trace_u32(unsigned id, uint32_t para0){} +static inline void os_trace_u32x2(unsigned id, uint32_t para0, uint32_t para1){} +static inline void os_trace_u32x3(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2){} +static inline void os_trace_u32x4(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3){} +static inline void os_trace_u32x5(unsigned id, uint32_t para0, uint32_t para1, uint32_t para2, uint32_t para3, uint32_t para4){} +static inline void os_trace_enter_timer(uint32_t timer_id){} +static inline void os_trace_exit_timer(void){} +static inline void os_trace_end_call(unsigned id){} +static inline void os_trace_end_call_return_value(unsigned id, uint32_t return_value){} +#endif + +#endif diff --git a/porting/common/include/os/queue.h b/porting/common/include/os/queue.h new file mode 100755 index 000000000..faffd8518 --- /dev/null +++ b/porting/common/include/os/queue.h @@ -0,0 +1,522 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.7 2002/04/17 14:21:02 des Exp $ + */ + +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file defines five types of data structures: singly-linked lists, + * singly-linked tail queues, lists, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ CIRCLEQ + * _HEAD + + + + + + * _HEAD_INITIALIZER + + + + + + * _ENTRY + + + + + + * _INIT + + + + + + * _EMPTY + + + + + + * _FIRST + + + + + + * _NEXT + + + + + + * _PREV - - - + + + * _LAST - - + + + + * _FOREACH + + + + + + * _FOREACH_REVERSE - - - + + + * _INSERT_HEAD + + + + + + * _INSERT_BEFORE - + - + + + * _INSERT_AFTER + + + + + + * _INSERT_TAIL - - + + + + * _REMOVE_HEAD + - + - - + * _REMOVE + + + + + + * + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY(head) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD(head, field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) + +/* + * Circular queue declarations. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&(head), (void *)&(head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) + +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = CIRCLEQ_FIRST((head)); \ + (var) != (void *)(head) || ((var) = NULL); \ + (var) = CIRCLEQ_NEXT((var), field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = CIRCLEQ_LAST((head)); \ + (var) != (void *)(head) || ((var) = NULL); \ + (var) = CIRCLEQ_PREV((var), field)) + +#define CIRCLEQ_INIT(head) do { \ + CIRCLEQ_FIRST((head)) = (void *)(head); \ + CIRCLEQ_LAST((head)) = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \ + CIRCLEQ_PREV((elm), field) = (listelm); \ + if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = (elm); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\ + CIRCLEQ_NEXT((listelm), field) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = (listelm); \ + CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \ + if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = (elm); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\ + CIRCLEQ_PREV((listelm), field) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \ + CIRCLEQ_PREV((elm), field) = (void *)(head); \ + if (CIRCLEQ_LAST((head)) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = (elm); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \ + CIRCLEQ_FIRST((head)) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = (void *)(head); \ + CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \ + if (CIRCLEQ_FIRST((head)) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = (elm); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \ + CIRCLEQ_LAST((head)) = (elm); \ +} while (0) + +#define CIRCLEQ_LAST(head) ((head)->cqh_last) + +#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) + +#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \ + CIRCLEQ_PREV((elm), field); \ + if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \ + CIRCLEQ_NEXT((elm), field); \ +} while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* !_QUEUE_H_ */ diff --git a/porting/common/include/stats/stats.h b/porting/common/include/stats/stats.h new file mode 100644 index 000000000..ac2a182f1 --- /dev/null +++ b/porting/common/include/stats/stats.h @@ -0,0 +1,83 @@ +/* + * 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. + */ +#ifndef __UTIL_STATS_H__ +#define __UTIL_STATS_H__ + +#include +#include "syscfg/syscfg.h" +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct stats_name_map { + uint16_t snm_off; + char *snm_name; +} __attribute__((packed)); + +struct stats_hdr { + char *s_name; + uint8_t s_size; + uint8_t s_cnt; + uint16_t s_pad1; +#if MYNEWT_VAL(STATS_NAMES) + const struct stats_name_map *s_map; + int s_map_cnt; +#endif + STAILQ_ENTRY(stats_hdr) s_next; +}; + +#define STATS_SECT_DECL(__name) \ + struct stats_ ## __name +#define STATS_SECT_END }; + +#define STATS_SECT_START(__name) \ + STATS_SECT_DECL(__name) { +#define STATS_SECT_VAR(__var) + +#define STATS_HDR(__sectname) + +#define STATS_SECT_ENTRY(__var) +#define STATS_SECT_ENTRY16(__var) +#define STATS_SECT_ENTRY32(__var) +#define STATS_SECT_ENTRY64(__var) +#define STATS_RESET(__var) + +#define STATS_SIZE_INIT_PARMS(__sectvarname, __size) 0, 0 + +#define STATS_INC(__sectvarname, __var) +#define STATS_INCN(__sectvarname, __var, __n) +#define STATS_CLEAR(__sectvarname, __var) + +#define STATS_NAME_START(__name) +#define STATS_NAME(__name, __entry) +#define STATS_NAME_END(__name) +#define STATS_NAME_INIT_PARMS(__name) NULL, 0 + +#define stats_init(...) 0 +#define stats_register(name, shdr) 0 +#define stats_init_and_reg(...) 0 +#define stats_reset(shdr) + +#ifdef __cplusplus +} +#endif + +#endif /* __UTIL_STATS_H__ */ diff --git a/porting/common/include/sysinit/sysinit.h b/porting/common/include/sysinit/sysinit.h new file mode 100644 index 000000000..7694c428a --- /dev/null +++ b/porting/common/include/sysinit/sysinit.h @@ -0,0 +1,128 @@ +/* + * 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. + */ + +#ifndef H_SYSINIT_ +#define H_SYSINIT_ + +#include +#include +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(SPLIT_APPLICATION) +#include "split/split.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t sysinit_active; + +void sysinit_start(void); +void sysinit_end(void); + +typedef void sysinit_panic_fn(const char *file, int line, const char *func, + const char *expr, const char *msg); + +extern sysinit_panic_fn *sysinit_panic_cb; + +void sysinit_panic_set(sysinit_panic_fn *panic_fn); + +#if MYNEWT_VAL(SYSINIT_PANIC_MESSAGE) + +#if MYNEWT_VAL(SYSINIT_PANIC_FILE_LINE) +#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(__FILE__, __LINE__, 0, 0, msg) +#else +#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(0, 0, 0, 0, msg) +#endif + +#else + +#if MYNEWT_VAL(SYSINIT_PANIC_FILE_LINE) +#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(__FILE__, __LINE__, 0, 0, 0) +#else +#define SYSINIT_PANIC_MSG(msg) sysinit_panic_cb(0, 0, 0, 0, 0) +#endif + +#endif + +#define SYSINIT_PANIC() SYSINIT_PANIC_MSG(NULL) + +#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) do \ +{ \ + if (!(rc)) { \ + SYSINIT_PANIC_MSG(msg); \ + } \ +} while (0) + +#define SYSINIT_PANIC_ASSERT(rc) SYSINIT_PANIC_ASSERT_MSG(rc, NULL) + +/** + * Asserts that system initialization is in progress. This macro is used to + * ensure packages don't get initialized a second time after system + * initialization has completed. + */ +#if MYNEWT_VAL(SYSINIT_CONSTRAIN_INIT) +#define SYSINIT_ASSERT_ACTIVE() assert(sysinit_active) +#else +#define SYSINIT_ASSERT_ACTIVE() +#endif + +#if MYNEWT_VAL(SPLIT_LOADER) + +/*** System initialization for loader (first stage of split image). */ +void sysinit_loader(void); +#define sysinit() do \ +{ \ + sysinit_start(); \ + sysinit_loader(); \ + sysinit_end(); \ +} while (0) + +#elif MYNEWT_VAL(SPLIT_APPLICATION) + +/*** System initialization for split-app (second stage of split image). */ +void sysinit_app(void); +#define sysinit() do \ +{ \ + /* Record that a split app is running; imgmgt needs to know this. */ \ + split_app_active_set(1); \ + sysinit_start(); \ + sysinit_app(); \ + sysinit_end(); \ +} while (0) + +#else + +/*** System initialization for a unified image (no split). */ +void sysinit_app(void); +#define sysinit() do \ +{ \ + sysinit_start(); \ + sysinit_app(); \ + sysinit_end(); \ +} while (0) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/src/mem/mem.c b/porting/common/src/mem/mem.c new file mode 100644 index 000000000..340e60e7c --- /dev/null +++ b/porting/common/src/mem/mem.c @@ -0,0 +1,245 @@ +/* + * 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 "os/os.h" +#include "mem/mem.h" + +/** + * Mallocs a block of memory and initializes a mempool to use it. + * + * @param mempool The mempool to initialize. + * @param num_blocks The total number of memory blocks in the + * mempool. + * @param block_size The size of each mempool entry. + * @param name The name to give the mempool. + * @param out_buf On success, this points to the malloced memory. + * Pass NULL if you don't need this + * information. + * + * @return 0 on success; + * OS_ENOMEM on malloc failure; + * Other OS code on unexpected error. + */ +int +mem_malloc_mempool(struct os_mempool *mempool, int num_blocks, int block_size, + char *name, void **out_buf) +{ + void *buf; + int rc; + + block_size = OS_ALIGN(block_size, OS_ALIGNMENT); + + if (num_blocks > 0) { + buf = malloc(OS_MEMPOOL_BYTES(num_blocks, block_size)); + if (buf == NULL) { + return OS_ENOMEM; + } + } else { + buf = NULL; + } + + rc = os_mempool_init(mempool, num_blocks, block_size, buf, name); + if (rc != 0) { + free(buf); + return rc; + } + + if (out_buf != NULL) { + *out_buf = buf; + } + + return 0; +} + +/** + * Mallocs a block of memory and initializes an mbuf pool to use it. The + * specified block_size indicates the size of an mbuf acquired from the pool if + * it does not contain a pkthdr. + * + * @param mempool The mempool to initialize. + * @param mbuf_pool The mbuf pool to initialize. + * @param num_blocks The total number of mbufs in the pool. + * @param block_size The size of each mbuf. + * @param name The name to give the mempool. + * @param out_buf On success, this points to the malloced memory. + * Pass NULL if you don't need this + * information. + * + * @return 0 on success; + * OS_ENOMEM on malloc failure; + * Other OS code on unexpected error. + */ +int +mem_malloc_mbuf_pool(struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, int num_blocks, + int block_size, char *name, + void **out_buf) +{ + void *buf; + int rc; + + block_size = OS_ALIGN(block_size + sizeof (struct os_mbuf), OS_ALIGNMENT); + + rc = mem_malloc_mempool(mempool, num_blocks, block_size, name, &buf); + if (rc != 0) { + return rc; + } + + rc = os_mbuf_pool_init(mbuf_pool, mempool, block_size, num_blocks); + if (rc != 0) { + free(buf); + return rc; + } + + if (out_buf != NULL) { + *out_buf = buf; + } + + return 0; +} + +/** + * Mallocs a block of memory and initializes an mbuf pool to use it. The + * specified block_size indicates the size of an mbuf acquired from the pool if + * it contains a pkthdr. + * + * @param mempool The mempool to initialize. + * @param mbuf_pool The mbuf pool to initialize. + * @param num_blocks The total number of mbufs in the pool. + * @param block_size The size of each mbuf. + * @param name The name to give the mempool. + * @param out_buf On success, this points to the malloced memory. + * Pass NULL if you don't need this + * information. + * + * @return 0 on success; + * OS_ENOMEM on malloc failure; + * Other OS code on unexpected error. + */ +int +mem_malloc_mbufpkt_pool(struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, int num_blocks, + int block_size, char *name, + void **out_buf) +{ + int rc; + + rc = mem_malloc_mbuf_pool(mempool, mbuf_pool, num_blocks, + block_size + sizeof (struct os_mbuf_pkthdr), + name, out_buf); + return rc; +} + +int +mem_init_mbuf_pool(void *mem, struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, int num_blocks, + int block_size, char *name) +{ + int rc; + + rc = os_mempool_init(mempool, num_blocks, block_size, mem, name); + if (rc != 0) { + return rc; + } + + rc = os_mbuf_pool_init(mbuf_pool, mempool, block_size, num_blocks); + if (rc != 0) { + return rc; + } + + return 0; +} + +/* + * Splits an appropriately-sized fragment from the front of an mbuf chain, as + * neeeded. If the length of the mbuf chain greater than specified maximum + * fragment size, a new mbuf is allocated, and data is moved from the source + * mbuf to the new mbuf. If the mbuf chain is small enough to fit in a single + * fragment, the source mbuf itself is returned unmodified, and the suplied + * pointer is set to NULL. + * + * This function is expected to be called in a loop until the entire mbuf chain + * has been consumed. For example: + * + * struct os_mbuf *frag; + * struct os_mbuf *rsp; + * // [...] + * while (rsp != NULL) { + * frag = mem_split_frag(&rsp, get_mtu(), frag_alloc, NULL); + * if (frag == NULL) { + * os_mbuf_free_chain(rsp); + * return SYS_ENOMEM; + * } + * send_packet(frag) + * } + * + * @param om The packet to fragment. Upon fragmentation, + * this mbuf is adjusted such that the + * fragment data is removed. If the packet + * constitutes a single fragment, this gets + * set to NULL on success. + * @param max_frag_sz The maximum payload size of a fragment. + * Typically this is the MTU of the + * connection. + * @param alloc_cb Points to a function that allocates an mbuf to + * hold a fragment. This function gets called + * before the source mbuf chain is modified, + * so it can safely inspect it. + * @param cb_arg Generic parameter that gets passed to the + * callback function. + * + * @return The next fragment to send on success; + * NULL on failure. + */ +struct os_mbuf * +mem_split_frag(struct os_mbuf **om, uint16_t max_frag_sz, + mem_frag_alloc_fn *alloc_cb, void *cb_arg) +{ + struct os_mbuf *frag; + int rc; + + if (OS_MBUF_PKTLEN(*om) <= max_frag_sz) { + /* Final fragment. */ + frag = *om; + *om = NULL; + return frag; + } + + /* Packet needs to be split. Allocate a new buffer for the fragment. */ + frag = alloc_cb(max_frag_sz, cb_arg); + if (frag == NULL) { + goto err; + } + + /* Move data from the front of the packet into the fragment mbuf. */ + rc = os_mbuf_appendfrom(frag, *om, 0, max_frag_sz); + if (rc != 0) { + goto err; + } + os_mbuf_adj(*om, max_frag_sz); + + /* Free unused portion of of source mbuf chain, if possible. */ + *om = os_mbuf_trim_front(*om); + + return frag; + +err: + os_mbuf_free_chain(frag); + return NULL; +} diff --git a/porting/common/src/nimble_port.c b/porting/common/src/nimble_port.c new file mode 100644 index 000000000..8f8daa9cd --- /dev/null +++ b/porting/common/src/nimble_port.c @@ -0,0 +1,65 @@ +/* + * 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 +#include "os/os.h" +#include "sysinit/sysinit.h" +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" +#include "services/ans/ble_svc_ans.h" +#include "services/ias/ble_svc_ias.h" +#include "services/lls/ble_svc_lls.h" +#include "services/tps/ble_svc_tps.h" +#include "controller/ble_ll.h" + +void +nimble_init(void) +{ + void os_msys_init(void); + void ble_hci_ram_pkg_init(void); + void ble_store_ram_init(void); + + sysinit_start(); + os_msys_init(); + ble_hci_ram_pkg_init(); + ble_hs_init(); + ble_ll_init(); + ble_svc_gap_init(); + ble_svc_gatt_init(); + ble_svc_ans_init(); + ble_svc_ias_init(); + ble_svc_lls_init(); + ble_svc_tps_init(); + ble_store_ram_init(); + sysinit_end(); +} + +void +nimble_run(void) +{ + while (1) { + struct os_event *ev; + + ev = os_eventq_get(os_eventq_dflt_get()); + assert(ev->ev_cb != NULL); + + ev->ev_cb(ev); + } +} diff --git a/porting/common/src/os/endian.c b/porting/common/src/os/endian.c new file mode 100644 index 000000000..1311f43ef --- /dev/null +++ b/porting/common/src/os/endian.c @@ -0,0 +1,218 @@ +/* + * 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 "os/endian.h" + +void +put_le16(void *buf, uint16_t x) +{ + uint8_t *u8ptr; + + u8ptr = buf; + u8ptr[0] = (uint8_t)x; + u8ptr[1] = (uint8_t)(x >> 8); +} + +void +put_le32(void *buf, uint32_t x) +{ + uint8_t *u8ptr; + + u8ptr = buf; + u8ptr[0] = (uint8_t)x; + u8ptr[1] = (uint8_t)(x >> 8); + u8ptr[2] = (uint8_t)(x >> 16); + u8ptr[3] = (uint8_t)(x >> 24); +} + +void +put_le64(void *buf, uint64_t x) +{ + uint8_t *u8ptr; + + u8ptr = buf; + u8ptr[0] = (uint8_t)x; + u8ptr[1] = (uint8_t)(x >> 8); + u8ptr[2] = (uint8_t)(x >> 16); + u8ptr[3] = (uint8_t)(x >> 24); + u8ptr[4] = (uint8_t)(x >> 32); + u8ptr[5] = (uint8_t)(x >> 40); + u8ptr[6] = (uint8_t)(x >> 48); + u8ptr[7] = (uint8_t)(x >> 56); +} + +uint16_t +get_le16(const void *buf) +{ + const uint8_t *u8ptr; + uint16_t x; + + u8ptr = buf; + x = u8ptr[0]; + x |= (uint16_t)u8ptr[1] << 8; + + return x; +} + +uint32_t +get_le32(const void *buf) +{ + const uint8_t *u8ptr; + uint32_t x; + + u8ptr = buf; + x = u8ptr[0]; + x |= (uint32_t)u8ptr[1] << 8; + x |= (uint32_t)u8ptr[2] << 16; + x |= (uint32_t)u8ptr[3] << 24; + + return x; +} + +uint64_t +get_le64(const void *buf) +{ + const uint8_t *u8ptr; + uint64_t x; + + u8ptr = buf; + x = u8ptr[0]; + x |= (uint64_t)u8ptr[1] << 8; + x |= (uint64_t)u8ptr[2] << 16; + x |= (uint64_t)u8ptr[3] << 24; + x |= (uint64_t)u8ptr[4] << 32; + x |= (uint64_t)u8ptr[5] << 40; + x |= (uint64_t)u8ptr[6] << 48; + x |= (uint64_t)u8ptr[7] << 56; + + return x; +} + +void +put_be16(void *buf, uint16_t x) +{ + uint8_t *u8ptr; + + u8ptr = buf; + u8ptr[0] = (uint8_t)(x >> 8); + u8ptr[1] = (uint8_t)x; +} + +void +put_be32(void *buf, uint32_t x) +{ + uint8_t *u8ptr; + + u8ptr = buf; + u8ptr[0] = (uint8_t)(x >> 24); + u8ptr[1] = (uint8_t)(x >> 16); + u8ptr[2] = (uint8_t)(x >> 8); + u8ptr[3] = (uint8_t)x; +} + +void +put_be64(void *buf, uint64_t x) +{ + uint8_t *u8ptr; + + u8ptr = buf; + u8ptr[0] = (uint8_t)(x >> 56); + u8ptr[1] = (uint8_t)(x >> 48); + u8ptr[2] = (uint8_t)(x >> 40); + u8ptr[3] = (uint8_t)(x >> 32); + u8ptr[4] = (uint8_t)(x >> 24); + u8ptr[5] = (uint8_t)(x >> 16); + u8ptr[6] = (uint8_t)(x >> 8); + u8ptr[7] = (uint8_t)x; +} + +uint16_t +get_be16(const void *buf) +{ + const uint8_t *u8ptr; + uint16_t x; + + u8ptr = buf; + x = (uint16_t)u8ptr[0] << 8; + x |= u8ptr[1]; + + return x; +} + +uint32_t +get_be32(const void *buf) +{ + const uint8_t *u8ptr; + uint32_t x; + + u8ptr = buf; + x = (uint32_t)u8ptr[0] << 24; + x |= (uint32_t)u8ptr[1] << 16; + x |= (uint32_t)u8ptr[2] << 8; + x |= u8ptr[3]; + + return x; +} + +uint64_t +get_be64(const void *buf) +{ + const uint8_t *u8ptr; + uint64_t x; + + u8ptr = buf; + x = (uint64_t)u8ptr[0] << 56; + x |= (uint64_t)u8ptr[1] << 48; + x |= (uint64_t)u8ptr[2] << 40; + x |= (uint64_t)u8ptr[3] << 32; + x |= (uint64_t)u8ptr[4] << 24; + x |= (uint64_t)u8ptr[5] << 16; + x |= (uint64_t)u8ptr[6] << 8; + x |= u8ptr[7]; + + return x; +} +void +swap_in_place(void *buf, int len) +{ + uint8_t *u8ptr; + uint8_t tmp; + int i; + int j; + + u8ptr = buf; + + for (i = 0, j = len - 1; i < j; i++, j--) { + tmp = u8ptr[i]; + + u8ptr[i] = u8ptr[j]; + u8ptr[j] = tmp; + } +} + +/* swap octets */ +void +swap_buf(uint8_t *dst, const uint8_t *src, int len) +{ + int i; + + for (i = 0; i < len; i++) { + dst[len - 1 - i] = src[i]; + } +} diff --git a/porting/common/src/os/os.c b/porting/common/src/os/os.c new file mode 100644 index 000000000..b8ec3ff95 --- /dev/null +++ b/porting/common/src/os/os.c @@ -0,0 +1,240 @@ +/* + * 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 "sysinit/sysinit.h" +#include "os/os.h" +#include "os/queue.h" +#include "os/os_dev.h" +#include "os/os_trace_api.h" +#include "hal/hal_os_tick.h" +#include "hal/hal_bsp.h" +#include "hal/hal_watchdog.h" + +#include +#include "../os/os_priv.h" + +/** + * @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_stack_t g_idle_task_stack[OS_STACK_ALIGN(OS_IDLE_STACK_SIZE)]; + +uint32_t g_os_idle_ctr; + +static struct os_task os_main_task; +static os_stack_t os_main_stack[OS_STACK_ALIGN(OS_MAIN_STACK_SIZE)]; + +/* Default zero. Set by the architecture specific code when os is started. + */ +int g_os_started; + +#ifdef ARCH_sim +#define MIN_IDLE_TICKS 1 +#else +#define MIN_IDLE_TICKS (100 * OS_TICKS_PER_SEC / 1000) /* 100 msec */ +#endif +#define MAX_IDLE_TICKS (600 * OS_TICKS_PER_SEC) /* 10 minutes */ + + +/** + * 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(); + + 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(); + 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); +} + +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); + + assert(MYNEWT_VAL(WATCHDOG_INTERVAL) - 200 > MYNEWT_VAL(SANITY_INTERVAL)); + + rc = hal_watchdog_init(MYNEWT_VAL(WATCHDOG_INTERVAL)); + assert(rc == 0); +} + +/** + * Initialize the operating system, calls into the architecture specific + * support to initialize the operating system. + */ +void +os_init(int (*main_fn)(int argc, char **arg)) +{ + os_error_t err; + + 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); +} + +/** + * Start the operating system, calls into the architecture specific support + * to start the operating system. + */ +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 + */ diff --git a/porting/common/src/os/os_callout.c b/porting/common/src/os/os_callout.c new file mode 100644 index 000000000..e8deeaba2 --- /dev/null +++ b/porting/common/src/os/os_callout.c @@ -0,0 +1,230 @@ +/* + * 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 +#include + +#include "../os/os_priv.h" +#include "os/os.h" + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSCallouts Event Timers (Callouts) + * @{ + */ +struct os_callout_list g_callout_list; + +/** + * Initialize a callout. + * + * Callouts are used to schedule events in the future onto a task's event + * queue. Callout timers are scheduled using the os_callout_reset() + * function. When the timer expires, an event is posted to the event + * queue specified in os_callout_init(). The event argument given here + * is posted in the ev_arg field of that event. + * + * @param c The callout to initialize + * @param evq The event queue to post an OS_EVENT_T_TIMER event to + * @param timo_func The function to call on this callout for the host task + * used to provide multiple timer events to a task + * (this can be NULL.) + * @param ev_arg The argument to provide to the event when posting the + * timer. + */ +void os_callout_init(struct os_callout *c, struct os_eventq *evq, + os_event_fn *ev_cb, void *ev_arg) +{ + memset(c, 0, sizeof(*c)); + c->c_ev.ev_cb = ev_cb; + c->c_ev.ev_arg = ev_arg; + c->c_evq = evq; +} + +/** + * Stop the callout from firing off, any pending events will be cleared. + * + * @param c The callout to stop + */ +void +os_callout_stop(struct os_callout *c) +{ + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + + if (os_callout_queued(c)) { + TAILQ_REMOVE(&g_callout_list, c, c_next); + c->c_next.tqe_prev = NULL; + } + + if (c->c_evq) { + os_eventq_remove(c->c_evq, &c->c_ev); + } + + OS_EXIT_CRITICAL(sr); +} + +/** + * Reset the callout to fire off in 'ticks' ticks. + * + * @param c The callout to reset + * @param ticks The number of ticks to wait before posting an event + * + * @return 0 on success, non-zero on failure + */ +int +os_callout_reset(struct os_callout *c, int32_t ticks) +{ + struct os_callout *entry; + os_sr_t sr; + int rc; + + if (ticks < 0) { + rc = OS_EINVAL; + goto err; + } + + OS_ENTER_CRITICAL(sr); + + os_callout_stop(c); + + if (ticks == 0) { + ticks = 1; + } + + c->c_ticks = os_time_get() + ticks; + + entry = NULL; + TAILQ_FOREACH(entry, &g_callout_list, c_next) { + if (OS_TIME_TICK_LT(c->c_ticks, entry->c_ticks)) { + break; + } + } + + if (entry) { + TAILQ_INSERT_BEFORE(entry, c, c_next); + } else { + TAILQ_INSERT_TAIL(&g_callout_list, c, c_next); + } + + OS_EXIT_CRITICAL(sr); + + return (0); +err: + return (rc); +} + +/** + * This function is called by the OS in the time tick. It searches the list + * of callouts, and sees if any of them are ready to run. If they are ready + * to run, it posts an event for each callout that's ready to run, + * to the event queue provided to os_callout_init(). + */ +void +os_callout_tick(void) +{ + os_sr_t sr; + struct os_callout *c; + uint32_t now; + + now = os_time_get(); + + while (1) { + OS_ENTER_CRITICAL(sr); + c = TAILQ_FIRST(&g_callout_list); + if (c) { + if (OS_TIME_TICK_GEQ(now, c->c_ticks)) { + TAILQ_REMOVE(&g_callout_list, c, c_next); + c->c_next.tqe_prev = NULL; + } else { + c = NULL; + } + } + OS_EXIT_CRITICAL(sr); + + if (c) { + if (c->c_evq) { + os_eventq_put(c->c_evq, &c->c_ev); + } else { + c->c_ev.ev_cb(&c->c_ev); + } + } else { + break; + } + } +} + +/* + * Returns the number of ticks to the first pending callout. If there are no + * pending callouts then return OS_TIMEOUT_NEVER instead. + * + * @param now The time now + * + * @return Number of ticks to first pending callout + */ +os_time_t +os_callout_wakeup_ticks(os_time_t now) +{ + os_time_t rt; + struct os_callout *c; + + OS_ASSERT_CRITICAL(); + + c = TAILQ_FIRST(&g_callout_list); + if (c != NULL) { + if (OS_TIME_TICK_GEQ(c->c_ticks, now)) { + rt = c->c_ticks - now; + } else { + rt = 0; /* callout time is in the past */ + } + } else { + rt = OS_TIMEOUT_NEVER; + } + + return (rt); +} + +/* + * Returns the number of ticks which remains to callout.. + * + * @param c callout + * @param now The time now + * + * @return Number of ticks to first pending callout + */ +os_time_t os_callout_remaining_ticks(struct os_callout *c, os_time_t now) +{ + os_time_t rt; + + OS_ASSERT_CRITICAL(); + + if (OS_TIME_TICK_GEQ(c->c_ticks, now)) { + rt = c->c_ticks - now; + } else { + rt = 0; /* callout time is in the past */ + } + + return rt; +} + +/** + * @} Callout Timers + * @} OS Kernel + */ diff --git a/porting/common/src/os/os_cputime.c b/porting/common/src/os/os_cputime.c new file mode 100644 index 000000000..19b0b8241 --- /dev/null +++ b/porting/common/src/os/os_cputime.c @@ -0,0 +1,215 @@ +/* + * 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 +#include +#include +#include "os/os.h" +#include "os/os_cputime.h" + +/** + * @addtogroup OSKernel Operating System Kernel + * @{ + * @defgroup OSCPUTime High Resolution Timers + * @{ + */ + +#if defined(OS_CPUTIME_FREQ_HIGH) +struct os_cputime_data g_os_cputime; +#endif + +/** + * os cputime init + * + * Initialize the cputime module. This must be called after os_init is called + * and before any other timer API are used. This should be called only once + * and should be called before the hardware timer is used. + * + * @param clock_freq The desired cputime frequency, in hertz (Hz). + * + * @return int 0 on success; -1 on error. + */ +int +os_cputime_init(uint32_t clock_freq) +{ + int rc; + + /* Set the ticks per microsecond. */ +#if defined(OS_CPUTIME_FREQ_HIGH) + g_os_cputime.ticks_per_usec = clock_freq / 1000000U; +#endif + rc = hal_timer_config(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM), clock_freq); + return rc; +} + +/** + * os cputime delay ticks + * + * Wait until the number of ticks has elapsed. This is a blocking delay. + * + * @param ticks The number of ticks to wait. + */ +void +os_cputime_delay_ticks(uint32_t ticks) +{ + uint32_t until; + + until = os_cputime_get32() + ticks; + while ((int32_t)(os_cputime_get32() - until) < 0) { + /* Loop here till finished */ + } +} + +#if !defined(OS_CPUTIME_FREQ_PWR2) +/** + * os cputime delay nsecs + * + * Wait until 'nsecs' nanoseconds has elapsed. This is a blocking delay. + * + * @param nsecs The number of nanoseconds to wait. + */ +void +os_cputime_delay_nsecs(uint32_t nsecs) +{ + uint32_t ticks; + + ticks = os_cputime_nsecs_to_ticks(nsecs); + os_cputime_delay_ticks(ticks); +} +#endif + +/** + * os cputime delay usecs + * + * Wait until 'usecs' microseconds has elapsed. This is a blocking delay. + * + * @param usecs The number of usecs to wait. + */ +void +os_cputime_delay_usecs(uint32_t usecs) +{ + uint32_t ticks; + + ticks = os_cputime_usecs_to_ticks(usecs); + os_cputime_delay_ticks(ticks); +} + +/** + * os cputime timer init + * + * @param timer The timer to initialize. Cannot be NULL. + * @param fp The timer callback function. Cannot be NULL. + * @param arg Pointer to data object to pass to timer. + */ +void +os_cputime_timer_init(struct hal_timer *timer, hal_timer_cb fp, void *arg) +{ + assert(timer != NULL); + assert(fp != NULL); + + hal_timer_set_cb(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM), timer, fp, arg); +} + +/** + * os cputime timer start + * + * Start a cputimer that will expire at 'cputime'. If cputime has already + * passed, the timer callback will still be called (at interrupt context). + * + * NOTE: This must be called when the timer is stopped. + * + * @param timer Pointer to timer to start. Cannot be NULL. + * @param cputime The cputime at which the timer should expire. + * + * @return int 0 on success; EINVAL if timer already started or timer struct + * invalid + * + */ +int +os_cputime_timer_start(struct hal_timer *timer, uint32_t cputime) +{ + int rc; + + rc = hal_timer_start_at(timer, cputime); + return rc; +} + +/** + * os cputimer timer relative + * + * Sets a cpu timer that will expire 'usecs' microseconds from the current + * cputime. + * + * NOTE: This must be called when the timer is stopped. + * + * @param timer Pointer to timer. Cannot be NULL. + * @param usecs The number of usecs from now at which the timer will expire. + * + * @return int 0 on success; EINVAL if timer already started or timer struct + * invalid + */ +int +os_cputime_timer_relative(struct hal_timer *timer, uint32_t usecs) +{ + int rc; + uint32_t cputime; + + assert(timer != NULL); + + cputime = os_cputime_get32() + os_cputime_usecs_to_ticks(usecs); + rc = hal_timer_start_at(timer, cputime); + + return rc; +} + +/** + * os cputime timer stop + * + * Stops a cputimer from running. The timer is removed from the timer queue + * and interrupts are disabled if no timers are left on the queue. Can be + * called even if timer is not running. + * + * @param timer Pointer to cputimer to stop. Cannot be NULL. + */ +void +os_cputime_timer_stop(struct hal_timer *timer) +{ + hal_timer_stop(timer); +} + +/** + * os cputime get32 + * + * Returns current value of cputime. + * + * @return uint32_t cputime + */ +uint32_t +os_cputime_get32(void) +{ + uint32_t cpu_time; + + cpu_time = hal_timer_read(MYNEWT_VAL(OS_CPUTIME_TIMER_NUM)); + return cpu_time; +} + +/** + * @} OSCPUTime + * @} OSKernel + */ diff --git a/porting/common/src/os/os_cputime_1mhz.c b/porting/common/src/os/os_cputime_1mhz.c new file mode 100644 index 000000000..4e769687d --- /dev/null +++ b/porting/common/src/os/os_cputime_1mhz.c @@ -0,0 +1,52 @@ +#include "os/os_cputime.h" + +/** + * This module implements cputime functionality for timers whose frequency is + * exactly 1 MHz. + */ + +#if defined(OS_CPUTIME_FREQ_1MHZ) + +/** + * @addtogroup OSKernel Operating System Kernel + * @{ + * @defgroup OSCPUTime High Resolution Timers + * @{ + */ + +/** + * os cputime nsecs to ticks + * + * Converts the given number of nanoseconds into cputime ticks. + * + * @param usecs The number of nanoseconds to convert to ticks + * + * @return uint32_t The number of ticks corresponding to 'nsecs' + */ +uint32_t +os_cputime_nsecs_to_ticks(uint32_t nsecs) +{ + return (nsecs + 999) / 1000; +} + +/** + * os cputime ticks to nsecs + * + * Convert the given number of ticks into nanoseconds. + * + * @param ticks The number of ticks to convert to nanoseconds. + * + * @return uint32_t The number of nanoseconds corresponding to 'ticks' + */ +uint32_t +os_cputime_ticks_to_nsecs(uint32_t ticks) +{ + return ticks * 1000; +} + +/** + * @} OSCPUTime + * @} OSKernel + */ + +#endif diff --git a/porting/common/src/os/os_cputime_high.c b/porting/common/src/os/os_cputime_high.c new file mode 100644 index 000000000..bb7166234 --- /dev/null +++ b/porting/common/src/os/os_cputime_high.c @@ -0,0 +1,84 @@ +#include "os/os_cputime.h" + +/** + * This module implements cputime functionality for timers whose frequency is + * greater than 1 MHz. + */ + +#if defined(OS_CPUTIME_FREQ_HIGH) + +/** + * @addtogroup OSKernel Operating System Kernel + * @{ + * @defgroup OSCPUTime High Resolution Timers + * @{ + */ + +/** + * os cputime usecs to ticks + * + * Converts the given number of microseconds into cputime ticks. + * + * @param usecs The number of microseconds to convert to ticks + * + * @return uint32_t The number of ticks corresponding to 'usecs' + */ +uint32_t +os_cputime_usecs_to_ticks(uint32_t usecs) +{ + return usecs * g_os_cputime.ticks_per_usec; +} + +/** + * cputime ticks to usecs + * + * Convert the given number of ticks into microseconds. + * + * @param ticks The number of ticks to convert to microseconds. + * + * @return uint32_t The number of microseconds corresponding to 'ticks' + */ +uint32_t +os_cputime_ticks_to_usecs(uint32_t ticks) +{ + return (ticks + g_os_cputime.ticks_per_usec - 1) / + g_os_cputime.ticks_per_usec; +} + +/** + * os cputime nsecs to ticks + * + * Converts the given number of nanoseconds into cputime ticks. + * + * @param usecs The number of nanoseconds to convert to ticks + * + * @return uint32_t The number of ticks corresponding to 'nsecs' + */ +uint32_t +os_cputime_nsecs_to_ticks(uint32_t nsecs) +{ + return (nsecs * g_os_cputime.ticks_per_usec + 999) / 1000; +} + +/** + * os cputime ticks to nsecs + * + * Convert the given number of ticks into nanoseconds. + * + * @param ticks The number of ticks to convert to nanoseconds. + * + * @return uint32_t The number of nanoseconds corresponding to 'ticks' + */ +uint32_t +os_cputime_ticks_to_nsecs(uint32_t ticks) +{ + return (ticks * 1000 + g_os_cputime.ticks_per_usec - 1) / + g_os_cputime.ticks_per_usec; +} + +/** + * @} OSCPUTime + * @} OSKernel + */ + +#endif diff --git a/porting/common/src/os/os_cputime_pwr2.c b/porting/common/src/os/os_cputime_pwr2.c new file mode 100644 index 000000000..5a05b966c --- /dev/null +++ b/porting/common/src/os/os_cputime_pwr2.c @@ -0,0 +1,90 @@ +#include "os/os_cputime.h" + +/** + * This module implements cputime functionality for timers for which: + * a. freq is a power of 2 Hz, and + * b. 256 Hz <= freq < 1 MHz + */ + +#if defined(OS_CPUTIME_FREQ_PWR2) + +/** + * @addtogroup OSKernel Operating System Kernel + * @{ + * @defgroup OSCPUTime High Resolution Timers + * @{ + */ + +/** + * os cputime usecs to ticks + * + * Converts the given number of microseconds into cputime ticks. + * + * @param usecs The number of microseconds to convert to ticks + * + * @return uint32_t The number of ticks corresponding to 'usecs' + */ +uint32_t +os_cputime_usecs_to_ticks(uint32_t usecs) +{ + uint64_t ticks; + + /* + * Faster calculation but could be off 1 full tick since we do not + * add residual back. Adding back the residual is commented out below, but + * shown. + */ + ticks = (1ULL << 32) * MYNEWT_VAL(OS_CPUTIME_FREQ) / 1000000 * usecs; + + /* Residual for 32768 Hz. */ + //ticks += ((uint64_t)usecs * (1526122139+1)) >> 32; + + return ticks >> 32; +} + +/** + * cputime ticks to usecs + * + * Convert the given number of ticks into microseconds. + * + * @param ticks The number of ticks to convert to microseconds. + * + * @return uint32_t The number of microseconds corresponding to 'ticks' + * + * NOTE: This calculation will overflow if the value for ticks is greater + * than 140737488. I am not going to check that here because that many ticks + * is about 4222 seconds, way more than what this routine should be used for. + */ +uint32_t +os_cputime_ticks_to_usecs(uint32_t ticks) +{ + uint32_t usecs; + uint32_t shift; + uint32_t freq; + + /* Given: `freq = 2^n`, calculate `n`. */ + /* Note: this looks like a lot of work, but gcc can optimize it away since + * `freq` is known at compile time. + */ + freq = MYNEWT_VAL(OS_CPUTIME_FREQ); + shift = 0; + while (freq != 0) { + freq >>= 1; + shift++; + } + + if (shift <= 7) { + return 0; + } + shift -= 7; + + usecs = ((ticks >> shift) * 15625) + (((ticks & 0x1ff) * 15625) >> shift); + return usecs; +} + +/** + * @} OSCPUTime + * @} OSKernel + */ + +#endif diff --git a/porting/common/src/os/os_dev.c b/porting/common/src/os/os_dev.c new file mode 100644 index 000000000..07b1c5450 --- /dev/null +++ b/porting/common/src/os/os_dev.c @@ -0,0 +1,346 @@ +/* + * 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 "os/os.h" +#include "os/queue.h" +#include "os/os_dev.h" + +#include + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSDevice Device Framework + * @{ + */ + +static STAILQ_HEAD(, os_dev) g_os_dev_list; + +static int +os_dev_init(struct os_dev *dev, char *name, uint8_t stage, + uint8_t priority, os_dev_init_func_t od_init, void *arg) +{ + dev->od_name = name; + dev->od_stage = stage; + dev->od_priority = priority; + /* assume these are set after the fact. */ + dev->od_flags = 0; + dev->od_open_ref = 0; + dev->od_init = od_init; + dev->od_init_arg = arg; + memset(&dev->od_handlers, 0, sizeof(dev->od_handlers)); + + return (0); +} + +/** + * Add the device to the device tree. This is a private function. + * + * @param dev The device to add to the device tree. + * + * @return 0 on success, non-zero on failure. + */ +static int +os_dev_add(struct os_dev *dev) +{ + struct os_dev *cur_dev; + + /* If no devices present, insert into head */ + if (STAILQ_FIRST(&g_os_dev_list) == NULL) { + STAILQ_INSERT_HEAD(&g_os_dev_list, dev, od_next); + return (0); + } + + /* Add devices to the list, sorted first by stage, then by + * priority. Keep sorted in this order for initialization + * stage. + */ + cur_dev = NULL; + STAILQ_FOREACH(cur_dev, &g_os_dev_list, od_next) { + if (cur_dev->od_stage > dev->od_stage) { + continue; + } + + if (dev->od_priority >= cur_dev->od_priority) { + break; + } + } + + if (cur_dev) { + STAILQ_INSERT_AFTER(&g_os_dev_list, cur_dev, dev, od_next); + } else { + STAILQ_INSERT_TAIL(&g_os_dev_list, dev, od_next); + } + + return (0); +} + +/** + * Call device initialize routine, and mark it ready. This is a private + * function. + * + * @param dev The device to initialize. + * + * @return 0 on success, non-zero on failure. + */ +static int +os_dev_initialize(struct os_dev *dev) +{ + int rc; + + rc = dev->od_init(dev, dev->od_init_arg); + if (rc != 0) { + if (dev->od_flags & OS_DEV_F_INIT_CRITICAL) { + goto err; + } + } else { + dev->od_flags |= OS_DEV_F_STATUS_READY; + } + return 0; +err: + return rc; +} + + +/** + * Create a new device in the kernel. + * + * @param dev The device to create. + * @param name The name of the device to create. + * @param stage The stage to initialize that device to. + * @param priority The priority of initializing that device + * @param od_init The initialization function to call for this + * device. + * @param arg The argument to provide this device initialization + * function. + * + * @return 0 on success, non-zero on failure. + */ +int +os_dev_create(struct os_dev *dev, char *name, uint8_t stage, + uint8_t priority, os_dev_init_func_t od_init, void *arg) +{ + int rc; + + rc = os_dev_init(dev, name, stage, priority, od_init, arg); + if (rc != 0) { + goto err; + } + + rc = os_dev_add(dev); + if (rc != 0) { + goto err; + } + + if (g_os_started) { + rc = os_dev_initialize(dev); + } +err: + return (rc); +} + +/** + * Initialize all devices for a given state. + * + * @param stage The stage to initialize. + * + * @return 0 on success, non-zero on failure. + */ +int +os_dev_initialize_all(uint8_t stage) +{ + struct os_dev *dev; + int rc = 0; + + STAILQ_FOREACH(dev, &g_os_dev_list, od_next) { + if (dev->od_stage == stage) { + rc = os_dev_initialize(dev); + if (rc) { + break; + } + } + } + + return (rc); +} + +/** + * Suspend all devices. + * + * @param dev The device to suspend + * @param suspend_t The number of ticks to suspend this device for + * @param force Whether or not to force suspending the device + * + * @return 0 on success, or a non-zero error code if one of the devices + * returned it. + */ +int +os_dev_suspend_all(os_time_t suspend_t, uint8_t force) +{ + struct os_dev *dev; + int suspend_failure; + int rc; + + suspend_failure = 0; + STAILQ_FOREACH(dev, &g_os_dev_list, od_next) { + rc = os_dev_suspend(dev, suspend_t, force); + if (rc != 0) { + suspend_failure = OS_ERROR; + } + } + + return (suspend_failure); +} + +/** + * Resume all the devices that were suspended. + * + * @return 0 on success, -1 if any of the devices have failed to resume. + */ +int +os_dev_resume_all(void) +{ + struct os_dev *dev; + int rc; + + STAILQ_FOREACH(dev, &g_os_dev_list, od_next) { + rc = os_dev_resume(dev); + if (rc != 0) { + goto err; + } + } + + return (0); +err: + return (rc); +} + +/** + * Lookup a device by name. + * + * WARNING: This should be called before any locking on the device is done, or + * the device list itself is modified in any context. There is no locking. + * + * @param name The name of the device to look up. + * + * @return A pointer to the device corresponding to name, or NULL if not found. + */ +struct os_dev * +os_dev_lookup(char *name) +{ + struct os_dev *dev; + + dev = NULL; + STAILQ_FOREACH(dev, &g_os_dev_list, od_next) { + if (!strcmp(dev->od_name, name)) { + break; + } + } + return (dev); +} + +/** + * Open a device. + * + * @param dev The device to open + * @param timo The timeout to open the device, if not specified. + * @param arg The argument to the device open() call. + * + * @return 0 on success, non-zero on failure. + */ +struct os_dev * +os_dev_open(char *devname, uint32_t timo, void *arg) +{ + struct os_dev *dev; + os_sr_t sr; + int rc; + + dev = os_dev_lookup(devname); + if (dev == NULL) { + return (NULL); + } + + /* Device is not ready to be opened. */ + if ((dev->od_flags & OS_DEV_F_STATUS_READY) == 0) { + return (NULL); + } + + if (dev->od_handlers.od_open) { + rc = dev->od_handlers.od_open(dev, timo, arg); + if (rc != 0) { + goto err; + } + } + + OS_ENTER_CRITICAL(sr); + ++dev->od_open_ref; + dev->od_flags |= OS_DEV_F_STATUS_OPEN; + OS_EXIT_CRITICAL(sr); + + return (dev); +err: + return (NULL); +} + +/** + * Close a device. + * + * @param dev The device to close + * + * @return 0 on success, non-zero on failure. + */ +int +os_dev_close(struct os_dev *dev) +{ + int rc; + os_sr_t sr; + + if (dev->od_handlers.od_close) { + rc = dev->od_handlers.od_close(dev); + if (rc != 0) { + goto err; + } + } + + OS_ENTER_CRITICAL(sr); + if (--dev->od_open_ref == 0) { + dev->od_flags &= ~OS_DEV_F_STATUS_OPEN; + } + OS_EXIT_CRITICAL(sr); + + return (0); +err: + return (rc); +} + +/** + * Clears the device list. This function does not close any devices or free + * any resources; its purpose is to allow a full system reset between unit + * tests. + */ +void +os_dev_reset(void) +{ + STAILQ_INIT(&g_os_dev_list); +} + +/** + * @} OSDevice + * @} OSKernel + */ diff --git a/porting/common/src/os/os_eventq.c b/porting/common/src/os/os_eventq.c new file mode 100644 index 000000000..b09c81f22 --- /dev/null +++ b/porting/common/src/os/os_eventq.c @@ -0,0 +1,354 @@ +/* + * 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 +#include +#include "os/os_trace_api.h" + +#include "os/os.h" + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSEvent Event Queues + * @{ + */ + +static struct os_eventq os_eventq_main; + +/** + * Initialize the event queue + * + * @param evq The event queue to initialize + */ +void +os_eventq_init(struct os_eventq *evq) +{ + memset(evq, 0, sizeof(*evq)); + STAILQ_INIT(&evq->evq_list); +} + +int +os_eventq_inited(const struct os_eventq *evq) +{ + return evq->evq_list.stqh_last != NULL; +} + +/** + * Put an event on the event queue. + * + * @param evq The event queue to put an event on + * @param ev The event to put on the queue + */ +void +os_eventq_put(struct os_eventq *evq, struct os_event *ev) +{ + int resched; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + + /* Do not queue if already queued */ + if (OS_EVENT_QUEUED(ev)) { + OS_EXIT_CRITICAL(sr); + return; + } + + os_trace_void(OS_TRACE_ID_EVQ_PUT); + + /* Queue the event */ + ev->ev_queued = 1; + STAILQ_INSERT_TAIL(&evq->evq_list, ev, ev_next); + + resched = 0; + if (evq->evq_task) { + /* If task waiting on event, wake it up. + * Check if task is sleeping, because another event + * queue may have woken this task up beforehand. + */ + if (evq->evq_task->t_state == OS_TASK_SLEEP) { + os_sched_wakeup(evq->evq_task); + resched = 1; + } + /* Either way, NULL out the task, because the task will + * be awake upon exit of this function. + */ + evq->evq_task = NULL; + } + + os_trace_end_call(OS_TRACE_ID_EVQ_PUT); + OS_EXIT_CRITICAL(sr); + + if (resched) { + os_sched(NULL); + } +} + +struct os_event * +os_eventq_get_no_wait(struct os_eventq *evq) +{ + struct os_event *ev; + + ev = STAILQ_FIRST(&evq->evq_list); + if (ev) { + STAILQ_REMOVE(&evq->evq_list, ev, os_event, ev_next); + ev->ev_queued = 0; + } + + return ev; +} + +/** + * Pull a single item from an event queue. This function blocks until there + * is an item on the event queue to read. + * + * @param evq The event queue to pull an event from + * + * @return The event from the queue + */ +struct os_event * +os_eventq_get(struct os_eventq *evq) +{ + struct os_event *ev; + os_sr_t sr; + struct os_task *t; + + t = os_sched_get_current_task(); + if (evq->evq_owner != t) { + if (evq->evq_owner == NULL) { + evq->evq_owner = t; + } else { + /* + * A task is trying to read from event queue which is handled + * by another. + */ + assert(0); + } + } + OS_ENTER_CRITICAL(sr); + os_trace_void(OS_TRACE_ID_EVQ_GET); +pull_one: + ev = STAILQ_FIRST(&evq->evq_list); + if (ev) { + STAILQ_REMOVE(&evq->evq_list, ev, os_event, ev_next); + ev->ev_queued = 0; + t->t_flags &= ~OS_TASK_FLAG_EVQ_WAIT; + } else { + evq->evq_task = t; + os_sched_sleep(evq->evq_task, OS_TIMEOUT_NEVER); + t->t_flags |= OS_TASK_FLAG_EVQ_WAIT; + OS_EXIT_CRITICAL(sr); + + os_sched(NULL); + + OS_ENTER_CRITICAL(sr); + evq->evq_task = NULL; + goto pull_one; + } + os_trace_end_call(OS_TRACE_ID_EVQ_GET); + OS_EXIT_CRITICAL(sr); + + return (ev); +} + +void +os_eventq_run(struct os_eventq *evq) +{ + struct os_event *ev; + + ev = os_eventq_get(evq); + assert(ev->ev_cb != NULL); + + ev->ev_cb(ev); +} + +static struct os_event * +os_eventq_poll_0timo(struct os_eventq **evq, int nevqs) +{ + struct os_event *ev; + os_sr_t sr; + int i; + + ev = NULL; + + OS_ENTER_CRITICAL(sr); + for (i = 0; i < nevqs; i++) { + ev = STAILQ_FIRST(&evq[i]->evq_list); + if (ev) { + STAILQ_REMOVE(&evq[i]->evq_list, ev, os_event, ev_next); + ev->ev_queued = 0; + break; + } + } + OS_EXIT_CRITICAL(sr); + + return ev; +} + +/** + * Poll the list of event queues specified by the evq parameter + * (size nevqs), and return the "first" event available on any of + * the queues. Event queues are searched in the order that they + * are passed in the array. + * + * @param evq Array of event queues + * @param nevqs Number of event queues in evq + * @param timo Timeout, forever if OS_WAIT_FOREVER is passed to poll. + * + * @return An event, or NULL if no events available + */ +struct os_event * +os_eventq_poll(struct os_eventq **evq, int nevqs, os_time_t timo) +{ + struct os_event *ev; + struct os_task *cur_t; + int i, j; + os_sr_t sr; + + /* If the timeout is 0, don't involve the scheduler at all. Grab an event + * if one is available, else return immediately. + */ + if (timo == 0) { + return os_eventq_poll_0timo(evq, nevqs); + } + + ev = NULL; + + OS_ENTER_CRITICAL(sr); + cur_t = os_sched_get_current_task(); + + for (i = 0; i < nevqs; i++) { + ev = STAILQ_FIRST(&evq[i]->evq_list); + if (ev) { + STAILQ_REMOVE(&evq[i]->evq_list, ev, os_event, ev_next); + ev->ev_queued = 0; + /* Reset the items that already have an evq task set. */ + for (j = 0; j < i; j++) { + evq[j]->evq_task = NULL; + } + + OS_EXIT_CRITICAL(sr); + goto has_event; + } + evq[i]->evq_task = cur_t; + } + + cur_t->t_flags |= OS_TASK_FLAG_EVQ_WAIT; + + os_sched_sleep(cur_t, timo); + OS_EXIT_CRITICAL(sr); + + os_sched(NULL); + + OS_ENTER_CRITICAL(sr); + cur_t->t_flags &= ~OS_TASK_FLAG_EVQ_WAIT; + for (i = 0; i < nevqs; i++) { + /* Go through the entire loop to clear the evq_task variable, + * given this task is no longer sleeping on the event queues. + * Return the first event found, so only grab the event if + * we haven't found one. + */ + if (!ev) { + ev = STAILQ_FIRST(&evq[i]->evq_list); + if (ev) { + STAILQ_REMOVE(&evq[i]->evq_list, ev, os_event, ev_next); + ev->ev_queued = 0; + } + } + evq[i]->evq_task = NULL; + } + OS_EXIT_CRITICAL(sr); + +has_event: + return (ev); +} + +/** + * Remove an event from the queue. + * + * @param evq The event queue to remove the event from + * @param ev The event to remove from the queue + */ +void +os_eventq_remove(struct os_eventq *evq, struct os_event *ev) +{ + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + if (OS_EVENT_QUEUED(ev)) { + STAILQ_REMOVE(&evq->evq_list, ev, os_event, ev_next); + } + ev->ev_queued = 0; + OS_EXIT_CRITICAL(sr); +} + +/** + * Retrieves the default event queue processed by OS main task. + * + * @return The default event queue. + */ +struct os_eventq * +os_eventq_dflt_get(void) +{ + return &os_eventq_main; +} + +/** + * [DEPRECATED - packages should manually enqueue start events to the default + * task instead of calling this function] + * + * Reassigns an event queue pointer to the specified value. This function is + * used for configuring a package to use a particular event queue. A package's + * event queue can generally be reassigned repeatedly. If the package has a + * startup event, the event is moved from the current queue (if any) to the + * specified queue. + * + * @param cur_evq Points to the eventq pointer to reassign. + * *cur_evq should be NULL if the package's + * eventq has not been assigned yet. + * @param new_evq The eventq that the package should be + * associated with. + * @param start_ev The package's startup event, if any. If this + * is non-NULL, the event gets removed from + * the current queue (if set), and enqueued to + * the new eventq. + */ +void +os_eventq_designate(struct os_eventq **cur_evq, + struct os_eventq *new_evq, + struct os_event *start_ev) +{ + struct os_eventq *prev_evq; + + prev_evq = *cur_evq; + *cur_evq = new_evq; + + if (start_ev != NULL) { + if (start_ev->ev_queued) { + assert(prev_evq != NULL); + os_eventq_remove(prev_evq, start_ev); + } + os_eventq_put(new_evq, start_ev); + } +} + +/** + * @} OSEvent + * @} OSKernel + */ diff --git a/porting/common/src/os/os_heap.c b/porting/common/src/os/os_heap.c new file mode 100644 index 000000000..0d94325a1 --- /dev/null +++ b/porting/common/src/os/os_heap.c @@ -0,0 +1,124 @@ +/* + * 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 "syscfg/syscfg.h" + +#include +#include "os/os_mutex.h" +#include "os/os_heap.h" + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSGeneral + * @{ + */ + +#if MYNEWT_VAL(OS_SCHEDULING) +static struct os_mutex os_malloc_mutex; +#endif + +static void +os_malloc_lock(void) +{ +#if MYNEWT_VAL(OS_SCHEDULING) + int rc; + + if (g_os_started) { + rc = os_mutex_pend(&os_malloc_mutex, 0xffffffff); + assert(rc == 0); + } +#endif +} + +static void +os_malloc_unlock(void) +{ +#if MYNEWT_VAL(OS_SCHEDULING) + int rc; + + if (g_os_started) { + rc = os_mutex_release(&os_malloc_mutex); + assert(rc == 0); + } +#endif +} + +/** + * Operating system level malloc(). This ensures that a safe malloc occurs + * within the context of the OS. Depending on platform, the OS may rely on + * libc's malloc() implementation, which is not guaranteed to be thread-safe. + * This malloc() will always be thread-safe. + * + * @param size The number of bytes to allocate + * + * @return A pointer to the memory region allocated. + */ +void * +os_malloc(size_t size) +{ + void *ptr; + + os_malloc_lock(); + ptr = malloc(size); + os_malloc_unlock(); + + return ptr; +} + +/** + * Operating system level free(). See description of os_malloc() for reasoning. + * + * Free's memory allocated by malloc. + * + * @param mem The memory to free. + */ +void +os_free(void *mem) +{ + os_malloc_lock(); + free(mem); + os_malloc_unlock(); +} + +/** + * Operating system level realloc(). See description of os_malloc() for reasoning. + * + * Reallocates the memory at ptr, to be size contiguouos bytes. + * + * @param ptr A pointer to the memory to allocate + * @param size The number of contiguouos bytes to allocate at that location + * + * @return A pointer to memory of size, or NULL on failure to allocate + */ +void * +os_realloc(void *ptr, size_t size) +{ + void *new_ptr; + + os_malloc_lock(); + new_ptr = realloc(ptr, size); + os_malloc_unlock(); + + return new_ptr; +} + +/** + * @} OSGeneral + * @} OS Kernel + */ diff --git a/porting/common/src/os/os_mbuf.c b/porting/common/src/os/os_mbuf.c new file mode 100644 index 000000000..52c81ae5a --- /dev/null +++ b/porting/common/src/os/os_mbuf.c @@ -0,0 +1,1368 @@ +/* + * Software in this file is based heavily on code written in the FreeBSD source + * code repostiory. While the code is written from scratch, it contains + * many of the ideas and logic flow in the original source, this is a + * derivative work, and the following license applies as well: + * + * Copyright (c) 1982, 1986, 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "os/os.h" + +#include +#include +#include + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSMqueue Queue of Mbufs + * @{ + */ + +STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list = + STAILQ_HEAD_INITIALIZER(g_msys_pool_list); + +/** + * Initializes an mqueue. An mqueue is a queue of mbufs that ties to a + * particular task's event queue. Mqueues form a helper API around a common + * paradigm: wait on an event queue until at least one packet is available, + * then process a queue of packets. + * + * When mbufs are available on the queue, an event OS_EVENT_T_MQUEUE_DATA + * will be posted to the task's mbuf queue. + * + * @param mq The mqueue to initialize + * @param ev_cb The callback to associate with the mqeueue + * event. Typically, this callback pulls each + * packet off the mqueue and processes them. + * @param arg The argument to associate with the mqueue event. + * + * @return 0 on success, non-zero on failure. + */ +int +os_mqueue_init(struct os_mqueue *mq, os_event_fn *ev_cb, void *arg) +{ + struct os_event *ev; + + STAILQ_INIT(&mq->mq_head); + + ev = &mq->mq_ev; + memset(ev, 0, sizeof(*ev)); + ev->ev_cb = ev_cb; + ev->ev_arg = arg; + + return (0); +} + +/** + * Remove and return a single mbuf from the mbuf queue. Does not block. + * + * @param mq The mbuf queue to pull an element off of. + * + * @return The next mbuf in the queue, or NULL if queue has no mbufs. + */ +struct os_mbuf * +os_mqueue_get(struct os_mqueue *mq) +{ + struct os_mbuf_pkthdr *mp; + struct os_mbuf *m; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + mp = STAILQ_FIRST(&mq->mq_head); + if (mp) { + STAILQ_REMOVE_HEAD(&mq->mq_head, omp_next); + } + OS_EXIT_CRITICAL(sr); + + if (mp) { + m = OS_MBUF_PKTHDR_TO_MBUF(mp); + } else { + m = NULL; + } + + return (m); +} + +/** + * Adds a packet (i.e. packet header mbuf) to an mqueue. The event associated + * with the mqueue gets posted to the specified eventq. + * + * @param mq The mbuf queue to append the mbuf to. + * @param evq The event queue to post an event to. + * @param m The mbuf to append to the mbuf queue. + * + * @return 0 on success, non-zero on failure. + */ +int +os_mqueue_put(struct os_mqueue *mq, struct os_eventq *evq, struct os_mbuf *m) +{ + struct os_mbuf_pkthdr *mp; + os_sr_t sr; + int rc; + + /* Can only place the head of a chained mbuf on the queue. */ + if (!OS_MBUF_IS_PKTHDR(m)) { + rc = OS_EINVAL; + goto err; + } + + mp = OS_MBUF_PKTHDR(m); + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&mq->mq_head, mp, omp_next); + OS_EXIT_CRITICAL(sr); + + /* Only post an event to the queue if its specified */ + if (evq) { + os_eventq_put(evq, &mq->mq_ev); + } + + return (0); +err: + return (rc); +} + +/** + * @} OSMqueue + * @} OSKernel + */ + + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSMsys System level mbuf + * @{ + */ + +/** + * MSYS is a system level mbuf registry. Allows the system to share + * packet buffers amongst the various networking stacks that can be running + * simultaeneously. + * + * Mbuf pools are created in the system initialization code, and then when + * a mbuf is allocated out of msys, it will try and find the best fit based + * upon estimated mbuf size. + * + * os_msys_register() registers a mbuf pool with MSYS, and allows MSYS to + * allocate mbufs out of it. + * + * @param new_pool The pool to register with MSYS + * + * @return 0 on success, non-zero on failure + */ +int +os_msys_register(struct os_mbuf_pool *new_pool) +{ + struct os_mbuf_pool *pool; + + pool = NULL; + STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) { + if (new_pool->omp_databuf_len > pool->omp_databuf_len) { + break; + } + } + + if (pool) { + STAILQ_INSERT_AFTER(&g_msys_pool_list, pool, new_pool, omp_next); + } else { + STAILQ_INSERT_TAIL(&g_msys_pool_list, new_pool, omp_next); + } + + return (0); +} + +/** + * De-registers all mbuf pools from msys. + */ +void +os_msys_reset(void) +{ + STAILQ_INIT(&g_msys_pool_list); +} + +static struct os_mbuf_pool * +_os_msys_find_pool(uint16_t dsize) +{ + struct os_mbuf_pool *pool; + + pool = NULL; + STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) { + if (dsize <= pool->omp_databuf_len) { + break; + } + } + + if (!pool) { + pool = STAILQ_LAST(&g_msys_pool_list, os_mbuf_pool, omp_next); + } + + return (pool); +} + +/** + * Allocate a mbuf from msys. Based upon the data size requested, + * os_msys_get() will choose the mbuf pool that has the best fit. + * + * @param dsize The estimated size of the data being stored in the mbuf + * @param leadingspace The amount of leadingspace to allocate in the mbuf + * + * @return A freshly allocated mbuf on success, NULL on failure. + * + */ +struct os_mbuf * +os_msys_get(uint16_t dsize, uint16_t leadingspace) +{ + struct os_mbuf *m; + struct os_mbuf_pool *pool; + + pool = _os_msys_find_pool(dsize); + if (!pool) { + goto err; + } + + m = os_mbuf_get(pool, leadingspace); + return (m); +err: + return (NULL); +} + +/** + * Allocate a packet header structure from the MSYS pool. See + * os_msys_register() for a description of MSYS. + * + * @param dsize The estimated size of the data being stored in the mbuf + * @param user_hdr_len The length to allocate for the packet header structure + * + * @return A freshly allocated mbuf on success, NULL on failure. + */ +struct os_mbuf * +os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len) +{ + uint16_t total_pkthdr_len; + struct os_mbuf *m; + struct os_mbuf_pool *pool; + + total_pkthdr_len = user_hdr_len + sizeof(struct os_mbuf_pkthdr); + pool = _os_msys_find_pool(dsize + total_pkthdr_len); + if (!pool) { + goto err; + } + + m = os_mbuf_get_pkthdr(pool, user_hdr_len); + return (m); +err: + return (NULL); +} + +int +os_msys_count(void) +{ + struct os_mbuf_pool *omp; + int total; + + total = 0; + STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) { + total += omp->omp_pool->mp_num_blocks; + } + + return total; +} + +int +os_msys_num_free(void) +{ + struct os_mbuf_pool *omp; + int total; + + total = 0; + STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) { + total += omp->omp_pool->mp_num_free; + } + + return total; +} + +/** + * @} OSMsys + * @} OSKernel + */ + + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSMbuf Chained Memory Buffers + * @{ + */ + + +/** + * Initialize a pool of mbufs. + * + * @param omp The mbuf pool to initialize + * @param mp The memory pool that will hold this mbuf pool + * @param buf_len The length of the buffer itself. + * @param nbufs The number of buffers in the pool + * + * @return 0 on success, error code on failure. + */ +int +os_mbuf_pool_init(struct os_mbuf_pool *omp, struct os_mempool *mp, + uint16_t buf_len, uint16_t nbufs) +{ + omp->omp_databuf_len = buf_len - sizeof(struct os_mbuf); + omp->omp_mbuf_count = nbufs; + omp->omp_pool = mp; + + return (0); +} + +/** + * Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized + * prior to being returned. + * + * @param omp The mbuf pool to return the packet from + * @param leadingspace The amount of leadingspace to put before the data + * section by default. + * + * @return An initialized mbuf on success, and NULL on failure. + */ +struct os_mbuf * +os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace) +{ + struct os_mbuf *om; + + if (leadingspace > omp->omp_databuf_len) { + goto err; + } + + om = os_memblock_get(omp->omp_pool); + if (!om) { + goto err; + } + + SLIST_NEXT(om, om_next) = NULL; + om->om_flags = 0; + om->om_pkthdr_len = 0; + om->om_len = 0; + om->om_data = (&om->om_databuf[0] + leadingspace); + om->om_omp = omp; + + return (om); +err: + return (NULL); +} + +/** + * Allocate a new packet header mbuf out of the os_mbuf_pool. + * + * @param omp The mbuf pool to allocate out of + * @param user_pkthdr_len The packet header length to reserve for the caller. + * + * @return A freshly allocated mbuf on success, NULL on failure. + */ +struct os_mbuf * +os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, uint8_t user_pkthdr_len) +{ + uint16_t pkthdr_len; + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + + /* User packet header must fit inside mbuf */ + pkthdr_len = user_pkthdr_len + sizeof(struct os_mbuf_pkthdr); + if ((pkthdr_len > omp->omp_databuf_len) || (pkthdr_len > 255)) { + return NULL; + } + + om = os_mbuf_get(omp, 0); + if (om) { + om->om_pkthdr_len = pkthdr_len; + om->om_data += pkthdr_len; + + pkthdr = OS_MBUF_PKTHDR(om); + pkthdr->omp_len = 0; + pkthdr->omp_flags = 0; + STAILQ_NEXT(pkthdr, omp_next) = NULL; + } + + return om; +} + +/** + * Release a mbuf back to the pool + * + * @param omp The Mbuf pool to release back to + * @param om The Mbuf to release back to the pool + * + * @return 0 on success, -1 on failure + */ +int +os_mbuf_free(struct os_mbuf *om) +{ + int rc; + + if (om->om_omp != NULL) { + rc = os_memblock_put(om->om_omp->omp_pool, om); + if (rc != 0) { + goto err; + } + } + + return (0); +err: + return (rc); +} + +/** + * Free a chain of mbufs + * + * @param omp The mbuf pool to free the chain of mbufs into + * @param om The starting mbuf of the chain to free back into the pool + * + * @return 0 on success, -1 on failure + */ +int +os_mbuf_free_chain(struct os_mbuf *om) +{ + struct os_mbuf *next; + int rc; + + while (om != NULL) { + next = SLIST_NEXT(om, om_next); + + rc = os_mbuf_free(om); + if (rc != 0) { + goto err; + } + + om = next; + } + + return (0); +err: + return (rc); +} + +/** + * Copy a packet header from one mbuf to another. + * + * @param omp The mbuf pool associated with these buffers + * @param new_buf The new buffer to copy the packet header into + * @param old_buf The old buffer to copy the packet header from + */ +static inline void +_os_mbuf_copypkthdr(struct os_mbuf *new_buf, struct os_mbuf *old_buf) +{ + assert(new_buf->om_len == 0); + + memcpy(&new_buf->om_databuf[0], &old_buf->om_databuf[0], + old_buf->om_pkthdr_len); + new_buf->om_pkthdr_len = old_buf->om_pkthdr_len; + new_buf->om_data = new_buf->om_databuf + old_buf->om_pkthdr_len; +} + +/** + * Append data onto a mbuf + * + * @param om The mbuf to append the data onto + * @param data The data to append onto the mbuf + * @param len The length of the data to append + * + * @return 0 on success, and an error code on failure + */ +int +os_mbuf_append(struct os_mbuf *om, const void *data, uint16_t len) +{ + struct os_mbuf_pool *omp; + struct os_mbuf *last; + struct os_mbuf *new; + int remainder; + int space; + int rc; + + if (om == NULL) { + rc = OS_EINVAL; + goto err; + } + + omp = om->om_omp; + + /* Scroll to last mbuf in the chain */ + last = om; + while (SLIST_NEXT(last, om_next) != NULL) { + last = SLIST_NEXT(last, om_next); + } + + remainder = len; + space = OS_MBUF_TRAILINGSPACE(last); + + /* If room in current mbuf, copy the first part of the data into the + * remaining space in that mbuf. + */ + if (space > 0) { + if (space > remainder) { + space = remainder; + } + + memcpy(OS_MBUF_DATA(last, uint8_t *) + last->om_len , data, space); + + last->om_len += space; + data += space; + remainder -= space; + } + + /* Take the remaining data, and keep allocating new mbufs and copying + * data into it, until data is exhausted. + */ + while (remainder > 0) { + new = os_mbuf_get(omp, 0); + if (!new) { + break; + } + + new->om_len = min(omp->omp_databuf_len, remainder); + memcpy(OS_MBUF_DATA(new, void *), data, new->om_len); + data += new->om_len; + remainder -= new->om_len; + SLIST_NEXT(last, om_next) = new; + last = new; + } + + /* Adjust the packet header length in the buffer */ + if (OS_MBUF_IS_PKTHDR(om)) { + OS_MBUF_PKTHDR(om)->omp_len += len - remainder; + } + + if (remainder != 0) { + rc = OS_ENOMEM; + goto err; + } + + + return (0); +err: + return (rc); +} + +/** + * Reads data from one mbuf and appends it to another. On error, the specified + * data range may be partially appended. Neither mbuf is required to contain + * an mbuf packet header. + * + * @param dst The mbuf to append to. + * @param src The mbuf to copy data from. + * @param src_off The absolute offset within the source mbuf + * chain to read from. + * @param len The number of bytes to append. + * + * @return 0 on success; + * OS_EINVAL if the specified range extends beyond + * the end of the source mbuf chain. + */ +int +os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src, + uint16_t src_off, uint16_t len) +{ + const struct os_mbuf *src_cur_om; + uint16_t src_cur_off; + uint16_t chunk_sz; + int rc; + + src_cur_om = os_mbuf_off(src, src_off, &src_cur_off); + while (len > 0) { + if (src_cur_om == NULL) { + return OS_EINVAL; + } + + chunk_sz = min(len, src_cur_om->om_len - src_cur_off); + rc = os_mbuf_append(dst, src_cur_om->om_data + src_cur_off, chunk_sz); + if (rc != 0) { + return rc; + } + + len -= chunk_sz; + src_cur_om = SLIST_NEXT(src_cur_om, om_next); + src_cur_off = 0; + } + + return 0; +} + +/** + * Duplicate a chain of mbufs. Return the start of the duplicated chain. + * + * @param omp The mbuf pool to duplicate out of + * @param om The mbuf chain to duplicate + * + * @return A pointer to the new chain of mbufs + */ +struct os_mbuf * +os_mbuf_dup(struct os_mbuf *om) +{ + struct os_mbuf_pool *omp; + struct os_mbuf *head; + struct os_mbuf *copy; + + omp = om->om_omp; + + head = NULL; + copy = NULL; + + for (; om != NULL; om = SLIST_NEXT(om, om_next)) { + if (head) { + SLIST_NEXT(copy, om_next) = os_mbuf_get(omp, + OS_MBUF_LEADINGSPACE(om)); + if (!SLIST_NEXT(copy, om_next)) { + os_mbuf_free_chain(head); + goto err; + } + + copy = SLIST_NEXT(copy, om_next); + } else { + head = os_mbuf_get(omp, OS_MBUF_LEADINGSPACE(om)); + if (!head) { + goto err; + } + + if (OS_MBUF_IS_PKTHDR(om)) { + _os_mbuf_copypkthdr(head, om); + } + copy = head; + } + copy->om_flags = om->om_flags; + copy->om_len = om->om_len; + memcpy(OS_MBUF_DATA(copy, uint8_t *), OS_MBUF_DATA(om, uint8_t *), + om->om_len); + } + + return (head); +err: + return (NULL); +} + +/** + * Locates the specified absolute offset within an mbuf chain. The offset + * can be one past than the total length of the chain, but no greater. + * + * @param om The start of the mbuf chain to seek within. + * @param off The absolute address to find. + * @param out_off On success, this points to the relative offset + * within the returned mbuf. + * + * @return The mbuf containing the specified offset on + * success. + * NULL if the specified offset is out of bounds. + */ +struct os_mbuf * +os_mbuf_off(const struct os_mbuf *om, int off, uint16_t *out_off) +{ + struct os_mbuf *next; + struct os_mbuf *cur; + + /* Cast away const. */ + cur = (struct os_mbuf *)om; + + while (1) { + if (cur == NULL) { + return NULL; + } + + next = SLIST_NEXT(cur, om_next); + + if (cur->om_len > off || + (cur->om_len == off && next == NULL)) { + + *out_off = off; + return cur; + } + + off -= cur->om_len; + cur = next; + } +} + +/* + * Copy data from an mbuf chain starting "off" bytes from the beginning, + * continuing for "len" bytes, into the indicated buffer. + * + * @param m The mbuf chain to copy from + * @param off The offset into the mbuf chain to begin copying from + * @param len The length of the data to copy + * @param dst The destination buffer to copy into + * + * @return 0 on success; + * -1 if the mbuf does not contain enough data. + */ +int +os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst) +{ + unsigned int count; + uint8_t *udst; + + if (!len) { + return 0; + } + + udst = dst; + + while (off > 0) { + if (!m) { + return (-1); + } + + if (off < m->om_len) + break; + off -= m->om_len; + m = SLIST_NEXT(m, om_next); + } + while (len > 0 && m != NULL) { + count = min(m->om_len - off, len); + memcpy(udst, m->om_data + off, count); + len -= count; + udst += count; + off = 0; + m = SLIST_NEXT(m, om_next); + } + + return (len > 0 ? -1 : 0); +} + +/** + * Adjust the length of a mbuf, trimming either from the head or the tail + * of the mbuf. + * + * @param mp The mbuf chain to adjust + * @param req_len The length to trim from the mbuf. If positive, trims + * from the head of the mbuf, if negative, trims from the + * tail of the mbuf. + */ +void +os_mbuf_adj(struct os_mbuf *mp, int req_len) +{ + int len = req_len; + struct os_mbuf *m; + int count; + + if ((m = mp) == NULL) + return; + if (len >= 0) { + /* + * Trim from head. + */ + while (m != NULL && len > 0) { + if (m->om_len <= len) { + len -= m->om_len; + m->om_len = 0; + m = SLIST_NEXT(m, om_next); + } else { + m->om_len -= len; + m->om_data += len; + len = 0; + } + } + if (OS_MBUF_IS_PKTHDR(mp)) + OS_MBUF_PKTHDR(mp)->omp_len -= (req_len - len); + } else { + /* + * Trim from tail. Scan the mbuf chain, + * calculating its length and finding the last mbuf. + * If the adjustment only affects this mbuf, then just + * adjust and return. Otherwise, rescan and truncate + * after the remaining size. + */ + len = -len; + count = 0; + for (;;) { + count += m->om_len; + if (SLIST_NEXT(m, om_next) == (struct os_mbuf *)0) + break; + m = SLIST_NEXT(m, om_next); + } + if (m->om_len >= len) { + m->om_len -= len; + if (OS_MBUF_IS_PKTHDR(mp)) + OS_MBUF_PKTHDR(mp)->omp_len -= len; + return; + } + count -= len; + if (count < 0) + count = 0; + /* + * Correct length for chain is "count". + * Find the mbuf with last data, adjust its length, + * and toss data from remaining mbufs on chain. + */ + m = mp; + if (OS_MBUF_IS_PKTHDR(m)) + OS_MBUF_PKTHDR(m)->omp_len = count; + for (; m; m = SLIST_NEXT(m, om_next)) { + if (m->om_len >= count) { + m->om_len = count; + if (SLIST_NEXT(m, om_next) != NULL) { + os_mbuf_free_chain(SLIST_NEXT(m, om_next)); + SLIST_NEXT(m, om_next) = NULL; + } + break; + } + count -= m->om_len; + } + } +} + +/** + * Performs a memory compare of the specified region of an mbuf chain against a + * flat buffer. + * + * @param om The start of the mbuf chain to compare. + * @param off The offset within the mbuf chain to start the + * comparison. + * @param data The flat buffer to compare. + * @param len The length of the flat buffer. + * + * @return 0 if both memory regions are identical; + * A memcmp return code if there is a mismatch; + * INT_MAX if the mbuf is too short. + */ +int +os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len) +{ + uint16_t chunk_sz; + uint16_t data_off; + uint16_t om_off; + int rc; + + if (len <= 0) { + return 0; + } + + data_off = 0; + om = os_mbuf_off(om, off, &om_off); + while (1) { + if (om == NULL) { + return INT_MAX; + } + + chunk_sz = min(om->om_len - om_off, len - data_off); + if (chunk_sz > 0) { + rc = memcmp(om->om_data + om_off, data + data_off, chunk_sz); + if (rc != 0) { + return rc; + } + } + + data_off += chunk_sz; + if (data_off == len) { + return 0; + } + + om = SLIST_NEXT(om, om_next); + om_off = 0; + + if (om == NULL) { + return INT_MAX; + } + } +} + +/** + * Compares the contents of two mbuf chains. The ranges of the two chains to + * be compared are specified via the two offset parameters and the len + * parameter. Neither mbuf chain is required to contain a packet header. + * + * @param om1 The first mbuf chain to compare. + * @param offset1 The absolute offset within om1 at which to + * start the comparison. + * @param om2 The second mbuf chain to compare. + * @param offset2 The absolute offset within om2 at which to + * start the comparison. + * @param len The number of bytes to compare. + * + * @return 0 if both mbuf segments are identical; + * A memcmp() return code if the segment contents + * differ; + * INT_MAX if a specified range extends beyond the + * end of its corresponding mbuf chain. + */ +int +os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1, + const struct os_mbuf *om2, uint16_t offset2, + uint16_t len) +{ + const struct os_mbuf *cur1; + const struct os_mbuf *cur2; + uint16_t bytes_remaining; + uint16_t chunk_sz; + uint16_t om1_left; + uint16_t om2_left; + uint16_t om1_off; + uint16_t om2_off; + int rc; + + om1_off = 0; + om2_off = 0; + + cur1 = os_mbuf_off(om1, offset1, &om1_off); + cur2 = os_mbuf_off(om2, offset2, &om2_off); + + bytes_remaining = len; + while (1) { + if (bytes_remaining == 0) { + return 0; + } + + while (cur1 != NULL && om1_off >= cur1->om_len) { + cur1 = SLIST_NEXT(cur1, om_next); + om1_off = 0; + } + while (cur2 != NULL && om2_off >= cur2->om_len) { + cur2 = SLIST_NEXT(cur2, om_next); + om2_off = 0; + } + + if (cur1 == NULL || cur2 == NULL) { + return INT_MAX; + } + + om1_left = cur1->om_len - om1_off; + om2_left = cur2->om_len - om2_off; + chunk_sz = min(min(om1_left, om2_left), bytes_remaining); + + rc = memcmp(cur1->om_data + om1_off, cur2->om_data + om2_off, + chunk_sz); + if (rc != 0) { + return rc; + } + + om1_off += chunk_sz; + om2_off += chunk_sz; + bytes_remaining -= chunk_sz; + } +} + +/** + * Increases the length of an mbuf chain by adding data to the front. If there + * is insufficient room in the leading mbuf, additional mbufs are allocated and + * prepended as necessary. If this function fails to allocate an mbuf, the + * entire chain is freed. + * + * The specified mbuf chain does not need to contain a packet header. + * + * @param omp The mbuf pool to allocate from. + * @param om The head of the mbuf chain. + * @param len The number of bytes to prepend. + * + * @return The new head of the chain on success; + * NULL on failure. + */ +struct os_mbuf * +os_mbuf_prepend(struct os_mbuf *om, int len) +{ + struct os_mbuf *p; + int leading; + + while (1) { + /* Fill the available space at the front of the head of the chain, as + * needed. + */ + leading = min(len, OS_MBUF_LEADINGSPACE(om)); + + om->om_data -= leading; + om->om_len += leading; + if (OS_MBUF_IS_PKTHDR(om)) { + OS_MBUF_PKTHDR(om)->omp_len += leading; + } + + len -= leading; + if (len == 0) { + break; + } + + /* The current head didn't have enough space; allocate a new head. */ + if (OS_MBUF_IS_PKTHDR(om)) { + p = os_mbuf_get_pkthdr(om->om_omp, + om->om_pkthdr_len - sizeof (struct os_mbuf_pkthdr)); + } else { + p = os_mbuf_get(om->om_omp, 0); + } + if (p == NULL) { + os_mbuf_free_chain(om); + om = NULL; + break; + } + + if (OS_MBUF_IS_PKTHDR(om)) { + _os_mbuf_copypkthdr(p, om); + om->om_pkthdr_len = 0; + } + + /* Move the new head's data pointer to the end so that data can be + * prepended. + */ + p->om_data += OS_MBUF_TRAILINGSPACE(p); + + SLIST_NEXT(p, om_next) = om; + om = p; + } + + return om; +} + +/** + * Prepends a chunk of empty data to the specified mbuf chain and ensures the + * chunk is contiguous. If either operation fails, the specified mbuf chain is + * freed and NULL is returned. + * + * @param om The mbuf chain to prepend to. + * @param len The number of bytes to prepend and pullup. + * + * @return The modified mbuf on success; + * NULL on failure (and the mbuf chain is freed). + */ +struct os_mbuf * +os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len) +{ + om = os_mbuf_prepend(om, len); + if (om == NULL) { + return NULL; + } + + om = os_mbuf_pullup(om, len); + if (om == NULL) { + return NULL; + } + + return om; +} + +/** + * Copies the contents of a flat buffer into an mbuf chain, starting at the + * specified destination offset. If the mbuf is too small for the source data, + * it is extended as necessary. If the destination mbuf contains a packet + * header, the header length is updated. + * + * @param omp The mbuf pool to allocate from. + * @param om The mbuf chain to copy into. + * @param off The offset within the chain to copy to. + * @param src The source buffer to copy from. + * @param len The number of bytes to copy. + * + * @return 0 on success; nonzero on failure. + */ +int +os_mbuf_copyinto(struct os_mbuf *om, int off, const void *src, int len) +{ + struct os_mbuf *next; + struct os_mbuf *cur; + const uint8_t *sptr; + uint16_t cur_off; + int copylen; + int rc; + + /* Find the mbuf,offset pair for the start of the destination. */ + cur = os_mbuf_off(om, off, &cur_off); + if (cur == NULL) { + return -1; + } + + /* Overwrite existing data until we reach the end of the chain. */ + sptr = src; + while (1) { + copylen = min(cur->om_len - cur_off, len); + if (copylen > 0) { + memcpy(cur->om_data + cur_off, sptr, copylen); + sptr += copylen; + len -= copylen; + + copylen = 0; + } + + if (len == 0) { + /* All the source data fit in the existing mbuf chain. */ + return 0; + } + + next = SLIST_NEXT(cur, om_next); + if (next == NULL) { + break; + } + + cur = next; + cur_off = 0; + } + + /* Append the remaining data to the end of the chain. */ + rc = os_mbuf_append(cur, sptr, len); + if (rc != 0) { + return rc; + } + + /* Fix up the packet header, if one is present. */ + if (OS_MBUF_IS_PKTHDR(om)) { + OS_MBUF_PKTHDR(om)->omp_len = + max(OS_MBUF_PKTHDR(om)->omp_len, off + len); + } + + return 0; +} + +/** + * Attaches a second mbuf chain onto the end of the first. If the first chain + * contains a packet header, the header's length is updated. If the second + * chain has a packet header, its header is cleared. + * + * @param first The mbuf chain being attached to. + * @param second The mbuf chain that gets attached. + */ +void +os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second) +{ + struct os_mbuf *next; + struct os_mbuf *cur; + + /* Point 'cur' to the last buffer in the first chain. */ + cur = first; + while (1) { + next = SLIST_NEXT(cur, om_next); + if (next == NULL) { + break; + } + + cur = next; + } + + /* Attach the second chain to the end of the first. */ + SLIST_NEXT(cur, om_next) = second; + + /* If the first chain has a packet header, calculate the length of the + * second chain and add it to the header length. + */ + if (OS_MBUF_IS_PKTHDR(first)) { + if (OS_MBUF_IS_PKTHDR(second)) { + OS_MBUF_PKTHDR(first)->omp_len += OS_MBUF_PKTHDR(second)->omp_len; + } else { + for (cur = second; cur != NULL; cur = SLIST_NEXT(cur, om_next)) { + OS_MBUF_PKTHDR(first)->omp_len += cur->om_len; + } + } + } + + second->om_pkthdr_len = 0; +} + +/** + * Increases the length of an mbuf chain by the specified amount. If there is + * not sufficient room in the last buffer, a new buffer is allocated and + * appended to the chain. It is an error to request more data than can fit in + * a single buffer. + * + * @param omp + * @param om The head of the chain to extend. + * @param len The number of bytes to extend by. + * + * @return A pointer to the new data on success; + * NULL on failure. + */ +void * +os_mbuf_extend(struct os_mbuf *om, uint16_t len) +{ + struct os_mbuf *newm; + struct os_mbuf *last; + void *data; + + if (len > om->om_omp->omp_databuf_len) { + return NULL; + } + + /* Scroll to last mbuf in the chain */ + last = om; + while (SLIST_NEXT(last, om_next) != NULL) { + last = SLIST_NEXT(last, om_next); + } + + if (OS_MBUF_TRAILINGSPACE(last) < len) { + newm = os_mbuf_get(om->om_omp, 0); + if (newm == NULL) { + return NULL; + } + + SLIST_NEXT(last, om_next) = newm; + last = newm; + } + + data = last->om_data + last->om_len; + last->om_len += len; + + if (OS_MBUF_IS_PKTHDR(om)) { + OS_MBUF_PKTHDR(om)->omp_len += len; + } + + return data; +} + +/** + * Rearrange a mbuf chain so that len bytes are contiguous, + * and in the data area of an mbuf (so that OS_MBUF_DATA() will + * work on a structure of size len.) Returns the resulting + * mbuf chain on success, free's it and returns NULL on failure. + * + * If there is room, it will add up to "max_protohdr - len" + * extra bytes to the contiguous region, in an attempt to avoid being + * called next time. + * + * @param omp The mbuf pool to take the mbufs out of + * @param om The mbuf chain to make contiguous + * @param len The number of bytes in the chain to make contiguous + * + * @return The contiguous mbuf chain on success, NULL on failure. + */ +struct os_mbuf * +os_mbuf_pullup(struct os_mbuf *om, uint16_t len) +{ + struct os_mbuf_pool *omp; + struct os_mbuf *next; + struct os_mbuf *om2; + int count; + int space; + + omp = om->om_omp; + + /* + * If first mbuf has no cluster, and has room for len bytes + * without shifting current data, pullup into it, + * otherwise allocate a new mbuf to prepend to the chain. + */ + if (om->om_len >= len) { + return (om); + } + if (om->om_len + OS_MBUF_TRAILINGSPACE(om) >= len && + SLIST_NEXT(om, om_next)) { + om2 = om; + om = SLIST_NEXT(om, om_next); + len -= om2->om_len; + } else { + if (len > omp->omp_databuf_len - om->om_pkthdr_len) { + goto bad; + } + + om2 = os_mbuf_get(omp, 0); + if (om2 == NULL) { + goto bad; + } + + if (OS_MBUF_IS_PKTHDR(om)) { + _os_mbuf_copypkthdr(om2, om); + } + } + space = OS_MBUF_TRAILINGSPACE(om2); + do { + count = min(min(len, space), om->om_len); + memcpy(om2->om_data + om2->om_len, om->om_data, count); + len -= count; + om2->om_len += count; + om->om_len -= count; + space -= count; + if (om->om_len) { + om->om_data += count; + } else { + next = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + om = next; + } + } while (len > 0 && om); + if (len > 0) { + os_mbuf_free(om2); + goto bad; + } + SLIST_NEXT(om2, om_next) = om; + return (om2); +bad: + os_mbuf_free_chain(om); + return (NULL); +} + +/** + * Removes and frees empty mbufs from the front of a chain. If the chain + * contains a packet header, it is preserved. + * + * @param om The mbuf chain to trim. + * + * @return The head of the trimmed mbuf chain. + */ +struct os_mbuf * +os_mbuf_trim_front(struct os_mbuf *om) +{ + struct os_mbuf *next; + struct os_mbuf *cur; + + /* Abort early if there is nothing to trim. */ + if (om->om_len != 0) { + return om; + } + + /* Starting with the second mbuf in the chain, continue removing and + * freeing mbufs until an non-empty one is encountered. + */ + cur = SLIST_NEXT(om, om_next); + while (cur != NULL && cur->om_len == 0) { + next = SLIST_NEXT(cur, om_next); + + SLIST_NEXT(om, om_next) = next; + os_mbuf_free(cur); + + cur = next; + } + + if (cur == NULL) { + /* All buffers after the first have been freed. */ + return om; + } + + /* Try to remove the first mbuf in the chain. If this buffer contains a + * packet header, make sure the second buffer can accommodate it. + */ + if (OS_MBUF_LEADINGSPACE(cur) >= om->om_pkthdr_len) { + /* Second buffer has room; copy packet header. */ + cur->om_pkthdr_len = om->om_pkthdr_len; + memcpy(OS_MBUF_PKTHDR(cur), OS_MBUF_PKTHDR(om), om->om_pkthdr_len); + + /* Free first buffer. */ + os_mbuf_free(om); + om = cur; + } + + return om; +} + +/** + * @} OSMbuf + * @} OSKernel + */ diff --git a/porting/common/src/os/os_mempool.c b/porting/common/src/os/os_mempool.c new file mode 100644 index 000000000..65e4f6159 --- /dev/null +++ b/porting/common/src/os/os_mempool.c @@ -0,0 +1,321 @@ +/* + * 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 "os/os.h" + +#include +#include +#include + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSMempool Memory Pools + * @{ + */ + +#define OS_MEM_TRUE_BLOCK_SIZE(bsize) OS_ALIGN(bsize, OS_ALIGNMENT) +#define OS_MEMPOOL_TRUE_BLOCK_SIZE(mp) OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size) + +STAILQ_HEAD(, os_mempool) g_os_mempool_list = + STAILQ_HEAD_INITIALIZER(g_os_mempool_list); + +#if MYNEWT_VAL(OS_MEMPOOL_POISON) +static uint32_t os_mem_poison = 0xde7ec7ed; + +static void +os_mempool_poison(void *start, int sz) +{ + int i; + char *p = start; + + for (i = sizeof(struct os_memblock); i < sz; + i = i + sizeof(os_mem_poison)) { + memcpy(p + i, &os_mem_poison, min(sizeof(os_mem_poison), sz - i)); + } +} + +static void +os_mempool_poison_check(void *start, int sz) +{ + int i; + char *p = start; + + for (i = sizeof(struct os_memblock); i < sz; + i = i + sizeof(os_mem_poison)) { + assert(!memcmp(p + i, &os_mem_poison, + min(sizeof(os_mem_poison), sz - i))); + } +} +#else +#define os_mempool_poison(start, sz) +#define os_mempool_poison_check(start, sz) +#endif + +/** + * os mempool init + * + * Initialize a memory pool. + * + * @param mp Pointer to a pointer to a mempool + * @param blocks The number of blocks in the pool + * @param blocks_size The size of the block, in bytes. + * @param membuf Pointer to memory to contain blocks. + * @param name Name of the pool. + * + * @return os_error_t + */ +os_error_t +os_mempool_init(struct os_mempool *mp, int blocks, int block_size, + void *membuf, char *name) +{ + int true_block_size; + uint8_t *block_addr; + struct os_memblock *block_ptr; + + /* Check for valid parameters */ + if (!mp || (blocks < 0) || (block_size <= sizeof(struct os_memblock))) { + return OS_INVALID_PARM; + } + + if ((!membuf) && (blocks != 0)) { + return OS_INVALID_PARM; + } + + if (membuf != NULL) { + /* Blocks need to be sized properly and memory buffer should be + * aligned + */ + if (((uint32_t)membuf & (OS_ALIGNMENT - 1)) != 0) { + return OS_MEM_NOT_ALIGNED; + } + } + true_block_size = OS_MEM_TRUE_BLOCK_SIZE(block_size); + + /* Initialize the memory pool structure */ + mp->mp_block_size = block_size; + mp->mp_num_free = blocks; + mp->mp_min_free = blocks; + mp->mp_num_blocks = blocks; + mp->mp_membuf_addr = (uint32_t)membuf; + mp->name = name; + os_mempool_poison(membuf, true_block_size); + SLIST_FIRST(mp) = membuf; + + /* Chain the memory blocks to the free list */ + block_addr = (uint8_t *)membuf; + block_ptr = (struct os_memblock *)block_addr; + while (blocks > 1) { + block_addr += true_block_size; + os_mempool_poison(block_addr, true_block_size); + SLIST_NEXT(block_ptr, mb_next) = (struct os_memblock *)block_addr; + block_ptr = (struct os_memblock *)block_addr; + --blocks; + } + + /* Last one in the list should be NULL */ + SLIST_NEXT(block_ptr, mb_next) = NULL; + + STAILQ_INSERT_TAIL(&g_os_mempool_list, mp, mp_list); + + return OS_OK; +} + +/** + * Performs an integrity check of the specified mempool. This function + * attempts to detect memory corruption in the specified memory pool. + * + * @param mp The mempool to check. + * + * @return true if the memory pool passes the integrity + * check; + * false if the memory pool is corrupt. + */ +bool +os_mempool_is_sane(const struct os_mempool *mp) +{ + struct os_memblock *block; + + /* Verify that each block in the free list belongs to the mempool. */ + SLIST_FOREACH(block, mp, mb_next) { + if (!os_memblock_from(mp, block)) { + return false; + } + os_mempool_poison_check(block, OS_MEMPOOL_TRUE_BLOCK_SIZE(mp)); + } + + return true; +} + +/** + * Checks if a memory block was allocated from the specified mempool. + * + * @param mp The mempool to check as parent. + * @param block_addr The memory block to check as child. + * + * @return 0 if the block does not belong to the mempool; + * 1 if the block does belong to the mempool. + */ +int +os_memblock_from(const struct os_mempool *mp, const void *block_addr) +{ + uint32_t true_block_size; + uint32_t baddr32; + uint32_t end; + + _Static_assert(sizeof block_addr == sizeof baddr32, + "Pointer to void must be 32-bits."); + + baddr32 = (uint32_t)block_addr; + true_block_size = OS_MEMPOOL_TRUE_BLOCK_SIZE(mp); + end = mp->mp_membuf_addr + (mp->mp_num_blocks * true_block_size); + + /* Check that the block is in the memory buffer range. */ + if ((baddr32 < mp->mp_membuf_addr) || (baddr32 >= end)) { + return 0; + } + + /* All freed blocks should be on true block size boundaries! */ + if (((baddr32 - mp->mp_membuf_addr) % true_block_size) != 0) { + return 0; + } + + return 1; +} + +/** + * os memblock get + * + * Get a memory block from a memory pool + * + * @param mp Pointer to the memory pool + * + * @return void* Pointer to block if available; NULL otherwise + */ +void * +os_memblock_get(struct os_mempool *mp) +{ + os_sr_t sr; + struct os_memblock *block; + + /* Check to make sure they passed in a memory pool (or something) */ + block = NULL; + if (mp) { + OS_ENTER_CRITICAL(sr); + /* Check for any free */ + if (mp->mp_num_free) { + /* Get a free block */ + block = SLIST_FIRST(mp); + + os_mempool_poison_check(block, OS_MEMPOOL_TRUE_BLOCK_SIZE(mp)); + + /* Set new free list head */ + SLIST_FIRST(mp) = SLIST_NEXT(block, mb_next); + + /* Decrement number free by 1 */ + mp->mp_num_free--; + if (mp->mp_min_free > mp->mp_num_free) { + mp->mp_min_free = mp->mp_num_free; + } + } + OS_EXIT_CRITICAL(sr); + } + + return (void *)block; +} + +/** + * os memblock put + * + * Puts the memory block back into the pool + * + * @param mp Pointer to memory pool + * @param block_addr Pointer to memory block + * + * @return os_error_t + */ +os_error_t +os_memblock_put(struct os_mempool *mp, void *block_addr) +{ + os_sr_t sr; + struct os_memblock *block; + + /* Make sure parameters are valid */ + if ((mp == NULL) || (block_addr == NULL)) { + return OS_INVALID_PARM; + } + +#if MYNEWT_VAL(OS_MEMPOOL_CHECK) + /* Check that the block we are freeing is a valid block! */ + assert(os_memblock_from(mp, block_addr)); + + /* + * Check for duplicate free. + */ + SLIST_FOREACH(block, mp, mb_next) { + assert(block != (struct os_memblock *)block_addr); + } +#endif + os_mempool_poison(block_addr, OS_MEMPOOL_TRUE_BLOCK_SIZE(mp)); + block = (struct os_memblock *)block_addr; + OS_ENTER_CRITICAL(sr); + + /* Chain current free list pointer to this block; make this block head */ + SLIST_NEXT(block, mb_next) = SLIST_FIRST(mp); + SLIST_FIRST(mp) = block; + + /* XXX: Should we check that the number free <= number blocks? */ + /* Increment number free */ + mp->mp_num_free++; + + OS_EXIT_CRITICAL(sr); + + return OS_OK; +} + + +struct os_mempool * +os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi) +{ + struct os_mempool *cur; + + if (mp == NULL) { + cur = STAILQ_FIRST(&g_os_mempool_list); + } else { + cur = STAILQ_NEXT(mp, mp_list); + } + + if (cur == NULL) { + return (NULL); + } + + omi->omi_block_size = cur->mp_block_size; + omi->omi_num_blocks = cur->mp_num_blocks; + omi->omi_num_free = cur->mp_num_free; + omi->omi_min_free = cur->mp_min_free; + strncpy(omi->omi_name, cur->name, sizeof(omi->omi_name)); + + return (cur); +} + + +/** + * @} OSMempool + * @} OSKernel + */ diff --git a/porting/common/src/os/os_msys_init.c b/porting/common/src/os/os_msys_init.c new file mode 100644 index 000000000..a907b4136 --- /dev/null +++ b/porting/common/src/os/os_msys_init.c @@ -0,0 +1,88 @@ +/* + * 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 + +#include "../os/os_priv.h" +#include "sysinit/sysinit.h" +#include "syscfg/syscfg.h" +#include "os/os_mempool.h" +#include "mem/mem.h" + +#if MYNEWT_VAL(MSYS_1_BLOCK_COUNT) > 0 +#define SYSINIT_MSYS_1_MEMBLOCK_SIZE \ + OS_ALIGN(MYNEWT_VAL(MSYS_1_BLOCK_SIZE), 4) +#define SYSINIT_MSYS_1_MEMPOOL_SIZE \ + OS_MEMPOOL_SIZE(MYNEWT_VAL(MSYS_1_BLOCK_COUNT), \ + SYSINIT_MSYS_1_MEMBLOCK_SIZE) +static os_membuf_t os_msys_init_1_data[SYSINIT_MSYS_1_MEMPOOL_SIZE]; +static struct os_mbuf_pool os_msys_init_1_mbuf_pool; +static struct os_mempool os_msys_init_1_mempool; +#endif + +#if MYNEWT_VAL(MSYS_2_BLOCK_COUNT) > 0 +#define SYSINIT_MSYS_2_MEMBLOCK_SIZE \ + OS_ALIGN(MYNEWT_VAL(MSYS_2_BLOCK_SIZE), 4) +#define SYSINIT_MSYS_2_MEMPOOL_SIZE \ + OS_MEMPOOL_SIZE(MYNEWT_VAL(MSYS_2_BLOCK_COUNT), \ + SYSINIT_MSYS_2_MEMBLOCK_SIZE) +static os_membuf_t os_msys_init_2_data[SYSINIT_MSYS_2_MEMPOOL_SIZE]; +static struct os_mbuf_pool os_msys_init_2_mbuf_pool; +static struct os_mempool os_msys_init_2_mempool; +#endif + +static void +os_msys_init_once(void *data, struct os_mempool *mempool, + struct os_mbuf_pool *mbuf_pool, + int block_count, int block_size, char *name) +{ + int rc; + + rc = mem_init_mbuf_pool(data, mempool, mbuf_pool, block_count, block_size, + name); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_msys_register(mbuf_pool); + SYSINIT_PANIC_ASSERT(rc == 0); +} + +void +os_msys_init(void) +{ + os_msys_reset(); + + (void)os_msys_init_once; +#if MYNEWT_VAL(MSYS_1_BLOCK_COUNT) > 0 + os_msys_init_once(os_msys_init_1_data, + &os_msys_init_1_mempool, + &os_msys_init_1_mbuf_pool, + MYNEWT_VAL(MSYS_1_BLOCK_COUNT), + SYSINIT_MSYS_1_MEMBLOCK_SIZE, + "msys_1"); +#endif + +#if MYNEWT_VAL(MSYS_2_BLOCK_COUNT) > 0 + os_msys_init_once(os_msys_init_2_data, + &os_msys_init_2_mempool, + &os_msys_init_2_mbuf_pool, + MYNEWT_VAL(MSYS_2_BLOCK_COUNT), + SYSINIT_MSYS_2_MEMBLOCK_SIZE, + "msys_2"); +#endif +} diff --git a/porting/common/src/os/os_mutex.c b/porting/common/src/os/os_mutex.c new file mode 100644 index 000000000..117045f97 --- /dev/null +++ b/porting/common/src/os/os_mutex.c @@ -0,0 +1,262 @@ +/* + * 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 "os/os.h" +#include "os/os_trace_api.h" +#include + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSMutex Mutexes + * @{ + */ + + +/** + * os mutex create + * + * Create a mutex and initialize it. + * + * @param mu Pointer to mutex + * + * @return os_error_t + * OS_INVALID_PARM Mutex passed in was NULL. + * OS_OK no error. + */ +os_error_t +os_mutex_init(struct os_mutex *mu) +{ + if (!mu) { + return OS_INVALID_PARM; + } + + os_trace_void(OS_TRACE_ID_MUTEX_INIT); + /* Initialize to 0 */ + mu->mu_prio = 0; + mu->mu_level = 0; + mu->mu_owner = NULL; + SLIST_FIRST(&mu->mu_head) = NULL; + os_trace_end_call(OS_TRACE_ID_MUTEX_INIT); + + return OS_OK; +} + +/** + * os mutex release + * + * Release a mutex. + * + * @param mu Pointer to the mutex to be released + * + * @return os_error_t + * OS_INVALID_PARM Mutex passed in was NULL. + * OS_BAD_MUTEX Mutex was not granted to current task (not owner). + * OS_OK No error + */ +os_error_t +os_mutex_release(struct os_mutex *mu) +{ + int resched; + os_sr_t sr; + struct os_task *current; + struct os_task *rdy; + + /* Check if OS is started */ + if (!g_os_started) { + return (OS_NOT_STARTED); + } + + /* Check for valid mutex */ + if (!mu) { + return OS_INVALID_PARM; + } + + /* We better own this mutex! */ + current = os_sched_get_current_task(); + if ((mu->mu_level == 0) || (mu->mu_owner != current)) { + return (OS_BAD_MUTEX); + } + + /* Decrement nesting level by 1. If not zero, nested (so dont release!) */ + --mu->mu_level; + if (mu->mu_level != 0) { + return (OS_OK); + } + + OS_ENTER_CRITICAL(sr); + os_trace_void(OS_TRACE_ID_MUTEX_RELEASE); + + /* Restore owner task's priority; resort list if different */ + if (current->t_prio != mu->mu_prio) { + current->t_prio = mu->mu_prio; + os_sched_resort(current); + } + + /* Check if tasks are waiting for the mutex */ + rdy = SLIST_FIRST(&mu->mu_head); + if (rdy) { + /* There is one waiting. Wake it up */ + assert(rdy->t_obj); + os_sched_wakeup(rdy); + + /* Set mutex internals */ + mu->mu_level = 1; + mu->mu_prio = rdy->t_prio; + } + + /* Set new owner of mutex (or NULL if not owned) */ + mu->mu_owner = rdy; + if (rdy) { + rdy->t_lockcnt++; + } + --current->t_lockcnt; + + /* Do we need to re-schedule? */ + resched = 0; + rdy = os_sched_next_task(); + if (rdy != current) { + resched = 1; + } + OS_EXIT_CRITICAL(sr); + + /* Re-schedule if needed */ + if (resched) { + os_sched(rdy); + } + os_trace_end_call(OS_TRACE_ID_MUTEX_RELEASE); + + return OS_OK; +} + +/** + * os mutex pend + * + * Pend (wait) for a mutex. + * + * @param mu Pointer to mutex. + * @param timeout Timeout, in os ticks. A timeout of 0 means do + * not wait if not available. A timeout of + * 0xFFFFFFFF means wait forever. + * + * + * @return os_error_t + * OS_INVALID_PARM Mutex passed in was NULL. + * OS_TIMEOUT Mutex was owned by another task and timeout=0 + * OS_OK no error. + */ +os_error_t +os_mutex_pend(struct os_mutex *mu, uint32_t timeout) +{ + os_sr_t sr; + os_error_t rc; + struct os_task *current; + struct os_task *entry; + struct os_task *last; + + /* OS must be started when calling this function */ + if (!g_os_started) { + return (OS_NOT_STARTED); + } + + /* Check for valid mutex */ + if (!mu) { + return OS_INVALID_PARM; + } + + OS_ENTER_CRITICAL(sr); + + /* Is this owned? */ + current = os_sched_get_current_task(); + if (mu->mu_level == 0) { + mu->mu_owner = current; + mu->mu_prio = current->t_prio; + current->t_lockcnt++; + mu->mu_level = 1; + OS_EXIT_CRITICAL(sr); + return OS_OK; + } + + /* Are we owner? */ + if (mu->mu_owner == current) { + ++mu->mu_level; + OS_EXIT_CRITICAL(sr); + return OS_OK; + } + + /* Mutex is not owned by us. If timeout is 0, return immediately */ + if (timeout == 0) { + OS_EXIT_CRITICAL(sr); + return OS_TIMEOUT; + } + + os_trace_void(OS_TRACE_ID_MUTEX_PEND); + + /* Change priority of owner if needed */ + if (mu->mu_owner->t_prio > current->t_prio) { + mu->mu_owner->t_prio = current->t_prio; + os_sched_resort(mu->mu_owner); + } + + /* Link current task to tasks waiting for mutex */ + last = NULL; + if (!SLIST_EMPTY(&mu->mu_head)) { + /* Insert in priority order */ + SLIST_FOREACH(entry, &mu->mu_head, t_obj_list) { + if (current->t_prio < entry->t_prio) { + break; + } + last = entry; + } + } + + if (last) { + SLIST_INSERT_AFTER(last, current, t_obj_list); + } else { + SLIST_INSERT_HEAD(&mu->mu_head, current, t_obj_list); + } + + /* Set mutex pointer in task */ + current->t_obj = mu; + current->t_flags |= OS_TASK_FLAG_MUTEX_WAIT; + os_sched_sleep(current, timeout); + OS_EXIT_CRITICAL(sr); + + os_sched(NULL); + + OS_ENTER_CRITICAL(sr); + current->t_flags &= ~OS_TASK_FLAG_MUTEX_WAIT; + OS_EXIT_CRITICAL(sr); + + /* If we are owner we did not time out. */ + if (mu->mu_owner == current) { + rc = OS_OK; + } else { + rc = OS_TIMEOUT; + } + os_trace_end_call(OS_TRACE_ID_MUTEX_PEND); + + return rc; +} + + +/** + * @} OSMutex + * @} OSKernel + */ diff --git a/porting/common/src/os/os_priv.h b/porting/common/src/os/os_priv.h new file mode 100644 index 000000000..be7f4580d --- /dev/null +++ b/porting/common/src/os/os_priv.h @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef H_OS_PRIV_ +#define H_OS_PRIV_ + +#include "os/queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct os_task g_idle_task; +extern struct os_task_list g_os_run_list; +extern struct os_task_list g_os_sleep_list; +extern struct os_task_stailq g_os_task_list; +extern struct os_callout_list g_callout_list; + +void os_msys_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/common/src/os/os_sanity.c b/porting/common/src/os/os_sanity.c new file mode 100644 index 000000000..5b967119a --- /dev/null +++ b/porting/common/src/os/os_sanity.c @@ -0,0 +1,250 @@ +/* + * 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 +#include + +#include "os/os.h" + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSSanity Sanity + * @{ + */ + +SLIST_HEAD(, os_sanity_check) g_os_sanity_check_list = + SLIST_HEAD_INITIALIZER(os_sanity_check_list); + +struct os_mutex g_os_sanity_check_mu; + +/** + * Initialize a sanity check + * + * @param sc The sanity check to initialize + * + * @return 0 on success, error code on failure. + */ +int +os_sanity_check_init(struct os_sanity_check *sc) +{ + memset(sc, 0, sizeof(*sc)); + + return (0); +} + +/** + * Lock the sanity check list + * + * @return 0 on success, error code on failure. + */ +static int +os_sanity_check_list_lock(void) +{ + int rc; + + if (!g_os_started) { + return (0); + } + + rc = os_mutex_pend(&g_os_sanity_check_mu, OS_WAIT_FOREVER); + if (rc != OS_OK) { + goto err; + } + + return (0); +err: + return (rc); +} + +/** + * Unlock the sanity check list + * + * @return 0 on success, error code on failure + */ +static int +os_sanity_check_list_unlock(void) +{ + int rc; + + if (!g_os_started) { + return (0); + } + + rc = os_mutex_release(&g_os_sanity_check_mu); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +/** + * Provide a "task checkin" for the sanity task. + * + * @param t The task to check in + * + * @return 0 on success, error code on failure + */ +int +os_sanity_task_checkin(struct os_task *t) +{ + int rc; + + if (t == NULL) { + t = os_sched_get_current_task(); + } + + rc = os_sanity_check_reset(&t->t_sanity_check); + if (rc != OS_OK) { + goto err; + } + + return (0); +err: + return (rc); +} + + +/** + * Register a sanity check + * + * @param sc The sanity check to register + * + * @return 0 on success, error code on failure + */ +int +os_sanity_check_register(struct os_sanity_check *sc) +{ + int rc; + + rc = os_sanity_check_list_lock(); + if (rc != OS_OK) { + goto err; + } + + SLIST_INSERT_HEAD(&g_os_sanity_check_list, sc, sc_next); + + rc = os_sanity_check_list_unlock(); + if (rc != OS_OK) { + goto err; + } + + return (0); +err: + return (rc); +} + + +/** + * Reset the os sanity check, so that it doesn't trip up the + * sanity timer. + * + * @param sc The sanity check to reset + * + * @return 0 on success, error code on failure + */ +int +os_sanity_check_reset(struct os_sanity_check *sc) +{ + int rc; + + rc = os_sanity_check_list_lock(); + if (rc != OS_OK) { + goto err; + } + + sc->sc_checkin_last = os_time_get(); + + rc = os_sanity_check_list_unlock(); + if (rc != OS_OK) { + goto err; + } + + return (0); +err: + return (rc); +} + +/* + * Called from the IDLE task context, every MYNEWT_VAL(SANITY_INTERVAL) msecs. + * + * Goes through the sanity check list, and performs sanity checks. If any of + * these checks failed, or tasks have not checked in, it resets the processor. + */ +void +os_sanity_run(void) +{ + struct os_sanity_check *sc; + int rc; + + rc = os_sanity_check_list_lock(); + if (rc != 0) { + assert(0); + } + + SLIST_FOREACH(sc, &g_os_sanity_check_list, sc_next) { + rc = OS_OK; + + if (sc->sc_func) { + rc = sc->sc_func(sc, sc->sc_arg); + if (rc == OS_OK) { + sc->sc_checkin_last = os_time_get(); + continue; + } + } + + if (OS_TIME_TICK_GT(os_time_get(), + sc->sc_checkin_last + sc->sc_checkin_itvl)) { + assert(0); + } + } + + rc = os_sanity_check_list_unlock(); + if (rc != 0) { + assert(0); + } +} + +/** + * Initialize the sanity task and mutex. + * + * @return 0 on success, error code on failure + */ +int +os_sanity_init(void) +{ + int rc; + + rc = os_mutex_init(&g_os_sanity_check_mu); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +/** + * @} OSSanity + * @} OSKernel + */ diff --git a/porting/common/src/os/os_sched.c b/porting/common/src/os/os_sched.c new file mode 100644 index 000000000..9204a7395 --- /dev/null +++ b/porting/common/src/os/os_sched.c @@ -0,0 +1,377 @@ +/* + * 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 "os/os.h" +#include "os/os_trace_api.h" +#include "os/queue.h" +#include +#include "../os/os_priv.h" + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSSched Scheduler + * @{ + */ + +struct os_task_list g_os_run_list = TAILQ_HEAD_INITIALIZER(g_os_run_list); +struct os_task_list g_os_sleep_list = TAILQ_HEAD_INITIALIZER(g_os_sleep_list); + +struct os_task *g_current_task; + +extern os_time_t g_os_time; +os_time_t g_os_last_ctx_sw_time; + +/** + * os sched insert + * + * Insert a task into the scheduler list. This causes the task to be evaluated + * for running when os_sched is called. + * + * @param t Pointer to task to insert in run list + * + * @return int OS_OK: task was inserted into run list + * OS_EINVAL: Task was not in ready state. + */ +os_error_t +os_sched_insert(struct os_task *t) +{ + struct os_task *entry; + os_sr_t sr; + os_error_t rc; + + if (t->t_state != OS_TASK_READY) { + rc = OS_EINVAL; + goto err; + } + + entry = NULL; + OS_ENTER_CRITICAL(sr); + TAILQ_FOREACH(entry, &g_os_run_list, t_os_list) { + if (t->t_prio < entry->t_prio) { + break; + } + } + if (entry) { + TAILQ_INSERT_BEFORE(entry, (struct os_task *) t, t_os_list); + } else { + TAILQ_INSERT_TAIL(&g_os_run_list, (struct os_task *) t, t_os_list); + } + OS_EXIT_CRITICAL(sr); + + return (0); +err: + return (rc); +} + +void +os_sched_ctx_sw_hook(struct os_task *next_t) +{ +#if MYNEWT_VAL(OS_CTX_SW_STACK_CHECK) + os_stack_t *top; + int i; + + top = g_current_task->t_stacktop - g_current_task->t_stacksize; + for (i = 0; i < MYNEWT_VAL(OS_CTX_SW_STACK_GUARD); i++) { + assert(top[i] == OS_STACK_PATTERN); + } +#endif + os_trace_task_start_exec(next_t->t_taskid); + next_t->t_ctx_sw_cnt++; + g_current_task->t_run_time += g_os_time - g_os_last_ctx_sw_time; + g_os_last_ctx_sw_time = g_os_time; +} + +/** + * os sched get current task + * + * Returns the currently running task. Note that this task may or may not be + * the highest priority task ready to run. + * + * + * @return struct os_task* + */ +struct os_task * +os_sched_get_current_task(void) +{ + return (g_current_task); +} + +/** + * os sched set current task + * + * Sets the currently running task to 't'. Note that this function simply sets + * the global variable holding the currently running task. It does not perform + * a context switch or change the os run or sleep list. + * + * @param t Pointer to currently running task. + */ +void +os_sched_set_current_task(struct os_task *t) +{ + g_current_task = t; +} + +/** + * os sched + * + * Performs a context switch. When called, it will either find the highest + * priority task ready to run if next_t is NULL (i.e. the head of the os run + * list) or will schedule next_t as the task to run. + * + * @param next_t Task to run + */ +void +os_sched(struct os_task *next_t) +{ + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + + if (!next_t) { + next_t = os_sched_next_task(); + } + + os_arch_ctx_sw(next_t); + + OS_EXIT_CRITICAL(sr); +} + +/** + * os sched sleep + * + * Removes the task from the run list and puts it on the sleep list. + * + * @param t Task to put to sleep + * @param nticks Number of ticks to put task to sleep + * + * @return int + * + * NOTE: must be called with interrupts disabled! This function does not call + * the scheduler + */ +int +os_sched_sleep(struct os_task *t, os_time_t nticks) +{ + struct os_task *entry; + + entry = NULL; + + TAILQ_REMOVE(&g_os_run_list, t, t_os_list); + t->t_state = OS_TASK_SLEEP; + t->t_next_wakeup = os_time_get() + nticks; + if (nticks == OS_TIMEOUT_NEVER) { + t->t_flags |= OS_TASK_FLAG_NO_TIMEOUT; + TAILQ_INSERT_TAIL(&g_os_sleep_list, t, t_os_list); + } else { + TAILQ_FOREACH(entry, &g_os_sleep_list, t_os_list) { + if ((entry->t_flags & OS_TASK_FLAG_NO_TIMEOUT) || + OS_TIME_TICK_GT(entry->t_next_wakeup, t->t_next_wakeup)) { + break; + } + } + if (entry) { + TAILQ_INSERT_BEFORE(entry, t, t_os_list); + } else { + TAILQ_INSERT_TAIL(&g_os_sleep_list, t, t_os_list); + } + } + + os_trace_task_stop_ready(t->t_taskid, OS_TASK_SLEEP); + return (0); +} + +/** + * os sched remove + * + * XXX + * NOTE - This routine is currently experimental and not ready for common use + * + * Stops a task and removes it from the task list. + * + * @return int + * + * NOTE: must be called with interrupts disabled! This function does not call + * the scheduler + */ +int +os_sched_remove(struct os_task *t) +{ + + if (t->t_state == OS_TASK_SLEEP) { + TAILQ_REMOVE(&g_os_sleep_list, t, t_os_list); + } else if (t->t_state == OS_TASK_READY) { + TAILQ_REMOVE(&g_os_run_list, t, t_os_list); + } + t->t_next_wakeup = 0; + t->t_flags |= OS_TASK_FLAG_NO_TIMEOUT; + + STAILQ_REMOVE(&g_os_task_list, t, os_task, t_os_task_list); + + os_trace_task_stop_exec(); + return OS_OK; +} + +/** + * os sched wakeup + * + * Called to wake up a task. Waking up a task consists of setting the task state + * to READY and moving it from the sleep list to the run list. + * + * @param t Pointer to task to wake up. + * + * @return int + * + * NOTE: This function must be called with interrupts disabled. + */ +int +os_sched_wakeup(struct os_task *t) +{ + struct os_task_obj *os_obj; + + assert(t->t_state == OS_TASK_SLEEP); + + /* Remove self from object list if waiting on one */ + if (t->t_obj) { + os_obj = (struct os_task_obj *)t->t_obj; + assert(!SLIST_EMPTY(&os_obj->obj_head)); + SLIST_REMOVE(&os_obj->obj_head, t, os_task, t_obj_list); + SLIST_NEXT(t, t_obj_list) = NULL; + t->t_obj = NULL; + } + + /* Remove task from sleep list */ + t->t_state = OS_TASK_READY; + t->t_next_wakeup = 0; + t->t_flags &= ~OS_TASK_FLAG_NO_TIMEOUT; + TAILQ_REMOVE(&g_os_sleep_list, t, t_os_list); + os_sched_insert(t); + + return (0); +} + +/** + * os sched os timer exp + * + * Called when the OS tick timer expires. Search the sleep list for any tasks + * that need waking up. This occurs when the current OS time exceeds the next + * wakeup time stored in the task. Any tasks that need waking up will be + * removed from the sleep list and added to the run list. + * + */ +void +os_sched_os_timer_exp(void) +{ + struct os_task *t; + struct os_task *next; + os_time_t now; + os_sr_t sr; + + now = os_time_get(); + + OS_ENTER_CRITICAL(sr); + + /* + * Wakeup any tasks that have their sleep timer expired + */ + t = TAILQ_FIRST(&g_os_sleep_list); + while (t) { + /* If task waiting forever, do not check next wakeup time */ + if (t->t_flags & OS_TASK_FLAG_NO_TIMEOUT) { + break; + } + next = TAILQ_NEXT(t, t_os_list); + if (OS_TIME_TICK_GEQ(now, t->t_next_wakeup)) { + os_trace_task_start_ready(t->t_taskid); + os_sched_wakeup(t); + } else { + break; + } + t = next; + } + + OS_EXIT_CRITICAL(sr); +} + +/* + * Return the number of ticks until the first sleep timer expires.If there are + * no such tasks then return OS_TIMEOUT_NEVER instead. + */ +os_time_t +os_sched_wakeup_ticks(os_time_t now) +{ + os_time_t rt; + struct os_task *t; + + OS_ASSERT_CRITICAL(); + + t = TAILQ_FIRST(&g_os_sleep_list); + if (t == NULL || (t->t_flags & OS_TASK_FLAG_NO_TIMEOUT)) { + rt = OS_TIMEOUT_NEVER; + } else if (OS_TIME_TICK_GEQ(t->t_next_wakeup, now)) { + rt = t->t_next_wakeup - now; + } else { + rt = 0; /* wakeup time was in the past */ + } + return (rt); +} + +/** + * os sched next task + * + * Returns the task that we should be running. This is the task at the head + * of the run list. + * + * NOTE: if you want to guarantee that the os run list does not change after + * calling this function you have to call it with interrupts disabled. + * + * @return struct os_task* + */ +struct os_task * +os_sched_next_task(void) +{ + return (TAILQ_FIRST(&g_os_run_list)); +} + +/** + * os sched resort + * + * Resort a task that is in the ready list as its priority has + * changed. If the task is not in the ready state, there is + * nothing to do. + * + * @param t Pointer to task to insert back into ready to run + * list. + * + * NOTE: this function expects interrupts to be disabled so they + * are not disabled here. + */ +void +os_sched_resort(struct os_task *t) +{ + if (t->t_state == OS_TASK_READY) { + TAILQ_REMOVE(&g_os_run_list, t, t_os_list); + os_sched_insert(t); + } +} + +/** + * @} OSSched + * @} OSKernel + */ diff --git a/porting/common/src/os/os_sem.c b/porting/common/src/os/os_sem.c new file mode 100644 index 000000000..7566087a6 --- /dev/null +++ b/porting/common/src/os/os_sem.c @@ -0,0 +1,225 @@ +/* + * 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 "os/os.h" +#include + + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSSem Semaphores + * @{ + */ + +/* XXX: + * 1) Should I check to see if we are within an ISR for some of these? + * 2) Would I do anything different for os_sem_release() if we were in an + * ISR when this was called? + */ + +/** + * os sem initialize + * + * Initialize a semaphore + * + * @param sem Pointer to semaphore + * tokens: # of tokens the semaphore should contain initially. + * + * @return os_error_t + * OS_INVALID_PARM Semaphore passed in was NULL. + * OS_OK no error. + */ +os_error_t +os_sem_init(struct os_sem *sem, uint16_t tokens) +{ + if (!sem) { + return OS_INVALID_PARM; + } + + sem->sem_tokens = tokens; + SLIST_FIRST(&sem->sem_head) = NULL; + + return OS_OK; +} + +/** + * os sem release + * + * Release a semaphore. + * + * @param sem Pointer to the semaphore to be released + * + * @return os_error_t + * OS_INVALID_PARM Semaphore passed in was NULL. + * OS_OK No error + */ +os_error_t +os_sem_release(struct os_sem *sem) +{ + int resched; + os_sr_t sr; + struct os_task *current; + struct os_task *rdy; + + /* OS must be started to release semaphores */ + if (!g_os_started) { + return (OS_NOT_STARTED); + } + + /* Check for valid semaphore */ + if (!sem) { + return OS_INVALID_PARM; + } + + /* Get current task */ + resched = 0; + current = os_sched_get_current_task(); + + OS_ENTER_CRITICAL(sr); + + /* Check if tasks are waiting for the semaphore */ + rdy = SLIST_FIRST(&sem->sem_head); + if (rdy) { + /* Clear flag that we are waiting on the semaphore; wake up task */ + rdy->t_flags &= ~OS_TASK_FLAG_SEM_WAIT; + os_sched_wakeup(rdy); + + /* Schedule if waiting task higher priority */ + if (current->t_prio > rdy->t_prio) { + resched = 1; + } + } else { + /* Add to the number of tokens */ + sem->sem_tokens++; + } + + OS_EXIT_CRITICAL(sr); + + /* Re-schedule if needed */ + if (resched) { + os_sched(rdy); + } + + return OS_OK; +} + +/** + * os sem pend + * + * Pend (wait) for a semaphore. + * + * @param mu Pointer to semaphore. + * @param timeout Timeout, in os ticks. A timeout of 0 means do + * not wait if not available. A timeout of + * 0xFFFFFFFF means wait forever. + * + * + * @return os_error_t + * OS_INVALID_PARM Semaphore passed in was NULL. + * OS_TIMEOUT Semaphore was owned by another task and timeout=0 + * OS_OK no error. + */ +os_error_t +os_sem_pend(struct os_sem *sem, uint32_t timeout) +{ + os_sr_t sr; + os_error_t rc; + int sched; + struct os_task *current; + struct os_task *entry; + struct os_task *last; + + /* Check if OS is started */ + if (!g_os_started) { + return (OS_NOT_STARTED); + } + + /* Check for valid semaphore */ + if (!sem) { + return OS_INVALID_PARM; + } + + /* Assume we dont have to put task to sleep; get current task */ + sched = 0; + current = os_sched_get_current_task(); + + OS_ENTER_CRITICAL(sr); + + /* + * If there is a token available, take it. If no token, either return + * with error if timeout was 0 or put this task to sleep. + */ + if (sem->sem_tokens != 0) { + sem->sem_tokens--; + rc = OS_OK; + } else if (timeout == 0) { + rc = OS_TIMEOUT; + } else { + /* Silence gcc maybe-uninitialized warning. */ + rc = OS_OK; + + /* Link current task to tasks waiting for semaphore */ + current->t_obj = sem; + current->t_flags |= OS_TASK_FLAG_SEM_WAIT; + last = NULL; + if (!SLIST_EMPTY(&sem->sem_head)) { + /* Insert in priority order */ + SLIST_FOREACH(entry, &sem->sem_head, t_obj_list) { + if (current->t_prio < entry->t_prio) { + break; + } + last = entry; + } + } + + if (last) { + SLIST_INSERT_AFTER(last, current, t_obj_list); + } else { + SLIST_INSERT_HEAD(&sem->sem_head, current, t_obj_list); + } + + /* We will put this task to sleep */ + sched = 1; + os_sched_sleep(current, timeout); + } + + OS_EXIT_CRITICAL(sr); + + if (sched) { + os_sched(NULL); + /* Check if we timed out or got the semaphore */ + if (current->t_flags & OS_TASK_FLAG_SEM_WAIT) { + OS_ENTER_CRITICAL(sr); + current->t_flags &= ~OS_TASK_FLAG_SEM_WAIT; + OS_EXIT_CRITICAL(sr); + rc = OS_TIMEOUT; + } else { + rc = OS_OK; + } + } + + return rc; +} + + +/** + * @} OSSched + * @} OSKernel + */ diff --git a/porting/common/src/os/os_task.c b/porting/common/src/os/os_task.c new file mode 100644 index 000000000..4f9620909 --- /dev/null +++ b/porting/common/src/os/os_task.c @@ -0,0 +1,284 @@ +/* + * 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 "os/os.h" +#include "os/os_trace_api.h" + +#include +#include +#include "../os/os_priv.h" + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSTask Tasks + * @{ + */ + +uint8_t g_task_id; + +struct os_task_stailq g_os_task_list; + +static void +_clear_stack(os_stack_t *stack_bottom, int size) +{ + int i; + + for (i = 0; i < size; i++) { + stack_bottom[i] = OS_STACK_PATTERN; + } +} + +static inline uint8_t +os_task_next_id(void) +{ + uint8_t rc; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + rc = g_task_id; + g_task_id++; + OS_EXIT_CRITICAL(sr); + + return (rc); +} + +/** + * Return the number of tasks initialized. + * + * @return number of tasks initialized + */ +uint8_t +os_task_count(void) +{ + return (g_task_id); +} + +/** + * Initialize a task. + * + * This function initializes the task structure pointed to by t, + * clearing and setting it's stack pointer, provides sane defaults + * and sets the task as ready to run, and inserts it into the operating + * system scheduler. + * + * @param t The task to initialize + * @param name The name of the task to initialize + * @param func The task function to call + * @param arg The argument to pass to this task function + * @param prio The priority at which to run this task + * @param sanity_itvl The time at which this task should check in with the + * sanity task. OS_WAIT_FOREVER means never check in + * here. + * @param stack_bottom A pointer to the bottom of a task's stack + * @param stack_size The overall size of the task's stack. + * + * @return 0 on success, non-zero on failure. + */ +int +os_task_init(struct os_task *t, const char *name, os_task_func_t func, + void *arg, uint8_t prio, os_time_t sanity_itvl, + os_stack_t *stack_bottom, uint16_t stack_size) +{ + struct os_sanity_check *sc; + int rc; + struct os_task *task; + + memset(t, 0, sizeof(*t)); + + t->t_func = func; + t->t_arg = arg; + + t->t_taskid = os_task_next_id(); + t->t_prio = prio; + + t->t_state = OS_TASK_READY; + t->t_name = name; + t->t_next_wakeup = 0; + + rc = os_sanity_check_init(&t->t_sanity_check); + if (rc != OS_OK) { + goto err; + } + + if (sanity_itvl != OS_WAIT_FOREVER) { + sc = (struct os_sanity_check *) &t->t_sanity_check; + sc->sc_checkin_itvl = sanity_itvl; + + rc = os_sanity_check_register(sc); + if (rc != OS_OK) { + goto err; + } + } + + _clear_stack(stack_bottom, stack_size); + t->t_stacktop = &stack_bottom[stack_size]; + t->t_stacksize = stack_size; + t->t_stackptr = os_arch_task_stack_init(t, t->t_stacktop, + t->t_stacksize); + + STAILQ_FOREACH(task, &g_os_task_list, t_os_task_list) { + assert(t->t_prio != task->t_prio); + } + + /* insert this task into the task list */ + STAILQ_INSERT_TAIL(&g_os_task_list, t, t_os_task_list); + + /* insert this task into the scheduler list */ + rc = os_sched_insert(t); + if (rc != OS_OK) { + goto err; + } + + os_trace_task_info(t); + + return (0); +err: + return (rc); +} + +/* + * Removes specified task + * XXX + * NOTE: This interface is currently experimental and not ready for common use + */ +int +os_task_remove(struct os_task *t) +{ + struct os_task *current; + int rc; + os_sr_t sr; + + current = os_sched_get_current_task(); + /* + * Can't suspend yourself + */ + if (t->t_taskid == current->t_taskid) { + return OS_INVALID_PARM; + } + + /* + * If state is not READY or SLEEP, assume task has not been initialized + */ + if (t->t_state != OS_TASK_READY && t->t_state != OS_TASK_SLEEP) + { + return OS_NOT_STARTED; + } + + /* + * Disallow suspending tasks which are waiting on a lock + */ + if (t->t_flags & (OS_TASK_FLAG_SEM_WAIT | OS_TASK_FLAG_MUTEX_WAIT | + OS_TASK_FLAG_EVQ_WAIT)) { + return OS_EBUSY; + } + + /* + * Disallowing suspending tasks which are holding a mutex + */ + if (t->t_lockcnt) { + return OS_EBUSY; + } + + OS_ENTER_CRITICAL(sr); + rc = os_sched_remove(t); + OS_EXIT_CRITICAL(sr); + return rc; +} + +/** + * Iterate through tasks, and return the following information about them: + * + * - Priority + * - Task ID + * - State (ACTIVE, SLEEP) + * - Total Stack Usage + * - Stack Size + * - Context Switch Count + * - Runtime + * - Last & Next Sanity checkin + * - Task Name + * + * To get the first task in the list, call os_task_info_get_next() with a + * NULL pointer in the prev argument, and os_task_info_get_next() will + * return a pointer to the task structure, and fill out the os_task_info + * structure pointed to by oti. + * + * To get the next task in the list, provide the task structure returned + * by the previous call to os_task_info_get_next(), and os_task_info_get_next() + * will fill out the task structure pointed to by oti again, and return + * the next task in the list. + * + * @param prev The previous task returned by os_task_info_get_next(), or NULL + * to begin iteration. + * @param oti The OS task info structure to fill out. + * + * @return A pointer to the OS task that has been read, or NULL when finished + * iterating through all tasks. + */ +struct os_task * +os_task_info_get_next(const struct os_task *prev, struct os_task_info *oti) +{ + struct os_task *next; + os_stack_t *top; + os_stack_t *bottom; + + if (prev != NULL) { + next = STAILQ_NEXT(prev, t_os_task_list); + } else { + next = STAILQ_FIRST(&g_os_task_list); + } + + if (next == NULL) { + return (NULL); + } + + /* Otherwise, copy OS task information into the OTI structure, and + * return 1, which means continue + */ + oti->oti_prio = next->t_prio; + oti->oti_taskid = next->t_taskid; + oti->oti_state = next->t_state; + + top = next->t_stacktop; + bottom = next->t_stacktop - next->t_stacksize; + while (bottom < top) { + if (*bottom != OS_STACK_PATTERN) { + break; + } + ++bottom; + } + + oti->oti_stkusage = (uint16_t) (next->t_stacktop - bottom); + oti->oti_stksize = next->t_stacksize; + oti->oti_cswcnt = next->t_ctx_sw_cnt; + oti->oti_runtime = next->t_run_time; + oti->oti_last_checkin = next->t_sanity_check.sc_checkin_last; + oti->oti_next_checkin = next->t_sanity_check.sc_checkin_last + + next->t_sanity_check.sc_checkin_itvl; + strncpy(oti->oti_name, next->t_name, sizeof(oti->oti_name)); + + return (next); +} + +/** + * @} OSTask + * @} OSKernel + */ diff --git a/porting/common/src/os/os_time.c b/porting/common/src/os/os_time.c new file mode 100644 index 000000000..3f6816de3 --- /dev/null +++ b/porting/common/src/os/os_time.c @@ -0,0 +1,268 @@ +/* + * 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 "syscfg/syscfg.h" + +#include + +#include "os/os.h" +#include "os/queue.h" + +/** + * @addtogroup OSKernel + * @{ + * @defgroup OSTime Time + * @{ + */ + +CTASSERT(sizeof(os_time_t) == 4); + +#define OS_USEC_PER_TICK (1000000 / OS_TICKS_PER_SEC) + +os_time_t g_os_time; + +/* + * Time-of-day collateral. + */ +static struct { + os_time_t ostime; + struct os_timeval uptime; + struct os_timeval utctime; + struct os_timezone timezone; +} basetod; + +static void +os_deltatime(os_time_t delta, const struct os_timeval *base, + struct os_timeval *result) +{ + struct os_timeval tvdelta; + + tvdelta.tv_sec = delta / OS_TICKS_PER_SEC; + tvdelta.tv_usec = (delta % OS_TICKS_PER_SEC) * OS_USEC_PER_TICK; + os_timeradd(base, &tvdelta, result); +} + +/** + * Get the current OS time in ticks + * + * @return OS time in ticks + */ +os_time_t +os_time_get(void) +{ + return (g_os_time); +} + +#if MYNEWT_VAL(OS_SCHEDULING) +static void +os_time_tick(int ticks) +{ + os_sr_t sr; + os_time_t delta, prev_os_time; + + assert(ticks >= 0); + + OS_ENTER_CRITICAL(sr); + prev_os_time = g_os_time; + g_os_time += ticks; + + /* + * Update 'basetod' when 'g_os_time' crosses the 0x00000000 and + * 0x80000000 thresholds. + */ + if ((prev_os_time ^ g_os_time) >> 31) { + delta = g_os_time - basetod.ostime; + os_deltatime(delta, &basetod.uptime, &basetod.uptime); + os_deltatime(delta, &basetod.utctime, &basetod.utctime); + basetod.ostime = g_os_time; + } + OS_EXIT_CRITICAL(sr); +} + +/** + * Move OS time forward ticks. + * + * @param ticks The number of ticks to move time forward. + */ +void +os_time_advance(int ticks) +{ + assert(ticks >= 0); + + if (ticks > 0) { + if (!os_started()) { + g_os_time += ticks; + } else { + os_time_tick(ticks); + os_callout_tick(); + os_sched_os_timer_exp(); + os_sched(NULL); + } + } +} +#else +void +os_time_advance(int ticks) +{ + g_os_time += ticks; +} +#endif + +/** + * Puts the current task to sleep for the specified number of os ticks. There + * is no delay if ticks is <= 0. + * + * @param osticks Number of ticks to delay (<= 0 means no delay). + */ +void +os_time_delay(int32_t osticks) +{ + os_sr_t sr; + + if (osticks > 0) { + OS_ENTER_CRITICAL(sr); + os_sched_sleep(os_sched_get_current_task(), (os_time_t)osticks); + OS_EXIT_CRITICAL(sr); + os_sched(NULL); + } +} + +/** + * Set the time of day. This does not modify os time, but rather just modifies + * the offset by which we are tracking real time against os time. + * + * @param utctime A timeval representing the UTC time we are setting + * @param tz The time-zone to apply against the utctime being set. + * + * @return 0 on success, non-zero on failure. + */ +int +os_settimeofday(struct os_timeval *utctime, struct os_timezone *tz) +{ + os_sr_t sr; + os_time_t delta; + + OS_ENTER_CRITICAL(sr); + if (utctime != NULL) { + /* + * Update all time-of-day base values. + */ + delta = os_time_get() - basetod.ostime; + os_deltatime(delta, &basetod.uptime, &basetod.uptime); + basetod.utctime = *utctime; + basetod.ostime += delta; + } + + if (tz != NULL) { + basetod.timezone = *tz; + } + OS_EXIT_CRITICAL(sr); + + return (0); +} + +/** + * Get the current time of day. Returns the time of day in UTC + * into the tv argument, and returns the timezone (if set) into + * tz. + * + * @param tv The structure to put the UTC time of day into + * @param tz The structure to put the timezone information into + * + * @return 0 on success, non-zero on failure + */ +int +os_gettimeofday(struct os_timeval *tv, struct os_timezone *tz) +{ + os_sr_t sr; + os_time_t delta; + + OS_ENTER_CRITICAL(sr); + if (tv != NULL) { + delta = os_time_get() - basetod.ostime; + os_deltatime(delta, &basetod.utctime, tv); + } + + if (tz != NULL) { + *tz = basetod.timezone; + } + OS_EXIT_CRITICAL(sr); + + return (0); +} + +/** + * Get time since boot in microseconds. + * + * @return time since boot in microseconds + */ +int64_t +os_get_uptime_usec(void) +{ + struct os_timeval tv; + os_time_t delta; + os_sr_t sr; + os_time_t ostime; + + + OS_ENTER_CRITICAL(sr); + tv = basetod.uptime; + ostime = basetod.ostime; + delta = os_time_get() - ostime; + OS_EXIT_CRITICAL(sr); + + os_deltatime(delta, &tv, &tv); + + return(tv.tv_sec * 1000000 + tv.tv_usec); +} + +/** + * Converts milliseconds to OS ticks. + * + * @param ms The milliseconds input. + * @param out_ticks The OS ticks output. + * + * @return 0 on success; OS_EINVAL if the result is too + * large to fit in a uint32_t. + */ +int +os_time_ms_to_ticks(uint32_t ms, uint32_t *out_ticks) +{ + uint64_t ticks; + +#if OS_TICKS_PER_SEC == 1000 + *out_ticks = ms; + return 0; +#endif + + _Static_assert(OS_TICKS_PER_SEC <= UINT32_MAX, + "OS_TICKS_PER_SEC must be <= UINT32_MAX"); + + ticks = (uint64_t)ms * OS_TICKS_PER_SEC / 1000; + if (ticks > UINT32_MAX) { + return OS_EINVAL; + } + + *out_ticks = ticks; + return 0; +} + +/** + * @} OSKernel + * @} OSTime + */ diff --git a/porting/common/src/sysinit/sysinit.c b/porting/common/src/sysinit/sysinit.c new file mode 100644 index 000000000..393d1c54c --- /dev/null +++ b/porting/common/src/sysinit/sysinit.c @@ -0,0 +1,64 @@ +/* + * 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 +#include +#include +#include "os/os_fault.h" +#include "syscfg/syscfg.h" +#include "sysinit/sysinit.h" + +static void +sysinit_dflt_panic_cb(const char *file, int line, const char *func, + const char *expr, const char *msg) +{ +#if MYNEWT_VAL(SYSINIT_PANIC_MESSAGE) + if (msg != NULL) { + fprintf(stderr, "sysinit failure: %s\n", msg); + } +#endif + + __assert_func(file, line, func, expr); +} + +sysinit_panic_fn *sysinit_panic_cb = sysinit_dflt_panic_cb; + +uint8_t sysinit_active; + +/** + * Sets the sysinit panic function; i.e., the function which executes when + * initialization fails. By default, a panic triggers a failed assertion. + */ +void +sysinit_panic_set(sysinit_panic_fn *panic_cb) +{ + sysinit_panic_cb = panic_cb; +} + +void +sysinit_start(void) +{ + sysinit_active = 1; +} + +void +sysinit_end(void) +{ + sysinit_active = 0; +} diff --git a/porting/freertos_nrf5_sdk/Makefile b/porting/freertos_nrf5_sdk/Makefile new file mode 100644 index 000000000..fb2818b1e --- /dev/null +++ b/porting/freertos_nrf5_sdk/Makefile @@ -0,0 +1,257 @@ +PROJECT_NAME := nimble_FreeRTOS_pca10040 +TARGETS := nrf52832_xxaa +OUTPUT_DIRECTORY := _build + +NRF5_SDK_ROOT ?= ./nrf5_sdk +PROJ_ROOT := ../.. + +$(OUTPUT_DIRECTORY)/nrf52832_xxaa.out: \ + LINKER_SCRIPT := nimble_FreeRTOS_gcc_nrf52.ld + +# Source files common to all targets +SRC_FILES += \ + $(NRF5_SDK_ROOT)/components/libraries/log/src/nrf_log_backend_serial.c \ + $(NRF5_SDK_ROOT)/components/libraries/log/src/nrf_log_frontend.c \ + $(NRF5_SDK_ROOT)/components/libraries/button/app_button.c \ + $(NRF5_SDK_ROOT)/components/libraries/util/app_error.c \ + $(NRF5_SDK_ROOT)/components/libraries/util/app_error_weak.c \ + $(NRF5_SDK_ROOT)/components/libraries/timer/app_timer_freertos.c \ + $(NRF5_SDK_ROOT)/components/libraries/util/app_util_platform.c \ + $(NRF5_SDK_ROOT)/components/libraries/util/nrf_assert.c \ + $(NRF5_SDK_ROOT)/components/libraries/util/sdk_errors.c \ + $(NRF5_SDK_ROOT)/external/freertos/source/croutine.c \ + $(NRF5_SDK_ROOT)/external/freertos/source/event_groups.c \ + $(NRF5_SDK_ROOT)/external/freertos/source/portable/MemMang/heap_1.c \ + $(NRF5_SDK_ROOT)/external/freertos/source/list.c \ + $(NRF5_SDK_ROOT)/external/freertos/portable/GCC/nrf52/port.c \ + $(NRF5_SDK_ROOT)/external/freertos/portable/CMSIS/nrf52/port_cmsis.c \ + $(NRF5_SDK_ROOT)/external/freertos/portable/CMSIS/nrf52/port_cmsis_systick.c \ + $(NRF5_SDK_ROOT)/external/freertos/source/queue.c \ + $(NRF5_SDK_ROOT)/external/freertos/source/tasks.c \ + $(NRF5_SDK_ROOT)/external/freertos/source/timers.c \ + $(NRF5_SDK_ROOT)/components/boards/boards.c \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/clock/nrf_drv_clock.c \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/common/nrf_drv_common.c \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/gpiote/nrf_drv_gpiote.c \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/uart/nrf_drv_uart.c \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c \ + $(NRF5_SDK_ROOT)/components/libraries/bsp/bsp.c \ + $(NRF5_SDK_ROOT)/components/libraries/bsp/bsp_nfc.c \ + $(NRF5_SDK_ROOT)/external/segger_rtt/RTT_Syscalls_GCC.c \ + $(NRF5_SDK_ROOT)/external/segger_rtt/SEGGER_RTT.c \ + $(NRF5_SDK_ROOT)/external/segger_rtt/SEGGER_RTT_printf.c \ + $(NRF5_SDK_ROOT)/components/toolchain/gcc/gcc_startup_nrf52.S \ + $(NRF5_SDK_ROOT)/components/toolchain/system_nrf52.c \ + ./src/main.c \ + ./src/ble_task.c \ + ./src/os_port.c \ + ./src/cmsis_nvic.c \ + ./src/hal_timer.c \ + $(PROJ_ROOT)/porting/common/src/nimble_port.c \ + $(PROJ_ROOT)/porting/common/src/mem/mem.c \ + $(PROJ_ROOT)/porting/common/src/os/endian.c \ + $(PROJ_ROOT)/porting/common/src/os/os_cputime.c \ + $(PROJ_ROOT)/porting/common/src/os/os_cputime_pwr2.c \ + $(PROJ_ROOT)/porting/common/src/os/os_mbuf.c \ + $(PROJ_ROOT)/porting/common/src/os/os_mempool.c \ + $(PROJ_ROOT)/porting/common/src/os/os_msys_init.c \ + $(PROJ_ROOT)/porting/common/src/sysinit/sysinit.c \ + $(PROJ_ROOT)/nimble/src/ble_util.c \ + $(PROJ_ROOT)/nimble/src/hci_common.c \ + $(PROJ_ROOT)/nimble/host/src/ble_att_clt.c \ + $(PROJ_ROOT)/nimble/host/src/ble_att_cmd.c \ + $(PROJ_ROOT)/nimble/host/src/ble_att.c \ + $(PROJ_ROOT)/nimble/host/src/ble_att_svr.c \ + $(PROJ_ROOT)/nimble/host/src/ble_eddystone.c \ + $(PROJ_ROOT)/nimble/host/src/ble_gap.c \ + $(PROJ_ROOT)/nimble/host/src/ble_gattc.c \ + $(PROJ_ROOT)/nimble/host/src/ble_gatts_lcl.c \ + $(PROJ_ROOT)/nimble/host/src/ble_gatts.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_adv.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_atomic.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_cfg.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_conn.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_dbg.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_hci_cmd.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_hci_evt.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_hci.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_hci_util.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_id.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_log.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_mbuf.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_misc.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_pvcy.c \ + $(PROJ_ROOT)/nimble/host/src/ble_hs_startup.c \ + $(PROJ_ROOT)/nimble/host/src/ble_ibeacon.c \ + $(PROJ_ROOT)/nimble/host/src/ble_l2cap_coc.c \ + $(PROJ_ROOT)/nimble/host/src/ble_l2cap.c \ + $(PROJ_ROOT)/nimble/host/src/ble_l2cap_sig_cmd.c \ + $(PROJ_ROOT)/nimble/host/src/ble_l2cap_sig.c \ + $(PROJ_ROOT)/nimble/host/src/ble_monitor.c \ + $(PROJ_ROOT)/nimble/host/src/ble_sm_alg.c \ + $(PROJ_ROOT)/nimble/host/src/ble_sm_cmd.c \ + $(PROJ_ROOT)/nimble/host/src/ble_sm_lgcy.c \ + $(PROJ_ROOT)/nimble/host/src/ble_sm.c \ + $(PROJ_ROOT)/nimble/host/src/ble_sm_sc.c \ + $(PROJ_ROOT)/nimble/host/src/ble_store.c \ + $(PROJ_ROOT)/nimble/host/src/ble_store_util.c \ + $(PROJ_ROOT)/nimble/host/src/ble_uuid.c \ + $(PROJ_ROOT)/nimble/host/src/ble_uuid.c \ + $(PROJ_ROOT)/nimble/host/services/ans/src/ble_svc_ans.c \ + $(PROJ_ROOT)/nimble/host/services/gap/src/ble_svc_gap.c \ + $(PROJ_ROOT)/nimble/host/services/gatt/src/ble_svc_gatt.c \ + $(PROJ_ROOT)/nimble/host/services/ias/src/ble_svc_ias.c \ + $(PROJ_ROOT)/nimble/host/services/lls/src/ble_svc_lls.c \ + $(PROJ_ROOT)/nimble/host/services/tps/src/ble_svc_tps.c \ + $(PROJ_ROOT)/nimble/host/store/ram/src/ble_store_ram.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_sched.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_xcvr.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_whitelist.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_ctrl.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_hci.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_supp_cmd.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_adv.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_conn.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_resolv.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_conn_hci.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_rand.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_scan.c \ + $(PROJ_ROOT)/nimble/controller/src/ble_ll_hci_ev.c \ + $(PROJ_ROOT)/nimble/transport/ram/src/ble_hci_ram.c \ + $(PROJ_ROOT)/nimble/drivers/nrf52/src/ble_hw.c \ + $(PROJ_ROOT)/nimble/drivers/nrf52/src/ble_phy.c \ + $(PROJ_ROOT)/tinycrypt/src/aes_decrypt.c \ + $(PROJ_ROOT)/tinycrypt/src/aes_encrypt.c \ + $(PROJ_ROOT)/tinycrypt/src/cmac_mode.c \ + $(PROJ_ROOT)/tinycrypt/src/ecc.c \ + $(PROJ_ROOT)/tinycrypt/src/ecc_dh.c \ + $(PROJ_ROOT)/tinycrypt/src/utils.c \ + +# Include folders common to all targets +INC_FOLDERS += \ + ./config \ + $(NRF5_SDK_ROOT)/components \ + $(NRF5_SDK_ROOT)/components/toolchain/cmsis/include \ + $(NRF5_SDK_ROOT)/external/freertos/source/include \ + $(NRF5_SDK_ROOT)/external/freertos/config \ + $(NRF5_SDK_ROOT)/components/libraries/util \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/uart \ + $(NRF5_SDK_ROOT)/components/libraries/bsp \ + $(NRF5_SDK_ROOT)/components/device \ + $(NRF5_SDK_ROOT)/components/libraries/log \ + $(NRF5_SDK_ROOT)/components/libraries/button \ + $(NRF5_SDK_ROOT)/components/libraries/timer \ + $(NRF5_SDK_ROOT)/external/freertos/portable/CMSIS/nrf52 \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/gpiote \ + $(NRF5_SDK_ROOT)/external/segger_rtt \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd \ + $(NRF5_SDK_ROOT)/components/boards \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/hal \ + $(NRF5_SDK_ROOT)/components/toolchain/gcc \ + $(NRF5_SDK_ROOT)/components/toolchain \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/common \ + $(NRF5_SDK_ROOT)/components/drivers_nrf/clock \ + $(NRF5_SDK_ROOT)/external/freertos/portable/GCC/nrf52 \ + $(NRF5_SDK_ROOT)/components/libraries/log/src \ + ./include \ + $(PROJ_ROOT)/porting/common/include \ + $(PROJ_ROOT)/nimble/include \ + $(PROJ_ROOT)/nimble/host/include \ + $(PROJ_ROOT)/nimble/host/mesh/include \ + $(PROJ_ROOT)/nimble/host/services/ans/include \ + $(PROJ_ROOT)/nimble/host/services/gap/include \ + $(PROJ_ROOT)/nimble/host/services/gatt/include \ + $(PROJ_ROOT)/nimble/host/services/ias/include \ + $(PROJ_ROOT)/nimble/host/services/lls/include \ + $(PROJ_ROOT)/nimble/host/services/tps/include \ + $(PROJ_ROOT)/nimble/host/store/ram/include \ + $(PROJ_ROOT)/nimble/controller/include \ + $(PROJ_ROOT)/nimble/transport/ram/include \ + $(PROJ_ROOT)/nimble/drivers/nrf52/include \ + $(PROJ_ROOT)/tinycrypt/include \ + +# Libraries common to all targets +LIB_FILES += \ + +# C flags common to all targets +CFLAGS += -DNRF52_PAN_12 +CFLAGS += -DNRF52_PAN_15 +CFLAGS += -DNRF52_PAN_58 +CFLAGS += -DFREERTOS +CFLAGS += -DNRF52_PAN_20 +CFLAGS += -DNRF52_PAN_54 +CFLAGS += -DNRF52 +CFLAGS += -DNRF52_PAN_51 +CFLAGS += -DNRF52_PAN_36 +CFLAGS += -DCONFIG_GPIO_AS_PINRESET +CFLAGS += -DNRF52_PAN_64 +CFLAGS += -DNRF52_PAN_55 +CFLAGS += -DBOARD_PCA10040 +CFLAGS += -DNRF52_PAN_31 +CFLAGS += -DNRF52832 +CFLAGS += -mcpu=cortex-m4 +CFLAGS += -mthumb -mabi=aapcs +CFLAGS += -Wall -Werror -Og -g3 +CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 +# keep every function in separate section, this allows linker to discard unused ones +CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing +CFLAGS += -fno-builtin --short-enums + +# C++ flags common to all targets +CXXFLAGS += \ + +# Assembler flags common to all targets +ASMFLAGS += -x assembler-with-cpp +ASMFLAGS += -DNRF52_PAN_12 +ASMFLAGS += -DNRF52_PAN_15 +ASMFLAGS += -DNRF52_PAN_58 +ASMFLAGS += -DFREERTOS +ASMFLAGS += -DNRF52_PAN_20 +ASMFLAGS += -DNRF52_PAN_54 +ASMFLAGS += -DNRF52 +ASMFLAGS += -DNRF52_PAN_51 +ASMFLAGS += -DNRF52_PAN_36 +ASMFLAGS += -DCONFIG_GPIO_AS_PINRESET +ASMFLAGS += -DNRF52_PAN_64 +ASMFLAGS += -DNRF52_PAN_55 +ASMFLAGS += -DBOARD_PCA10040 +ASMFLAGS += -DNRF52_PAN_31 +ASMFLAGS += -DNRF52832 + +# Linker flags +LDFLAGS += -mthumb -mabi=aapcs -L $(TEMPLATE_PATH) -T$(LINKER_SCRIPT) +LDFLAGS += -mcpu=cortex-m4 +LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 +# let linker to dump unused sections +LDFLAGS += -Wl,--gc-sections +# use newlib in nano version +LDFLAGS += --specs=nano.specs -lc -lnosys + + +.PHONY: $(TARGETS) default all clean help flash + +# Default target - first one defined +default: nrf52832_xxaa + +# Print all targets that can be built +help: + @echo following targets are available: + @echo nrf52832_xxaa + +TEMPLATE_PATH := $(NRF5_SDK_ROOT)/components/toolchain/gcc + +include $(TEMPLATE_PATH)/Makefile.common + +$(foreach target, $(TARGETS), $(call define_target, $(target))) + +# Flash the program +flash: $(OUTPUT_DIRECTORY)/nrf52832_xxaa.hex + @echo Flashing: $< + nrfjprog --program $< -f nrf52 --sectorerase + nrfjprog --reset -f nrf52 + +erase: + nrfjprog --eraseall -f nrf52 diff --git a/porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h b/porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h new file mode 100644 index 000000000..7569484b0 --- /dev/null +++ b/porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h @@ -0,0 +1,229 @@ +/* + FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that has become a de facto standard. * + * * + * Help yourself get started quickly and support the FreeRTOS * + * project by purchasing a FreeRTOS tutorial book, reference * + * manual, or both from: http://www.FreeRTOS.org/Documentation * + * * + * Thank you! * + * * + *************************************************************************** + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. + + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + + FreeRTOS 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. Full license text is available from the following + link: http://www.freertos.org/a00114.html + + 1 tab == 4 spaces! + + *************************************************************************** + * * + * Having a problem? Start by reading the FAQ "My application does * + * not run, what could be wrong?" * + * * + * http://www.FreeRTOS.org/FAQHelp.html * + * * + *************************************************************************** + + http://www.FreeRTOS.org - Documentation, books, training, latest versions, + license and Real Time Engineers Ltd. contact details. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High + Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#ifdef SOFTDEVICE_PRESENT +#include "nrf_soc.h" +#endif + +/*----------------------------------------------------------- + * Possible configurations for system timer + */ +#define FREERTOS_USE_RTC 0 /**< Use real time clock for the system */ +#define FREERTOS_USE_SYSTICK 1 /**< Use SysTick timer for system */ + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +#define configTICK_SOURCE FREERTOS_USE_RTC + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configUSE_TICKLESS_IDLE 1 +#define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG 1 /* See into vPortSuppressTicksAndSleep source code for explanation */ +#define configCPU_CLOCK_HZ ( SystemCoreClock ) +#define configTICK_RATE_HZ 1000 +#define configMAX_PRIORITIES ( 3 ) +#define configMINIMAL_STACK_SIZE ( 60 ) +#define configTOTAL_HEAP_SIZE ( 6144 ) +#define configMAX_TASK_NAME_LEN ( 4 ) +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 2 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Software timer definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( 2 ) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH ( 80 ) + +/* Tickless Idle configuration. */ +#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2 + +/* Tickless idle/low power functionality. */ + + +/* Define to trap errors during development. */ +#if defined(DEBUG_NRF) || defined(DEBUG_NRF_USER) +#define configASSERT( x ) ASSERT(x) +#endif + +/* FreeRTOS MPU specific definitions. */ +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 1 + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xResumeFromISR 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 +#define INCLUDE_pcTaskGetTaskName 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1 + +/* Interrupt priorities used by the kernel port layer itself. These are generic +to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY configLIBRARY_LOWEST_INTERRUPT_PRIORITY +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names - or at least those used in the unmodified vector table. */ + +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler + + +/*----------------------------------------------------------- + * Settings that are generated automatically + * basing on the settings above + */ +#if (configTICK_SOURCE == FREERTOS_USE_SYSTICK) + // do not define configSYSTICK_CLOCK_HZ for SysTick to be configured automatically + // to CPU clock source + #define xPortSysTickHandler SysTick_Handler +#elif (configTICK_SOURCE == FREERTOS_USE_RTC) + #define configSYSTICK_CLOCK_HZ ( 32768UL ) + #define xPortSysTickHandler RTC1_IRQHandler +#else + #error Unsupported configTICK_SOURCE value +#endif + +/* Code below should be only used by the compiler, and not the assembler. */ +#if !(defined(__ASSEMBLY__) || defined(__ASSEMBLER__)) + #include "nrf.h" + #include "nrf_assert.h" + + /* This part of definitions may be problematic in assembly - it uses definitions from files that are not assembly compatible. */ + /* Cortex-M specific definitions. */ + #ifdef __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS + #else + #error "This port requires __NVIC_PRIO_BITS to be defined" + #endif + + /* Access to current system core clock is required only if we are ticking the system by systimer */ + #if (configTICK_SOURCE == FREERTOS_USE_SYSTICK) + #include + extern uint32_t SystemCoreClock; + #endif +#endif /* !assembler */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/porting/freertos_nrf5_sdk/config/sdk_config.h b/porting/freertos_nrf5_sdk/config/sdk_config.h new file mode 100644 index 000000000..b05fd3fe0 --- /dev/null +++ b/porting/freertos_nrf5_sdk/config/sdk_config.h @@ -0,0 +1,699 @@ + + +#ifndef SDK_CONFIG_H +#define SDK_CONFIG_H +// <<< Use Configuration Wizard in Context Menu >>>\n +#ifdef USE_APP_CONFIG +#include "app_config.h" +#endif +// nRF_Drivers + +//========================================================== +// CLOCK_ENABLED - nrf_drv_clock - CLOCK peripheral driver +//========================================================== +#ifndef CLOCK_ENABLED +#define CLOCK_ENABLED 1 +#endif +#if CLOCK_ENABLED +// CLOCK_CONFIG_XTAL_FREQ - HF XTAL Frequency + +// <0=> Default (64 MHz) + +#ifndef CLOCK_CONFIG_XTAL_FREQ +#define CLOCK_CONFIG_XTAL_FREQ 0 +#endif + +// CLOCK_CONFIG_LF_SRC - LF Clock Source + +// <0=> RC +// <1=> XTAL +// <2=> Synth + +#ifndef CLOCK_CONFIG_LF_SRC +#define CLOCK_CONFIG_LF_SRC 1 +#endif + +// CLOCK_CONFIG_IRQ_PRIORITY - Interrupt priority + + +// Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef CLOCK_CONFIG_IRQ_PRIORITY +#define CLOCK_CONFIG_IRQ_PRIORITY 7 +#endif + +// CLOCK_CONFIG_LOG_ENABLED - Enables logging in the module. +//========================================================== +#ifndef CLOCK_CONFIG_LOG_ENABLED +#define CLOCK_CONFIG_LOG_ENABLED 0 +#endif +#if CLOCK_CONFIG_LOG_ENABLED +// CLOCK_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef CLOCK_CONFIG_LOG_LEVEL +#define CLOCK_CONFIG_LOG_LEVEL 3 +#endif + +// CLOCK_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef CLOCK_CONFIG_INFO_COLOR +#define CLOCK_CONFIG_INFO_COLOR 0 +#endif + +// CLOCK_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef CLOCK_CONFIG_DEBUG_COLOR +#define CLOCK_CONFIG_DEBUG_COLOR 0 +#endif + +#endif //CLOCK_CONFIG_LOG_ENABLED +// + +#endif //CLOCK_ENABLED +// + +// GPIOTE_ENABLED - nrf_drv_gpiote - GPIOTE peripheral driver +//========================================================== +#ifndef GPIOTE_ENABLED +#define GPIOTE_ENABLED 1 +#endif +#if GPIOTE_ENABLED +// GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - Number of lower power input pins +#ifndef GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS +#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 4 +#endif + +// GPIOTE_CONFIG_IRQ_PRIORITY - Interrupt priority + + +// Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef GPIOTE_CONFIG_IRQ_PRIORITY +#define GPIOTE_CONFIG_IRQ_PRIORITY 7 +#endif + +// GPIOTE_CONFIG_LOG_ENABLED - Enables logging in the module. +//========================================================== +#ifndef GPIOTE_CONFIG_LOG_ENABLED +#define GPIOTE_CONFIG_LOG_ENABLED 0 +#endif +#if GPIOTE_CONFIG_LOG_ENABLED +// GPIOTE_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef GPIOTE_CONFIG_LOG_LEVEL +#define GPIOTE_CONFIG_LOG_LEVEL 3 +#endif + +// GPIOTE_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef GPIOTE_CONFIG_INFO_COLOR +#define GPIOTE_CONFIG_INFO_COLOR 0 +#endif + +// GPIOTE_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef GPIOTE_CONFIG_DEBUG_COLOR +#define GPIOTE_CONFIG_DEBUG_COLOR 0 +#endif + +#endif //GPIOTE_CONFIG_LOG_ENABLED +// + +#endif //GPIOTE_ENABLED +// + +// PERIPHERAL_RESOURCE_SHARING_ENABLED - nrf_drv_common - Peripheral drivers common module +//========================================================== +#ifndef PERIPHERAL_RESOURCE_SHARING_ENABLED +#define PERIPHERAL_RESOURCE_SHARING_ENABLED 0 +#endif +#if PERIPHERAL_RESOURCE_SHARING_ENABLED +// COMMON_CONFIG_LOG_ENABLED - Enables logging in the module. +//========================================================== +#ifndef COMMON_CONFIG_LOG_ENABLED +#define COMMON_CONFIG_LOG_ENABLED 0 +#endif +#if COMMON_CONFIG_LOG_ENABLED +// COMMON_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef COMMON_CONFIG_LOG_LEVEL +#define COMMON_CONFIG_LOG_LEVEL 3 +#endif + +// COMMON_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef COMMON_CONFIG_INFO_COLOR +#define COMMON_CONFIG_INFO_COLOR 0 +#endif + +// COMMON_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef COMMON_CONFIG_DEBUG_COLOR +#define COMMON_CONFIG_DEBUG_COLOR 0 +#endif + +#endif //COMMON_CONFIG_LOG_ENABLED +// + +#endif //PERIPHERAL_RESOURCE_SHARING_ENABLED +// + +// UART_ENABLED - nrf_drv_uart - UART/UARTE peripheral driver +//========================================================== +#ifndef UART_ENABLED +#define UART_ENABLED 1 +#endif +#if UART_ENABLED +// UART_DEFAULT_CONFIG_HWFC - Hardware Flow Control + +// <0=> Disabled +// <1=> Enabled + +#ifndef UART_DEFAULT_CONFIG_HWFC +#define UART_DEFAULT_CONFIG_HWFC 0 +#endif + +// UART_DEFAULT_CONFIG_PARITY - Parity + +// <0=> Excluded +// <14=> Included + +#ifndef UART_DEFAULT_CONFIG_PARITY +#define UART_DEFAULT_CONFIG_PARITY 0 +#endif + +// UART_DEFAULT_CONFIG_BAUDRATE - Default Baudrate + +// <323584=> 1200 baud +// <643072=> 2400 baud +// <1290240=> 4800 baud +// <2576384=> 9600 baud +// <3862528=> 14400 baud +// <5152768=> 19200 baud +// <7716864=> 28800 baud +// <10289152=> 38400 baud +// <15400960=> 57600 baud +// <20615168=> 76800 baud +// <30801920=> 115200 baud +// <61865984=> 230400 baud +// <67108864=> 250000 baud +// <121634816=> 460800 baud +// <251658240=> 921600 baud +// <268435456=> 57600 baud + +#ifndef UART_DEFAULT_CONFIG_BAUDRATE +#define UART_DEFAULT_CONFIG_BAUDRATE 30801920 +#endif + +// UART_DEFAULT_CONFIG_IRQ_PRIORITY - Interrupt priority + + +// Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice +// <0=> 0 (highest) +// <1=> 1 +// <2=> 2 +// <3=> 3 +// <4=> 4 +// <5=> 5 +// <6=> 6 +// <7=> 7 + +#ifndef UART_DEFAULT_CONFIG_IRQ_PRIORITY +#define UART_DEFAULT_CONFIG_IRQ_PRIORITY 7 +#endif + +// UART_EASY_DMA_SUPPORT - Driver supporting EasyDMA + + +#ifndef UART_EASY_DMA_SUPPORT +#define UART_EASY_DMA_SUPPORT 1 +#endif + +// UART_LEGACY_SUPPORT - Driver supporting Legacy mode + + +#ifndef UART_LEGACY_SUPPORT +#define UART_LEGACY_SUPPORT 1 +#endif + +// UART0_ENABLED - Enable UART0 instance +//========================================================== +#ifndef UART0_ENABLED +#define UART0_ENABLED 1 +#endif +#if UART0_ENABLED +// UART0_CONFIG_USE_EASY_DMA - Default setting for using EasyDMA + + +#ifndef UART0_CONFIG_USE_EASY_DMA +#define UART0_CONFIG_USE_EASY_DMA 1 +#endif + +#endif //UART0_ENABLED +// + +// UART_CONFIG_LOG_ENABLED - Enables logging in the module. +//========================================================== +#ifndef UART_CONFIG_LOG_ENABLED +#define UART_CONFIG_LOG_ENABLED 0 +#endif +#if UART_CONFIG_LOG_ENABLED +// UART_CONFIG_LOG_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef UART_CONFIG_LOG_LEVEL +#define UART_CONFIG_LOG_LEVEL 3 +#endif + +// UART_CONFIG_INFO_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef UART_CONFIG_INFO_COLOR +#define UART_CONFIG_INFO_COLOR 0 +#endif + +// UART_CONFIG_DEBUG_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef UART_CONFIG_DEBUG_COLOR +#define UART_CONFIG_DEBUG_COLOR 0 +#endif + +#endif //UART_CONFIG_LOG_ENABLED +// + +#endif //UART_ENABLED +// + +// +//========================================================== + +// nRF_Libraries + +//========================================================== +// APP_TIMER_ENABLED - app_timer - Application timer functionality +//========================================================== +#ifndef APP_TIMER_ENABLED +#define APP_TIMER_ENABLED 1 +#endif +#if APP_TIMER_ENABLED +// APP_TIMER_WITH_PROFILER - Enable app_timer profiling + + +#ifndef APP_TIMER_WITH_PROFILER +#define APP_TIMER_WITH_PROFILER 0 +#endif + +// APP_TIMER_KEEPS_RTC_ACTIVE - Enable RTC always on + + +// If option is enabled RTC is kept running even if there is no active timers. +// This option can be used when app_timer is used for timestamping. + +#ifndef APP_TIMER_KEEPS_RTC_ACTIVE +#define APP_TIMER_KEEPS_RTC_ACTIVE 0 +#endif + +#endif //APP_TIMER_ENABLED +// + +// BUTTON_ENABLED - app_button - buttons handling module + + +#ifndef BUTTON_ENABLED +#define BUTTON_ENABLED 1 +#endif + +// +//========================================================== + +// nRF_Log + +//========================================================== +// NRF_LOG_ENABLED - nrf_log - Logging +//========================================================== +#ifndef NRF_LOG_ENABLED +#define NRF_LOG_ENABLED 0 +#endif +#if NRF_LOG_ENABLED +// NRF_LOG_USES_COLORS - If enabled then ANSI escape code for colors is prefixed to every string +//========================================================== +#ifndef NRF_LOG_USES_COLORS +#define NRF_LOG_USES_COLORS 0 +#endif +#if NRF_LOG_USES_COLORS +// NRF_LOG_COLOR_DEFAULT - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRF_LOG_COLOR_DEFAULT +#define NRF_LOG_COLOR_DEFAULT 0 +#endif + +// NRF_LOG_ERROR_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRF_LOG_ERROR_COLOR +#define NRF_LOG_ERROR_COLOR 0 +#endif + +// NRF_LOG_WARNING_COLOR - ANSI escape code prefix. + +// <0=> Default +// <1=> Black +// <2=> Red +// <3=> Green +// <4=> Yellow +// <5=> Blue +// <6=> Magenta +// <7=> Cyan +// <8=> White + +#ifndef NRF_LOG_WARNING_COLOR +#define NRF_LOG_WARNING_COLOR 0 +#endif + +#endif //NRF_LOG_USES_COLORS +// + +// NRF_LOG_DEFAULT_LEVEL - Default Severity level + +// <0=> Off +// <1=> Error +// <2=> Warning +// <3=> Info +// <4=> Debug + +#ifndef NRF_LOG_DEFAULT_LEVEL +#define NRF_LOG_DEFAULT_LEVEL 3 +#endif + +// NRF_LOG_DEFERRED - Enable deffered logger. + +// Log data is buffered and can be processed in idle. +//========================================================== +#ifndef NRF_LOG_DEFERRED +#define NRF_LOG_DEFERRED 1 +#endif +#if NRF_LOG_DEFERRED +// NRF_LOG_DEFERRED_BUFSIZE - Size of the buffer for logs in words. +// Must be power of 2 + +#ifndef NRF_LOG_DEFERRED_BUFSIZE +#define NRF_LOG_DEFERRED_BUFSIZE 256 +#endif + +#endif //NRF_LOG_DEFERRED +// + +// NRF_LOG_USES_TIMESTAMP - Enable timestamping + + +// Function for getting the timestamp is provided by the user + +#ifndef NRF_LOG_USES_TIMESTAMP +#define NRF_LOG_USES_TIMESTAMP 0 +#endif + +#endif //NRF_LOG_ENABLED +// + +// nrf_log_backend - Logging sink + +//========================================================== +// NRF_LOG_BACKEND_MAX_STRING_LENGTH - Buffer for storing single output string +// Logger backend RAM usage is determined by this value. + +#ifndef NRF_LOG_BACKEND_MAX_STRING_LENGTH +#define NRF_LOG_BACKEND_MAX_STRING_LENGTH 256 +#endif + +// NRF_LOG_TIMESTAMP_DIGITS - Number of digits for timestamp +// If higher resolution timestamp source is used it might be needed to increase that + +#ifndef NRF_LOG_TIMESTAMP_DIGITS +#define NRF_LOG_TIMESTAMP_DIGITS 8 +#endif + +// NRF_LOG_BACKEND_SERIAL_USES_UART - If enabled data is printed over UART +//========================================================== +#ifndef NRF_LOG_BACKEND_SERIAL_USES_UART +#define NRF_LOG_BACKEND_SERIAL_USES_UART 1 +#endif +#if NRF_LOG_BACKEND_SERIAL_USES_UART +// NRF_LOG_BACKEND_SERIAL_UART_BAUDRATE - Default Baudrate + +// <323584=> 1200 baud +// <643072=> 2400 baud +// <1290240=> 4800 baud +// <2576384=> 9600 baud +// <3862528=> 14400 baud +// <5152768=> 19200 baud +// <7716864=> 28800 baud +// <10289152=> 38400 baud +// <15400960=> 57600 baud +// <20615168=> 76800 baud +// <30801920=> 115200 baud +// <61865984=> 230400 baud +// <67108864=> 250000 baud +// <121634816=> 460800 baud +// <251658240=> 921600 baud +// <268435456=> 57600 baud + +#ifndef NRF_LOG_BACKEND_SERIAL_UART_BAUDRATE +#define NRF_LOG_BACKEND_SERIAL_UART_BAUDRATE 30801920 +#endif + +// NRF_LOG_BACKEND_SERIAL_UART_TX_PIN - UART TX pin +#ifndef NRF_LOG_BACKEND_SERIAL_UART_TX_PIN +#define NRF_LOG_BACKEND_SERIAL_UART_TX_PIN 6 +#endif + +// NRF_LOG_BACKEND_SERIAL_UART_RX_PIN - UART RX pin +#ifndef NRF_LOG_BACKEND_SERIAL_UART_RX_PIN +#define NRF_LOG_BACKEND_SERIAL_UART_RX_PIN 8 +#endif + +// NRF_LOG_BACKEND_SERIAL_UART_RTS_PIN - UART RTS pin +#ifndef NRF_LOG_BACKEND_SERIAL_UART_RTS_PIN +#define NRF_LOG_BACKEND_SERIAL_UART_RTS_PIN 5 +#endif + +// NRF_LOG_BACKEND_SERIAL_UART_CTS_PIN - UART CTS pin +#ifndef NRF_LOG_BACKEND_SERIAL_UART_CTS_PIN +#define NRF_LOG_BACKEND_SERIAL_UART_CTS_PIN 7 +#endif + +// NRF_LOG_BACKEND_SERIAL_UART_FLOW_CONTROL - Hardware Flow Control + +// <0=> Disabled +// <1=> Enabled + +#ifndef NRF_LOG_BACKEND_SERIAL_UART_FLOW_CONTROL +#define NRF_LOG_BACKEND_SERIAL_UART_FLOW_CONTROL 0 +#endif + +// NRF_LOG_BACKEND_UART_INSTANCE - UART instance used + +// <0=> 0 + +#ifndef NRF_LOG_BACKEND_UART_INSTANCE +#define NRF_LOG_BACKEND_UART_INSTANCE 0 +#endif + +#endif //NRF_LOG_BACKEND_SERIAL_USES_UART +// + +// NRF_LOG_BACKEND_SERIAL_USES_RTT - If enabled data is printed using RTT +//========================================================== +#ifndef NRF_LOG_BACKEND_SERIAL_USES_RTT +#define NRF_LOG_BACKEND_SERIAL_USES_RTT 0 +#endif +#if NRF_LOG_BACKEND_SERIAL_USES_RTT +// NRF_LOG_BACKEND_RTT_OUTPUT_BUFFER_SIZE - RTT output buffer size. +// Should be equal or bigger than \ref NRF_LOG_BACKEND_MAX_STRING_LENGTH. +// This value is used in Segger RTT configuration to set the buffer size +// if it is bigger than default RTT buffer size. + +#ifndef NRF_LOG_BACKEND_RTT_OUTPUT_BUFFER_SIZE +#define NRF_LOG_BACKEND_RTT_OUTPUT_BUFFER_SIZE 512 +#endif + +#endif //NRF_LOG_BACKEND_SERIAL_USES_RTT +// + +// +//========================================================== + +// +//========================================================== + +// nRF_Segger_RTT + +//========================================================== +// segger_rtt - SEGGER RTT + +//========================================================== +// SEGGER_RTT_CONFIG_BUFFER_SIZE_UP - Size of upstream buffer. +#ifndef SEGGER_RTT_CONFIG_BUFFER_SIZE_UP +#define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 64 +#endif + +// SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS - Size of upstream buffer. +#ifndef SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS +#define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 2 +#endif + +// SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN - Size of upstream buffer. +#ifndef SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN +#define SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN 16 +#endif + +// SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS - Size of upstream buffer. +#ifndef SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS +#define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 2 +#endif + +// +//========================================================== + +// +//========================================================== + +// <<< end of configuration section >>> +#endif //SDK_CONFIG_H + diff --git a/porting/freertos_nrf5_sdk/include/bsp/cmsis_nvic.h b/porting/freertos_nrf5_sdk/include/bsp/cmsis_nvic.h new file mode 100644 index 000000000..856f7d087 --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/bsp/cmsis_nvic.h @@ -0,0 +1,29 @@ +/* mbed Microcontroller Library - cmsis_nvic + * Copyright (c) 2009-2011 ARM Limited. All rights reserved. + * + * CMSIS-style functionality to support dynamic vectors + */ + +#ifndef MBED_CMSIS_NVIC_H +#define MBED_CMSIS_NVIC_H + +#include + +#define NVIC_NUM_VECTORS (16 + 38) // CORE + MCU Peripherals +#define NVIC_USER_IRQ_OFFSET 16 + +#include "nrf52.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void NVIC_Relocate(void); +void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector); +uint32_t NVIC_GetVector(IRQn_Type IRQn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/freertos_nrf5_sdk/include/mcu/nrf52_hal.h b/porting/freertos_nrf5_sdk/include/mcu/nrf52_hal.h new file mode 100755 index 000000000..26a43439e --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/mcu/nrf52_hal.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#ifndef H_NRF52_HAL_ +#define H_NRF52_HAL_ + +#ifdef __cplusplus + extern "C" { +#endif + +/* Helper functions to enable/disable interrupts. */ +#define __HAL_DISABLE_INTERRUPTS(x) \ + do { \ + x = __get_PRIMASK(); \ + __disable_irq(); \ + } while(0); + +#define __HAL_ENABLE_INTERRUPTS(x) \ + do { \ + if (!x) { \ + __enable_irq(); \ + } \ + } while(0); + +struct nrf52_uart_cfg { + int8_t suc_pin_tx; /* pins for IO */ + int8_t suc_pin_rx; + int8_t suc_pin_rts; + int8_t suc_pin_cts; +}; +const struct nrf52_uart_cfg *bsp_uart_config(void); + +struct nrf52_hal_i2c_cfg { + int scl_pin; + int sda_pin; + uint32_t i2c_frequency; +}; +struct hal_flash; +extern const struct hal_flash nrf52k_flash_dev; + +/* SPI configuration (used for both master and slave) */ +struct nrf52_hal_spi_cfg { + uint8_t sck_pin; + uint8_t mosi_pin; + uint8_t miso_pin; + uint8_t ss_pin; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* H_NRF52_HAL_ */ + diff --git a/porting/freertos_nrf5_sdk/include/os/os_arch.h b/porting/freertos_nrf5_sdk/include/os/os_arch.h new file mode 100755 index 000000000..21eb55197 --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/os/os_arch.h @@ -0,0 +1,25 @@ +#ifndef _OS_ARCH_H +#define _OS_ARCH_H + +#include +#include "FreeRTOS.h" +#include "FreeRTOSConfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int os_sr_t; +typedef int os_stack_t; + +#define OS_ALIGNMENT (4) +#define OS_TICKS_PER_SEC (configTICK_RATE_HZ) + +#define OS_ENTER_CRITICAL(unused) do { (void)unused; vPortEnterCritical(); } while (0) +#define OS_EXIT_CRITICAL(unused) do { (void)unused; vPortExitCritical(); } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_ARCH_H */ diff --git a/porting/freertos_nrf5_sdk/include/os/os_callout.h b/porting/freertos_nrf5_sdk/include/os/os_callout.h new file mode 100644 index 000000000..36ee3c1ff --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/os/os_callout.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + + +#ifndef _OS_CALLOUT_H +#define _OS_CALLOUT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os/os_eventq.h" +#include "FreeRTOS.h" +#include "timers.h" + +struct os_callout { + struct os_event c_ev; + struct os_eventq *c_evq; + uint32_t c_ticks; + TimerHandle_t c_timer; +}; + +void os_callout_init(struct os_callout *cf, struct os_eventq *evq, + os_event_fn *ev_cb, void *ev_arg); +int os_callout_reset(struct os_callout *, int32_t); +int os_callout_queued(struct os_callout *c); +void os_callout_stop(struct os_callout *c); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_CALLOUT_H */ + + + diff --git a/porting/freertos_nrf5_sdk/include/os/os_eventq.h b/porting/freertos_nrf5_sdk/include/os/os_eventq.h new file mode 100644 index 000000000..9770cdfe7 --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/os/os_eventq.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef _OS_EVENTQ_H +#define _OS_EVENTQ_H + +#include +#include "os/os_time.h" +#include "os/queue.h" +#include "FreeRTOS.h" +#include "queue.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_event; +typedef void os_event_fn(struct os_event *ev); + +struct os_event { + uint8_t ev_queued; + os_event_fn *ev_cb; + void *ev_arg; +}; + +#define OS_EVENT_QUEUED(__ev) ((__ev)->ev_queued) + +struct os_eventq { + QueueHandle_t q; +}; + +void os_eventq_init(struct os_eventq *); +int os_eventq_inited(const struct os_eventq *evq); +void os_eventq_put(struct os_eventq *, struct os_event *); +struct os_event *os_eventq_get_no_wait(struct os_eventq *evq); +struct os_event *os_eventq_get(struct os_eventq *); +void os_eventq_run(struct os_eventq *evq); +struct os_event *os_eventq_poll(struct os_eventq **, int, os_time_t); +void os_eventq_remove(struct os_eventq *, struct os_event *); +struct os_eventq *os_eventq_dflt_get(void); + +/* [DEPRECATED] */ +void os_eventq_designate(struct os_eventq **dst, struct os_eventq *val, + struct os_event *start_ev); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_EVENTQ_H */ + diff --git a/porting/freertos_nrf5_sdk/include/os/os_mutex.h b/porting/freertos_nrf5_sdk/include/os/os_mutex.h new file mode 100644 index 000000000..dc5319423 --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/os/os_mutex.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#ifndef _OS_MUTEX_H_ +#define _OS_MUTEX_H_ + +#include "os/os.h" +#include "FreeRTOS.h" +#include "semphr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct os_mutex +{ + SemaphoreHandle_t handle; +}; + +os_error_t os_mutex_init(struct os_mutex *mu); + +os_error_t os_mutex_release(struct os_mutex *mu); + +os_error_t os_mutex_pend(struct os_mutex *mu, uint32_t timeout); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_MUTEX_H_ */ diff --git a/porting/freertos_nrf5_sdk/include/os/os_sem.h b/porting/freertos_nrf5_sdk/include/os/os_sem.h new file mode 100644 index 000000000..224c8d4aa --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/os/os_sem.h @@ -0,0 +1,27 @@ +#ifndef _OS_SEM_H_ +#define _OS_SEM_H_ + +#include "os/os_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "FreeRTOS.h" +#include "semphr.h" + +struct os_sem +{ + SemaphoreHandle_t handle; +}; + +os_error_t os_sem_init(struct os_sem *sem, uint16_t tokens); +os_error_t os_sem_release(struct os_sem *sem); +os_error_t os_sem_pend(struct os_sem *sem, uint32_t timeout); +uint16_t os_sem_get_count(struct os_sem *sem); + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_SEM_H_ */ diff --git a/porting/freertos_nrf5_sdk/include/syscfg/syscfg.h b/porting/freertos_nrf5_sdk/include/syscfg/syscfg.h new file mode 100644 index 000000000..7f5f6be07 --- /dev/null +++ b/porting/freertos_nrf5_sdk/include/syscfg/syscfg.h @@ -0,0 +1,967 @@ +/** + * This file was generated by Apache Newt version: 1.2.0-dev + */ + +#ifndef H_MYNEWT_SYSCFG_ +#define H_MYNEWT_SYSCFG_ + +/** + * This macro exists to ensure code includes this header when needed. If code + * checks the existence of a setting directly via ifdef without including this + * header, the setting macro will silently evaluate to 0. In contrast, an + * attempt to use these macros without including this header will result in a + * compiler error. + */ +#define MYNEWT_VAL(x) MYNEWT_VAL_ ## x + + + +/*** compiler/arm-none-eabi-m4 */ +#ifndef MYNEWT_VAL_HARDFLOAT +#define MYNEWT_VAL_HARDFLOAT (0) +#endif + +/*** hw/bsp/nrf52840pdk */ +#ifndef MYNEWT_VAL_BSP_NRF52840 +#define MYNEWT_VAL_BSP_NRF52840 (1) +#endif + +#ifndef MYNEWT_VAL_TIMER_0 +#define MYNEWT_VAL_TIMER_0 (1) +#endif + +#ifndef MYNEWT_VAL_TIMER_1 +#define MYNEWT_VAL_TIMER_1 (0) +#endif + +#ifndef MYNEWT_VAL_TIMER_2 +#define MYNEWT_VAL_TIMER_2 (0) +#endif + +#ifndef MYNEWT_VAL_TIMER_3 +#define MYNEWT_VAL_TIMER_3 (0) +#endif + +#ifndef MYNEWT_VAL_TIMER_4 +#define MYNEWT_VAL_TIMER_4 (0) +#endif + +#ifndef MYNEWT_VAL_TIMER_5 +#define MYNEWT_VAL_TIMER_5 (1) +#endif + +#ifndef MYNEWT_VAL_UART_0 +#define MYNEWT_VAL_UART_0 (1) +#endif + +#ifndef MYNEWT_VAL_UART_0_PIN_CTS +#define MYNEWT_VAL_UART_0_PIN_CTS (7) +#endif + +#ifndef MYNEWT_VAL_UART_0_PIN_RTS +#define MYNEWT_VAL_UART_0_PIN_RTS (5) +#endif + +#ifndef MYNEWT_VAL_UART_0_PIN_RX +#define MYNEWT_VAL_UART_0_PIN_RX (8) +#endif + +#ifndef MYNEWT_VAL_UART_0_PIN_TX +#define MYNEWT_VAL_UART_0_PIN_TX (6) +#endif + +#ifndef MYNEWT_VAL_UART_1 +#define MYNEWT_VAL_UART_1 (0) +#endif + +#ifndef MYNEWT_VAL_UART_1_PIN_RX +#define MYNEWT_VAL_UART_1_PIN_RX (-1) +#endif + +#ifndef MYNEWT_VAL_UART_1_PIN_TX +#define MYNEWT_VAL_UART_1_PIN_TX (-1) +#endif + +/*** hw/drivers/nimble/nrf52 */ +#ifndef MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN +#define MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN +#define MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_DBG_TIME_TXRXEN_READY_PIN +#define MYNEWT_VAL_BLE_PHY_DBG_TIME_TXRXEN_READY_PIN (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_DBG_TIME_WFR_PIN +#define MYNEWT_VAL_BLE_PHY_DBG_TIME_WFR_PIN (-1) +#endif + +/*** hw/mcu/nordic/nrf52xxx */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_I2C_1 +#define MYNEWT_VAL_I2C_1 (0) +#endif + +/* Overridden by hw/bsp/nrf52840pdk (defined by hw/mcu/nordic/nrf52xxx) */ +#ifndef MYNEWT_VAL_MCU_DCDC_ENABLED +#define MYNEWT_VAL_MCU_DCDC_ENABLED (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_SPI_0_MASTER +#define MYNEWT_VAL_SPI_0_MASTER (0) +#endif + +#ifndef MYNEWT_VAL_SPI_0_SLAVE +#define MYNEWT_VAL_SPI_0_SLAVE (0) +#endif + +#ifndef MYNEWT_VAL_SPI_1_MASTER +#define MYNEWT_VAL_SPI_1_MASTER (0) +#endif + +#ifndef MYNEWT_VAL_SPI_1_SLAVE +#define MYNEWT_VAL_SPI_1_SLAVE (0) +#endif + +/* Overridden by hw/bsp/nrf52840pdk (defined by hw/mcu/nordic/nrf52xxx) */ +#ifndef MYNEWT_VAL_XTAL_32768 +#define MYNEWT_VAL_XTAL_32768 (1) +#endif + +#ifndef MYNEWT_VAL_XTAL_32768_SYNTH +#define MYNEWT_VAL_XTAL_32768_SYNTH (0) +#endif + +#ifndef MYNEWT_VAL_XTAL_RC +#define MYNEWT_VAL_XTAL_RC (0) +#endif + +/*** kernel/os */ +#ifndef MYNEWT_VAL_FLOAT_USER +#define MYNEWT_VAL_FLOAT_USER (0) +#endif + +#ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT +#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (12) +#endif + +#ifndef MYNEWT_VAL_MSYS_1_BLOCK_SIZE +#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292) +#endif + +#ifndef MYNEWT_VAL_MSYS_2_BLOCK_COUNT +#define MYNEWT_VAL_MSYS_2_BLOCK_COUNT (0) +#endif + +#ifndef MYNEWT_VAL_MSYS_2_BLOCK_SIZE +#define MYNEWT_VAL_MSYS_2_BLOCK_SIZE (0) +#endif + +#ifndef MYNEWT_VAL_OS_CLI +#define MYNEWT_VAL_OS_CLI (0) +#endif + +#ifndef MYNEWT_VAL_OS_COREDUMP +#define MYNEWT_VAL_OS_COREDUMP (0) +#endif + +/* Overridden by hw/bsp/nrf52840pdk (defined by kernel/os) */ +#ifndef MYNEWT_VAL_OS_CPUTIME_FREQ +#define MYNEWT_VAL_OS_CPUTIME_FREQ (32768) +#endif + +/* Overridden by hw/bsp/nrf52840pdk (defined by kernel/os) */ +#ifndef MYNEWT_VAL_OS_CPUTIME_TIMER_NUM +#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (5) +#endif + +#ifndef MYNEWT_VAL_OS_CTX_SW_STACK_CHECK +#define MYNEWT_VAL_OS_CTX_SW_STACK_CHECK (0) +#endif + +#ifndef MYNEWT_VAL_OS_CTX_SW_STACK_GUARD +#define MYNEWT_VAL_OS_CTX_SW_STACK_GUARD (4) +#endif + +#ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE +#define MYNEWT_VAL_OS_MAIN_STACK_SIZE (1024) +#endif + +#ifndef MYNEWT_VAL_OS_MAIN_TASK_PRIO +#define MYNEWT_VAL_OS_MAIN_TASK_PRIO (127) +#endif + +#ifndef MYNEWT_VAL_OS_MEMPOOL_CHECK +#define MYNEWT_VAL_OS_MEMPOOL_CHECK (0) +#endif + +#ifndef MYNEWT_VAL_OS_MEMPOOL_POISON +#define MYNEWT_VAL_OS_MEMPOOL_POISON (0) +#endif + +#ifndef MYNEWT_VAL_OS_SCHEDULING +#define MYNEWT_VAL_OS_SCHEDULING (1) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW +#define MYNEWT_VAL_OS_SYSVIEW (0) +#endif + +#ifndef MYNEWT_VAL_SANITY_INTERVAL +#define MYNEWT_VAL_SANITY_INTERVAL (15000) +#endif + +#ifndef MYNEWT_VAL_WATCHDOG_INTERVAL +#define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) +#endif + +/*** libc/baselibc */ +#ifndef MYNEWT_VAL_BASELIBC_ASSERT_FILE_LINE +#define MYNEWT_VAL_BASELIBC_ASSERT_FILE_LINE (0) +#endif + +#ifndef MYNEWT_VAL_BASELIBC_PRESENT +#define MYNEWT_VAL_BASELIBC_PRESENT (1) +#endif + +/*** net/nimble */ +#ifndef MYNEWT_VAL_BLE_EXT_ADV +#define MYNEWT_VAL_BLE_EXT_ADV (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE +#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) +#endif + +#ifndef MYNEWT_VAL_BLE_MAX_CONNECTIONS +#define MYNEWT_VAL_BLE_MAX_CONNECTIONS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES +#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER +#define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_CENTRAL +#define MYNEWT_VAL_BLE_ROLE_CENTRAL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_OBSERVER +#define MYNEWT_VAL_BLE_ROLE_OBSERVER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_PERIPHERAL +#define MYNEWT_VAL_BLE_ROLE_PERIPHERAL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_WHITELIST +#define MYNEWT_VAL_BLE_WHITELIST (1) +#endif + +/*** net/nimble/controller */ +#ifndef MYNEWT_VAL_BLE_DEVICE +#define MYNEWT_VAL_BLE_DEVICE (1) +#endif + +/* Overridden by net/nimble/controller (defined by net/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE +#define MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS +#define MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_EXT_SCAN_FILT +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_EXT_SCAN_FILT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY (0) +#endif + +/* Overridden by net/nimble/controller (defined by net/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING (MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV (MYNEWT_VAL_BLE_EXT_ADV) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES +#define MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES (27) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET +#define MYNEWT_VAL_BLE_LL_CONN_INIT_MIN_WIN_OFFSET (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS +#define MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS (4) +#endif + +/* Overridden by net/nimble/controller (defined by net/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT +#define MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT (5) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_MASTER_SCA +#define MYNEWT_VAL_BLE_LL_MASTER_SCA (4) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE +#define MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_MFRG_ID +#define MYNEWT_VAL_BLE_LL_MFRG_ID (0xFFFF) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS +#define MYNEWT_VAL_BLE_LL_NUM_SCAN_DUP_ADVS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS +#define MYNEWT_VAL_BLE_LL_NUM_SCAN_RSP_ADVS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_OUR_SCA +#define MYNEWT_VAL_BLE_LL_OUR_SCA (60) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_PRIO +#define MYNEWT_VAL_BLE_LL_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE +#define MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_RNG_BUFSIZE +#define MYNEWT_VAL_BLE_LL_RNG_BUFSIZE (32) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING +#define MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES +#define MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES +#define MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_TX_PWR_DBM +#define MYNEWT_VAL_BLE_LL_TX_PWR_DBM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD +#define MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD (3250) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_WHITELIST_SIZE +#define MYNEWT_VAL_BLE_LL_WHITELIST_SIZE (8) +#endif + +#ifndef MYNEWT_VAL_BLE_LP_CLOCK +#define MYNEWT_VAL_BLE_LP_CLOCK (1) +#endif + +#ifndef MYNEWT_VAL_BLE_NUM_COMP_PKT_RATE +#define MYNEWT_VAL_BLE_NUM_COMP_PKT_RATE (((2000 * OS_TICKS_PER_SEC) / 1000)) +#endif + +#ifndef MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR +#define MYNEWT_VAL_BLE_PUBLIC_DEV_ADDR ((uint8_t[6]){0xff, 0xaa, 0xff, 0xc0, 0xde, 0xc0}) +#endif + +/* Overridden by hw/bsp/nrf52840pdk (defined by net/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_XTAL_SETTLE_TIME +#define MYNEWT_VAL_BLE_XTAL_SETTLE_TIME (1500) +#endif + +/*** net/nimble/host */ +#ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU +#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_INDICATE +#define MYNEWT_VAL_BLE_ATT_SVR_INDICATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES +#define MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES (64) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO (30000) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ +#define MYNEWT_VAL_BLE_ATT_SVR_READ (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB +#define MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_MULT +#define MYNEWT_VAL_BLE_ATT_SVR_READ_MULT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID +#define MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID +#define MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS +#define MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_INDICATE +#define MYNEWT_VAL_BLE_GATT_INDICATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_MAX_PROCS +#define MYNEWT_VAL_BLE_GATT_MAX_PROCS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY +#define MYNEWT_VAL_BLE_GATT_NOTIFY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ +#define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_LONG +#define MYNEWT_VAL_BLE_GATT_READ_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS +#define MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT +#define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_UUID +#define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_RESUME_RATE +#define MYNEWT_VAL_BLE_GATT_RESUME_RATE (1000) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_SIGNED_WRITE +#define MYNEWT_VAL_BLE_GATT_SIGNED_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE +#define MYNEWT_VAL_BLE_GATT_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_LONG +#define MYNEWT_VAL_BLE_GATT_WRITE_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS +#define MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP +#define MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE +#define MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_HOST +#define MYNEWT_VAL_BLE_HOST (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_DEBUG +#define MYNEWT_VAL_BLE_HS_DEBUG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS +#define MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_REQUIRE_OS +#define MYNEWT_VAL_BLE_HS_REQUIRE_OS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM +#define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS +#define MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_MAX_CHANS +#define MYNEWT_VAL_BLE_L2CAP_MAX_CHANS (3*MYNEWT_VAL_BLE_MAX_CONNECTIONS) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT +#define MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT (30000) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS +#define MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS (1) +#endif + +/* Overridden by apps/bleall (defined by net/nimble/host) */ +#ifndef MYNEWT_VAL_BLE_MESH +#define MYNEWT_VAL_BLE_MESH (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("monitor") +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") +#endif + +#ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT +#define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_BONDING +#define MYNEWT_VAL_BLE_SM_BONDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_IO_CAP +#define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_KEYPRESS +#define MYNEWT_VAL_BLE_SM_KEYPRESS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_LEGACY +#define MYNEWT_VAL_BLE_SM_LEGACY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS +#define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_MITM +#define MYNEWT_VAL_BLE_SM_MITM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG +#define MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_OUR_KEY_DIST +#define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) +#endif + +/* Overridden by net/nimble/host (defined by net/nimble/host) */ +#ifndef MYNEWT_VAL_BLE_SM_SC +#define MYNEWT_VAL_BLE_SM_SC (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST +#define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) +#endif + +#ifndef MYNEWT_VAL_BLE_STORE_MAX_BONDS +#define MYNEWT_VAL_BLE_STORE_MAX_BONDS (3) +#endif + +#ifndef MYNEWT_VAL_BLE_STORE_MAX_CCCDS +#define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) +#endif + +/*** net/nimble/host/mesh */ +#ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT +#define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO +#define MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO (9) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CRPL +#define MYNEWT_VAL_BLE_MESH_CRPL (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG +#define MYNEWT_VAL_BLE_MESH_DEBUG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS +#define MYNEWT_VAL_BLE_MESH_DEBUG_ACCESS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_ADV +#define MYNEWT_VAL_BLE_MESH_DEBUG_ADV (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_BEACON +#define MYNEWT_VAL_BLE_MESH_DEBUG_BEACON (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CRYPTO +#define MYNEWT_VAL_BLE_MESH_DEBUG_CRYPTO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_FRIEND +#define MYNEWT_VAL_BLE_MESH_DEBUG_FRIEND (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_LOW_POWER +#define MYNEWT_VAL_BLE_MESH_DEBUG_LOW_POWER (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_MODEL +#define MYNEWT_VAL_BLE_MESH_DEBUG_MODEL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_NET +#define MYNEWT_VAL_BLE_MESH_DEBUG_NET (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_PROV +#define MYNEWT_VAL_BLE_MESH_DEBUG_PROV (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_PROXY +#define MYNEWT_VAL_BLE_MESH_DEBUG_PROXY (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_TRANS +#define MYNEWT_VAL_BLE_MESH_DEBUG_TRANS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEV_UUID +#define MYNEWT_VAL_BLE_MESH_DEV_UUID (((uint8_t[16]){0x11, 0x22, 0})) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND +#define MYNEWT_VAL_BLE_MESH_FRIEND (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT +#define MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE +#define MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE (16) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN +#define MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN (255) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE +#define MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE (16) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY +#define MYNEWT_VAL_BLE_MESH_GATT_PROXY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST +#define MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LABEL_COUNT +#define MYNEWT_VAL_BLE_MESH_LABEL_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER +#define MYNEWT_VAL_BLE_MESH_LOW_POWER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_GROUPS +#define MYNEWT_VAL_BLE_MESH_LPN_GROUPS (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE +#define MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT (100) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY +#define MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR +#define MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR +#define MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY +#define MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT +#define MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE +#define MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV +#define MYNEWT_VAL_BLE_MESH_PB_ADV (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PB_GATT +#define MYNEWT_VAL_BLE_MESH_PB_GATT (1) +#endif + +/* Overridden by net/nimble/host/mesh (defined by net/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROV +#define MYNEWT_VAL_BLE_MESH_PROV (1) +#endif + +/* Overridden by net/nimble/host/mesh (defined by net/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROXY +#define MYNEWT_VAL_BLE_MESH_PROXY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE +#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RELAY +#define MYNEWT_VAL_BLE_MESH_RELAY (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RX_SDU_MAX +#define MYNEWT_VAL_BLE_MESH_RX_SDU_MAX (384) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT +#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SUBNET_COUNT +#define MYNEWT_VAL_BLE_MESH_SUBNET_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT +#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4) +#endif + +/*** net/nimble/host/services/ans */ +#ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT +#define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT +#define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) +#endif + +/*** net/nimble/transport/ram */ +#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT +#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE +#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE +#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT +#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT +#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) +#endif + +/*** sys/console/stub */ +#ifndef MYNEWT_VAL_CONSOLE_UART_BAUD +#define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) +#endif + +#ifndef MYNEWT_VAL_CONSOLE_UART_DEV +#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#endif + +#ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL +#define MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL (UART_FLOW_CTL_NONE) +#endif + +/*** sys/flash_map */ +#ifndef MYNEWT_VAL_FLASH_MAP_MAX_AREAS +#define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) +#endif + +/*** sys/log/stub */ +#ifndef MYNEWT_VAL_LOG_CONSOLE +#define MYNEWT_VAL_LOG_CONSOLE (1) +#endif + +#ifndef MYNEWT_VAL_LOG_FCB +#define MYNEWT_VAL_LOG_FCB (0) +#endif + +#ifndef MYNEWT_VAL_LOG_LEVEL +#define MYNEWT_VAL_LOG_LEVEL (255) +#endif + +/*** sys/sysinit */ +#ifndef MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT +#define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) +#endif + +#ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#endif + +#ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#endif + +#endif diff --git a/porting/freertos_nrf5_sdk/nimble_FreeRTOS_gcc_nrf52.ld b/porting/freertos_nrf5_sdk/nimble_FreeRTOS_gcc_nrf52.ld new file mode 100644 index 000000000..97cb5b5d2 --- /dev/null +++ b/porting/freertos_nrf5_sdk/nimble_FreeRTOS_gcc_nrf52.ld @@ -0,0 +1,35 @@ +/* Linker script to configure memory regions. */ + +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x80000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000 +} + +SECTIONS +{ + .vector_relocation : + { + . = ALIGN(256); + __vector_tbl_reloc__ = .; + . = . + (__isr_vector_end - __isr_vector_start); + . = ALIGN(256); + } > RAM + .fs_data : + { + PROVIDE(__start_fs_data = .); + KEEP(*(.fs_data)) + PROVIDE(__stop_fs_data = .); + } > RAM + .pwr_mgmt_data : + { + PROVIDE(__start_pwr_mgmt_data = .); + KEEP(*(.pwr_mgmt_data)) + PROVIDE(__stop_pwr_mgmt_data = .); + } > RAM +} INSERT AFTER .data; + +INCLUDE "nrf5x_common.ld" diff --git a/porting/freertos_nrf5_sdk/src/ble_task.c b/porting/freertos_nrf5_sdk/src/ble_task.c new file mode 100644 index 000000000..43b1754c3 --- /dev/null +++ b/porting/freertos_nrf5_sdk/src/ble_task.c @@ -0,0 +1,175 @@ +/* + * 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 +#include +#include +#include "bsp.h" +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "nimble_port.h" +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" +#include "services/ias/ble_svc_ias.h" + +#if LEDS_NUMBER < 4 +#error "Board is not equipped with enough amount of LEDs" +#endif + +static const char gap_name[] = "freertos"; + +static TaskHandle_t task_h; +static TimerHandle_t led_tmr_h; + +static void start_advertise(void); + +static int +ias_event_cb(uint8_t alert_level) +{ + switch (alert_level) { + case BLE_SVC_IAS_ALERT_LEVEL_NO_ALERT: + xTimerStop(led_tmr_h, portMAX_DELAY); + bsp_board_leds_off(); + break; + case BLE_SVC_IAS_ALERT_LEVEL_MILD_ALERT: + bsp_board_led_on(BSP_BOARD_LED_0); + bsp_board_led_off(BSP_BOARD_LED_1); + bsp_board_led_off(BSP_BOARD_LED_2); + bsp_board_led_on(BSP_BOARD_LED_3); + xTimerStart(led_tmr_h, portMAX_DELAY); + break; + case BLE_SVC_IAS_ALERT_LEVEL_HIGH_ALERT: + bsp_board_leds_on(); + xTimerStart(led_tmr_h, portMAX_DELAY); + break; + } + + return 0; +} + +static void +put_ad(uint8_t ad_type, uint8_t ad_len, const void *ad, uint8_t *buf, + uint8_t *len) +{ + buf[(*len)++] = ad_len + 1; + buf[(*len)++] = ad_type; + + memcpy(&buf[*len], ad, ad_len); + + *len += ad_len; +} + +static void +update_ad(void) +{ + uint8_t ad[BLE_HS_ADV_MAX_SZ]; + uint8_t ad_len = 0; + uint8_t ad_flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; + uint16_t ad_uuid = htole16(BLE_SVC_IAS_UUID16); + + put_ad(BLE_HS_ADV_TYPE_FLAGS, 1, &ad_flags, ad, &ad_len); + put_ad(BLE_HS_ADV_TYPE_COMP_NAME, sizeof(gap_name), gap_name, ad, &ad_len); + put_ad(BLE_HS_ADV_TYPE_COMP_UUIDS16, sizeof(ad_uuid), &ad_uuid, ad, &ad_len); + + ble_gap_adv_set_data(ad, ad_len); +} + +static int +gap_event_cb(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + if (event->connect.status) { + start_advertise(); + } + break; + + case BLE_GAP_EVENT_DISCONNECT: + start_advertise(); + break; + } + + return 0; +} + +static void +start_advertise(void) +{ + struct ble_gap_adv_params advp; + int rc; + + update_ad(); + + memset(&advp, 0, sizeof advp); + advp.conn_mode = BLE_GAP_CONN_MODE_UND; + advp.disc_mode = BLE_GAP_DISC_MODE_GEN; + rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, + &advp, gap_event_cb, NULL); + assert(rc == 0); +} + +static void +on_sync_cb(void) +{ + start_advertise(); +} + +static void +task_func(void *param) +{ + int rc; + + rc = hal_timer_init(0, NULL); + assert(rc == 0); + rc = hal_timer_init(5, NULL); + assert(rc == 0); + rc = os_cputime_init(MYNEWT_VAL(OS_CPUTIME_FREQ)); + assert(rc == 0); + + nimble_init(); + + ble_hs_cfg.sync_cb = on_sync_cb; + + ble_svc_gap_device_name_set(gap_name); + ble_svc_ias_set_cb(ias_event_cb); + + nimble_run(); +} + +static void led_tmr_func(void *param) +{ + bsp_board_led_invert(BSP_BOARD_LED_0); + bsp_board_led_invert(BSP_BOARD_LED_1); + bsp_board_led_invert(BSP_BOARD_LED_2); + bsp_board_led_invert(BSP_BOARD_LED_3); +} + +void start_nimble(void) +{ + void ble_ll_task(void *arg); + + led_tmr_h = xTimerCreate("led", 500, pdTRUE, NULL, led_tmr_func); + + xTaskCreate(task_func, "nimble", configMINIMAL_STACK_SIZE + 400, + NULL, 2, &task_h); + + xTaskCreate(ble_ll_task, "ll", configMINIMAL_STACK_SIZE + 100, + NULL, 0, &task_h); +} diff --git a/porting/freertos_nrf5_sdk/src/cmsis_nvic.c b/porting/freertos_nrf5_sdk/src/cmsis_nvic.c new file mode 100644 index 000000000..a35079129 --- /dev/null +++ b/porting/freertos_nrf5_sdk/src/cmsis_nvic.c @@ -0,0 +1,73 @@ +/* mbed Microcontroller Library - cmsis_nvic for XXXX + * Copyright (c) 2009-2011 ARM Limited. All rights reserved. + * + * CMSIS-style functionality to support dynamic vectors + */ +#include "bsp/cmsis_nvic.h" + +#ifndef __CORTEX_M + #error "Macro __CORTEX_M not defined; must define cortex-m type!" +#endif + +#if (__CORTEX_M == 0) + #ifndef __VTOR_PRESENT + /* no VTOR is defined so we assume we can't relocate the vector table */ + #define __VTOR_PRESENT (0) +#endif +#endif + +extern char __isr_vector[]; +extern char __vector_tbl_reloc__[]; + +void +NVIC_Relocate(void) +{ + uint32_t *current_location; + uint32_t *new_location; + int i; + + /* + * Relocate the vector table from its current position to the position + * designated in the linker script. + */ + current_location = (uint32_t *)&__isr_vector; + new_location = (uint32_t *)&__vector_tbl_reloc__; + + if (new_location != current_location) { + for (i = 0; i < NVIC_NUM_VECTORS; i++) { + new_location[i] = current_location[i]; + } + } + + /* Set VTOR except for M0 */ +#if ((__CORTEX_M == 0) && (__VTOR_PRESENT == 0)) +#else + SCB->VTOR = (uint32_t)&__vector_tbl_reloc__; +#endif +} + +void +NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + uint32_t *vectors; +#if ((__CORTEX_M == 0) && (__VTOR_PRESENT == 0)) + vectors = (uint32_t *)&__vector_tbl_reloc__; +#else + vectors = (uint32_t *)SCB->VTOR; +#endif + vectors[IRQn + NVIC_USER_IRQ_OFFSET] = vector; + __DMB(); +} + +uint32_t +NVIC_GetVector(IRQn_Type IRQn) +{ + uint32_t *vectors; +#if (__CORTEX_M == 0) + vectors = (uint32_t *)&__vector_tbl_reloc__; +#else + vectors = (uint32_t*)SCB->VTOR; +#endif + return vectors[IRQn + NVIC_USER_IRQ_OFFSET]; +} + diff --git a/porting/freertos_nrf5_sdk/src/hal_timer.c b/porting/freertos_nrf5_sdk/src/hal_timer.c new file mode 100644 index 000000000..8f2919793 --- /dev/null +++ b/porting/freertos_nrf5_sdk/src/hal_timer.c @@ -0,0 +1,932 @@ +/* + * 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 +#include +#include +#include +#include "syscfg/syscfg.h" +#include "bsp/cmsis_nvic.h" +#include "hal/hal_timer.h" +#include "os/os_trace_api.h" +#include "nrf.h" +#include "mcu/nrf52_hal.h" + +/* IRQ prototype */ +typedef void (*hal_timer_irq_handler_t)(void); + +/* User CC 2 for reading counter, CC 3 for timer isr */ +#define NRF_TIMER_CC_READ (2) +#define NRF_TIMER_CC_INT (3) + +/* Output compare 2 used for RTC timers */ +#define NRF_RTC_TIMER_CC_INT (2) + +/* Maximum number of hal timers used */ +#define NRF52_HAL_TIMER_MAX (6) + +/* Maximum timer frequency */ +#define NRF52_MAX_TIMER_FREQ (16000000) + +struct nrf52_hal_timer { + uint8_t tmr_enabled; + uint8_t tmr_irq_num; + uint8_t tmr_rtc; + uint8_t tmr_pad; + uint32_t tmr_cntr; + uint32_t timer_isrs; + uint32_t tmr_freq; + void *tmr_reg; + TAILQ_HEAD(hal_timer_qhead, hal_timer) hal_timer_q; +}; + +#if MYNEWT_VAL(TIMER_0) +struct nrf52_hal_timer nrf52_hal_timer0; +#endif +#if MYNEWT_VAL(TIMER_1) +struct nrf52_hal_timer nrf52_hal_timer1; +#endif +#if MYNEWT_VAL(TIMER_2) +struct nrf52_hal_timer nrf52_hal_timer2; +#endif +#if MYNEWT_VAL(TIMER_3) +struct nrf52_hal_timer nrf52_hal_timer3; +#endif +#if MYNEWT_VAL(TIMER_4) +struct nrf52_hal_timer nrf52_hal_timer4; +#endif +#if MYNEWT_VAL(TIMER_5) +struct nrf52_hal_timer nrf52_hal_timer5; +#endif + +static const struct nrf52_hal_timer *nrf52_hal_timers[NRF52_HAL_TIMER_MAX] = { +#if MYNEWT_VAL(TIMER_0) + &nrf52_hal_timer0, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_1) + &nrf52_hal_timer1, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_2) + &nrf52_hal_timer2, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_3) + &nrf52_hal_timer3, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_4) + &nrf52_hal_timer4, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_5) + &nrf52_hal_timer5 +#else + NULL +#endif +}; + +/* Resolve timer number into timer structure */ +#define NRF52_HAL_TIMER_RESOLVE(__n, __v) \ + if ((__n) >= NRF52_HAL_TIMER_MAX) { \ + rc = EINVAL; \ + goto err; \ + } \ + (__v) = (struct nrf52_hal_timer *) nrf52_hal_timers[(__n)]; \ + if ((__v) == NULL) { \ + rc = EINVAL; \ + goto err; \ + } + +/* Interrupt mask for interrupt enable/clear */ +#define NRF_TIMER_INT_MASK(x) ((1 << (uint32_t)(x)) << 16) + +static uint32_t +nrf_read_timer_cntr(NRF_TIMER_Type *hwtimer) +{ + uint32_t tcntr; + + /* Force a capture of the timer into 'cntr' capture channel; read it */ + hwtimer->TASKS_CAPTURE[NRF_TIMER_CC_READ] = 1; + tcntr = hwtimer->CC[NRF_TIMER_CC_READ]; + + return tcntr; +} + +/** + * nrf timer set ocmp + * + * Set the OCMP used by the timer to the desired expiration tick + * + * NOTE: Must be called with interrupts disabled. + * + * @param timer Pointer to timer. + */ +static void +nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry) +{ + int32_t delta_t; + uint32_t temp; + uint32_t cntr; + NRF_TIMER_Type *hwtimer; + NRF_RTC_Type *rtctimer; + + if (bsptimer->tmr_rtc) { + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT); + temp = bsptimer->tmr_cntr; + cntr = rtctimer->COUNTER; + if (rtctimer->EVENTS_OVRFLW) { + temp += (1UL << 24); + cntr = rtctimer->COUNTER; + } + temp |= cntr; + delta_t = (int32_t)(expiry - temp); + + /* + * The nrf documentation states that you must set the output + * compare to 2 greater than the counter to guarantee an interrupt. + * Since the counter can tick once while we check, we make sure + * it is greater than 2. + */ + if (delta_t < 3) { + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } else { + if (delta_t < (1UL << 24)) { + rtctimer->CC[NRF_RTC_TIMER_CC_INT] = expiry & 0x00ffffff; + } else { + /* CC too far ahead. Just make sure we set compare far ahead */ + rtctimer->CC[NRF_RTC_TIMER_CC_INT] = cntr + (1UL << 23); + } + rtctimer->INTENSET = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT); + } + } else { + hwtimer = bsptimer->tmr_reg; + + /* Disable ocmp interrupt and set new value */ + hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT); + + /* Set output compare register to timer expiration */ + hwtimer->CC[NRF_TIMER_CC_INT] = expiry; + + /* Clear interrupt flag */ + hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0; + + /* Enable the output compare interrupt */ + hwtimer->INTENSET = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT); + + /* Force interrupt to occur as we may have missed it */ + if ((int32_t)(nrf_read_timer_cntr(hwtimer) - expiry) >= 0) { + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + } +} + +/* Disable output compare used for timer */ +static void +nrf_timer_disable_ocmp(NRF_TIMER_Type *hwtimer) +{ + hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT); +} + +static void +nrf_rtc_disable_ocmp(NRF_RTC_Type *rtctimer) +{ + rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT); +} + +static uint32_t +hal_timer_read_bsptimer(struct nrf52_hal_timer *bsptimer) +{ + uint32_t low32; + uint32_t ctx; + uint32_t tcntr; + NRF_RTC_Type *rtctimer; + + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + __HAL_DISABLE_INTERRUPTS(ctx); + tcntr = bsptimer->tmr_cntr; + low32 = rtctimer->COUNTER; + if (rtctimer->EVENTS_OVRFLW) { + tcntr += (1UL << 24); + bsptimer->tmr_cntr = tcntr; + low32 = rtctimer->COUNTER; + rtctimer->EVENTS_OVRFLW = 0; + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + tcntr |= low32; + __HAL_ENABLE_INTERRUPTS(ctx); + + return tcntr; +} + +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \ + MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4) || MYNEWT_VAL(TIMER_5)) +/** + * hal timer chk queue + * + * + * @param bsptimer + */ +static void +hal_timer_chk_queue(struct nrf52_hal_timer *bsptimer) +{ + int32_t delta; + uint32_t tcntr; + uint32_t ctx; + struct hal_timer *timer; + + /* disable interrupts */ + __HAL_DISABLE_INTERRUPTS(ctx); + while ((timer = TAILQ_FIRST(&bsptimer->hal_timer_q)) != NULL) { + if (bsptimer->tmr_rtc) { + tcntr = hal_timer_read_bsptimer(bsptimer); + /* + * If we are within 3 ticks of RTC, we wont be able to set compare. + * Thus, we have to service this timer early. + */ + delta = -3; + } else { + tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg); + delta = 0; + } + if ((int32_t)(tcntr - timer->expiry) >= delta) { + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + timer->cb_func(timer->cb_arg); + } else { + break; + } + } + + /* Any timers left on queue? If so, we need to set OCMP */ + timer = TAILQ_FIRST(&bsptimer->hal_timer_q); + if (timer) { + nrf_timer_set_ocmp(bsptimer, timer->expiry); + } else { + if (bsptimer->tmr_rtc) { + nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg); + } else { + nrf_timer_disable_ocmp(bsptimer->tmr_reg); + } + } + __HAL_ENABLE_INTERRUPTS(ctx); +} +#endif + +/** + * hal timer irq handler + * + * Generic HAL timer irq handler. + * + * @param tmr + */ +/** + * hal timer irq handler + * + * This is the global timer interrupt routine. + * + */ +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \ + MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4)) + +static void +hal_timer_irq_handler(struct nrf52_hal_timer *bsptimer) +{ + uint32_t compare; + NRF_TIMER_Type *hwtimer; + + os_trace_enter_isr(); + + /* Check interrupt source. If set, clear them */ + hwtimer = bsptimer->tmr_reg; + compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT]; + if (compare) { + hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0; + } + + /* XXX: make these stats? */ + /* Count # of timer isrs */ + ++bsptimer->timer_isrs; + + /* + * NOTE: we dont check the 'compare' variable here due to how the timer + * is implemented on this chip. There is no way to force an output + * compare, so if we are late setting the output compare (i.e. the timer + * counter is already passed the output compare value), we use the NVIC + * to set a pending interrupt. This means that there will be no compare + * flag set, so all we do is check to see if the compare interrupt is + * enabled. + */ + if (hwtimer->INTENCLR & NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)) { + hal_timer_chk_queue(bsptimer); + /* XXX: Recommended by nordic to make sure interrupts are cleared */ + compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT]; + } + + os_trace_exit_isr(); +} +#endif + +#if MYNEWT_VAL(TIMER_5) +static void +hal_rtc_timer_irq_handler(struct nrf52_hal_timer *bsptimer) +{ + uint32_t overflow; + uint32_t compare; + NRF_RTC_Type *rtctimer; + + /* Check interrupt source. If set, clear them */ + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT]; + if (compare) { + rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT] = 0; + } + + overflow = rtctimer->EVENTS_OVRFLW; + if (overflow) { + rtctimer->EVENTS_OVRFLW = 0; + bsptimer->tmr_cntr += (1UL << 24); + } + + /* Count # of timer isrs */ + ++bsptimer->timer_isrs; + + /* + * NOTE: we dont check the 'compare' variable here due to how the timer + * is implemented on this chip. There is no way to force an output + * compare, so if we are late setting the output compare (i.e. the timer + * counter is already passed the output compare value), we use the NVIC + * to set a pending interrupt. This means that there will be no compare + * flag set, so all we do is check to see if the compare interrupt is + * enabled. + */ + hal_timer_chk_queue(bsptimer); + + /* Recommended by nordic to make sure interrupts are cleared */ + compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT]; +} +#endif + +#if MYNEWT_VAL(TIMER_0) +void +nrf52_timer0_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer0); +} +#endif + +#if MYNEWT_VAL(TIMER_1) +void +nrf52_timer1_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer1); +} +#endif + +#if MYNEWT_VAL(TIMER_2) +void +nrf52_timer2_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer2); +} +#endif + +#if MYNEWT_VAL(TIMER_3) +void +nrf52_timer3_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer3); +} +#endif + +#if MYNEWT_VAL(TIMER_4) +void +nrf52_timer4_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer4); +} +#endif + +#if MYNEWT_VAL(TIMER_5) +void +nrf52_timer5_irq_handler(void) +{ + hal_rtc_timer_irq_handler(&nrf52_hal_timer5); +} +#endif + +/** + * hal timer init + * + * Initialize platform specific timer items + * + * @param timer_num Timer number to initialize + * @param cfg Pointer to platform specific configuration + * + * @return int 0: success; error code otherwise + */ +int +hal_timer_init(int timer_num, void *cfg) +{ + int rc; + uint8_t irq_num; + struct nrf52_hal_timer *bsptimer; + void *hwtimer; + hal_timer_irq_handler_t irq_isr; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + /* If timer is enabled do not allow init */ + if (bsptimer->tmr_enabled) { + rc = EINVAL; + goto err; + } + + switch (timer_num) { +#if MYNEWT_VAL(TIMER_0) + case 0: + irq_num = TIMER0_IRQn; + hwtimer = NRF_TIMER0; + irq_isr = nrf52_timer0_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_1) + case 1: + irq_num = TIMER1_IRQn; + hwtimer = NRF_TIMER1; + irq_isr = nrf52_timer1_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_2) + case 2: + irq_num = TIMER2_IRQn; + hwtimer = NRF_TIMER2; + irq_isr = nrf52_timer2_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_3) + case 3: + irq_num = TIMER3_IRQn; + hwtimer = NRF_TIMER3; + irq_isr = nrf52_timer3_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_4) + case 4: + irq_num = TIMER4_IRQn; + hwtimer = NRF_TIMER4; + irq_isr = nrf52_timer4_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_5) + case 5: + irq_num = RTC0_IRQn; + hwtimer = NRF_RTC0; + irq_isr = nrf52_timer5_irq_handler; + bsptimer->tmr_rtc = 1; + break; +#endif + default: + hwtimer = NULL; + break; + } + + if (hwtimer == NULL) { + rc = EINVAL; + goto err; + } + + bsptimer->tmr_reg = hwtimer; + bsptimer->tmr_irq_num = irq_num; + + /* Disable IRQ, set priority and set vector in table */ + NVIC_DisableIRQ(irq_num); + NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1); + NVIC_SetVector(irq_num, (uint32_t)irq_isr); + + return 0; + +err: + return rc; +} + +/** + * hal timer config + * + * Configure a timer to run at the desired frequency. This starts the timer. + * + * @param timer_num + * @param freq_hz + * + * @return int + */ +int +hal_timer_config(int timer_num, uint32_t freq_hz) +{ + int rc; + uint8_t prescaler; + uint32_t ctx; + uint32_t div; + uint32_t min_delta; + uint32_t max_delta; + struct nrf52_hal_timer *bsptimer; + NRF_TIMER_Type *hwtimer; +#if MYNEWT_VAL(TIMER_5) + NRF_RTC_Type *rtctimer; +#endif + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + +#if MYNEWT_VAL(TIMER_5) + if (timer_num == 5) { + /* NOTE: we only allow the RTC frequency to be set at 32768 */ + if (bsptimer->tmr_enabled || (freq_hz != 32768) || + (bsptimer->tmr_reg == NULL)) { + rc = EINVAL; + goto err; + } + + bsptimer->tmr_freq = freq_hz; + bsptimer->tmr_enabled = 1; + + __HAL_DISABLE_INTERRUPTS(ctx); + + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + + /* Stop the timer first */ + rtctimer->TASKS_STOP = 1; + + /* Always no prescaler */ + rtctimer->PRESCALER = 0; + + /* Clear overflow events and set overflow interrupt */ + rtctimer->EVENTS_OVRFLW = 0; + rtctimer->INTENSET = RTC_INTENSET_OVRFLW_Msk; + + /* Start the timer */ + rtctimer->TASKS_START = 1; + + /* Set isr in vector table and enable interrupt */ + NVIC_EnableIRQ(bsptimer->tmr_irq_num); + + __HAL_ENABLE_INTERRUPTS(ctx); + return 0; + } +#endif + + /* Set timer to desired frequency */ + div = NRF52_MAX_TIMER_FREQ / freq_hz; + + /* + * Largest prescaler is 2^9 and must make sure frequency not too high. + * If hwtimer is NULL it means that the timer was not initialized prior + * to call. + */ + if (bsptimer->tmr_enabled || (div == 0) || (div > 512) || + (bsptimer->tmr_reg == NULL)) { + rc = EINVAL; + goto err; + } + + if (div == 1) { + prescaler = 0; + } else { + /* Find closest prescaler */ + for (prescaler = 1; prescaler < 10; ++prescaler) { + if (div <= (1 << prescaler)) { + min_delta = div - (1 << (prescaler - 1)); + max_delta = (1 << prescaler) - div; + if (min_delta < max_delta) { + prescaler -= 1; + } + break; + } + } + } + + /* Now set the actual frequency */ + bsptimer->tmr_freq = NRF52_MAX_TIMER_FREQ / (1 << prescaler); + bsptimer->tmr_enabled = 1; + + /* disable interrupts */ + __HAL_DISABLE_INTERRUPTS(ctx); + + /* Make sure HFXO is started */ + if ((NRF_CLOCK->HFCLKSTAT & + (CLOCK_HFCLKSTAT_SRC_Msk | CLOCK_HFCLKSTAT_STATE_Msk)) != + (CLOCK_HFCLKSTAT_SRC_Msk | CLOCK_HFCLKSTAT_STATE_Msk)) { + NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; + NRF_CLOCK->TASKS_HFCLKSTART = 1; + while (1) { + if ((NRF_CLOCK->EVENTS_HFCLKSTARTED) != 0) { + break; + } + } + } + hwtimer = bsptimer->tmr_reg; + + /* Stop the timer first */ + hwtimer->TASKS_STOP = 1; + + /* Put the timer in timer mode using 32 bits. */ + hwtimer->MODE = TIMER_MODE_MODE_Timer; + hwtimer->BITMODE = TIMER_BITMODE_BITMODE_32Bit; + + /* Set the pre-scalar */ + hwtimer->PRESCALER = prescaler; + + /* Start the timer */ + hwtimer->TASKS_START = 1; + + NVIC_EnableIRQ(bsptimer->tmr_irq_num); + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; + +err: + return rc; +} + +/** + * hal timer deinit + * + * De-initialize a HW timer. + * + * @param timer_num + * + * @return int + */ +int +hal_timer_deinit(int timer_num) +{ + int rc; + uint32_t ctx; + struct nrf52_hal_timer *bsptimer; + NRF_TIMER_Type *hwtimer; + NRF_RTC_Type *rtctimer; + + rc = 0; + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + __HAL_DISABLE_INTERRUPTS(ctx); + if (bsptimer->tmr_rtc) { + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + rtctimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT); + rtctimer->TASKS_STOP = 1; + } else { + hwtimer = (NRF_TIMER_Type *)bsptimer->tmr_reg; + hwtimer->INTENCLR = NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT); + hwtimer->TASKS_STOP = 1; + } + bsptimer->tmr_enabled = 0; + bsptimer->tmr_reg = NULL; + __HAL_ENABLE_INTERRUPTS(ctx); + +err: + return rc; +} + +/** + * hal timer get resolution + * + * Get the resolution of the timer. This is the timer period, in nanoseconds + * + * @param timer_num + * + * @return uint32_t The + */ +uint32_t +hal_timer_get_resolution(int timer_num) +{ + int rc; + uint32_t resolution; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + resolution = 1000000000 / bsptimer->tmr_freq; + return resolution; + +err: + rc = 0; + return rc; +} + +/** + * hal timer read + * + * Returns the timer counter. NOTE: if the timer is a 16-bit timer, only + * the lower 16 bits are valid. If the timer is a 64-bit timer, only the + * low 32-bits are returned. + * + * @return uint32_t The timer counter register. + */ +uint32_t +hal_timer_read(int timer_num) +{ + int rc; + uint32_t tcntr; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + if (bsptimer->tmr_rtc) { + tcntr = hal_timer_read_bsptimer(bsptimer); + } else { + tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg); + } + + return tcntr; + + /* Assert here since there is no invalid return code */ +err: + assert(0); + rc = 0; + return rc; +} + +/** + * hal timer delay + * + * Blocking delay for n ticks + * + * @param timer_num + * @param ticks + * + * @return int 0 on success; error code otherwise. + */ +int +hal_timer_delay(int timer_num, uint32_t ticks) +{ + uint32_t until; + + until = hal_timer_read(timer_num) + ticks; + while ((int32_t)(hal_timer_read(timer_num) - until) <= 0) { + /* Loop here till finished */ + } + + return 0; +} + +/** + * + * Initialize the HAL timer structure with the callback and the callback + * argument. Also initializes the HW specific timer pointer. + * + * @param cb_func + * + * @return int + */ +int +hal_timer_set_cb(int timer_num, struct hal_timer *timer, hal_timer_cb cb_func, + void *arg) +{ + int rc; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + timer->cb_func = cb_func; + timer->cb_arg = arg; + timer->link.tqe_prev = NULL; + timer->bsp_timer = bsptimer; + + rc = 0; + +err: + return rc; +} + +int +hal_timer_start(struct hal_timer *timer, uint32_t ticks) +{ + int rc; + uint32_t tick; + struct nrf52_hal_timer *bsptimer; + + /* Set the tick value at which the timer should expire */ + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + if (bsptimer->tmr_rtc) { + tick = hal_timer_read_bsptimer(bsptimer) + ticks; + } else { + tick = nrf_read_timer_cntr(bsptimer->tmr_reg) + ticks; + } + rc = hal_timer_start_at(timer, tick); + return rc; +} + +int +hal_timer_start_at(struct hal_timer *timer, uint32_t tick) +{ + uint32_t ctx; + struct hal_timer *entry; + struct nrf52_hal_timer *bsptimer; + + if ((timer == NULL) || (timer->link.tqe_prev != NULL) || + (timer->cb_func == NULL)) { + return EINVAL; + } + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + timer->expiry = tick; + + __HAL_DISABLE_INTERRUPTS(ctx); + + if (TAILQ_EMPTY(&bsptimer->hal_timer_q)) { + TAILQ_INSERT_HEAD(&bsptimer->hal_timer_q, timer, link); + } else { + TAILQ_FOREACH(entry, &bsptimer->hal_timer_q, link) { + if ((int32_t)(timer->expiry - entry->expiry) < 0) { + TAILQ_INSERT_BEFORE(entry, timer, link); + break; + } + } + if (!entry) { + TAILQ_INSERT_TAIL(&bsptimer->hal_timer_q, timer, link); + } + } + + /* If this is the head, we need to set new OCMP */ + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + nrf_timer_set_ocmp(bsptimer, timer->expiry); + } + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; +} + +/** + * hal timer stop + * + * Stop a timer. + * + * @param timer + * + * @return int + */ +int +hal_timer_stop(struct hal_timer *timer) +{ + uint32_t ctx; + int reset_ocmp; + struct hal_timer *entry; + struct nrf52_hal_timer *bsptimer; + + if (timer == NULL) { + return EINVAL; + } + + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + + __HAL_DISABLE_INTERRUPTS(ctx); + + if (timer->link.tqe_prev != NULL) { + reset_ocmp = 0; + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + /* If first on queue, we will need to reset OCMP */ + entry = TAILQ_NEXT(timer, link); + reset_ocmp = 1; + } + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + if (reset_ocmp) { + if (entry) { + nrf_timer_set_ocmp((struct nrf52_hal_timer *)entry->bsp_timer, + entry->expiry); + } else { + if (bsptimer->tmr_rtc) { + nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg); + } else { + nrf_timer_disable_ocmp(bsptimer->tmr_reg); + } + } + } + } + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; +} diff --git a/porting/freertos_nrf5_sdk/src/main.c b/porting/freertos_nrf5_sdk/src/main.c new file mode 100644 index 000000000..76dbe7d75 --- /dev/null +++ b/porting/freertos_nrf5_sdk/src/main.c @@ -0,0 +1,60 @@ +/* + * 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 +#include +#include "FreeRTOS.h" +#include "task.h" +#include "bsp.h" +#include "nordic_common.h" +#include "nrf_drv_clock.h" +#include "sdk_errors.h" +#include "app_error.h" +#include "bsp/cmsis_nvic.h" + +int main(void) +{ + ret_code_t err_code; + + /* Relocate ISR vector from flash to RAM */ + NVIC_Relocate(); + + /* Initialize clock driver for better time accuracy in FREERTOS */ + err_code = nrf_drv_clock_init(); + APP_ERROR_CHECK(err_code); + + /* Configure LED-pins as outputs */ + bsp_board_leds_init(); + bsp_board_leds_off(); + + /* Activate deep sleep mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + + void start_nimble(void); + start_nimble(); + + /* Start FreeRTOS scheduler. */ + vTaskStartScheduler(); + + while (true) + { + /* FreeRTOS should not be here... FreeRTOS goes back to the start of stack + * in vTaskStartScheduler function. */ + } +} diff --git a/porting/freertos_nrf5_sdk/src/os_port.c b/porting/freertos_nrf5_sdk/src/os_port.c new file mode 100644 index 000000000..cbff72340 --- /dev/null +++ b/porting/freertos_nrf5_sdk/src/os_port.c @@ -0,0 +1,348 @@ +/* + * 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 +#include +#include +#include "os/os.h" +#include "FreeRTOS.h" +#include "semphr.h" +#include "task.h" +#include "timers.h" + +static struct os_eventq dflt_evq; + +static inline bool in_isr() +{ + return (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0; +} + +int +os_started(void) +{ + return xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED; +} + +struct os_task * +os_sched_get_current_task(void) +{ + return xTaskGetCurrentTaskHandle(); +} + +os_error_t +os_mutex_init(struct os_mutex *mu) +{ + if (!mu) { + return OS_INVALID_PARM; + } + + mu->handle = xSemaphoreCreateRecursiveMutex(); + assert(mu->handle); + + return OS_OK; +} + +os_error_t +os_mutex_release(struct os_mutex *mu) +{ + if (!mu) { + return OS_INVALID_PARM; + } + + assert(mu->handle); + + if (in_isr()) { + assert(0); + } else { + if (xSemaphoreGiveRecursive(mu->handle) != pdPASS) { + return OS_BAD_MUTEX; + } + } + + return OS_OK; +} + +os_error_t +os_mutex_pend(struct os_mutex *mu, uint32_t timeout) +{ + if (!mu) { + return OS_INVALID_PARM; + } + + assert(mu->handle); + + if (in_isr()) { + assert(0); + } else { + if (xSemaphoreTakeRecursive(mu->handle, timeout) != pdPASS) { + return OS_TIMEOUT; + } + } + + return OS_OK; +} + +os_error_t +os_sem_init(struct os_sem *sem, uint16_t tokens) +{ + if (!sem) { + return OS_INVALID_PARM; + } + + sem->handle = xSemaphoreCreateCounting(128, tokens); + assert(sem->handle); + + return OS_OK; +} + +os_error_t +os_sem_release(struct os_sem *sem) +{ + BaseType_t ret; + BaseType_t woken; + + if (!sem) { + return OS_INVALID_PARM; + } + + assert(sem->handle); + + if (in_isr()) { + ret = xSemaphoreGiveFromISR(sem->handle, &woken); + assert(ret == pdPASS); + + portYIELD_FROM_ISR(woken); + } else { + ret = xSemaphoreGive(sem->handle); + assert(ret == pdPASS); + } + + return OS_OK; +} + +os_error_t +os_sem_pend(struct os_sem *sem, uint32_t timeout) +{ + BaseType_t woken; + + if (!sem) { + return OS_INVALID_PARM; + } + + assert(sem->handle); + + if (in_isr()) { + assert(timeout == 0); + if (xSemaphoreTakeFromISR(sem->handle, &woken) != pdPASS) { + portYIELD_FROM_ISR(woken); + return OS_TIMEOUT; + } + portYIELD_FROM_ISR(woken); + } else { + if (xSemaphoreTake(sem->handle, timeout) != pdPASS) { + return OS_TIMEOUT; + } + } + + return OS_OK; +} + +uint16_t +os_sem_get_count(struct os_sem *sem) +{ + /* XXX FreeRTOS 9.x added dedicated API for this - it's the same as below */ + return uxQueueMessagesWaiting(sem->handle); +} + +struct os_eventq * +os_eventq_dflt_get(void) +{ + if (!dflt_evq.q) { + dflt_evq.q = xQueueCreate(32, sizeof(struct os_event *)); + } + + return &dflt_evq; +} + +void +os_eventq_init(struct os_eventq *evq) +{ + evq->q = xQueueCreate(32, sizeof(struct os_event *)); +} + +struct os_event * +os_eventq_get(struct os_eventq *evq) +{ + struct os_event *ev; + BaseType_t ret; + + ret = xQueueReceive(evq->q, &ev, portMAX_DELAY); + assert(ret == pdPASS); + + ev->ev_queued = 0; + + return ev; +} + +void +os_eventq_put(struct os_eventq *evq, struct os_event *ev) +{ + BaseType_t ret; + + if (OS_EVENT_QUEUED(ev)) { + return; + } + + ev->ev_queued = 1; + + ret = xQueueSendToBack(evq->q, &ev, 0); + assert(ret == pdPASS); +} + +void +os_eventq_remove(struct os_eventq *evq, struct os_event *ev) +{ + struct os_event *tmp_ev; + BaseType_t ret; + int i; + int count; + + if (!OS_EVENT_QUEUED(ev)) { + return; + } + + /* + * XXX We cannot extract element from inside FreeRTOS queue so as a quick + * workaround we'll just remove all elements and add them back except the + * one we need to remove. This is silly, but works for now - we probably + * better use counting semaphore with os_queue to handle this in future. + */ + + vPortEnterCritical(); + + count = uxQueueMessagesWaiting(evq->q); + for (i = 0; i < count; i++) { + ret = xQueueReceive(evq->q, &tmp_ev, 0); + assert(ret == pdPASS); + + if (tmp_ev == ev) { + continue; + } + + ret = xQueueSendToBack(evq->q, &tmp_ev, 0); + assert(ret == pdPASS); + } + + vPortExitCritical(); + + ev->ev_queued = 0; +} + +void +os_eventq_run(struct os_eventq *evq) +{ + struct os_event *ev; + + ev = os_eventq_get(evq); + assert(ev->ev_cb != NULL); + + ev->ev_cb(ev); +} + +static void +os_callout_timer_cb(TimerHandle_t timer) +{ + struct os_callout *c; + + c = pvTimerGetTimerID(timer); + assert(c); + + if (c->c_evq) { + os_eventq_put(c->c_evq, &c->c_ev); + } else { + c->c_ev.ev_cb(&c->c_ev); + } +} + +void +os_callout_init(struct os_callout *c, struct os_eventq *evq, + os_event_fn *ev_cb, void *ev_arg) +{ + memset(c, 0, sizeof(*c)); + c->c_ev.ev_cb = ev_cb; + c->c_ev.ev_arg = ev_arg; + c->c_evq = evq; + c->c_timer = xTimerCreate("co", 1, pdFALSE, c, os_callout_timer_cb); +} + +int +os_callout_reset(struct os_callout *c, int32_t ticks) +{ + BaseType_t woken1, woken2, woken3; + + if (ticks < 0) { + return OS_EINVAL; + } + + if (ticks == 0) { + ticks = 1; + } + + c->c_ticks = os_time_get() + ticks; + + if (in_isr()) { + xTimerStopFromISR(c->c_timer, &woken1); + xTimerChangePeriodFromISR(c->c_timer, ticks, &woken2); + xTimerResetFromISR(c->c_timer, &woken3); + + portYIELD_FROM_ISR(woken1 || woken2 || woken3); + } else { + xTimerStop(c->c_timer, portMAX_DELAY); + xTimerChangePeriod(c->c_timer, ticks, portMAX_DELAY); + xTimerReset(c->c_timer, portMAX_DELAY); + } + + return OS_OK; +} + +int +os_callout_queued(struct os_callout *c) +{ + return xTimerIsTimerActive(c->c_timer) == pdTRUE; +} + +void +os_callout_stop(struct os_callout *c) +{ + xTimerStop(c->c_timer, portMAX_DELAY); +} + +os_time_t +os_time_get(void) +{ + return xTaskGetTickCountFromISR(); +} + +int +os_time_ms_to_ticks(uint32_t ms, uint32_t *out_ticks) +{ + *out_ticks = ms; + + return OS_OK; +}