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