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