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