1 /*
2  * Copyright (c) 2018 Analog Devices Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/sensor.h>
10 #include <stdio.h>
11 #include <zephyr/sys/__assert.h>
12 
13 #define DELAY_WITH_TRIGGER K_SECONDS(5)
14 #define DELAY_WITHOUT_TRIGGER K_SECONDS(1)
15 
16 #define UCEL_PER_CEL 1000000
17 #define UCEL_PER_MCEL 1000
18 #define TEMP_INITIAL_CEL 21
19 #define TEMP_WINDOW_HALF_UCEL 500000
20 
21 K_SEM_DEFINE(sem, 0, 1);
now_str(void)22 static const char *now_str(void)
23 {
24 	static char buf[16]; /* ...HH:MM:SS.MMM */
25 	uint32_t now = k_uptime_get_32();
26 	unsigned int ms = now % MSEC_PER_SEC;
27 	unsigned int s;
28 	unsigned int min;
29 	unsigned int h;
30 
31 	now /= MSEC_PER_SEC;
32 	s = now % 60U;
33 	now /= 60U;
34 	min = now % 60U;
35 	now /= 60U;
36 	h = now;
37 
38 	snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u",
39 		 h, min, s, ms);
40 	return buf;
41 }
trigger_handler(const struct device * dev,const struct sensor_trigger * trigger)42 static void trigger_handler(const struct device *dev,
43 			    const struct sensor_trigger *trigger)
44 {
45 	k_sem_give(&sem);
46 }
47 
48 static int low_ucel;
49 static int high_ucel;
50 
sensor_set_attribute(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,int value)51 static int sensor_set_attribute(const struct device *dev,
52 				enum sensor_channel chan,
53 				enum sensor_attribute attr, int value)
54 {
55 	struct sensor_value sensor_val;
56 	int ret;
57 
58 	sensor_val.val1 = value / UCEL_PER_CEL;
59 	sensor_val.val2 = value % UCEL_PER_CEL;
60 
61 	ret = sensor_attr_set(dev, chan, attr, &sensor_val);
62 	if (ret) {
63 		printf("sensor_attr_set failed ret %d\n", ret);
64 	}
65 
66 	return ret;
67 }
68 
temp_in_window(const struct sensor_value * val)69 static bool temp_in_window(const struct sensor_value *val)
70 {
71 	int temp_ucel = val->val1 * UCEL_PER_CEL + val->val2;
72 
73 	return (temp_ucel >= low_ucel) && (temp_ucel <= high_ucel);
74 }
75 
sensor_set_window(const struct device * dev,const struct sensor_value * val)76 static int sensor_set_window(const struct device *dev,
77 			     const struct sensor_value *val)
78 {
79 	int temp_ucel = val->val1 * UCEL_PER_CEL + val->val2;
80 
81 	low_ucel = temp_ucel - TEMP_WINDOW_HALF_UCEL;
82 	high_ucel = temp_ucel + TEMP_WINDOW_HALF_UCEL;
83 
84 	int rc = sensor_set_attribute(dev, SENSOR_CHAN_AMBIENT_TEMP,
85 				      SENSOR_ATTR_UPPER_THRESH, high_ucel);
86 
87 	if (rc == 0) {
88 		sensor_set_attribute(dev, SENSOR_CHAN_AMBIENT_TEMP,
89 				     SENSOR_ATTR_LOWER_THRESH, low_ucel);
90 	}
91 
92 	if (rc == 0) {
93 		printk("Alert on temp outside [%d, %d] mCel\n",
94 		       low_ucel / UCEL_PER_MCEL,
95 		       high_ucel / UCEL_PER_MCEL);
96 	}
97 
98 	return rc;
99 }
100 
process(const struct device * dev)101 static void process(const struct device *dev)
102 {
103 	struct sensor_value temp_val;
104 	int ret;
105 	bool reset_window = false;
106 
107 	/* Set update rate to 240 mHz */
108 	sensor_set_attribute(dev, SENSOR_CHAN_AMBIENT_TEMP,
109 			     SENSOR_ATTR_SAMPLING_FREQUENCY, 240 * 1000);
110 
111 	if (IS_ENABLED(CONFIG_ADT7420_TRIGGER)) {
112 		struct sensor_trigger trig = {
113 			.type = SENSOR_TRIG_THRESHOLD,
114 			.chan = SENSOR_CHAN_AMBIENT_TEMP,
115 		};
116 		struct sensor_value val = {
117 			.val1 = TEMP_INITIAL_CEL,
118 		};
119 
120 		ret = sensor_set_window(dev, &val);
121 		if (ret == 0) {
122 			ret = sensor_trigger_set(dev, &trig, trigger_handler);
123 		}
124 		if (ret != 0) {
125 			printf("Could not set trigger\n");
126 			return;
127 		}
128 	}
129 
130 	while (1) {
131 		ret = sensor_sample_fetch(dev);
132 		if (ret) {
133 			printf("sensor_sample_fetch failed ret %d\n", ret);
134 			return;
135 		}
136 
137 		ret = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP,
138 					 &temp_val);
139 		if (ret) {
140 			printf("sensor_channel_get failed ret %d\n", ret);
141 			return;
142 		}
143 
144 		if (IS_ENABLED(CONFIG_ADT7420_TRIGGER)) {
145 			reset_window |= !temp_in_window(&temp_val);
146 		}
147 
148 		printf("[%s]: temperature %.6f Cel%s\n", now_str(),
149 		       sensor_value_to_double(&temp_val),
150 		       reset_window ? ": NEED RESET" : "");
151 
152 
153 		if (IS_ENABLED(CONFIG_ADT7420_TRIGGER)) {
154 			if (reset_window) {
155 				ret = sensor_set_window(dev, &temp_val);
156 			}
157 			if (ret) {
158 				printf("Window update failed ret %d\n", ret);
159 				return;
160 			}
161 
162 			printk("Wait for trigger...");
163 			ret = k_sem_take(&sem, DELAY_WITH_TRIGGER);
164 			reset_window = (ret == 0);
165 			printk("%s\n", reset_window ? "ALERTED!" : "timed-out");
166 		} else {
167 			k_sleep(DELAY_WITHOUT_TRIGGER);
168 		}
169 	}
170 }
171 
main(void)172 int main(void)
173 {
174 	const struct device *const dev = DEVICE_DT_GET_ONE(adi_adt7420);
175 
176 	if (!device_is_ready(dev)) {
177 		printk("sensor: device not ready.\n");
178 		return 0;
179 	}
180 
181 	printf("device is %p, name is %s\n", dev, dev->name);
182 
183 	process(dev);
184 	return 0;
185 }
186