You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2017/12/18 13:55:11 UTC
[mynewt-nimble] 01/01: porting: Add FreeRTOS port (based on nRF5
SDK)
This is an automated email from the ASF dual-hosted git repository.
andk pushed a commit to branch freertos-port
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit c1b85089e0c11a32cb26a115433f286aa13697f7
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Wed Dec 6 10:36:40 2017 +0100
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 <x>/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 ++++
porting/freertos_nrf5_sdk/config/FreeRTOSConfig.h | 229 ++++
porting/freertos_nrf5_sdk/config/sdk_config.h | 699 ++++++++++
porting/freertos_nrf5_sdk/include/bsp/cmsis_nvic.h | 29 +
porting/freertos_nrf5_sdk/include/mcu/nrf52_hal.h | 70 +
porting/freertos_nrf5_sdk/include/os/os_arch.h | 25 +
porting/freertos_nrf5_sdk/include/os/os_callout.h | 52 +
porting/freertos_nrf5_sdk/include/os/os_eventq.h | 67 +
porting/freertos_nrf5_sdk/include/os/os_mutex.h | 46 +
porting/freertos_nrf5_sdk/include/os/os_sem.h | 27 +
porting/freertos_nrf5_sdk/include/syscfg/syscfg.h | 967 ++++++++++++++
.../freertos_nrf5_sdk/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(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dfb676a
--- /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 0000000..60f8a3c
--- /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 0000000..7f9f0ed
--- /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 <inttypes.h>
+
+#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 0000000..1937130
--- /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 <inttypes.h>
+#include "os/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#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 0000000..46282a0
--- /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 0000000..ac4d7e7
--- /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 <inttypes.h>
+#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 0000000..18461b6
--- /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 0000000..6d5e214
--- /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 0000000..ca8698d
--- /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 <inttypes.h>
+
+#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 0000000..9ff6ed5
--- /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 <stdlib.h>
+#include <inttypes.h>
+
+#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 0000000..22d47f7
--- /dev/null
+++ b/porting/common/include/os/os_arch.h
@@ -0,0 +1,26 @@
+#ifndef _OS_ARCH_H
+#define _OS_ARCH_H
+
+#include <stdint.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 (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 0000000..254d7a4
--- /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 0000000..15f43d5
--- /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 0000000..fc3b881
--- /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 0000000..ed65a08
--- /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 <os/os.h>
+
+#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 0000000..01df389
--- /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 0000000..b0c3abd
--- /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 <inttypes.h>
+#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 0000000..4ce34c2
--- /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 0000000..4413568
--- /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 <stddef.h>
+
+#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 0000000..32b72c2
--- /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 0000000..314a2eb
--- /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 0000000..0f5cca9
--- /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 <stdbool.h>
+#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 0000000..2964edb
--- /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 0000000..e74f2f9
--- /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 <stdint.h>
+
+#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 0000000..be6b7fd
--- /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 0000000..d5451ab
--- /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 0000000..a9e420f
--- /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 0000000..b71d608
--- /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 0000000..2fa07e9
--- /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 <stdbool.h>
+#include <stdint.h>
+
+#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 0000000..e01ff20
--- /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 <stdint.h>
+
+#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 0000000..faffd85
--- /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 0000000..ac2a182
--- /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 <stdint.h>
+#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 0000000..7694c42
--- /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 <inttypes.h>
+#include <assert.h>
+#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 0000000..340e60e
--- /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 0000000..8f8daa9
--- /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 <stddef.h>
+#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 0000000..1311f43
--- /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 0000000..b8ec3ff
--- /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 <assert.h>
+#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 0000000..e8deeab
--- /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 <assert.h>
+#include <string.h>
+
+#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 0000000..19b0b82
--- /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 <string.h>
+#include <stdint.h>
+#include <assert.h>
+#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 0000000..4e76968
--- /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 0000000..bb71662
--- /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 0000000..5a05b96
--- /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 0000000..07b1c54
--- /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 <string.h>
+
+/**
+ * @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 0000000..b09c81f
--- /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 <assert.h>
+#include <string.h>
+#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 0000000..0d94325
--- /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 <assert.h>
+#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 0000000..52c81ae
--- /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 <assert.h>
+#include <string.h>
+#include <limits.h>
+
+/**
+ * @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 0000000..65e4f61
--- /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 <string.h>
+#include <assert.h>
+#include <stdbool.h>
+
+/**
+ * @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 0000000..a907b41
--- /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 <assert.h>
+
+#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 0000000..117045f
--- /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 <assert.h>
+
+/**
+ * @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 0000000..be7f458
--- /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 0000000..5b96711
--- /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 <assert.h>
+#include <string.h>
+
+#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 0000000..9204a73
--- /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 <assert.h>
+#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 0000000..7566087
--- /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 <assert.h>
+
+
+/**
+ * @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 0000000..4f96209
--- /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 <assert.h>
+#include <string.h>
+#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 0000000..3f6816d
--- /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 <assert.h>
+
+#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 0000000..393d1c5
--- /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 <stdio.h>
+#include <stddef.h>
+#include <limits.h>
+#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 0000000..fb2818b
--- /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 0000000..7569484
--- /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
... 3734 lines suppressed ...
--
To stop receiving notification emails like this one, please contact
"commits@mynewt.apache.org" <co...@mynewt.apache.org>.