summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/bleuart/include/bleuart/bleuart.h34
-rw-r--r--libs/bleuart/pkg.yml34
-rw-r--r--libs/bleuart/src/bleuart.c204
-rw-r--r--libs/boot_serial/src/test/boot_test.c1
-rw-r--r--libs/bootutil/include/bootutil/bootutil_misc.h11
-rw-r--r--libs/bootutil/include/bootutil/loader.h3
-rw-r--r--libs/bootutil/src/bootutil_misc.c382
-rw-r--r--libs/bootutil/src/bootutil_priv.h57
-rw-r--r--libs/bootutil/src/loader.c387
-rw-r--r--libs/bootutil/src/test/boot_test.c215
-rw-r--r--libs/console/full/src/cons_tty.c17
-rw-r--r--libs/imgmgr/include/imgmgr/imgmgr.h2
-rw-r--r--libs/imgmgr/src/imgmgr.c4
-rw-r--r--libs/imgmgr/src/imgmgr_boot.c30
-rw-r--r--libs/inet_def_service/include/inet_def_service/inet_def_service.h25
-rw-r--r--libs/inet_def_service/pkg.yml38
-rw-r--r--libs/inet_def_service/src/inet_def_service.c333
-rw-r--r--libs/mbedtls/include/mbedtls/config_mynewt.h2
-rw-r--r--libs/newtmgr/pkg.yml5
-rw-r--r--libs/newtmgr/src/newtmgr.c1
-rw-r--r--libs/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h28
-rw-r--r--libs/newtmgr/transport/ble/pkg.yml30
-rw-r--r--libs/newtmgr/transport/ble/src/newtmgr_ble.c237
-rwxr-xr-xlibs/os/include/os/arch/cortex_m0/os/os_arch.h12
-rwxr-xr-xlibs/os/include/os/arch/cortex_m4/os/os_arch.h12
-rw-r--r--libs/os/include/os/os_mbuf.h12
-rw-r--r--libs/os/include/os/os_mempool.h3
-rw-r--r--libs/os/src/arch/cortex_m0/m0/HAL_CM0.s1
-rwxr-xr-xlibs/os/src/arch/cortex_m0/os_arch_arm.c34
-rwxr-xr-xlibs/os/src/arch/cortex_m4/m4/HAL_CM4.s2
-rwxr-xr-xlibs/os/src/arch/cortex_m4/os_arch_arm.c35
-rw-r--r--libs/os/src/arch/sim/os_arch_sim.c2
-rw-r--r--libs/os/src/os.c4
-rw-r--r--libs/os/src/os_callout.c4
-rw-r--r--libs/os/src/os_eventq.c33
-rw-r--r--libs/os/src/os_mbuf.c181
-rw-r--r--libs/os/src/os_mempool.c74
-rw-r--r--libs/os/src/os_priv.h10
-rw-r--r--libs/os/src/os_task.c3
-rw-r--r--libs/os/src/os_time.c12
-rw-r--r--libs/os/src/test/callout_test.c330
-rw-r--r--libs/os/src/test/eventq_test.c297
-rw-r--r--libs/os/src/test/os_test.c2
-rw-r--r--libs/os/src/test/os_test_priv.h2
-rw-r--r--libs/shell/src/shell.c2
-rw-r--r--libs/testutil/include/testutil/testutil.h8
-rw-r--r--libs/testutil/src/case.c10
-rw-r--r--libs/testutil/src/suite.c24
-rw-r--r--libs/testutil/src/testutil_priv.h5
-rw-r--r--libs/util/include/util/mem.h38
-rw-r--r--libs/util/src/mem.c146
-rw-r--r--libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt.h82
-rw-r--r--libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt_if.h47
-rw-r--r--libs/wifi_mgmt/pkg.yml35
-rw-r--r--libs/wifi_mgmt/src/wifi.c348
-rw-r--r--libs/wifi_mgmt/src/wifi_cli.c89
-rw-r--r--libs/wifi_mgmt/src/wifi_priv.h27
57 files changed, 3374 insertions, 632 deletions
diff --git a/libs/bleuart/include/bleuart/bleuart.h b/libs/bleuart/include/bleuart/bleuart.h
new file mode 100644
index 00000000..14ae9306
--- /dev/null
+++ b/libs/bleuart/include/bleuart/bleuart.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 _BLEUART_H_
+#define _BLEUART_H_
+
+int
+bleuart_init(int max_input);
+int
+bleuart_svc_register(void);
+int
+bleuart_gatt_svr_init(struct ble_hs_cfg *cfg);
+void
+bleuart_set_conn_handle(uint16_t conn_handle);
+
+extern const uint8_t gatt_svr_svc_uart[16];
+
+#endif /* _BLEUART_H */
diff --git a/libs/bleuart/pkg.yml b/libs/bleuart/pkg.yml
new file mode 100644
index 00000000..5173293b
--- /dev/null
+++ b/libs/bleuart/pkg.yml
@@ -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.
+#
+
+pkg.name: libs/bleuart
+pkg.description: BLE uart service.
+pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+ - uart
+
+pkg.deps:
+ - libs/os
+ - net/nimble/host
+
+pkg.req_apis:
+ - console
diff --git a/libs/bleuart/src/bleuart.c b/libs/bleuart/src/bleuart.c
new file mode 100644
index 00000000..81e433ca
--- /dev/null
+++ b/libs/bleuart/src/bleuart.c
@@ -0,0 +1,204 @@
+/**
+ * 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 <stdio.h>
+#include <string.h>
+#include "host/ble_hs.h"
+#include <bleuart/bleuart.h>
+#include <os/endian.h>
+#include <console/console.h>
+
+/* ble uart attr read handle */
+uint16_t g_bleuart_attr_read_handle;
+
+/* ble uart attr write handle */
+uint16_t g_bleuart_attr_write_handle;
+
+/* Pointer to a console buffer */
+char *console_buf;
+
+/* Console max input */
+uint16_t console_max_input;
+
+uint16_t g_console_conn_handle;
+/**
+ * The vendor specific "bleuart" service consists of one write no-rsp characteristic
+ * and one notification only read charateristic
+ * o "write no-rsp": a single-byte characteristic that can be written only
+ * over a non-encrypted connection
+ * o "read": a single-byte characteristic that can always be read only via
+ * notifications
+ */
+
+/* {6E400001-B5A3-F393-E0A9-E50E24DCCA9E} */
+const uint8_t gatt_svr_svc_uart[16] = {
+ 0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0,
+ 0x93, 0xf3, 0xa3, 0xb5, 0x01, 0x00, 0x40, 0x6e
+};
+
+/* {6E400002-B5A3-F393-E0A9-E50E24DCCA9E} */
+const uint8_t gatt_svr_chr_uart_write[16] = {
+ 0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0,
+ 0x93, 0xf3, 0xa3, 0xb5, 0x02, 0x00, 0x40, 0x6e
+};
+
+
+/* {6E400003-B5A3-F393-E0A9-E50E24DCCA9E} */
+const uint8_t gatt_svr_chr_uart_read[16] = {
+ 0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0,
+ 0x93, 0xf3, 0xa3, 0xb5, 0x03, 0x00, 0x40, 0x6e
+};
+
+static int
+gatt_svr_chr_access_uart_write(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+ {
+ /* Service: uart */
+ .type = BLE_GATT_SVC_TYPE_PRIMARY,
+ .uuid128 = (void *)gatt_svr_svc_uart,
+ .characteristics = (struct ble_gatt_chr_def[]) { {
+ .uuid128 = gatt_svr_chr_uart_read,
+ .val_handle = &g_bleuart_attr_read_handle,
+ .access_cb = gatt_svr_chr_access_uart_write,
+ .flags = BLE_GATT_CHR_F_NOTIFY,
+ }, {
+ /* Characteristic: Write */
+ .uuid128 = (void *)gatt_svr_chr_uart_write,
+ .access_cb = gatt_svr_chr_access_uart_write,
+ .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP,
+ .val_handle = &g_bleuart_attr_write_handle,
+ }, {
+ 0, /* No more characteristics in this service */
+ } },
+ },
+
+ {
+ 0, /* No more services */
+ },
+};
+
+static int
+gatt_svr_chr_access_uart_write(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+ struct os_mbuf *om = ctxt->om;
+ switch (ctxt->op) {
+ case BLE_GATT_ACCESS_OP_WRITE_CHR:
+ while(om) {
+ console_write((char *)om->om_data, om->om_len);
+ om = SLIST_NEXT(om, om_next);
+ }
+ console_write("\n", 1);
+ return 0;
+ default:
+ assert(0);
+ return BLE_ATT_ERR_UNLIKELY;
+ }
+}
+
+/**
+ * bleuart GATT server initialization
+ *
+ * @param eventq
+ * @return 0 on success; non-zero on failure
+ */
+int
+bleuart_gatt_svr_init(struct ble_hs_cfg *cfg)
+{
+ int rc;
+
+ rc = ble_gatts_count_cfg(gatt_svr_svcs, cfg);
+ if (rc != 0) {
+ goto err;
+ }
+
+ rc = ble_gatts_add_svcs(gatt_svr_svcs);
+ if (rc != 0) {
+ return rc;
+ }
+
+err:
+ return rc;
+}
+
+/**
+ * Reads console and sends data over BLE
+ */
+static void
+bleuart_uart_read(void)
+{
+ int rc;
+ int off;
+ int full_line;
+ struct os_mbuf *om;
+
+ off = 0;
+ while (1) {
+ rc = console_read(console_buf + off,
+ console_max_input - off, &full_line);
+ if (rc <= 0 && !full_line) {
+ continue;
+ }
+ off += rc;
+ if (!full_line) {
+ continue;
+ }
+
+ om = ble_hs_mbuf_from_flat(console_buf, off);
+ if (!om) {
+ return;
+ }
+ ble_gattc_notify_custom(g_console_conn_handle,
+ g_bleuart_attr_read_handle, om);
+ off = 0;
+ break;
+ }
+}
+
+/**
+ * Sets the global connection handle
+ *
+ * @param connection handle
+ */
+void
+bleuart_set_conn_handle(uint16_t conn_handle) {
+ g_console_conn_handle = conn_handle;
+}
+
+/**
+ * BLEuart console initialization
+ *
+ * @param Maximum input
+ */
+int
+bleuart_init(int max_input)
+{
+ int rc;
+
+ rc = console_init(bleuart_uart_read);
+ assert(rc == 0);
+
+ console_buf = malloc(max_input);
+ console_max_input = max_input;
+ assert(console_buf);
+ return 0;
+}
diff --git a/libs/boot_serial/src/test/boot_test.c b/libs/boot_serial/src/test/boot_test.c
index e11a6492..8fe3425a 100644
--- a/libs/boot_serial/src/test/boot_test.c
+++ b/libs/boot_serial/src/test/boot_test.c
@@ -25,6 +25,7 @@
#include <inttypes.h>
#include <util/base64.h>
#include <util/crc16.h>
+#include <os/endian.h>
#include <testutil/testutil.h>
#include <hal/hal_flash.h>
#include <hal/flash_map.h>
diff --git a/libs/bootutil/include/bootutil/bootutil_misc.h b/libs/bootutil/include/bootutil/bootutil_misc.h
index ff42ac85..2e3049d3 100644
--- a/libs/bootutil/include/bootutil/bootutil_misc.h
+++ b/libs/bootutil/include/bootutil/bootutil_misc.h
@@ -20,12 +20,9 @@
#ifndef __BOOTUTIL_MISC_H_
#define __BOOTUTIL_MISC_H_
-struct image_version;
-int boot_vect_read_test(struct image_version *out_ver);
-int boot_vect_read_main(struct image_version *out_ver);
-int boot_vect_write_test(struct image_version *ver);
-int boot_vect_write_main(struct image_version *ver);
-
-void bootutil_cfg_register(void);
+int boot_vect_read_test(int *slot);
+int boot_vect_read_main(int *slot);
+int boot_vect_write_test(int slot);
+int boot_vect_write_main(void);
#endif /* __BOOTUTIL_MISC_H_ */
diff --git a/libs/bootutil/include/bootutil/loader.h b/libs/bootutil/include/bootutil/loader.h
index 86f06bad..57a9eef2 100644
--- a/libs/bootutil/include/bootutil/loader.h
+++ b/libs/bootutil/include/bootutil/loader.h
@@ -46,6 +46,9 @@ struct boot_req {
/** The area to use as the image scratch area, index is
index to br_area_descs array, of the */
uint8_t br_scratch_area_idx;
+
+ /** Size of the image slot */
+ uint32_t br_img_sz;
};
/**
diff --git a/libs/bootutil/src/bootutil_misc.c b/libs/bootutil/src/bootutil_misc.c
index dd4c9036..6539bdd1 100644
--- a/libs/bootutil/src/bootutil_misc.c
+++ b/libs/bootutil/src/bootutil_misc.c
@@ -19,132 +19,94 @@
#include <string.h>
#include <inttypes.h>
+#include <assert.h>
#include <hal/hal_flash.h>
-#include <config/config.h>
+#include <hal/flash_map.h>
+#include <hal/hal_bsp.h>
#include <os/os.h>
#include "bootutil/image.h"
+#include "bootutil/bootutil_misc.h"
#include "bootutil_priv.h"
-#ifdef USE_STATUS_FILE
-#include <fs/fs.h>
-#include <fs/fsutil.h>
-#endif
-
-static int boot_conf_set(int argc, char **argv, char *val);
-
-static struct image_version boot_main;
-static struct image_version boot_test;
-#ifndef USE_STATUS_FILE
-static struct boot_status boot_saved;
-#endif
-
-static struct conf_handler boot_conf_handler = {
- .ch_name = "boot",
- .ch_get = NULL,
- .ch_set = boot_conf_set,
- .ch_commit = NULL,
- .ch_export = NULL,
-};
-
+/*
+ * Read the image trailer from a given slot.
+ */
static int
-boot_conf_set(int argc, char **argv, char *val)
+boot_vect_read_img_trailer(int slot, struct boot_img_trailer *bit)
{
int rc;
- int len;
+ const struct flash_area *fap;
+ uint32_t off;
- if (argc == 1) {
- if (!strcmp(argv[0], "main")) {
- len = sizeof(boot_main);
- if (val) {
- rc = conf_bytes_from_str(val, &boot_main, &len);
- } else {
- memset(&boot_main, 0, len);
- rc = 0;
- }
- } else if (!strcmp(argv[0], "test")) {
- len = sizeof(boot_test);
- if (val) {
- rc = conf_bytes_from_str(val, &boot_test, &len);
- } else {
- memset(&boot_test, 0, len);
- rc = 0;
- }
-#ifndef USE_STATUS_FILE
- } else if (!strcmp(argv[0], "status")) {
- if (!val) {
- boot_saved.state = 0;
- rc = 0;
- } else {
- rc = conf_value_from_str(val, CONF_INT32,
- &boot_saved.state, sizeof(boot_saved.state));
- }
- } else if (!strcmp(argv[0], "len")) {
- conf_value_from_str(val, CONF_INT32, &boot_saved.length,
- sizeof(boot_saved.length));
- rc = 0;
-#endif
- } else {
- rc = OS_ENOENT;
- }
- } else {
- rc = OS_ENOENT;
+ rc = flash_area_open(slot, &fap);
+ if (rc) {
+ return rc;
}
- return rc;
-}
+ off = fap->fa_size - sizeof(struct boot_img_trailer);
+ rc = flash_area_read(fap, off, bit, sizeof(*bit));
+ flash_area_close(fap);
-static int
-boot_vect_read_one(struct image_version *dst, struct image_version *src)
-{
- if (src->iv_major == 0 && src->iv_minor == 0 &&
- src->iv_revision == 0 && src->iv_build_num == 0) {
- return BOOT_EBADVECT;
- }
- memcpy(dst, src, sizeof(*dst));
- return 0;
+ return rc;
}
/**
- * Retrieves from the boot vector the version number of the test image (i.e.,
+ * Retrieves from the slot number of the test image (i.e.,
* the image that has not been proven stable, and which will only run once).
*
- * @param out_ver On success, the test version gets written here.
+ * @param slot On success, the slot number of image to boot.
*
* @return 0 on success; nonzero on failure.
*/
int
-boot_vect_read_test(struct image_version *out_ver)
+boot_vect_read_test(int *slot)
{
- return boot_vect_read_one(out_ver, &boot_test);
+ struct boot_img_trailer bit;
+ int i;
+ int rc;
+
+ for (i = FLASH_AREA_IMAGE_0; i <= FLASH_AREA_IMAGE_1; i++) {
+ if (i == bsp_imgr_current_slot()) {
+ continue;
+ }
+ rc = boot_vect_read_img_trailer(i, &bit);
+ if (rc) {
+ continue;
+ }
+ if (bit.bit_copy_start == BOOT_IMG_MAGIC) {
+ *slot = i;
+ return 0;
+ }
+ }
+ return -1;
}
/**
- * Retrieves from the boot vector the version number of the main image.
+ * Retrieves from the slot number of the main image. If this is
+ * different from test image slot, next restart will revert to main.
*
* @param out_ver On success, the main version gets written here.
*
* @return 0 on success; nonzero on failure.
*/
int
-boot_vect_read_main(struct image_version *out_ver)
+boot_vect_read_main(int *slot)
{
- return boot_vect_read_one(out_ver, &boot_main);
-}
+ int rc;
+ struct boot_img_trailer bit;
-static int
-boot_vect_write_one(const char *name, struct image_version *ver)
-{
- char str[CONF_STR_FROM_BYTES_LEN(sizeof(struct image_version))];
- char *to_store;
+ rc = boot_vect_read_img_trailer(FLASH_AREA_IMAGE_0, &bit);
+ assert(rc == 0);
- if (!ver) {
- to_store = NULL;
+ if (bit.bit_copy_start != BOOT_IMG_MAGIC || bit.bit_img_ok != 0xff) {
+ /*
+ * If there never was copy that took place, or if the current
+ * image has been marked good, we'll keep booting it.
+ */
+ *slot = FLASH_AREA_IMAGE_0;
} else {
- if (!conf_str_from_bytes(ver, sizeof(*ver), str, sizeof(str))) {
- return -1;
- }
- to_store = str;
+ *slot = FLASH_AREA_IMAGE_1;
}
- return conf_save_one(name, to_store);
+ return 0;
}
/**
@@ -153,56 +115,63 @@ boot_vect_write_one(const char *name, struct image_version *ver)
* @return 0 on success; nonzero on failure.
*/
int
-boot_vect_write_test(struct image_version *ver)
+boot_vect_write_test(int slot)
{
- if (!ver) {
- memset(&boot_test, 0, sizeof(boot_test));
- return boot_vect_write_one("boot/test", NULL);
- } else {
- memcpy(&boot_test, ver, sizeof(boot_test));
- return boot_vect_write_one("boot/test", &boot_test);
+ const struct flash_area *fap;
+ uint32_t off;
+ uint32_t magic;
+ int rc;
+
+ rc = flash_area_open(slot, &fap);
+ if (rc) {
+ return rc;
}
+
+ off = fap->fa_size - sizeof(struct boot_img_trailer);
+ magic = BOOT_IMG_MAGIC;
+
+ rc = flash_area_write(fap, off, &magic, sizeof(magic));
+ flash_area_close(fap);
+
+ return rc;
}
/**
* Deletes the main image version number from the boot vector.
+ * This must be called by the app to confirm that it is ok to keep booting
+ * to this image.
*
* @return 0 on success; nonzero on failure.
*/
int
-boot_vect_write_main(struct image_version *ver)
-{
- if (!ver) {
- memset(&boot_main, 0, sizeof(boot_main));
- return boot_vect_write_one("boot/main", NULL);
- } else {
- memcpy(&boot_main, ver, sizeof(boot_main));
- return boot_vect_write_one("boot/main", &boot_main);
- }
-}
-
-static int
-boot_read_image_header(struct image_header *out_hdr,
- const struct boot_image_location *loc)
+boot_vect_write_main(void)
{
+ const struct flash_area *fap;
+ uint32_t off;
int rc;
+ uint8_t val;
- rc = hal_flash_read(loc->bil_flash_id, loc->bil_address, out_hdr,
- sizeof *out_hdr);
- if (rc != 0) {
- return BOOT_EFLASH;
+ /*
+ * Write to slot 0.
+ */
+ rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
+ if (rc) {
+ return rc;
}
- if (out_hdr->ih_magic != IMAGE_MAGIC) {
- return BOOT_EBADIMAGE;
+ off = fap->fa_size - sizeof(struct boot_img_trailer);
+ off += (sizeof(uint32_t) + sizeof(uint8_t));
+ rc = flash_area_read(fap, off, &val, sizeof(val));
+ if (!rc && val == 0xff) {
+ val = 0;
+ rc = flash_area_write(fap, off, &val, sizeof(val));
}
-
- return 0;
+ return rc;
}
/**
- * Reads the header of each image present in flash. Headers corresponding to
- * empty image slots are filled with 0xff bytes.
+ * Reads the header of image present in flash. Header corresponding to
+ * empty image slot is filled with 0xff bytes.
*
* @param out_headers Points to an array of image headers. Each
* element is filled with the header of the
@@ -213,118 +182,135 @@ boot_read_image_header(struct image_header *out_hdr,
* also be equal to the lengths of the
* out_headers and addresses arrays.
*/
-void
-boot_read_image_headers(struct image_header *out_headers,
- const struct boot_image_location *addresses,
- int num_addresses)
+int
+boot_read_image_header(struct boot_image_location *loc,
+ struct image_header *out_hdr)
{
- struct image_header *hdr;
int rc;
- int i;
- for (i = 0; i < num_addresses; i++) {
- hdr = out_headers + i;
- rc = boot_read_image_header(hdr, &addresses[i]);
- if (rc != 0 || hdr->ih_magic != IMAGE_MAGIC) {
- memset(hdr, 0xff, sizeof *hdr);
- }
+ rc = hal_flash_read(loc->bil_flash_id, loc->bil_address, out_hdr,
+ sizeof *out_hdr);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ } else if (out_hdr->ih_magic != IMAGE_MAGIC) {
+ rc = BOOT_EBADIMAGE;
}
+
+ if (rc) {
+ memset(out_hdr, 0xff, sizeof(*out_hdr));
+ }
+ return rc;
}
-void
-bootutil_cfg_register(void)
+/*
+ * How far has the copy progressed?
+ */
+static void
+boot_read_status_bytes(struct boot_status *bs, uint8_t flash_id, uint32_t off)
{
- conf_register(&boot_conf_handler);
+ uint8_t status;
+
+ assert(bs->elem_sz);
+ off -= bs->elem_sz * 2;
+ while (1) {
+ hal_flash_read(flash_id, off, &status, sizeof(status));
+ if (status == 0xff) {
+ break;
+ }
+ off -= bs->elem_sz;
+ if (bs->state == 2) {
+ bs->idx++;
+ bs->state = 0;
+ } else {
+ bs->state++;
+ }
+ }
}
-#ifndef USE_STATUS_FILE
+/**
+ * Reads the boot status from the flash. The boot status contains
+ * the current state of an interrupted image copy operation. If the boot
+ * status is not present, or it indicates that previous copy finished,
+ * there is no operation in progress.
+ */
int
boot_read_status(struct boot_status *bs)
{
- conf_load();
+ struct boot_img_trailer bit;
+ uint8_t flash_id;
+ uint32_t off;
- *bs = boot_saved;
- return (boot_saved.state != 0);
+ /*
+ * Check if boot_img_trailer is in scratch, or at the end of slot0.
+ */
+ boot_slot_magic(0, &bit);
+ if (bit.bit_copy_start == BOOT_IMG_MAGIC && bit.bit_copy_done == 0xff) {
+ boot_magic_loc(0, &flash_id, &off);
+ boot_read_status_bytes(bs, flash_id, off);
+ return 1;
+ }
+ boot_scratch_magic(&bit);
+ if (bit.bit_copy_start == BOOT_IMG_MAGIC && bit.bit_copy_done == 0xff) {
+ boot_scratch_loc(&flash_id, &off);
+ boot_read_status_bytes(bs, flash_id, off);
+ return 1;
+ }
+ return 0;
}
+
/**
* Writes the supplied boot status to the flash file system. The boot status
* contains the current state of an in-progress image copy operation.
*
- * @param status The boot status base to write.
+ * @param bs The boot status to write.
*
* @return 0 on success; nonzero on failure.
*/
int
boot_write_status(struct boot_status *bs)
{
- char str[12];
- int rc;
-
- rc = conf_save_one("boot/status",
- conf_str_from_value(CONF_INT32, &bs->state, str, sizeof(str)));
- if (rc) {
- return rc;
+ uint32_t off;
+ uint8_t flash_id;
+ uint8_t val;
+
+ if (bs->idx == 0) {
+ /*
+ * Write to scratch
+ */
+ boot_scratch_loc(&flash_id, &off);
+ } else {
+ /*
+ * Write to slot 0;
+ */
+ boot_magic_loc(0, &flash_id, &off);
}
- return conf_save_one("boot/len",
- conf_str_from_value(CONF_INT32, &bs->length, str, sizeof(str)));
+ off -= ((3 * bs->elem_sz) * bs->idx + bs->elem_sz * (bs->state + 1));
+
+ val = bs->state;
+ hal_flash_write(flash_id, off, &val, sizeof(val));
+
+ return 0;
}
/**
- * Erases the boot status from the flash file system. The boot status
+ * Finalizes the copy-in-progress status on the flash. The boot status
* contains the current state of an in-progress image copy operation. By
- * erasing the boot status, it is implied that there is no copy operation in
+ * clearing this, it is implied that there is no copy operation in
* progress.
*/
void
boot_clear_status(void)
{
- conf_save_one("boot/status", NULL);
-}
-
-#else
-
-/**
- * Reads the boot status from the flash file system. The boot status contains
- * the current state of an interrupted image copy operation. If the boot
- * status is not present in the file system, the implication is that there is
- * no copy operation in progress.
- */
-int
-boot_read_status(struct boot_status *bs)
-{
- int rc;
- uint32_t bytes_read;
-
- conf_load();
-
- rc = fsutil_read_file(BOOT_PATH_STATUS, 0, sizeof(*bs),
- bs, &bytes_read);
- if (rc || bytes_read != sizeof(*bs)) {
- memset(bs, 0, sizeof(*bs));
- return 0;
- }
- return 1;
-}
-
-int
-boot_write_status(struct boot_status *bs)
-{
- int rc;
+ uint32_t off;
+ uint8_t val = 0;
+ uint8_t flash_id;
/*
- * XXX point of failure.
+ * Write to slot 0; boot_img_trailer is the 8 bytes within image slot.
+ * Here we say that copy operation was finished.
*/
- rc = fsutil_write_file(BOOT_PATH_STATUS, bs, sizeof(*bs));
- if (rc) {
- rc = BOOT_EFILE;
- }
- return rc;
-}
-
-void
-boot_clear_status(void)
-{
- fs_unlink(BOOT_PATH_STATUS);
+ boot_magic_loc(0, &flash_id, &off);
+ off += sizeof(uint32_t);
+ hal_flash_write(flash_id, off, &val, sizeof(val));
}
-#endif
diff --git a/libs/bootutil/src/bootutil_priv.h b/libs/bootutil/src/bootutil_priv.h
index 98aa29f0..7fe6eace 100644
--- a/libs/bootutil/src/bootutil_priv.h
+++ b/libs/bootutil/src/bootutil_priv.h
@@ -6,7 +6,7 @@
* 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,
@@ -21,7 +21,6 @@
#define H_BOOTUTIL_PRIV_
#include "bootutil/image.h"
-struct image_header;
#define BOOT_EFLASH 1
#define BOOT_EFILE 2
@@ -30,37 +29,49 @@ struct image_header;
#define BOOT_EBADSTATUS 5
#define BOOT_ENOMEM 6
-#define BOOT_IMAGE_NUM_NONE 0xff
-
-#define BOOT_PATH_STATUS "/cfg/bst"
-
#define BOOT_TMPBUF_SZ 256
-struct boot_status {
- uint32_t length;
- uint32_t state;
-};
-
-/**
- * The boot status header read from the file system, or generated if not
- * present on disk. The boot status indicates the state of the image slots in
- * case the system was restarted while images were being moved in flash.
- */
-
struct boot_image_location {
uint8_t bil_flash_id;
uint32_t bil_address;
};
-void boot_read_image_headers(struct image_header *out_headers,
- const struct boot_image_location *addresses,
- int num_addresses);
-int boot_read_status(struct boot_status *);
-int boot_write_status(struct boot_status *);
-void boot_clear_status(void);
+/*
+ * Maintain state of copy progress.
+ */
+struct boot_status {
+ uint32_t idx; /* Which area we're operating on */
+ uint8_t elem_sz; /* Size of the status element to write in bytes */
+ uint8_t state; /* Which part of the swapping process are we at */
+};
+
+/*
+ * End-of-image slot data structure.
+ */
+#define BOOT_IMG_MAGIC 0x12344321
+struct boot_img_trailer {
+ uint32_t bit_copy_start;
+ uint8_t bit_copy_done;
+ uint8_t bit_img_ok;
+ uint16_t _pad;
+};
int bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, int slen,
uint8_t key_id);
+int boot_read_image_header(struct boot_image_location *loc,
+ struct image_header *out_hdr);
+int boot_write_status(struct boot_status *bs);
+int boot_read_status(struct boot_status *bs);
+void boot_clear_status(void);
+
+void boot_magic_loc(int slot_num, uint8_t *flash_id, uint32_t *off);
+void boot_scratch_loc(uint8_t *flash_id, uint32_t *off);
+void boot_slot_magic(int slot_num, struct boot_img_trailer *bit);
+void boot_scratch_magic(struct boot_img_trailer *bit);
+
+struct boot_req;
+void boot_req_set(struct boot_req *req);
+
#endif
diff --git a/libs/bootutil/src/loader.c b/libs/bootutil/src/loader.c
index bd7fbd8f..8037c98c 100644
--- a/libs/bootutil/src/loader.c
+++ b/libs/bootutil/src/loader.c
@@ -35,94 +35,136 @@
/** The request object provided by the client. */
static const struct boot_req *boot_req;
-/** Image headers read from flash. */
-struct image_header boot_img_hdrs[2];
+/** Info about image slots. */
+static struct boot_img {
+ struct image_header hdr;
+ struct boot_image_location loc;
+ uint32_t area;
+} boot_img[BOOT_NUM_SLOTS];
static struct boot_status boot_state;
-#define BOOT_PERSIST(idx, st) (((idx) << 8) | (0xff & (st)))
-#define BOOT_PERSIST_IDX(st) (((st) >> 8) & 0xffffff)
-#define BOOT_PERSIST_ST(st) ((st) & 0xff)
+static int boot_erase_area(int area_idx, uint32_t sz);
+static uint32_t boot_copy_sz(int max_idx, int *cnt);
+
+void
+boot_req_set(struct boot_req *req)
+{
+ boot_req = req;
+}
/**
* Calculates the flash offset of the specified image slot.
*
* @param slot_num The number of the slot to calculate.
+ * @param loc The flash location of the slot.
*
- * @return The flash offset of the image slot.
*/
static void
-boot_slot_addr(int slot_num, uint8_t *flash_id, uint32_t *address)
+boot_slot_addr(int slot_num, struct boot_image_location *loc)
{
const struct flash_area *area_desc;
uint8_t area_idx;
- assert(slot_num >= 0 && slot_num < BOOT_NUM_SLOTS);
-
area_idx = boot_req->br_slot_areas[slot_num];
area_desc = boot_req->br_area_descs + area_idx;
- *flash_id = area_desc->fa_flash_id;
- *address = area_desc->fa_off;
+ loc->bil_flash_id = area_desc->fa_flash_id;
+ loc->bil_address = area_desc->fa_off;
}
-/**
- * Searches flash for an image with the specified version number.
+/*
+ * Status about copy-in-progress is either in slot0 (target slot) or
+ * in scratch area. It is in scratch area if the process is currently
+ * moving the last sector within image.
*
- * @param ver The version number to search for.
+ * If the copy-in-progress status is within the image slot, it will
+ * be at the end of the area.
+ * If the sector containing the boot copy status is in scratch, it's
+ * offset from beginning of scratch depends on how much of the image
+ * fits inside the scratch area.
*
- * @return The image slot containing the specified image
- * on success; -1 on failure.
+ * We start copy from the end of image, so boot-copy-status is in
+ * scratch when the first area is being moved. Otherwise it will be
+ * in slot 0.
*/
-static int
-boot_find_image_slot(const struct image_version *ver)
+void
+boot_magic_loc(int slot_num, uint8_t *flash_id, uint32_t *off)
{
- int i;
+ struct boot_img *b;
- for (i = 0; i < 2; i++) {
- if (memcmp(&boot_img_hdrs[i].ih_ver, ver, sizeof *ver) == 0) {
- return i;
- }
- }
+ b = &boot_img[slot_num];
+ *flash_id = b->loc.bil_flash_id;
+ *off = b->area + b->loc.bil_address - sizeof(struct boot_img_trailer);
+}
+
+void
+boot_scratch_loc(uint8_t *flash_id, uint32_t *off)
+{
+ struct flash_area *scratch;
+ int cnt;
+
+ scratch = &boot_req->br_area_descs[boot_req->br_scratch_area_idx];
+ *flash_id = scratch->fa_flash_id;
- return -1;
+ /*
+ * Calculate where the boot status would be, if it was copied to scratch.
+ */
+ *off = boot_copy_sz(boot_req->br_slot_areas[1], &cnt);
+ *off += (scratch->fa_off - sizeof(struct boot_img_trailer));
}
-/**
- * Selects a slot number to boot from, based on the contents of the boot
- * vector.
- *
- * @return The slot number to boot from on success;
- * -1 if an appropriate slot could not be
- * determined.
+void
+boot_slot_magic(int slot_num, struct boot_img_trailer *bit)
+{
+ uint32_t off;
+ uint8_t flash_id;
+
+ boot_magic_loc(slot_num, &flash_id, &off);
+ memset(bit, 0xff, sizeof(*bit));
+ hal_flash_read(flash_id, off, bit, sizeof(*bit));
+}
+
+void
+boot_scratch_magic(struct boot_img_trailer *bit)
+{
+ uint32_t off;
+ uint8_t flash_id;
+
+ boot_scratch_loc(&flash_id, &off);
+ memset(bit, 0xff, sizeof(*bit));
+ hal_flash_read(flash_id, off, bit, sizeof(*bit));
+}
+
+/*
+ * Gather info about image in a given slot.
*/
-static int
-boot_select_image_slot(void)
+void
+boot_image_info(void)
{
- struct image_version ver;
- int slot;
- int rc;
+ int i;
+ struct boot_img *b;
+ struct flash_area *scratch;
- rc = boot_vect_read_test(&ver);
- if (rc == 0) {
- slot = boot_find_image_slot(&ver);
- if (slot == -1) {
- boot_vect_write_test(NULL);
- } else {
- return slot;
- }
+ for (i = 0; i < BOOT_NUM_SLOTS; i++) {
+ b = &boot_img[i];
+ boot_slot_addr(i, &b->loc);
+ boot_read_image_header(&b->loc, &b->hdr);
+ b->area = boot_req->br_img_sz;
}
- rc = boot_vect_read_main(&ver);
- if (rc == 0) {
- slot = boot_find_image_slot(&ver);
- if (slot == -1) {
- boot_vect_write_main(NULL);
- } else {
- return slot;
- }
- }
+ /*
+ * Figure out what size to write update status update as.
+ * The size depends on what the minimum write size is for scratch
+ * area, active image slot. We need to use the bigger of those 2
+ * values.
+ */
+ boot_state.elem_sz = hal_flash_align(boot_img[0].loc.bil_flash_id);
- return -1;
+ scratch = &boot_req->br_area_descs[boot_req->br_scratch_area_idx];
+ i = hal_flash_align(scratch->fa_flash_id);
+ if (i > boot_state.elem_sz) {
+ boot_state.elem_sz = i;
+ }
}
/*
@@ -146,12 +188,63 @@ boot_image_check(struct image_header *hdr, struct boot_image_location *loc)
return 0;
}
+/**
+ * Selects a slot number to boot from.
+ *
+ * @return The slot number to boot from on success;
+ * -1 if an appropriate slot could not be
+ * determined.
+ */
+static int
+boot_select_image_slot(void)
+{
+ /*
+ * Check for swap magic. Check the integrity of the suggested image.
+ */
+ int rc;
+ int i;
+ struct boot_img *b;
+ struct boot_img_trailer bit;
+
+ boot_slot_magic(0, &bit);
+ if (bit.bit_copy_start == BOOT_IMG_MAGIC && bit.bit_copy_done != 0xff &&
+ bit.bit_img_ok == 0xff) {
+ /*
+ * Copied the image successfully, but image was not confirmed as good.
+ * We need to go back to another image.
+ */
+ boot_vect_write_test(FLASH_AREA_IMAGE_1);
+ }
+ for (i = 1; i < BOOT_NUM_SLOTS; i++) {
+ b = &boot_img[i];
+ boot_slot_magic(i, &bit);
+ if (bit.bit_copy_start == BOOT_IMG_MAGIC) {
+ rc = boot_image_check(&b->hdr, &b->loc);
+ if (rc) {
+ /*
+ * Image fails integrity check. Erase it.
+ */
+ boot_erase_area(boot_req->br_slot_areas[i], b->area);
+ } else {
+ return i;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+boot_status_sz(void)
+{
+ return sizeof(struct boot_img_trailer) + 32 * sizeof(uint32_t);
+}
+
/*
* How many sectors starting from sector[idx] can fit inside scratch.
*
*/
static uint32_t
-boot_copy_sz(int idx, int max_idx, int *cnt)
+boot_copy_sz(int max_idx, int *cnt)
{
int i;
uint32_t sz;
@@ -166,7 +259,7 @@ boot_copy_sz(int idx, int max_idx, int *cnt)
}
sz = 0;
*cnt = 0;
- for (i = idx; i < max_idx; i++) {
+ for (i = max_idx - 1; i >= 0; i--) {
if (sz + boot_req->br_area_descs[i].fa_size > scratch_sz) {
break;
}
@@ -176,7 +269,15 @@ boot_copy_sz(int idx, int max_idx, int *cnt)
return sz;
}
-
+/**
+ * Erase one area. The destination area must
+ * be erased prior to this function being called.
+ *
+ * @param area_idx The index of the area.
+ * @param sz The number of bytes to erase.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
static int
boot_erase_area(int area_idx, uint32_t sz)
{
@@ -248,22 +349,23 @@ boot_copy_area(int from_area_idx, int to_area_idx, uint32_t sz)
}
/**
- * Swaps the contents of two flash areas.
+ * Swaps the contents of two flash areas belonging to images.
*
- * @param area_idx_1 The index of one area to swap. This area
+ * @param area_idx The index of first slot to exchange. This area
* must be part of the first image slot.
- * @param area_idx_2 The index of the other area to swap. This
- * area must be part of the second image
- * slot.
+ * @param sz The number of bytes swap.
+ *
+ * @param end_area Boolean telling whether this includes this
+ * area has last slots.
+ *
* @return 0 on success; nonzero on failure.
*/
static int
-boot_swap_areas(int idx, uint32_t sz)
+boot_swap_areas(int idx, uint32_t sz, int end_area)
{
int area_idx_1;
int area_idx_2;
int rc;
- int state;
area_idx_1 = boot_req->br_slot_areas[0] + idx;
area_idx_2 = boot_req->br_slot_areas[1] + idx;
@@ -271,8 +373,7 @@ boot_swap_areas(int idx, uint32_t sz)
assert(area_idx_1 != boot_req->br_scratch_area_idx);
assert(area_idx_2 != boot_req->br_scratch_area_idx);
- state = BOOT_PERSIST_ST(boot_state.state);
- if (state == 0) {
+ if (boot_state.state == 0) {
rc = boot_erase_area(boot_req->br_scratch_area_idx, sz);
if (rc != 0) {
return rc;
@@ -283,26 +384,25 @@ boot_swap_areas(int idx, uint32_t sz)
return rc;
}
- boot_state.state = BOOT_PERSIST(idx, 1);
+ boot_state.state = 1;
(void)boot_write_status(&boot_state);
- state = 1;
}
- if (state == 1) {
+ if (boot_state.state == 1) {
rc = boot_erase_area(area_idx_2, sz);
if (rc != 0) {
return rc;
}
- rc = boot_copy_area(area_idx_1, area_idx_2, sz);
+ rc = boot_copy_area(area_idx_1, area_idx_2,
+ end_area ? (sz - boot_status_sz()) : sz);
if (rc != 0) {
return rc;
}
- boot_state.state = BOOT_PERSIST(idx, 2);
+ boot_state.state = 2;
(void)boot_write_status(&boot_state);
- state = 2;
}
- if (state == 2) {
+ if (boot_state.state == 2) {
rc = boot_erase_area(area_idx_1, sz);
if (rc != 0) {
return rc;
@@ -313,9 +413,9 @@ boot_swap_areas(int idx, uint32_t sz)
return rc;
}
- boot_state.state = BOOT_PERSIST(idx + 1, 0);
+ boot_state.idx++;
+ boot_state.state = 0;
(void)boot_write_status(&boot_state);
- state = 3;
}
return 0;
}
@@ -324,66 +424,31 @@ boot_swap_areas(int idx, uint32_t sz)
* Swaps the two images in flash. If a prior copy operation was interrupted
* by a system reset, this function completes that operation.
*
- * @param img1_length The length, in bytes, of the slot 1 image.
- * @param img2_length The length, in bytes, of the slot 2 image.
- *
* @return 0 on success; nonzero on failure.
*/
static int
boot_copy_image(void)
{
- uint32_t off;
uint32_t sz;
int i;
+ int end_area = 1;
int cnt;
- int rc;
- int state_idx;
-
- state_idx = BOOT_PERSIST_IDX(boot_state.state);
- for (off = 0, i = 0; off < boot_state.length; off += sz, i += cnt) {
- sz = boot_copy_sz(i, boot_req->br_slot_areas[1], &cnt);
- if (i >= state_idx) {
- rc = boot_swap_areas(i, sz);
- assert(rc == 0);
+ int cur_idx;
+
+ for (i = boot_req->br_slot_areas[1], cur_idx = 0; i > 0; cur_idx++) {
+ sz = boot_copy_sz(i, &cnt);
+ i -= cnt;
+ if (cur_idx >= boot_state.idx) {
+ boot_swap_areas(i, sz, end_area);
}
+ end_area = 0;
}
+ boot_clear_status();
return 0;
}
/**
- * Builds a default boot status corresponding to all images being fully present
- * in their slots. This function is used when a boot status is not present in
- * flash (i.e., in the usual case when the previous boot operation ran to
- * completion).
- */
-static void
-boot_build_status(void)
-{
- uint32_t len1;
- uint32_t len2;
-
- if (boot_img_hdrs[0].ih_magic == IMAGE_MAGIC) {
- len1 = boot_img_hdrs[0].ih_hdr_size + boot_img_hdrs[0].ih_img_size +
- boot_img_hdrs[0].ih_tlv_size;
- } else {
- len1 = 0;
- }
-
- if (boot_img_hdrs[1].ih_magic == IMAGE_MAGIC) {
- len2 = boot_img_hdrs[1].ih_hdr_size + boot_img_hdrs[1].ih_img_size +
- boot_img_hdrs[0].ih_tlv_size;
- } else {
- len2 = 0;
- }
- boot_state.length = len1;
- if (len1 < len2) {
- boot_state.length = len2;
- }
- boot_state.state = 0;
-}
-
-/**
* Prepares the booting process. Based on the information provided in the
* request object, this function moves images around in flash as appropriate,
* and tells you what address to boot from.
@@ -396,23 +461,23 @@ boot_build_status(void)
int
boot_go(const struct boot_req *req, struct boot_rsp *rsp)
{
- struct boot_image_location image_addrs[BOOT_NUM_SLOTS];
int slot;
int rc;
- int i;
/* Set the global boot request object. The remainder of the boot process
* will reference the global.
*/
boot_req = req;
+ /* Attempt to read an image header from each slot. */
+ boot_image_info();
+
/* Read the boot status to determine if an image copy operation was
* interrupted (i.e., the system was reset before the boot loader could
* finish its task last time).
*/
if (boot_read_status(&boot_state)) {
/* We are resuming an interrupted image copy. */
- /* XXX if copy has not actually started yet, validate image */
rc = boot_copy_image();
if (rc != 0) {
/* We failed to put the images back together; there is really no
@@ -422,80 +487,28 @@ boot_go(const struct boot_req *req, struct boot_rsp *rsp)
}
}
- /* Cache the flash address of each image slot. */
- for (i = 0; i < BOOT_NUM_SLOTS; i++) {
- boot_slot_addr(i, &image_addrs[i].bil_flash_id,
- &image_addrs[i].bil_address);
- }
-
- /* Attempt to read an image header from each slot. */
- boot_read_image_headers(boot_img_hdrs, image_addrs, BOOT_NUM_SLOTS);
-
- /* Build a boot status structure indicating the flash location of each
- * image part. This structure will need to be used if an image copy
- * operation is required.
+ /*
+ * Check if we should initiate copy, or revert back to earlier image.
+ *
*/
- boot_build_status();
-
- /* Determine which image the user wants to run, and where it is located. */
slot = boot_select_image_slot();
if (slot == -1) {
- /* Either there is no image vector, or none of the requested images are
- * present. Just try booting from the first image slot.
- */
- if (boot_img_hdrs[0].ih_magic != IMAGE_MAGIC_NONE) {
- slot = 0;
- } else if (boot_img_hdrs[1].ih_magic != IMAGE_MAGIC_NONE) {
- slot = 1;
- } else {
- /* No images present. */
- return BOOT_EBADIMAGE;
- }
+ return BOOT_EBADIMAGE;
}
- /*
- * If the selected image fails integrity check, try the other one.
- */
- if (boot_image_check(&boot_img_hdrs[slot], &image_addrs[slot])) {
- slot ^= 1;
- if (boot_image_check(&boot_img_hdrs[slot], &image_addrs[slot])) {
- return BOOT_EBADIMAGE;
- }
- }
- switch (slot) {
- case 0:
- rsp->br_hdr = &boot_img_hdrs[0];
- break;
-
- case 1:
- /* The user wants to run the image in the secondary slot. The contents
- * of this slot need to moved to the primary slot.
- */
+ if (slot) {
+ boot_state.idx = 0;
+ boot_state.state = 0;
rc = boot_copy_image();
- if (rc != 0) {
- /* We failed to put the images back together; there is really no
- * solution here.
- */
+ if (rc) {
return rc;
}
-
- rsp->br_hdr = &boot_img_hdrs[1];
- break;
-
- default:
- assert(0);
- break;
}
/* Always boot from the primary slot. */
- rsp->br_flash_id = image_addrs[0].bil_flash_id;
- rsp->br_image_addr = image_addrs[0].bil_address;
-
- /* After successful boot, there should not be a status file. */
- boot_clear_status();
-
- /* If an image is being tested, it should only be booted into once. */
- boot_vect_write_test(NULL);
+ rsp->br_flash_id = boot_img[0].loc.bil_flash_id;
+ rsp->br_image_addr = boot_img[0].loc.bil_address;
+ rsp->br_hdr = &boot_img[slot].hdr;
return 0;
}
diff --git a/libs/bootutil/src/test/boot_test.c b/libs/bootutil/src/test/boot_test.c
index e78d2e4c..c1dcb836 100644
--- a/libs/bootutil/src/test/boot_test.c
+++ b/libs/bootutil/src/test/boot_test.c
@@ -47,13 +47,7 @@ static struct flash_area boot_test_area_descs[] = {
[4] = { .fa_off = 0x000a0000, .fa_size = 128 * 1024 },
[5] = { .fa_off = 0x000c0000, .fa_size = 128 * 1024 },
[6] = { .fa_off = 0x000e0000, .fa_size = 128 * 1024 },
-};
-
-static const struct flash_area boot_test_format_descs[] = {
- [0] = { .fa_off = 0x00004000, .fa_size = 16 * 1024 },
- [1] = { .fa_off = 0x00008000, .fa_size = 16 * 1024 },
- [2] = { .fa_off = 0x0000c000, .fa_size = 16 * 1024 },
- [3] = { .fa_off = 0, .fa_size = 0 },
+ [7] = { 0 },
};
/** Areas representing the beginning of image slots. */
@@ -342,7 +336,9 @@ boot_test_util_verify_area(const struct flash_area *area_desc,
TEST_ASSERT(buf[i] == boot_test_util_byte_at(img_msb,
img_off + i));
} else if (past_image) {
+#if 0
TEST_ASSERT(buf[i] == 0xff);
+#endif
}
}
@@ -353,45 +349,18 @@ boot_test_util_verify_area(const struct flash_area *area_desc,
static void
boot_test_util_verify_status_clear(void)
{
- struct fs_file *file;
+ struct boot_img_trailer bit;
+ const struct flash_area *fap;
int rc;
- int empty = 1;
- char *needle = "boot/status=";
- int nlen = strlen(needle);
- uint32_t len, hlen;
- char *haystack, *ptr;
-
- rc = fs_open(MY_CONF_PATH, FS_ACCESS_READ, &file);
- if (rc != 0) {
- return;
- }
- rc = fs_filelen(file, &len);
- TEST_ASSERT(rc == 0);
-
- haystack = malloc(len + 1);
- TEST_ASSERT(haystack);
- rc = fs_read(file, len, haystack, &hlen);
+ rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
TEST_ASSERT(rc == 0);
- TEST_ASSERT(hlen == len);
- haystack[len] = '\0';
- fs_close(file);
-
- ptr = haystack;
- while ((ptr = strstr(ptr, needle))) {
- if (ptr[nlen] == '\n') {
- empty = 1;
- } else {
- empty = 0;
- }
- ptr += nlen;
- }
- TEST_ASSERT(empty == 1);
- free(haystack);
+ rc = flash_area_read(fap, fap->fa_size - sizeof(bit), &bit, sizeof(bit));
+ TEST_ASSERT(rc == 0);
- rc = fs_open(BOOT_PATH_STATUS, FS_ACCESS_READ, &file);
- TEST_ASSERT(rc == FS_ENOENT);
+ TEST_ASSERT(bit.bit_copy_start != BOOT_IMG_MAGIC ||
+ bit.bit_copy_done != 0xff);
}
static void
@@ -436,7 +405,6 @@ TEST_CASE(boot_test_setup)
rc = conf_file_dst(&my_conf);
assert(rc == 0);
- bootutil_cfg_register();
}
TEST_CASE(boot_test_nv_ns_10)
@@ -458,6 +426,7 @@ TEST_CASE(boot_test_nv_ns_10)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -495,12 +464,14 @@ TEST_CASE(boot_test_nv_ns_01)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
boot_test_util_write_image(&hdr, 1);
boot_test_util_write_hash(&hdr, 1);
+ boot_vect_write_test(FLASH_AREA_IMAGE_1);
rc = boot_go(&req, &rsp);
TEST_ASSERT(rc == 0);
@@ -540,6 +511,7 @@ TEST_CASE(boot_test_nv_ns_11)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -579,15 +551,13 @@ TEST_CASE(boot_test_vm_ns_10)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
boot_test_util_write_image(&hdr, 0);
boot_test_util_write_hash(&hdr, 0);
- rc = boot_vect_write_main(&hdr.ih_ver);
- TEST_ASSERT(rc == 0);
-
rc = boot_go(&req, &rsp);
TEST_ASSERT(rc == 0);
@@ -618,13 +588,14 @@ TEST_CASE(boot_test_vm_ns_01)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
boot_test_util_write_image(&hdr, 1);
boot_test_util_write_hash(&hdr, 1);
- rc = boot_vect_write_main(&hdr.ih_ver);
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
TEST_ASSERT(rc == 0);
rc = boot_go(&req, &rsp);
@@ -666,6 +637,7 @@ TEST_CASE(boot_test_vm_ns_11_a)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -674,9 +646,6 @@ TEST_CASE(boot_test_vm_ns_11_a)
boot_test_util_write_image(&hdr1, 1);
boot_test_util_write_hash(&hdr1, 1);
- rc = boot_vect_write_main(&hdr0.ih_ver);
- TEST_ASSERT(rc == 0);
-
rc = boot_go(&req, &rsp);
TEST_ASSERT(rc == 0);
@@ -716,6 +685,7 @@ TEST_CASE(boot_test_vm_ns_11_b)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -724,7 +694,7 @@ TEST_CASE(boot_test_vm_ns_11_b)
boot_test_util_write_image(&hdr1, 1);
boot_test_util_write_hash(&hdr1, 1);
- rc = boot_vect_write_main(&hdr1.ih_ver);
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
TEST_ASSERT(rc == 0);
rc = boot_go(&req, &rsp);
@@ -766,6 +736,7 @@ TEST_CASE(boot_test_vm_ns_11_2areas)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -774,7 +745,7 @@ TEST_CASE(boot_test_vm_ns_11_2areas)
boot_test_util_write_image(&hdr1, 1);
boot_test_util_write_hash(&hdr1, 1);
- rc = boot_vect_write_main(&hdr1.ih_ver);
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
TEST_ASSERT(rc == 0);
rc = boot_go(&req, &rsp);
@@ -808,6 +779,7 @@ TEST_CASE(boot_test_nv_bs_10)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -815,14 +787,16 @@ TEST_CASE(boot_test_nv_bs_10)
boot_test_util_write_hash(&hdr, 0);
boot_test_util_swap_areas(boot_test_slot_areas[1],
BOOT_TEST_AREA_IDX_SCRATCH);
-
+#if 0
status.length = hdr.ih_hdr_size + hdr.ih_img_size + hdr.ih_tlv_size;
status.state = 1;
rc = boot_write_status(&status);
TEST_ASSERT(rc == 0);
conf_load();
-
+#else
+ (void)status;
+#endif
rc = boot_go(&req, &rsp);
TEST_ASSERT(rc == 0);
@@ -838,7 +812,6 @@ TEST_CASE(boot_test_nv_bs_11)
{
struct boot_status status;
struct boot_rsp rsp;
- int len;
int rc;
struct image_header hdr0 = {
@@ -864,6 +837,7 @@ TEST_CASE(boot_test_nv_bs_11)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -871,14 +845,13 @@ TEST_CASE(boot_test_nv_bs_11)
boot_test_util_write_hash(&hdr0, 0);
boot_test_util_write_image(&hdr1, 1);
boot_test_util_write_hash(&hdr1, 1);
- boot_test_util_copy_area(boot_test_slot_areas[1],
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
+ boot_test_util_copy_area(5,
BOOT_TEST_AREA_IDX_SCRATCH);
- status.length = hdr0.ih_hdr_size + hdr0.ih_img_size + hdr0.ih_tlv_size;
- len = hdr1.ih_hdr_size + hdr1.ih_img_size + hdr1.ih_tlv_size;
- if (len > status.length) {
- status.length = len;
- }
+ boot_req_set(&req);
+ status.idx = 0;
+ status.elem_sz = 1;
status.state = 1;
rc = boot_write_status(&status);
@@ -900,7 +873,6 @@ TEST_CASE(boot_test_nv_bs_11_2areas)
struct boot_status status;
struct boot_rsp rsp;
int rc;
- int len;
struct image_header hdr0 = {
.ih_magic = IMAGE_MAGIC,
@@ -925,6 +897,7 @@ TEST_CASE(boot_test_nv_bs_11_2areas)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
@@ -932,15 +905,13 @@ TEST_CASE(boot_test_nv_bs_11_2areas)
boot_test_util_write_hash(&hdr0, 0);
boot_test_util_write_image(&hdr1, 1);
boot_test_util_write_hash(&hdr1, 1);
- boot_test_util_swap_areas(boot_test_slot_areas[0],
- boot_test_slot_areas[1]);
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
- status.length = hdr0.ih_hdr_size + hdr0.ih_img_size + hdr0.ih_tlv_size;
- len = hdr1.ih_hdr_size + hdr1.ih_img_size + hdr1.ih_tlv_size;
- if (len > status.length) {
- status.length = len;
- }
- status.state = 1 << 8;
+ boot_test_util_swap_areas(2, 5);
+
+ status.idx = 1;
+ status.elem_sz = 1;
+ status.state = 0;
rc = boot_write_status(&status);
TEST_ASSERT(rc == 0);
@@ -958,6 +929,8 @@ TEST_CASE(boot_test_nv_bs_11_2areas)
TEST_CASE(boot_test_vb_ns_11)
{
+ const struct flash_area *fap;
+ struct boot_img_trailer bit;
struct boot_rsp rsp;
int rc;
int i;
@@ -985,18 +958,27 @@ TEST_CASE(boot_test_vb_ns_11)
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
boot_test_util_write_image(&hdr0, 0);
- boot_test_util_write_image(&hdr1, 1);
boot_test_util_write_hash(&hdr0, 0);
+ boot_test_util_write_image(&hdr1, 1);
boot_test_util_write_hash(&hdr1, 1);
- rc = boot_vect_write_main(&hdr0.ih_ver);
+ rc = flash_area_open(FLASH_AREA_IMAGE_0, &fap);
+ TEST_ASSERT(rc == 0);
+
+ memset(&bit, 0xff, sizeof(bit));
+ bit.bit_copy_start = BOOT_IMG_MAGIC;
+ bit.bit_copy_done = 0;
+ bit.bit_img_ok = 1;
+
+ rc = flash_area_write(fap, fap->fa_size - sizeof(bit), &bit, sizeof(bit));
TEST_ASSERT(rc == 0);
- rc = boot_vect_write_test(&hdr1.ih_ver);
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
TEST_ASSERT(rc == 0);
/* First boot should use the test image. */
@@ -1021,6 +1003,7 @@ TEST_CASE(boot_test_vb_ns_11)
boot_test_util_verify_flash(&hdr0, 0, &hdr1, 1);
boot_test_util_verify_status_clear();
+ boot_vect_write_main();
}
}
@@ -1029,29 +1012,45 @@ TEST_CASE(boot_test_no_hash)
struct boot_rsp rsp;
int rc;
- struct image_header hdr = {
+ struct image_header hdr0 = {
.ih_magic = IMAGE_MAGIC,
- .ih_tlv_size = 0,
+ .ih_tlv_size = 4 + 32,
.ih_hdr_size = BOOT_TEST_HEADER_SIZE,
.ih_img_size = 12 * 1024,
- .ih_flags = 0,
+ .ih_flags = IMAGE_F_SHA256,
.ih_ver = { 0, 2, 3, 4 },
};
+ struct image_header hdr1 = {
+ .ih_magic = IMAGE_MAGIC,
+ .ih_tlv_size = 0,
+ .ih_hdr_size = BOOT_TEST_HEADER_SIZE,
+ .ih_img_size = 32 * 1024,
+ .ih_flags = 0,
+ .ih_ver = { 1, 2, 3, 432 },
+ };
struct boot_req req = {
.br_area_descs = boot_test_area_descs,
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
- boot_test_util_write_image(&hdr, 0);
+ boot_test_util_write_image(&hdr0, 0);
+ boot_test_util_write_hash(&hdr0, 0);
+ boot_test_util_write_image(&hdr1, 1);
+
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
+ TEST_ASSERT(rc == 0);
rc = boot_go(&req, &rsp);
- TEST_ASSERT(rc != 0);
+ TEST_ASSERT(rc == 0);
- boot_test_util_verify_flash(&hdr, 0, NULL, 0xff);
+ TEST_ASSERT(memcmp(rsp.br_hdr, &hdr0, sizeof hdr0) == 0);
+
+ boot_test_util_verify_flash(&hdr0, 0, NULL, 0xff);
boot_test_util_verify_status_clear();
}
@@ -1060,30 +1059,46 @@ TEST_CASE(boot_test_no_flag_has_hash)
struct boot_rsp rsp;
int rc;
- struct image_header hdr = {
+ struct image_header hdr0 = {
.ih_magic = IMAGE_MAGIC,
.ih_tlv_size = 4 + 32,
.ih_hdr_size = BOOT_TEST_HEADER_SIZE,
.ih_img_size = 12 * 1024,
- .ih_flags = 0,
+ .ih_flags = IMAGE_F_SHA256,
.ih_ver = { 0, 2, 3, 4 },
};
+ struct image_header hdr1 = {
+ .ih_magic = IMAGE_MAGIC,
+ .ih_tlv_size = 4 + 32,
+ .ih_hdr_size = BOOT_TEST_HEADER_SIZE,
+ .ih_img_size = 32 * 1024,
+ .ih_flags = 0,
+ .ih_ver = { 1, 2, 3, 432 },
+ };
struct boot_req req = {
.br_area_descs = boot_test_area_descs,
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
boot_test_util_init_flash();
- boot_test_util_write_image(&hdr, 0);
- boot_test_util_write_hash(&hdr, 0);
+ boot_test_util_write_image(&hdr0, 0);
+ boot_test_util_write_hash(&hdr0, 0);
+ boot_test_util_write_image(&hdr1, 1);
+ boot_test_util_write_hash(&hdr1, 1);
+
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
+ TEST_ASSERT(rc == 0);
rc = boot_go(&req, &rsp);
- TEST_ASSERT(rc != 0);
+ TEST_ASSERT(rc == 0);
- boot_test_util_verify_flash(&hdr, 0, NULL, 0xff);
+ TEST_ASSERT(memcmp(rsp.br_hdr, &hdr0, sizeof hdr0) == 0);
+
+ boot_test_util_verify_flash(&hdr0, 0, NULL, 0xff);
boot_test_util_verify_status_clear();
}
@@ -1092,7 +1107,7 @@ TEST_CASE(boot_test_invalid_hash)
struct boot_rsp rsp;
int rc;
- struct image_header hdr = {
+ struct image_header hdr0 = {
.ih_magic = IMAGE_MAGIC,
.ih_tlv_size = 4 + 32,
.ih_hdr_size = BOOT_TEST_HEADER_SIZE,
@@ -1100,12 +1115,21 @@ TEST_CASE(boot_test_invalid_hash)
.ih_flags = IMAGE_F_SHA256,
.ih_ver = { 0, 2, 3, 4 },
};
+ struct image_header hdr1 = {
+ .ih_magic = IMAGE_MAGIC,
+ .ih_tlv_size = 4 + 32,
+ .ih_hdr_size = BOOT_TEST_HEADER_SIZE,
+ .ih_img_size = 32 * 1024,
+ .ih_flags = 0,
+ .ih_ver = { 1, 2, 3, 432 },
+ };
struct boot_req req = {
.br_area_descs = boot_test_area_descs,
.br_slot_areas = boot_test_slot_areas,
.br_num_image_areas = BOOT_TEST_AREA_IDX_SCRATCH + 1,
.br_scratch_area_idx = BOOT_TEST_AREA_IDX_SCRATCH,
+ .br_img_sz = (384 * 1024),
};
struct image_tlv tlv = {
@@ -1113,16 +1137,23 @@ TEST_CASE(boot_test_invalid_hash)
.it_len = 32
};
boot_test_util_init_flash();
- boot_test_util_write_image(&hdr, 0);
- rc = hal_flash_write(boot_test_img_addrs[0].flash_id,
- boot_test_img_addrs[0].address + hdr.ih_hdr_size + hdr.ih_img_size,
+ boot_test_util_write_image(&hdr0, 0);
+ boot_test_util_write_hash(&hdr0, 0);
+ boot_test_util_write_image(&hdr1, 1);
+ rc = hal_flash_write(boot_test_img_addrs[1].flash_id,
+ boot_test_img_addrs[1].address + hdr1.ih_hdr_size + hdr1.ih_img_size,
&tlv, sizeof(tlv));
TEST_ASSERT(rc == 0);
+ rc = boot_vect_write_test(FLASH_AREA_IMAGE_1);
+ TEST_ASSERT(rc == 0);
+
rc = boot_go(&req, &rsp);
- TEST_ASSERT(rc != 0);
+ TEST_ASSERT(rc == 0);
- boot_test_util_verify_flash(&hdr, 0, NULL, 0xff);
+ TEST_ASSERT(memcmp(rsp.br_hdr, &hdr0, sizeof hdr0) == 0);
+
+ boot_test_util_verify_flash(&hdr0, 0, NULL, 0xff);
boot_test_util_verify_status_clear();
}
@@ -1156,9 +1187,11 @@ boot_test_all(void)
#ifdef MYNEWT_SELFTEST
int
-main(void)
+main(int argc, char **argv)
{
tu_config.tc_print_results = 1;
+ tu_parse_args(argc, argv);
+
tu_init();
boot_test_all();
diff --git a/libs/console/full/src/cons_tty.c b/libs/console/full/src/cons_tty.c
index 7dfd0b70..9c576e23 100644
--- a/libs/console/full/src/cons_tty.c
+++ b/libs/console/full/src/cons_tty.c
@@ -165,6 +165,9 @@ console_file_write(void *arg, const char *str, size_t cnt)
struct console_tty *ct = &console_tty;
int i;
+ if (!ct->ct_write_char) {
+ return cnt;
+ }
for (i = 0; i < cnt; i++) {
if (str[i] == '\n') {
ct->ct_write_char('\r');
@@ -200,13 +203,13 @@ console_read(char *str, int cnt, int *newline)
break;
}
- if ((i & (CONSOLE_RX_CHUNK - 1)) == (CONSOLE_RX_CHUNK - 1)) {
- /*
- * Make a break from blocking interrupts during the copy.
- */
- OS_EXIT_CRITICAL(sr);
- OS_ENTER_CRITICAL(sr);
- }
+ if ((i & (CONSOLE_RX_CHUNK - 1)) == (CONSOLE_RX_CHUNK - 1)) {
+ /*
+ * Make a break from blocking interrupts during the copy.
+ */
+ OS_EXIT_CRITICAL(sr);
+ OS_ENTER_CRITICAL(sr);
+ }
ch = console_pull_char(cr);
if (ch == '\n') {
diff --git a/libs/imgmgr/include/imgmgr/imgmgr.h b/libs/imgmgr/include/imgmgr/imgmgr.h
index d007e7f2..17c9e7f4 100644
--- a/libs/imgmgr/include/imgmgr/imgmgr.h
+++ b/libs/imgmgr/include/imgmgr/imgmgr.h
@@ -29,7 +29,7 @@
#define IMGMGR_NMGR_OP_CORELIST 6
#define IMGMGR_NMGR_OP_CORELOAD 7
-#define IMGMGR_NMGR_MAX_MSG 120
+#define IMGMGR_NMGR_MAX_MSG 400
#define IMGMGR_NMGR_MAX_NAME 64
#define IMGMGR_NMGR_MAX_VER 25 /* 255.255.65535.4294967295\0 */
diff --git a/libs/imgmgr/src/imgmgr.c b/libs/imgmgr/src/imgmgr.c
index 5e8539a1..ebdf1a81 100644
--- a/libs/imgmgr/src/imgmgr.c
+++ b/libs/imgmgr/src/imgmgr.c
@@ -28,6 +28,7 @@
#include <util/base64.h>
#include <bootutil/image.h>
+#include <bootutil/bootutil_misc.h>
#include "imgmgr/imgmgr.h"
#include "imgmgr_priv.h"
@@ -494,5 +495,8 @@ imgmgr_module_init(void)
rc = nmgr_group_register(&imgr_nmgr_group);
assert(rc == 0);
+
+ boot_vect_write_main();
+
return rc;
}
diff --git a/libs/imgmgr/src/imgmgr_boot.c b/libs/imgmgr/src/imgmgr_boot.c
index e678b74b..f636a5e1 100644
--- a/libs/imgmgr/src/imgmgr_boot.c
+++ b/libs/imgmgr/src/imgmgr_boot.c
@@ -63,6 +63,7 @@ imgr_boot_read(struct nmgr_jbuf *njb)
{
int rc;
struct json_encoder *enc;
+ int slot;
struct image_version ver;
struct json_value jv;
uint8_t hash[IMGMGR_HASH_LEN];
@@ -71,14 +72,20 @@ imgr_boot_read(struct nmgr_jbuf *njb)
json_encode_object_start(enc);
- rc = boot_vect_read_test(&ver);
+ rc = boot_vect_read_test(&slot);
if (!rc) {
- imgr_ver_jsonstr(enc, "test", &ver);
+ rc = imgr_read_info(slot, &ver, hash);
+ if (!rc) {
+ imgr_ver_jsonstr(enc, "test", &ver);
+ }
}
- rc = boot_vect_read_main(&ver);
+ rc = boot_vect_read_main(&slot);
if (!rc) {
- imgr_ver_jsonstr(enc, "main", &ver);
+ rc = imgr_read_info(slot, &ver, hash);
+ if (!rc) {
+ imgr_ver_jsonstr(enc, "main", &ver);
+ }
}
rc = imgr_read_info(bsp_imgr_current_slot(), &ver, hash);
@@ -132,12 +139,11 @@ imgr_boot_write(struct nmgr_jbuf *njb)
rc = NMGR_ERR_EINVAL;
goto err;
}
- rc = boot_vect_write_test(&ver);
+ rc = boot_vect_write_test(rc);
if (rc) {
rc = NMGR_ERR_EINVAL;
goto err;
}
-
enc = &njb->njb_enc;
json_encode_object_start(enc);
@@ -162,22 +168,23 @@ imgr_boot2_read(struct nmgr_jbuf *njb)
struct image_version ver;
struct json_value jv;
uint8_t hash[IMGMGR_HASH_LEN];
+ int slot;
enc = &njb->njb_enc;
json_encode_object_start(enc);
- rc = boot_vect_read_test(&ver);
+ rc = boot_vect_read_test(&slot);
if (!rc) {
- rc = imgr_find_by_ver(&ver, hash);
+ rc = imgr_read_info(slot, &ver, hash);
if (rc >= 0) {
imgr_hash_jsonstr(enc, "test", hash);
}
}
- rc = boot_vect_read_main(&ver);
+ rc = boot_vect_read_main(&slot);
if (!rc) {
- rc = imgr_find_by_ver(&ver, hash);
+ rc = imgr_read_info(slot, &ver, hash);
if (rc >= 0) {
imgr_hash_jsonstr(enc, "main", hash);
}
@@ -226,11 +233,12 @@ imgr_boot2_write(struct nmgr_jbuf *njb)
base64_decode(hash_str, hash);
rc = imgr_find_by_hash(hash, &ver);
if (rc >= 0) {
- rc = boot_vect_write_test(&ver);
+ rc = boot_vect_write_test(rc);
if (rc) {
rc = NMGR_ERR_EUNKNOWN;
goto err;
}
+ rc = 0;
} else {
rc = NMGR_ERR_EINVAL;
goto err;
diff --git a/libs/inet_def_service/include/inet_def_service/inet_def_service.h b/libs/inet_def_service/include/inet_def_service/inet_def_service.h
new file mode 100644
index 00000000..6b219fe4
--- /dev/null
+++ b/libs/inet_def_service/include/inet_def_service/inet_def_service.h
@@ -0,0 +1,25 @@
+/**
+ * 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 __INET_DEF_SERVICE_H__
+#define __INET_DEF_SERVICE_H__
+
+int inet_def_service_init(uint8_t prio, os_stack_t *stack, uint16_t stack_sz);
+
+#endif /* __INET_DEF_SERVICE_H__ */
diff --git a/libs/inet_def_service/pkg.yml b/libs/inet_def_service/pkg.yml
new file mode 100644
index 00000000..103b0d54
--- /dev/null
+++ b/libs/inet_def_service/pkg.yml
@@ -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.
+#
+
+pkg.name: libs/inet_def_service
+pkg.description: INET services chargen, discard and echo
+pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - socket
+ - inet
+ - test
+
+pkg.deps:
+ - sys/mn_socket
+ - libs/os
+ - libs/util
+ - libs/testutil
+
+pkg.reqs:
+ - console
+
+pkg.features:
diff --git a/libs/inet_def_service/src/inet_def_service.c b/libs/inet_def_service/src/inet_def_service.c
new file mode 100644
index 00000000..fd756bf3
--- /dev/null
+++ b/libs/inet_def_service/src/inet_def_service.c
@@ -0,0 +1,333 @@
+/**
+ * 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>
+#include <os/endian.h>
+#include <mn_socket/mn_socket.h>
+#include <console/console.h>
+
+#include "inet_def_service/inet_def_service.h"
+
+#define ECHO_PORT 7
+#define DISCARD_PORT 9
+#define CHARGEN_PORT 19
+
+enum inet_def_type {
+ INET_DEF_ECHO = 0,
+ INET_DEF_DISCARD,
+ INET_DEF_CHARGEN,
+ INET_DEF_MAXTYPE
+};
+
+#define INET_DEF_FROM_EVENT_TYPE(a) ((a) - OS_EVENT_T_PERUSER)
+#define INET_EVENT_TYPE_FROM_DEF(a) ((a) + OS_EVENT_T_PERUSER)
+
+#define CHARGEN_WRITE_SZ 512
+static const char chargen_pattern[] = "1234567890";
+#define CHARGEN_PATTERN_SZ (sizeof(chargen_pattern) - 1)
+
+static struct os_task inet_def_task;
+static struct os_eventq inet_def_evq;
+
+/*
+ * UDP service.
+ */
+struct inet_def_udp {
+ struct os_event ev; /* Datagram RX reported via event */
+ struct mn_socket *socket;
+ uint32_t pkt_cnt;
+};
+
+/*
+ * Connected TCP socket.
+ */
+struct inet_def_tcp {
+ struct os_event ev; /* Data RX reported with this event */
+ SLIST_ENTRY(inet_def_tcp) list;
+ struct mn_socket *socket;
+ int closed;
+};
+
+/*
+ * TCP service.
+ */
+struct inet_def_listen {
+ struct mn_socket *socket;
+ uint32_t conn_cnt;
+};
+
+static struct inet_def {
+ struct inet_def_listen tcp_service[INET_DEF_MAXTYPE];
+ struct inet_def_udp udp_service[INET_DEF_MAXTYPE];
+ SLIST_HEAD(, inet_def_tcp) tcp_conns; /* List of connected TCP sockets */
+} inet_def;
+
+/*
+ * UDP socket callbacks. Called in context of IP stack task.
+ */
+static void
+inet_def_udp_readable(void *arg, int err)
+{
+ struct inet_def_udp *idu = (struct inet_def_udp *)arg;
+
+ os_eventq_put(&inet_def_evq, &idu->ev);
+}
+
+static const union mn_socket_cb inet_udp_cbs = {
+ .socket.readable = inet_def_udp_readable,
+};
+
+/*
+ * TCP socket callbacks. Called in context of IP stack task.
+ */
+static void
+inet_def_tcp_readable(void *arg, int err)
+{
+ struct inet_def_tcp *idt = (struct inet_def_tcp *)arg;
+
+ if (err) {
+ idt->closed = 1;
+ /*
+ * No locking here. Assuming new connection notifications, as well as
+ * close notifications arrive in context of a single task.
+ */
+ SLIST_REMOVE(&inet_def.tcp_conns, idt, inet_def_tcp, list);
+ }
+ os_eventq_put(&inet_def_evq, &idt->ev);
+}
+
+static const union mn_socket_cb inet_tcp_cbs = {
+ .socket.readable = inet_def_tcp_readable,
+ .socket.writable = inet_def_tcp_readable /* we want the same behavior */
+};
+
+/*
+ * Callback for new connection for TCP listen socket.
+ */
+static int inet_def_newconn(void *arg, struct mn_socket *new)
+{
+ struct inet_def_listen *idl = (struct inet_def_listen *)arg;
+ struct inet_def_tcp *idt;
+ enum inet_def_type type;
+
+ idt = (struct inet_def_tcp *)os_malloc(sizeof(*idt));
+ if (!idt) {
+ return -1;
+ }
+
+ memset(idt, 0, sizeof(*idt));
+ idt->socket = new;
+
+ /*
+ * Event type tells what type of service this connection belongs to.
+ * Ev_arg says whether it's TCP or UDP.
+ */
+ type = idl - &inet_def.tcp_service[0];
+ idt->ev.ev_type = INET_EVENT_TYPE_FROM_DEF(type);
+ idt->ev.ev_arg = (void *)MN_SOCK_STREAM;
+ mn_socket_set_cbs(new, idt, &inet_tcp_cbs);
+ SLIST_INSERT_HEAD(&inet_def.tcp_conns, idt, list);
+
+ if (type == INET_DEF_CHARGEN) {
+ /*
+ * Start transmitting right away.
+ */
+ os_eventq_put(&inet_def_evq, &idt->ev);
+ }
+ return 0;
+}
+
+static const union mn_socket_cb inet_listen_cbs = {
+ .listen.newconn = inet_def_newconn,
+};
+
+static int
+inet_def_create_srv(enum inet_def_type idx, uint16_t port)
+{
+ struct mn_socket *ms;
+ struct mn_sockaddr_in msin;
+
+ memset(&msin, 0, sizeof(msin));
+ msin.msin_len = sizeof(msin);
+ msin.msin_family = MN_AF_INET;
+ msin.msin_port = htons(port);
+
+ /*
+ * Create TCP listen socket for service.
+ */
+ if (mn_socket(&ms, MN_PF_INET, MN_SOCK_STREAM, 0)) {
+ goto err;
+ }
+ inet_def.tcp_service[idx].socket = ms;
+ mn_socket_set_cbs(ms, &inet_def.tcp_service[idx], &inet_listen_cbs);
+
+ if (mn_bind(ms, (struct mn_sockaddr *)&msin)) {
+ goto err;
+ }
+ if (mn_listen(ms, 1)) {
+ goto err;
+ }
+
+ /*
+ * Create UDP socket for service.
+ */
+ if (mn_socket(&ms, MN_PF_INET, MN_SOCK_DGRAM, 0)) {
+ goto err;
+ }
+ inet_def.udp_service[idx].socket = ms;
+ mn_socket_set_cbs(ms, &inet_def.udp_service[idx], &inet_udp_cbs);
+
+ if (mn_bind(ms, (struct mn_sockaddr *)&msin)) {
+ goto err;
+ }
+
+ return 0;
+err:
+ if (inet_def.tcp_service[idx].socket) {
+ mn_close(inet_def.tcp_service[idx].socket);
+ inet_def.tcp_service[idx].socket = NULL;
+ }
+ if (inet_def.udp_service[idx].socket) {
+ mn_close(inet_def.udp_service[idx].socket);
+ inet_def.udp_service[idx].socket = NULL;
+ }
+ return -1;
+}
+
+static void
+inet_def_srv(void *arg)
+{
+ struct inet_def_udp *idu;
+ struct inet_def_tcp *idt;
+ struct mn_socket *sock;
+ struct os_event *ev;
+ struct mn_sockaddr_in msin;
+ struct os_mbuf *m;
+ enum inet_def_type type;
+ int rc;
+ int off;
+ int loop_cnt;
+
+ inet_def_create_srv(INET_DEF_ECHO, ECHO_PORT);
+ inet_def_create_srv(INET_DEF_DISCARD, DISCARD_PORT);
+ inet_def_create_srv(INET_DEF_CHARGEN, CHARGEN_PORT);
+
+ while (1) {
+ /*
+ * Wait here. When event comes, check what type of socket got it,
+ * and then act on it.
+ */
+ ev = os_eventq_get(&inet_def_evq);
+ type = INET_DEF_FROM_EVENT_TYPE(ev->ev_type);
+ idt = (struct inet_def_tcp *)ev;
+ idu = (struct inet_def_udp *)ev;
+ if ((int)ev->ev_arg == MN_SOCK_DGRAM) {
+ sock = idu->socket;
+ } else {
+ sock = idt->socket;
+ }
+ switch (type) {
+ case INET_DEF_ECHO:
+ while (mn_recvfrom(sock, &m, (struct mn_sockaddr *)&msin) == 0) {
+ console_printf("echo %d bytes\n", OS_MBUF_PKTLEN(m));
+ rc = mn_sendto(sock, m, (struct mn_sockaddr *)&msin);
+ if (rc) {
+ console_printf(" failed: %d!!!!\n", rc);
+ os_mbuf_free_chain(m);
+ }
+ }
+ break;
+ case INET_DEF_DISCARD:
+ while (mn_recvfrom(sock, &m, NULL) == 0) {
+ console_printf("discard %d bytes\n", OS_MBUF_PKTLEN(m));
+ os_mbuf_free_chain(m);
+ }
+ break;
+ case INET_DEF_CHARGEN:
+ while (mn_recvfrom(sock, &m, NULL) == 0) {
+ os_mbuf_free_chain(m);
+ }
+ if ((int)ev->ev_arg == MN_SOCK_STREAM && idt->closed) {
+ /*
+ * Don't try to send tons of data to a closed socket.
+ */
+ break;
+ }
+ loop_cnt = 0;
+ do {
+ m = os_msys_get(CHARGEN_WRITE_SZ, 0);
+ if (m) {
+ for (off = 0;
+ OS_MBUF_TRAILINGSPACE(m) >= CHARGEN_PATTERN_SZ;
+ off += CHARGEN_PATTERN_SZ) {
+ os_mbuf_copyinto(m, off, chargen_pattern,
+ CHARGEN_PATTERN_SZ);
+ }
+ console_printf("chargen %d bytes\n", m->om_len);
+ rc = mn_sendto(sock, m, NULL); /* assumes TCP for now */
+ if (rc) {
+ os_mbuf_free_chain(m);
+ if (rc != MN_ENOBUFS && rc != MN_EAGAIN) {
+ console_write(" sendto fail!!! %d\n", rc);
+ }
+ break;
+ }
+ } else {
+ /*
+ * Mbuf shortage. Wait for them to appear.
+ */
+ os_time_delay(1);
+ }
+ loop_cnt++;
+ } while (loop_cnt < 32);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ if ((int)ev->ev_arg == MN_SOCK_STREAM && idt->closed) {
+ /*
+ * Remote end has closed the connection, as indicated in the
+ * callback. Close the socket and free the memory.
+ */
+ mn_socket_set_cbs(idt->socket, NULL, NULL);
+ os_eventq_remove(&inet_def_evq, &idt->ev);
+ mn_close(idt->socket);
+ os_free(idt);
+ }
+ }
+}
+
+int
+inet_def_service_init(uint8_t prio, os_stack_t *stack, uint16_t stack_sz)
+{
+ int i;
+
+ os_eventq_init(&inet_def_evq);
+ SLIST_INIT(&inet_def.tcp_conns);
+ for (i = 0; i < 3; i++) {
+ inet_def.udp_service[i].ev.ev_type = INET_EVENT_TYPE_FROM_DEF(i);
+ inet_def.udp_service[i].ev.ev_arg = (void *)MN_SOCK_DGRAM;
+ }
+ return os_task_init(&inet_def_task, "inet_def_task",
+ inet_def_srv, NULL, prio, OS_WAIT_FOREVER, stack, stack_sz);
+}
+
diff --git a/libs/mbedtls/include/mbedtls/config_mynewt.h b/libs/mbedtls/include/mbedtls/config_mynewt.h
index d200879c..a18ac6f7 100644
--- a/libs/mbedtls/include/mbedtls/config_mynewt.h
+++ b/libs/mbedtls/include/mbedtls/config_mynewt.h
@@ -40,6 +40,8 @@
#undef MBEDTLS_SELF_TEST
#endif
+#define MBEDTLS_SHA256_SMALLER /* comes with performance hit */
+
/**
* \name SECTION: Module configuration options
*
diff --git a/libs/newtmgr/pkg.yml b/libs/newtmgr/pkg.yml
index 6b8435d9..a0e75a23 100644
--- a/libs/newtmgr/pkg.yml
+++ b/libs/newtmgr/pkg.yml
@@ -32,5 +32,8 @@ pkg.deps:
- libs/shell
- sys/reboot
+pkg.deps.BLE_HOST:
+ - libs/newtmgr/transport/ble
+
pkg.features:
- - NEWTMGR
+ - NEWTMGR
diff --git a/libs/newtmgr/src/newtmgr.c b/libs/newtmgr/src/newtmgr.c
index c3bc6141..d15b4b9a 100644
--- a/libs/newtmgr/src/newtmgr.c
+++ b/libs/newtmgr/src/newtmgr.c
@@ -472,7 +472,6 @@ nmgr_handle_req(struct nmgr_transport *nt, struct os_mbuf *req)
rsp_hdr->nh_len = htons(rsp_hdr->nh_len);
rsp_hdr->nh_group = htons(rsp_hdr->nh_group);
- rsp_hdr->nh_id = htons(rsp_hdr->nh_id);
off += sizeof(hdr) + OS_ALIGN(hdr.nh_len, 4);
}
diff --git a/libs/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h b/libs/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h
new file mode 100644
index 00000000..a320eaab
--- /dev/null
+++ b/libs/newtmgr/transport/ble/include/nmgrble/newtmgr_ble.h
@@ -0,0 +1,28 @@
+/**
+ * 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 _NEWTMGR_BLE_H_
+#define _NEWTMGR_BLE_H_
+
+int
+nmgr_ble_proc_mq_evt(struct os_event *ev);
+int
+nmgr_ble_gatt_svr_init(struct os_eventq *evq, struct ble_hs_cfg *cfg);
+
+#endif /* _NETMGR_H */
diff --git a/libs/newtmgr/transport/ble/pkg.yml b/libs/newtmgr/transport/ble/pkg.yml
new file mode 100644
index 00000000..9ab9d4e5
--- /dev/null
+++ b/libs/newtmgr/transport/ble/pkg.yml
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+pkg.name: libs/newtmgr/transport/ble
+pkg.description: BLE transport newtmgr functionality.
+pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+
+pkg.deps:
+ - libs/os
+ - net/nimble
diff --git a/libs/newtmgr/transport/ble/src/newtmgr_ble.c b/libs/newtmgr/transport/ble/src/newtmgr_ble.c
new file mode 100644
index 00000000..716a974e
--- /dev/null
+++ b/libs/newtmgr/transport/ble/src/newtmgr_ble.c
@@ -0,0 +1,237 @@
+/**
+ * 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 <stdio.h>
+#include <string.h>
+#include "host/ble_hs.h"
+#include <newtmgr/newtmgr.h>
+#include <os/endian.h>
+
+/* nmgr ble mqueue */
+struct os_mqueue ble_nmgr_mq;
+
+/* ble nmgr transport */
+struct nmgr_transport ble_nt;
+
+/* ble nmgr attr handle */
+uint16_t g_ble_nmgr_attr_handle;
+
+struct os_eventq *app_evq;
+/**
+ * The vendor specific "newtmgr" service consists of one write no-rsp
+ * characteristic for newtmgr requests: a single-byte characteristic that can
+ * only accepts write-without-response commands. The contents of each write
+ * command contains an NMP request. NMP responses are sent back in the form of
+ * unsolicited notifications from the same characteristic.
+ */
+
+/* {8D53DC1D-1DB7-4CD3-868B-8A527460AA84} */
+const uint8_t gatt_svr_svc_newtmgr[16] = {
+ 0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86,
+ 0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d
+};
+
+/* {DA2E7828-FBCE-4E01-AE9E-261174997C48} */
+const uint8_t gatt_svr_chr_newtmgr[16] = {
+ 0x48, 0x7c, 0x99, 0x74, 0x11, 0x26, 0x9e, 0xae,
+ 0x01, 0x4e, 0xce, 0xfb, 0x28, 0x78, 0x2e, 0xda
+};
+
+static int
+gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+ {
+ /* Service: newtmgr */
+ .type = BLE_GATT_SVC_TYPE_PRIMARY,
+ .uuid128 = (void *)gatt_svr_svc_newtmgr,
+ .characteristics = (struct ble_gatt_chr_def[]) { {
+ /* Characteristic: Write No Rsp */
+ .uuid128 = (void *)gatt_svr_chr_newtmgr,
+ .access_cb = gatt_svr_chr_access_newtmgr,
+ .flags = BLE_GATT_CHR_F_WRITE_NO_RSP,
+ .val_handle = &g_ble_nmgr_attr_handle,
+ }, {
+ 0, /* No more characteristics in this service */
+ } },
+ },
+
+ {
+ 0, /* No more services */
+ },
+};
+
+static int
+gatt_svr_chr_access_newtmgr(uint16_t conn_handle, uint16_t attr_handle,
+ struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+ int rc;
+ struct os_mbuf *m_req;
+
+ switch (ctxt->op) {
+ case BLE_GATT_ACCESS_OP_WRITE_CHR:
+ /* Try to reuse the BLE packet mbuf as the newtmgr request. This
+ * requires a two-byte usrhdr to hold the BLE connection handle so
+ * that the newtmgr response can be sent to the correct peer. If
+ * it is not possible to reuse the mbuf, then allocate a new one
+ * and copy the request contents.
+ */
+ if (OS_MBUF_USRHDR_LEN(ctxt->om) >= sizeof (conn_handle)) {
+ /* Sufficient usrhdr space already present. */
+ m_req = ctxt->om;
+ ctxt->om = NULL;
+ } else if (OS_MBUF_LEADINGSPACE(ctxt->om) >=
+ sizeof (conn_handle)) {
+
+ /* Usrhdr isn't present, but there is enough leading space to
+ * add one.
+ */
+ m_req = ctxt->om;
+ ctxt->om = NULL;
+
+ m_req->om_pkthdr_len += sizeof (conn_handle);
+ } else {
+ /* The mbuf can't be reused. Allocate a new one and perform a
+ * copy. Don't set ctxt->om to NULL; let the NimBLE host free
+ * it.
+ */
+ m_req = os_msys_get_pkthdr(OS_MBUF_PKTLEN(ctxt->om),
+ sizeof (conn_handle));
+ if (!m_req) {
+ return BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+ rc = os_mbuf_appendfrom(m_req, ctxt->om, 0,
+ OS_MBUF_PKTLEN(ctxt->om));
+ if (rc) {
+ return BLE_ATT_ERR_INSUFFICIENT_RES;
+ }
+ }
+
+ /* Write the connection handle to the newtmgr request usrhdr. This
+ * is necessary so that we later know who to send the newtmgr
+ * response to.
+ */
+ memcpy(OS_MBUF_USRHDR(m_req), &conn_handle, sizeof(conn_handle));
+
+ rc = nmgr_rx_req(&ble_nt, m_req);
+ if (rc != 0) {
+ return BLE_ATT_ERR_UNLIKELY;
+ }
+ return 0;
+
+ default:
+ assert(0);
+ return BLE_ATT_ERR_UNLIKELY;
+ }
+}
+
+/**
+ * Nmgr ble process mqueue event
+ * Gets an event from the nmgr mqueue and does a notify with the response
+ *
+ * @param eventq
+ * @return 0 on success; non-zero on failure
+ */
+
+int
+nmgr_ble_proc_mq_evt(struct os_event *ev)
+{
+ struct os_mbuf *m_resp;
+ uint16_t conn_handle;
+ int rc;
+
+ rc = 0;
+ switch (ev->ev_type) {
+ case OS_EVENT_T_MQUEUE_DATA:
+ if (ev->ev_arg != &ble_nmgr_mq) {
+ rc = -1;
+ goto done;
+ }
+
+ while (1) {
+ m_resp = os_mqueue_get(&ble_nmgr_mq);
+ if (!m_resp) {
+ break;
+ }
+ assert(OS_MBUF_USRHDR_LEN(m_resp) >= sizeof (conn_handle));
+ memcpy(&conn_handle, OS_MBUF_USRHDR(m_resp),
+ sizeof (conn_handle));
+ ble_gattc_notify_custom(conn_handle, g_ble_nmgr_attr_handle,
+ m_resp);
+ }
+ break;
+
+ default:
+ rc = -1;
+ goto done;
+ }
+
+done:
+ return rc;
+}
+
+static int
+nmgr_ble_out(struct nmgr_transport *nt, struct os_mbuf *m)
+{
+ int rc;
+
+ rc = os_mqueue_put(&ble_nmgr_mq, app_evq, m);
+ if (rc != 0) {
+ goto err;
+ }
+
+ return (0);
+err:
+ return (rc);
+}
+
+/**
+ * Nmgr ble GATT server initialization
+ *
+ * @param eventq
+ * @return 0 on success; non-zero on failure
+ */
+int
+nmgr_ble_gatt_svr_init(struct os_eventq *evq, struct ble_hs_cfg *cfg)
+{
+ int rc;
+
+ assert(evq != NULL);
+
+ rc = ble_gatts_count_cfg(gatt_svr_svcs, cfg);
+ if (rc != 0) {
+ goto err;
+ }
+
+ rc = ble_gatts_add_svcs(gatt_svr_svcs);
+ if (rc != 0) {
+ return rc;
+ }
+
+ app_evq = evq;
+
+ os_mqueue_init(&ble_nmgr_mq, &ble_nmgr_mq);
+
+ rc = nmgr_transport_init(&ble_nt, &nmgr_ble_out);
+
+err:
+ return rc;
+}
diff --git a/libs/os/include/os/arch/cortex_m0/os/os_arch.h b/libs/os/include/os/arch/cortex_m0/os/os_arch.h
index e986702a..1a83ba9b 100755
--- a/libs/os/include/os/arch/cortex_m0/os/os_arch.h
+++ b/libs/os/include/os/arch/cortex_m0/os/os_arch.h
@@ -6,7 +6,7 @@
* 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,
@@ -17,8 +17,8 @@
* under the License.
*/
-#ifndef _OS_ARCH_ARM_H
-#define _OS_ARCH_ARM_H
+#ifndef _OS_ARCH_ARM_H
+#define _OS_ARCH_ARM_H
#include <stdint.h>
#include <mcu/cortex_m0.h>
@@ -48,7 +48,7 @@ typedef uint32_t os_stack_t;
(OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
/* Enter a critical section, save processor state, and block interrupts */
-#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr())
+#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr())
/* Exit a critical section, restore processor state and unblock interrupts */
#define OS_EXIT_CRITICAL(__os_sr) (os_arch_restore_sr(__os_sr))
#define OS_ASSERT_CRITICAL() (assert(os_arch_in_critical()))
@@ -63,7 +63,7 @@ void os_arch_init(void);
uint32_t os_arch_start(void);
os_error_t os_arch_os_init(void);
os_error_t os_arch_os_start(void);
-void os_set_env(void);
+void os_set_env(os_stack_t *);
void os_arch_init_task_stack(os_stack_t *sf);
void os_default_irq_asm(void);
@@ -71,4 +71,4 @@ void os_default_irq_asm(void);
void os_bsp_systick_init(uint32_t os_ticks_per_sec, int prio);
void os_bsp_ctx_sw(void);
-#endif /* _OS_ARCH_X86_H */
+#endif /* _OS_ARCH_ARM_H */
diff --git a/libs/os/include/os/arch/cortex_m4/os/os_arch.h b/libs/os/include/os/arch/cortex_m4/os/os_arch.h
index 8c67f09f..9e43a7a2 100755
--- a/libs/os/include/os/arch/cortex_m4/os/os_arch.h
+++ b/libs/os/include/os/arch/cortex_m4/os/os_arch.h
@@ -6,7 +6,7 @@
* 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,
@@ -17,8 +17,8 @@
* under the License.
*/
-#ifndef _OS_ARCH_ARM_H
-#define _OS_ARCH_ARM_H
+#ifndef _OS_ARCH_ARM_H
+#define _OS_ARCH_ARM_H
#include <stdint.h>
#include "mcu/cortex_m4.h"
@@ -48,7 +48,7 @@ typedef uint32_t os_stack_t;
(OS_ALIGN((__nmemb), OS_STACK_ALIGNMENT))
/* Enter a critical section, save processor state, and block interrupts */
-#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr())
+#define OS_ENTER_CRITICAL(__os_sr) (__os_sr = os_arch_save_sr())
/* Exit a critical section, restore processor state and unblock interrupts */
#define OS_EXIT_CRITICAL(__os_sr) (os_arch_restore_sr(__os_sr))
#define OS_ASSERT_CRITICAL() (assert(os_arch_in_critical()))
@@ -63,7 +63,7 @@ void os_arch_init(void);
uint32_t os_arch_start(void);
os_error_t os_arch_os_init(void);
os_error_t os_arch_os_start(void);
-void os_set_env(void);
+void os_set_env(os_stack_t *);
void os_arch_init_task_stack(os_stack_t *sf);
void os_default_irq_asm(void);
@@ -72,4 +72,4 @@ void os_bsp_systick_init(uint32_t os_tick_per_sec, int prio);
void os_bsp_idle(os_time_t ticks);
void os_bsp_ctx_sw(void);
-#endif /* _OS_ARCH_X86_H */
+#endif /* _OS_ARCH_ARM_H */
diff --git a/libs/os/include/os/os_mbuf.h b/libs/os/include/os/os_mbuf.h
index 74b9548d..f3c48aeb 100644
--- a/libs/os/include/os/os_mbuf.h
+++ b/libs/os/include/os/os_mbuf.h
@@ -259,7 +259,8 @@ struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp,
/* Duplicate a mbuf from the pool */
struct os_mbuf *os_mbuf_dup(struct os_mbuf *m);
-struct os_mbuf * os_mbuf_off(struct os_mbuf *om, int off, int *out_off);
+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);
@@ -267,6 +268,9 @@ 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);
@@ -274,10 +278,14 @@ int os_mbuf_free(struct os_mbuf *mb);
int os_mbuf_free_chain(struct os_mbuf *om);
void os_mbuf_adj(struct os_mbuf *mp, int req_len);
-int os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data,
+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);
diff --git a/libs/os/include/os/os_mempool.h b/libs/os/include/os/os_mempool.h
index 6b0f24c1..a7316184 100644
--- a/libs/os/include/os/os_mempool.h
+++ b/libs/os/include/os/os_mempool.h
@@ -82,6 +82,9 @@ typedef uint64_t os_membuf_t;
os_error_t os_mempool_init(struct os_mempool *mp, int blocks, int block_size,
void *membuf, char *name);
+/* Checks if a memory block was allocated from the specified mempool. */
+int os_memblock_from(struct os_mempool *mp, void *block_addr);
+
/* Get a memory block from the pool */
void *os_memblock_get(struct os_mempool *mp);
diff --git a/libs/os/src/arch/cortex_m0/m0/HAL_CM0.s b/libs/os/src/arch/cortex_m0/m0/HAL_CM0.s
index 03d79577..de7d46c7 100644
--- a/libs/os/src/arch/cortex_m0/m0/HAL_CM0.s
+++ b/libs/os/src/arch/cortex_m0/m0/HAL_CM0.s
@@ -52,7 +52,6 @@ os_set_env:
.fnstart
.cantunwind
- MOV R0,SP /* Copy MSP to PSP */
MSR PSP,R0
LDR R0,=os_flags
LDRB R0,[R0]
diff --git a/libs/os/src/arch/cortex_m0/os_arch_arm.c b/libs/os/src/arch/cortex_m0/os_arch_arm.c
index 40b92549..ef1be4d6 100755
--- a/libs/os/src/arch/cortex_m0/os_arch_arm.c
+++ b/libs/os/src/arch/cortex_m0/os_arch_arm.c
@@ -6,7 +6,7 @@
* 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,
@@ -23,6 +23,8 @@
#include <hal/hal_os_tick.h>
#include <bsp/cmsis_nvic.h>
+#include "os_priv.h"
+
/*
* From HAL_CM0.s
*/
@@ -223,13 +225,6 @@ os_arch_os_init(void)
/* Set the SVC interrupt to priority 0 (highest configurable) */
NVIC_SetPriority(SVCall_IRQn, SVC_PRIO);
- /*
- * Set the os environment. This will set stack pointers and, based
- * on the contents of os_flags, will determine if the tasks run in
- * priviliged or un-privileged mode.
- */
- os_set_env();
-
/* Check if privileged or not */
if ((__get_CONTROL() & 1) == 0) {
os_arch_init();
@@ -273,17 +268,26 @@ static inline void svc_os_arch_start(void)
}
/**
- * Start the OS. First check to see if we are running with the correct stack
- * pointer set (PSP) and privilege mode (PRIV).
- *
- *
- * @return os_error_t
+ * Start the OS. First check to see if we are running with the correct stack
+ * pointer set (PSP) and privilege mode (PRIV).
+ *
+ * @return os_error_t
*/
os_error_t
os_arch_os_start(void)
{
os_error_t err;
+ /*
+ * Set the os environment. This will set stack pointers and, based
+ * on the contents of os_flags, will determine if the tasks run in
+ * priviliged or un-privileged mode.
+ *
+ * We switch to using "empty" part of idle task's stack until
+ * the svc_os_arch_start() executes SVC, and we will never return.
+ */
+ os_set_env(g_idle_task.t_stackptr - 1);
+
err = OS_ERR_IN_ISR;
if (__get_IPSR() == 0) {
/*
@@ -304,7 +308,7 @@ os_arch_os_start(void)
err = OS_ERR_PRIV;
break;
case 0x02:
- /*
+ /*
* We are running in Privileged Thread mode w/SP = PSP but we
* are supposed to be un-privileged.
*/
@@ -313,7 +317,7 @@ os_arch_os_start(void)
}
break;
case 0x03:
- /*
+ /*
* We are running in Unprivileged Thread mode w/SP = PSP but we
* are supposed to be privileged.
*/
diff --git a/libs/os/src/arch/cortex_m4/m4/HAL_CM4.s b/libs/os/src/arch/cortex_m4/m4/HAL_CM4.s
index c9ae1037..9c6ab521 100755
--- a/libs/os/src/arch/cortex_m4/m4/HAL_CM4.s
+++ b/libs/os/src/arch/cortex_m4/m4/HAL_CM4.s
@@ -52,7 +52,6 @@ os_set_env:
.fnstart
.cantunwind
- MOV R0,SP /* Copy MSP to PSP */
MSR PSP,R0
LDR R0,=os_flags
LDRB R0,[R0]
@@ -63,6 +62,7 @@ os_set_env:
.fnend
.size os_set_env, .-os_set_env
+
/*--------------------------- os_set_env ------------------------------------*/
diff --git a/libs/os/src/arch/cortex_m4/os_arch_arm.c b/libs/os/src/arch/cortex_m4/os_arch_arm.c
index 2bd084ab..48f69769 100755
--- a/libs/os/src/arch/cortex_m4/os_arch_arm.c
+++ b/libs/os/src/arch/cortex_m4/os_arch_arm.c
@@ -6,7 +6,7 @@
* 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,
@@ -23,6 +23,8 @@
#include <hal/hal_os_tick.h>
#include <bsp/cmsis_nvic.h>
+#include "os_priv.h"
+
/* Initial program status register */
#define INITIAL_xPSR 0x01000000
@@ -217,13 +219,6 @@ os_arch_os_init(void)
/* Set the SVC interrupt to priority 0 (highest configurable) */
NVIC_SetPriority(SVCall_IRQn, SVC_PRIO);
- /*
- * Set the os environment. This will set stack pointers and, based
- * on the contents of os_flags, will determine if the tasks run in
- * priviliged or un-privileged mode.
- */
- os_set_env();
-
/* Check if privileged or not */
if ((__get_CONTROL() & 1) == 0) {
os_arch_init();
@@ -267,17 +262,27 @@ static inline void svc_os_arch_start(void)
}
/**
- * Start the OS. First check to see if we are running with the correct stack
- * pointer set (PSP) and privilege mode (PRIV).
- *
- *
- * @return os_error_t
+ * Start the OS. First check to see if we are running with the correct stack
+ * pointer set (PSP) and privilege mode (PRIV).
+ *
+ *
+ * @return os_error_t
*/
os_error_t
os_arch_os_start(void)
{
os_error_t err;
+ /*
+ * Set the os environment. This will set stack pointers and, based
+ * on the contents of os_flags, will determine if the tasks run in
+ * privileged or un-privileged mode.
+ *
+ * We switch to using "empty" part of idle task's stack until
+ * the svc_os_arch_start() executes SVC, and we will never return.
+ */
+ os_set_env(g_idle_task.t_stackptr - 1);
+
err = OS_ERR_IN_ISR;
if (__get_IPSR() == 0) {
/*
@@ -298,7 +303,7 @@ os_arch_os_start(void)
err = OS_ERR_PRIV;
break;
case 0x02:
- /*
+ /*
* We are running in Privileged Thread mode w/SP = PSP but we
* are supposed to be un-privileged.
*/
@@ -307,7 +312,7 @@ os_arch_os_start(void)
}
break;
case 0x03:
- /*
+ /*
* We are running in Unprivileged Thread mode w/SP = PSP but we
* are supposed to be privileged.
*/
diff --git a/libs/os/src/arch/sim/os_arch_sim.c b/libs/os/src/arch/sim/os_arch_sim.c
index 287b4fc1..49705220 100644
--- a/libs/os/src/arch/sim/os_arch_sim.c
+++ b/libs/os/src/arch/sim/os_arch_sim.c
@@ -404,7 +404,7 @@ os_arch_os_init(void)
mypid = getpid();
g_current_task = NULL;
- TAILQ_INIT(&g_os_task_list);
+ STAILQ_INIT(&g_os_task_list);
TAILQ_INIT(&g_os_run_list);
TAILQ_INIT(&g_os_sleep_list);
diff --git a/libs/os/src/os.c b/libs/os/src/os.c
index 5ec71ec2..90f972ea 100644
--- a/libs/os/src/os.c
+++ b/libs/os/src/os.c
@@ -19,6 +19,7 @@
#include "os/os.h"
#include "os/queue.h"
+#include "os_priv.h"
#include "hal/hal_os_tick.h"
@@ -105,6 +106,9 @@ os_init(void)
{
os_error_t err;
+ TAILQ_INIT(&g_callout_list);
+ STAILQ_INIT(&g_os_task_list);
+
err = os_arch_os_init();
assert(err == OS_OK);
}
diff --git a/libs/os/src/os_callout.c b/libs/os/src/os_callout.c
index 02462c0b..bc36a195 100644
--- a/libs/os/src/os_callout.c
+++ b/libs/os/src/os_callout.c
@@ -18,12 +18,12 @@
*/
#include "os/os.h"
+#include "os_priv.h"
#include <assert.h>
#include <string.h>
-TAILQ_HEAD(, os_callout) g_callout_list =
- TAILQ_HEAD_INITIALIZER(g_callout_list);
+struct os_callout_list g_callout_list;
static void
_os_callout_init(struct os_callout *c, struct os_eventq *evq, void *ev_arg)
diff --git a/libs/os/src/os_eventq.c b/libs/os/src/os_eventq.c
index b3ff26f7..f9cc2837 100644
--- a/libs/os/src/os_eventq.c
+++ b/libs/os/src/os_eventq.c
@@ -117,6 +117,29 @@ pull_one:
return (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
@@ -137,6 +160,13 @@ os_eventq_poll(struct os_eventq **evq, int nevqs, os_time_t timo)
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);
@@ -147,8 +177,7 @@ os_eventq_poll(struct os_eventq **evq, int nevqs, os_time_t timo)
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
- */
+ /* Reset the items that already have an evq task set. */
for (j = 0; j < i; j++) {
evq[j]->evq_task = NULL;
}
diff --git a/libs/os/src/os_mbuf.c b/libs/os/src/os_mbuf.c
index 85232d88..a2302df7 100644
--- a/libs/os/src/os_mbuf.c
+++ b/libs/os/src/os_mbuf.c
@@ -37,6 +37,7 @@
#include <assert.h>
#include <string.h>
+#include <limits.h>
STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list =
STAILQ_HEAD_INITIALIZER(g_msys_pool_list);
@@ -509,6 +510,49 @@ 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.
@@ -576,26 +620,30 @@ err:
* NULL if the specified offset is out of bounds.
*/
struct os_mbuf *
-os_mbuf_off(struct os_mbuf *om, int off, int *out_off)
+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 (om == NULL) {
+ if (cur == NULL) {
return NULL;
}
- next = SLIST_NEXT(om, om_next);
+ next = SLIST_NEXT(cur, om_next);
- if (om->om_len > off ||
- (om->om_len == off && next == NULL)) {
+ if (cur->om_len > off ||
+ (cur->om_len == off && next == NULL)) {
*out_off = off;
- return om;
+ return cur;
}
- off -= om->om_len;
- om = next;
+ off -= cur->om_len;
+ cur = next;
}
}
@@ -739,14 +787,14 @@ os_mbuf_adj(struct os_mbuf *mp, int req_len)
*
* @return 0 if both memory regions are identical;
* A memcmp return code if there is a mismatch;
- * -1 if the mbuf is too short.
+ * INT_MAX if the mbuf is too short.
*/
int
-os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
+os_mbuf_cmpf(const struct os_mbuf *om, int off, const void *data, int len)
{
- int chunk_sz;
- int data_off;
- int om_off;
+ uint16_t chunk_sz;
+ uint16_t data_off;
+ uint16_t om_off;
int rc;
if (len <= 0) {
@@ -754,10 +802,10 @@ os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
}
data_off = 0;
- om = os_mbuf_off((struct os_mbuf *)om, off, &om_off);
+ om = os_mbuf_off(om, off, &om_off);
while (1) {
if (om == NULL) {
- return -1;
+ return INT_MAX;
}
chunk_sz = min(om->om_len - om_off, len - data_off);
@@ -777,12 +825,84 @@ os_mbuf_memcmp(const struct os_mbuf *om, int off, const void *data, int len)
om_off = 0;
if (om == NULL) {
- return -1;
+ 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;
+
+ 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
@@ -851,6 +971,33 @@ os_mbuf_prepend(struct os_mbuf *om, int len)
}
/**
+ * 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
@@ -870,8 +1017,8 @@ 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 cur_off;
int rc;
/* Find the mbuf,offset pair for the start of the destination. */
diff --git a/libs/os/src/os_mempool.c b/libs/os/src/os_mempool.c
index 1e7428ca..e940ba42 100644
--- a/libs/os/src/os_mempool.c
+++ b/libs/os/src/os_mempool.c
@@ -41,21 +41,29 @@ STAILQ_HEAD(, os_mempool) g_os_mempool_list =
* @return os_error_t
*/
os_error_t
-os_mempool_init(struct os_mempool *mp, int blocks, int block_size, void *membuf,
- char *name)
+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) || (!membuf) || (blocks <= 0) || (block_size <= 0)) {
+ if ((!mp) || (blocks < 0) || (block_size <= 0)) {
return OS_INVALID_PARM;
}
- /* 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;
+ 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_MEMPOOL_TRUE_BLOCK_SIZE(block_size);
@@ -86,6 +94,42 @@ os_mempool_init(struct os_mempool *mp, int blocks, int block_size, void *membuf,
}
/**
+ * 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(struct os_mempool *mp, 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->mp_block_size);
+ 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
@@ -135,9 +179,6 @@ os_error_t
os_memblock_put(struct os_mempool *mp, void *block_addr)
{
os_sr_t sr;
- uint32_t end;
- uint32_t true_block_size;
- uint32_t baddr32;
struct os_memblock *block;
/* Make sure parameters are valid */
@@ -146,23 +187,10 @@ os_memblock_put(struct os_mempool *mp, void *block_addr)
}
/* Check that the block we are freeing is a valid block! */
- baddr32 = (uint32_t)block_addr;
- true_block_size = OS_MEMPOOL_TRUE_BLOCK_SIZE(mp->mp_block_size);
- end = mp->mp_membuf_addr + (mp->mp_num_blocks * true_block_size);
- if ((baddr32 < mp->mp_membuf_addr) || (baddr32 >= end)) {
- return OS_INVALID_PARM;
- }
-
- /* All freed blocks should be on true block size boundaries! */
- if (((baddr32 - mp->mp_membuf_addr) % true_block_size) != 0) {
+ if (!os_memblock_from(mp, block_addr)) {
return OS_INVALID_PARM;
}
- /*
- * XXX: we should do boundary checks here! The block had better be within
- * the pool. If it fails, do we return an error or assert()? Add this when
- * we add the memory debug.
- */
block = (struct os_memblock *)block_addr;
OS_ENTER_CRITICAL(sr);
diff --git a/libs/os/src/os_priv.h b/libs/os/src/os_priv.h
index dfc9e384..b5c8f65e 100644
--- a/libs/os/src/os_priv.h
+++ b/libs/os/src/os_priv.h
@@ -6,7 +6,7 @@
* 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,
@@ -20,11 +20,17 @@
#ifndef H_OS_PRIV_
#define H_OS_PRIV_
+#include "os/queue.h"
+
TAILQ_HEAD(os_task_list, os_task);
+TAILQ_HEAD(os_callout_list, os_callout);
+STAILQ_HEAD(os_task_stailq, os_task);
+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_list g_os_task_list;
+extern struct os_task_stailq g_os_task_list;
extern struct os_task *g_current_task;
+extern struct os_callout_list g_callout_list;
#endif
diff --git a/libs/os/src/os_task.c b/libs/os/src/os_task.c
index 55c1da24..e48fdf97 100644
--- a/libs/os/src/os_task.c
+++ b/libs/os/src/os_task.c
@@ -19,12 +19,13 @@
#include "os/os.h"
+#include "os_priv.h"
#include <string.h>
uint8_t g_task_id;
-STAILQ_HEAD(, os_task) g_os_task_list = STAILQ_HEAD_INITIALIZER(g_os_task_list);
+struct os_task_stailq g_os_task_list;
static void
_clear_stack(os_stack_t *stack_bottom, int size)
diff --git a/libs/os/src/os_time.c b/libs/os/src/os_time.c
index 2ce379e8..4ef439f5 100644
--- a/libs/os/src/os_time.c
+++ b/libs/os/src/os_time.c
@@ -97,10 +97,14 @@ os_time_advance(int ticks)
assert(ticks >= 0);
if (ticks > 0) {
- os_time_tick(ticks);
- os_callout_tick();
- os_sched_os_timer_exp();
- os_sched(NULL);
+ if (!os_started()) {
+ g_os_time += ticks;
+ } else {
+ os_time_tick(ticks);
+ os_callout_tick();
+ os_sched_os_timer_exp();
+ os_sched(NULL);
+ }
}
}
diff --git a/libs/os/src/test/callout_test.c b/libs/os/src/test/callout_test.c
new file mode 100644
index 00000000..4e3811d7
--- /dev/null
+++ b/libs/os/src/test/callout_test.c
@@ -0,0 +1,330 @@
+/**
+ * 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 "testutil/testutil.h"
+#include "os/os.h"
+#include "os_test_priv.h"
+#include "os/os_eventq.h"
+#include "os/os_callout.h"
+#include "os/os_time.h"
+
+/* Task 1 for sending */
+#define CALLOUT_STACK_SIZE (5120)
+#define SEND_CALLOUT_TASK_PRIO (1)
+struct os_task callout_task_struct_send;
+os_stack_t callout_task_stack_send[CALLOUT_STACK_SIZE];
+
+#define RECEIVE_CALLOUT_TASK_PRIO (2)
+struct os_task callout_task_struct_receive;
+os_stack_t callout_task_stack_receive[CALLOUT_STACK_SIZE];
+
+/* Delearing variables for callout_func */
+struct os_callout_func callout_func_test;
+
+/* The event to be sent*/
+struct os_eventq callout_evq;
+struct os_event callout_ev;
+
+/* The callout_stop task */
+#define SEND_STOP_CALLOUT_TASK_PRIO (3)
+struct os_task callout_task_struct_stop_send;
+os_stack_t callout_task_stack_stop_send[CALLOUT_STACK_SIZE];
+
+#define RECEIVE_STOP_CALLOUT_TASK_PRIO (4)
+struct os_task callout_task_struct_stop_receive;
+os_stack_t callout_task_stack_stop_receive[CALLOUT_STACK_SIZE];
+
+/* Delearing variables for callout_stop_func */
+#define MULTI_SIZE (2)
+struct os_callout_func callout_func_stop_test[MULTI_SIZE];
+
+/* The event to be sent*/
+struct os_eventq callout_stop_evq[MULTI_SIZE];
+struct os_event callout_stop_ev;
+
+/* Declearing varables for callout_speak */
+#define SPEAK_CALLOUT_TASK_PRIO (5)
+struct os_task callout_task_struct_speak;
+os_stack_t callout_task_stack_speak[CALLOUT_STACK_SIZE];
+
+/* Declearing varaibles for listen */
+#define LISTEN_CALLOUT_TASK_PRIO (6)
+struct os_task callout_task_struct_listen;
+os_stack_t callout_task_stack_listen[CALLOUT_STACK_SIZE];
+
+struct os_callout_func callout_func_speak;
+
+/* Global variables to be used by the callout functions */
+int p;
+int q;
+int t;
+/* This is the function for callout_init*/
+void
+my_callout_func(void *arg)
+{
+ p = 4;
+}
+
+/* This is the function for callout_init of stop test_case*/
+void
+my_callout_stop_func(void *arg)
+{
+ q = 1;
+}
+/* This is the function for callout_init for speak test_case*/
+void
+my_callout_speak_func(void *arg)
+{
+ t = 2;
+}
+
+/* This is a callout task to send data */
+void
+callout_task_send(void *arg )
+{
+ int i;
+ /* Should say whether callout is armed or not */
+ i= os_callout_queued(&callout_func_test.cf_c);
+ TEST_ASSERT(i == 0);
+
+ /* Arm the callout */
+ i = os_callout_reset(&callout_func_test.cf_c, OS_TICKS_PER_SEC/ 50);
+ TEST_ASSERT_FATAL(i == 0);
+
+ /* Should say whether callout is armed or not */
+ i = os_callout_queued(&callout_func_test.cf_c);
+ TEST_ASSERT(i == 1);
+
+ /* Send the callout */
+ os_time_delay(OS_TICKS_PER_SEC );
+}
+
+/* This is the callout to receive data */
+void
+callout_task_receive( void *arg)
+{
+ int i;
+ struct os_event *event;
+ struct os_callout_func *callout;
+ os_time_t now;
+ os_time_t tm;
+ os_sr_t sr;
+ /* Recieve using the os_eventq_poll */
+ event = os_eventq_poll(&callout_func_test.cf_c.c_evq, 1, OS_WAIT_FOREVER);
+ TEST_ASSERT(event->ev_type == OS_EVENT_T_TIMER);
+ TEST_ASSERT(event->ev_arg == NULL);
+ callout = (struct os_callout_func *)event;
+ TEST_ASSERT(callout->cf_func == my_callout_func);
+
+ /* Should say whether callout is armed or not */
+ i = os_callout_queued(&callout_func_test.cf_c);
+ TEST_ASSERT(i == 0);
+
+ OS_ENTER_CRITICAL(sr);
+ now = os_time_get();
+ tm = os_callout_wakeup_ticks(now);
+ TEST_ASSERT(tm == OS_TIMEOUT_NEVER);
+ OS_EXIT_CRITICAL(sr);
+
+ /* Finishes the test when OS has been started */
+ os_test_restart();
+
+}
+
+/* This is callout to send the stop_callout */
+void
+callout_task_stop_send( void *arg)
+{
+ int k;
+ int j;
+ /* Should say whether callout is armed or not */
+ for(k = 0; k<MULTI_SIZE; k++){
+ j = os_callout_queued(&callout_func_stop_test[k].cf_c);
+ TEST_ASSERT(j == 0);
+ }
+
+
+ /* Show that callout is not armed after calling callout_stop */
+ for(k = 0; k<MULTI_SIZE; k++){
+ os_callout_stop(&callout_func_stop_test[k].cf_c);
+ j = os_callout_queued(&callout_func_stop_test[k].cf_c);
+ TEST_ASSERT(j == 0);
+ }
+ /* Arm the callout */
+ for(k = 0; k<MULTI_SIZE; k++){
+ j = os_callout_reset(&callout_func_stop_test[k].cf_c, OS_TICKS_PER_SEC/ 50);
+ TEST_ASSERT_FATAL(j == 0);
+ }
+ os_time_delay( OS_TICKS_PER_SEC );
+}
+
+/* This is the callout to receive stop_callout data */
+void
+callout_task_stop_receive( void *arg )
+{
+ int k;
+ struct os_event *event;
+ struct os_callout_func *callout;
+ /* Recieving using the os_eventq_poll */
+ for(k=0; k<MULTI_SIZE; k++){
+ event = os_eventq_poll(&callout_func_stop_test[k].cf_c.c_evq, 1,
+ OS_WAIT_FOREVER);
+ TEST_ASSERT(event->ev_type == OS_EVENT_T_TIMER);
+ TEST_ASSERT(event->ev_arg == NULL);
+ callout = (struct os_callout_func *)event;
+ TEST_ASSERT(callout->cf_func == my_callout_stop_func);
+
+
+ }
+
+ /* Show that event is removed from the queued after calling callout_stop */
+ for(k=0; k<MULTI_SIZE; k++){
+ os_callout_stop(&callout_func_stop_test[k].cf_c);
+ /* Testing that the event has been removed from queue */
+ TEST_ASSERT_FATAL(1);
+ }
+ /* Finishes the test when OS has been started */
+ os_test_restart();
+
+}
+
+/* This is a callout task to send data */
+void
+callout_task_stop_speak( void *arg )
+{
+ int i;
+ /* Arm the callout */
+ i = os_callout_reset(&callout_func_speak.cf_c, OS_TICKS_PER_SEC/ 50);
+ TEST_ASSERT_FATAL(i == 0);
+
+ /* should say whether callout is armed or not */
+ i = os_callout_queued(&callout_func_speak.cf_c);
+ TEST_ASSERT(i == 1);
+
+ os_callout_stop(&callout_func_speak.cf_c);
+
+ /* Send the callout */
+ os_time_delay(OS_TICKS_PER_SEC/ 100 );
+ /* Finishes the test when OS has been started */
+ os_test_restart();
+}
+
+void
+callout_task_stop_listen( void *arg )
+{
+ struct os_event *event;
+ struct os_callout_func *callout;
+ event = os_eventq_get(callout_func_speak.cf_c.c_evq);
+ TEST_ASSERT_FATAL(0);
+ callout = (struct os_callout_func *)event;
+ TEST_ASSERT(callout->cf_func == my_callout_speak_func);
+
+}
+
+/* Test case to test the basics of the callout */
+TEST_CASE(callout_test)
+{
+
+ /* Initializing the OS */
+ os_init();
+
+ /* Initialize the sending task */
+ os_task_init(&callout_task_struct_send, "callout_task_send",
+ callout_task_send, NULL, SEND_CALLOUT_TASK_PRIO, OS_WAIT_FOREVER,
+ callout_task_stack_send, CALLOUT_STACK_SIZE);
+
+ /* Initialize the receive task */
+ os_task_init(&callout_task_struct_receive, "callout_task_receive",
+ callout_task_receive, NULL, RECEIVE_CALLOUT_TASK_PRIO, OS_WAIT_FOREVER,
+ callout_task_stack_receive, CALLOUT_STACK_SIZE);
+
+ os_eventq_init(&callout_evq);
+
+ /* Initialize the callout function */
+ os_callout_func_init(&callout_func_test, &callout_evq,
+ my_callout_func, NULL);
+
+ /* Does not return until OS_restart is called */
+ os_start();
+}
+
+/* Test case of the callout_task_stop */
+TEST_CASE(callout_test_stop)
+{
+ int k;
+ /* Initializing the OS */
+ os_init();
+
+ /* Initialize the sending task */
+ os_task_init(&callout_task_struct_stop_send, "callout_task_stop_send",
+ callout_task_stop_send, NULL, SEND_STOP_CALLOUT_TASK_PRIO, OS_WAIT_FOREVER,
+ callout_task_stack_stop_send, CALLOUT_STACK_SIZE);
+
+ /* Initialize the receiving task */
+ os_task_init(&callout_task_struct_stop_receive, "callout_task_stop_receive",
+ callout_task_stop_receive, NULL, RECEIVE_STOP_CALLOUT_TASK_PRIO,
+ OS_WAIT_FOREVER, callout_task_stack_stop_receive, CALLOUT_STACK_SIZE);
+
+ for(k = 0; k< MULTI_SIZE; k++){
+ os_eventq_init(&callout_stop_evq[k]);
+ }
+
+ /* Initialize the callout function */
+ for(k = 0; k<MULTI_SIZE; k++){
+ os_callout_func_init(&callout_func_stop_test[k], &callout_stop_evq[k],
+ my_callout_stop_func, NULL);
+ }
+
+ /* Does not return until OS_restart is called */
+ os_start();
+
+}
+
+/* Test case to test case for speak and listen */
+TEST_CASE(callout_test_speak)
+{
+ /* Initializing the OS */
+ os_init();
+
+ /* Initialize the sending task */
+ os_task_init(&callout_task_struct_speak, "callout_task_speak",
+ callout_task_stop_speak, NULL, SPEAK_CALLOUT_TASK_PRIO, OS_WAIT_FOREVER,
+ callout_task_stack_speak, CALLOUT_STACK_SIZE);
+
+ /* Initialize the receive task */
+ os_task_init(&callout_task_struct_listen, "callout_task_listen",
+ callout_task_stop_listen, NULL, LISTEN_CALLOUT_TASK_PRIO, OS_WAIT_FOREVER,
+ callout_task_stack_listen, CALLOUT_STACK_SIZE);
+
+ os_eventq_init(&callout_evq);
+
+ /* Initialize the callout function */
+ os_callout_func_init(&callout_func_speak, &callout_evq,
+ my_callout_speak_func, NULL);
+ /* Does not return until OS_restart is called */
+ os_start();
+
+}
+
+TEST_SUITE(os_callout_test_suite)
+{
+ callout_test();
+ callout_test_stop();
+ callout_test_speak();
+}
diff --git a/libs/os/src/test/eventq_test.c b/libs/os/src/test/eventq_test.c
index 29e5fe30..cb1ed94b 100644
--- a/libs/os/src/test/eventq_test.c
+++ b/libs/os/src/test/eventq_test.c
@@ -17,21 +17,21 @@
* under the License.
*/
-
+#include <string.h>
#include "testutil/testutil.h"
#include "os/os.h"
#include "os_test_priv.h"
#include "os/os_eventq.h"
#define MY_STACK_SIZE (5120)
-
-/*Task 1 sending task*/
+#define POLL_STACK_SIZE (4096)
+/* Task 1 sending task */
/* Define task stack and task object */
#define SEND_TASK_PRIO (1)
struct os_task eventq_task_s;
os_stack_t eventq_task_stack_s[MY_STACK_SIZE];
-/*Task 2 receiving task*/
+/* Task 2 receiving task */
#define RECEIVE_TASK_PRIO (2)
struct os_task eventq_task_r;
os_stack_t eventq_task_stack_r[MY_STACK_SIZE];
@@ -48,6 +48,39 @@ struct os_event m_event[SIZE_MULTI_EVENT];
/* Setting the event to send and receive multiple data */
uint8_t my_event_type = 1;
+/* Setting up data for the poll */
+/* Define the task stack for the eventq_task_poll_send */
+#define SEND_TASK_POLL_PRIO (3)
+struct os_task eventq_task_poll_s;
+os_stack_t eventq_task_stack_poll_s[POLL_STACK_SIZE];
+
+/* Define the task stack for the eventq_task_poll_receive */
+#define RECEIVE_TASK_POLL_PRIO (4)
+struct os_task eventq_task_poll_r;
+os_stack_t eventq_task_stack_poll_r[POLL_STACK_SIZE ];
+
+/* Setting the data for the poll timeout */
+/* Define the task stack for the eventq_task_poll_timeout_send */
+#define SEND_TASK_POLL_TIMEOUT_PRIO (5)
+struct os_task eventq_task_poll_timeout_s;
+os_stack_t eventq_task_stack_poll_timeout_s[POLL_STACK_SIZE];
+
+/* Define the task stack for the eventq_task_poll_receive */
+#define RECEIVE_TASK_POLL_TIMEOUT_PRIO (6)
+struct os_task eventq_task_poll_timeout_r;
+os_stack_t eventq_task_stack_poll_timeout_r[POLL_STACK_SIZE];
+
+/* Setting the data for the poll single */
+/* Define the task stack for the eventq_task_poll_single_send */
+#define SEND_TASK_POLL_SINGLE_PRIO (7)
+struct os_task eventq_task_poll_single_s;
+os_stack_t eventq_task_stack_poll_single_s[POLL_STACK_SIZE];
+
+/* Define the task stack for the eventq_task_poll_single_receive */
+#define RECEIVE_TASK_POLL_SINGLE_PRIO (8)
+struct os_task eventq_task_poll_single_r;
+os_stack_t eventq_task_stack_poll_single_r[POLL_STACK_SIZE];
+
/* This is the task function to send data */
void
eventq_task_send(void *arg)
@@ -95,6 +128,138 @@ eventq_task_receive(void *arg)
os_test_restart();
}
+void
+eventq_task_poll_send(void *arg)
+{
+ struct os_eventq *eventqs[SIZE_MULTI_EVENT];
+ int i;
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ eventqs[i] = &multi_eventq[i];
+ }
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ m_event[i].ev_type = i + 10;
+ m_event[i].ev_arg = NULL;
+
+ /* Put and send */
+ os_eventq_put(eventqs[i], &m_event[i]);
+ os_time_delay(OS_TICKS_PER_SEC / 2);
+ }
+
+ /* This task sleeps until the receive task completes the test. */
+ os_time_delay(1000000);
+}
+
+void
+eventq_task_poll_receive(void *arg)
+{
+ struct os_eventq *eventqs[SIZE_MULTI_EVENT];
+ struct os_event *event;
+ int i;
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ eventqs[i] = &multi_eventq[i];
+ }
+
+ /* Recieving using the os_eventq_poll*/
+ for (i = 0; i < SIZE_MULTI_EVENT; i++) {
+ event = os_eventq_poll(eventqs, SIZE_MULTI_EVENT, OS_WAIT_FOREVER);
+ TEST_ASSERT(event->ev_type == i +10);
+ }
+
+ /* Finishes the test when OS has been started */
+ os_test_restart();
+
+}
+
+/* Sending with a time failure */
+void
+eventq_task_poll_timeout_send(void *arg)
+{
+ struct os_eventq *eventqs[SIZE_MULTI_EVENT];
+ int i;
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ eventqs[i] = &multi_eventq[i];
+ }
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ os_time_delay(1000);
+
+ /* Put and send */
+ os_eventq_put(eventqs[i], &m_event[i]);
+ os_time_delay(OS_TICKS_PER_SEC / 2);
+ }
+
+ /* This task sleeps until the receive task completes the test. */
+ os_time_delay(1000000);
+
+}
+
+/* Receiving multiple event queues with a time failure */
+void
+eventq_task_poll_timeout_receive(void *arg)
+{
+ struct os_eventq *eventqs[SIZE_MULTI_EVENT];
+ struct os_event *event;
+ int i;
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ eventqs[i] = &multi_eventq[i];
+ }
+
+ /* Recieving using the os_eventq_poll_timeout*/
+ for (i = 0; i < SIZE_MULTI_EVENT; i++) {
+ event = os_eventq_poll(eventqs, SIZE_MULTI_EVENT, 200);
+ TEST_ASSERT(event == NULL);
+ }
+
+ /* Finishes the test when OS has been started */
+ os_test_restart();
+
+}
+
+/* Sending a single event to poll */
+void
+eventq_task_poll_single_send(void *arg)
+{
+ struct os_eventq *eventqs[SIZE_MULTI_EVENT];
+ int i;
+ int position = 2;
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ eventqs[i] = &multi_eventq[i];
+ }
+
+ /* Put and send */
+ os_eventq_put(eventqs[position], &m_event[position]);
+ os_time_delay(OS_TICKS_PER_SEC / 2);
+
+ /* This task sleeps until the receive task completes the test. */
+ os_time_delay(1000000);
+}
+
+/* Recieving the single event */
+void
+eventq_task_poll_single_receive(void *arg)
+{
+ struct os_eventq *eventqs[SIZE_MULTI_EVENT];
+ struct os_event *event;
+ int i;
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ eventqs[i] = &multi_eventq[i];
+ }
+
+ /* Recieving using the os_eventq_poll*/
+ event = os_eventq_poll(eventqs, SIZE_MULTI_EVENT, OS_WAIT_FOREVER);
+ TEST_ASSERT(event->ev_type == 20);
+
+ /* Finishes the test when OS has been started */
+ os_test_restart();
+}
+
TEST_CASE(event_test_sr)
{
int i;
@@ -121,7 +286,131 @@ TEST_CASE(event_test_sr)
}
+/* To test for the basic function of os_eventq_poll() */
+TEST_CASE(event_test_poll_sr)
+{
+ int i;
+
+ /* Initializing the OS */
+ os_init();
+ /* Initialize the task */
+ os_task_init(&eventq_task_poll_s, "eventq_task_poll_s", eventq_task_poll_send,
+ NULL, SEND_TASK_POLL_PRIO, OS_WAIT_FOREVER, eventq_task_stack_poll_s,
+ POLL_STACK_SIZE);
+
+ /* Receive events and check whether the eevnts are correctly received */
+ os_task_init(&eventq_task_poll_r, "eventq_task_r", eventq_task_poll_receive,
+ NULL, RECEIVE_TASK_POLL_PRIO, OS_WAIT_FOREVER, eventq_task_stack_poll_r,
+ POLL_STACK_SIZE);
+
+ /* Initializing the eventqs. */
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ os_eventq_init(&multi_eventq[i]);
+ }
+
+ /* Does not return until OS_restart is called */
+ os_start();
+
+}
+
+/* Test case for poll timeout */
+TEST_CASE(event_test_poll_timeout_sr)
+{
+ int i;
+
+ /* Initializing the OS */
+ os_init();
+ /* Initialize the task */
+ os_task_init(&eventq_task_poll_timeout_s, "eventq_task_poll_timeout_s",
+ eventq_task_poll_timeout_send, NULL, SEND_TASK_POLL_TIMEOUT_PRIO,
+ OS_WAIT_FOREVER, eventq_task_stack_poll_timeout_s, POLL_STACK_SIZE);
+
+ /* Receive events and check whether the eevnts are correctly received */
+ os_task_init(&eventq_task_poll_timeout_r, "eventq_task_timeout_r",
+ eventq_task_poll_timeout_receive, NULL, RECEIVE_TASK_POLL_TIMEOUT_PRIO,
+ OS_WAIT_FOREVER, eventq_task_stack_poll_timeout_r, POLL_STACK_SIZE);
+
+ /* Initializing the eventqs. */
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ os_eventq_init(&multi_eventq[i]);
+
+ m_event[i].ev_type = i + 10;
+ m_event[i].ev_arg = NULL;
+ }
+
+ /* Does not return until OS_restart is called */
+ os_start();
+
+}
+
+/* The case for poll single */
+/* Test case for poll timeout */
+TEST_CASE(event_test_poll_single_sr)
+{
+ int i;
+
+ /* Initializing the OS */
+ os_init();
+ /* Initialize the task */
+ os_task_init(&eventq_task_poll_single_s, "eventq_task_poll_single_s",
+ eventq_task_poll_single_send, NULL, SEND_TASK_POLL_SINGLE_PRIO,
+ OS_WAIT_FOREVER, eventq_task_stack_poll_single_s, POLL_STACK_SIZE);
+
+ /* Receive events and check whether the eevnts are correctly received */
+ os_task_init(&eventq_task_poll_single_r, "eventq_task_single_r",
+ eventq_task_poll_single_receive, NULL, RECEIVE_TASK_POLL_SINGLE_PRIO,
+ OS_WAIT_FOREVER, eventq_task_stack_poll_single_r, POLL_STACK_SIZE);
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ os_eventq_init(&multi_eventq[i]);
+
+ m_event[i].ev_type = 10 * i;
+ m_event[i].ev_arg = NULL;
+ }
+
+ /* Does not return until OS_restart is called */
+ os_start();
+
+}
+
+/**
+ * Tests eventq_poll() with a timeout of 0. This should not involve the
+ * scheduler at all, so it should work without starting the OS.
+ */
+TEST_CASE(event_test_poll_0timo)
+{
+ struct os_eventq *eventqs[SIZE_MULTI_EVENT];
+ struct os_event *evp;
+ struct os_event ev;
+ int i;
+
+ for (i = 0; i < SIZE_MULTI_EVENT; i++){
+ os_eventq_init(&multi_eventq[i]);
+ eventqs[i] = &multi_eventq[i];
+ }
+
+ evp = os_eventq_poll(eventqs, SIZE_MULTI_EVENT, 0);
+ TEST_ASSERT(evp == NULL);
+
+ /* Ensure no eventq thinks a task is waiting on it. */
+ for (i = 0; i < SIZE_MULTI_EVENT; i++) {
+ TEST_ASSERT(eventqs[i]->evq_task == NULL);
+ }
+
+ /* Put an event on one of the queues. */
+ memset(&ev, 0, sizeof ev);
+ ev.ev_type = 1;
+ os_eventq_put(eventqs[3], &ev);
+
+ evp = os_eventq_poll(eventqs, SIZE_MULTI_EVENT, 0);
+ TEST_ASSERT(evp == &ev);
+}
+
TEST_SUITE(os_eventq_test_suite)
{
event_test_sr();
+ event_test_poll_sr();
+ event_test_poll_timeout_sr();
+ event_test_poll_single_sr();
+ event_test_poll_0timo();
}
diff --git a/libs/os/src/test/os_test.c b/libs/os/src/test/os_test.c
index 1b3af1ab..48f07206 100644
--- a/libs/os/src/test/os_test.c
+++ b/libs/os/src/test/os_test.c
@@ -31,7 +31,7 @@ os_test_all(void)
os_sem_test_suite();
os_mbuf_test_suite();
os_eventq_test_suite();
-
+ os_callout_test_suite();
return tu_case_failed;
}
diff --git a/libs/os/src/test/os_test_priv.h b/libs/os/src/test/os_test_priv.h
index 5193c33b..e923a6fa 100644
--- a/libs/os/src/test/os_test_priv.h
+++ b/libs/os/src/test/os_test_priv.h
@@ -27,6 +27,6 @@ int os_mbuf_test_suite(void);
int os_mutex_test_suite(void);
int os_sem_test_suite(void);
int os_eventq_test_suite(void);
-
+int os_callout_test_suite(void);
#endif
diff --git a/libs/shell/src/shell.c b/libs/shell/src/shell.c
index 95ddcb03..d38573c9 100644
--- a/libs/shell/src/shell.c
+++ b/libs/shell/src/shell.c
@@ -572,6 +572,8 @@ shell_task_init(uint8_t prio, os_stack_t *stack, uint16_t stack_size,
os_eventq_init(&shell_evq);
os_mqueue_init(&g_shell_nlip_mq, NULL);
+ console_init(shell_console_rx_cb);
+
rc = os_task_init(&shell_task, "shell", shell_task_func,
NULL, prio, OS_WAIT_FOREVER, stack, stack_size);
if (rc != 0) {
diff --git a/libs/testutil/include/testutil/testutil.h b/libs/testutil/include/testutil/testutil.h
index da3f618e..9c6192a2 100644
--- a/libs/testutil/include/testutil/testutil.h
+++ b/libs/testutil/include/testutil/testutil.h
@@ -57,6 +57,9 @@ extern const char *tu_suite_name;
extern const char *tu_case_name;
extern int tu_first_idx;
+typedef void tu_post_test_fn_t(void *arg);
+
+void tu_suite_set_post_test_cb(tu_post_test_fn_t *cb, void *cb_arg);
int tu_parse_args(int argc, char **argv);
int tu_init(void);
void tu_restart(void);
@@ -65,6 +68,7 @@ void tu_restart(void);
* Private declarations *
*****************************************************************************/
+void tu_suite_complete(void);
void tu_suite_init(const char *name);
void tu_case_init(const char *name);
@@ -74,7 +78,7 @@ void tu_case_fail_assert(int fatal, const char *file, int line,
void tu_case_write_pass_auto(void);
void tu_case_pass_manual(const char *file, int line,
const char *format, ...);
-
+void tu_case_post_test(void);
extern int tu_any_failed;
extern int tu_suite_failed;
@@ -91,6 +95,7 @@ extern jmp_buf tu_case_jb;
{ \
tu_suite_init(#suite_name); \
TEST_SUITE_##suite_name(); \
+ tu_suite_complete(); \
\
return tu_suite_failed; \
} \
@@ -113,6 +118,7 @@ extern jmp_buf tu_case_jb;
\
if (setjmp(tu_case_jb) == 0) { \
TEST_CASE_##case_name(); \
+ tu_case_post_test(); \
tu_case_write_pass_auto(); \
} \
} \
diff --git a/libs/testutil/src/case.c b/libs/testutil/src/case.c
index bea6efa3..614b1425 100644
--- a/libs/testutil/src/case.c
+++ b/libs/testutil/src/case.c
@@ -30,6 +30,8 @@ int tu_case_failed;
int tu_case_idx;
const char *tu_case_name;
+tu_post_test_fn_t *tu_case_post_test_cb;
+void *tu_case_post_test_cb_arg;
#define TU_CASE_BUF_SZ 1024
@@ -101,6 +103,14 @@ tu_case_complete(void)
tu_case_idx++;
}
+void
+tu_case_post_test(void)
+{
+ if (tu_case_post_test_cb != NULL) {
+ tu_case_post_test_cb(tu_case_post_test_cb_arg);
+ }
+}
+
static void
tu_case_write_fail_buf(void)
{
diff --git a/libs/testutil/src/suite.c b/libs/testutil/src/suite.c
index 5c2e5cbc..93ca639f 100644
--- a/libs/testutil/src/suite.c
+++ b/libs/testutil/src/suite.c
@@ -30,6 +30,30 @@ tu_suite_set_name(const char *name)
tu_suite_name = name;
}
+/**
+ * Configures a callback that gets executed at the end of each test case in the
+ * current suite. This is useful when there are some checks that should be
+ * performed at the end of each test (e.g., verify no memory leaks). This
+ * callback is cleared when the current suite completes.
+ *
+ * @param cb The callback to execute at the end of each test
+ * case.
+ * @param cb_arg An optional argument that gets passed to the
+ * callback.
+ */
+void
+tu_suite_set_post_test_cb(tu_post_test_fn_t *cb, void *cb_arg)
+{
+ tu_case_post_test_cb = cb;
+ tu_case_post_test_cb_arg = cb_arg;
+}
+
+void
+tu_suite_complete(void)
+{
+ tu_suite_set_post_test_cb(NULL, NULL);
+}
+
void
tu_suite_init(const char *name)
{
diff --git a/libs/testutil/src/testutil_priv.h b/libs/testutil/src/testutil_priv.h
index 0047874e..3f8cb2dc 100644
--- a/libs/testutil/src/testutil_priv.h
+++ b/libs/testutil/src/testutil_priv.h
@@ -23,7 +23,12 @@
#include <stddef.h>
#include <inttypes.h>
+#include "testutil/testutil.h"
+
void tu_arch_restart(void);
void tu_case_abort(void);
+extern tu_post_test_fn_t *tu_case_post_test_cb;
+extern void *tu_case_post_test_cb_arg;
+
#endif
diff --git a/libs/util/include/util/mem.h b/libs/util/include/util/mem.h
new file mode 100644
index 00000000..52ddce4d
--- /dev/null
+++ b/libs/util/include/util/mem.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_UTIL_MEM_
+#define H_UTIL_MEM_
+
+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);
+
+#endif
diff --git a/libs/util/src/mem.c b/libs/util/src/mem.c
new file mode 100644
index 00000000..faf82345
--- /dev/null
+++ b/libs/util/src/mem.c
@@ -0,0 +1,146 @@
+/**
+ * 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"
+
+/**
+ * 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;
+}
diff --git a/libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt.h b/libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt.h
new file mode 100644
index 00000000..411921a8
--- /dev/null
+++ b/libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt.h
@@ -0,0 +1,82 @@
+/**
+ * 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 __WIFI_MGMT_H__
+#define __WIFI_MGMT_H__
+
+/*
+ * Wi-Fi interface abstraction.
+ */
+#define WIFI_SSID_MAX 32 /* max SSID name length */
+#define WIFI_BSSID_LEN 6 /* MAC address len */
+#define WIFI_SCAN_CNT_MAX 20
+#define WIFI_KEY_MAX 64 /* max key length */
+#define WIFI_SSID_EMPTY(ssid) (ssid)[0] == '\0'
+
+/*
+ * Info about an access point.
+ */
+struct wifi_ap {
+ char wa_ssid[WIFI_SSID_MAX + 1];
+ char wa_bssid[WIFI_BSSID_LEN + 1];
+ int8_t wa_rssi;
+ uint8_t wa_key_type;
+ uint8_t wa_channel;
+};
+
+struct wifi_if_ops;
+
+/*
+ * Wifi interface
+ */
+struct wifi_if {
+ enum {
+ STOPPED = 0,
+ INIT,
+ CONNECTING,
+ DHCP_WAIT,
+ CONNECTED,
+ SCANNING
+ } wi_state, wi_tgt;
+ struct os_mutex wi_mtx;
+ struct os_event wi_event;
+ struct os_callout_func wi_timer;
+ const struct wifi_if_ops *wi_ops;
+
+ uint8_t wi_scan_cnt;
+ struct wifi_ap wi_scan[WIFI_SCAN_CNT_MAX];
+ char wi_ssid[WIFI_SSID_MAX + 1];
+ char wi_key[WIFI_KEY_MAX + 1];
+ uint8_t wi_myip[4];
+};
+
+/*
+ * XXX. is wifi_if_lookup() needed? It is unlikely that there's going to be
+ * multiple wifi interfaces on a system.
+ */
+struct wifi_if *wifi_if_lookup(int port);
+int wifi_if_register(struct wifi_if *, const struct wifi_if_ops *);
+
+int wifi_start(struct wifi_if *);
+int wifi_connect(struct wifi_if *);
+int wifi_stop(struct wifi_if *w);
+int wifi_scan_start(struct wifi_if *w);
+
+int wifi_task_init(uint8_t prio, os_stack_t *stack, uint16_t stack_size);
+
+#endif /* __WIFI_MGMT_H__ */
diff --git a/libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt_if.h b/libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt_if.h
new file mode 100644
index 00000000..c6e432da
--- /dev/null
+++ b/libs/wifi_mgmt/include/wifi_mgmt/wifi_mgmt_if.h
@@ -0,0 +1,47 @@
+/**
+ * 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 __WIFI_MGMT_IF_H__
+#define __WIFI_MGMT_IF_H__
+
+/*
+ * Interface between Wi-fi management and the driver.
+ */
+struct wifi_if_ops {
+ int (*wio_init)(struct wifi_if *);
+ void (*wio_deinit)(struct wifi_if *);
+ int (*wio_scan_start)(struct wifi_if *);
+ int (*wio_connect)(struct wifi_if *, struct wifi_ap *);
+ void (*wio_disconnect)(struct wifi_if *);
+};
+
+/*
+ * Exported so driver can use this for it's timers.
+ */
+extern struct os_eventq wifi_evq;
+
+/*
+ * Called by the Wi-fi driver.
+ */
+void wifi_scan_result(struct wifi_if *, struct wifi_ap *);
+void wifi_scan_done(struct wifi_if *, int status);
+void wifi_connect_done(struct wifi_if *wi, int status);
+void wifi_disconnected(struct wifi_if *wi, int status);
+void wifi_dhcp_done(struct wifi_if *wi, uint8_t *ip); /* XXX more IP info */
+
+#endif /* __WIFI_MGMT_IF_H__ */
diff --git a/libs/wifi_mgmt/pkg.yml b/libs/wifi_mgmt/pkg.yml
new file mode 100644
index 00000000..ebe582c5
--- /dev/null
+++ b/libs/wifi_mgmt/pkg.yml
@@ -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.
+#
+
+pkg.name: libs/wifi_mgmt
+pkg.description: Wifi state management
+pkg.author: "Apache Mynewt <dev@mynewt.incubator.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+pkg.deps:
+ - "@apache-mynewt-core/libs/os"
+ - "@apache-mynewt-core/libs/util"
+pkg.reqs:
+ - console
+pkg.cflags.SHELL:
+ - -DSHELL_PRESENT
+
+pkg.deps.TEST:
+ - libs/testutil
+
diff --git a/libs/wifi_mgmt/src/wifi.c b/libs/wifi_mgmt/src/wifi.c
new file mode 100644
index 00000000..b5b6a72a
--- /dev/null
+++ b/libs/wifi_mgmt/src/wifi.c
@@ -0,0 +1,348 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include <os/os.h>
+#include <bsp/bsp.h>
+#include <hal/hal_gpio.h>
+#include <shell/shell.h>
+#include <console/console.h>
+
+#include "wifi_mgmt/wifi_mgmt.h"
+#include "wifi_mgmt/wifi_mgmt_if.h"
+#include "wifi_priv.h"
+
+#define WIFI_EV_STATE OS_EVENT_T_PERUSER
+
+static struct os_task wifi_os_task;
+struct os_eventq wifi_evq;
+
+static struct wifi_ap *wifi_find_ap(struct wifi_if *wi, char *ssid);
+static void wifi_events(void *arg);
+
+static struct wifi_if *wifi_if;
+
+/*
+ * Looks up interface based on port number.
+ */
+struct wifi_if *
+wifi_if_lookup(int port)
+{
+ assert(port == 0);
+ return wifi_if;
+}
+
+/*
+ * Called by wi-fi driver to register itself.
+ */
+int
+wifi_if_register(struct wifi_if *wi, const struct wifi_if_ops *ops)
+{
+ if (wifi_if) {
+ return -1;
+ }
+ wifi_if = wi;
+
+ wi->wi_ops = ops;
+ os_mutex_init(&wi->wi_mtx);
+ os_callout_func_init(&wi->wi_timer, &wifi_evq, wifi_events, wi);
+ wi->wi_event.ev_type = WIFI_EV_STATE;
+ wi->wi_event.ev_arg = wi;
+
+ return 0;
+}
+
+/*
+ * For Wi-fi mgmt state machine, set the target state, and queue an
+ * event to do the state transition in wifi task context.
+ */
+static void
+wifi_tgt_state(struct wifi_if *wi, int state)
+{
+ wi->wi_tgt = state;
+ os_eventq_put(&wifi_evq, &wi->wi_event);
+}
+
+/*
+ * Wi-fi driver reports a response to wifi scan request.
+ * Driver reports networks one at a time.
+ */
+void
+wifi_scan_result(struct wifi_if *wi, struct wifi_ap *ap)
+{
+ if (wi->wi_scan_cnt == WIFI_SCAN_CNT_MAX) {
+ return;
+ }
+ wi->wi_scan[wi->wi_scan_cnt++] = *ap;
+}
+
+/*
+ * Wifi driver reports that scan is finished.
+ */
+void
+wifi_scan_done(struct wifi_if *wi, int status)
+{
+ struct wifi_ap *ap = NULL;
+
+ console_printf("scan_results %d: %d\n", wi->wi_scan_cnt, status);
+ if (status) {
+ wifi_tgt_state(wi, STOPPED);
+ return;
+ }
+
+ /*
+ * XXX decide what to do with scan results here.
+ */
+ if (!WIFI_SSID_EMPTY(wi->wi_ssid)) {
+ ap = wifi_find_ap(wi, wi->wi_ssid);
+ }
+ if (ap) {
+ wifi_tgt_state(wi, CONNECTING);
+ } else {
+ wifi_tgt_state(wi, INIT);
+ }
+}
+
+/*
+ * Wi-fi driver reports whether it was successful in establishing connection
+ * to an AP. XXX need status codes in wifi_mgmt.h
+ */
+void
+wifi_connect_done(struct wifi_if *wi, int status)
+{
+ console_printf("connect_done : %d\n", status);
+ if (status) {
+ wifi_tgt_state(wi, INIT);
+ return;
+ }
+ wifi_tgt_state(wi, DHCP_WAIT);
+}
+
+/*
+ * Wi-fi driver reports that there's an IP address. We can start using
+ * this interface.
+ */
+void
+wifi_dhcp_done(struct wifi_if *wi, uint8_t *ip)
+{
+ console_printf("dhcp done %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
+ wifi_tgt_state(wi, CONNECTED);
+}
+
+/*
+ * Wi-fi driver reports that we are disconnected from an AP.
+ */
+void
+wifi_disconnected(struct wifi_if *wi, int status)
+{
+ console_printf("disconnect : %d\n", status);
+ wifi_tgt_state(wi, INIT);
+}
+
+static struct wifi_ap *
+wifi_find_ap(struct wifi_if *wi, char *ssid)
+{
+ int i;
+
+ for (i = 0; i < wi->wi_scan_cnt; i++) {
+ if (!strcmp(wi->wi_scan[i].wa_ssid, ssid)) {
+ return &wi->wi_scan[i];
+ }
+ }
+ return NULL;
+}
+
+static void
+wifi_events(void *arg)
+{
+ /*
+ * Expire connection attempts. Periodic scanning if tgt AP not visible.
+ */
+}
+
+/*
+ * Called by user to start bringing up Wi-fi interface online.
+ */
+int
+wifi_start(struct wifi_if *wi)
+{
+ if (wi->wi_state != STOPPED) {
+ return -1;
+ }
+ wifi_tgt_state(wi, INIT);
+ return 0;
+}
+
+/*
+ * Called by user to stop Wi-fi interface.
+ */
+int
+wifi_stop(struct wifi_if *wi)
+{
+ wifi_tgt_state(wi, STOPPED);
+ return 0;
+}
+
+/*
+ * Called by user to connect Wi-fi interface to AP. Will fail if no
+ * SSID name is set.
+ */
+int
+wifi_connect(struct wifi_if *wi)
+{
+ switch (wi->wi_state) {
+ case STOPPED:
+ return -1;
+ case INIT:
+ if (WIFI_SSID_EMPTY(wi->wi_ssid)) {
+ return -1;
+ }
+ wifi_tgt_state(wi, CONNECTING);
+ return 0;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * From user to initiate Wi-Fi scan.
+ */
+int
+wifi_scan_start(struct wifi_if *wi)
+{
+ if (wi->wi_state == INIT) {
+ wifi_tgt_state(wi, SCANNING);
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * Wi-fi mgmt state machine.
+ */
+static void
+wifi_step(struct wifi_if *wi)
+{
+ int rc;
+ struct wifi_ap *ap;
+
+ switch (wi->wi_tgt) {
+ case STOPPED:
+ if (wi->wi_state != STOPPED) {
+ if (wi->wi_state >= CONNECTING) {
+ wi->wi_ops->wio_disconnect(wi);
+ }
+ wi->wi_ops->wio_deinit(wi);
+ wi->wi_state = STOPPED;
+ }
+ break;
+ case INIT:
+ if (wi->wi_state == STOPPED) {
+ rc = wi->wi_ops->wio_init(wi);
+ console_printf("wifi_init : %d\n", rc);
+ if (!rc) {
+ wi->wi_state = INIT;
+ }
+ } else if (wi->wi_state == SCANNING) {
+ wi->wi_state = wi->wi_tgt;
+ } else if (wi->wi_state == CONNECTING) {
+ wi->wi_state = wi->wi_tgt;
+ }
+ break;
+ case SCANNING:
+ if (wi->wi_state == INIT) {
+ memset(wi->wi_scan, 0, sizeof(wi->wi_scan));
+ rc = wi->wi_ops->wio_scan_start(wi);
+ console_printf("wifi_request_scan : %d\n", rc);
+ if (rc != 0) {
+ break;
+ }
+ wi->wi_state = SCANNING;
+ } else {
+ wi->wi_tgt = wi->wi_state;
+ }
+ break;
+ case CONNECTING:
+ if (wi->wi_state == INIT || wi->wi_state == SCANNING) {
+ ap = wifi_find_ap(wi, wi->wi_ssid);
+ if (!ap) {
+ wifi_tgt_state(wi, SCANNING);
+ break;
+ }
+ rc = wi->wi_ops->wio_connect(wi, ap);
+ console_printf("wifi_connect : %d\n", rc);
+ if (rc == 0) {
+ wi->wi_state = CONNECTING;
+ } else {
+ wi->wi_tgt = STOPPED;
+ }
+ }
+ break;
+ case DHCP_WAIT:
+ wi->wi_state = wi->wi_tgt;
+ break;
+ case CONNECTED:
+ wi->wi_state = wi->wi_tgt;
+ break;
+ default:
+ console_printf("wifi_step() unknown tgt : %d\n", wi->wi_tgt);
+ wi->wi_state = wi->wi_tgt;
+ break;
+ }
+}
+
+static void
+wifi_task(void *arg)
+{
+ struct os_event *ev;
+ struct os_callout_func *cf;
+ struct wifi_if *wi;
+
+ while ((ev = os_eventq_get(&wifi_evq))) {
+ switch (ev->ev_type) {
+ case OS_EVENT_T_TIMER:
+ cf = (struct os_callout_func *)ev;
+ cf->cf_func(CF_ARG(cf));
+ break;
+ case WIFI_EV_STATE:
+ wi = (struct wifi_if *)ev->ev_arg;
+ while (wi->wi_state != wi->wi_tgt) {
+ wifi_step(wi);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int
+wifi_task_init(uint8_t prio, os_stack_t *stack, uint16_t stack_size)
+{
+#ifdef SHELL_PRESENT
+ shell_cmd_register(&wifi_cli_cmd);
+#endif
+ os_eventq_init(&wifi_evq);
+
+ return os_task_init(&wifi_os_task, "wifi", wifi_task, NULL,
+ prio, OS_WAIT_FOREVER, stack, stack_size);
+}
diff --git a/libs/wifi_mgmt/src/wifi_cli.c b/libs/wifi_mgmt/src/wifi_cli.c
new file mode 100644
index 00000000..4cd95529
--- /dev/null
+++ b/libs/wifi_mgmt/src/wifi_cli.c
@@ -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.
+ */
+#ifdef SHELL_PRESENT
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+
+#include <shell/shell.h>
+#include <console/console.h>
+
+#include "wifi_mgmt/wifi_mgmt.h"
+
+#include "wifi_priv.h"
+
+static int
+wifi_cli(int argc, char **argv)
+{
+ struct wifi_if *wi;
+ int i;
+
+ if (argc < 1) {
+ return 0;
+ }
+ wi = wifi_if_lookup(0);
+
+ if (!strcmp(argv[1], "start")) {
+ wifi_start(wi);
+ } else if (!strcmp(argv[1], "stop")) {
+ wifi_stop(wi);
+ } else if (!strcmp(argv[1], "scan")) {
+ wifi_scan_start(wi);
+ } else if (!strcmp(argv[1], "aps")) {
+ int i;
+ struct wifi_ap *ap;
+
+ console_printf(" %32s %4s %4s %s\n", "SSID", "RSSI", "chan", "sec");
+ for (i = 0; i < wi->wi_scan_cnt; i++) {
+ ap = (struct wifi_ap *)&wi->wi_scan[i];
+ console_printf("%2d:%32s %4d %4d %s\n",
+ i, ap->wa_ssid, ap->wa_rssi, ap->wa_channel,
+ ap->wa_key_type ? "X" : "");
+ }
+ } else if (!strcmp(argv[1], "connect")) {
+ if (argc < 2) {
+ goto conn_usage;
+ }
+ i = strlen(argv[2]);
+ if (i >= sizeof(wi->wi_ssid)) {
+ goto conn_usage;
+ }
+ if (argc > 2) {
+ i = strlen(argv[2]);
+ if (i >= sizeof(wi->wi_key)) {
+ goto conn_usage;
+ }
+ strcpy(wi->wi_key, argv[3]);
+ }
+ strcpy(wi->wi_ssid, argv[2]);
+ if (wifi_connect(wi)) {
+conn_usage:
+ console_printf("%s %s [<ssid> [<key>]]\n",
+ argv[0], argv[1]);
+ }
+ }
+ return 0;
+}
+
+struct shell_cmd wifi_cli_cmd = {
+ .sc_cmd = "wifi",
+ .sc_cmd_func = wifi_cli
+};
+
+#endif
diff --git a/libs/wifi_mgmt/src/wifi_priv.h b/libs/wifi_mgmt/src/wifi_priv.h
new file mode 100644
index 00000000..dfba81da
--- /dev/null
+++ b/libs/wifi_mgmt/src/wifi_priv.h
@@ -0,0 +1,27 @@
+/**
+ * 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 __WIFI_PRIV_H__
+#define __WIFI_PRIV_H__
+
+#ifdef SHELL_PRESENT
+extern struct shell_cmd wifi_cli_cmd;
+#endif
+
+#endif /* __WIFI_PRIV_H__ */