1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "retained.h"
8
9 #include <stdint.h>
10 #include <string.h>
11
12 #include <zephyr/kernel.h>
13 #include <zephyr/devicetree.h>
14 #include <zephyr/drivers/retained_mem.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/sys/crc.h>
17
18 #if DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(retainedmemdevice))
19 const static struct device *retained_mem_device = DEVICE_DT_GET(DT_ALIAS(retainedmemdevice));
20 #else
21 #error "retained_mem region not defined"
22 #endif
23
24 struct retained_data retained;
25
26 #define RETAINED_CRC_OFFSET offsetof(struct retained_data, crc)
27 #define RETAINED_CHECKED_SIZE (RETAINED_CRC_OFFSET + sizeof(retained.crc))
28
retained_validate(void)29 bool retained_validate(void)
30 {
31 int rc;
32
33 rc = retained_mem_read(retained_mem_device, 0, (uint8_t *)&retained, sizeof(retained));
34 __ASSERT_NO_MSG(rc == 0);
35
36 /* The residue of a CRC is what you get from the CRC over the
37 * message catenated with its CRC. This is the post-final-xor
38 * residue for CRC-32 (CRC-32/ISO-HDLC) which Zephyr calls
39 * crc32_ieee.
40 */
41 const uint32_t residue = 0x2144df1c;
42 uint32_t crc = crc32_ieee((const uint8_t *)&retained,
43 RETAINED_CHECKED_SIZE);
44 bool valid = (crc == residue);
45
46 /* If the CRC isn't valid, reset the retained data. */
47 if (!valid) {
48 memset(&retained, 0, sizeof(retained));
49 }
50
51 /* Reset to accrue runtime from this session. */
52 retained.uptime_latest = 0;
53
54 return valid;
55 }
56
retained_update(void)57 void retained_update(void)
58 {
59 int rc;
60
61 uint64_t now = k_uptime_ticks();
62
63 retained.uptime_sum += (now - retained.uptime_latest);
64 retained.uptime_latest = now;
65
66 uint32_t crc = crc32_ieee((const uint8_t *)&retained,
67 RETAINED_CRC_OFFSET);
68
69 retained.crc = sys_cpu_to_le32(crc);
70
71 rc = retained_mem_write(retained_mem_device, 0, (uint8_t *)&retained, sizeof(retained));
72 __ASSERT_NO_MSG(rc == 0);
73 }
74