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);