Skip to content

Commit

Permalink
use delegate placeholder and implemented events
Browse files Browse the repository at this point in the history
  • Loading branch information
fessehaeve committed Apr 26, 2023
1 parent 84d7a62 commit b04ad4b
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/

#include "time-synchronization-server.h"
#include "TimeSyncManager.h"
#include "time-synchronization-delegate.h"

#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/cluster-objects.h>
Expand All @@ -40,6 +42,46 @@ using namespace chip::app::Clusters::TimeSynchronization::Attributes;
using chip::TimeSyncDataProvider;
using chip::Protocols::InteractionModel::Status;

// -----------------------------------------------------------------------------
// Delegate Implementation

using chip::app::Clusters::TimeSynchronization::Delegate;

namespace {

Delegate * gDelegate = nullptr;

Delegate * GetDelegate()
{
if (gDelegate == nullptr)
{
static TimeSyncManager dg;
gDelegate = &dg;
}
return gDelegate;
}
} // namespace

namespace chip {
namespace app {
namespace Clusters {
namespace TimeSynchronization {

void SetDefaultDelegate(Delegate * delegate)
{
gDelegate = delegate;
}

Delegate * GetDefaultDelegate(void)
{
return GetDelegate();
}

} // namespace TimeSynchronization
} // namespace Clusters
} // namespace app
} // namespace chip

TimeSynchronizationServer TimeSynchronizationServer::mTimeSyncInstance;

TimeSynchronizationServer & TimeSynchronizationServer::Instance(void)
Expand Down Expand Up @@ -84,6 +126,31 @@ struct TimeZoneCodec
return CHIP_NO_ERROR;
}
};

static bool computeLocalTime(chip::EndpointId ep)
{
DataModel::Nullable<uint64_t> utcTime, localTime;
int32_t timeZoneOffset = 0, dstOffset = 0;
UTCTime::Get(ep, utcTime);
if (utcTime.IsNull())
{
return false;
}
auto tz = TimeSynchronizationServer::Instance().GetTimeZone().begin();
auto dst = TimeSynchronizationServer::Instance().GetDSTOffset().begin();
if (tz->validAt <= utcTime.Value())
{
timeZoneOffset = tz->offset;
}
if (dst->validStarting <= utcTime.Value() && dst->offset != 0 && !dst->validUntil.IsNull())
{
dstOffset = dst->offset;
}
localTime.SetNonNull(utcTime.Value() + static_cast<uint64_t>(timeZoneOffset) + static_cast<uint64_t>(dstOffset));
LocalTime::Set(ep, localTime);
return true;
}

class TimeSynchronizationAttrAccess : public AttributeAccessInterface
{
public:
Expand Down Expand Up @@ -214,26 +281,16 @@ CHIP_ERROR TimeSynchronizationAttrAccess::Read(const ConcreteReadAttributePath &
return aEncoder.Encode(max);
}
case LocalTime::Id: {
DataModel::Nullable<uint64_t> utcTime, localTime;
int32_t timeZoneOffset = 0, dstOffset = 0;
UTCTime::Get(aPath.mEndpointId, utcTime);
if (utcTime.IsNull())
DataModel::Nullable<uint64_t> localTime;
if (computeLocalTime(aPath.mEndpointId))
{
return aEncoder.EncodeNull();
}
auto tz = TimeSynchronizationServer::Instance().GetTimeZone().begin();
auto dst = TimeSynchronizationServer::Instance().GetDSTOffset().begin();
if (tz->validAt <= utcTime.Value())
{
timeZoneOffset = tz->offset;
LocalTime::Get(aPath.mEndpointId, localTime);
return aEncoder.Encode(localTime.Value());
}
if (dst->validStarting <= utcTime.Value() && dst->offset != 0 && !dst->validUntil.IsNull())
else
{
dstOffset = dst->offset;
return aEncoder.EncodeNull();
}
localTime.SetNonNull(utcTime.Value() + static_cast<uint64_t>(timeZoneOffset) + static_cast<uint64_t>(dstOffset));
LocalTime::Set(aPath.mEndpointId, localTime);
return aEncoder.Encode(localTime.Value());
}
default: {
break;
Expand All @@ -244,6 +301,102 @@ CHIP_ERROR TimeSynchronizationAttrAccess::Read(const ConcreteReadAttributePath &
}
} // anonymous namespace

static bool sendDSTTableEmpty(chip::EndpointId endpointId)
{
Events::DSTTableEmpty::Type event;
EventNumber eventNumber;

CHIP_ERROR error = LogEvent(event, endpointId, eventNumber);

if (CHIP_NO_ERROR != error)
{
ChipLogError(Zcl, "Unable to send DSTTableEmpty event [endpointId=%d]", endpointId);
return false;
}
ChipLogProgress(Zcl, "Emit DSTTableEmpty event [endpointId=%d]", endpointId);

// re-schedule event for after min 1hr
// delegate->scheduleDSTTableEmptyEvent()
return true;
}

static bool sendDSTStatus(chip::EndpointId endpointId, bool dstOffsetActive)
{
Events::DSTStatus::Type event;
event.DSTOffsetActive = dstOffsetActive;
EventNumber eventNumber;

CHIP_ERROR error = LogEvent(event, endpointId, eventNumber);

if (CHIP_NO_ERROR != error)
{
ChipLogError(Zcl, "Unable to send sendDSTStatus event [endpointId=%d]", endpointId);
return false;
}

ChipLogProgress(Zcl, "Emit sendDSTStatus event [endpointId=%d]", endpointId);
return true;
}

static bool sendTimeZoneStatus(chip::EndpointId endpointId, uint8_t listIndex)
{
Events::TimeZoneStatus::Type event;
auto tz = TimeSynchronizationServer::Instance().GetTimeZone().begin();
event.offset = tz[listIndex].offset;
if (tz[listIndex].name.HasValue())
{
event.name = tz[listIndex].name.Value();
}
EventNumber eventNumber;

CHIP_ERROR error = LogEvent(event, endpointId, eventNumber);

if (CHIP_NO_ERROR != error)
{
ChipLogError(Zcl, "Unable to send sendTimeZoneStatus event [endpointId=%d]", endpointId);
return false;
}

ChipLogProgress(Zcl, "Emit sendTimeZoneStatus event [endpointId=%d]", endpointId);
return true;
}

static bool sendTimeFailure(chip::EndpointId endpointId)
{
Events::TimeFailure::Type event;
EventNumber eventNumber;

CHIP_ERROR error = LogEvent(event, endpointId, eventNumber);

if (CHIP_NO_ERROR != error)
{
ChipLogError(Zcl, "Unable to send sendTimeFailure event [endpointId=%d]", endpointId);
return false;
}

// re-schedule event for after min 1hr if no time is still available
ChipLogProgress(Zcl, "Emit sendTimeFailure event [endpointId=%d]", endpointId);
return true;
}

static bool sendMissingTrustedTimeSource(chip::EndpointId endpointId)
{
Events::MissingTrustedTimeSource::Type event;
EventNumber eventNumber;

CHIP_ERROR error = LogEvent(event, endpointId, eventNumber);

if (CHIP_NO_ERROR != error)
{
ChipLogError(Zcl, "Unable to send sendMissingTrustedTimeSource event [endpointId=%d]", endpointId);
return false;
}

// re-schedule event for after min 1hr if TTS is null or cannot be reached
ChipLogProgress(Zcl, "Emit sendMissingTrustedTimeSource event [endpointId=%d]", endpointId);
return true;
}

static void utcTimeChanged(uint64_t utcTime)
{
System::Clock::Seconds32 lastKnownGoodChipEpoch;
Expand Down Expand Up @@ -315,7 +468,7 @@ bool emberAfTimeSynchronizationClusterSetTrustedTimeSourceCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::TimeSynchronization::Commands::SetTrustedTimeSource::DecodableType & commandData)
{
Status status = Status::Success;
Status status = Status::Success;
auto timeSource = commandData.trustedTimeSource;
DataModel::Nullable<TimeSynchronization::Structs::TrustedTimeSourceStruct::Type> tts;

Expand All @@ -329,7 +482,7 @@ bool emberAfTimeSynchronizationClusterSetTrustedTimeSourceCallback(
else
{
tts.SetNull();
// TODO generate MissingTrustedTimeSource event
sendMissingTrustedTimeSource(commandPath.mEndpointId);
}

TimeSynchronizationServer::Instance().SetTrustedTimeSource(tts);
Expand Down Expand Up @@ -360,41 +513,37 @@ bool emberAfTimeSynchronizationClusterSetTimeZoneCallback(
commandObj->AddStatus(commandPath, Status::ConstraintError);
return true;
}
// TODO generate TimeZoneStatus event
// TODO delegate->timezonechanged
// TODO delegate->dstoffsetlookup
/*
if (hasfeature(timezone) && TimeZoneDatabase != Enum::None)
sendTimeZoneStatus(commandPath.mEndpointId, 0);
sendTimeFailure(commandPath.mEndpointId); // TODO remove
GetDelegate()->HandleTimeZoneChanged(TimeSynchronizationServer::Instance().GetTimeZone());
GetDelegate()->HandleDstoffsetlookup();

TimeSynchronization::TimeZoneDatabaseEnum tzDb;
TimeZoneDatabase::Get(commandPath.mEndpointId, &tzDb);
if (GetDelegate()->HasFeature(0, TimeSynchronization::TimeSynchronizationFeature::kTimeZone) &&
tzDb != TimeSynchronization::TimeZoneDatabaseEnum::kNone)
{
if (delegate->dstoffsetavailable(timezone.name) == true)
auto tz = TimeSynchronizationServer::Instance().GetTimeZone().begin();
Commands::SetTimeZoneResponse::Type response;
if (GetDelegate()->HandleDstoffsetavailable(tz->name.Value()) == true) // TODO make const
{
delegate->getdstoffset
response.DSTOffsetRequired = false
GetDelegate()->HandleGetdstoffset();
response.DSTOffsetRequired = false;
sendDSTStatus(commandPath.mEndpointId, true);
}
else
{
cleardstoffsetAttribList
generate DSTTableEmpty event
response.DSTOffsetRequired = true
TimeSynchronizationServer::Instance().ClearDSTOffset();
sendDSTTableEmpty(commandPath.mEndpointId);
response.DSTOffsetRequired = true;
sendDSTStatus(commandPath.mEndpointId, false);
}
if (dstoffsetisactive)
generate DSTStatus event
Commands::SetTimeZoneResponse::Type response;
response.DSTOffsetRequired = true; // lookup if there is a matching dstoffset value using the Name field in timezone
commandObj->AddResponse(commandPath, response);
recomputeLocalTime()
computeLocalTime(commandPath.mEndpointId);
return true;
}
else
{
if tz-db supported and data available for tz, based on the name field it may update dstoffset (use delegate with name as
parameter)
if tz-db not supported, don't use name to calculate localtime and DST if tz-db
}

recomputeLocalTime()
*/
computeLocalTime(commandPath.mEndpointId);

commandObj->AddStatus(commandPath, Status::Success);

Expand Down Expand Up @@ -429,7 +578,9 @@ bool emberAfTimeSynchronizationClusterSetDSTOffsetCallback(
return true;
}
// if DST state changes, generate DSTStatus event
sendDSTStatus(commandPath.mEndpointId, true);
// if list is empty, generate DSTTableEmpty event
sendDSTTableEmpty(commandPath.mEndpointId);

commandObj->AddStatus(commandPath, status);
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ class TimeSynchronizationServer
return mTimeSyncDataProvider.StoreDSTOffset(mDstOffList);
}

CHIP_ERROR ClearDSTOffset()
{
for (size_t i = 0; i < CHIP_CONFIG_DST_OFFSET_LIST_MAX_SIZE; i++)
{
mDst[i] = { 0 };
}

return mTimeSyncDataProvider.ClearDSTOffset();
}

DataModel::Nullable<TimeSynchronization::Structs::TrustedTimeSourceStruct::Type> & GetTrustedTimeSource(void)
{
return mTrustedTimeSource;
Expand Down

0 comments on commit b04ad4b

Please sign in to comment.