1 /*
2  * Copyright (c) 2019 Peter Bigot Consulting, LLC
3  * Copyright (c) 2016 Intel Corporation.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <stdio.h>
12 
13 #define UCEL_PER_CEL 1000000
14 #define UCEL_PER_MCEL 1000
15 #define TEMP_INITIAL_CEL 25
16 #define TEMP_WINDOW_HALF_UCEL 500000
17 
now_str(void)18 static const char *now_str(void)
19 {
20 	static char buf[16]; /* ...HH:MM:SS.MMM */
21 	uint32_t now = k_uptime_get_32();
22 	unsigned int ms = now % MSEC_PER_SEC;
23 	unsigned int s;
24 	unsigned int min;
25 	unsigned int h;
26 
27 	now /= MSEC_PER_SEC;
28 	s = now % 60U;
29 	now /= 60U;
30 	min = now % 60U;
31 	now /= 60U;
32 	h = now;
33 
34 	snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u",
35 		 h, min, s, ms);
36 	return buf;
37 }
38 
39 #ifdef CONFIG_MCP9808_TRIGGER
40 
41 static struct sensor_trigger sensor_trig;
42 
set_window(const struct device * dev,const struct sensor_value * temp)43 static int set_window(const struct device *dev,
44 		      const struct sensor_value *temp)
45 {
46 	const int temp_ucel = temp->val1 * UCEL_PER_CEL + temp->val2;
47 	const int low_ucel = temp_ucel - TEMP_WINDOW_HALF_UCEL;
48 	const int high_ucel = temp_ucel + TEMP_WINDOW_HALF_UCEL;
49 	struct sensor_value val = {
50 		.val1 = low_ucel / UCEL_PER_CEL,
51 		.val2 = low_ucel % UCEL_PER_CEL,
52 	};
53 	int rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP,
54 				 SENSOR_ATTR_LOWER_THRESH, &val);
55 	if (rc == 0) {
56 		val.val1 = high_ucel / UCEL_PER_CEL,
57 		val.val2 = high_ucel % UCEL_PER_CEL,
58 		rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP,
59 				     SENSOR_ATTR_UPPER_THRESH, &val);
60 	}
61 
62 	if (rc == 0) {
63 		printf("Alert on temp outside [%d, %d] milli-Celsius\n",
64 		       low_ucel / UCEL_PER_MCEL,
65 		       high_ucel / UCEL_PER_MCEL);
66 	}
67 
68 	return rc;
69 }
70 
set_window_ucel(const struct device * dev,int temp_ucel)71 static inline int set_window_ucel(const struct device *dev,
72 				  int temp_ucel)
73 {
74 	struct sensor_value val = {
75 		.val1 = temp_ucel / UCEL_PER_CEL,
76 		.val2 = temp_ucel % UCEL_PER_CEL,
77 	};
78 
79 	return set_window(dev, &val);
80 }
81 
trigger_handler(const struct device * dev,const struct sensor_trigger * trig)82 static void trigger_handler(const struct device *dev,
83 			    const struct sensor_trigger *trig)
84 {
85 	struct sensor_value temp;
86 	static size_t cnt;
87 	int rc;
88 
89 	++cnt;
90 	rc = sensor_sample_fetch(dev);
91 	if (rc != 0) {
92 		printf("sensor_sample_fetch error: %d\n", rc);
93 		return;
94 	}
95 	rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
96 	if (rc != 0) {
97 		printf("sensor_channel_get error: %d\n", rc);
98 		return;
99 	}
100 
101 	printf("trigger fired %u, temp %g deg C\n", cnt,
102 	       sensor_value_to_double(&temp));
103 	set_window(dev, &temp);
104 }
105 #endif
106 
main(void)107 int main(void)
108 {
109 	const struct device *const dev = DEVICE_DT_GET_ANY(microchip_mcp9808);
110 	int rc;
111 
112 	if (dev == NULL) {
113 		printf("Device not found.\n");
114 		return 0;
115 	}
116 	if (!device_is_ready(dev)) {
117 		printf("Device %s is not ready.\n", dev->name);
118 		return 0;
119 	}
120 
121 #ifdef CONFIG_MCP9808_TRIGGER
122 	rc = set_window_ucel(dev, TEMP_INITIAL_CEL * UCEL_PER_CEL);
123 	if (rc == 0) {
124 		sensor_trig.type = SENSOR_TRIG_THRESHOLD;
125 		sensor_trig.chan = SENSOR_CHAN_AMBIENT_TEMP;
126 		rc = sensor_trigger_set(dev, &sensor_trig, trigger_handler);
127 	}
128 
129 	if (rc != 0) {
130 		printf("Trigger set failed: %d\n", rc);
131 		return 0;
132 	}
133 	printk("Trigger set got %d\n", rc);
134 #endif
135 
136 	while (1) {
137 		struct sensor_value temp;
138 
139 		rc = sensor_sample_fetch(dev);
140 		if (rc != 0) {
141 			printf("sensor_sample_fetch error: %d\n", rc);
142 			break;
143 		}
144 
145 		rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
146 		if (rc != 0) {
147 			printf("sensor_channel_get error: %d\n", rc);
148 			break;
149 		}
150 
151 		printf("%s: %g C\n", now_str(),
152 		       sensor_value_to_double(&temp));
153 
154 		k_sleep(K_SECONDS(2));
155 	}
156 	return 0;
157 }
158