Coverage Report

Created: 2026-03-24 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openweave-core/src/system/SystemLayer.cpp
Line
Count
Source
1
/*
2
 *
3
 *    Copyright (c) 2016-2017 Nest Labs, Inc.
4
 *    All rights reserved.
5
 *
6
 *    Licensed under the Apache License, Version 2.0 (the "License");
7
 *    you may not use this file except in compliance with the License.
8
 *    You may obtain a copy of the License at
9
 *
10
 *        http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *    Unless required by applicable law or agreed to in writing, software
13
 *    distributed under the License is distributed on an "AS IS" BASIS,
14
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 *    See the License for the specific language governing permissions and
16
 *    limitations under the License.
17
 */
18
19
/**
20
 *    @file
21
 *      This file contains definitions of the nl::Weave::System::Layer
22
 *      class methods and related data and functions.
23
 */
24
25
// Include module header
26
#include <SystemLayer/SystemLayer.h>
27
28
// Include common private header
29
#include "SystemLayerPrivate.h"
30
31
// Include local headers
32
#include <SystemLayer/SystemClock.h>
33
#include <SystemLayer/SystemTimer.h>
34
35
// Include additional Weave headers
36
#include <Weave/Support/logging/WeaveLogging.h>
37
38
#include <Weave/Support/NLDLLUtil.h>
39
#include <Weave/Support/CodeUtils.h>
40
41
// Include system and language headers
42
#include <stddef.h>
43
44
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
45
#include <unistd.h>
46
#include <fcntl.h>
47
#include <errno.h>
48
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
49
50
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
51
#if !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS
52
#include <lwip/err.h>
53
#include <lwip/sys.h>
54
#endif // !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS
55
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
56
57
#if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
58
#include <pthread.h>
59
60
// Choose an approximation of PTHREAD_NULL if pthread.h doesn't define one.
61
#ifndef PTHREAD_NULL
62
#define PTHREAD_NULL 0
63
#endif // PTHREAD_NULL
64
#endif // WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
65
66
namespace nl {
67
namespace Weave {
68
namespace System {
69
70
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
71
bool LwIPEventHandlerDelegate::IsInitialized() const
72
{
73
    return this->mFunction != NULL;
74
}
75
76
void LwIPEventHandlerDelegate::Init(LwIPEventHandlerFunction aFunction)
77
{
78
    this->mFunction         = aFunction;
79
    this->mNextDelegate     = NULL;
80
}
81
82
void LwIPEventHandlerDelegate::Prepend(const LwIPEventHandlerDelegate*& aDelegateList)
83
{
84
    this->mNextDelegate = aDelegateList;
85
    aDelegateList = this;
86
}
87
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
88
89
Layer::Layer()
90
10
  : mLayerState(kLayerState_NotInitialized),
91
10
    mContext(NULL), mPlatformData(NULL)
92
10
{
93
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
94
    if (!sSystemEventHandlerDelegate.IsInitialized())
95
        sSystemEventHandlerDelegate.Init(HandleSystemLayerEvent);
96
97
    this->mEventDelegateList = NULL;
98
    this->mTimerList = NULL;
99
    this->mTimerComplete = false;
100
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
101
102
10
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
103
10
    this->mWakePipeIn = 0;
104
10
    this->mWakePipeOut = 0;
105
106
10
#if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
107
10
    this->mHandleSelectThread = PTHREAD_NULL;
108
10
#endif // WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
109
10
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
110
10
}
111
112
Error Layer::Init(void* aContext)
113
0
{
114
0
    Error lReturn;
115
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
116
0
    int lPipeFDs[2];
117
0
    int lOSReturn, lFlags;
118
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
119
120
0
    RegisterSystemLayerErrorFormatter();
121
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
122
0
    RegisterPOSIXErrorFormatter();
123
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
124
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
125
    RegisterLwIPErrorFormatter();
126
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
127
128
0
    if (this->mLayerState != kLayerState_NotInitialized)
129
0
        return WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE;
130
131
0
    lReturn = Platform::Layer::WillInit(*this, aContext);
132
0
    SuccessOrExit(lReturn);
133
134
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
135
    this->AddEventHandlerDelegate(sSystemEventHandlerDelegate);
136
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
137
138
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
139
    // Create a Unix pipe to allow an arbitrary thread to wake the thread in the select loop.
140
0
    lOSReturn = ::pipe(lPipeFDs);
141
0
    VerifyOrExit(lOSReturn == 0, lReturn = nl::Weave::System::MapErrorPOSIX(errno));
142
143
0
    this->mWakePipeIn = lPipeFDs[0];
144
0
    this->mWakePipeOut = lPipeFDs[1];
145
146
    // Enable non-blocking mode for both ends of the pipe.
147
0
    lFlags = ::fcntl(this->mWakePipeIn, F_GETFL, 0);
148
0
    lOSReturn = ::fcntl(this->mWakePipeIn, F_SETFL, lFlags | O_NONBLOCK);
149
0
    VerifyOrExit(lOSReturn == 0, lReturn = nl::Weave::System::MapErrorPOSIX(errno));
150
151
0
    lFlags = ::fcntl(this->mWakePipeOut, F_GETFL, 0);
152
0
    lOSReturn = ::fcntl(this->mWakePipeOut, F_SETFL, lFlags | O_NONBLOCK);
153
0
    VerifyOrExit(lOSReturn == 0, lReturn = nl::Weave::System::MapErrorPOSIX(errno));
154
0
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
155
156
0
    this->mLayerState = kLayerState_Initialized;
157
0
    this->mContext = aContext;
158
159
0
exit:
160
0
    Platform::Layer::DidInit(*this, aContext, lReturn);
161
0
    return lReturn;
162
0
}
163
164
Error Layer::Shutdown()
165
0
{
166
0
    Error lReturn;
167
0
    void* lContext;
168
169
0
    if (this->mLayerState == kLayerState_NotInitialized)
170
0
        return WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE;
171
172
0
    lContext = this->mContext;
173
0
    lReturn = Platform::Layer::WillShutdown(*this, lContext);
174
0
    SuccessOrExit(lReturn);
175
176
0
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
177
0
    if (this->mWakePipeOut != -1)
178
0
    {
179
0
        ::close(this->mWakePipeOut);
180
0
        this->mWakePipeOut = -1;
181
0
        this->mWakePipeIn = -1;
182
0
    }
183
0
#endif
184
185
0
    for (size_t i = 0; i < Timer::sPool.Size(); ++i)
186
0
    {
187
0
        Timer* lTimer = Timer::sPool.Get(*this, i);
188
189
0
        if (lTimer != NULL)
190
0
        {
191
0
            lTimer->Cancel();
192
0
        }
193
0
    }
194
195
0
    this->mContext = NULL;
196
0
    this->mLayerState = kLayerState_NotInitialized;
197
198
0
exit:
199
0
    Platform::Layer::DidShutdown(*this, lContext, lReturn);
200
0
    return lReturn;
201
0
}
202
203
/**
204
 * This returns any client-specific platform data assigned to the instance, if it has been previously set.
205
 *
206
 * @return Client-specific platform data, if is has been previously set; otherwise, NULL.
207
 */
208
void* Layer::GetPlatformData() const
209
0
{
210
0
    return this->mPlatformData;
211
0
}
212
213
/**
214
 * This sets the specified client-specific platform data to the
215
 * instance for later retrieval by the client platform.
216
 *
217
 * @param[in]  aPlatformData  The client-specific platform data to set.
218
 *
219
 */
220
void Layer::SetPlatformData(void* aPlatformData)
221
0
{
222
0
    this->mPlatformData = aPlatformData;
223
0
}
224
225
Error Layer::NewTimer(Timer*& aTimerPtr)
226
0
{
227
0
    Timer* lTimer = NULL;
228
229
0
    if (this->State() != kLayerState_Initialized)
230
0
        return WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE;
231
232
0
    lTimer = Timer::sPool.TryCreate(*this);
233
0
    aTimerPtr = lTimer;
234
235
0
    if (lTimer == NULL)
236
0
    {
237
0
        WeaveLogError(WeaveSystemLayer, "Timer pool EMPTY");
238
0
        return WEAVE_SYSTEM_ERROR_NO_MEMORY;
239
0
    }
240
241
0
    return WEAVE_SYSTEM_NO_ERROR;
242
0
}
243
244
/**
245
* @brief
246
*   This method starts a one-shot timer.
247
*
248
*   @note
249
*       Only a single timer is allowed to be started with the same @a aComplete and @a aAppState
250
*       arguments. If called with @a aComplete and @a aAppState identical to an existing timer,
251
*       the currently-running timer will first be cancelled.
252
*
253
*   @param[in]  aMilliseconds Expiration time in milliseconds.
254
*   @param[in]  aComplete     A pointer to the function called when timer expires.
255
*   @param[in]  aAppState     A pointer to the application state object used when timer expires.
256
*
257
*   @return WEAVE_SYSTEM_NO_ERROR On success.
258
*   @return WEAVE_SYSTEM_ERROR_NO_MEMORY If a timer cannot be allocated.
259
*   @return Other Value indicating timer failed to start.
260
*
261
*/
262
Error Layer::StartTimer(uint32_t aMilliseconds, TimerCompleteFunct aComplete, void* aAppState)
263
0
{
264
0
    Error lReturn;
265
0
    Timer* lTimer;
266
267
0
    this->CancelTimer(aComplete, aAppState);
268
0
    lReturn = this->NewTimer(lTimer);
269
0
    SuccessOrExit(lReturn);
270
271
0
    lReturn = lTimer->Start(aMilliseconds, aComplete, aAppState);
272
0
    if (lReturn != WEAVE_SYSTEM_NO_ERROR)
273
0
    {
274
0
        lTimer->Release();
275
0
    }
276
277
0
exit:
278
0
    return lReturn;
279
0
}
280
281
/**
282
* @brief
283
*   This method cancels a one-shot timer, started earlier through @p StartTimer().
284
*
285
*   @note
286
*       The cancellation could fail silently in two different ways. If the timer specified by the combination of the callback
287
*       function and application state object couldn't be found, cancellation could fail. If the timer has fired, but not yet
288
*       removed from memory, cancellation could also fail.
289
*
290
*   @param[in]  aOnComplete   A pointer to the callback function used in calling @p StartTimer().
291
*   @param[in]  aAppState     A pointer to the application state object used in calling @p StartTimer().
292
*
293
*/
294
void Layer::CancelTimer(Layer::TimerCompleteFunct aOnComplete, void* aAppState)
295
0
{
296
0
    if (this->State() != kLayerState_Initialized)
297
0
        return;
298
299
0
    for (size_t i = 0; i < Timer::sPool.Size(); ++i)
300
0
    {
301
0
        Timer* lTimer = Timer::sPool.Get(*this, i);
302
303
0
        if (lTimer != NULL && lTimer->OnComplete == aOnComplete && lTimer->AppState == aAppState)
304
0
        {
305
0
            lTimer->Cancel();
306
0
            break;
307
0
        }
308
0
    }
309
0
}
310
311
#if WEAVE_SYSTEM_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
312
void Layer::CancelAllMatchingInetTimers(nl::Inet::InetLayer& aInetLayer, void* aOnCompleteInetLayer, void* aAppState)
313
{
314
    for (size_t i = 0; i < Timer::sPool.Size(); ++i)
315
    {
316
        Timer* lTimer = Timer::sPool.Get(*this, i);
317
318
        if (lTimer != NULL && lTimer->mInetLayer == &aInetLayer && lTimer->mOnCompleteInetLayer == aOnCompleteInetLayer &&
319
            lTimer->mAppStateInetLayer == aAppState)
320
        {
321
            lTimer->Cancel();
322
            break;
323
        }
324
    }
325
}
326
#endif // WEAVE_SYSTEM_CONFIG_PROVIDE_OBSOLESCENT_INTERFACES
327
328
/**
329
 * @brief
330
 *   Schedules a function with a signature identical to
331
 *   `TimerCompleteFunct` to be run as soon as possible on the Weave
332
 *   thread.
333
 *
334
 * @note
335
 *   This function could, in principle, be implemented as
336
 *   `StartTimer(0, aComplete, aAppState)`.  The specification for
337
 *   `SystemTimer` however permits certain optimizations that might
338
 *   make that implementation impossible. Specifically, `SystemTimer`
339
 *   API may only be called from the thread owning the particular
340
 *   `SystemLayer`, whereas the `ScheduleWork` may be called from
341
 *   any thread.  Additionally, whereas the `SystemTimer` API permits
342
 *   the invocation of the already expired handler in line,
343
 *   `ScheduleWork` guarantees that the handler function will be
344
 *   called only after the current Weave event completes.
345
 *
346
 * @param[in] aComplete A pointer to a callback function to be called
347
 *                      when this timer fires.
348
 *
349
 * @param[in] aAppState A pointer to an application state object to be
350
 *                      passed to the callback function as argument.
351
 *
352
 * @retval WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE If the SystemLayer has
353
 *                      not been initialized.
354
 *
355
 * @retval WEAVE_SYSTEM_ERROR_NO_MEMORY If the SystemLayer cannot
356
 *                      allocate a new timer.
357
 *
358
 * @retval WEAVE_SYSTEM_NO_ERROR On success.
359
 */
360
Error Layer::ScheduleWork(TimerCompleteFunct aComplete, void* aAppState)
361
0
{
362
0
    Error lReturn;
363
0
    Timer* lTimer;
364
365
0
    lReturn = this->NewTimer(lTimer);
366
0
    SuccessOrExit(lReturn);
367
368
0
    lReturn = lTimer->ScheduleWork(aComplete, aAppState);
369
0
    if (lReturn != WEAVE_SYSTEM_NO_ERROR)
370
0
    {
371
0
        lTimer->Release();
372
0
    }
373
374
0
exit:
375
0
    return lReturn;
376
0
}
377
378
/**
379
 * @brief
380
 *   Returns a monotonic system time in units of microseconds.
381
 *
382
 * This function returns an elapsed time in microseconds since an arbitrary, platform-defined
383
 * epoch.  The value returned is guaranteed to be ever-increasing (i.e. never wrapping) between
384
 * reboots of the system.  Additionally, the underlying time source is guaranteed to tick
385
 * continuously during any system sleep modes that do not entail a restart upon wake.
386
 *
387
 * Although some platforms may choose to return a value that measures the time since boot for the
388
 * system, applications must *not* rely on this.  Additionally, the epoch for GetClock_Monotonic()
389
 * is *not* required to be the same as that for any of the other GetClock... functions.  Therefore
390
 * relative time calculations can only be performed on values returned by the same function.
391
 *
392
 * This function is guaranteed to be thread-safe on any platform that employs threading.
393
 *
394
 * @returns             Elapsed time in microseconds since an arbitrary, platform-defined epoch.
395
 */
396
uint64_t Layer::GetClock_Monotonic(void)
397
0
{
398
    // Current implementation is a simple pass-through to the platform.
399
0
    return Platform::Layer::GetClock_Monotonic();
400
0
}
401
402
/**
403
 * @brief
404
 *   Returns a monotonic system time in units of milliseconds.
405
 *
406
 * This function returns an elapsed time in milliseconds since an arbitrary, platform-defined
407
 * epoch.  The value returned is guaranteed to be ever-increasing (i.e. never wrapping) between
408
 * reboots of the system.  Additionally, the underlying time source is guaranteed to tick
409
 * continuously during any system sleep modes that do not entail a restart upon wake.
410
 *
411
 * Although some platforms may choose to return a value that measures the time since boot for the
412
 * system, applications must *not* rely on this.  Additionally, the epoch for GetClock_Monotonic()
413
 * is *not* required to be the same as that for any of the other GetClock... functions.  Therefore
414
 * relative time calculations can only be performed on values returned by the same function.
415
 *
416
 * This function is guaranteed to be thread-safe on any platform that employs threading.
417
 *
418
 * @returns             Elapsed time in milliseconds since an arbitrary, platform-defined epoch.
419
 */
420
uint64_t Layer::GetClock_MonotonicMS(void)
421
0
{
422
    // Current implementation is a simple pass-through to the platform.
423
0
    return Platform::Layer::GetClock_MonotonicMS();
424
0
}
425
426
/**
427
 * @brief
428
 *   Returns a (potentially) high-resolution monotonic system time in units of microseconds.
429
 *
430
 * This function returns an elapsed time in microseconds since an arbitrary, platform-defined
431
 * epoch.  The value returned is guaranteed to be ever-increasing (i.e. never wrapping) between
432
 * reboots of the system.  However, the underlying timer is *not* required to tick continuously
433
 * during system deep-sleep states.
434
 *
435
 * Some platforms may implement GetClock_MonotonicHiRes() using a high-resolution timer capable
436
 * of greater precision than GetClock_Monotonic(), and that is not subject to gradual clock
437
 * adjustments (slewing).  Systems without such a timer may simply return the same value as
438
 * GetClock_Monotonic().
439
 *
440
 * The epoch for time returned by GetClock_MonotonicHiRes() is not required to be the same that
441
 * for any of the other GetClock... functions, including GetClock_Monotonic().
442
 *
443
 * This function is guaranteed to be thread-safe on any platform that employs threading.
444
 *
445
 * @returns             Elapsed time in microseconds since an arbitrary, platform-defined epoch.
446
 */
447
uint64_t Layer::GetClock_MonotonicHiRes(void)
448
0
{
449
    // Current implementation is a simple pass-through to the platform.
450
0
    return Platform::Layer::GetClock_MonotonicHiRes();
451
0
}
452
453
/**
454
 * @brief
455
 *   Returns the current real (civil) time in microsecond Unix time format.
456
 *
457
 * This method returns the local platform's notion of current real time, expressed as a Unix time
458
 * value scaled to microseconds.  The underlying clock is guaranteed to tick at a rate of least at
459
 * whole seconds (values of 1,000,000), but on some platforms may tick faster.
460
 *
461
 * If the underlying platform is capable of tracking real time, but the system is currently
462
 * unsynchronized, GetClock_RealTime() will return the error WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED.
463
 *
464
 * On platforms that are incapable of tracking real time, the GetClock_RealTime() method may be absent,
465
 * resulting a link error for any application that references it.  Alternatively, such platforms may
466
 * supply an implementation of GetClock_RealTime() that always returns the error WEAVE_SYSTEM_ERROR_NOT_SUPPORTED.
467
 *
468
 * This function is guaranteed to be thread-safe on any platform that employs threading.
469
 *
470
 * @param[out] curTime                  The current time, expressed as Unix time scaled to microseconds.
471
 *
472
 * @retval #WEAVE_SYSTEM_NO_ERROR       If the method succeeded.
473
 * @retval #WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED
474
 *                                      If the platform is capable of tracking real time, but is
475
 *                                      is currently unsynchronized.
476
 * @retval #WEAVE_SYSTEM_ERROR_NOT_SUPPORTED
477
 *                                      If the platform is incapable of tracking real time.
478
 */
479
Error Layer::GetClock_RealTime(uint64_t & curTime)
480
0
{
481
    // Current implementation is a simple pass-through to the platform.
482
0
    return Platform::Layer::GetClock_RealTime(curTime);
483
0
}
484
485
/**
486
 * @brief
487
 *   Returns the current real (civil) time in millisecond Unix time format.
488
 *
489
 * This method returns the local platform's notion of current real time, expressed as a Unix time
490
 * value scaled to milliseconds.  The underlying clock is guaranteed to tick at a rate of least at
491
 * whole seconds (values of 1,000,000), but on some platforms may tick faster.
492
 *
493
 * If the underlying platform is capable of tracking real time, but the system is currently
494
 * unsynchronized, GetClock_RealTimeMS() will return the error WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED.
495
 *
496
 * On platforms that are incapable of tracking real time, the GetClock_RealTimeMS() method may be absent,
497
 * resulting a link error for any application that references it.  Alternatively, such platforms may
498
 * supply an implementation of GetClock_RealTimeMS() that always returns the error WEAVE_SYSTEM_ERROR_NOT_SUPPORTED.
499
 *
500
 * This function is guaranteed to be thread-safe on any platform that employs threading.
501
 *
502
 * @param[out] curTime                  The current time, expressed as Unix time scaled to milliseconds.
503
 *
504
 * @retval #WEAVE_SYSTEM_NO_ERROR       If the method succeeded.
505
 * @retval #WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED
506
 *                                      If the platform is capable of tracking real time, but is
507
 *                                      is currently unsynchronized.
508
 * @retval #WEAVE_SYSTEM_ERROR_NOT_SUPPORTED
509
 *                                      If the platform is incapable of tracking real time.
510
 */
511
Error Layer::GetClock_RealTimeMS(uint64_t & curTimeMS)
512
0
{
513
    // Current implementation is a simple pass-through to the platform.
514
0
    return Platform::Layer::GetClock_RealTimeMS(curTimeMS);
515
0
}
516
517
/**
518
 * @brief
519
 *   Sets the platform's notion of current real (civil) time.
520
 *
521
 * Applications can call this function to set the local platform's notion of current real time.  The
522
 * new current time is expressed as a Unix time value scaled to microseconds.
523
 *
524
 * Once set, underlying platform clock is guaranteed to track real time with a granularity of at least
525
 * whole seconds.
526
 *
527
 * Some platforms may restrict which applications or processes can set real time.  If the caller is
528
 * not permitted to change real time, the SetClock_RealTime() function will return the error
529
 * WEAVE_SYSTEM_ERROR_ACCESS_DENIED.
530
 *
531
 * On platforms that are incapable of tracking real time, or do not offer the ability to set real time,
532
 * the SetClock_RealTime() function may be absent, resulting a link error for any application that
533
 * references it.  Alternatively, such platforms may supply an implementation of SetClock_RealTime()
534
 * that always returns the error WEAVE_SYSTEM_ERROR_NOT_SUPPORTED.
535
 *
536
 * This function is guaranteed to be thread-safe on any platform that employs threading.
537
 *
538
 * @param[in] newCurTime                The new current time, expressed as Unix time scaled to microseconds.
539
 *
540
 * @retval #WEAVE_SYSTEM_NO_ERROR       If the method succeeded.
541
 * @retval #WEAVE_SYSTEM_ERROR_NOT_SUPPORTED
542
 *                                      If the platform is incapable of tracking real time.
543
 * @retval #WEAVE_SYSTEM_ERROR_ACCESS_DENIED
544
 *                                      If the calling application does not have the privilege to set the
545
 *                                      current time.
546
 */
547
Error Layer::SetClock_RealTime(uint64_t newCurTime)
548
0
{
549
    // Current implementation is a simple pass-through to the platform.
550
0
    return Platform::Layer::SetClock_RealTime(newCurTime);
551
0
}
552
553
#if WEAVE_SYSTEM_CONFIG_USE_SOCKETS
554
555
/**
556
 *  Prepare the sets of file descriptors for @p select() to work with.
557
 *
558
 *  @param[in,out]  pollFDs     The fd set which is going to be polled
559
 *  @param[in,out]  numPollFDs  The number of fds in the fd set
560
 *  @param[in]      timeoutMS   A reference to the maximum sleep time.
561
 */
562
void Layer::PrepareSelect(struct pollfd * pollFDs, int& numPollFDs, int& timeoutMS)
563
0
{
564
0
    if (this->State() != kLayerState_Initialized)
565
0
        return;
566
567
0
    struct pollfd & event = pollFDs[numPollFDs++];
568
0
    event.fd = this->mWakePipeIn;
569
0
    event.events = POLLIN;
570
0
    event.revents = 0;
571
572
0
    const Timer::Epoch kCurrentEpoch = Timer::GetCurrentEpoch();
573
0
    Timer::Epoch lAwakenEpoch = kCurrentEpoch + timeoutMS;
574
575
0
    for (size_t i = 0; i < Timer::sPool.Size(); i++)
576
0
    {
577
0
        Timer* lTimer = Timer::sPool.Get(*this, i);
578
579
0
        if (lTimer != NULL)
580
0
        {
581
0
            if (!Timer::IsEarlierEpoch(kCurrentEpoch, lTimer->mAwakenEpoch))
582
0
            {
583
0
                lAwakenEpoch = kCurrentEpoch;
584
0
                break;
585
0
            }
586
587
0
            if (Timer::IsEarlierEpoch(lTimer->mAwakenEpoch, lAwakenEpoch))
588
0
                lAwakenEpoch = lTimer->mAwakenEpoch;
589
0
        }
590
0
    }
591
592
0
    const Timer::Epoch kSleepTime = lAwakenEpoch - kCurrentEpoch;
593
0
    timeoutMS = kSleepTime;
594
0
}
595
596
/**
597
 * Handle I/O from a select call. This method registers the pending I/O event in each active endpoint and then invokes the
598
 * respective I/O handling functions for those endpoints.
599
 *
600
 * @note
601
 *  It is important to set the pending I/O fields for all endpoints *before* making any callbacks. This avoids the case where an
602
 *  endpoint is closed and then re-opened within the callback for another endpoint. When this happens the new endpoint is likely to
603
 *  be assigned the same file descriptor as the old endpoint. However, any pending I/O for that file descriptor number represents
604
 *  I/O related to the old incarnation of the endpoint, not the current one. Saving the pending I/O state in each endpoint before
605
 *  acting on it allows the endpoint code to clear the I/O flags in the event of a close, thus avoiding any confusion.
606
 *
607
 *  @param[in]    pollFDs     The result of polled FDs
608
 *  @param[in]    numPollFDs  The number of fds in the fd set
609
 */
610
void Layer::HandleSelectResult(const struct pollfd * pollFDs, int numPollFDs)
611
0
{
612
0
    pthread_t lThreadSelf;
613
614
0
    if (this->State() != kLayerState_Initialized)
615
0
        return;
616
617
0
#if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
618
0
    lThreadSelf = pthread_self();
619
0
#endif // WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
620
621
0
    for (int i = 0; i < numPollFDs; ++i)
622
0
    {
623
0
        const struct pollfd & event = pollFDs[i];
624
        // If we woke because of someone writing to the wake pipe, clear the contents of the pipe before returning.
625
0
        if (event.fd == this->mWakePipeIn && event.revents != 0)
626
0
        {
627
0
            while (true)
628
0
            {
629
0
                uint8_t lBytes[128];
630
0
                int lTmp = ::read(this->mWakePipeIn, static_cast<void*>(lBytes), sizeof(lBytes));
631
0
                if (lTmp < static_cast<int>(sizeof(lBytes)))
632
0
                    break;
633
0
            }
634
0
        }
635
0
    }
636
637
0
    const Timer::Epoch kCurrentEpoch = Timer::GetCurrentEpoch();
638
639
0
#if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
640
0
    this->mHandleSelectThread = lThreadSelf;
641
0
#endif // WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
642
643
0
    for (size_t i = 0; i < Timer::sPool.Size(); i++)
644
0
    {
645
0
        Timer* lTimer = Timer::sPool.Get(*this, i);
646
647
0
        if (lTimer != NULL && !Timer::IsEarlierEpoch(kCurrentEpoch, lTimer->mAwakenEpoch))
648
0
        {
649
0
            lTimer->HandleComplete();
650
0
        }
651
0
    }
652
653
0
#if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
654
0
    this->mHandleSelectThread = PTHREAD_NULL;
655
0
#endif // WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
656
0
}
657
658
/**
659
 * Wake up the I/O thread that monitors the file descriptors using select() by writing a single byte to the wake pipe.
660
 *
661
 *  @note
662
 *      If @p WakeSelect() is being called from within @p HandleSelectResult(), then writing to the wake pipe can be skipped, since
663
 *      the I/O thread is already awake.
664
 *
665
 *      Furthermore, we don't care if this write fails as the only reasonably likely failure is that the pipe is full, in which
666
 *      case the select calling thread is going to wake up anyway.
667
 */
668
void Layer::WakeSelect()
669
0
{
670
0
    if (this->State() != kLayerState_Initialized)
671
0
        return;
672
673
0
#if WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
674
0
    if (pthread_equal(this->mHandleSelectThread, pthread_self()))
675
0
    {
676
0
        return;
677
0
    }
678
0
#endif // WEAVE_SYSTEM_CONFIG_POSIX_LOCKING
679
680
    // Write a single byte to the wake pipe to wake up the select call.
681
0
    const uint8_t kByte = 0;
682
0
    const ssize_t kIOResult = ::write(this->mWakePipeOut, &kByte, 1);
683
0
    static_cast<void>(kIOResult);
684
0
}
685
686
#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
687
688
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
689
LwIPEventHandlerDelegate Layer::sSystemEventHandlerDelegate;
690
691
/**
692
 * This is the dispatch handler for system layer events.
693
 *
694
 *  @param[inout]   aTarget     A pointer to the Weave System Layer object making the post request.
695
 *  @param[in]      aEventType  The type of event to post.
696
 *  @param[inout]   aArgument   The argument associated with the event to post.
697
 */
698
Error Layer::HandleSystemLayerEvent(Object& aTarget, EventType aEventType, uintptr_t aArgument)
699
{
700
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
701
;
702
703
    // Dispatch logic specific to the event type
704
    switch (aEventType)
705
    {
706
    case kEvent_ReleaseObj:
707
        aTarget.Release();
708
        break;
709
710
    case kEvent_ScheduleWork:
711
        static_cast<Timer&>(aTarget).HandleComplete();
712
        break;
713
714
    default:
715
        lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT;
716
        break;
717
    }
718
719
    return lReturn;
720
}
721
722
/**
723
 * This adds an event handler delegate to the system layer to extend its ability to handle LwIP events.
724
 *
725
 *  @param[in]  aDelegate   An uninitialied LwIP event handler delegate structure
726
 *
727
 *  @retval     WEAVE_SYSTEM_NO_ERROR          On success.
728
 *  @retval     WEAVE_SYSTEM_ERROR_BAD_ARGS    If the function pointer contained in aDelegate is NULL
729
 */
730
Error Layer::AddEventHandlerDelegate(LwIPEventHandlerDelegate& aDelegate)
731
{
732
    Error lReturn;
733
734
    VerifyOrExit(aDelegate.mFunction != NULL, lReturn = WEAVE_SYSTEM_ERROR_BAD_ARGS);
735
    aDelegate.Prepend(this->mEventDelegateList);
736
    lReturn = WEAVE_SYSTEM_NO_ERROR;
737
738
exit:
739
    return lReturn;
740
}
741
742
/**
743
 * This posts an event / message of the specified type with the provided argument to this instance's platform-specific event queue.
744
 *
745
 *  @param[inout]   aTarget     A pointer to the Weave System Layer object making the post request.
746
 *  @param[in]      aEventType  The type of event to post.
747
 *  @param[inout]   aArgument   The argument associated with the event to post.
748
 *
749
 *  @retval    WEAVE_SYSTEM_NO_ERROR                   On success.
750
 *  @retval    WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE     If the state of the Layer object is incorrect.
751
 *  @retval    WEAVE_SYSTEM_ERROR_NO_MEMORY            If the event queue is already full.
752
 *  @retval    other Platform-specific errors generated indicating the reason for failure.
753
 */
754
Error Layer::PostEvent(Object& aTarget, EventType aEventType, uintptr_t aArgument)
755
{
756
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
757
    VerifyOrExit(this->State() == kLayerState_Initialized, lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE);
758
759
    // Sanity check that this instance and the target layer haven't been "crossed".
760
    VerifyOrDieWithMsg(aTarget.IsRetained(*this), WeaveSystemLayer, "wrong poster! [target %p != this %p]",
761
        &(aTarget.SystemLayer()), this);
762
763
    lReturn = Platform::Layer::PostEvent(*this, this->mContext, aTarget, aEventType, aArgument);
764
    if (lReturn != WEAVE_SYSTEM_NO_ERROR)
765
    {
766
        WeaveLogError(WeaveSystemLayer, "Failed to queue Weave System Layer event (type %d): %s", aEventType, ErrorStr(lReturn));
767
    }
768
    SuccessOrExit(lReturn);
769
770
exit:
771
    return lReturn;
772
}
773
774
/**
775
 * This is a syntactic wrapper around a platform-specific hook that effects an event loop, waiting on a queue that services this
776
 * instance, pulling events off of that queue, and then dispatching them for handling.
777
 *
778
 *  @return #WEAVE_SYSTEM_NO_ERROR on success; otherwise, a specific error indicating the reason for initialization failure.
779
 */
780
Error Layer::DispatchEvents()
781
{
782
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
783
    VerifyOrExit(this->State() == kLayerState_Initialized, lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE);
784
785
    lReturn = Platform::Layer::DispatchEvents(*this, this->mContext);
786
    SuccessOrExit(lReturn);
787
788
 exit:
789
    return lReturn;
790
}
791
792
/**
793
 * This dispatches the specified event for handling by this instance.
794
 *
795
 *  The unmarshalling of the type and arguments from the event is handled by a platform-specific hook which should then call back
796
 *  to Layer::HandleEvent for the actual dispatch.
797
 *
798
 *  @param[in]  aEvent  The platform-specific event object to dispatch for handling.
799
 *
800
 * @return WEAVE_SYSTEM_NO_ERROR on success; otherwise, a specific error indicating the reason for initialization failure.
801
 */
802
Error Layer::DispatchEvent(Event aEvent)
803
{
804
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
805
    VerifyOrExit(this->State() == kLayerState_Initialized, lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE);
806
807
    lReturn = Platform::Layer::DispatchEvent(*this, this->mContext, aEvent);
808
    SuccessOrExit(lReturn);
809
810
 exit:
811
    return lReturn;
812
}
813
814
/**
815
 * This implements the actual dispatch and handling of a Weave System Layer event.
816
 *
817
 *  @param[inout]   aTarget     A reference to the layer object to which the event is targeted.
818
 *  @param[in]      aEventType  The event / message type to handle.
819
 *  @param[in]      aArgument   The argument associated with the event / message.
820
 *
821
 *  @retval   WEAVE_SYSTEM_NO_ERROR                On success.
822
 *  @retval   WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE  If the state of the InetLayer object is incorrect.
823
 *  @retval   WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT  If the event type is unrecognized.
824
 */
825
Error Layer::HandleEvent(Object& aTarget, EventType aEventType, uintptr_t aArgument)
826
{
827
    const LwIPEventHandlerDelegate* lEventDelegate;
828
    Error lReturn;
829
    VerifyOrExit(this->State() == kLayerState_Initialized, lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE);
830
831
    // Sanity check that this instance and the target layer haven't been "crossed".
832
    VerifyOrDieWithMsg(aTarget.IsRetained(*this), WeaveSystemLayer, "wrong handler! [target %p != this %p]",
833
        &(aTarget.SystemLayer()), this);
834
835
    lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT;
836
    lEventDelegate = this->mEventDelegateList;
837
838
    // Prevent the target object from being freed while dispatching the event.
839
    aTarget.Retain();
840
841
    while (lReturn == WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT && lEventDelegate != NULL)
842
    {
843
        lReturn = lEventDelegate->mFunction(aTarget, aEventType, aArgument);
844
        lEventDelegate = lEventDelegate->mNextDelegate;
845
    }
846
847
    if (lReturn == WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT)
848
    {
849
        WeaveLogError(WeaveSystemLayer, "Unexpected event type %d", aEventType);
850
    }
851
852
    /*
853
      Release the reference to the target object. When the object's lifetime finally comes to an end, in most cases this will be
854
      the release call that decrements the ref count to zero.
855
      */
856
    aTarget.Release();
857
858
 exit:
859
    return lReturn;
860
}
861
862
/**
863
 * Start the platform timer with specified millsecond duration.
864
 *
865
 *  @brief
866
 *      Calls the Platform specific API to start a platform timer. This API is called by the nl::Weave::System::Timer class when
867
 *      one or more timers are active and require deferred execution.
868
 *
869
 *  @param[in]  aDelayMilliseconds  The timer duration in milliseconds.
870
 *
871
 *  @return WEAVE_SYSTEM_NO_ERROR on success, error code otherwise.
872
 *
873
 */
874
Error Layer::StartPlatformTimer(uint32_t aDelayMilliseconds)
875
{
876
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
877
    VerifyOrExit(this->State() == kLayerState_Initialized, lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE);
878
879
    lReturn = Platform::Layer::StartTimer(*this, this->mContext, aDelayMilliseconds);
880
    SuccessOrExit(lReturn);
881
882
 exit:
883
    return lReturn;
884
}
885
886
/**
887
 * Handle the platform timer expiration event.
888
 *
889
 *  @brief
890
 *      Calls nl::Weave::System::Timer::HandleExpiredTimers to handle any expired timers.  It is assumed that this API is called
891
 *      only while on the thread which owns the Weave System Layer object.
892
 *
893
 *  @return WEAVE_SYSTEM_NO_ERROR on success, error code otherwise.
894
 *
895
 */
896
Error Layer::HandlePlatformTimer()
897
{
898
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
899
    VerifyOrExit(this->State() == kLayerState_Initialized, lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE);
900
901
    lReturn = Timer::HandleExpiredTimers(*this);
902
    SuccessOrExit(lReturn);
903
904
 exit:
905
    return lReturn;
906
}
907
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
908
909
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
910
#if !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS
911
912
// MARK: Weave System Layer platform- and system-specific functions for LwIP-native eventing.
913
struct LwIPEvent
914
{
915
    EventType   Type;
916
    Object*     Target;
917
    uintptr_t   Argument;
918
};
919
920
#endif // !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS
921
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
922
923
namespace Platform {
924
namespace Layer {
925
926
#if !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_XTOR_FUNCTIONS
927
928
/**
929
 * This is a platform-specific Weave System Layer pre-initialization hook. This may be overridden by assserting the preprocessor
930
 * definition, #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_XTOR_FUNCTIONS.
931
 *
932
 *  @param[inout]  aLayer    A reference to the Weave System Layer instance being initialized.
933
 *
934
 *  @param[inout]  aContext  Platform-specific context data passed to the layer initialization method, ::Init.
935
 *
936
 *  @return #WEAVE_SYSTEM_NO_ERROR on success; otherwise, a specific error indicating the reason for initialization failure.
937
 *      Returning non-successful status will abort initialization.
938
 */
939
NL_DLL_EXPORT Error WillInit(Layer& aLayer, void* aContext)
940
0
{
941
0
    static_cast<void>(aLayer);
942
0
    static_cast<void>(aContext);
943
944
0
    return WEAVE_SYSTEM_NO_ERROR;
945
0
}
946
947
/**
948
 * This is a platform-specific Weave System Layer pre-shutdown hook. This may be overridden by assserting the preprocessor
949
 * definition, #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_XTOR_FUNCTIONS.
950
 *
951
 *  @param[inout]  aLayer    A pointer to the Weave System Layer instance being shutdown.
952
 *
953
 *  @param[inout]  aContext  Platform-specific context data passed to the layer initialization method, ::Shutdown.
954
 *
955
 *  @return #WEAVE_SYSTEM_NO_ERROR on success; otherwise, a specific error indicating the reason for shutdown failure. Returning
956
 *      non-successful status will abort shutdown.
957
 */
958
NL_DLL_EXPORT Error WillShutdown(Layer& aLayer, void* aContext)
959
0
{
960
0
    static_cast<void>(aLayer);
961
0
    static_cast<void>(aContext);
962
963
0
    return WEAVE_SYSTEM_NO_ERROR;
964
0
}
965
966
/**
967
 * This is a platform-specific Weave System Layer post-initialization hook. This may be overridden by assserting the preprocessor
968
 * definition, #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_XTOR_FUNCTIONS.
969
 *
970
 *  @param[inout]  aLayer    A reference to the Weave System Layer instance being initialized.
971
 *
972
 *  @param[inout]  aContext  Platform-specific context data passed to the layer initialization method, ::Init.
973
 *
974
 *  @param[in]     anError   The overall status being returned via the Weave System Layer ::Init method.
975
 */
976
NL_DLL_EXPORT void DidInit(Layer& aLayer, void* aContext, Error aStatus)
977
0
{
978
0
    static_cast<void>(aLayer);
979
0
    static_cast<void>(aContext);
980
0
    static_cast<void>(aStatus);
981
0
}
982
983
/**
984
 * This is a platform-specific Weave System Layer pre-shutdown hook. This may be overridden by assserting the preprocessor
985
 * definition, #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_XTOR_FUNCTIONS.
986
 *
987
 *  @param[inout]  aLayer    A reference to the Weave System Layer instance being shutdown.
988
 *
989
 *  @param[inout]  aContext  Platform-specific context data passed to the layer initialization method, ::Shutdown.
990
 *
991
 *  @param[in]     anError   The overall status being returned via the Weave System Layer ::Shutdown method.
992
 *
993
 *  @return #WEAVE_SYSTEM_NO_ERROR on success; otherwise, a specific error indicating the reason for shutdown failure. Returning
994
 *      non-successful status will abort shutdown.
995
 */
996
NL_DLL_EXPORT void DidShutdown(Layer& aLayer, void* aContext, Error aStatus)
997
0
{
998
0
    static_cast<void>(aLayer);
999
0
    static_cast<void>(aContext);
1000
0
    static_cast<void>(aStatus);
1001
0
}
1002
1003
#endif // !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_XTOR_FUNCTIONS
1004
1005
#if WEAVE_SYSTEM_CONFIG_USE_LWIP
1006
#if !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS
1007
1008
using nl::Weave::System::LwIPEvent;
1009
1010
/**
1011
 *  This is a platform-specific event / message post hook. This may be overridden by assserting the preprocessor definition,
1012
 *  #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS.
1013
 *
1014
 *  This posts an event / message of the specified type with the provided argument to this instance's platform-specific event /
1015
 *  message queue.
1016
 *
1017
 *  @note
1018
 *    This is an implementation for LwIP.
1019
 *
1020
 *  @param[inout]  aLayer    A pointer to the layer instance to which the event / message is being posted.
1021
 *
1022
 *  @param[inout]  aContext  Platform-specific context data passed to the layer initialization method, ::Init.
1023
 *
1024
 *  @param[inout]  aTarget   A pointer to the Weave System Layer object making the post request.
1025
 *
1026
 *  @param[in]     aType     The type of event to post.
1027
 *
1028
 *  @param[inout]  anArg     The argument associated with the event to post.
1029
 *
1030
 *  @return #WEAVE_SYSTEM_NO_ERROR on success; otherwise, a specific error indicating the reason for initialization failure.
1031
 */
1032
NL_DLL_EXPORT Error PostEvent(Layer& aLayer, void* aContext, Object& aTarget, EventType aType, uintptr_t aArgument)
1033
{
1034
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
1035
    sys_mbox_t lSysMbox;
1036
    LwIPEvent* ev;
1037
    err_t lLwIPError;
1038
1039
    VerifyOrExit(aContext != NULL, lReturn = WEAVE_SYSTEM_ERROR_BAD_ARGS);
1040
    lSysMbox = reinterpret_cast<sys_mbox_t>(aContext);
1041
1042
    ev = new LwIPEvent;
1043
    VerifyOrExit(ev != NULL, lReturn = WEAVE_SYSTEM_ERROR_NO_MEMORY);
1044
1045
    ev->Type = aType;
1046
    ev->Target = &aTarget;
1047
    ev->Argument = aArgument;
1048
1049
    lLwIPError = sys_mbox_trypost(&lSysMbox, ev);
1050
    VerifyOrExit(lLwIPError == ERR_OK, delete ev; lReturn = nl::Weave::System::MapErrorLwIP(lLwIPError));
1051
1052
 exit:
1053
    return lReturn;
1054
}
1055
1056
/**
1057
 *  This is a platform-specific event / message dispatch hook. This may be overridden by assserting the preprocessor definition,
1058
 *  #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS.
1059
 *
1060
 *  This effects an event loop, waiting on a queue that services this instance, pulling events off of that queue, and then
1061
 *  dispatching them for handling.
1062
 *
1063
 *  @note
1064
 *    This is an implementation for LwIP.
1065
 *
1066
 *  @param[inout]  aLayer    A reference to the layer instance for which events / messages are being dispatched.
1067
 *
1068
 *  @param[inout]  aContext  Platform-specific context data passed to the layer initialization method, ::Init.
1069
 *
1070
 *  @retval   #WEAVE_SYSTEM_ERROR_BAD_ARGS          If #aLayer or #aContext is NULL.
1071
 *  @retval   #WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE  If the state of the Weave System Layer object is unexpected.
1072
 *  @retval   #WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT  If an event type is unrecognized.
1073
 *  @retval   #WEAVE_SYSTEM_NO_ERROR                On success.
1074
 */
1075
NL_DLL_EXPORT Error DispatchEvents(Layer& aLayer, void* aContext)
1076
{
1077
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
1078
    err_t lLwIPError;
1079
    sys_mbox_t lSysMbox;
1080
    void* lVoidPointer;
1081
    const LwIPEvent* lEvent;
1082
1083
    // Sanity check the context / queue.
1084
    VerifyOrExit(aContext != NULL, lReturn = WEAVE_SYSTEM_ERROR_BAD_ARGS);
1085
    lSysMbox = reinterpret_cast<sys_mbox_t>(aContext);
1086
1087
    while (true)
1088
    {
1089
        lLwIPError = sys_arch_mbox_tryfetch(&lSysMbox, &lVoidPointer);
1090
        VerifyOrExit(lLwIPError == ERR_OK, lReturn = nl::Weave::System::MapErrorLwIP(lLwIPError));
1091
1092
        lEvent = static_cast<const LwIPEvent*>(lVoidPointer);
1093
        VerifyOrExit(lEvent != NULL && lEvent->Target != NULL, lReturn = WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT);
1094
1095
        lReturn = aLayer.HandleEvent(*lEvent->Target, lEvent->Type, lEvent->Argument);
1096
        delete lEvent;
1097
1098
        SuccessOrExit(lReturn);
1099
    }
1100
1101
 exit:
1102
    return lReturn;
1103
}
1104
1105
/**
1106
 *  This is a platform-specific event / message dispatch hook. This may be overridden by assserting the preprocessor definition,
1107
 *  #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS.
1108
 *
1109
 *  This dispatches the specified event for handling, unmarshalling the type and arguments from the event for hand off to Weave
1110
 *  System Layer::HandleEvent for the actual dispatch.
1111
 *
1112
 *  @note
1113
 *    This is an implementation for LwIP.
1114
 *
1115
 *  @param[inout]  aLayer    A reference to the layer instance for which events / messages are being dispatched.
1116
 *  @param[inout]  aContext  Platform-specific context data passed to the layer initialization method, ::Init.
1117
 *  @param[in]     anEvent   The platform-specific event object to dispatch for handling.
1118
 *
1119
 *  @retval   #WEAVE_SYSTEM_ERROR_BAD_ARGS          If #aLayer or the event target is NULL.
1120
 *  @retval   #WEAVE_SYSTEM_ERROR_UNEXPECTED_EVENT  If the event type is unrecognized.
1121
 *  @retval   #WEAVE_SYSTEM_ERROR_UNEXPECTED_STATE  If the state of the Weave System Layer object is unexpected.
1122
 *  @retval   #WEAVE_SYSTEM_NO_ERROR                On success.
1123
 */
1124
NL_DLL_EXPORT Error DispatchEvent(Layer& aLayer, void* aContext, Event aEvent)
1125
{
1126
    const EventType type = aEvent->Type;
1127
    Object* target = aEvent->Target;
1128
    const uint32_t data = aEvent->Argument;
1129
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
1130
1131
    // Sanity check the target object.
1132
    VerifyOrExit(target != NULL, lReturn = WEAVE_SYSTEM_ERROR_BAD_ARGS);
1133
1134
    // Handle the event.
1135
    lReturn = aLayer.HandleEvent(*target, type, data);
1136
    SuccessOrExit(lReturn);
1137
1138
 exit:
1139
    return lReturn;
1140
}
1141
1142
/**
1143
 *  This is a platform-specific event / message dispatch hook. This may be overridden by assserting the preprocessor definition,
1144
 *  #WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS.
1145
 *
1146
 *  @note
1147
 *    This is an implementation for LwIP.
1148
 *
1149
 *  @param[inout]  aLayer               A reference to the layer instance for which events / messages are being dispatched.
1150
 *  @param[inout]  aContext             Platform-specific context data passed to the layer initialization method, ::Init.
1151
 *  @param[in]     aMilliseconds        The number of milliseconds to set for the timer.
1152
 *
1153
 *  @retval   #WEAVE_SYSTEM_NO_ERROR    Always succeeds unless overridden.
1154
 */
1155
NL_DLL_EXPORT Error StartTimer(Layer& aLayer, void* aContext, uint32_t aMilliseconds)
1156
{
1157
    Error lReturn = WEAVE_SYSTEM_NO_ERROR;
1158
1159
    // At the moment there is no need to do anything for standalone weave + LWIP.
1160
    // the Task will periodically call HandleTimer which will process any expired
1161
    // timers.
1162
    static_cast<void>(aLayer);
1163
    static_cast<void>(aContext);
1164
    static_cast<void>(aMilliseconds);
1165
1166
    return lReturn;
1167
}
1168
1169
#endif // !WEAVE_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS
1170
#endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
1171
1172
} // namespace Layer
1173
} // namespace Platform
1174
} // namespace System
1175
} // namespace Weave
1176
} // namespace nl