This is an automated email from the ASF dual-hosted git repository.

marko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 4f39ba0aecb34ee96273ffccfea34f11f764f417
Author: Marko Kiiskila <[email protected]>
AuthorDate: Wed Aug 21 16:49:23 2019 +0300

    sys/config; add option to store config in FCB2.
---
 sys/config/include/config/config_fcb2.h            |  72 ++++
 sys/config/pkg.yml                                 |   2 +
 sys/config/{ => selftest-fcb2}/pkg.yml             |  28 +-
 sys/config/selftest-fcb2/src/conf_test_fcb2.c      | 401 +++++++++++++++++++++
 sys/config/selftest-fcb2/src/conf_test_fcb2.h      | 105 ++++++
 .../src/testcases/config_empty_lookups.c           |  34 ++
 .../src/testcases/config_test_commit.c             |  41 +++
 .../src/testcases/config_test_compress_reset.c     |  92 +++++
 .../src/testcases/config_test_custom_compress.c    | 121 +++++++
 .../src/testcases/config_test_empty_fcb.c          |  44 +++
 .../src/testcases/config_test_get_stored.c         |  78 ++++
 .../src/testcases/config_test_getset_bytes.c       |  49 +++
 .../src/testcases/config_test_getset_int.c         |  40 ++
 .../src/testcases/config_test_getset_int64.c       |  56 +++
 .../src/testcases/config_test_getset_unknown.c     |  48 +++
 .../src/testcases/config_test_save_1_fcb.c         |  48 +++
 .../src/testcases/config_test_save_2_fcb.c         |  87 +++++
 .../src/testcases/config_test_save_3_fcb.c         |  53 +++
 .../src/testcases/config_test_save_one_fcb.c       |  57 +++
 sys/config/{pkg.yml => selftest-fcb2/syscfg.yml}   |  30 +-
 sys/config/src/config_fcb2.c                       | 356 ++++++++++++++++++
 sys/config/src/config_init.c                       |  40 ++
 sys/config/syscfg.yml                              |  11 +-
 23 files changed, 1850 insertions(+), 43 deletions(-)

diff --git a/sys/config/include/config/config_fcb2.h 
b/sys/config/include/config/config_fcb2.h
new file mode 100644
index 0000000..7072521
--- /dev/null
+++ b/sys/config/include/config/config_fcb2.h
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef __SYS_CONFIG_FCB2_H_
+#define __SYS_CONFIG_FCB2_H_
+
+#include "config/config.h"
+#include "config/config_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct conf_fcb2 {
+    struct conf_store cf2_store;
+    struct fcb cf2_fcb;
+};
+
+/**
+ * Add FCB as a sourced of persisted configation
+ *
+ * @param cf Information regarding FCB2 area to add.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int conf_fcb2_src(struct conf_fcb2 *cf);
+
+/**
+ * Set FCB as the destination for persisting configation
+ *
+ * @param cf Information regarding FCB2 area to add. This FCB area should have
+ *           been added using conf_fcb2_src() previously.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int conf_fcb2_dst(struct conf_fcb2 *cf);
+
+/**
+ * Do a custom compression cycle. Caller provides a callback function which
+ * returns whether value should be copied or not. Note that compression
+ * automatically filters out old configuration values.
+ *
+ * @param cf FCB2 source to compress.
+ * @param copy_or_not Function which gets called with key/value pair.
+ *                    Returns 0 if copy should happen, 1 if key/value pair
+ *                    should be skipped.
+ */
+void conf_fcb2_compress(struct conf_fcb2 *cf,
+                        int (*copy_or_not)(const char *name, const char *val,
+                                           void *con_arg),
+                        void *con_arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SYS_CONFIG_FCB2_H_ */
diff --git a/sys/config/pkg.yml b/sys/config/pkg.yml
index 93fe279..f361a8b 100644
--- a/sys/config/pkg.yml
+++ b/sys/config/pkg.yml
@@ -32,6 +32,8 @@ pkg.deps.CONFIG_NEWTMGR:
     - "@apache-mynewt-core/mgmt/mgmt"
 pkg.deps.CONFIG_FCB:
     - "@apache-mynewt-core/fs/fcb"
+pkg.deps.CONFIG_FCB2:
+    - "@apache-mynewt-core/fs/fcb2"
 pkg.deps.CONFIG_NFFS:
     - "@apache-mynewt-core/fs/nffs"
 
diff --git a/sys/config/pkg.yml b/sys/config/selftest-fcb2/pkg.yml
similarity index 62%
copy from sys/config/pkg.yml
copy to sys/config/selftest-fcb2/pkg.yml
index 93fe279..757b560 100644
--- a/sys/config/pkg.yml
+++ b/sys/config/selftest-fcb2/pkg.yml
@@ -1,4 +1,3 @@
-#
 # 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
@@ -6,7 +5,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,
@@ -16,25 +15,16 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-
-pkg.name: sys/config
-pkg.description: Configuration management for embedded systems.
+pkg.name: sys/config/selftest-fcb2
+pkg.type: unittest
+pkg.description: "Config unit tests for fcb2."
 pkg.author: "Apache Mynewt <[email protected]>"
 pkg.homepage: "http://mynewt.apache.org/";
 pkg.keywords:
 
 pkg.deps:
-    - "@apache-mynewt-core/encoding/base64"
-pkg.deps.CONFIG_CLI:
-    - "@apache-mynewt-core/sys/shell"
-pkg.deps.CONFIG_NEWTMGR:
-    - "@apache-mynewt-core/encoding/cborattr"
-    - "@apache-mynewt-core/mgmt/mgmt"
-pkg.deps.CONFIG_FCB:
-    - "@apache-mynewt-core/fs/fcb"
-pkg.deps.CONFIG_NFFS:
-    - "@apache-mynewt-core/fs/nffs"
-
-pkg.init:
-    config_pkg_init: 'MYNEWT_VAL(CONFIG_SYSINIT_STAGE_1)'
-    config_pkg_init_stage2: 'MYNEWT_VAL(CONFIG_SYSINIT_STAGE_2)'
+    - "@apache-mynewt-core/fs/fcb2"
+    - "@apache-mynewt-core/sys/config"
+    - "@apache-mynewt-core/sys/console/stub"
+    - "@apache-mynewt-core/sys/log/stub"
+    - "@apache-mynewt-core/test/testutil"
diff --git a/sys/config/selftest-fcb2/src/conf_test_fcb2.c 
b/sys/config/selftest-fcb2/src/conf_test_fcb2.c
new file mode 100644
index 0000000..8f097fd
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/conf_test_fcb2.c
@@ -0,0 +1,401 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <os/mynewt.h>
+#include <flash_map/flash_map.h>
+#include <testutil/testutil.h>
+#include <fcb/fcb.h>
+#include <config/config.h>
+#include <config/config_fcb2.h>
+#include <config_priv.h>
+#include "conf_test_fcb2.h"
+
+char val_string[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+
+uint8_t val8;
+int c2_var_count = 1;
+
+uint32_t val32;
+uint64_t val64;
+
+int test_get_called;
+int test_set_called;
+int test_commit_called;
+int test_export_block;
+
+char *ctest_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int ctest_handle_set(int argc, char **argv, char *val);
+int ctest_handle_commit(void);
+int ctest_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+char *c2_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int c2_handle_set(int argc, char **argv, char *val);
+int c2_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+char *c3_handle_get(int argc, char **argv, char *val,
+  int val_len_max);
+int c3_handle_set(int argc, char **argv, char *val);
+int c3_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt);
+
+struct conf_handler config_test_handler = {
+    .ch_name = "myfoo",
+    .ch_get = ctest_handle_get,
+    .ch_set = ctest_handle_set,
+    .ch_commit = ctest_handle_commit,
+    .ch_export = ctest_handle_export
+};
+
+char *
+ctest_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    test_get_called = 1;
+    if (argc == 1 && !strcmp(argv[0], "mybar")) {
+        return conf_str_from_value(CONF_INT8, &val8, val, val_len_max);
+    }
+    if (argc == 1 && !strcmp(argv[0], "mybar64")) {
+        return conf_str_from_value(CONF_INT64, &val64, val, val_len_max);
+    }
+    return NULL;
+}
+
+int
+ctest_handle_set(int argc, char **argv, char *val)
+{
+    uint8_t newval;
+    uint64_t newval64;
+    int rc;
+
+    test_set_called = 1;
+    if (argc == 1 && !strcmp(argv[0], "mybar")) {
+        rc = CONF_VALUE_SET(val, CONF_INT8, newval);
+        TEST_ASSERT(rc == 0);
+        val8 = newval;
+        return 0;
+    }
+    if (argc == 1 && !strcmp(argv[0], "mybar64")) {
+        rc = CONF_VALUE_SET(val, CONF_INT64, newval64);
+        TEST_ASSERT(rc == 0);
+        val64 = newval64;
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+ctest_handle_commit(void)
+{
+    test_commit_called = 1;
+    return 0;
+}
+
+int
+ctest_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    char value[32];
+
+    if (test_export_block) {
+        return 0;
+    }
+    conf_str_from_value(CONF_INT8, &val8, value, sizeof(value));
+    cb("myfoo/mybar", value);
+
+    conf_str_from_value(CONF_INT64, &val64, value, sizeof(value));
+    cb("myfoo/mybar64", value);
+
+    return 0;
+}
+
+struct conf_handler c2_test_handler = {
+    .ch_name = "2nd",
+    .ch_get = c2_handle_get,
+    .ch_set = c2_handle_set,
+    .ch_commit = NULL,
+    .ch_export = c2_handle_export
+};
+
+char *
+c2_var_find(char *name)
+{
+    int idx = 0;
+    int len;
+    char *eptr;
+
+    len = strlen(name);
+    TEST_ASSERT(!strncmp(name, "string", 6));
+    TEST_ASSERT(len > 6);
+
+    idx = strtoul(&name[6], &eptr, 10);
+    TEST_ASSERT(*eptr == '\0');
+    TEST_ASSERT(idx < c2_var_count);
+    return val_string[idx];
+}
+
+char *
+c2_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    int len;
+    char *valptr;
+
+    if (argc == 1) {
+        valptr = c2_var_find(argv[0]);
+        if (!valptr) {
+            return NULL;
+        }
+        len = strlen(val_string[0]);
+        if (len > val_len_max) {
+            len = val_len_max;
+        }
+        strncpy(val, valptr, len);
+    }
+    return NULL;
+}
+
+int
+c2_handle_set(int argc, char **argv, char *val)
+{
+    char *valptr;
+
+    if (argc == 1) {
+        valptr = c2_var_find(argv[0]);
+        if (!valptr) {
+            return OS_ENOENT;
+        }
+        if (val) {
+            strncpy(valptr, val, sizeof(val_string[0]));
+        } else {
+            memset(valptr, 0, sizeof(val_string[0]));
+        }
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+c2_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    int i;
+    char name[32];
+
+    for (i = 0; i < c2_var_count; i++) {
+        snprintf(name, sizeof(name), "2nd/string%d", i);
+        cb(name, val_string[i]);
+    }
+    return 0;
+}
+
+struct conf_handler c3_test_handler = {
+    .ch_name = "3",
+    .ch_get = c3_handle_get,
+    .ch_set = c3_handle_set,
+    .ch_commit = NULL,
+    .ch_export = c3_handle_export
+};
+
+char *
+c3_handle_get(int argc, char **argv, char *val, int val_len_max)
+{
+    if (argc == 1 && !strcmp(argv[0], "v")) {
+        return conf_str_from_value(CONF_INT32, &val32, val, val_len_max);
+    }
+    return NULL;
+}
+
+int
+c3_handle_set(int argc, char **argv, char *val)
+{
+    uint32_t newval;
+    int rc;
+
+    if (argc == 1 && !strcmp(argv[0], "v")) {
+        rc = CONF_VALUE_SET(val, CONF_INT32, newval);
+        TEST_ASSERT(rc == 0);
+        val32 = newval;
+        return 0;
+    }
+    return OS_ENOENT;
+}
+
+int
+c3_handle_export(void (*cb)(char *name, char *value),
+  enum conf_export_tgt tgt)
+{
+    char value[32];
+
+    conf_str_from_value(CONF_INT32, &val32, value, sizeof(value));
+    cb("3/v", value);
+
+    return 0;
+}
+
+void
+ctest_clear_call_state(void)
+{
+    test_get_called = 0;
+    test_set_called = 0;
+    test_commit_called = 0;
+}
+
+int
+ctest_get_call_state(void)
+{
+    return test_get_called + test_set_called + test_commit_called;
+}
+
+void config_wipe_srcs(void)
+{
+    SLIST_INIT(&conf_load_srcs);
+    conf_save_dst = NULL;
+}
+
+void config_wipe_fcb2(struct flash_sector_range *fsr, int cnt)
+{
+    int rc;
+    int i;
+
+    for (i = 0; i < cnt; i++) {
+        rc = flash_area_erase(&fsr[i].fsr_flash_area, 0,
+                              fsr[i].fsr_sector_size * 
fsr[i].fsr_sector_count);
+        TEST_ASSERT(rc == 0);
+    }
+}
+
+struct flash_sector_range fcb_range[] = {
+    [0] = {
+        .fsr_flash_area = {
+            .fa_off = 0x00000000,
+            .fa_size = 64 * 1024
+        },
+        .fsr_range_start = 0,
+        .fsr_first_sector = 0,
+        .fsr_sector_size = 16 * 1024,
+        .fsr_sector_count = 4,
+        .fsr_align = 1,
+    }
+};
+
+void
+config_test_fill_area(
+          char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN],
+          int iteration)
+{
+      int i, j;
+
+      for (j = 0; j < CONF_TEST_FCB_VAL_STR_CNT; j++) {
+          for (i = 0; i < CONF_MAX_VAL_LEN; i++) {
+              test_value[j][i] = ((j * 2) + i + iteration) % 10 + '0';
+          }
+          test_value[j][sizeof(test_value[j]) - 1] = '\0';
+      }
+}
+
+static void
+conf_test_fcb_pre_test(void *arg)
+{
+    int rc;
+
+    rc = conf_register(&config_test_handler);
+    TEST_ASSERT_FATAL(rc == 0);
+}
+
+static void
+conf_test_fcb_pre_test2(void *arg)
+{
+    int rc;
+
+    rc = conf_register(&config_test_handler);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    rc = conf_register(&c2_test_handler);
+    TEST_ASSERT_FATAL(rc == 0);
+}
+
+static void
+conf_test_fcb_pre_test3(void *arg)
+{
+    int rc;
+
+    rc = conf_register(&config_test_handler);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    rc = conf_register(&c2_test_handler);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    rc = conf_register(&c3_test_handler);
+    TEST_ASSERT_FATAL(rc == 0);
+}
+
+TEST_SUITE(config_test_c0)
+{
+    config_empty_lookups();
+}
+
+TEST_SUITE(config_test_c1)
+{
+    tu_config.pre_test_cb = conf_test_fcb_pre_test;
+
+    config_test_getset_unknown();
+    config_test_getset_int();
+    config_test_getset_bytes();
+    config_test_getset_int64();
+
+    config_test_commit();
+
+    config_test_save_1_fcb();
+}
+
+TEST_SUITE(config_test_c2)
+{
+    tu_config.pre_test_cb = conf_test_fcb_pre_test2;
+
+    config_test_empty_fcb();
+
+    config_test_save_2_fcb();
+
+    config_test_save_one_fcb();
+    config_test_get_stored_fcb();
+}
+
+TEST_SUITE(config_test_c3)
+{
+    tu_config.pre_test_cb = conf_test_fcb_pre_test3;
+
+    config_test_save_3_fcb();
+
+    config_test_compress_reset();
+    config_test_custom_compress();
+}
+
+int
+main(int argc, char **argv)
+{
+    config_test_c0();
+    config_test_c1();
+    config_test_c2();
+    config_test_c3();
+
+    return tu_any_failed;
+}
diff --git a/sys/config/selftest-fcb2/src/conf_test_fcb2.h 
b/sys/config/selftest-fcb2/src/conf_test_fcb2.h
new file mode 100644
index 0000000..3b2b63f
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/conf_test_fcb2.h
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifndef _CONF_TEST_FCB2_H
+#define _CONF_TEST_FCB2_H
+
+#include <stdio.h>
+#include <string.h>
+#include <os/mynewt.h>
+#include <flash_map/flash_map.h>
+#include <testutil/testutil.h>
+#include <fcb/fcb.h>
+#include <config/config.h>
+#include <config/config_fcb2.h>
+#include <config_priv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint8_t val8;
+extern int c2_var_count;
+
+#define CONF_TEST_FCB_VAL_STR_CNT   64
+
+extern char val_string[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+
+#define CONF_TEST_FCB_RANGE_CNT   1
+
+extern struct flash_sector_range fcb_range[CONF_TEST_FCB_RANGE_CNT];
+
+extern uint32_t val32;
+extern uint64_t val64;
+
+extern int test_get_called;
+extern int test_set_called;
+extern int test_commit_called;
+extern int test_export_block;
+
+void ctest_clear_call_state(void);
+int ctest_get_call_state(void);
+void config_wipe_srcs(void);
+extern void config_test_fill_area(
+        char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN],
+        int iteration);
+
+void config_wipe_fcb2(struct flash_sector_range *fsr, int cnt);
+
+char *ctest_handle_get(int argc, char **argv, char *val, int val_len_max);
+int ctest_handle_set(int argc, char **argv, char *val);
+int ctest_handle_commit(void);
+int ctest_handle_export(void (*cb)(char *name, char *value),
+                        enum conf_export_tgt tgt);
+
+char *c2_handle_get(int argc, char **argv, char *val, int val_len_max);
+int c2_handle_set(int argc, char **argv, char *val);
+int c2_handle_export(void (*cb)(char *name, char *value),
+                     enum conf_export_tgt tgt);
+
+char *c3_handle_get(int argc, char **argv, char *val, int val_len_max);
+int c3_handle_set(int argc, char **argv, char *val);
+int c3_handle_export(void (*cb)(char *name, char *value),
+                     enum conf_export_tgt tgt);
+
+extern struct conf_handler config_test_handler;
+
+extern struct conf_handler c2_test_handler;
+
+extern struct conf_handler c3_test_handler;
+
+TEST_CASE_DECL(config_empty_lookups)
+TEST_CASE_DECL(config_test_getset_unknown)
+TEST_CASE_DECL(config_test_getset_int)
+TEST_CASE_DECL(config_test_getset_bytes)
+TEST_CASE_DECL(config_test_getset_int64)
+TEST_CASE_DECL(config_test_commit)
+TEST_CASE_DECL(config_test_empty_fcb)
+TEST_CASE_DECL(config_test_save_1_fcb)
+TEST_CASE_DECL(config_test_save_2_fcb)
+TEST_CASE_DECL(config_test_save_3_fcb)
+TEST_CASE_DECL(config_test_compress_reset)
+TEST_CASE_DECL(config_test_save_one_fcb)
+TEST_CASE_DECL(config_test_custom_compress)
+TEST_CASE_DECL(config_test_get_stored_fcb)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONF_TEST_FCB_H */
diff --git a/sys/config/selftest-fcb2/src/testcases/config_empty_lookups.c 
b/sys/config/selftest-fcb2/src/testcases/config_empty_lookups.c
new file mode 100644
index 0000000..5294b5f
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_empty_lookups.c
@@ -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.
+ */
+#include "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_empty_lookups)
+{
+    int rc;
+    char name[80];
+    char tmp[64], *str;
+
+    strcpy(name, "foo/bar");
+    rc = conf_set_value(name, "tmp");
+    TEST_ASSERT(rc != 0);
+
+    strcpy(name, "foo/bar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str == NULL);
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_commit.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_commit.c
new file mode 100644
index 0000000..9729e46
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_commit.c
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_commit)
+{
+    char name[80];
+    int rc;
+
+    strcpy(name, "bar");
+    rc = conf_commit(name);
+    TEST_ASSERT(rc);
+    TEST_ASSERT(ctest_get_call_state() == 0);
+
+    rc = conf_commit(NULL);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_commit_called == 1);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo");
+    rc = conf_commit(name);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_commit_called == 1);
+    ctest_clear_call_state();
+}
diff --git 
a/sys/config/selftest-fcb2/src/testcases/config_test_compress_reset.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_compress_reset.c
new file mode 100644
index 0000000..f74c8da
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_compress_reset.c
@@ -0,0 +1,92 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_compress_reset)
+{
+    int rc;
+    struct conf_fcb2 cf;
+    uint16_t fa;
+    char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+    int elems[4];
+    int i;
+
+    config_wipe_srcs();
+    config_wipe_fcb2(fcb_range, CONF_TEST_FCB_RANGE_CNT);
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    c2_var_count = 1;
+    memset(elems, 0, sizeof(elems));
+
+    for (i = 0; ; i++) {
+        config_test_fill_area(test_value, i);
+        memcpy(val_string, test_value, sizeof(val_string));
+
+        rc = conf_save();
+        TEST_ASSERT(rc == 0);
+
+        if (cf.cf2_fcb.f_active_id == fcb_range[0].fsr_sector_count - 2) {
+            /*
+             * Started using space just before scratch.
+             */
+            break;
+        }
+        memset(val_string, 0, sizeof(val_string));
+
+        rc = conf_load();
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(!memcmp(val_string, test_value, CONF_MAX_VAL_LEN));
+    }
+
+    fa = cf.cf2_fcb.f_active_id;
+    rc = fcb_append_to_scratch(&cf.cf2_fcb);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(fcb_free_sector_cnt(&cf.cf2_fcb) == 0);
+    TEST_ASSERT(fa != cf.cf2_fcb.f_active_id);
+
+    config_wipe_srcs();
+
+    memset(&cf, 0, sizeof(cf));
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    TEST_ASSERT(fcb_free_sector_cnt(&cf.cf2_fcb) == 1);
+    TEST_ASSERT(fa == cf.cf2_fcb.f_active_id);
+
+    c2_var_count = 0;
+}
diff --git 
a/sys/config/selftest-fcb2/src/testcases/config_test_custom_compress.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_custom_compress.c
new file mode 100644
index 0000000..2204a8f
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_custom_compress.c
@@ -0,0 +1,121 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+static int unique_val_cnt;
+
+static int
+test_custom_compress_filter1(const char *val, const char *name, void *arg)
+{
+    unique_val_cnt++;
+    return 0;
+}
+
+static int
+test_custom_compress_filter2(const char *val, const char *name, void *arg)
+{
+    if (!strcmp(val, "myfoo/mybar")) {
+        return 0;
+    }
+    return 1;
+}
+
+TEST_CASE_SELF(config_test_custom_compress)
+{
+    int rc;
+    struct conf_fcb2 cf;
+    char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+    int elems[4];
+    int i;
+
+    config_wipe_srcs();
+    config_wipe_fcb2(fcb_range, CONF_TEST_FCB_RANGE_CNT);
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    c2_var_count = 1;
+    test_export_block = 0;
+    val8 = 4;
+    val64 = 8;
+    memset(elems, 0, sizeof(elems));
+
+    for (i = 0; ; i++) {
+        config_test_fill_area(test_value, i);
+        memcpy(val_string, test_value, sizeof(val_string));
+
+        rc = conf_save();
+        TEST_ASSERT(rc == 0);
+
+        if (cf.cf2_fcb.f_active_id == fcb_range[0].fsr_sector_count - 2) {
+            /*
+             * Started using space just before scratch.
+             */
+            break;
+        }
+        memset(val_string, 0, sizeof(val_string));
+
+        rc = conf_load();
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(!memcmp(val_string, test_value, CONF_MAX_VAL_LEN));
+    }
+
+    for (i = 0; i < cf.cf2_fcb.f_sector_cnt - 1; i++) {
+        conf_fcb2_compress(&cf, test_custom_compress_filter1, NULL);
+    }
+    TEST_ASSERT(unique_val_cnt == 4); /* c2, c3 and ctest together */
+
+    test_export_block = 1;
+
+    /*
+     * Read values back, make sure they were carried over.
+     */
+    memset(val_string, 0, sizeof(val_string));
+    val8 = 0;
+    val64 = 0;
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(!memcmp(val_string, test_value, CONF_MAX_VAL_LEN));
+    TEST_ASSERT(val8 == 4);
+    TEST_ASSERT(val64 == 8);
+
+    /*
+     * Only leave one var.
+     */
+    for (i = 0; i < cf.cf2_fcb.f_sector_cnt - 1; i++) {
+        conf_fcb2_compress(&cf, test_custom_compress_filter2, NULL);
+    }
+
+    memset(val_string, 0, sizeof(val_string));
+    val8 = 0;
+    val64 = 0;
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val_string[0][0] == 0);
+    TEST_ASSERT(val8 == 4);
+    TEST_ASSERT(val64 == 0);
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_empty_fcb.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_empty_fcb.c
new file mode 100644
index 0000000..c2d28c5
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_empty_fcb.c
@@ -0,0 +1,44 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_empty_fcb)
+{
+    int rc;
+    struct conf_fcb2 cf;
+
+    config_wipe_srcs();
+    config_wipe_fcb2(fcb_range, CONF_TEST_FCB_RANGE_CNT);
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * No values
+     */
+    conf_load();
+
+    config_wipe_srcs();
+    ctest_clear_call_state();
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_get_stored.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_get_stored.c
new file mode 100644
index 0000000..3be6c89
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_get_stored.c
@@ -0,0 +1,78 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_get_stored_fcb)
+{
+    int rc;
+    struct conf_fcb2 cf;
+    char stored_val[32];
+
+    config_wipe_srcs();
+    config_wipe_fcb2(fcb_range, CONF_TEST_FCB_RANGE_CNT);
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    test_export_block = 0;
+    val8 = 33;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    /*
+     * Nonexistent key
+     */
+    rc = conf_get_stored_value("random/name", stored_val, sizeof(stored_val));
+    TEST_ASSERT(rc == OS_ENOENT);
+
+    rc = conf_get_stored_value("myfoo/mybar", stored_val, sizeof(stored_val));
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(atoi(stored_val) == 33);
+
+    rc = conf_save_one("myfoo/mybar", "42");
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_get_stored_value("myfoo/mybar", stored_val, sizeof(stored_val));
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(atoi(stored_val) == 42);
+
+    val8 = 31;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_get_stored_value("myfoo/mybar", stored_val, sizeof(stored_val));
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(atoi(stored_val) == 31);
+
+    /*
+     * Too small of a buffer
+     */
+    rc = conf_get_stored_value("myfoo/mybar", stored_val, 1);
+    TEST_ASSERT(rc == OS_EINVAL);
+
+    test_export_block = 1;
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_getset_bytes.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_getset_bytes.c
new file mode 100644
index 0000000..b757f53
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_getset_bytes.c
@@ -0,0 +1,49 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_getset_bytes)
+{
+    char orig[32];
+    char bytes[32];
+    char str[48];
+    char *ret;
+    int j, i;
+    int tmp;
+    int rc;
+
+    for (j = 1; j < sizeof(orig); j++) {
+        for (i = 0; i < j; i++) {
+            orig[i] = i + j + 1;
+        }
+        ret = conf_str_from_bytes(orig, j, str, sizeof(str));
+        TEST_ASSERT(ret);
+        tmp = strlen(str);
+        TEST_ASSERT(tmp < sizeof(str));
+
+        memset(bytes, 0, sizeof(bytes));
+        tmp = sizeof(bytes);
+
+        tmp = sizeof(bytes);
+        rc = conf_bytes_from_str(str, bytes, &tmp);
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(tmp == j);
+        TEST_ASSERT(!memcmp(orig, bytes, j));
+    }
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_getset_int.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_getset_int.c
new file mode 100644
index 0000000..3e2d61a
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_getset_int.c
@@ -0,0 +1,40 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_getset_int)
+{
+    char name[80];
+    char tmp[64], *str;
+    int rc;
+
+    strcpy(name, "myfoo/mybar");
+    rc = conf_set_value(name, "42");
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_set_called == 1);
+    TEST_ASSERT(val8 == 42);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo/mybar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str);
+    TEST_ASSERT(test_get_called == 1);
+    TEST_ASSERT(!strcmp("42", tmp));
+    ctest_clear_call_state();
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_getset_int64.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_getset_int64.c
new file mode 100644
index 0000000..147f5a2
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_getset_int64.c
@@ -0,0 +1,56 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_getset_int64)
+{
+    char name[80];
+    char tmp[64], *str;
+    int rc;
+    int64_t cmp;
+
+    strcpy(name, "myfoo/mybar64");
+    rc = conf_set_value(name, "-9218247941279444428");
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_set_called == 1);
+    cmp = 0x8012345678901234;
+    TEST_ASSERT(memcmp(&val64, &cmp, sizeof(val64)) == 0);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo/mybar64");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str);
+    TEST_ASSERT(test_get_called == 1);
+    TEST_ASSERT(!strcmp("-9218247941279444428", tmp));
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo/mybar64");
+    rc = conf_set_value(name, "1");
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(test_set_called == 1);
+    TEST_ASSERT(val64 == 1);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo/mybar64");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str);
+    TEST_ASSERT(test_get_called == 1);
+    TEST_ASSERT(!strcmp("1", tmp));
+    ctest_clear_call_state();
+}
diff --git 
a/sys/config/selftest-fcb2/src/testcases/config_test_getset_unknown.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_getset_unknown.c
new file mode 100644
index 0000000..cd21a82
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_getset_unknown.c
@@ -0,0 +1,48 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_getset_unknown)
+{
+    char name[80];
+    char tmp[64], *str;
+    int rc;
+
+    strcpy(name, "foo/bar");
+    rc = conf_set_value(name, "tmp");
+    TEST_ASSERT(rc != 0);
+    TEST_ASSERT(ctest_get_call_state() == 0);
+
+    strcpy(name, "foo/bar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str == NULL);
+    TEST_ASSERT(ctest_get_call_state() == 0);
+
+    strcpy(name, "myfoo/bar");
+    rc = conf_set_value(name, "tmp");
+    TEST_ASSERT(rc == OS_ENOENT);
+    TEST_ASSERT(test_set_called == 1);
+    ctest_clear_call_state();
+
+    strcpy(name, "myfoo/bar");
+    str = conf_get_value(name, tmp, sizeof(tmp));
+    TEST_ASSERT(str == NULL);
+    TEST_ASSERT(test_get_called == 1);
+    ctest_clear_call_state();
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_save_1_fcb.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_save_1_fcb.c
new file mode 100644
index 0000000..43ab8de
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_save_1_fcb.c
@@ -0,0 +1,48 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_save_1_fcb)
+{
+    int rc;
+    struct conf_fcb2 cf;
+
+    config_wipe_srcs();
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    val8 = 33;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    val8 = 0;
+
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 33);
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_save_2_fcb.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_save_2_fcb.c
new file mode 100644
index 0000000..da9c0cb
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_save_2_fcb.c
@@ -0,0 +1,87 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_save_2_fcb)
+{
+    int rc;
+    struct conf_fcb2 cf;
+    char test_value[CONF_TEST_FCB_VAL_STR_CNT][CONF_MAX_VAL_LEN];
+    int i;
+
+    config_wipe_srcs();
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    config_test_fill_area(test_value, 0);
+    memcpy(val_string, test_value, sizeof(val_string));
+
+    val8 = 42;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    val8 = 0;
+    memset(val_string[0], 0, sizeof(val_string[0]));
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 42);
+    TEST_ASSERT(!strcmp(val_string[0], test_value[0]));
+    test_export_block = 1;
+
+    /*
+     * Now add the number of settings to max. Keep adjusting the test_data,
+     * check that rollover happens when it's supposed to.
+     */
+    c2_var_count = 64;
+
+    for (i = 0; i < 32; i++) {
+        config_test_fill_area(test_value, i);
+        memcpy(val_string, test_value, sizeof(val_string));
+
+        rc = conf_save();
+        TEST_ASSERT(rc == 0);
+
+        memset(val_string, 0, sizeof(val_string));
+
+        val8 = 0;
+        rc = conf_load();
+        TEST_ASSERT(rc == 0);
+        {
+            int i;
+
+            for (i = 0; i < sizeof(val_string); i++) {
+                if (((char *)val_string)[i] != (((char *)test_value)[i])) {
+                    printf("diff at off %d\n", i);
+                }
+            }
+        }
+        TEST_ASSERT(!memcmp(val_string, test_value, sizeof(val_string)));
+        TEST_ASSERT(val8 == 42);
+    }
+    c2_var_count = 0;
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_save_3_fcb.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_save_3_fcb.c
new file mode 100644
index 0000000..99cb89a
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_save_3_fcb.c
@@ -0,0 +1,53 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_save_3_fcb)
+{
+    int rc;
+    struct conf_fcb2 cf;
+    int i;
+
+    config_wipe_srcs();
+    config_wipe_fcb2(fcb_range, CONF_TEST_FCB_RANGE_CNT);
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    for (i = 0; i < 4096; i++) {
+        val32 = i;
+
+        rc = conf_save();
+        TEST_ASSERT(rc == 0);
+
+        val32 = 0;
+
+        rc = conf_load();
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(val32 == i);
+    }
+}
diff --git a/sys/config/selftest-fcb2/src/testcases/config_test_save_one_fcb.c 
b/sys/config/selftest-fcb2/src/testcases/config_test_save_one_fcb.c
new file mode 100644
index 0000000..1ae9915
--- /dev/null
+++ b/sys/config/selftest-fcb2/src/testcases/config_test_save_one_fcb.c
@@ -0,0 +1,57 @@
+/*
+ * 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 "conf_test_fcb2.h"
+
+TEST_CASE_SELF(config_test_save_one_fcb)
+{
+    int rc;
+    struct conf_fcb2 cf;
+
+    config_wipe_srcs();
+    config_wipe_fcb2(fcb_range, CONF_TEST_FCB_RANGE_CNT);
+
+    cf.cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC);
+    cf.cf2_fcb.f_range_cnt = CONF_TEST_FCB_RANGE_CNT;
+    cf.cf2_fcb.f_sector_cnt = fcb_range[0].fsr_sector_count;
+    cf.cf2_fcb.f_ranges = fcb_range;
+
+    rc = conf_fcb2_src(&cf);
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_fcb2_dst(&cf);
+    TEST_ASSERT(rc == 0);
+
+    val8 = 33;
+    rc = conf_save();
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_save_one("myfoo/mybar", "42");
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 42);
+
+    rc = conf_save_one("myfoo/mybar", "44");
+    TEST_ASSERT(rc == 0);
+
+    rc = conf_load();
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(val8 == 44);
+}
diff --git a/sys/config/pkg.yml b/sys/config/selftest-fcb2/syscfg.yml
similarity index 54%
copy from sys/config/pkg.yml
copy to sys/config/selftest-fcb2/syscfg.yml
index 93fe279..87e8798 100644
--- a/sys/config/pkg.yml
+++ b/sys/config/selftest-fcb2/syscfg.yml
@@ -1,4 +1,3 @@
-#
 # 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
@@ -6,7 +5,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,24 +16,9 @@
 # under the License.
 #
 
-pkg.name: sys/config
-pkg.description: Configuration management for embedded systems.
-pkg.author: "Apache Mynewt <[email protected]>"
-pkg.homepage: "http://mynewt.apache.org/";
-pkg.keywords:
-
-pkg.deps:
-    - "@apache-mynewt-core/encoding/base64"
-pkg.deps.CONFIG_CLI:
-    - "@apache-mynewt-core/sys/shell"
-pkg.deps.CONFIG_NEWTMGR:
-    - "@apache-mynewt-core/encoding/cborattr"
-    - "@apache-mynewt-core/mgmt/mgmt"
-pkg.deps.CONFIG_FCB:
-    - "@apache-mynewt-core/fs/fcb"
-pkg.deps.CONFIG_NFFS:
-    - "@apache-mynewt-core/fs/nffs"
-
-pkg.init:
-    config_pkg_init: 'MYNEWT_VAL(CONFIG_SYSINIT_STAGE_1)'
-    config_pkg_init_stage2: 'MYNEWT_VAL(CONFIG_SYSINIT_STAGE_2)'
+syscfg.vals:
+    CONFIG_FCB2: 1
+    CONFIG_FCB: 0
+    CONFIG_AUTO_INIT: 0
+    MCU_FLASH_STYLE_ST: 1
+    MCU_FLASH_STYLE_NORDIC: 0
diff --git a/sys/config/src/config_fcb2.c b/sys/config/src/config_fcb2.c
new file mode 100644
index 0000000..f3627ae
--- /dev/null
+++ b/sys/config/src/config_fcb2.c
@@ -0,0 +1,356 @@
+/*
+ * 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/mynewt.h>
+
+#if MYNEWT_VAL(CONFIG_FCB2)
+
+#include <fcb/fcb.h>
+#include <string.h>
+
+#include "config/config.h"
+#include "config/config_store.h"
+#include "config/config_fcb2.h"
+#include "config/config_generic_kv.h"
+#include "config_priv.h"
+
+#define CONF_FCB2_VERS         2
+
+struct conf_fcb2_load_cb_arg {
+    conf_store_load_cb cb;
+    void *cb_arg;
+};
+
+struct conf_kv_load_cb_arg {
+    const char *name;
+    char *value;
+    size_t len;
+};
+
+static int conf_fcb2_load(struct conf_store *, conf_store_load_cb cb,
+                          void *cb_arg);
+static int conf_fcb2_save(struct conf_store *, const char *name,
+                          const char *value);
+
+static struct conf_store_itf conf_fcb2_itf = {
+    .csi_load = conf_fcb2_load,
+    .csi_save = conf_fcb2_save,
+};
+
+int
+conf_fcb2_src(struct conf_fcb2 *cf)
+{
+    int rc;
+
+    cf->cf2_fcb.f_version = CONF_FCB2_VERS;
+    if (cf->cf2_fcb.f_sector_cnt > 1) {
+        cf->cf2_fcb.f_scratch_cnt = 1;
+    } else {
+        cf->cf2_fcb.f_scratch_cnt = 0;
+    }
+    while (1) {
+        rc = fcb_init(&cf->cf2_fcb);
+        if (rc) {
+            return OS_INVALID_PARM;
+        }
+
+        /*
+         * Check if system was reset in middle of emptying a sector. This
+         * situation is recognized by checking if the scratch block is missing.
+         */
+        if (cf->cf2_fcb.f_scratch_cnt &&
+            fcb_free_sector_cnt(&cf->cf2_fcb) < 1) {
+            fcb_sector_erase(&cf->cf2_fcb, cf->cf2_fcb.f_active.fe_sector);
+        } else {
+            break;
+        }
+    }
+
+    cf->cf2_store.cs_itf = &conf_fcb2_itf;
+    conf_src_register(&cf->cf2_store);
+
+    return OS_OK;
+}
+
+int
+conf_fcb2_dst(struct conf_fcb2 *cf)
+{
+    cf->cf2_store.cs_itf = &conf_fcb2_itf;
+    conf_dst_register(&cf->cf2_store);
+
+    return OS_OK;
+}
+
+static int
+conf_fcb2_load_cb(struct fcb_entry *loc, void *arg)
+{
+    struct conf_fcb2_load_cb_arg *argp;
+    char buf[CONF_MAX_NAME_LEN + CONF_MAX_VAL_LEN + 32];
+    char *name_str;
+    char *val_str;
+    int rc;
+    int len;
+
+    argp = (struct conf_fcb2_load_cb_arg *)arg;
+
+    len = loc->fe_data_len;
+    if (len >= sizeof(buf)) {
+        len = sizeof(buf) - 1;
+    }
+
+    rc = fcb_read(loc, 0, buf, len);
+    if (rc) {
+        return 0;
+    }
+    buf[len] = '\0';
+
+    rc = conf_line_parse(buf, &name_str, &val_str);
+    if (rc) {
+        return 0;
+    }
+    argp->cb(name_str, val_str, argp->cb_arg);
+    return 0;
+}
+
+static int
+conf_fcb2_load(struct conf_store *cs, conf_store_load_cb cb, void *cb_arg)
+{
+    struct conf_fcb2 *cf = (struct conf_fcb2 *)cs;
+    struct conf_fcb2_load_cb_arg arg;
+    int rc;
+
+    arg.cb = cb;
+    arg.cb_arg = cb_arg;
+    rc = fcb_walk(&cf->cf2_fcb, FCB_SECTOR_OLDEST, conf_fcb2_load_cb, &arg);
+    if (rc) {
+        return OS_EINVAL;
+    }
+    return OS_OK;
+}
+
+static int
+conf_fcb2_var_read(struct fcb_entry *loc, char *buf, char **name, char **val)
+{
+    int rc;
+
+    rc = fcb_read(loc, 0, buf, loc->fe_data_len);
+    if (rc) {
+        return rc;
+    }
+    buf[loc->fe_data_len] = '\0';
+    rc = conf_line_parse(buf, name, val);
+    return rc;
+}
+
+static void
+conf_fcb2_compress_internal(struct fcb *fcb,
+                            int (*copy_or_not)(const char *name, const char 
*val,
+                                               void *cn_arg),
+                            void *cn_arg)
+{
+    int rc;
+    char buf1[CONF_MAX_NAME_LEN + CONF_MAX_VAL_LEN + 32];
+    char buf2[CONF_MAX_NAME_LEN + CONF_MAX_VAL_LEN + 32];
+    struct fcb_entry loc1;
+    struct fcb_entry loc2;
+    char *name1, *val1;
+    char *name2, *val2;
+    int copy;
+
+    rc = fcb_append_to_scratch(fcb);
+    if (rc) {
+        return; /* XXX */
+    }
+
+    loc1.fe_range = NULL;
+    loc1.fe_entry_num = 0;
+    while (fcb_getnext(fcb, &loc1) == 0) {
+        if (loc1.fe_sector != fcb->f_oldest_sec) {
+            break;
+        }
+        rc = conf_fcb2_var_read(&loc1, buf1, &name1, &val1);
+        if (rc) {
+            continue;
+        }
+        if (!val1) {
+            continue;
+        }
+        loc2 = loc1;
+        copy = 1;
+        while (fcb_getnext(fcb, &loc2) == 0) {
+            rc = conf_fcb2_var_read(&loc2, buf2, &name2, &val2);
+            if (rc) {
+                continue;
+            }
+            if (!strcmp(name1, name2)) {
+                copy = 0;
+                break;
+            }
+        }
+        if (!copy) {
+            continue;
+        }
+
+        if (copy_or_not) {
+            if (copy_or_not(name1, val1, cn_arg)) {
+                /* Copy rejected */
+                continue;
+            }
+        }
+        /*
+         * Can't find one. Must copy.
+         */
+        rc = fcb_read(&loc1, 0, buf1, loc1.fe_data_len);
+        if (rc) {
+            continue;
+        }
+        rc = fcb_append(fcb, loc1.fe_data_len, &loc2);
+        if (rc) {
+            continue;
+        }
+        rc = fcb_write(&loc2, 0, buf1, loc1.fe_data_len);
+        if (rc) {
+            continue;
+        }
+        fcb_append_finish(&loc2);
+    }
+    rc = fcb_rotate(fcb);
+    if (rc) {
+        /* XXXX */
+        ;
+    }
+}
+
+static int
+conf_fcb2_append(struct fcb *fcb, char *buf, int len)
+{
+    int rc;
+    int i;
+    struct fcb_entry loc;
+
+    for (i = 0; i < 10; i++) {
+        rc = fcb_append(fcb, len, &loc);
+        if (rc != FCB_ERR_NOSPACE) {
+            break;
+        }
+        if (fcb->f_scratch_cnt == 0) {
+            return OS_ENOMEM;
+        }
+        conf_fcb2_compress_internal(fcb, NULL, NULL);
+    }
+    if (rc) {
+        return OS_EINVAL;
+    }
+    rc = fcb_write(&loc, 0, buf, len);
+    if (rc) {
+        return OS_EINVAL;
+    }
+    fcb_append_finish(&loc);
+    return OS_OK;
+}
+
+static int
+conf_fcb2_save(struct conf_store *cs, const char *name, const char *value)
+{
+    struct conf_fcb2 *cf = (struct conf_fcb2 *)cs;
+
+    return conf_fcb_kv_save(&cf->cf2_fcb, name, value);
+}
+
+void
+conf_fcb2_compress(struct conf_fcb2 *cf,
+                   int (*copy_or_not)(const char *name, const char *val,
+                                      void *cn_arg),
+                   void *cn_arg)
+{
+    conf_fcb2_compress_internal(&cf->cf2_fcb, copy_or_not, cn_arg);
+}
+
+static int
+conf_kv_load_cb(struct fcb_entry *loc, void *arg)
+{
+    struct conf_kv_load_cb_arg *cb_arg = arg;
+    char buf[CONF_MAX_NAME_LEN + CONF_MAX_VAL_LEN + 32];
+    char *name_str;
+    char *val_str;
+    int rc;
+    int len;
+
+    len = loc->fe_data_len;
+    if (len >= sizeof(buf)) {
+        len = sizeof(buf) - 1;
+    }
+
+    rc = fcb_read(loc, 0, buf, len);
+    if (rc) {
+        return 0;
+    }
+    buf[len] = '\0';
+
+    rc = conf_line_parse(buf, &name_str, &val_str);
+    if (rc) {
+        return 0;
+    }
+
+    if (strcmp(name_str, cb_arg->name)) {
+        return 0;
+    }
+
+    strncpy(cb_arg->value, val_str, cb_arg->len);
+    cb_arg->value[cb_arg->len - 1] = '\0';
+
+    return 0;
+}
+
+int
+conf_fcb_kv_load(struct fcb *fcb, const char *name, char *value, size_t len)
+{
+    struct conf_kv_load_cb_arg arg;
+    int rc;
+
+    arg.name = name;
+    arg.value = value;
+    arg.len = len;
+
+    rc = fcb_walk(fcb, 0, conf_kv_load_cb, &arg);
+    if (rc) {
+        return OS_EINVAL;
+    }
+
+    return OS_OK;
+}
+
+int
+conf_fcb_kv_save(struct fcb *fcb, const char *name, const char *value)
+{
+    char buf[CONF_MAX_NAME_LEN + CONF_MAX_VAL_LEN + 32];
+    int len;
+
+    if (!name) {
+        return OS_INVALID_PARM;
+    }
+
+    len = conf_line_make(buf, sizeof(buf), name, value);
+    if (len < 0 || len + 2 > sizeof(buf)) {
+        return OS_INVALID_PARM;
+    }
+    return conf_fcb2_append(fcb, buf, len);
+}
+
+#endif
diff --git a/sys/config/src/config_init.c b/sys/config/src/config_init.c
index 9a3f9e3..ca5cccc 100644
--- a/sys/config/src/config_init.c
+++ b/sys/config/src/config_init.c
@@ -88,6 +88,44 @@ config_init_fcb(void)
     SYSINIT_PANIC_ASSERT(rc == 0);
 }
 
+#elif MYNEWT_VAL(CONFIG_FCB2)
+
+#include "fcb/fcb.h"
+#include "config/config_fcb2.h"
+
+static struct flash_sector_range config_init_fcb2_sector_range;
+static struct conf_fcb2 config_init_conf_fcb2 = {
+    .cf2_fcb.f_magic = MYNEWT_VAL(CONFIG_FCB_MAGIC),
+    .cf2_fcb.f_range_cnt = 1,
+    .cf2_fcb.f_ranges = &config_init_fcb2_sector_range
+};
+
+static void
+config_init_fcb2(void)
+{
+    int cnt;
+    int rc;
+
+    cnt = 1;
+    rc = flash_area_to_sector_ranges(MYNEWT_VAL(CONFIG_FCB_FLASH_AREA), &cnt,
+                                     &config_init_fcb2_sector_range);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    config_init_conf_fcb2.cf2_fcb.f_sector_cnt =
+      config_init_fcb2_sector_range.fsr_sector_count;
+
+    rc = conf_fcb2_src(&config_init_conf_fcb2);
+    if (rc) {
+        flash_area_erase(&config_init_fcb2_sector_range.fsr_flash_area, 0,
+                         config_init_fcb2_sector_range.fsr_sector_count *
+                         config_init_fcb2_sector_range.fsr_sector_size);
+        rc = conf_fcb2_src(&config_init_conf_fcb2);
+    }
+    SYSINIT_PANIC_ASSERT(rc == 0);
+    rc = conf_fcb2_dst(&config_init_conf_fcb2);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+}
+
 #endif
 #endif
 
@@ -104,6 +142,8 @@ config_pkg_init(void)
     config_init_fs();
 #elif MYNEWT_VAL(CONFIG_FCB)
     config_init_fcb();
+#elif MYNEWT_VAL(CONFIG_FCB2)
+    config_init_fcb2();
 #endif
 #endif
 }
diff --git a/sys/config/syscfg.yml b/sys/config/syscfg.yml
index b3995f7..684f962 100644
--- a/sys/config/syscfg.yml
+++ b/sys/config/syscfg.yml
@@ -22,12 +22,21 @@ syscfg.defs:
         value: 0
         restrictions:
             - '!CONFIG_NFFS'
+            - '!CONFIG_FCB2'
             - 'CONFIG_FCB_FLASH_AREA'
     CONFIG_NFFS:
         description: 'Config default storage is in NFFS'
         value: 0
         restrictions:
             - '!CONFIG_FCB'
+            - '!CONFIG_FCB2'
+    CONFIG_FCB2:
+        description: 'Config default storage is in FCB2'
+        value: 0
+        restrictions:
+            - '!CONFIG_FCB'
+            - '!CONFIG_NFFS'
+            - 'CONFIG_FCB_FLASH_AREA'
     CONFIG_NEWTMGR:
         description: 'Newtmgr access to config'
         value: 0
@@ -63,7 +72,7 @@ syscfg.defs:
             Config CLI commands read 1, write 2, read/write 3
         value: 3
 
-syscfg.defs.CONFIG_FCB:
+syscfg.defs.(CONFIG_FCB || CONFIG_FCB2):
     CONFIG_FCB_FLASH_AREA:
         description: 'BSP flash area for config'
         type: 'flash_owner'

Reply via email to