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