9857430e489cf0f73975e06917ebf73dc5dd3709
[platform/upstream/connectedhomeip.git] / src / messaging / ReliableMessageManager.cpp
1 /*
2  *    Copyright (c) 2020 Project CHIP Authors
3  *    All rights reserved.
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17
18 /**
19  *    @file
20  *      This file implements the CHIP reliable message protocol.
21  *
22  */
23
24 #include <inttypes.h>
25
26 #include <messaging/ReliableMessageManager.h>
27
28 #include <messaging/ErrorCategory.h>
29 #include <messaging/Flags.h>
30 #include <messaging/ReliableMessageContext.h>
31 #include <support/BitFlags.h>
32 #include <support/CHIPFaultInjection.h>
33 #include <support/CodeUtils.h>
34 #include <support/logging/CHIPLogging.h>
35
36 namespace chip {
37 namespace Messaging {
38
39 ReliableMessageManager::RetransTableEntry::RetransTableEntry() :
40     rc(nullptr), msgBuf(nullptr), msgId(0), msgSendFlags(0), nextRetransTimeTick(0), sendCount(0)
41 {}
42
43 ReliableMessageManager::ReliableMessageManager() :
44     mTimeStampBase(System::Timer::GetCurrentEpoch()), mCurrentTimerExpiry(0),
45     mTimerIntervalShift(CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT)
46 {}
47
48 ReliableMessageManager::~ReliableMessageManager() {}
49
50 void ReliableMessageManager::ProcessDelayedDeliveryMessage(ReliableMessageContext * rc, uint32_t PauseTimeMillis)
51 {
52     // Expire any virtual ticks that have expired so all wakeup sources reflect the current time
53     ExpireTicks();
54
55     // Go through the retrans table entries for that node and adjust the timer.
56     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
57     {
58         // Exchcontext is the sentinel object to ascertain validity of the element
59         if (RetransTable[i].rc && RetransTable[i].rc == rc)
60         {
61             // Paustime is specified in milliseconds; Update retrans values
62             RetransTable[i].nextRetransTimeTick =
63                 static_cast<uint16_t>(RetransTable[i].nextRetransTimeTick + (PauseTimeMillis >> mTimerIntervalShift));
64         } // exchContext
65     }     // for loop in table entry
66
67     // Schedule next physical wakeup
68     StartTimer();
69 }
70
71 /**
72  * Return a tick counter value given a time period.
73  *
74  * @param[in]  newTime        Timestamp value of in milliseconds.
75  *
76  * @return Tick count for the time period.
77  */
78 uint64_t ReliableMessageManager::GetTickCounterFromTimePeriod(uint64_t period)
79 {
80     return (period >> mTimerIntervalShift);
81 }
82
83 /**
84  * Return a tick counter value between the given time and the stored time.
85  *
86  * @param[in]  newTime        Timestamp value of in milliseconds.
87  *
88  * @return Tick count of the difference between the given time and the stored time.
89  */
90 uint64_t ReliableMessageManager::GetTickCounterFromTimeDelta(uint64_t newTime)
91 {
92     return GetTickCounterFromTimePeriod(newTime - mTimeStampBase);
93 }
94
95 #if defined(RMP_TICKLESS_DEBUG)
96 void ReliableMessageManager::TicklessDebugDumpRetransTable(const char * log)
97 {
98     ChipLogProgress(ExchangeManager, log);
99
100     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
101     {
102         if (RetransTable[i].rc)
103         {
104             ChipLogProgress(ExchangeManager, "EC:%04" PRIX16 " MsgId:%08" PRIX32 " NextRetransTimeCtr:%04" PRIX16,
105                             RetransTable[i].rc, RetransTable[i].msgId, RetransTable[i].nextRetransTimeTick);
106         }
107     }
108 }
109 #else
110 void ReliableMessageManager::TicklessDebugDumpRetransTable(const char * log)
111 {
112     return;
113 }
114 #endif // RMP_TICKLESS_DEBUG
115
116 /**
117  * Iterate through active exchange contexts and retrans table entries.  If an
118  * action needs to be triggered by ReliableMessageProtocol time facilities,
119  * execute that action.
120  */
121 void ReliableMessageManager::ExecuteActions()
122 {
123 #if defined(RMP_TICKLESS_DEBUG)
124     ChipLogProgress(ExchangeManager, "ReliableMessageManager::ExecuteActions");
125 #endif
126
127     ExecuteForAllContext([](ReliableMessageContext * rc) {
128         if (rc->IsAckPending())
129         {
130             if (0 == rc->mNextAckTimeTick)
131             {
132 #if defined(RMP_TICKLESS_DEBUG)
133                 ChipLogProgress(ExchangeManager, "ReliableMessageManager::ExecuteActions sending ACK");
134 #endif
135                 // Send the Ack in a Common::Null message
136                 rc->SendCommonNullMessage();
137                 rc->SetAckPending(false);
138             }
139         }
140     });
141
142     TicklessDebugDumpRetransTable("ReliableMessageManager::ExecuteActions Dumping RetransTable entries before processing");
143
144     // Retransmit / cancel anything in the retrans table whose retrans timeout
145     // has expired
146     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
147     {
148         ReliableMessageContext * rc = RetransTable[i].rc;
149         CHIP_ERROR err              = CHIP_NO_ERROR;
150
151         if (!rc || RetransTable[i].nextRetransTimeTick != 0)
152             continue;
153
154         uint8_t sendCount = RetransTable[i].sendCount;
155
156         if (sendCount == rc->mConfig.mMaxRetrans)
157         {
158             err = CHIP_ERROR_MESSAGE_NOT_ACKNOWLEDGED;
159
160             ChipLogError(ExchangeManager, "Failed to Send CHIP MsgId:%08" PRIX32 " sendCount: %" PRIu8 " max retries: %" PRIu8,
161                          RetransTable[i].msgId, sendCount, rc->mConfig.mMaxRetrans);
162
163             // Remove from Table
164             ClearRetransmitTable(RetransTable[i]);
165         }
166
167         // Resend from Table (if the operation fails, the entry is cleared)
168         if (err == CHIP_NO_ERROR)
169             err = SendFromRetransTable(&(RetransTable[i]));
170
171         if (err == CHIP_NO_ERROR)
172         {
173             // If the retransmission was successful, update the passive timer
174             RetransTable[i].nextRetransTimeTick = static_cast<uint16_t>(rc->GetCurrentRetransmitTimeoutTick());
175 #if !defined(NDEBUG)
176             ChipLogProgress(ExchangeManager, "Retransmit MsgId:%08" PRIX32 " Send Cnt %d", RetransTable[i].msgId,
177                             RetransTable[i].sendCount);
178 #endif
179         }
180
181         if (err != CHIP_NO_ERROR)
182             rc->mDelegate->OnSendError(err);
183     }
184
185     TicklessDebugDumpRetransTable("ReliableMessageManager::ExecuteActions Dumping RetransTable entries after processing");
186 }
187
188 static void TickProceed(uint16_t & time, uint64_t ticks)
189 {
190     if (time >= ticks)
191     {
192         time = static_cast<uint16_t>(time - ticks);
193     }
194     else
195     {
196         time = 0;
197     }
198 }
199
200 /**
201  * Calculate number of virtual ReliableMessageProtocol ticks that have expired
202  * since we last called this function. Iterate through active exchange contexts
203  * and retrans table entries, subtracting expired virtual ticks to synchronize
204  * wakeup times with the current system time. Do not perform any actions beyond
205  * updating tick counts, actions will be performed by the physical
206  * ReliableMessageProtocol timer tick expiry.
207  *
208  */
209 void ReliableMessageManager::ExpireTicks()
210 {
211     uint64_t now = System::Timer::GetCurrentEpoch();
212
213     // Number of full ticks elapsed since last timer processing.  We always round down
214     // to the previous tick.  If we are between tick boundaries, the extra time since the
215     // last virtual tick is not accounted for here (it will be accounted for when resetting
216     // the ReliableMessageProtocol timer)
217     uint64_t deltaTicks = GetTickCounterFromTimeDelta(now);
218
219 #if defined(RMP_TICKLESS_DEBUG)
220     ChipLogProgress(ExchangeManager, "ReliableMessageManager::ExpireTicks at %" PRIu64 ", %" PRIu64 ", %u", now, mTimeStampBase,
221                     deltaTicks);
222 #endif
223
224     ExecuteForAllContext([deltaTicks](ReliableMessageContext * rc) {
225         if (rc->IsAckPending())
226         {
227             // Decrement counter of Ack timestamp by the elapsed timer ticks
228             TickProceed(rc->mNextAckTimeTick, deltaTicks);
229 #if defined(RMP_TICKLESS_DEBUG)
230             ChipLogProgress(ExchangeManager, "ReliableMessageManager::ExpireTicks set mNextAckTimeTick to %u",
231                             rc->mNextAckTimeTick);
232 #endif
233         }
234     });
235
236     // Process Throttle Time
237     // Check Throttle timeout stored in EC to set/unset Throttle flag
238     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
239     {
240         ReliableMessageContext * rc = RetransTable[i].rc;
241         if (rc)
242         {
243             // Process Retransmit Table
244             // Decrement Throttle timeout by elapsed timeticks
245             TickProceed(rc->mThrottleTimeoutTick, deltaTicks);
246 #if defined(RMP_TICKLESS_DEBUG)
247             ChipLogProgress(ExchangeManager, "ReliableMessageManager::ExpireTicks set mThrottleTimeoutTick to %u",
248                             RetransTable[i].nextRetransTimeTick);
249 #endif
250
251             // Decrement Retransmit timeout by elapsed timeticks
252             TickProceed(RetransTable[i].nextRetransTimeTick, deltaTicks);
253 #if defined(RMP_TICKLESS_DEBUG)
254             ChipLogProgress(ExchangeManager, "ReliableMessageManager::ExpireTicks set nextRetransTimeTick to %u",
255                             RetransTable[i].nextRetransTimeTick);
256 #endif
257         } // rc entry is allocated
258     }
259
260     // Re-Adjust the base time stamp to the most recent tick boundary
261     mTimeStampBase += (deltaTicks << mTimerIntervalShift);
262
263 #if defined(RMP_TICKLESS_DEBUG)
264     ChipLogProgress(ExchangeManager, "ReliableMessageManager::ExpireTicks mTimeStampBase to %" PRIu64, mTimeStampBase);
265 #endif
266 }
267
268 /**
269  * Handle physical wakeup of system due to ReliableMessageProtocol wakeup.
270  *
271  */
272 void ReliableMessageManager::Timeout(System::Layer * aSystemLayer, void * aAppState, System::Error aError)
273 {
274     ReliableMessageManager * manager = reinterpret_cast<ReliableMessageManager *>(aAppState);
275
276     VerifyOrDie((aSystemLayer != nullptr) && (manager != nullptr));
277
278 #if defined(RMP_TICKLESS_DEBUG)
279     ChipLogProgress(ExchangeManager, "ReliableMessageManager::Timeout\n");
280 #endif
281
282     // Make sure all tick counts are sync'd to the current time
283     manager->ExpireTicks();
284
285     // Execute any actions that are due this tick
286     manager->ExecuteActions();
287
288     // Calculate next physical wakeup
289     manager->StartTimer();
290 }
291
292 /**
293  *  Add a CHIP message into the retransmission table to be subsequently resent if a corresponding acknowledgment
294  *  is not received within the retransmission timeout.
295  *
296  *  @param[in]    rc        A pointer to the ExchangeContext object.
297  *
298  *  @param[in]    msgBuf    A pointer to the message buffer holding the CHIP message to be retransmitted.
299  *
300  *  @param[in]    messageId The message identifier of the stored CHIP message.
301  *
302  *  @param[out]   rEntry    A pointer to a pointer of a retransmission table entry added into the table.
303  *
304  *  @retval  #CHIP_ERROR_RETRANS_TABLE_FULL If there is no empty slot left in the table for addition.
305  *  @retval  #CHIP_NO_ERROR On success.
306  *
307  */
308 CHIP_ERROR ReliableMessageManager::AddToRetransTable(ReliableMessageContext * rc, System::PacketBuffer * msgBuf, uint32_t messageId,
309                                                      uint16_t msgSendFlags, RetransTableEntry ** rEntry)
310 {
311     bool added     = false;
312     CHIP_ERROR err = CHIP_NO_ERROR;
313
314     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
315     {
316         // Check the exchContext pointer for finding an empty slot in Table
317         if (!RetransTable[i].rc)
318         {
319             // Expire any virtual ticks that have expired so all wakeup sources reflect the current time
320             ExpireTicks();
321
322             RetransTable[i].rc                  = rc;
323             RetransTable[i].msgId               = messageId;
324             RetransTable[i].msgBuf              = msgBuf;
325             RetransTable[i].msgSendFlags        = msgSendFlags;
326             RetransTable[i].sendCount           = 0;
327             RetransTable[i].nextRetransTimeTick = static_cast<uint16_t>(
328                 rc->GetCurrentRetransmitTimeoutTick() + GetTickCounterFromTimeDelta(System::Timer::GetCurrentEpoch()));
329
330             *rEntry = &RetransTable[i];
331             // Increment the reference count
332             rc->Retain();
333             added = true;
334
335             // Check if the timer needs to be started and start it.
336             StartTimer();
337             break;
338         }
339     }
340
341     if (!added)
342     {
343         ChipLogError(ExchangeManager, "RetransTable Already Full");
344         err = CHIP_ERROR_RETRANS_TABLE_FULL;
345     }
346
347     return err;
348 }
349
350 void ReliableMessageManager::PauseRetransTable(ReliableMessageContext * rc, uint32_t PauseTimeMillis)
351 {
352     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
353     {
354         if (RetransTable[i].rc == rc)
355         {
356             RetransTable[i].nextRetransTimeTick =
357                 static_cast<uint16_t>(RetransTable[i].nextRetransTimeTick + (PauseTimeMillis >> mTimerIntervalShift));
358             break;
359         }
360     }
361 }
362
363 void ReliableMessageManager::ResumeRetransTable(ReliableMessageContext * rc)
364 {
365     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
366     {
367         if (RetransTable[i].rc == rc)
368         {
369             RetransTable[i].nextRetransTimeTick = 0;
370             break;
371         }
372     }
373 }
374
375 bool ReliableMessageManager::CheckAndRemRetransTable(ReliableMessageContext * rc, uint32_t ackMsgId)
376 {
377     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
378     {
379         if ((RetransTable[i].rc == rc) && RetransTable[i].msgId == ackMsgId)
380         {
381             // Clear the entry from the retransmision table.
382             ClearRetransmitTable(RetransTable[i]);
383
384 #if !defined(NDEBUG)
385             ChipLogProgress(ExchangeManager, "Rxd Ack; Removing MsgId:%08" PRIX32 " from Retrans Table", ackMsgId);
386 #endif
387             return true;
388         }
389     }
390
391     return false;
392 }
393
394 /**
395  *  Send the specified entry from the retransmission table.
396  *
397  *  @param[in]    entry                A pointer to a retransmission table entry object that needs to be sent.
398  *
399  *  @return  #CHIP_NO_ERROR On success, else corresponding CHIP_ERROR returned from SendMessage.
400  *
401  */
402 CHIP_ERROR ReliableMessageManager::SendFromRetransTable(RetransTableEntry * entry)
403 {
404     CHIP_ERROR err              = CHIP_NO_ERROR;
405     ReliableMessageContext * rc = entry->rc;
406
407     // To trigger a call to OnSendError, set the number of transmissions so
408     // that the next call to ExecuteActions will abort this entry,
409     // restart the timer immediately, and ExitNow.
410
411     CHIP_FAULT_INJECT(FaultInjection::kFault_RMPSendError, entry->sendCount = static_cast<uint8_t>(rc->mConfig.mMaxRetrans + 1);
412                       entry->nextRetransTimeTick = 0; StartTimer(); ExitNow());
413
414     if (rc)
415     {
416         // Locally store the start and length;
417         uint8_t * p  = entry->msgBuf->Start();
418         uint16_t len = entry->msgBuf->DataLength();
419
420         // Send the message through
421         uint16_t msgSendFlags = entry->msgSendFlags;
422         SetFlag(msgSendFlags, MessageFlagValues::kMessageFlag_RetainBuffer);
423         err = SendMessage(rc, entry->msgBuf, msgSendFlags);
424
425         // Reset the msgBuf start pointer and data length after sending
426         entry->msgBuf->SetStart(p);
427         entry->msgBuf->SetDataLength(len);
428
429         // Update the counters
430         entry->sendCount++;
431     }
432     else
433     {
434         ChipLogError(ExchangeManager, "Table entry invalid");
435     }
436
437     VerifyOrExit(err != CHIP_NO_ERROR, err = CHIP_NO_ERROR);
438
439     // Any error generated during initial sending is evaluated for criticality which would
440     // qualify it to be reportable back to the caller. If it is non-critical then
441     // err is set to CHIP_NO_ERROR.
442     if (IsSendErrorNonCritical(err))
443     {
444         ChipLogError(ExchangeManager, "Non-crit err %ld sending CHIP MsgId:%08" PRIX32 " from retrans table", long(err),
445                      entry->msgId);
446         err = CHIP_NO_ERROR;
447     }
448     else
449     {
450         // Remove from table
451         ChipLogError(ExchangeManager, "Crit-err %ld when sending CHIP MsgId:%08" PRIX32 ", send tries: %d", long(err), entry->msgId,
452                      entry->sendCount);
453
454         ClearRetransmitTable(*entry);
455     }
456
457 exit:
458     return err;
459 }
460
461 /**
462  *  Clear entries matching a specified ExchangeContext.
463  *
464  *  @param[in]    rc    A pointer to the ExchangeContext object.
465  *
466  */
467 void ReliableMessageManager::ClearRetransmitTable(ReliableMessageContext * rc)
468 {
469     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
470     {
471         if (RetransTable[i].rc == rc)
472         {
473             // Clear the retransmit table entry.
474             ClearRetransmitTable(RetransTable[i]);
475         }
476     }
477 }
478
479 /**
480  *  Clear an entry in the retransmission table.
481  *
482  *  @param[in]    rEntry   A reference to the RetransTableEntry object.
483  *
484  */
485 void ReliableMessageManager::ClearRetransmitTable(RetransTableEntry & rEntry)
486 {
487     if (rEntry.rc)
488     {
489         // Expire any virtual ticks that have expired so all wakeup sources reflect the current time
490         ExpireTicks();
491
492         rEntry.rc->Release();
493         rEntry.rc = nullptr;
494
495         if (rEntry.msgBuf)
496         {
497             System::PacketBuffer::Free(rEntry.msgBuf);
498             rEntry.msgBuf = nullptr;
499         }
500
501         // Clear all other fields
502         rEntry = RetransTableEntry();
503
504         // Schedule next physical wakeup
505         StartTimer();
506     }
507 }
508
509 /**
510  *  Fail entries matching a specified ExchangeContext.
511  *
512  *  @param[in]    rc    A pointer to the ExchangeContext object.
513  *
514  *  @param[in]    err   The error for failing table entries.
515  *
516  */
517 void ReliableMessageManager::FailRetransmitTableEntries(ReliableMessageContext * rc, CHIP_ERROR err)
518 {
519     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
520     {
521         if (RetransTable[i].rc == rc)
522         {
523             // Remove the entry from the retransmission table.
524             ClearRetransmitTable(RetransTable[i]);
525
526             // Application callback OnSendError.
527             rc->mDelegate->OnSendError(err);
528         }
529     }
530 }
531
532 /**
533  * Iterate through active exchange contexts and retrans table entries.
534  * Determine how many ReliableMessageProtocol ticks we need to sleep before we
535  * need to physically wake the CPU to perform an action.  Set a timer to go off
536  * when we next need to wake the system.
537  */
538 void ReliableMessageManager::StartTimer()
539 {
540     CHIP_ERROR res            = CHIP_NO_ERROR;
541     uint64_t nextWakeTimeTick = UINT64_MAX;
542     bool foundWake            = false;
543
544     // When do we need to next wake up to send an ACK?
545
546     ExecuteForAllContext([&nextWakeTimeTick, &foundWake](ReliableMessageContext * rc) {
547         if (rc->IsAckPending() && rc->mNextAckTimeTick < nextWakeTimeTick)
548         {
549             nextWakeTimeTick = rc->mNextAckTimeTick;
550             foundWake        = true;
551 #if defined(RMP_TICKLESS_DEBUG)
552             ChipLogProgress(ExchangeManager, "ReliableMessageManager::StartTimer next ACK time %u", nextWakeTimeTick);
553 #endif
554         }
555     });
556
557     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
558     {
559         ReliableMessageContext * rc = RetransTable[i].rc;
560         if (rc)
561         {
562             // When do we need to next wake up for throttle retransmission?
563             if (rc->mThrottleTimeoutTick != 0 && rc->mThrottleTimeoutTick < nextWakeTimeTick)
564             {
565                 nextWakeTimeTick = rc->mThrottleTimeoutTick;
566                 foundWake        = true;
567 #if defined(RMP_TICKLESS_DEBUG)
568                 ChipLogProgress(ExchangeManager, "ReliableMessageManager::StartTimer throttle timeout %u", nextWakeTimeTick);
569 #endif
570             }
571
572             // When do we need to next wake up for ReliableMessageProtocol retransmit?
573             if (RetransTable[i].nextRetransTimeTick < nextWakeTimeTick)
574             {
575                 nextWakeTimeTick = RetransTable[i].nextRetransTimeTick;
576                 foundWake        = true;
577 #if defined(RMP_TICKLESS_DEBUG)
578                 ChipLogProgress(ExchangeManager, "ReliableMessageManager::StartTimer RetransTime %u", nextWakeTimeTick);
579 #endif
580             }
581         }
582     }
583
584     if (foundWake)
585     {
586         // Set timer for next tick boundary - subtract the elapsed time from the current tick
587         System::Timer::Epoch timerExpiryEpoch = (nextWakeTimeTick << mTimerIntervalShift) + mTimeStampBase;
588
589 #if defined(RMP_TICKLESS_DEBUG)
590         ChipLogProgress(ExchangeManager, "ReliableMessageManager::StartTimer wake at %" PRIu64 " ms (%" PRIu64 " %" PRIu64 ")",
591                         timerExpiryEpoch, nextWakeTimeTick, mTimeStampBase);
592 #endif
593         if (timerExpiryEpoch != mCurrentTimerExpiry)
594         {
595             // If the tick boundary has expired in the past (delayed processing of event due to other system activity),
596             // expire the timer immediately
597             uint64_t now           = System::Timer::GetCurrentEpoch();
598             uint64_t timerArmValue = (timerExpiryEpoch > now) ? timerExpiryEpoch - now : 0;
599
600 #if defined(RMP_TICKLESS_DEBUG)
601             ChipLogProgress(ExchangeManager, "ReliableMessageManager::StartTimer set timer for %" PRIu64, timerArmValue);
602 #endif
603             StopTimer();
604             res = mSystemLayer->StartTimer((uint32_t) timerArmValue, Timeout, this);
605
606             VerifyOrDieWithMsg(res == CHIP_NO_ERROR, ExchangeManager, "Cannot start ReliableMessageManager::Timeout\n");
607             mCurrentTimerExpiry = timerExpiryEpoch;
608 #if defined(RMP_TICKLESS_DEBUG)
609         }
610         else
611         {
612             ChipLogProgress(ExchangeManager, "ReliableMessageManager::StartTimer timer already set for %" PRIu64, timerExpiryEpoch);
613 #endif
614         }
615     }
616     else
617     {
618 #if defined(RMP_TICKLESS_DEBUG)
619         ChipLogProgress(ExchangeManager, "Not setting ReliableMessageProtocol timeout at %" PRIu64,
620                         System::Timer::GetCurrentEpoch());
621 #endif
622         StopTimer();
623     }
624
625     TicklessDebugDumpRetransTable("ReliableMessageManager::StartTimer Dumping RetransTable entries after setting wakeup times");
626 }
627
628 void ReliableMessageManager::StopTimer()
629 {
630     mSystemLayer->CancelTimer(Timeout, this);
631 }
632
633 int ReliableMessageManager::TestGetCountRetransTable()
634 {
635     int count = 0;
636     for (int i = 0; i < CHIP_CONFIG_RMP_RETRANS_TABLE_SIZE; i++)
637     {
638         ReliableMessageContext * rc = RetransTable[i].rc;
639         if (rc)
640             count++;
641     }
642     return count;
643 }
644
645 } // namespace Messaging
646 } // namespace chip