1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // DOCSTAG: [pw_async2-examples-count]
16 #define PW_LOG_MODULE_NAME "ASYNC_COUNTER"
17
18 #include "pw_allocator/libc_allocator.h"
19 #include "pw_async2/allocate_task.h"
20 #include "pw_async2/coro.h"
21 #include "pw_async2/coro_or_else_task.h"
22 #include "pw_async2/dispatcher.h"
23 #include "pw_async2/system_time_provider.h"
24 #include "pw_chrono/system_clock.h"
25 #include "pw_log/log.h"
26 #include "pw_result/result.h"
27 #include "pw_status/status.h"
28
29 using ::pw::Allocator;
30 using ::pw::OkStatus;
31 using ::pw::Result;
32 using ::pw::Status;
33 using ::pw::allocator::GetLibCAllocator;
34 using ::pw::async2::AllocateTask;
35 using ::pw::async2::Coro;
36 using ::pw::async2::CoroContext;
37 using ::pw::async2::CoroOrElseTask;
38 using ::pw::async2::Dispatcher;
39 using ::pw::async2::GetSystemTimeProvider;
40 using ::pw::async2::Task;
41 using ::pw::async2::TimeProvider;
42 using ::pw::chrono::SystemClock;
43 using ::std::chrono_literals::operator""ms;
44
45 namespace {
46
47 class Counter {
48 public:
49 // examples-constructor-start
Counter(Dispatcher & dispatcher,Allocator & allocator,TimeProvider<SystemClock> & time)50 Counter(Dispatcher& dispatcher,
51 Allocator& allocator,
52 TimeProvider<SystemClock>& time)
53 : dispatcher_(&dispatcher), allocator_(&allocator), time_(&time) {}
54 // examples-constructor-end
55
56 // examples-task-start
57 // Posts a new asynchronous task which will count up to `times`, one count
58 // per `period`.
StartCounting(SystemClock::duration period,int times)59 void StartCounting(SystemClock::duration period, int times) {
60 CoroContext coro_cx(*allocator_);
61 Coro<Status> coro = CountCoro(coro_cx, period, times);
62 Task* new_task =
63 AllocateTask<CoroOrElseTask>(*allocator_, std::move(coro), [](Status) {
64 PW_LOG_ERROR("Counter coroutine failed to allocate.");
65 });
66
67 // The newly allocated task will be free'd by the dispatcher
68 // upon completion.
69 dispatcher_->Post(*new_task);
70 }
71 // examples-task-end
72
73 private:
74 // Asynchronous counter implementation.
CountCoro(CoroContext &,SystemClock::duration period,int times)75 Coro<Status> CountCoro(CoroContext&,
76 SystemClock::duration period,
77 int times) {
78 PW_LOG_INFO("Counting to %i", times);
79 for (int i = 1; i <= times; ++i) {
80 co_await time_->WaitFor(period);
81 PW_LOG_INFO("%i of %i", i, times);
82 }
83 co_return OkStatus();
84 }
85
86 Dispatcher* dispatcher_;
87 Allocator* allocator_;
88 TimeProvider<SystemClock>* time_;
89 };
90
91 } // namespace
92
main()93 int main() {
94 Allocator& alloc = GetLibCAllocator();
95 TimeProvider<SystemClock>& time = GetSystemTimeProvider();
96 Dispatcher dispatcher;
97
98 Counter counter(dispatcher, alloc, time);
99 counter.StartCounting(/*period=*/500ms, /*times=*/5);
100
101 dispatcher.RunToCompletion();
102 }
103 // DOCSTAG: [pw_async2-examples-count]
104