@@ -28,6 +28,8 @@ using namespace chip::app::Clusters::Thermostat::Structs;
28
28
using namespace chip ::app::Clusters::Globals::Structs;
29
29
using namespace chip ::Protocols::InteractionModel;
30
30
31
+ namespace {}
32
+
31
33
namespace chip {
32
34
namespace app {
33
35
namespace Clusters {
@@ -133,15 +135,13 @@ bool CountAttributeRequests(const DataModel::DecodableList<chip::AttributeId> at
133
135
// / @param attributeRequests The list of requested attributes
134
136
// / @param attributeStatusCount The number of attribute statuses in attributeStatuses
135
137
// / @param attributeStatuses The status of each requested attribute, plus additional attributes if needed
136
- // / @param requireAll Whether the caller requires all atomic attributes to be represented in attributeRequests
137
138
// / @return Status::Success if the request is valid, an error status if it is not
138
139
Status BuildAttributeStatuses (const EndpointId endpoint, const DataModel::DecodableList<chip::AttributeId> attributeRequests,
139
- size_t & attributeStatusCount,
140
- Platform::ScopedMemoryBuffer<AtomicAttributeStatusStruct::Type> & attributeStatuses, bool requireAll)
140
+ Platform::ScopedMemoryBufferWithSize<AtomicAttributeStatusStruct::Type> & attributeStatuses)
141
141
{
142
142
143
143
bool requestedPresets = false , requestedSchedules = false ;
144
- attributeStatusCount = 0 ;
144
+ size_t attributeStatusCount = 0 ;
145
145
if (!CountAttributeRequests (attributeRequests, attributeStatusCount, requestedPresets, requestedSchedules))
146
146
{
147
147
// We errored reading the list
@@ -152,12 +152,6 @@ Status BuildAttributeStatuses(const EndpointId endpoint, const DataModel::Decoda
152
152
// List can't be empty
153
153
return Status::InvalidCommand;
154
154
}
155
- if (requestedPresets ^ requestedSchedules)
156
- {
157
- // Client requested presets or schedules, but not both, so we need an extra status
158
- // because we will in fact treat the atomic request as applying to both.
159
- attributeStatusCount++;
160
- }
161
155
attributeStatuses.Alloc (attributeStatusCount);
162
156
for (size_t i = 0 ; i < attributeStatusCount; ++i)
163
157
{
@@ -199,64 +193,152 @@ Status BuildAttributeStatuses(const EndpointId endpoint, const DataModel::Decoda
199
193
return Status::InvalidCommand;
200
194
}
201
195
}
202
- if (requireAll)
196
+ return Status::Success;
197
+ }
198
+
199
+ bool ThermostatAttrAccess::InAtomicWrite (EndpointId endpoint, Optional<AttributeId> attributeId)
200
+ {
201
+
202
+ uint16_t ep =
203
+ emberAfGetClusterServerEndpointIndex (endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT);
204
+
205
+ if (ep >= ArraySize (mAtomicWriteSessions ))
203
206
{
204
- if (!requestedPresets || !requestedSchedules)
207
+ return false ;
208
+ }
209
+ auto & atomicWriteSession = mAtomicWriteSessions [ep];
210
+ if (atomicWriteSession.state != AtomicWriteState::Open)
211
+ {
212
+ return false ;
213
+ }
214
+ if (!attributeId.HasValue ())
215
+ {
216
+ return true ;
217
+ }
218
+ for (size_t i = 0 ; i < atomicWriteSession.attributeIds .AllocatedSize (); ++i)
219
+ {
220
+ if (atomicWriteSession.attributeIds [i] == attributeId.Value ())
205
221
{
206
- return Status::InvalidInState ;
222
+ return true ;
207
223
}
208
224
}
209
- else if (requestedPresets ^ requestedSchedules)
225
+ return false ;
226
+ }
227
+
228
+ bool ThermostatAttrAccess::InAtomicWrite (EndpointId endpoint, const Access::SubjectDescriptor & subjectDescriptor,
229
+ Optional<AttributeId> attributeId)
230
+ {
231
+ if (!InAtomicWrite (endpoint, attributeId))
210
232
{
211
- // Client requested presets or schedules, but not both, so we add the extra status
212
- attributeStatuses[index ].attributeID = requestedSchedules ? Presets::Id : Schedules::Id;
213
- attributeStatuses[index ].statusCode = to_underlying (Status::Success);
233
+ return false ;
214
234
}
215
- return Status::Success;
235
+ return subjectDescriptor.authMode == Access::AuthMode::kCase &&
236
+ GetAtomicWriteOriginatorScopedNodeId (endpoint) == ScopedNodeId (subjectDescriptor.subject , subjectDescriptor.fabricIndex );
216
237
}
217
238
218
- void ThermostatAttrAccess::ResetAtomicWrite (EndpointId endpoint)
239
+ bool ThermostatAttrAccess::InAtomicWrite (EndpointId endpoint, CommandHandler * commandObj, Optional<AttributeId> attributeId )
219
240
{
220
- auto delegate = GetDelegate (endpoint);
221
- if (delegate != nullptr )
241
+ if (!InAtomicWrite (endpoint, attributeId))
222
242
{
223
- delegate-> ClearPendingPresetList () ;
243
+ return false ;
224
244
}
225
- ClearTimer (endpoint );
226
- SetAtomicWrite (endpoint, ScopedNodeId (), AtomicWriteState::Closed) ;
245
+ ScopedNodeId sourceNodeId = GetSourceScopedNodeId (commandObj );
246
+ return GetAtomicWriteOriginatorScopedNodeId (endpoint) == sourceNodeId ;
227
247
}
228
248
229
- bool ThermostatAttrAccess::InAtomicWrite (EndpointId endpoint)
249
+ bool ThermostatAttrAccess::InAtomicWrite (
250
+ EndpointId endpoint, CommandHandler * commandObj,
251
+ Platform::ScopedMemoryBufferWithSize<AtomicAttributeStatusStruct::Type> & attributeStatuses)
230
252
{
231
-
232
253
uint16_t ep =
233
254
emberAfGetClusterServerEndpointIndex (endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT);
234
255
235
- if (ep < ArraySize (mAtomicWriteSessions ))
256
+ if (ep >= ArraySize (mAtomicWriteSessions ))
236
257
{
237
- return mAtomicWriteSessions [ep]. state == AtomicWriteState::Open ;
258
+ return false ;
238
259
}
239
- return false ;
260
+ auto & atomicWriteSession = mAtomicWriteSessions [ep];
261
+ if (atomicWriteSession.state != AtomicWriteState::Open)
262
+ {
263
+ return false ;
264
+ }
265
+ if (atomicWriteSession.attributeIds .AllocatedSize () == 0 ||
266
+ atomicWriteSession.attributeIds .AllocatedSize () != attributeStatuses.AllocatedSize ())
267
+ {
268
+ return false ;
269
+ }
270
+ for (size_t i = 0 ; i < atomicWriteSession.attributeIds .AllocatedSize (); ++i)
271
+ {
272
+ bool hasAttribute = false ;
273
+ auto attributeId = atomicWriteSession.attributeIds [i];
274
+ for (size_t j = 0 ; j < attributeStatuses.AllocatedSize (); ++j)
275
+ {
276
+ auto & attributeStatus = attributeStatuses[j];
277
+ if (attributeStatus.attributeID == attributeId)
278
+ {
279
+ hasAttribute = true ;
280
+ break ;
281
+ }
282
+ }
283
+ if (!hasAttribute)
284
+ {
285
+ return false ;
286
+ }
287
+ }
288
+ return true ;
240
289
}
241
290
242
- bool ThermostatAttrAccess::InAtomicWrite (const Access::SubjectDescriptor & subjectDescriptor, EndpointId endpoint)
291
+ bool ThermostatAttrAccess::SetAtomicWrite (
292
+ EndpointId endpoint, ScopedNodeId originatorNodeId, AtomicWriteState state,
293
+ Platform::ScopedMemoryBufferWithSize<AtomicAttributeStatusStruct::Type> & attributeStatuses)
243
294
{
244
- if (!InAtomicWrite (endpoint))
295
+ uint16_t ep =
296
+ emberAfGetClusterServerEndpointIndex (endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT);
297
+
298
+ if (ep >= ArraySize (mAtomicWriteSessions ))
245
299
{
246
300
return false ;
247
301
}
248
- return subjectDescriptor.authMode == Access::AuthMode::kCase &&
249
- GetAtomicWriteOriginatorScopedNodeId (endpoint) == ScopedNodeId (subjectDescriptor.subject , subjectDescriptor.fabricIndex );
302
+
303
+ auto & atomicWriteSession = mAtomicWriteSessions [ep];
304
+ atomicWriteSession.endpointId = endpoint;
305
+ if (!atomicWriteSession.attributeIds .Alloc (attributeStatuses.AllocatedSize ()))
306
+ {
307
+ atomicWriteSession.state = AtomicWriteState::Closed;
308
+ atomicWriteSession.nodeId = ScopedNodeId ();
309
+ return false ;
310
+ }
311
+
312
+ atomicWriteSession.state = state;
313
+ atomicWriteSession.nodeId = originatorNodeId;
314
+
315
+ for (size_t i = 0 ; i < attributeStatuses.AllocatedSize (); ++i)
316
+ {
317
+ atomicWriteSession.attributeIds [i] = attributeStatuses[i].attributeID ;
318
+ }
319
+ return true ;
250
320
}
251
321
252
- bool ThermostatAttrAccess::InAtomicWrite (CommandHandler * commandObj, EndpointId endpoint)
322
+ void ThermostatAttrAccess::ResetAtomicWrite ( EndpointId endpoint)
253
323
{
254
- if (!InAtomicWrite (endpoint))
324
+ auto delegate = GetDelegate (endpoint);
325
+ if (delegate != nullptr )
255
326
{
256
- return false ;
327
+ delegate-> ClearPendingPresetList () ;
257
328
}
258
- ScopedNodeId sourceNodeId = GetSourceScopedNodeId (commandObj);
259
- return GetAtomicWriteOriginatorScopedNodeId (endpoint) == sourceNodeId;
329
+ ClearTimer (endpoint);
330
+ uint16_t ep =
331
+ emberAfGetClusterServerEndpointIndex (endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT);
332
+
333
+ if (ep >= ArraySize (mAtomicWriteSessions ))
334
+ {
335
+ return ;
336
+ }
337
+ auto & atomicWriteSession = mAtomicWriteSessions [ep];
338
+ atomicWriteSession.state = AtomicWriteState::Closed;
339
+ atomicWriteSession.endpointId = endpoint;
340
+ atomicWriteSession.nodeId = ScopedNodeId ();
341
+ atomicWriteSession.attributeIds .Alloc (0 );
260
342
}
261
343
262
344
ScopedNodeId ThermostatAttrAccess::GetAtomicWriteOriginatorScopedNodeId (const EndpointId endpoint)
@@ -273,13 +355,13 @@ ScopedNodeId ThermostatAttrAccess::GetAtomicWriteOriginatorScopedNodeId(const En
273
355
}
274
356
275
357
void SendAtomicResponse (CommandHandler * commandObj, const ConcreteCommandPath & commandPath, Status status,
276
- const Platform::ScopedMemoryBuffer <AtomicAttributeStatusStruct::Type> & attributeStatuses,
277
- size_t attributeRequestCount, Optional<uint16_t > timeout = NullOptional)
358
+ const Platform::ScopedMemoryBufferWithSize <AtomicAttributeStatusStruct::Type> & attributeStatuses,
359
+ Optional<uint16_t > timeout = NullOptional)
278
360
{
279
361
Commands::AtomicResponse::Type response;
280
362
response.statusCode = to_underlying (status);
281
363
response.attributeStatus =
282
- DataModel::List<const AtomicAttributeStatusStruct::Type>(attributeStatuses.Get (), attributeRequestCount );
364
+ DataModel::List<const AtomicAttributeStatusStruct::Type>(attributeStatuses.Get (), attributeStatuses. AllocatedSize () );
283
365
response.timeout = timeout;
284
366
commandObj->AddResponse (commandPath, response);
285
367
}
@@ -298,16 +380,15 @@ void ThermostatAttrAccess::BeginAtomicWrite(CommandHandler * commandObj, const C
298
380
return ;
299
381
}
300
382
301
- size_t attributeStatusCount = 0 ;
302
- Platform::ScopedMemoryBuffer<AtomicAttributeStatusStruct::Type> attributeStatuses;
303
- auto status = BuildAttributeStatuses (endpoint, commandData.attributeRequests , attributeStatusCount, attributeStatuses, false );
383
+ Platform::ScopedMemoryBufferWithSize<AtomicAttributeStatusStruct::Type> attributeStatuses;
384
+ auto status = BuildAttributeStatuses (endpoint, commandData.attributeRequests , attributeStatuses);
304
385
if (status != Status::Success)
305
386
{
306
387
commandObj->AddStatus (commandPath, status);
307
388
return ;
308
389
}
309
390
310
- if (gThermostatAttrAccess . InAtomicWrite (commandObj, endpoint ))
391
+ if (InAtomicWrite (endpoint, commandObj ))
311
392
{
312
393
// This client already has an open atomic write
313
394
commandObj->AddStatus (commandPath, Status::InvalidInState);
@@ -342,15 +423,15 @@ void ThermostatAttrAccess::BeginAtomicWrite(CommandHandler * commandObj, const C
342
423
}
343
424
344
425
status = Status::Success;
345
- for (size_t i = 0 ; i < attributeStatusCount ; ++i)
426
+ for (size_t i = 0 ; i < attributeStatuses. AllocatedSize () ; ++i)
346
427
{
347
428
auto & attributeStatus = attributeStatuses[i];
348
429
auto statusCode = Status::Success;
349
430
switch (attributeStatus.attributeID )
350
431
{
351
432
case Presets::Id:
352
433
case Schedules::Id:
353
- statusCode = gThermostatAttrAccess . InAtomicWrite (endpoint) ? Status::Busy : Status::Success;
434
+ statusCode = InAtomicWrite (endpoint, MakeOptional (attributeStatus. attributeID ) ) ? Status::Busy : Status::Success;
354
435
break ;
355
436
default :
356
437
statusCode = Status::InvalidCommand;
@@ -372,14 +453,24 @@ void ThermostatAttrAccess::BeginAtomicWrite(CommandHandler * commandObj, const C
372
453
373
454
if (status == Status::Success)
374
455
{
375
- // This is a valid request to open an atomic write. Tell the delegate it
376
- // needs to keep track of a pending preset list now.
377
- delegate->InitializePendingPresets ();
378
- ScheduleTimer (endpoint, timeout);
379
- SetAtomicWrite (endpoint, GetSourceScopedNodeId (commandObj), AtomicWriteState::Open);
456
+ if (!SetAtomicWrite (endpoint, GetSourceScopedNodeId (commandObj), AtomicWriteState::Open, attributeStatuses))
457
+ {
458
+ for (size_t i = 0 ; i < attributeStatuses.AllocatedSize (); ++i)
459
+ {
460
+ attributeStatuses[i].statusCode = to_underlying (Status::ResourceExhausted);
461
+ }
462
+ status = Status::Failure;
463
+ }
464
+ else
465
+ {
466
+ // This is a valid request to open an atomic write. Tell the delegate it
467
+ // needs to keep track of a pending preset list now.
468
+ delegate->InitializePendingPresets ();
469
+ ScheduleTimer (endpoint, timeout);
470
+ }
380
471
}
381
472
382
- SendAtomicResponse (commandObj, commandPath, status, attributeStatuses, attributeStatusCount, MakeOptional (timeout.count ()));
473
+ SendAtomicResponse (commandObj, commandPath, status, attributeStatuses, MakeOptional (timeout.count ()));
383
474
}
384
475
385
476
void ThermostatAttrAccess::CommitAtomicWrite (CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
@@ -395,23 +486,22 @@ void ThermostatAttrAccess::CommitAtomicWrite(CommandHandler * commandObj, const
395
486
return ;
396
487
}
397
488
398
- size_t attributeStatusCount = 0 ;
399
- Platform::ScopedMemoryBuffer<AtomicAttributeStatusStruct::Type> attributeStatuses;
400
- auto status = BuildAttributeStatuses (endpoint, commandData.attributeRequests , attributeStatusCount, attributeStatuses, true );
489
+ Platform::ScopedMemoryBufferWithSize<AtomicAttributeStatusStruct::Type> attributeStatuses;
490
+ auto status = BuildAttributeStatuses (endpoint, commandData.attributeRequests , attributeStatuses);
401
491
if (status != Status::Success)
402
492
{
403
493
commandObj->AddStatus (commandPath, status);
404
494
return ;
405
495
}
406
496
407
- if (!gThermostatAttrAccess . InAtomicWrite (commandObj, endpoint ))
497
+ if (!InAtomicWrite (endpoint, commandObj, attributeStatuses ))
408
498
{
409
499
commandObj->AddStatus (commandPath, Status::InvalidInState);
410
500
return ;
411
501
}
412
502
413
503
status = Status::Success;
414
- for (size_t i = 0 ; i < attributeStatusCount ; ++i)
504
+ for (size_t i = 0 ; i < attributeStatuses. AllocatedSize () ; ++i)
415
505
{
416
506
auto & attributeStatus = attributeStatuses[i];
417
507
auto statusCode = Status::Success;
@@ -443,7 +533,7 @@ void ThermostatAttrAccess::CommitAtomicWrite(CommandHandler * commandObj, const
443
533
}
444
534
445
535
ResetAtomicWrite (endpoint);
446
- SendAtomicResponse (commandObj, commandPath, status, attributeStatuses, attributeStatusCount );
536
+ SendAtomicResponse (commandObj, commandPath, status, attributeStatuses);
447
537
}
448
538
449
539
void ThermostatAttrAccess::RollbackAtomicWrite (CommandHandler * commandObj, const ConcreteCommandPath & commandPath,
@@ -460,16 +550,15 @@ void ThermostatAttrAccess::RollbackAtomicWrite(CommandHandler * commandObj, cons
460
550
return ;
461
551
}
462
552
463
- size_t attributeStatusCount = 0 ;
464
- Platform::ScopedMemoryBuffer<AtomicAttributeStatusStruct::Type> attributeStatuses;
465
- auto status = BuildAttributeStatuses (endpoint, commandData.attributeRequests , attributeStatusCount, attributeStatuses, true );
553
+ Platform::ScopedMemoryBufferWithSize<AtomicAttributeStatusStruct::Type> attributeStatuses;
554
+ auto status = BuildAttributeStatuses (endpoint, commandData.attributeRequests , attributeStatuses);
466
555
if (status != Status::Success)
467
556
{
468
557
commandObj->AddStatus (commandPath, status);
469
558
return ;
470
559
}
471
560
472
- if (!gThermostatAttrAccess . InAtomicWrite (commandObj, endpoint ))
561
+ if (!InAtomicWrite (endpoint, commandObj, attributeStatuses ))
473
562
{
474
563
// There's no open atomic write
475
564
commandObj->AddStatus (commandPath, Status::InvalidInState);
@@ -478,7 +567,7 @@ void ThermostatAttrAccess::RollbackAtomicWrite(CommandHandler * commandObj, cons
478
567
479
568
ResetAtomicWrite (endpoint);
480
569
481
- for (size_t i = 0 ; i < attributeStatusCount ; ++i)
570
+ for (size_t i = 0 ; i < attributeStatuses. AllocatedSize () ; ++i)
482
571
{
483
572
auto & attributeStatus = attributeStatuses[i];
484
573
switch (attributeStatus.attributeID )
@@ -493,20 +582,7 @@ void ThermostatAttrAccess::RollbackAtomicWrite(CommandHandler * commandObj, cons
493
582
}
494
583
}
495
584
496
- SendAtomicResponse (commandObj, commandPath, status, attributeStatuses, attributeStatusCount);
497
- }
498
-
499
- void ThermostatAttrAccess::SetAtomicWrite (EndpointId endpoint, ScopedNodeId originatorNodeId, AtomicWriteState state)
500
- {
501
- uint16_t ep =
502
- emberAfGetClusterServerEndpointIndex (endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT);
503
-
504
- if (ep < ArraySize (mAtomicWriteSessions ))
505
- {
506
- mAtomicWriteSessions [ep].state = state;
507
- mAtomicWriteSessions [ep].endpointId = endpoint;
508
- mAtomicWriteSessions [ep].nodeId = originatorNodeId;
509
- }
585
+ SendAtomicResponse (commandObj, commandPath, status, attributeStatuses);
510
586
}
511
587
512
588
} // namespace Thermostat
0 commit comments