1 /*
2 * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3 *
4 *
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "aos/kernel.h"
11 #include "sensor_drv_api.h"
12 #include "sensor_hal.h"
13
14
15 #define CCS811_I2C_ADDR1 (0x5A) /* When ADDR is high the 7bit I2C address is 0x5B */
16 #define CCS811_I2C_ADDR_TRANS(n) ((n)<<1)
17 #define CCS811_I2C_ADDR CCS811_I2C_ADDR_TRANS(CCS811_I2C_ADDR1)
18
19 /**
20 * @brief CCS811 API Constants
21 */
22 #define CCS811_REG_STATUS 0x00
23 #define CCS811_REG_MEAS_MODE 0x01
24 #define CCS811_REG_ALG_RESULT_DATA 0x02
25 #define CCS811_REG_RAW_DATA 0x03
26 #define CCS811_REG_ALG_CONFIG_DATA 0x04
27 #define CCS811_REG_ENVIRONMENT_DATA 0x05
28 #define CCS811_REG_THRESHOLDS 0x10
29 #define CCS811_CHIP_ID_REG 0x20
30 #define CCS811_HW_VERSION 0x21
31 #define CCS811_FW_BOOT_VERSION 0x23
32 #define CCS811_FW_APP_VERSION 0x24
33 #define CCS811_ERROR_ID 0xE0
34 #define CCS811_RST_REG 0xFF
35
36 #define CCS811_APP_ERASE 0xF1
37 #define CCS811_APP_DATE 0xF2
38 #define CCS811_APP_VERIFY 0xF3
39 #define CCS811_APP_START 0xF4
40
41 #define CCS811_CHIP_ID_VAL 0x81
42
43 #define CCS811_MEASUREMENT_MODE_IDLE 0x00
44 #define CCS811_MEASUREMENT_MODE_VOC_1S 0x10
45 #define CCS811_MEASUREMENT_MODE_VOC_10S 0x20
46 #define CCS811_MEASUREMENT_MODE_VOC_60S 0x30
47
48 #define CCS811_VOC_DATA_SIZE 8
49 #define CCS811_CMD_LENGTH 1
50 #define CCS811_REG_LENGTH 1
51 #define CCS811_DATA_LENGTH 2
52 #define CCS811_RESET_LENGTH 4
53
54
55 #define CCS811_DATA_READ_MIN_INTERVAL 1000 /* in millisecond */
56
57 typedef struct {
58 uint16_t eCO2;
59 uint16_t voc;
60 uint16_t adc;
61 uint16_t current;
62 uint32_t resistance;
63 } ccs811_measurement_t;
64
65 ccs811_measurement_t g_ccs811_data = {0};
66
67 i2c_dev_t ccs811_ctx = {
68 .port = 3,
69 .config.address_width = 8,
70 .config.freq = 100000,
71 .config.dev_addr = CCS811_I2C_ADDR,
72 };
73
drv_voc_ams_ccs811_validate_id(i2c_dev_t * drv,uint8_t id_value)74 static int drv_voc_ams_ccs811_validate_id(i2c_dev_t* drv, uint8_t id_value)
75 {
76 int ret = 0;
77 uint8_t value = 0;
78
79 if(drv == NULL){
80 return -1;
81 }
82
83 ret = sensor_i2c_read(drv, CCS811_CHIP_ID_REG, &value, CCS811_CMD_LENGTH, I2C_OP_RETRIES);
84 if(unlikely(ret)){
85 return ret;
86 }
87
88 if (id_value != value){
89 return -1;
90 }
91 return 0;
92 }
93
94
drv_voc_ams_ccs811_soft_reset(i2c_dev_t * drv)95 UNUSED static int drv_voc_ams_ccs811_soft_reset(i2c_dev_t* drv)
96 {
97 int ret = 0;
98 uint8_t data[4];
99
100 data[0] = 0x11;
101 data[1] = 0xE5;
102 data[2] = 0x72;
103 data[3] = 0x8A;
104
105 ret = sensor_i2c_write(drv,CCS811_RST_REG,
106 &data[0],CCS811_RESET_LENGTH,I2C_OP_RETRIES);
107 if(unlikely(ret)){
108 return ret;
109 }
110
111 return ret;
112 }
113
drv_voc_ams_ccs811_app_start(i2c_dev_t * drv)114 static int drv_voc_ams_ccs811_app_start(i2c_dev_t* drv)
115 {
116 int ret = 0;
117 uint8_t value;
118
119 ret = sensor_i2c_read(&ccs811_ctx, CCS811_REG_STATUS, &value, CCS811_CMD_LENGTH, I2C_OP_RETRIES);
120 if(unlikely(ret)){
121 return ret;
122 }
123
124 aos_msleep(2);
125
126 value = CCS811_APP_START;
127 ret = hal_i2c_master_send(&ccs811_ctx, CCS811_I2C_ADDR, &value, CCS811_CMD_LENGTH, AOS_WAIT_FOREVER);
128 if(unlikely(ret)){
129 return ret;
130 }
131
132 aos_msleep(250);
133
134 return 0;
135 }
136
drv_voc_ams_ccs811_set_power_mode(i2c_dev_t * drv,dev_power_mode_e mode)137 static int drv_voc_ams_ccs811_set_power_mode(i2c_dev_t* drv, dev_power_mode_e mode)
138 {
139 int ret = 0;
140 uint8_t value = 0x00;
141
142
143 switch(mode){
144 case DEV_POWER_OFF:
145 case DEV_SLEEP:{
146 value = CCS811_MEASUREMENT_MODE_IDLE;
147 ret = sensor_i2c_write(&ccs811_ctx, CCS811_REG_MEAS_MODE, &value, CCS811_CMD_LENGTH, I2C_OP_RETRIES);
148 if(unlikely(ret)){
149 return ret;
150 }
151 }break;
152 case DEV_POWER_ON:{
153 value = CCS811_MEASUREMENT_MODE_VOC_1S;
154 ret = sensor_i2c_write(&ccs811_ctx, CCS811_REG_MEAS_MODE, &value, CCS811_CMD_LENGTH, I2C_OP_RETRIES);
155 if(unlikely(ret)){
156 return ret;
157 }
158 }break;
159
160 default:break;
161 }
162 return 0;
163 }
164
drv_voc_ams_ccs811_set_default_config(i2c_dev_t * drv)165 static int drv_voc_ams_ccs811_set_default_config(i2c_dev_t* drv)
166 {
167 int ret = 0;
168 uint8_t value = 0x00;
169
170 ret = sensor_i2c_read(&ccs811_ctx, CCS811_REG_STATUS, &value, CCS811_CMD_LENGTH, I2C_OP_RETRIES);
171 if(unlikely(ret)){
172 return ret;
173 }
174
175 ret = drv_voc_ams_ccs811_set_power_mode(&ccs811_ctx, DEV_SLEEP);
176 if(unlikely(ret)){
177 return ret;
178 }
179
180 return 0;
181
182 }
183
drv_voc_ams_ccs811_set_work_mode(i2c_dev_t * drv,uint8_t mode)184 UNUSED static int drv_voc_ams_ccs811_set_work_mode(i2c_dev_t* drv,uint8_t mode)
185 {
186 uint8_t ret = 0;
187 uint8_t value = 0;
188
189 ret = sensor_i2c_read(&ccs811_ctx, CCS811_REG_STATUS, &value, I2C_DATA_LEN, I2C_OP_RETRIES);
190 if(unlikely(ret)){
191 return ret;
192 }
193
194 value = mode;
195
196 ret = sensor_i2c_write(&ccs811_ctx, CCS811_REG_MEAS_MODE, &value, I2C_DATA_LEN, I2C_OP_RETRIES);
197 if(unlikely(ret)){
198 return ret;
199 }
200
201 return 0;
202 }
203
204
drv_voc_ams_ccs811_irq_handle(void)205 static void drv_voc_ams_ccs811_irq_handle(void)
206 {
207 /* no handle so far */
208 }
209
drv_voc_ams_ccs811_open(void)210 static int drv_voc_ams_ccs811_open(void)
211 {
212 int ret = 0;
213 uint8_t value = 0x00;
214
215 ret = sensor_i2c_read(&ccs811_ctx, CCS811_REG_STATUS, &value, I2C_DATA_LEN, I2C_OP_RETRIES);
216 if(unlikely(ret)){
217 return -1;
218 }
219
220 ret = drv_voc_ams_ccs811_set_power_mode(&ccs811_ctx, DEV_POWER_ON);
221 if(unlikely(ret)){
222 return -1;
223 }
224
225 LOG("%s %s successfully \n", SENSOR_STR, __func__);
226 return 0;
227 }
228
drv_voc_ams_ccs811_close(void)229 static int drv_voc_ams_ccs811_close(void)
230 {
231 int ret = 0;
232 uint8_t value = 0x00;
233
234 ret = sensor_i2c_read(&ccs811_ctx, CCS811_REG_STATUS, &value, I2C_DATA_LEN, I2C_OP_RETRIES);
235 if(unlikely(ret)){
236 return 0;
237 }
238
239 ret = drv_voc_ams_ccs811_set_power_mode(&ccs811_ctx, DEV_SLEEP);
240 if(unlikely(ret)){
241 return 0;
242 }
243
244 LOG("%s %s successfully \n", SENSOR_STR, __func__);
245 return 0;
246 }
247
drv_voc_ams_ccs811_read(void * buf,size_t len)248 static int drv_voc_ams_ccs811_read(void *buf, size_t len)
249 {
250 int ret = 0;
251 size_t size = 0;
252 uint8_t buffer[8];
253 uint16_t data[2];
254 integer_data_t* pdata = (integer_data_t*)buf;
255
256 if(buf == NULL){
257 return -1;
258 }
259
260 size = sizeof(integer_data_t);
261 if(len < size){
262 return -1;
263 }
264
265 ret = sensor_i2c_read(&ccs811_ctx, CCS811_REG_ALG_RESULT_DATA, buffer, 8, I2C_OP_RETRIES);
266
267 data[0] = (uint16_t)(buffer[0] << 8) | (uint16_t)(buffer[1] << 0);
268 data[1] = (uint16_t)(buffer[2] << 8) | (uint16_t)(buffer[3] << 0);
269
270 if(unlikely(ret)){
271 return -1;
272 }
273
274 if (data[1] > 32768)
275 data[1] = 32768;
276
277 pdata->data = data[1];
278 pdata->timestamp = aos_now_ms();
279
280 return (int)size;
281 }
282
drv_voc_ams_ccs811_write(const void * buf,size_t len)283 static int drv_voc_ams_ccs811_write(const void *buf, size_t len)
284 {
285 return 0;
286 }
287
drv_voc_ams_ccs811_ioctl(int cmd,unsigned long arg)288 static int drv_voc_ams_ccs811_ioctl(int cmd, unsigned long arg)
289 {
290 int ret = 0;
291
292 switch(cmd){
293 case SENSOR_IOCTL_SET_POWER:{
294 ret = drv_voc_ams_ccs811_set_power_mode(&ccs811_ctx, arg);
295 if(unlikely(ret)){
296 return -1;
297 }
298 }break;
299 case SENSOR_IOCTL_GET_INFO:{
300 /* fill the dev info here */
301 dev_sensor_info_t *info = (dev_sensor_info_t *)arg;
302 info->model = "CCS811";
303 info->range_max = 32768;
304 info->range_min = 0;
305 //info->unit = ppb;
306
307 }break;
308
309 default:break;
310 }
311 LOG("%s %s successfully \n", SENSOR_STR, __func__);
312 return 0;
313 }
314
drv_voc_ams_ccs811_init(void)315 int drv_voc_ams_ccs811_init(void)
316 {
317 int ret = 0;
318 sensor_obj_t sensor;
319
320 memset(&sensor, 0, sizeof(sensor));
321 /* fill the sensor obj parameters here */
322 sensor.tag = TAG_DEV_TVOC;
323 sensor.path = dev_tvoc_path;
324 sensor.io_port = I2C_PORT;
325 sensor.open = drv_voc_ams_ccs811_open;
326 sensor.close = drv_voc_ams_ccs811_close;
327 sensor.read = drv_voc_ams_ccs811_read;
328 sensor.write = drv_voc_ams_ccs811_write;
329 sensor.ioctl = drv_voc_ams_ccs811_ioctl;
330 sensor.irq_handle = drv_voc_ams_ccs811_irq_handle;
331
332
333 ret = sensor_create_obj(&sensor);
334 if(unlikely(ret)){
335 return -1;
336 }
337
338 ret = drv_voc_ams_ccs811_validate_id(&ccs811_ctx, CCS811_CHIP_ID_VAL);
339 if(unlikely(ret)){
340 return -1;
341 }
342
343 /*
344 ret = drv_voc_ams_ccs811_soft_reset(&ccs811_ctx);
345 if(unlikely(ret)){
346 return -1;
347 }
348 */
349
350 ret = drv_voc_ams_ccs811_app_start(&ccs811_ctx);
351 if(unlikely(ret)){
352 return -1;
353 }
354
355 ret = drv_voc_ams_ccs811_set_default_config(&ccs811_ctx);
356 if(unlikely(ret)){
357 return -1;
358 }
359
360 LOG("%s %s successfully \n", SENSOR_STR, __func__);
361 return 0;
362 }
363
364 SENSOR_DRV_ADD(drv_voc_ams_ccs811_init);