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