forked from nrfconnect/ncs-matter
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp_task.cpp
More file actions
253 lines (218 loc) · 8.02 KB
/
Copy pathapp_task.cpp
File metadata and controls
253 lines (218 loc) · 8.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include "app_task.h"
#include "app/matter_init.h"
#include "app/task_executor.h"
#include "board/board.h"
#include "clusters/identify.h"
#include "lib/core/CHIPError.h"
#include <app/clusters/temperature-measurement-server/CodegenIntegration.h>
#include <zephyr/logging/log.h>
#ifdef CONFIG_BME680
#include <zephyr/drivers/sensor.h>
const device *sBme688SensorDev = DEVICE_DT_GET_ONE(bosch_bme680);
#endif
LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
using namespace ::chip;
using namespace ::chip::app;
using namespace ::chip::DeviceLayer;
namespace
{
constexpr chip::EndpointId kTemperatureSensorEndpointId = 1;
Nrf::Matter::IdentifyCluster sIdentifyCluster(kTemperatureSensorEndpointId);
#ifdef CONFIG_CHIP_ICD_UAT_SUPPORT
#ifdef CONFIG_MATTER_USE_DEFAULT_BUTTON_HANDLER
#define UAT_BUTTON_MASK DK_BTN3_MSK
#endif
#endif
#ifndef CONFIG_MATTER_USE_DEFAULT_BUTTON_HANDLER
constexpr int kSoftwareUpdateTimeout = 1500;
constexpr int kUatTimeout = 1500;
constexpr int kFactoryResetTimeout = 3000;
constexpr int kUatBlinkPeriod = 200;
ButtonState sBtnState = ButtonState::None;
k_timer sBtn1Timer;
#endif
} /* namespace */
void HandleUAT()
{
#ifdef CONFIG_CHIP_ICD_UAT_SUPPORT
LOG_INF("ICD UserActiveMode has been triggered.");
Server::GetInstance().GetICDManager().OnNetworkActivity();
#endif
}
/* nRF54T15 TAG has only a single button,
* therefore the default handler for factory data and software update had to be overridden.
* On other DK's only UAT is handled by the application.
*/
void AppTask::ButtonEventHandler(Nrf::ButtonState state, Nrf::ButtonMask hasChanged)
{
#ifdef CONFIG_MATTER_USE_DEFAULT_BUTTON_HANDLER
if (UAT_BUTTON_MASK & state & hasChanged) {
HandleUAT();
}
#else
if (DK_BTN1_MSK & hasChanged) {
if (DK_BTN1_MSK & state) {
LOG_INF("Release the button within %ums to trigger Software Update", kSoftwareUpdateTimeout);
k_timer_start(&sBtn1Timer, K_MSEC(kSoftwareUpdateTimeout), K_NO_WAIT);
sBtnState = ButtonState::SoftwareUpdate;
} else {
if (sBtnState == ButtonState::SoftwareUpdate) {
#ifndef CONFIG_MATTER_CUSTOM_BLUETOOTH_ADVERTISING
if (Nrf::GetBoard().GetDeviceState() == Nrf::DeviceState::DeviceProvisioned) {
/* In this case we need to run only Bluetooth LE SMP advertising if it is available */
#ifdef CONFIG_CHIP_DFU_OVER_BT_SMP
GetDFUOverSMP().StartServer();
#else
LOG_INF("Software update is disabled");
#endif
} else {
/* In this case we start both Bluetooth LE SMP and Matter advertising at the
* same time */
Nrf::GetBoard().StartBLEAdvertisement();
}
#endif
} else if (sBtnState == ButtonState::UAT) {
HandleUAT();
}
/* Restore LED's state and cancel the timer */
k_timer_stop(&sBtn1Timer);
sBtnState = ButtonState::None;
Nrf::GetBoard().RestoreAllLedsState();
Nrf::GetBoard().RunLedStateHandler();
}
}
#endif
}
#ifndef CONFIG_MATTER_USE_DEFAULT_BUTTON_HANDLER
void ButtonTimerEventHandler()
{
if (sBtnState == ButtonState::SoftwareUpdate) {
LOG_INF("Release the button within %ums to trigger UAT", kUatTimeout);
k_timer_start(&sBtn1Timer, K_MSEC(kUatTimeout), K_NO_WAIT);
sBtnState = ButtonState::UAT;
/* Turn off all LEDs before starting blink to make sure blink is coordinated. */
Nrf::GetBoard().ResetAllLeds();
Nrf::GetBoard().ForEachLED([](Nrf::LEDWidget &led) { led.Blink(kUatBlinkPeriod); });
} else if (sBtnState == ButtonState::UAT) {
LOG_INF("Factory reset has been triggered. Release button within %ums to cancel.",
kFactoryResetTimeout);
/* Start timer for sFactoryResetTimeout to allow user to cancel, if required. */
k_timer_start(&sBtn1Timer, K_MSEC(kFactoryResetTimeout), K_NO_WAIT);
sBtnState = ButtonState::None;
Nrf::GetBoard().ForEachLED([](Nrf::LEDWidget &led) { led.Blink(Nrf::LedConsts::kBlinkRate_ms); });
/* If we reached here, the button was held past FactoryResetTriggerTimeout, initiate factory reset */
} else if (sBtnState == ButtonState::None) {
/* Actually trigger Factory Reset */
chip::Server::GetInstance().ScheduleFactoryReset();
}
}
void ButtonTimerTimeoutCallback(k_timer *timer)
{
Nrf::PostTask([] { ButtonTimerEventHandler(); });
}
#endif
void AppTask::UpdateTemperatureMeasurement()
{
#ifdef CONFIG_BME680
/* Real data from the onboard sensor*/
int result = sensor_sample_fetch(sBme688SensorDev);
if (result == 0) {
sensor_value temperature;
int result = sensor_channel_get(sBme688SensorDev, SENSOR_CHAN_AMBIENT_TEMP, &temperature);
if (result == 0) {
/* Defined by cluster temperature measured value = 100 x temperature in degC with resolution of
* 0.01 degC. val1 is an integer part of the value and val2 is fractional part in one-millionth
* parts. To achieve resolution of 0.01 degC val2 needs to be divided by 10000. */
mCurrentTemperature = static_cast<int16_t>(temperature.val1 * 100 + temperature.val2 / 10000);
LOG_DBG("New temperature measurement %d.%d *C", temperature.val1, temperature.val2);
} else {
LOG_ERR("Getting temperature measurement data from BME688 failed with: %d", result);
}
} else {
LOG_ERR("Fetching data from BME688 sensor failed with: %d", result);
}
#else
/* Linear temperature increase that is wrapped around to min value after reaching the max value. */
if (mCurrentTemperature < mTemperatureSensorMaxValue) {
mCurrentTemperature += kTemperatureMeasurementStep;
} else {
mCurrentTemperature = mTemperatureSensorMinValue;
}
#endif
}
void AppTask::UpdateTemperatureTimeoutCallback(k_timer *timer)
{
if (!timer || !timer->user_data) {
return;
}
CHIP_ERROR err = DeviceLayer::PlatformMgr().ScheduleWork(
[](intptr_t p) {
AppTask::Instance().UpdateTemperatureMeasurement();
CHIP_ERROR setErr = Clusters::TemperatureMeasurement::SetMeasuredValue(
kTemperatureSensorEndpointId, AppTask::Instance().GetCurrentTemperature());
if (setErr != CHIP_NO_ERROR) {
LOG_ERR("Updating temperature measurement failed %" CHIP_ERROR_FORMAT,
setErr.Format());
}
},
reinterpret_cast<intptr_t>(timer->user_data));
if (err != CHIP_NO_ERROR) {
LOG_ERR("ScheduleWork failed: %" CHIP_ERROR_FORMAT, err.Format());
}
}
CHIP_ERROR AppTask::Init()
{
/* Initialize Matter stack */
ReturnErrorOnFailure(Nrf::Matter::PrepareServer());
if (!Nrf::GetBoard().Init(ButtonEventHandler)) {
LOG_ERR("User interface initialization failed.");
return CHIP_ERROR_INCORRECT_STATE;
}
/* Register Matter event handler that controls the connectivity status LED based on the captured Matter network
* state. */
ReturnErrorOnFailure(Nrf::Matter::RegisterEventHandler(Nrf::Board::DefaultMatterEventHandler, 0));
#ifdef CONFIG_BME680
if (!device_is_ready(sBme688SensorDev)) {
LOG_ERR("BME688 sensor device not ready");
return chip::System::MapErrorZephyr(-ENODEV);
}
#endif
return Nrf::Matter::StartServer();
}
CHIP_ERROR AppTask::StartApp()
{
ReturnErrorOnFailure(Init());
auto *temperatureMeasurement =
Clusters::TemperatureMeasurement::FindClusterOnEndpoint(kTemperatureSensorEndpointId);
if (temperatureMeasurement == nullptr) {
LOG_ERR("Failed to find TemperatureMeasurement cluster");
return CHIP_ERROR_INCORRECT_STATE;
}
DataModel::Nullable<int16_t> minVal = temperatureMeasurement->GetMinMeasuredValue();
if (minVal.IsNull()) {
LOG_ERR("Failed to get temperature measurement min value");
return CHIP_ERROR_INCORRECT_STATE;
}
mTemperatureSensorMinValue = minVal.Value();
DataModel::Nullable<int16_t> maxVal = temperatureMeasurement->GetMaxMeasuredValue();
if (maxVal.IsNull()) {
LOG_ERR("Failed to get temperature measurement max value");
return CHIP_ERROR_INCORRECT_STATE;
}
mTemperatureSensorMaxValue = maxVal.Value();
k_timer_init(&mTimer, AppTask::UpdateTemperatureTimeoutCallback, nullptr);
k_timer_user_data_set(&mTimer, this);
k_timer_start(&mTimer, K_MSEC(kTemperatureMeasurementIntervalMs), K_MSEC(kTemperatureMeasurementIntervalMs));
#ifndef CONFIG_MATTER_USE_DEFAULT_BUTTON_HANDLER
k_timer_init(&sBtn1Timer, &ButtonTimerTimeoutCallback, nullptr);
#endif
while (true) {
Nrf::DispatchNextTask();
}
return CHIP_NO_ERROR;
}