diff --git a/Makefile.am b/Makefile.am
index 46fdfdc41..c39282beb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -79,6 +79,10 @@ PRETTY_SUBDIRS = \
tools \
$(NULL)
+# Ignore the pseudo flash files on Posix platform during diskcheck
+distcleancheck_listfiles = \
+ $(AM_V_at)find . -type f -name "*flash"
+
#
# Package version files:
#
diff --git a/etc/visual-studio/libopenthread-windows.vcxproj b/etc/visual-studio/libopenthread-windows.vcxproj
index f53a7bbce..15c9487db 100644
--- a/etc/visual-studio/libopenthread-windows.vcxproj
+++ b/etc/visual-studio/libopenthread-windows.vcxproj
@@ -20,6 +20,7 @@
+
@@ -171,4 +172,4 @@
-
\ No newline at end of file
+
diff --git a/etc/visual-studio/libopenthread-windows.vcxproj.filters b/etc/visual-studio/libopenthread-windows.vcxproj.filters
index bc34f58f9..68f59f463 100644
--- a/etc/visual-studio/libopenthread-windows.vcxproj.filters
+++ b/etc/visual-studio/libopenthread-windows.vcxproj.filters
@@ -13,6 +13,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -40,4 +43,4 @@
Header Files
-
\ No newline at end of file
+
diff --git a/examples/platforms/cc2538/platform.c b/examples/platforms/cc2538/platform.c
index 72bcea2b2..15a9ca23d 100644
--- a/examples/platforms/cc2538/platform.c
+++ b/examples/platforms/cc2538/platform.c
@@ -33,6 +33,7 @@
*/
#include
+#include
#include "platform-cc2538.h"
otInstance *sInstance;
@@ -43,6 +44,7 @@ void PlatformInit(int argc, char *argv[])
cc2538RandomInit();
cc2538RadioInit();
otPlatUartEnable();
+ otPlatFlashInit();
(void)argc;
(void)argv;
diff --git a/examples/platforms/posix/flash-windows-stubs.c b/examples/platforms/posix/flash-windows-stubs.c
new file mode 100644
index 000000000..b174fefe9
--- /dev/null
+++ b/examples/platforms/posix/flash-windows-stubs.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "platform-posix.h"
+
+ThreadError otPlatFlashInit(void)
+{
+ return kThreadError_NotImplemented;
+}
+
+uint32_t otPlatFlashGetSize(void)
+{
+ return 0;
+}
+
+ThreadError otPlatFlashErasePage(uint32_t aAddress)
+{
+ return kThreadError_NotImplemented;
+}
+
+ThreadError otPlatFlashStatusWait(uint32_t aTimeout)
+{
+ return kThreadError_None;
+}
+
+uint32_t otPlatFlashWrite(uint32_t aAddress, uint8_t *aData, uint32_t aSize)
+{
+ return 0;
+}
+
+uint32_t otPlatFlashRead(uint32_t aAddress, uint8_t *aData, uint32_t aSize)
+{
+ return 0;
+}
diff --git a/examples/platforms/posix/flash.c b/examples/platforms/posix/flash.c
index 52aefeddb..9aa853007 100644
--- a/examples/platforms/posix/flash.c
+++ b/examples/platforms/posix/flash.c
@@ -53,9 +53,12 @@ enum
ThreadError otPlatFlashInit(void)
{
ThreadError error = kThreadError_None;
- char fileName[16];
+ char fileName[20];
struct stat st;
bool create = false;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
memset(&st, 0, sizeof(st));
@@ -64,7 +67,7 @@ ThreadError otPlatFlashInit(void)
mkdir("tmp", 0777);
}
- snprintf(fileName, sizeof(fileName), "tmp/%d.flash", NODE_ID);
+ snprintf(fileName, sizeof(fileName), "tmp/%d_%d.flash", NODE_ID, (uint32_t)tv.tv_usec);
if (access(fileName, 0))
{
diff --git a/examples/platforms/posix/platform.c b/examples/platforms/posix/platform.c
index e83ee60bc..ee2f7d018 100644
--- a/examples/platforms/posix/platform.c
+++ b/examples/platforms/posix/platform.c
@@ -43,6 +43,7 @@
#include
#include
+#include
#include
uint32_t NODE_ID = 1;
@@ -68,6 +69,7 @@ void PlatformInit(int argc, char *argv[])
platformAlarmInit();
platformRadioInit();
platformRandomInit();
+ otPlatFlashInit();
}
bool UartInitialized = false;
diff --git a/include/platform/settings.h b/include/platform/settings.h
index 1da0a0a51..c399534cd 100644
--- a/include/platform/settings.h
+++ b/include/platform/settings.h
@@ -36,6 +36,7 @@
#define OT_PLATFORM_SETTINGS_H 1
#include
+#include
#ifdef __cplusplus
extern "C" {
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index e35cd1d59..6f0492692 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -126,6 +126,7 @@ noinst_HEADERS = \
common/logging.hpp \
common/message.hpp \
common/new.hpp \
+ common/settings.hpp \
common/tasklet.hpp \
common/timer.hpp \
common/trickle_timer.hpp \
diff --git a/src/core/common/settings.hpp b/src/core/common/settings.hpp
new file mode 100644
index 000000000..5636580cf
--- /dev/null
+++ b/src/core/common/settings.hpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, The OpenThread Authors.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * This file includes functions for debugging.
+ */
+
+#ifndef SETTINGS_HPP_
+#define SETTINGS_HPP_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * This enumeration defines the keys of settings
+ *
+ */
+enum
+{
+ kKeyActiveDataset = 0x0001,
+ kKeyPendingDataset = 0x0002,
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // SETTINGS_HPP_
diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp
index 5a9092b2c..dfde5fbf2 100644
--- a/src/core/openthread.cpp
+++ b/src/core/openthread.cpp
@@ -50,6 +50,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -1019,6 +1020,13 @@ otInstance *otInstanceInit(void *aInstanceBuffer, size_t *aInstanceBufferSize)
// Construct the context
aInstance = new(aInstanceBuffer)otInstance();
+ // restore datasets
+ otPlatSettingsInit(aInstance);
+
+ aInstance->mThreadNetif.GetActiveDataset().Restore();
+
+ aInstance->mThreadNetif.GetPendingDataset().Restore();
+
exit:
otLogFuncExit();
@@ -1038,6 +1046,13 @@ otInstance *otInstanceInit()
// Construct the context
sInstance = new(&sInstanceRaw)otInstance();
+ // restore datasets
+ otPlatSettingsInit(sInstance);
+
+ sInstance->mThreadNetif.GetActiveDataset().Restore();
+
+ sInstance->mThreadNetif.GetPendingDataset().Restore();
+
exit:
otLogFuncExit();
diff --git a/src/core/thread/meshcop_dataset.cpp b/src/core/thread/meshcop_dataset.cpp
index 9591501b2..d629c70f9 100644
--- a/src/core/thread/meshcop_dataset.cpp
+++ b/src/core/thread/meshcop_dataset.cpp
@@ -35,21 +35,29 @@
#include
#include
+#include
+#include
#include
#include
namespace Thread {
namespace MeshCoP {
-Dataset::Dataset(const Tlv::Type aType) :
+Dataset::Dataset(otInstance *aInstance, const Tlv::Type aType) :
mType(aType),
- mLength(0)
+ mLength(0),
+ mInstance(aInstance)
{
}
-void Dataset::Clear(void)
+void Dataset::Clear(bool isLocal)
{
mLength = 0;
+
+ if (isLocal)
+ {
+ otPlatSettingsDelete(mInstance, mType == Tlv::kActiveTimestamp ? kKeyActiveDataset : kKeyPendingDataset, -1);
+ }
}
Tlv *Dataset::Get(Tlv::Type aType)
@@ -109,8 +117,6 @@ void Dataset::Get(otOperationalDataset &aDataset) const
const ActiveTimestampTlv *tlv = static_cast(cur);
aDataset.mActiveTimestamp = tlv->GetSeconds();
aDataset.mIsActiveTimestampSet = true;
-
- GetTimestamp();
break;
}
@@ -432,6 +438,18 @@ int Dataset::Compare(const Dataset &aCompare) const
return rval;
}
+ThreadError Dataset::Restore(void)
+{
+ return otPlatSettingsGet(mInstance, mType == Tlv::kActiveTimestamp ? kKeyActiveDataset : kKeyPendingDataset, 0, mTlvs,
+ reinterpret_cast(&mLength));
+}
+
+ThreadError Dataset::Store(void)
+{
+ return otPlatSettingsSet(mInstance, mType == Tlv::kActiveTimestamp ? kKeyActiveDataset : kKeyPendingDataset, mTlvs,
+ mLength);
+}
+
ThreadError Dataset::Set(const Tlv &aTlv)
{
ThreadError error = kThreadError_None;
diff --git a/src/core/thread/meshcop_dataset.hpp b/src/core/thread/meshcop_dataset.hpp
index 07872257e..8108f026a 100644
--- a/src/core/thread/meshcop_dataset.hpp
+++ b/src/core/thread/meshcop_dataset.hpp
@@ -56,13 +56,15 @@ public:
* @param[in] aType The type of the dataset, active or pending.
*
*/
- Dataset(const Tlv::Type aType);
+ Dataset(otInstance *aInstance, const Tlv::Type aType);
/**
* This method clears the Dataset.
*
+ * @param[in] isLocal TRUE to delete the local dataset from non-volatile memory, FALSE not.
+ *
*/
- void Clear(void);
+ void Clear(bool isLocal);
/**
* This method returns a pointer to the TLV.
@@ -128,6 +130,24 @@ public:
*/
int Compare(const Dataset &aCompare) const;
+ /**
+ * This method restores dataset from non-volatile memory.
+ *
+ * @retval kThreadError_None Successfully restore the dataset.
+ * @retval kThreadError_NotFound There is no corresponding dataset stored in non-volatile memory.
+ *
+ */
+ ThreadError Restore(void);
+
+ /**
+ * This method stores dataset into non-volatile memory.
+ *
+ * @retval kThreadError_None Successfully store the dataset.
+ * @retval kThreadError_NoBufs Could not store the dataset due to insufficient memory space.
+ *
+ */
+ ThreadError Store(void);
+
/**
* This method sets a TLV in the Dataset.
*
@@ -153,6 +173,7 @@ private:
Tlv::Type mType; ///< Active or Pending
uint8_t mTlvs[kMaxSize]; ///< The Dataset buffer
uint8_t mLength; ///< The number of valid bytes in @var mTlvs
+ otInstance *mInstance; ///< The pointer to an OpenThread instance
};
} // namespace MeshCoP
diff --git a/src/core/thread/meshcop_dataset_manager.cpp b/src/core/thread/meshcop_dataset_manager.cpp
index 27efcd9dc..c7f772812 100644
--- a/src/core/thread/meshcop_dataset_manager.cpp
+++ b/src/core/thread/meshcop_dataset_manager.cpp
@@ -57,8 +57,8 @@ namespace MeshCoP {
DatasetManager::DatasetManager(ThreadNetif &aThreadNetif, const Tlv::Type aType, const char *aUriSet,
const char *aUriGet):
- mLocal(aType),
- mNetwork(aType),
+ mLocal(aThreadNetif.GetInstance(), aType),
+ mNetwork(aThreadNetif.GetInstance(), aType),
mCoapServer(aThreadNetif.GetCoapServer()),
mMle(aThreadNetif.GetMle()),
mNetif(aThreadNetif),
@@ -75,6 +75,7 @@ ThreadError DatasetManager::Set(const otOperationalDataset &aDataset, uint8_t &a
ThreadError error = kThreadError_None;
SuccessOrExit(error = mLocal.Set(aDataset));
+ mLocal.Store();
aFlags = kFlagLocalUpdated;
switch (mMle.GetDeviceState())
@@ -101,7 +102,12 @@ exit:
ThreadError DatasetManager::Clear(uint8_t &aFlags)
{
- mNetwork.Clear();
+ if (mLocal.Compare(mNetwork) == 0)
+ {
+ mLocal.Clear(true);
+ }
+
+ mNetwork.Clear(false);
HandleNetworkUpdate(aFlags);
return kThreadError_None;
}
@@ -135,6 +141,7 @@ void DatasetManager::HandleNetworkUpdate(uint8_t &aFlags)
if (compare > 0)
{
mLocal = mNetwork;
+ mLocal.Store();
aFlags |= kFlagLocalUpdated;
}
else if (compare < 0)
@@ -352,6 +359,7 @@ ThreadError DatasetManager::Set(Coap::Header &aHeader, Message &aMessage, const
offset += sizeof(Tlv) + data.tlv.GetLength();
}
+ mLocal.Store();
mNetwork = mLocal;
mNetworkDataLeader.IncrementVersion();
mNetworkDataLeader.IncrementStableVersion();
@@ -644,8 +652,59 @@ ActiveDataset::ActiveDataset(ThreadNetif &aThreadNetif):
{
}
+void ActiveDataset::Restore(void)
+{
+ mLocal.Restore();
+ ApplyConfiguration();
+}
+
void ActiveDataset::StartLeader(void)
{
+ if (mLocal.GetTimestamp() == NULL)
+ {
+ otOperationalDataset dataset;
+
+ memset(&dataset, 0, sizeof(dataset));
+
+ // Active Timestamp
+ dataset.mActiveTimestamp = 0;
+ dataset.mIsActiveTimestampSet = true;
+
+ // Channel
+ dataset.mChannel = mNetif.GetMac().GetChannel();
+ dataset.mIsChannelSet = true;
+
+ // Extended PAN ID
+ memcpy(dataset.mExtendedPanId.m8, mNetif.GetMac().GetExtendedPanId(), sizeof(dataset.mExtendedPanId));
+ dataset.mIsExtendedPanIdSet = true;
+
+ // Mesh-Local Prefix
+ memcpy(dataset.mMeshLocalPrefix.m8, mNetif.GetMle().GetMeshLocalPrefix(), sizeof(dataset.mMeshLocalPrefix));
+ dataset.mIsMeshLocalPrefixSet = true;
+
+ // Master Key
+ const uint8_t *key;
+ uint8_t keyLength;
+
+ key = mNetif.GetKeyManager().GetMasterKey(&keyLength);
+ memcpy(dataset.mMasterKey.m8, key, keyLength);
+ dataset.mIsMasterKeySet = true;
+
+ // Network Name
+ const char *name;
+
+ name = mNetif.GetMac().GetNetworkName();
+ memcpy(dataset.mNetworkName.m8, name, strlen(name));
+ dataset.mIsNetworkNameSet = true;
+
+ // Pan ID
+ dataset.mPanId = mNetif.GetMac().GetPanId();
+ dataset.mIsPanIdSet = true;
+
+ mLocal.Set(dataset);
+ }
+
+ mLocal.Store();
mNetwork = mLocal;
mCoapServer.AddResource(mResourceGet);
mCoapServer.AddResource(mResourceSet);
@@ -812,9 +871,16 @@ PendingDataset::PendingDataset(ThreadNetif &aThreadNetif):
{
}
+void PendingDataset::Restore(void)
+{
+ mLocal.Restore();
+ ResetDelayTimer(kFlagLocalUpdated);
+}
+
void PendingDataset::StartLeader(void)
{
UpdateDelayTimer(mLocal, mLocalTime);
+ mLocal.Store();
mNetwork = mLocal;
ResetDelayTimer(kFlagNetworkUpdated);
@@ -972,6 +1038,8 @@ void PendingDataset::HandleTimer(void)
assert(delayTimer != NULL && delayTimer->GetDelayTimer() == 0);
mNetif.GetActiveDataset().Set(mNetwork);
+
+ Clear();
}
} // namespace MeshCoP
diff --git a/src/core/thread/meshcop_dataset_manager.hpp b/src/core/thread/meshcop_dataset_manager.hpp
index 9362a5bf1..9284b6298 100644
--- a/src/core/thread/meshcop_dataset_manager.hpp
+++ b/src/core/thread/meshcop_dataset_manager.hpp
@@ -115,6 +115,8 @@ class ActiveDataset: public DatasetManager
public:
ActiveDataset(ThreadNetif &aThreadNetif);
+ void Restore(void);
+
void StartLeader(void);
void StopLeader(void);
@@ -147,6 +149,8 @@ class PendingDataset: public DatasetManager
public:
PendingDataset(ThreadNetif &aThreadNetif);
+ void Restore(void);
+
void StartLeader(void);
void StopLeader(void);