Skip to content

Commit b589bff

Browse files
committed
modules: battery: Add battery percentage request/response events
- Add battery percentage request/response events - Send battery percentage to the transport module - Forward battery percentage to nRF Cloud - Add test for battery module - Update test for trigger module to handle the new battery percentage sample event Signed-off-by: Simen S. Røstad <simen.rostad@nordicsemi.no>
1 parent 9868133 commit b589bff

File tree

14 files changed

+397
-71
lines changed

14 files changed

+397
-71
lines changed

app/src/common/message_channel.c

+8
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ ZBUS_CHAN_DEFINE(NETWORK_CHAN,
5050
ZBUS_MSG_INIT(.type = NETWORK_DISCONNECTED)
5151
);
5252

53+
ZBUS_CHAN_DEFINE(BATTERY_CHAN,
54+
struct battery_msg,
55+
NULL,
56+
NULL,
57+
ZBUS_OBSERVERS_EMPTY,
58+
ZBUS_MSG_INIT(0)
59+
);
60+
5361
ZBUS_CHAN_DEFINE(ERROR_CHAN,
5462
enum error_type,
5563
NULL,

app/src/common/message_channel.h

+30
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ struct payload {
5353

5454
#define MSG_TO_PAYLOAD(_msg) ((struct payload *)_msg)
5555

56+
/** NETWORK_MODULE */
57+
5658
enum network_msg_type {
5759
/* Output message types */
5860

@@ -178,6 +180,33 @@ struct network_msg {
178180

179181
#define MSG_TO_NETWORK_MSG(_msg) (*(const struct network_msg *)_msg)
180182

183+
/** BATTERY MODULE */
184+
185+
enum battery_msg_type {
186+
/* Output message types */
187+
188+
/* Response message to a request for a battery percentage sample. The sample is found in the
189+
* .percentage field of the message.
190+
*/
191+
BATTERY_PERCENTAGE_SAMPLE_RESPONSE = 0x1,
192+
193+
/* Input message types */
194+
195+
/* Request to retrieve the current battery percentage. The response is sent as a
196+
* BATTERY_PERCENTAGE_SAMPLE_RESPONSE message.
197+
*/
198+
BATTERY_PERCENTAGE_SAMPLE_REQUEST,
199+
};
200+
201+
struct battery_msg {
202+
enum battery_msg_type type;
203+
204+
/** Contains the current charge of the battery in percentage. */
205+
double percentage;
206+
};
207+
208+
#define MSG_TO_BATTERY_MSG(_msg) (*(const struct battery_msg *)_msg)
209+
181210
enum cloud_status {
182211
CLOUD_DISCONNECTED = 0x1,
183212
CLOUD_CONNECTED_READY_TO_SEND,
@@ -263,6 +292,7 @@ ZBUS_CHAN_DECLARE(
263292
FOTA_STATUS_CHAN,
264293
LED_CHAN,
265294
NETWORK_CHAN,
295+
BATTERY_CHAN,
266296
PAYLOAD_CHAN,
267297
TIME_CHAN,
268298
TRIGGER_CHAN,

app/src/modules/battery/battery.c

+32-55
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,13 @@ LOG_MODULE_REGISTER(battery, CONFIG_APP_BATTERY_LOG_LEVEL);
2626
ZBUS_MSG_SUBSCRIBER_DEFINE(battery);
2727

2828
/* Observe channels */
29-
ZBUS_CHAN_ADD_OBS(TRIGGER_CHAN, battery, 0);
30-
ZBUS_CHAN_ADD_OBS(NETWORK_CHAN, battery, 0);
31-
ZBUS_CHAN_ADD_OBS(TIME_CHAN, battery, 0);
29+
ZBUS_CHAN_ADD_OBS(BATTERY_CHAN, battery, 0);
3230

33-
#define MAX_MSG_SIZE \
34-
(MAX(sizeof(enum trigger_type), \
35-
(MAX(sizeof(struct network_msg), sizeof(enum time_status)))))
31+
#define MAX_MSG_SIZE sizeof(struct battery_msg)
3632

3733
BUILD_ASSERT(CONFIG_APP_BATTERY_WATCHDOG_TIMEOUT_SECONDS >
38-
CONFIG_APP_BATTERY_EXEC_TIME_SECONDS_MAX,
39-
"Watchdog timeout must be greater than maximum execution time");
34+
CONFIG_APP_BATTERY_EXEC_TIME_SECONDS_MAX,
35+
"Watchdog timeout must be greater than maximum execution time");
4036

4137
/* nPM1300 register bitmasks */
4238

@@ -50,20 +46,17 @@ BUILD_ASSERT(CONFIG_APP_BATTERY_WATCHDOG_TIMEOUT_SECONDS >
5046
static const struct device *charger = DEVICE_DT_GET(DT_NODELABEL(npm1300_charger));
5147

5248
/* Forward declarations */
53-
static struct s_object s_obj;
5449
static int charger_read_sensors(float *voltage, float *current, float *temp, int32_t *chg_status);
5550
static void sample(int64_t *ref_time);
5651

5752
/* State machine */
5853

5954
/* Defininig the module states.
6055
*
61-
* STATE_INIT: The battery module is initializing and waiting for time to be available.
62-
* STATE_SAMPLING: The battery module is ready to sample upon receiving a trigger.
56+
* STATE_RUNNING: The battery module is initializing and waiting battery percentage to be requested.
6357
*/
6458
enum battery_module_state {
65-
STATE_INIT,
66-
STATE_SAMPLING,
59+
STATE_RUNNING,
6760
};
6861

6962
/* User defined state object.
@@ -84,25 +77,18 @@ struct s_object {
8477
};
8578

8679
/* Forward declarations of state handlers */
87-
static void state_init_entry(void *o);
88-
static void state_init_run(void *o);
89-
static void state_sampling_run(void *o);
80+
static void state_running_entry(void *o);
81+
static void state_running_run(void *o);
9082

9183
static struct s_object battery_state_object;
9284
static const struct smf_state states[] = {
93-
[STATE_INIT] =
94-
SMF_CREATE_STATE(state_init_entry, state_init_run, NULL,
95-
NULL, /* No parent state */
96-
NULL), /* No initial transition */
97-
[STATE_SAMPLING] =
98-
SMF_CREATE_STATE(NULL, state_sampling_run, NULL,
99-
NULL,
100-
NULL),
85+
[STATE_RUNNING] =
86+
SMF_CREATE_STATE(state_running_entry, state_running_run, NULL, NULL, NULL),
10187
};
10288

10389
/* State handlers */
10490

105-
static void state_init_entry(void *o)
91+
static void state_running_entry(void *o)
10692
{
10793
int err;
10894
struct sensor_value value;
@@ -142,30 +128,15 @@ static void state_init_entry(void *o)
142128
}
143129
}
144130

145-
static void state_init_run(void *o)
131+
static void state_running_run(void *o)
146132
{
147133
struct s_object *state_object = o;
148134

149-
if (&TIME_CHAN == state_object->chan) {
150-
enum time_status time_status = MSG_TO_TIME_STATUS(state_object->msg_buf);
135+
if (&BATTERY_CHAN == state_object->chan) {
136+
struct battery_msg msg = MSG_TO_BATTERY_MSG(state_object->msg_buf);
151137

152-
if (time_status == TIME_AVAILABLE) {
153-
LOG_DBG("Time available, sampling can start");
154-
155-
STATE_SET(battery_state_object, STATE_SAMPLING);
156-
}
157-
}
158-
}
159-
160-
static void state_sampling_run(void *o)
161-
{
162-
struct s_object *state_object = o;
163-
164-
if (&TRIGGER_CHAN == state_object->chan) {
165-
enum trigger_type trigger_type = MSG_TO_TRIGGER_TYPE(state_object->msg_buf);
166-
167-
if (trigger_type == TRIGGER_DATA_SAMPLE) {
168-
LOG_DBG("Data sample trigger received, getting battery data");
138+
if (msg.type == BATTERY_PERCENTAGE_SAMPLE_REQUEST) {
139+
LOG_DBG("Battery percentage sample request received, getting battery data");
169140
sample(&state_object->fuel_gauge_ref_time);
170141
}
171142
}
@@ -209,13 +180,6 @@ static void sample(int64_t *ref_time)
209180
float temp;
210181
float state_of_charge;
211182
float delta;
212-
int64_t system_time;
213-
214-
err = date_time_now(&system_time);
215-
if (err) {
216-
LOG_ERR("Failed to convert uptime to unix time, error: %d", err);
217-
return;
218-
}
219183

220184
err = charger_read_sensors(&voltage, &current, &temp, &chg_status);
221185
if (err) {
@@ -235,7 +199,17 @@ static void sample(int64_t *ref_time)
235199
LOG_DBG("State of charge: %f", (double)roundf(state_of_charge));
236200
LOG_DBG("The battery is %s", charging ? "charging" : "not charging");
237201

238-
/* No further use of the battery data is implemented */
202+
struct battery_msg msg = {
203+
.type = BATTERY_PERCENTAGE_SAMPLE_RESPONSE,
204+
.percentage = (double)roundf(state_of_charge)
205+
};
206+
207+
err = zbus_chan_pub(&BATTERY_CHAN, &msg, K_NO_WAIT);
208+
if (err) {
209+
LOG_ERR("zbus_chan_pub, error: %d", err);
210+
SEND_FATAL_ERROR();
211+
return;
212+
}
239213
}
240214

241215
static void task_wdt_callback(int channel_id, void *user_data)
@@ -258,7 +232,7 @@ static void battery_task(void)
258232

259233
task_wdt_id = task_wdt_add(wdt_timeout_ms, task_wdt_callback, (void *)k_current_get());
260234

261-
STATE_SET_INITIAL(battery_state_object, STATE_INIT);
235+
STATE_SET_INITIAL(battery_state_object, STATE_RUNNING);
262236

263237
while (true) {
264238
err = task_wdt_feed(task_wdt_id);
@@ -268,7 +242,10 @@ static void battery_task(void)
268242
return;
269243
}
270244

271-
err = zbus_sub_wait_msg(&battery, &s_obj.chan, s_obj.msg_buf, zbus_wait_ms);
245+
err = zbus_sub_wait_msg(&battery,
246+
&battery_state_object.chan,
247+
battery_state_object.msg_buf,
248+
zbus_wait_ms);
272249
if (err == -ENOMSG) {
273250
continue;
274251
} else if (err) {

app/src/modules/transport/transport.c

+36-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
/* Register log module */
2020
LOG_MODULE_REGISTER(transport, CONFIG_APP_TRANSPORT_LOG_LEVEL);
2121

22+
#define CUSTOM_JSON_APPID_VAL_CONEVAL "CONEVAL"
23+
#define CUSTOM_JSON_APPID_VAL_BATTERY "BATTERY"
2224

2325
BUILD_ASSERT(CONFIG_APP_TRANSPORT_WATCHDOG_TIMEOUT_SECONDS >
2426
CONFIG_APP_TRANSPORT_EXEC_TIME_SECONDS_MAX,
@@ -30,8 +32,9 @@ ZBUS_MSG_SUBSCRIBER_DEFINE(transport);
3032
/* Observe channels */
3133
ZBUS_CHAN_ADD_OBS(PAYLOAD_CHAN, transport, 0);
3234
ZBUS_CHAN_ADD_OBS(NETWORK_CHAN, transport, 0);
35+
ZBUS_CHAN_ADD_OBS(BATTERY_CHAN, transport, 0);
3336

34-
#define MAX_MSG_SIZE (MAX(sizeof(struct payload), sizeof(struct network_msg)))
37+
#define MAX_MSG_SIZE (MAX(sizeof(struct payload), MAX(sizeof(struct network_msg), sizeof(struct battery_msg))))
3538

3639
/* Enumerator to be used in privat transport channel */
3740
enum priv_transport_evt {
@@ -366,7 +369,6 @@ static void state_connected_ready_run(void *o)
366369
{
367370
int err;
368371
struct state_object *state_object = o;
369-
struct network_msg msg = MSG_TO_NETWORK_MSG(state_object->msg_buf);
370372

371373
LOG_DBG("%s", __func__);
372374

@@ -382,6 +384,9 @@ static void state_connected_ready_run(void *o)
382384
}
383385

384386
if (state_object->chan == &NETWORK_CHAN) {
387+
388+
struct network_msg msg = MSG_TO_NETWORK_MSG(state_object->msg_buf);
389+
385390
if (msg.type == NETWORK_DISCONNECTED) {
386391
STATE_SET(transport_state, STATE_CONNECTED_PAUSED);
387392

@@ -396,7 +401,34 @@ static void state_connected_ready_run(void *o)
396401

397402
if (msg.type == NETWORK_QUALITY_SAMPLE_RESPONSE) {
398403

399-
err = nrf_cloud_coap_sensor_send("RSRP", msg.conn_eval_params.rsrp,
404+
err = nrf_cloud_coap_sensor_send(CUSTOM_JSON_APPID_VAL_CONEVAL,
405+
msg.conn_eval_params.energy_estimate,
406+
NRF_CLOUD_NO_TIMESTAMP, true);
407+
if (err) {
408+
LOG_ERR("nrf_cloud_coap_sensor_send, error: %d", err);
409+
SEND_FATAL_ERROR();
410+
}
411+
412+
err = nrf_cloud_coap_sensor_send(NRF_CLOUD_JSON_APPID_VAL_RSRP,
413+
msg.conn_eval_params.rsrp,
414+
NRF_CLOUD_NO_TIMESTAMP, true);
415+
if (err) {
416+
LOG_ERR("nrf_cloud_coap_sensor_send, error: %d", err);
417+
SEND_FATAL_ERROR();
418+
}
419+
420+
return;
421+
}
422+
}
423+
424+
if (state_object->chan == &BATTERY_CHAN) {
425+
426+
struct battery_msg msg = MSG_TO_BATTERY_MSG(state_object->msg_buf);
427+
428+
if (msg.type == BATTERY_PERCENTAGE_SAMPLE_RESPONSE) {
429+
430+
err = nrf_cloud_coap_sensor_send(CUSTOM_JSON_APPID_VAL_BATTERY,
431+
msg.percentage,
400432
NRF_CLOUD_NO_TIMESTAMP, true);
401433
if (err) {
402434
LOG_ERR("nrf_cloud_coap_sensor_send, error: %d", err);
@@ -405,6 +437,7 @@ static void state_connected_ready_run(void *o)
405437

406438
return;
407439
}
440+
408441
}
409442
}
410443

app/src/modules/trigger/trigger.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,22 @@ static struct state_object trigger_state;
6262

6363
static void trigger_send(void)
6464
{
65+
int err;
6566
struct network_msg network_msg = {
6667
.type = NETWORK_QUALITY_SAMPLE_REQUEST,
6768
};
69+
struct battery_msg battery_msg = {
70+
.type = BATTERY_PERCENTAGE_SAMPLE_REQUEST,
71+
};
6872

69-
int err = zbus_chan_pub(&NETWORK_CHAN, &network_msg, K_SECONDS(1));
73+
err = zbus_chan_pub(&NETWORK_CHAN, &network_msg, K_SECONDS(1));
74+
if (err) {
75+
LOG_ERR("zbus_chan_pub, error: %d", err);
76+
SEND_FATAL_ERROR();
77+
return;
78+
}
7079

80+
err = zbus_chan_pub(&BATTERY_CHAN, &battery_msg, K_SECONDS(1));
7181
if (err) {
7282
LOG_ERR("zbus_chan_pub, error: %d", err);
7383
SEND_FATAL_ERROR();

tests/module/battery/CMakeLists.txt

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#
2+
# Copyright (c) 2024 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
project(battery_module_test)
11+
12+
test_runner_generate(src/main.c)
13+
14+
set(ASSET_TRACKER_TEMPLATE_DIR ../../..)
15+
16+
target_sources(app
17+
PRIVATE
18+
src/main.c
19+
src/redef.c
20+
${ASSET_TRACKER_TEMPLATE_DIR}/app/src/modules/battery/battery.c
21+
${ASSET_TRACKER_TEMPLATE_DIR}/app/src/common/message_channel.c
22+
)
23+
24+
target_include_directories(app PRIVATE src)
25+
26+
zephyr_include_directories(${ZEPHYR_BASE}/include/zephyr/)
27+
zephyr_include_directories(${ZEPHYR_NRFXLIB_MODULE_DIR}/nrf_fuel_gauge/include/)
28+
zephyr_include_directories(${ZEPHYR_BASE}/subsys/testsuite/include)
29+
zephyr_include_directories(${ASSET_TRACKER_TEMPLATE_DIR}/app/src/common)
30+
31+
# Options that cannot be passed through Kconfig fragments
32+
target_compile_definitions(app PRIVATE
33+
-DCONFIG_APP_BATTERY_LOG_LEVEL=4
34+
-DCONFIG_APP_BATTERY_THREAD_STACK_SIZE=4096
35+
-DCONFIG_APP_PAYLOAD_CHANNEL_BUFFER_MAX_SIZE=100
36+
-DCONFIG_APP_BATTERY_EXEC_TIME_SECONDS_MAX=3
37+
-DCONFIG_APP_BATTERY_WATCHDOG_TIMEOUT_SECONDS=120
38+
)
39+
40+
set_property(SOURCE ${ASSET_TRACKER_TEMPLATE_DIR}/app/src/modules/battery/battery.c PROPERTY COMPILE_FLAGS
41+
"-include ${CMAKE_CURRENT_SOURCE_DIR}/src/redef.h")

0 commit comments

Comments
 (0)