1 /*
2 * Copyright (c) 2018 Peter Bigot Consulting, LLC
3 * Copyright (c) 2018 Linaro Ltd.
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 <zephyr/sys/printk.h>
12 #include <zephyr/drivers/sensor/ccs811.h>
13 #include <stdio.h>
14
15 static bool app_fw_2;
16
now_str(void)17 static const char *now_str(void)
18 {
19 static char buf[16]; /* ...HH:MM:SS.MMM */
20 uint32_t now = k_uptime_get_32();
21 unsigned int ms = now % MSEC_PER_SEC;
22 unsigned int s;
23 unsigned int min;
24 unsigned int h;
25
26 now /= MSEC_PER_SEC;
27 s = now % 60U;
28 now /= 60U;
29 min = now % 60U;
30 now /= 60U;
31 h = now;
32
33 snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u",
34 h, min, s, ms);
35 return buf;
36 }
37
do_fetch(const struct device * dev)38 static int do_fetch(const struct device *dev)
39 {
40 struct sensor_value co2, tvoc, voltage, current;
41 int rc = 0;
42 int baseline = -1;
43
44 #ifdef CONFIG_APP_MONITOR_BASELINE
45 rc = ccs811_baseline_fetch(dev);
46 if (rc >= 0) {
47 baseline = rc;
48 rc = 0;
49 }
50 #endif
51 if (rc == 0) {
52 rc = sensor_sample_fetch(dev);
53 }
54 if (rc == 0) {
55 const struct ccs811_result_type *rp = ccs811_result(dev);
56
57 sensor_channel_get(dev, SENSOR_CHAN_CO2, &co2);
58 sensor_channel_get(dev, SENSOR_CHAN_VOC, &tvoc);
59 sensor_channel_get(dev, SENSOR_CHAN_VOLTAGE, &voltage);
60 sensor_channel_get(dev, SENSOR_CHAN_CURRENT, ¤t);
61 printk("\n[%s]: CCS811: %u ppm eCO2; %u ppb eTVOC\n",
62 now_str(), co2.val1, tvoc.val1);
63 printk("Voltage: %d.%06dV; Current: %d.%06dA\n", voltage.val1,
64 voltage.val2, current.val1, current.val2);
65 #ifdef CONFIG_APP_MONITOR_BASELINE
66 printk("BASELINE %04x\n", baseline);
67 #endif
68 if (app_fw_2 && !(rp->status & CCS811_STATUS_DATA_READY)) {
69 printk("STALE DATA\n");
70 }
71
72 if (rp->status & CCS811_STATUS_ERROR) {
73 printk("ERROR: %02x\n", rp->error);
74 }
75 }
76 return rc;
77 }
78
79 #ifndef CONFIG_CCS811_TRIGGER_NONE
80
trigger_handler(const struct device * dev,const struct sensor_trigger * trig)81 static void trigger_handler(const struct device *dev,
82 const struct sensor_trigger *trig)
83 {
84 int rc = do_fetch(dev);
85
86 if (rc == 0) {
87 printk("Triggered fetch got %d\n", rc);
88 } else if (-EAGAIN == rc) {
89 printk("Triggered fetch got stale data\n");
90 } else {
91 printk("Triggered fetch failed: %d\n", rc);
92 }
93 }
94
95 #endif /* !CONFIG_CCS811_TRIGGER_NONE */
96
do_main(const struct device * dev)97 static void do_main(const struct device *dev)
98 {
99 while (true) {
100 int rc = do_fetch(dev);
101
102 if (rc == 0) {
103 printk("Timed fetch got %d\n", rc);
104 } else if (-EAGAIN == rc) {
105 printk("Timed fetch got stale data\n");
106 } else {
107 printk("Timed fetch failed: %d\n", rc);
108 break;
109 }
110 k_msleep(1000);
111 }
112 }
113
main(void)114 int main(void)
115 {
116 const struct device *const dev = DEVICE_DT_GET_ONE(ams_ccs811);
117 struct ccs811_configver_type cfgver;
118 int rc;
119
120 if (!device_is_ready(dev)) {
121 printk("Device %s is not ready\n", dev->name);
122 return 0;
123 }
124
125 printk("device is %p, name is %s\n", dev, dev->name);
126
127 rc = ccs811_configver_fetch(dev, &cfgver);
128 if (rc == 0) {
129 printk("HW %02x; FW Boot %04x App %04x ; mode %02x\n",
130 cfgver.hw_version, cfgver.fw_boot_version,
131 cfgver.fw_app_version, cfgver.mode);
132 app_fw_2 = (cfgver.fw_app_version >> 8) > 0x11;
133 }
134
135 #ifdef CONFIG_APP_USE_ENVDATA
136 struct sensor_value temp = { CONFIG_APP_ENV_TEMPERATURE };
137 struct sensor_value humidity = { CONFIG_APP_ENV_HUMIDITY };
138
139 rc = ccs811_envdata_update(dev, &temp, &humidity);
140 printk("ENV_DATA set for %d Cel, %d %%RH got %d\n",
141 temp.val1, humidity.val1, rc);
142 #endif
143
144 #ifdef CONFIG_CCS811_TRIGGER
145 struct sensor_trigger trig = { 0 };
146
147 #ifdef CONFIG_APP_TRIGGER_ON_THRESHOLD
148 printk("Triggering on threshold:\n");
149 if (rc == 0) {
150 struct sensor_value thr = {
151 .val1 = CONFIG_APP_CO2_MEDIUM_PPM,
152 };
153 rc = sensor_attr_set(dev, SENSOR_CHAN_CO2,
154 SENSOR_ATTR_LOWER_THRESH,
155 &thr);
156 printk("L/M threshold to %d got %d\n", thr.val1, rc);
157 }
158 if (rc == 0) {
159 struct sensor_value thr = {
160 .val1 = CONFIG_APP_CO2_HIGH_PPM,
161 };
162 rc = sensor_attr_set(dev, SENSOR_CHAN_CO2,
163 SENSOR_ATTR_UPPER_THRESH,
164 &thr);
165 printk("M/H threshold to %d got %d\n", thr.val1, rc);
166 }
167 trig.type = SENSOR_TRIG_THRESHOLD;
168 trig.chan = SENSOR_CHAN_CO2;
169 #elif defined(CONFIG_APP_TRIGGER_ON_DATAREADY)
170 printk("Triggering on data ready\n");
171 trig.type = SENSOR_TRIG_DATA_READY;
172 trig.chan = SENSOR_CHAN_ALL;
173 #else
174 #error Unhandled trigger on
175 #endif
176 if (rc == 0) {
177 rc = sensor_trigger_set(dev, &trig, trigger_handler);
178 }
179 if (rc == 0) {
180 #ifdef CONFIG_APP_TRIGGER_ON_DATAREADY
181 while (true) {
182 k_sleep(K_FOREVER);
183 }
184 #endif
185 }
186 printk("Trigger installation got: %d\n", rc);
187 #endif /* CONFIG_CCS811_TRIGGER */
188 if (rc == 0) {
189 do_main(dev);
190 }
191 return 0;
192 }
193