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 /* ST humi SENSOR REGISTER MAP */
15 #define HTS221_BIT(x) ((uint8_t)x)
16 #define HTS221_I2C_ADDR1 (0x5F)
17 #define HTS221_I2C_ADDR_TRANS(n) ((n) << 1)
18 #define HTS221_I2C_ADDR HTS221_I2C_ADDR_TRANS(HTS221_I2C_ADDR1)
19 #define HTS221_DriverVersion_Major (uint8_t)1
20 #define HTS221_DriverVersion_Minor (uint8_t)0
21 #define HTS221_DriverVersion_Point (uint8_t)0
22
23 // who Am I
24 #define HTS221_WHO_AM_I_REG (uint8_t)0x0F
25 #define HTS221_WHO_AM_I_VAL (uint8_t)0xBC
26
27 // brief Humidity and temperature average mode
28 #define HTS221_AV_CONF_REG (uint8_t)0x10
29 #define HTS221_AVGT_BIT HTS221_BIT(3)
30 #define HTS221_AVGH_BIT HTS221_BIT(0)
31 #define HTS221_AVGT_MASK (uint8_t)0x38
32 #define HTS221_AVGH_MASK (uint8_t)0x07
33
34 // brief Control register 1.
35 #define HTS221_CTRL_REG1 (uint8_t)0x20
36 #define HTS221_PD_BIT HTS221_BIT(7)
37 #define HTS221_BDU_BIT HTS221_BIT(2)
38 #define HTS221_ODR_BIT HTS221_BIT(0)
39 #define HTS221_PD_MASK (uint8_t)0x80
40 #define HTS221_BDU_MASK (uint8_t)0x04
41 #define HTS221_ODR_MASK (uint8_t)0x03
42
43 // brief Control register 2.
44 #define HTS221_CTRL_REG2 (uint8_t)0x21
45 #define HTS221_BOOT_BIT HTS221_BIT(7)
46 #define HTS221_HEATHER_BIT HTS221_BIT(1)
47 #define HTS221_ONESHOT_BIT HTS221_BIT(0)
48 #define HTS221_BOOT_MASK (uint8_t)0x80
49 #define HTS221_HEATHER_MASK (uint8_t)0x02
50 #define HTS221_ONE_SHOT_MASK (uint8_t)0x01
51
52 // brief Control register 3.
53 #define HTS221_CTRL_REG3 (uint8_t)0x22
54 #define HTS221_DRDY_H_L_BIT HTS221_BIT(7)
55 #define HTS221_PP_OD_BIT HTS221_BIT(6)
56 #define HTS221_DRDY_BIT HTS221_BIT(2)
57 #define HTS221_DRDY_H_L_MASK (uint8_t)0x80
58 #define HTS221_PP_OD_MASK (uint8_t)0x40
59 #define HTS221_DRDY_MASK (uint8_t)0x04
60
61 // brief Status register.
62 #define HTS221_STATUS_REG (uint8_t)0x27
63 #define HTS221_H_DA_BIT HTS221_BIT(1)
64 #define HTS221_T_DA_BIT HTS221_BIT(0)
65 #define HTS221_HDA_MASK (uint8_t)0x02
66 #define HTS221_TDA_MASK (uint8_t)0x01
67
68 // brief Humidity data (LSB)
69 #define HTS221_HR_OUT_L_REG (uint8_t)0x28
70
71 // brief Humidity data (MSB)
72 #define HTS221_HR_OUT_H_REG (uint8_t)0x29
73
74 // brief Temperature data (LSB)
75 #define HTS221_TEMP_OUT_L_REG (uint8_t)0x2A
76
77 // brief Temperature data (MSB)
78 #define HTS221_TEMP_OUT_H_REG (uint8_t)0x2B
79
80 // brief Calibration registers
81 #define HTS221_H0_RH_X2 (uint8_t)0x30
82 #define HTS221_H1_RH_X2 (uint8_t)0x31
83 #define HTS221_T0_DEGC_X8 (uint8_t)0x32
84 #define HTS221_T1_DEGC_X8 (uint8_t)0x33
85 #define HTS221_T0_T1_DEGC_H2 (uint8_t)0x35
86 #define HTS221_H0_T0_OUT_L (uint8_t)0x36
87 #define HTS221_H0_T0_OUT_H (uint8_t)0x37
88 #define HTS221_H1_T0_OUT_L (uint8_t)0x3A
89 #define HTS221_H1_T0_OUT_H (uint8_t)0x3B
90 #define HTS221_T0_OUT_L (uint8_t)0x3C
91 #define HTS221_T0_OUT_H (uint8_t)0x3D
92 #define HTS221_T1_OUT_L (uint8_t)0x3E
93 #define HTS221_T1_OUT_H (uint8_t)0x3F
94
95
96 typedef enum
97 {
98 HTS221_ODR_ONE_SHOT = (uint8_t)0x00, /*!< Output Data Rate: one shot */
99 HTS221_ODR_1HZ = (uint8_t)0x01, /*!< Output Data Rate: 1Hz */
100 HTS221_ODR_7HZ = (uint8_t)0x02, /*!< Output Data Rate: 7Hz */
101 HTS221_ODR_12_5HZ = (uint8_t)0x03, /*!< Output Data Rate: 12_5Hz */
102 } HTS221_odr_e;
103
104 typedef enum
105 {
106 HTS221_BDU_CONTINUOUS_UPDATE =
107 (uint8_t)0x00, /*!< Data updated continuously */
108 HTS221_BDU_NO_UPDATE =
109 (uint8_t)0x04 /*!< Data updated after a read operation */
110 } HTS221_bdu_e;
111
112 i2c_dev_t HTS221_ctx = {
113 .port = 1,
114 .config.address_width = 8,
115 .config.freq = 400000,
116 .config.dev_addr = HTS221_I2C_ADDR,
117 };
118
drv_temp_humi_st_hts221_hz2odr(int hz)119 static HTS221_odr_e drv_temp_humi_st_hts221_hz2odr(int hz)
120 {
121 if (hz > 10)
122 return HTS221_ODR_12_5HZ;
123 else if (hz > 5)
124 return HTS221_ODR_7HZ;
125 else
126 return HTS221_ODR_1HZ;
127 }
128
drv_temp_humi_st_hts221_validate_id(i2c_dev_t * drv,uint8_t id_value)129 static int drv_temp_humi_st_hts221_validate_id(i2c_dev_t *drv, uint8_t id_value)
130 {
131 uint8_t value = 0x00;
132 int ret = 0;
133
134 if (drv == NULL) {
135 return -1;
136 }
137
138 ret = sensor_i2c_read(drv, HTS221_WHO_AM_I_REG, &value, I2C_DATA_LEN,
139 I2C_OP_RETRIES);
140 if (unlikely(ret)) {
141 return ret;
142 }
143
144 if (id_value != value) {
145 return -1;
146 }
147 return 0;
148 }
149
drv_temp_humi_st_hts221_set_power_mode(i2c_dev_t * drv,dev_power_mode_e mode)150 static int drv_temp_humi_st_hts221_set_power_mode(i2c_dev_t *drv,
151 dev_power_mode_e mode)
152 {
153 uint8_t value = 0x00;
154 int ret = 0;
155
156 ret = sensor_i2c_read(drv, HTS221_CTRL_REG1, &value, I2C_DATA_LEN,
157 I2C_OP_RETRIES);
158 if (unlikely(ret)) {
159 return ret;
160 }
161
162 switch (mode) {
163 case DEV_POWER_ON: {
164 value |= HTS221_PD_MASK;
165 ret = sensor_i2c_write(drv, HTS221_CTRL_REG1, &value, I2C_DATA_LEN,
166 I2C_OP_RETRIES);
167 if (unlikely(ret)) {
168 return ret;
169 }
170 } break;
171
172 case DEV_POWER_OFF: {
173 value &= ~HTS221_PD_MASK;
174 ret = sensor_i2c_write(drv, HTS221_CTRL_REG1, &value, I2C_DATA_LEN,
175 I2C_OP_RETRIES);
176 if (unlikely(ret)) {
177 return ret;
178 }
179 } break;
180
181 default:
182 break;
183 }
184 return 0;
185 }
186
drv_temp_humi_st_hts221_set_odr(i2c_dev_t * drv,HTS221_odr_e odr)187 static int drv_temp_humi_st_hts221_set_odr(i2c_dev_t *drv, HTS221_odr_e odr)
188 {
189 uint8_t value = 0x00;
190 int ret = 0;
191
192 ret = sensor_i2c_read(drv, HTS221_CTRL_REG1, &value, I2C_DATA_LEN,
193 I2C_OP_RETRIES);
194 if (unlikely(ret)) {
195 return ret;
196 }
197 value &= ~HTS221_ODR_MASK;
198 value |= (uint8_t)odr;
199
200 ret = sensor_i2c_write(drv, HTS221_CTRL_REG1, &value, I2C_DATA_LEN,
201 I2C_OP_RETRIES);
202 if (unlikely(ret)) {
203 return ret;
204 }
205 return 0;
206 }
207
drv_temp_humi_st_hts221_set_bdu(i2c_dev_t * drv,HTS221_bdu_e bdu)208 static int drv_temp_humi_st_hts221_set_bdu(i2c_dev_t *drv, HTS221_bdu_e bdu)
209 {
210 uint8_t value = 0x00;
211 int ret = 0;
212
213 ret = sensor_i2c_read(drv, HTS221_CTRL_REG1, &value, I2C_DATA_LEN,
214 I2C_OP_RETRIES);
215 if (unlikely(ret)) {
216 return ret;
217 }
218 value &= ~HTS221_BDU_MASK;
219 value |= (uint8_t)bdu;
220
221 ret = sensor_i2c_write(drv, HTS221_CTRL_REG1, &value, I2C_DATA_LEN,
222 I2C_OP_RETRIES);
223 if (unlikely(ret)) {
224 return ret;
225 }
226 return 0;
227 }
228
drv_temp_humi_st_hts221_set_default_config(i2c_dev_t * drv)229 static int drv_temp_humi_st_hts221_set_default_config(i2c_dev_t *drv)
230 {
231 int ret = 0;
232
233 ret = drv_temp_humi_st_hts221_set_power_mode(drv, DEV_POWER_OFF);
234 if (unlikely(ret)) {
235 return ret;
236 }
237 ret = drv_temp_humi_st_hts221_set_odr(drv, HTS221_ODR_1HZ);
238 if (unlikely(ret)) {
239 return ret;
240 }
241
242 ret = drv_temp_humi_st_hts221_set_bdu(drv, HTS221_BDU_NO_UPDATE);
243 if (unlikely(ret)) {
244 return ret;
245 }
246 /* you also can set the low-pass filter and cut off config here */
247 return 0;
248 }
249
250
drv_temp_st_hts221_irq_handle(void)251 static void drv_temp_st_hts221_irq_handle(void)
252 {
253 /* no handle so far */
254 }
255
drv_temp_st_hts221_open(void)256 static int drv_temp_st_hts221_open(void)
257 {
258 int ret = 0;
259 ret = drv_temp_humi_st_hts221_set_power_mode(&HTS221_ctx, DEV_POWER_ON);
260 if (unlikely(ret)) {
261 return -1;
262 }
263 LOG("%s %s successfully \n", SENSOR_STR, __func__);
264 return 0;
265 }
266
drv_temp_st_hts221_close(void)267 static int drv_temp_st_hts221_close(void)
268 {
269 int ret = 0;
270 ret = drv_temp_humi_st_hts221_set_power_mode(&HTS221_ctx, DEV_POWER_OFF);
271 if (unlikely(ret)) {
272 return -1;
273 }
274 LOG("%s %s successfully \n", SENSOR_STR, __func__);
275 return 0;
276 }
277
278
drv_temp_st_hts221_read(void * buf,size_t len)279 static int drv_temp_st_hts221_read(void *buf, size_t len)
280 {
281 int ret = 0;
282 size_t size;
283 uint8_t data[2], buffer[4], tmp;
284 int16_t T0_out, T1_out, T_out, T0_degC_x8_u16, T1_degC_x8_u16;
285 int16_t T0_degC, T1_degC;
286 int16_t temp;
287 temperature_data_t *pdata = (temperature_data_t *)buf;
288 if (buf == NULL) {
289 return -1;
290 }
291
292 size = sizeof(temperature_data_t);
293 if (len < size) {
294 return -1;
295 }
296
297 ret = sensor_i2c_read(&HTS221_ctx, (HTS221_T0_DEGC_X8 | 0x80), buffer, 2,
298 I2C_OP_RETRIES);
299 ret = sensor_i2c_read(&HTS221_ctx, HTS221_T0_T1_DEGC_H2, &tmp, I2C_DATA_LEN,
300 I2C_OP_RETRIES);
301 T0_degC_x8_u16 = (((uint16_t)(tmp & 0x03)) << 8) | ((uint16_t)buffer[0]);
302 T1_degC_x8_u16 = (((uint16_t)(tmp & 0x0C)) << 6) | ((uint16_t)buffer[1]);
303 T0_degC = T0_degC_x8_u16 >> 3;
304 T1_degC = T1_degC_x8_u16 >> 3;
305 ret |= sensor_i2c_read(&HTS221_ctx, (HTS221_T0_OUT_L | 0x80), buffer, 4,
306 I2C_OP_RETRIES);
307 T0_out = (((uint16_t)buffer[1]) << 8) | (uint16_t)buffer[0];
308 T1_out = (((uint16_t)buffer[3]) << 8) | (uint16_t)buffer[2];
309 ret |= sensor_i2c_read(&HTS221_ctx, (HTS221_TEMP_OUT_L_REG | 0x80), buffer,
310 2, I2C_OP_RETRIES);
311 T_out = (((uint16_t)buffer[1]) << 8) | (uint16_t)buffer[0];
312
313 temp = 10 * (T_out - T0_out) * (T1_degC - T0_degC) / (T1_out - T0_out) +
314 10 * T0_degC;
315
316 data[0] = temp & 0x0FF;
317 data[1] = temp >> 8;
318
319 if (unlikely(ret)) {
320 return -1;
321 }
322
323 /* hatch the temp data here*/
324 for (int i = 0; i < 2; i++) {
325 pdata->t |= (((uint32_t)data[i]) << (8 * i));
326 }
327
328 pdata->timestamp = aos_now_ms();
329 return (int)size;
330 }
331
drv_temp_st_hts221_write(const void * buf,size_t len)332 static int drv_temp_st_hts221_write(const void *buf, size_t len)
333 {
334 return 0;
335 }
336
drv_temp_st_hts221_ioctl(int cmd,unsigned long arg)337 static int drv_temp_st_hts221_ioctl(int cmd, unsigned long arg)
338 {
339 int ret = 0;
340
341 switch (cmd) {
342 case SENSOR_IOCTL_ODR_SET: {
343 HTS221_odr_e odr = drv_temp_humi_st_hts221_hz2odr(arg);
344 ret = drv_temp_humi_st_hts221_set_odr(&HTS221_ctx, odr);
345 if (unlikely(ret)) {
346 return -1;
347 }
348 } break;
349 case SENSOR_IOCTL_SET_POWER: {
350 ret = drv_temp_humi_st_hts221_set_power_mode(&HTS221_ctx, arg);
351 if (unlikely(ret)) {
352 return -1;
353 }
354 } break;
355 case SENSOR_IOCTL_GET_INFO: {
356 /* fill the dev info here */
357 dev_sensor_info_t *info = (dev_sensor_info_t *)arg;
358 info->model = "HTS221";
359 info->range_max = 120;
360 info->range_min = -40;
361 info->unit = dCelsius;
362
363 } break;
364
365 default:
366 break;
367 }
368
369 LOG("%s %s successfully \n", SENSOR_STR, __func__);
370 return 0;
371 }
372
drv_temp_st_hts221_init(void)373 int drv_temp_st_hts221_init(void)
374 {
375 int ret = 0;
376 sensor_obj_t sensor;
377
378 memset(&sensor, 0, sizeof(sensor));
379
380 /* fill the sensor obj parameters here */
381 sensor.tag = TAG_DEV_TEMP;
382 sensor.path = dev_temp_path;
383 sensor.io_port = I2C_PORT;
384 sensor.open = drv_temp_st_hts221_open;
385 sensor.close = drv_temp_st_hts221_close;
386 sensor.read = drv_temp_st_hts221_read;
387 sensor.write = drv_temp_st_hts221_write;
388 sensor.ioctl = drv_temp_st_hts221_ioctl;
389 sensor.irq_handle = drv_temp_st_hts221_irq_handle;
390
391
392 ret = sensor_create_obj(&sensor);
393 if (unlikely(ret)) {
394 return -1;
395 }
396
397 ret = drv_temp_humi_st_hts221_validate_id(&HTS221_ctx, HTS221_WHO_AM_I_VAL);
398 if (unlikely(ret)) {
399 return -1;
400 }
401
402 /* set the default config for the sensor here */
403 ret = drv_temp_humi_st_hts221_set_default_config(&HTS221_ctx);
404 if (unlikely(ret)) {
405 return -1;
406 }
407
408 LOG("%s %s successfully \n", SENSOR_STR, __func__);
409
410 return 0;
411 }
412
413
drv_humi_st_hts221_irq_handle(void)414 static void drv_humi_st_hts221_irq_handle(void)
415 {
416 /* no handle so far */
417 }
418
drv_humi_st_hts221_open(void)419 static int drv_humi_st_hts221_open(void)
420 {
421 int ret = 0;
422 ret = drv_temp_humi_st_hts221_set_power_mode(&HTS221_ctx, DEV_POWER_ON);
423 if (unlikely(ret)) {
424 return -1;
425 }
426 LOG("%s %s successfully \n", SENSOR_STR, __func__);
427 return 0;
428 }
429
drv_humi_st_hts221_close(void)430 static int drv_humi_st_hts221_close(void)
431 {
432 int ret = 0;
433 ret = drv_temp_humi_st_hts221_set_power_mode(&HTS221_ctx, DEV_POWER_OFF);
434 if (unlikely(ret)) {
435 return -1;
436 }
437 LOG("%s %s successfully \n", SENSOR_STR, __func__);
438 return 0;
439 }
440
441
drv_humi_st_hts221_read(void * buf,size_t len)442 static int drv_humi_st_hts221_read(void *buf, size_t len)
443 {
444 int ret = 0;
445 size_t size;
446 uint8_t data[2], buffer[2];
447 int16_t H0_T0_out, H1_T0_out, H_T_out;
448 int16_t H0_rh, H1_rh;
449 int16_t humi;
450 humidity_data_t *pdata = (humidity_data_t *)buf;
451 if (buf == NULL) {
452 return -1;
453 }
454
455 size = sizeof(humidity_data_t);
456 if (len < size) {
457 return -1;
458 }
459
460 ret = sensor_i2c_read(&HTS221_ctx, (HTS221_H0_RH_X2 | 0x80), buffer, 2,
461 I2C_OP_RETRIES);
462
463 H0_rh = buffer[0] >> 1;
464 H1_rh = buffer[1] >> 1;
465
466 ret |= sensor_i2c_read(&HTS221_ctx, (HTS221_H0_T0_OUT_L | 0x80), buffer, 2,
467 I2C_OP_RETRIES);
468 H0_T0_out = (((uint16_t)buffer[1]) << 8) | (uint16_t)buffer[0];
469
470 ret |= sensor_i2c_read(&HTS221_ctx, (HTS221_H1_T0_OUT_L | 0x80), buffer, 2,
471 I2C_OP_RETRIES);
472 H1_T0_out = (((uint16_t)buffer[1]) << 8) | (uint16_t)buffer[0];
473
474 ret |= sensor_i2c_read(&HTS221_ctx, (HTS221_HR_OUT_L_REG | 0x80), buffer, 2,
475 I2C_OP_RETRIES);
476 H_T_out = (((uint16_t)buffer[1]) << 8) | (uint16_t)buffer[0];
477
478 humi =
479 (H_T_out - H0_T0_out) * (H1_rh - H0_rh) / (H1_T0_out - H0_T0_out) + H0_rh;
480 humi *= 10;
481 humi = (humi > 1000) ? 1000 : (humi < 0) ? 0 : humi;
482
483 humi /= 10;
484
485 data[1] = humi >> 8;
486 data[0] = humi & 0x0FF;
487
488 if (unlikely(ret)) {
489 return -1;
490 }
491
492 /* hatch the humi data here*/
493 for (int i = 0; i < 2; i++) {
494 pdata->h |= (((uint32_t)data[i]) << (8 * i));
495 }
496 pdata->timestamp = aos_now_ms();
497
498 return (int)size;
499 }
500
drv_humi_st_hts221_write(const void * buf,size_t len)501 static int drv_humi_st_hts221_write(const void *buf, size_t len)
502 {
503 return 0;
504 }
505
drv_humi_st_hts221_ioctl(int cmd,unsigned long arg)506 static int drv_humi_st_hts221_ioctl(int cmd, unsigned long arg)
507 {
508 int ret = 0;
509
510 switch (cmd) {
511 case SENSOR_IOCTL_ODR_SET: {
512 HTS221_odr_e odr = drv_temp_humi_st_hts221_hz2odr(arg);
513 ret = drv_temp_humi_st_hts221_set_odr(&HTS221_ctx, odr);
514 if (unlikely(ret)) {
515 return -1;
516 }
517 } break;
518 case SENSOR_IOCTL_SET_POWER: {
519 ret = drv_temp_humi_st_hts221_set_power_mode(&HTS221_ctx, arg);
520 if (unlikely(ret)) {
521 return -1;
522 }
523 } break;
524 case SENSOR_IOCTL_GET_INFO: {
525 /* fill the dev info here */
526 dev_sensor_info_t *info = (dev_sensor_info_t *)arg;
527 info->model = "HTS221";
528 info->range_max = 100;
529 info->range_min = 0;
530 info->unit = permillage;
531
532 } break;
533
534 default:
535 break;
536 }
537
538 LOG("%s %s successfully \n", SENSOR_STR, __func__);
539 return 0;
540 }
541
542
drv_humi_st_hts221_init(void)543 int drv_humi_st_hts221_init(void)
544 {
545
546 int ret = 0;
547 sensor_obj_t sensor;
548
549 memset(&sensor, 0, sizeof(sensor));
550 /* fill the sensor obj parameters here */
551 sensor.tag = TAG_DEV_HUMI;
552 sensor.path = dev_humi_path;
553 sensor.io_port = I2C_PORT;
554 sensor.open = drv_humi_st_hts221_open;
555 sensor.close = drv_humi_st_hts221_close;
556 sensor.read = drv_humi_st_hts221_read;
557 sensor.write = drv_humi_st_hts221_write;
558 sensor.ioctl = drv_humi_st_hts221_ioctl;
559 sensor.irq_handle = drv_humi_st_hts221_irq_handle;
560
561
562 ret = sensor_create_obj(&sensor);
563 if (unlikely(ret)) {
564 return -1;
565 }
566
567 ret = drv_temp_humi_st_hts221_validate_id(&HTS221_ctx, HTS221_WHO_AM_I_VAL);
568 if (unlikely(ret)) {
569 return -1;
570 }
571
572 /* set the default config for the sensor here */
573 ret = drv_temp_humi_st_hts221_set_default_config(&HTS221_ctx);
574 if (unlikely(ret)) {
575 return -1;
576 }
577
578 LOG("%s %s successfully \n", SENSOR_STR, __func__);
579
580 return 0;
581 }
582
583 SENSOR_DRV_ADD(drv_temp_st_hts221_init);
584 SENSOR_DRV_ADD(drv_humi_st_hts221_init);
585