1 /*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT plantower_pms7003
8
9 /* sensor pms7003.c - Driver for plantower PMS7003 sensor
10 * PMS7003 product: http://www.plantower.com/en/content/?110.html
11 * PMS7003 spec: http://aqicn.org/air/view/sensor/spec/pms7003.pdf
12 */
13
14 #include <errno.h>
15
16 #include <zephyr/arch/cpu.h>
17 #include <zephyr/init.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/drivers/sensor.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <zephyr/drivers/uart.h>
23 #include <zephyr/logging/log.h>
24
25 LOG_MODULE_REGISTER(PMS7003, CONFIG_SENSOR_LOG_LEVEL);
26
27 /* wait serial output with 1000ms timeout */
28 #define CFG_PMS7003_SERIAL_TIMEOUT 1000
29
30 struct pms7003_config {
31 const struct device *uart_dev;
32 };
33
34 struct pms7003_data {
35 uint16_t pm_1_0;
36 uint16_t pm_2_5;
37 uint16_t pm_10;
38 };
39
40 /**
41 * @brief wait for an array data from uart device with a timeout
42 *
43 * @param dev the uart device
44 * @param data the data array to be matched
45 * @param len the data array len
46 * @param timeout the timeout in milliseconds
47 * @return 0 if success; -ETIME if timeout
48 */
uart_wait_for(const struct device * dev,uint8_t * data,int len,int timeout)49 static int uart_wait_for(const struct device *dev, uint8_t *data, int len,
50 int timeout)
51 {
52 int matched_size = 0;
53 int64_t timeout_time = k_uptime_get() + timeout;
54
55 while (1) {
56 uint8_t c;
57
58 if (k_uptime_get() > timeout_time) {
59 return -ETIME;
60 }
61
62 if (uart_poll_in(dev, &c) == 0) {
63 if (c == data[matched_size]) {
64 matched_size++;
65
66 if (matched_size == len) {
67 break;
68 }
69 } else if (c == data[0]) {
70 matched_size = 1;
71 } else {
72 matched_size = 0;
73 }
74 }
75 }
76 return 0;
77 }
78
79 /**
80 * @brief read bytes from uart
81 *
82 * @param data the data buffer
83 * @param len the data len
84 * @param timeout the timeout in milliseconds
85 * @return 0 if success; -ETIME if timeout
86 */
uart_read_bytes(const struct device * dev,uint8_t * data,int len,int timeout)87 static int uart_read_bytes(const struct device *dev, uint8_t *data, int len,
88 int timeout)
89 {
90 int read_size = 0;
91 int64_t timeout_time = k_uptime_get() + timeout;
92
93 while (1) {
94 uint8_t c;
95
96 if (k_uptime_get() > timeout_time) {
97 return -ETIME;
98 }
99
100 if (uart_poll_in(dev, &c) == 0) {
101 data[read_size++] = c;
102 if (read_size == len) {
103 break;
104 }
105 }
106 }
107 return 0;
108 }
109
pms7003_sample_fetch(const struct device * dev,enum sensor_channel chan)110 static int pms7003_sample_fetch(const struct device *dev,
111 enum sensor_channel chan)
112 {
113 struct pms7003_data *drv_data = dev->data;
114 const struct pms7003_config *cfg = dev->config;
115
116 /* sample output */
117 /* 42 4D 00 1C 00 01 00 01 00 01 00 01 00 01 00 01 01 92
118 * 00 4E 00 03 00 00 00 00 00 00 71 00 02 06
119 */
120
121 uint8_t pms7003_start_bytes[] = {0x42, 0x4d};
122 uint8_t pms7003_receive_buffer[30];
123
124 if (uart_wait_for(cfg->uart_dev, pms7003_start_bytes,
125 sizeof(pms7003_start_bytes),
126 CFG_PMS7003_SERIAL_TIMEOUT) < 0) {
127 LOG_WRN("waiting for start bytes is timeout");
128 return -ETIME;
129 }
130
131 if (uart_read_bytes(cfg->uart_dev, pms7003_receive_buffer, 30,
132 CFG_PMS7003_SERIAL_TIMEOUT) < 0) {
133 return -ETIME;
134 }
135
136 drv_data->pm_1_0 =
137 (pms7003_receive_buffer[8] << 8) + pms7003_receive_buffer[9];
138 drv_data->pm_2_5 =
139 (pms7003_receive_buffer[10] << 8) + pms7003_receive_buffer[11];
140 drv_data->pm_10 =
141 (pms7003_receive_buffer[12] << 8) + pms7003_receive_buffer[13];
142
143 LOG_DBG("pm1.0 = %d", drv_data->pm_1_0);
144 LOG_DBG("pm2.5 = %d", drv_data->pm_2_5);
145 LOG_DBG("pm10 = %d", drv_data->pm_10);
146 return 0;
147 }
148
pms7003_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)149 static int pms7003_channel_get(const struct device *dev,
150 enum sensor_channel chan,
151 struct sensor_value *val)
152 {
153 struct pms7003_data *drv_data = dev->data;
154
155 if (chan == SENSOR_CHAN_PM_1_0) {
156 val->val1 = drv_data->pm_1_0;
157 val->val2 = 0;
158 } else if (chan == SENSOR_CHAN_PM_2_5) {
159 val->val1 = drv_data->pm_2_5;
160 val->val2 = 0;
161 } else if (chan == SENSOR_CHAN_PM_10) {
162 val->val1 = drv_data->pm_10;
163 val->val2 = 0;
164 } else {
165 return -ENOTSUP;
166 }
167 return 0;
168 }
169
170 static const struct sensor_driver_api pms7003_api = {
171 .sample_fetch = &pms7003_sample_fetch,
172 .channel_get = &pms7003_channel_get,
173 };
174
pms7003_init(const struct device * dev)175 static int pms7003_init(const struct device *dev)
176 {
177 const struct pms7003_config *cfg = dev->config;
178
179 if (!device_is_ready(cfg->uart_dev)) {
180 LOG_ERR("Bus device is not ready");
181 return -ENODEV;
182 }
183
184 return 0;
185 }
186
187 #define PMS7003_DEFINE(inst) \
188 static struct pms7003_data pms7003_data_##inst; \
189 \
190 static const struct pms7003_config pms7003_config_##inst = { \
191 .uart_dev = DEVICE_DT_GET(DT_INST_BUS(inst)), \
192 }; \
193 \
194 SENSOR_DEVICE_DT_INST_DEFINE(inst, &pms7003_init, NULL, \
195 &pms7003_data_##inst, &pms7003_config_##inst, POST_KERNEL, \
196 CONFIG_SENSOR_INIT_PRIORITY, &pms7003_api); \
197
198 DT_INST_FOREACH_STATUS_OKAY(PMS7003_DEFINE)
199