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 ENS210_I2C_ADDR1            (0x43)
16 #define ENS210_I2C_ADDR_TRANS(n)    ((n)<<1)
17 #define ENS210_I2C_ADDR             ENS210_I2C_ADDR_TRANS(ENS210_I2C_ADDR1)
18 
19 /**
20 * @brief ENS210 API Constants
21 */
22 /* Register address */
23 #define ENS210_REG_PART_ID                      0x00
24 #define ENS210_REG_UID                          0x04
25 #define ENS210_REG_SYS_CTRL                     0x10
26 #define ENS210_REG_SYS_STAT                     0x11
27 #define ENS210_REG_SENS_RUN                     0x21
28 #define ENS210_REG_SENS_START                   0x22
29 #define ENS210_REG_SENS_STOP                    0x23
30 #define ENS210_REG_SENS_STAT                    0x24
31 #define ENS210_REG_T_VAL                        0x30
32 #define ENS210_REG_H_VAL                        0x33
33 
34 /** Mask to extract 16-bit data from raw T and H values */
35 #define ENS210_T_H_MASK                         0xFFFFU
36 
37 /** Simplification macro, implementing integer division with simple rounding to closest number
38  *  It supports both positive and negative numbers, but ONLY positive divisors */
39 #define IDIV(n,d)                               ((n)>0 ? ((n)+(d)/2)/(d) : ((n)-(d)/2)/(d))
40 
41 #define CRC7WIDTH                               7       //7 bits CRC has polynomial of 7th order (has 8 terms)
42 #define CRC7POLY                                0x89    //The 8 coefficients of the polynomial
43 #define CRC7IVEC                                0x7F    //Initial vector has all 7 bits high
44 
45 #define DATA7WIDTH                              17
46 #define DATA7MASK                               ((1UL << DATA7WIDTH) - 1)     //0b 1 1111 1111 1111 1111
47 #define DATA7MSB                                (1UL << (DATA7WIDTH - 1))     //0b 1 0000 0000 0000 0000
48 #define I2C_RESULT_OK          					0
49 #define ENS210_RESET_WAIT_TIME_MS               2
50 #define ENS210_ADDRESS 							67 //Address of the ENS210
51 #define WaitMsec 								delay
52 
53 /*****************************************************************************
54  * Types/enumerations/variables
55  ****************************************************************************/
56 
57 /** ENS210 T and H conversion time in milliseconds. Refer to ENS210 data sheet for timing information. */
58 #define ENS210_T_H_CONVERSION_TIME_MS           130
59 
60 /** ENS210 T conversion time in milliseconds */
61 #define ENS210_T_CONVERSION_TIME_MS             105
62 
63 /** ENS210 Booting time in milliseconds. */
64 #define ENS210_BOOTING_TIME_MS                  1
65 
66 
67 /** ENS210 SysCtrl register: Low power enable */
68 #define ENS210_SYSCTRL_LOWPOWER_ENABLE          (1 << 0)
69 /** ENS210 SysCtrl register: Low power disable */
70 #define ENS210_SYSCTRL_LOWPOWER_DISABLE         (0 << 0)
71 /** ENS210 SysCtrl register: Reset enable */
72 #define ENS210_SYSCTRL_RESET_ENABLE             (1 << 7)
73 /** ENS210 SysCtrl register: Reset disable */
74 #define ENS210_SYSCTRL_RESET_DISABLE            (0 << 7)
75 
76 /** ENS210 SysStat register: Standby or Booting mode */
77 #define ENS210_SYSSTAT_MODE_STANDBY             (0 << 0)
78 /** ENS210 SysStat register: Active mode */
79 #define ENS210_SYSSTAT_MODE_ACTIVE              (1 << 0)
80 
81 
82 /** ENS210 SensRun register: temperature single shot mode */
83 #define ENS210_SENSRUN_T_MODE_SINGLE_SHOT       (0 << 0)
84 /** ENS210 SensRun register: temperature continuous mode */
85 #define ENS210_SENSRUN_T_MODE_CONTINUOUS        (1 << 0)
86 /** ENS210 SensRun register: relative humidity single shot mode */
87 #define ENS210_SENSRUN_H_MODE_SINGLE_SHOT       (0 << 1)
88 /** ENS210 SensRun register: relative humidity continuous mode */
89 #define ENS210_SENSRUN_H_MODE_CONTINUOUS        (1 << 1)
90 
91 /** ENS210  SensStart register: T sensor start */
92 #define ENS210_SENSSTART_T_START                (1 << 0)
93 /** ENS210  SensStart register: H sensor start */
94 #define ENS210_SENSSTART_H_START                (1 << 1)
95 
96 /** ENS210  SensStop register: T sensor stop */
97 #define ENS210_SENSSTOP_T_STOP                  (1 << 0)
98 /** ENS210  SensStop register: H sensor stop */
99 #define ENS210_SENSSTOP_H_STOP                  (1 << 1)
100 
101 /** ENS210  SensStat register: T sensor idle */
102 #define ENS210_SENSSTAT_T_STAT_IDLE             (0 << 0)
103 /** ENS210  SensStat register: T sensor active */
104 #define ENS210_SENSSTAT_T_STAT_ACTIVE           (1 << 0)
105 /** ENS210  SensStat register: H sensor idle */
106 #define ENS210_SENSSTAT_H_STAT_IDLE             (0 << 1)
107 /** ENS210  SensStat register: H sensor active */
108 #define ENS210_SENSSTAT_H_STAT_ACTIVE           (1 << 1)
109 
110 #define ENS210_CMD_LENGTH                            2
111 #define ENS210_RESPONSE_LENGTH                       6
112 #define ENS210_DATA_READ_MIN_INTERVAL              1000
113 
114 
115 
116 /**
117  * @brief    ENS210 ID block structure
118  */
119 typedef struct ENS210_Ids_s
120 {
121     uint16_t    partId;             /*!< Part ID */
122     uint8_t     uId[8];             /*!< Unique Identifier 8 bytes */
123 } ENS210_Ids_t;
124 
125 typedef struct {
126     int32_t temperature;
127     uint32_t humidity;
128 } ens210_sensor_data;
129 
130 ens210_sensor_data g_ens210_data = {0};
131 
132 typedef enum {
133     FLAG_INIT_TEMP = 0,
134     FLAG_INIT_HUMI,
135 } FLAG_INIT_BIT;
136 
137 static uint8_t g_init_bitwise = 0;
138 
139 i2c_dev_t ens210_ctx = {
140     .port = 3,
141     .config.address_width = 8,
142     .config.freq = 100000,
143     .config.dev_addr = ENS210_I2C_ADDR,
144 };
145 extern long long aos_now_ms(void);
146 
147 // Compute the CRC-7 of 'val' (should only have 17 bits)
crc7(uint32_t val)148 uint32_t crc7(uint32_t val)
149 {
150     // Setup polynomial
151     uint32_t pol= CRC7POLY;
152     // Align polynomial with data
153     pol = pol << (DATA7WIDTH-CRC7WIDTH-1);
154     // Loop variable (indicates which bit to test, start with highest)
155     uint32_t bit = DATA7MSB;
156     // Make room for CRC value
157     val = val << CRC7WIDTH;
158     bit = bit << CRC7WIDTH;
159     pol = pol << CRC7WIDTH;
160     // Insert initial vector
161     val |= CRC7IVEC;
162     // Apply division until all bits done
163     while( bit & (DATA7MASK<<CRC7WIDTH) ) {
164     if( bit & val ) val ^= pol;
165     bit >>= 1;
166     pol >>= 1;
167     }
168   return val;
169 }
170 
drv_ens210_read_temp_and_humi(i2c_dev_t * drv,int32_t * temperature,uint32_t * humidity)171 static int drv_ens210_read_temp_and_humi(i2c_dev_t* drv, int32_t *temperature, uint32_t *humidity)
172 {
173     int ret = 0;
174     uint8_t temp_data[3] = {0};
175     uint8_t humi_data[3] = {0};
176     uint8_t cmd;
177 
178     cmd = ENS210_SYSCTRL_LOWPOWER_DISABLE;
179     ret = sensor_i2c_write(&ens210_ctx, ENS210_REG_SYS_CTRL, &cmd, 1, I2C_OP_RETRIES);
180     if(unlikely(ret)){
181        return ret;
182     }
183 
184     cmd = (ENS210_SENSRUN_T_MODE_SINGLE_SHOT | ENS210_SENSRUN_H_MODE_SINGLE_SHOT);
185     ret = sensor_i2c_write(&ens210_ctx, ENS210_REG_SENS_RUN, &cmd, 1, I2C_OP_RETRIES);
186     if(unlikely(ret)){
187        return ret;
188     }
189 
190     cmd = (ENS210_SENSSTART_T_START | ENS210_SENSSTART_H_START);
191     ret = sensor_i2c_write(&ens210_ctx, ENS210_REG_SENS_START, &cmd, 1, I2C_OP_RETRIES);
192     if(unlikely(ret)){
193        return ret;
194     }
195 
196     if (temperature == NULL && humidity == NULL)
197         return -1;
198 
199     ret  = sensor_i2c_read(&ens210_ctx, ENS210_REG_T_VAL, temp_data, 3, I2C_OP_RETRIES);
200     if (unlikely(ret)) {
201         return ret;
202     }
203 
204     uint32_t t_val = (temp_data[2]<<16) + (temp_data[1]<<8) + (temp_data[0]<<0);
205 
206     // Extract (and print) the fields
207     uint32_t t_data = (t_val>>0 ) & 0xffff;
208     uint32_t t_valid= (t_val>>16) & 0x1;
209     uint32_t t_crc = (t_val>>17) & 0x7f;
210 
211     // Check the CRC
212     uint32_t t_payl = (t_val>>0 ) & 0x1ffff;
213     bool t_crc_ok= crc7(t_payl)==t_crc;
214     // Convert to float (and print)
215     float TinK = (float)t_data / 64; // Temperature in Kelvin
216     float TinC = TinK - 273.15; // Temperature in Celsius
217     float TinF = TinC * 1.8 + 32.0; // Temperature in Fahrenheit
218 
219     ret  = sensor_i2c_read(&ens210_ctx, ENS210_REG_H_VAL, humi_data, 3, I2C_OP_RETRIES);
220     if (unlikely(ret)) {
221         return ret;
222     }
223 
224     uint32_t h_val = (humi_data[2]<<16) + (humi_data[1]<<8) + (humi_data[0]<<0);
225 
226     // Extract (and print) the fields
227     uint32_t h_data = (h_val>>0 ) & 0xffff;
228     uint32_t h_valid= (h_val>>16) & 0x1;
229     uint32_t h_crc = (h_val>>17) & 0x7f;
230 
231     // Check the CRC
232     uint32_t h_payl = (h_val>>0 ) & 0x1ffff;
233     bool h_crc_ok= (crc7(h_payl)==h_crc);
234     // Convert to float (and print)
235     float H = (float)h_data/512; // relative humidity (in %)
236 
237     *temperature = (int32_t)(TinC*10); // Temperature in Celsius
238     *humidity = (uint32_t)(H*10);  // relative humidity (in ‰)
239 
240     (void)h_crc_ok;
241     (void)h_valid;
242     (void)TinF;
243     (void)t_crc_ok;
244     (void)t_valid;
245 
246     return 0;
247 }
248 
drv_ens210_update_data(i2c_dev_t * drv)249 UNUSED static int drv_ens210_update_data(i2c_dev_t* drv)
250 {
251     static uint32_t prev_update_tick = 0;
252     uint32_t now_tick = 0;
253     int ret = 0;
254 
255      now_tick = aos_now_ms();
256     if (now_tick - prev_update_tick > ENS210_DATA_READ_MIN_INTERVAL) {
257         ret = drv_ens210_read_temp_and_humi(drv, &g_ens210_data.temperature, &g_ens210_data.humidity);
258         if (ret != 0) {
259             return ret;
260         }
261         prev_update_tick = now_tick;
262     }
263 
264     return 0;
265 }
266 
drv_temp_humi_ams_ens210_validate_id(i2c_dev_t * drv,uint8_t id_value)267 static int drv_temp_humi_ams_ens210_validate_id(i2c_dev_t* drv, uint8_t id_value)
268 {
269     int     ret = 0;
270     uint8_t value, value2;
271     ENS210_Ids_t ids;
272 
273     if(drv == NULL){
274         return -1;
275     }
276 
277     value = 0x00;
278     ret = sensor_i2c_write(drv, ENS210_REG_SYS_CTRL, &value, 1, I2C_OP_RETRIES);
279     if(unlikely(ret)){
280        return ret;
281     }
282 
283     ret = sensor_i2c_read(drv, ENS210_REG_SYS_STAT, &value2, 1, I2C_OP_RETRIES);
284     if(unlikely(ret)){
285        return ret;
286     }
287 
288     ret = sensor_i2c_read(drv, ENS210_REG_PART_ID, (uint8_t*)&ids.partId, 2, I2C_OP_RETRIES);
289     if(unlikely(ret)){
290         return ret;
291     }
292 
293     if (id_value != value){
294         return -1;
295     }
296     return 0;
297 }
298 
299 
drv_temp_humi_ams_ens210_soft_reset(i2c_dev_t * drv)300 UNUSED static int  drv_temp_humi_ams_ens210_soft_reset(i2c_dev_t* drv)
301 {
302     int     ret = 0;
303     uint8_t value, value2;
304 
305     if(drv == NULL){
306         return -1;
307     }
308 
309     value = ENS210_SYSCTRL_RESET_ENABLE;
310     ret = sensor_i2c_write(drv, ENS210_REG_SYS_CTRL, &value, 1, I2C_OP_RETRIES);
311     if(unlikely(ret)){
312        return ret;
313     }
314 
315     ret = sensor_i2c_read(drv, ENS210_REG_SYS_STAT, &value2, 1, I2C_OP_RETRIES);
316     if(unlikely(ret)){
317        return ret;
318     }
319 
320     return 0;
321 }
322 
drv_temp_humi_ams_ens210_set_power_mode(i2c_dev_t * drv,dev_power_mode_e mode)323 static int drv_temp_humi_ams_ens210_set_power_mode(i2c_dev_t* drv, dev_power_mode_e mode)
324 {
325     return 0;
326 }
327 
drv_temp_humi_ams_ens210_set_default_config(i2c_dev_t * drv)328 UNUSED static int drv_temp_humi_ams_ens210_set_default_config(i2c_dev_t* drv)
329 {
330      int     ret = 0;
331     uint8_t value = 0x00;
332 
333     ret = sensor_i2c_read(&ens210_ctx, ENS210_REG_SYS_STAT, &value, 1, I2C_OP_RETRIES);
334     if(unlikely(ret)){
335         return ret;
336     }
337 
338     ret = drv_temp_humi_ams_ens210_set_power_mode(&ens210_ctx, DEV_SLEEP);
339     if(unlikely(ret)){
340         return ret;
341     }
342 
343     return 0;
344 }
345 
346 
347 
drv_temp_humi_ams_ens210_get_calib_param(i2c_dev_t * drv)348 UNUSED static int  drv_temp_humi_ams_ens210_get_calib_param(i2c_dev_t* drv)
349 {
350     return 0;
351 }
352 
drv_temp_humi_ams_ens210_set_work_mode(i2c_dev_t * drv,uint8_t mode)353 UNUSED static int drv_temp_humi_ams_ens210_set_work_mode(i2c_dev_t* drv,uint8_t mode)
354 {
355     return 0;
356 }
357 
358 
drv_temp_ams_ens210_irq_handle(void)359 static void drv_temp_ams_ens210_irq_handle(void)
360 {
361     /* no handle so far */
362 }
363 
drv_temp_ams_ens210_open(void)364 static int drv_temp_ams_ens210_open(void)
365 {
366     LOG("%s %s successfully \n", SENSOR_STR, __func__);
367 
368     return 0;
369 }
370 
drv_temp_ams_ens210_close(void)371 static int drv_temp_ams_ens210_close(void)
372 {
373     LOG("%s %s successfully \n", SENSOR_STR, __func__);
374 
375     return 0;
376 }
377 
drv_temp_ams_ens210_read(void * buf,size_t len)378 static int drv_temp_ams_ens210_read(void *buf, size_t len)
379 {
380     int ret = 0;
381     size_t size;
382     temperature_data_t* pdata = (temperature_data_t*)buf;
383 
384     if(buf == NULL){
385         return -1;
386     }
387 
388     size = sizeof(temperature_data_t);
389     if(len < size){
390         return -1;
391     }
392 
393     //ret = drv_ens210_update_data(&ens210_ctx);
394     ret = drv_ens210_read_temp_and_humi(&ens210_ctx, &g_ens210_data.temperature, &g_ens210_data.humidity);
395     if (ret != 0)
396         return -1;
397 
398     pdata->t = g_ens210_data.temperature;
399     pdata->timestamp = aos_now_ms();
400 
401     return (int)size;
402 }
403 
drv_temp_ams_ens210_write(const void * buf,size_t len)404 static int drv_temp_ams_ens210_write(const void *buf, size_t len)
405 {
406     (void)buf;
407     (void)len;
408     return 0;
409 }
410 
drv_temp_ams_ens210_ioctl(int cmd,unsigned long arg)411 static int drv_temp_ams_ens210_ioctl(int cmd, unsigned long arg)
412 {
413     switch (cmd) {
414         case SENSOR_IOCTL_GET_INFO:{
415             /* fill the dev info here */
416             dev_sensor_info_t *info = (dev_sensor_info_t *)arg;
417             info->model = "ENS210";
418             info->unit = dCelsius;
419         }break;
420         default:
421             return -1;
422     }
423 
424     LOG("%s %s successfully \n", SENSOR_STR, __func__);
425     return 0;
426 }
427 
drv_humi_ams_ens210_irq_handle(void)428 static void drv_humi_ams_ens210_irq_handle(void)
429 {
430     /* no handle so far */
431 }
432 
drv_humi_ams_ens210_open(void)433 static int drv_humi_ams_ens210_open(void)
434 {
435     LOG("%s %s successfully \n", SENSOR_STR, __func__);
436 
437     return 0;
438 }
439 
drv_humi_ams_ens210_close(void)440 static int drv_humi_ams_ens210_close(void)
441 {
442     LOG("%s %s successfully \n", SENSOR_STR, __func__);
443 
444     return 0;
445 }
446 
drv_humi_ams_ens210_read(void * buf,size_t len)447 static int drv_humi_ams_ens210_read(void *buf, size_t len)
448 {
449     int ret = 0;
450     size_t size;
451     humidity_data_t* pdata = (humidity_data_t*)buf;
452 
453     if(buf == NULL){
454         return -1;
455     }
456 
457     size = sizeof(humidity_data_t);
458     if(len < size){
459         return -1;
460     }
461 
462     ret = drv_ens210_read_temp_and_humi(&ens210_ctx, &g_ens210_data.temperature, &g_ens210_data.humidity);
463     if (ret != 0)
464         return -1;
465 
466     pdata->h = g_ens210_data.humidity;
467 
468     pdata->timestamp = aos_now_ms();
469 
470     return (int)size;
471 }
472 
drv_humi_ams_ens210_write(const void * buf,size_t len)473 static int drv_humi_ams_ens210_write(const void *buf, size_t len)
474 {
475     (void)buf;
476     (void)len;
477     return 0;
478 }
479 
drv_humi_ams_ens210_ioctl(int cmd,unsigned long arg)480 static int drv_humi_ams_ens210_ioctl(int cmd, unsigned long arg)
481 {
482     switch (cmd) {
483         case SENSOR_IOCTL_GET_INFO:{
484             /* fill the dev info here */
485             dev_sensor_info_t *info = (dev_sensor_info_t *)arg;
486             info->model = "ENS210";
487             info->unit = permillage;
488         }break;
489         default:
490             return -1;
491     }
492     LOG("%s %s successfully \n", SENSOR_STR, __func__);
493     return 0;
494 }
495 
drv_temp_ams_ens210_init(void)496 int drv_temp_ams_ens210_init(void)
497 {
498     int ret = 0;
499     sensor_obj_t sensor_temp;
500 
501     memset(&sensor_temp, 0, sizeof(sensor_temp));
502     if (!g_init_bitwise) {
503 
504         ret = drv_temp_humi_ams_ens210_validate_id(&ens210_ctx, ENS210_REG_PART_ID);
505         if (unlikely(ret)) {
506             return -1;
507         }
508     }
509 
510     if (!(g_init_bitwise & (1 << FLAG_INIT_TEMP))) {
511         /* fill the sensor_temp obj parameters here */
512         sensor_temp.tag = TAG_DEV_TEMP;
513         sensor_temp.path = dev_temp_path;
514         sensor_temp.io_port = I2C_PORT;
515         sensor_temp.open = drv_temp_ams_ens210_open;
516         sensor_temp.close = drv_temp_ams_ens210_close;
517         sensor_temp.read = drv_temp_ams_ens210_read;
518         sensor_temp.write = drv_temp_ams_ens210_write;
519         sensor_temp.ioctl = drv_temp_ams_ens210_ioctl;
520         sensor_temp.irq_handle = drv_temp_ams_ens210_irq_handle;
521 
522         ret = sensor_create_obj(&sensor_temp);
523         if (unlikely(ret)) {
524             return -1;
525         }
526 
527         g_init_bitwise |= 1 << FLAG_INIT_TEMP;
528     }
529 
530     LOG("%s %s successfully \n", SENSOR_STR, __func__);
531     return 0;
532 }
533 
534 
drv_humi_ams_ens210_init(void)535 int drv_humi_ams_ens210_init(void)
536 {
537     int ret = 0;
538     sensor_obj_t sensor_humi;
539     memset(&sensor_humi, 0, sizeof(sensor_humi));
540     if (!g_init_bitwise) {
541 
542         ret = drv_temp_humi_ams_ens210_validate_id(&ens210_ctx, ENS210_REG_PART_ID);
543         if (unlikely(ret)) {
544             return -1;
545         }
546      }
547 
548    if (!(g_init_bitwise & (1 << FLAG_INIT_HUMI))) {
549         /* fill the sensor_humi obj parameters here */
550         sensor_humi.tag = TAG_DEV_HUMI;
551         sensor_humi.path = dev_humi_path;
552         sensor_humi.io_port = I2C_PORT;
553         sensor_humi.open = drv_humi_ams_ens210_open;
554         sensor_humi.close = drv_humi_ams_ens210_close;
555         sensor_humi.read = drv_humi_ams_ens210_read;
556         sensor_humi.write = drv_humi_ams_ens210_write;
557         sensor_humi.ioctl = drv_humi_ams_ens210_ioctl;
558         sensor_humi.irq_handle = drv_humi_ams_ens210_irq_handle;
559 
560         ret = sensor_create_obj(&sensor_humi);
561         if (unlikely(ret)) {
562             return -1;
563         }
564 
565        g_init_bitwise |= 1 << FLAG_INIT_HUMI;
566     }
567 
568     LOG("%s %s successfully \n", SENSOR_STR, __func__);
569     return 0;
570 }
571 
572 SENSOR_DRV_ADD(drv_temp_ams_ens210_init);
573 SENSOR_DRV_ADD(drv_humi_ams_ens210_init);