blob: 8633c6fa03c62e8c604c877e92b3da9e6dfd3526 [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed 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.
*/
/**
* @file
* This file contains implementation of the basic message codecs
* used in Time Services #WEAVE_CONFIG_TIME must be defined if
* Time Services are needed.
*
*/
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <Weave/Core/WeaveEncoding.h>
#include <Weave/Profiles/time/WeaveTime.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Support/ErrorStr.h>
#include <Weave/Support/MathUtils.h>
#include <Weave/Support/logging/WeaveLogging.h>
#if WEAVE_CONFIG_TIME
using namespace nl::Weave::Encoding;
using namespace nl::Weave::Profiles::Time;
TimeChangeNotification::TimeChangeNotification(void)
{
}
WEAVE_ERROR TimeChangeNotification::Encode(PacketBuffer* const aMsg)
{
// note that we assume the buffer is big enough for this message
uint8_t *cursor = aMsg->Start();
// write stuff into the message body
// 16 reserved bits, all set to 0
LittleEndian::Write16(cursor, 0);
aMsg->SetDataLength(cursor - aMsg->Start());
return WEAVE_NO_ERROR;
}
WEAVE_ERROR TimeChangeNotification::Decode(TimeChangeNotification * const aObject, PacketBuffer* const aMsg)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// we should have at least 16 reserved bits
if (aMsg->DataLength() < 2)
{
ExitNow(err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH);
}
{
const uint8_t *cursor = aMsg->Start();
const uint16_t status = LittleEndian::Read16(cursor);
// non-zero reserved bits indicate the message has some extension that we are not aware of
if (status != 0)
{
WeaveLogDetail(TimeService,
"TimeSyncRequestAdvisory unknown extension, as reserved bits are not all 0s (0x%X)",
status);
}
}
exit:
WeaveLogFunctError(err);
return err;
}
TimeSyncRequest::TimeSyncRequest(void) :
mLikelihoodForResponse(kLikelihoodForResponse_Min)
{
}
void TimeSyncRequest::Init(const uint8_t aLikelihood, const bool aIsTimeCoordinator)
{
mLikelihoodForResponse = aLikelihood;
mIsTimeCoordinator = aIsTimeCoordinator;
}
WEAVE_ERROR TimeSyncRequest::Encode(PacketBuffer* const aMsg)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// validate the source object first
// Note that we cannot put check on kLikelihoodForResponse_Min here, because it's currently set to 0.
// The compiler would argue it's unnecessary
if (mLikelihoodForResponse > kLikelihoodForResponse_Max)
{
ExitNow(err = WEAVE_ERROR_INCORRECT_STATE);
}
{
// Compose the 16-bit status
const uint16_t status = ((mLikelihoodForResponse & 0x1F) << 1) | (mIsTimeCoordinator ? 1 : 0);
// write stuff into the message body
// note that we assume the buffer is big enough for this message
uint8_t *cursor = aMsg->Start();
LittleEndian::Write16(cursor, status);
// calculate the message length again
aMsg->SetDataLength(cursor - aMsg->Start());
}
exit:
WeaveLogFunctError(err);
return err;
}
WEAVE_ERROR TimeSyncRequest::Decode(TimeSyncRequest * const aObject, PacketBuffer* const aMsg)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// at least 2 bytes of status
if (aMsg->DataLength() < 2)
{
ExitNow(err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH);
}
{
const uint8_t *cursor = aMsg->Start();
const uint16_t status = LittleEndian::Read16(cursor);
// lowest 1-bit
aObject->mIsTimeCoordinator = status & 0x1;
// next 5-bit
aObject->mLikelihoodForResponse = (status >> 1) & 0x1F;
// Note that we cannot put check on kLikelihoodForResponse_Min here, because it's currently set to 0.
// The compiler would argue it's unnecessary
if (aObject->mLikelihoodForResponse > kLikelihoodForResponse_Max)
{
ExitNow(err = WEAVE_ERROR_MESSAGE_INCOMPLETE);
}
// anything other than the low 6-bit is reserved
// non-zero reserved bits indicate the message has some extension that we are not aware of
if ((status >> 6) != 0)
{
WeaveLogDetail(TimeService, "TimeSyncRequest unknown extension, as reserved bits are not all 0s (0x%X)",
status);
}
}
exit:
WeaveLogFunctError(err);
return err;
}
TimeSyncResponse::TimeSyncResponse(void)
{
}
void TimeSyncResponse::Init(const TimeSyncRole aRole, const timesync_t aTimeOfRequest,
const timesync_t aTimeOfResponse,
const uint8_t aNumContributorInLastLocalSync, const uint16_t aTimeSinceLastSyncWithServer_min)
{
mIsTimeCoordinator = (kTimeSyncRole_Coordinator == aRole) ? true : false;
mTimeOfRequest = aTimeOfRequest;
mTimeOfResponse = aTimeOfResponse;
mNumContributorInLastLocalSync = aNumContributorInLastLocalSync;
// clamp the number of contacts to kNumberOfContact_Max
if (mNumContributorInLastLocalSync > kNumberOfContributor_Max)
{
mNumContributorInLastLocalSync = kNumberOfContributor_Max;
}
if (aTimeSinceLastSyncWithServer_min <= kTimeSinceLastSyncWithServer_Max)
{
mTimeSinceLastSyncWithServer_min = aTimeSinceLastSyncWithServer_min;
}
else
{
mTimeSinceLastSyncWithServer_min = kTimeSinceLastSyncWithServer_Invalid;
}
}
WEAVE_ERROR TimeSyncResponse::Encode(PacketBuffer* const aMsg)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// Compose the 16-bit status
const uint16_t status = uint16_t(((mNumContributorInLastLocalSync & 0x1F) << 1) | (mIsTimeCoordinator ? 1 : 0));
const uint16_t freshness = uint16_t(mTimeSinceLastSyncWithServer_min & 0xFFF);
// write stuff into the message body
// note that we assume the buffer is big enough for this message
uint8_t *cursor = aMsg->Start();
LittleEndian::Write16(cursor, status);
LittleEndian::Write64(cursor, mTimeOfRequest);
LittleEndian::Write64(cursor, mTimeOfResponse);
LittleEndian::Write16(cursor, freshness);
// calculate the message length again
aMsg->SetDataLength(cursor - aMsg->Start());
WeaveLogFunctError(err);
return err;
}
WEAVE_ERROR TimeSyncResponse::Decode(TimeSyncResponse * const aObject, PacketBuffer* const aMsg)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
// at least 2 bytes of status plus 8 bytes of timestamp
if (aMsg->DataLength() < 20)
{
ExitNow(err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH);
}
{
const uint8_t *cursor = aMsg->Start();
const uint16_t status = LittleEndian::Read16(cursor);
aObject->mTimeOfRequest = LittleEndian::Read64(cursor);
aObject->mTimeOfResponse = LittleEndian::Read64(cursor);
aObject->mTimeSinceLastSyncWithServer_min = (LittleEndian::Read16(cursor) & 0xFFF);
if (aObject->mTimeOfRequest & MASK_INVALID_TIMESYNC)
{
ExitNow(err = WEAVE_ERROR_MESSAGE_INCOMPLETE);
}
if (aObject->mTimeOfResponse & MASK_INVALID_TIMESYNC)
{
ExitNow(err = WEAVE_ERROR_MESSAGE_INCOMPLETE);
}
// lowest 1-bit
aObject->mIsTimeCoordinator = bool(status & 0x1);
// next 5-bit
aObject->mNumContributorInLastLocalSync = ((status >> 1) & 0x1F);
// anything other than the low 6-bit is reserved
// non-zero reserved bits indicate the message has some extension that we are not aware of
if ((status >> 6) != 0)
{
WeaveLogDetail(TimeService, "TimeSyncResponse unknown extension, as reserved bits are not all 0s (0x%X)",
status);
}
}
exit:
WeaveLogFunctError(err);
return err;
}
_TimeSyncNodeBase::_TimeSyncNodeBase(void) :
FabricState(NULL),
ExchangeMgr(NULL)
{
}
void _TimeSyncNodeBase::Init(WeaveFabricState * const aFabricState,
WeaveExchangeManager * const aExchangeMgr)
{
FabricState = aFabricState;
ExchangeMgr = aExchangeMgr;
}
#endif // WEAVE_CONFIG_TIME