1 /*
2 * Copyright (C) 2018 Sensirion Inc.
3 * Author: Johannes Winkelmann, jwi@sensirion.com
4 *
5 * Based on SHTC1 driver
6 */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "aos/kernel.h"
12 #include "sensor_drv_api.h"
13 #include "sensor_hal.h"
14 
15 #define SHT30_I2C_SLAVE_ADDR_DEFAULT                   0x44
16 #define SHT30_I2C_SLAVE_ADDR_ALT                       0x45
17 
18 #define SHT30_ADDR_TRANS(n)                             ((n) << 1)
19 #define SHT30_I2C_ADDR                                  SHT30_ADDR_TRANS(SHT30_I2C_SLAVE_ADDR_DEFAULT)
20 
21 /* delays for non-blocking i2c commands, both in ms */
22 #define SHT30_NONBLOCKING_WAIT_TIME_HRM                 15
23 
24 #define SHT30_CMD_LENGTH                                2
25 #define SHT30_RESPONSE_LENGTH                           6
26 
27 #define SHT30_DATA_READ_MIN_INTERVAL                    200       /* in millisecond */
28 
29 typedef enum {
30     FLAG_INIT_TEMP = 0,
31     FLAG_INIT_HUMI,
32 } FLAG_INIT_BIT;
33 
34 /*
35  * default port = 3
36  * Use "GLOBAL_DEFINES += SENSIRION_SHT30_PORT=2" in a Makefile to override
37 */
38 #ifndef SENSIRION_SHT30_PORT
39 #define SENSIRION_SHT30_PORT 3
40 #endif /* SENSIRION_SHT30_PORT */
41 
42 i2c_dev_t sht30_ctx = {
43     .port = SENSIRION_SHT30_PORT,
44     .config.dev_addr = SHT30_I2C_ADDR,
45 };
46 
47 static uint8_t g_init_bitwise = 0;
48 
49 typedef struct {
50     int32_t temperature;
51     uint32_t humidity;
52 } sht30_sensor_data;
53 
54 static sht30_sensor_data g_sht30_data_new = {0};
55 
56 static const uint8_t sht30_cmd_list[][SHT30_CMD_LENGTH] = {
57     {0x2C, 0x06},                                       /* measure blocking hrm */
58 };
59 
60 typedef enum {
61     SHT30_CMD_measure_blocking_hrm,
62     SHT30_CMD_END
63 } CMD_SHT30_ENUM;
64 
drv_sht30_cmd_write(i2c_dev_t * drv,CMD_SHT30_ENUM cmd)65 static int drv_sht30_cmd_write(i2c_dev_t *drv, CMD_SHT30_ENUM cmd)
66 {
67     int ret = 0;
68 
69     if (cmd < SHT30_CMD_measure_blocking_hrm || cmd >= SHT30_CMD_END) {
70         return -1;
71     }
72     ret = hal_i2c_master_send(drv, drv->config.dev_addr, sht30_cmd_list[cmd], SHT30_CMD_LENGTH, AOS_WAIT_FOREVER);
73     return ret;
74 }
75 
drv_sht30_result_read(i2c_dev_t * drv,uint8_t * data,uint16_t size)76 static int drv_sht30_result_read(i2c_dev_t *drv, uint8_t *data, uint16_t size)
77 {
78     if (data == NULL || size == 0)
79         return -1;
80 
81     return hal_i2c_master_recv(drv, drv->config.dev_addr, data, size, AOS_WAIT_FOREVER);
82 }
83 
drv_sht30_read_raw_data(i2c_dev_t * drv,uint8_t * data)84 static int drv_sht30_read_raw_data(i2c_dev_t *drv, uint8_t *data)
85 {
86     int ret = 0;
87     CMD_SHT30_ENUM readcmd;
88 
89     if (data == NULL)
90         return -1;
91 
92     readcmd = SHT30_CMD_measure_blocking_hrm;
93     ret = drv_sht30_cmd_write(drv, readcmd);
94     if (unlikely(ret)) {
95         return ret;
96     }
97     ret = drv_sht30_result_read(drv, data, SHT30_RESPONSE_LENGTH);
98     if (unlikely(ret)) {
99         return ret;
100     }
101     return ret;
102 }
103 
drv_sht30_read_temp_and_humi(i2c_dev_t * drv,int32_t * temperature,uint32_t * humidity)104 static int drv_sht30_read_temp_and_humi(i2c_dev_t *drv, int32_t *temperature, uint32_t *humidity)
105 {
106     int ret = 0;
107     uint8_t data[SHT30_RESPONSE_LENGTH] = {0};
108     int32_t temp_raw = 0;
109     int32_t humi_raw = 0;
110 
111     if (temperature == NULL && humidity == NULL)
112         return -1;
113 
114     ret = drv_sht30_read_raw_data(drv, data);
115     if (unlikely(ret)) {
116         return ret;
117     }
118 
119     temp_raw = (int)(data[0] << 8 | data[1]);
120     humi_raw = (int)(data[3] << 8 | data[4]);
121 
122     if (temperature != NULL)
123         *temperature = (int32_t)((21875 * temp_raw) >> 13) - 45000;
124     if (humidity != NULL)
125         *humidity = (uint32_t)((12500 * humi_raw) >> 13);
126 
127     return 0;
128 }
129 
drv_sht30_update_data(i2c_dev_t * drv)130 static int drv_sht30_update_data(i2c_dev_t *drv)
131 {
132     static uint32_t prev_update_tick = 0;
133     uint32_t now_tick = 0;
134     int ret = 0;
135 
136     now_tick = aos_now_ms();
137     if (now_tick - prev_update_tick >= SHT30_DATA_READ_MIN_INTERVAL) {
138         ret = drv_sht30_read_temp_and_humi(drv, &g_sht30_data_new.temperature, &g_sht30_data_new.humidity);
139         if (unlikely(ret != 0)) {
140             return ret;
141         }
142         prev_update_tick = now_tick;
143     }
144 
145     return 0;
146 }
147 
drv_temp_sensirion_sht30_irq_handle(void)148 static void drv_temp_sensirion_sht30_irq_handle(void)
149 {
150     /* no handle so far */
151 }
152 
drv_temp_sensirion_sht30_open(void)153 static int drv_temp_sensirion_sht30_open(void)
154 {
155     LOG("%s %s successfully \n", SENSOR_STR, __func__);
156 
157     return 0;
158 }
159 
drv_temp_sensirion_sht30_close(void)160 static int drv_temp_sensirion_sht30_close(void)
161 {
162     LOG("%s %s successfully \n", SENSOR_STR, __func__);
163 
164     return 0;
165 }
166 
drv_temp_sensirion_sht30_read(void * buf,size_t len)167 static int drv_temp_sensirion_sht30_read(void *buf, size_t len)
168 {
169     int ret = 0;
170     const size_t size = sizeof(temperature_data_t);
171     temperature_data_t *pdata = (temperature_data_t*)buf;
172 
173     if (buf == NULL){
174         return -1;
175     }
176 
177     if (len < size){
178         return -1;
179     }
180 
181     ret = drv_sht30_update_data(&sht30_ctx);
182     if (ret != 0)
183         return -1;
184 
185     pdata->t = g_sht30_data_new.temperature / 100.0f;
186 
187     pdata->timestamp = aos_now_ms();
188 
189     return (int)size;
190 }
191 
drv_temp_sensirion_sht30_write(const void * buf,size_t len)192 static int drv_temp_sensirion_sht30_write(const void *buf, size_t len)
193 {
194     (void)buf;
195     (void)len;
196     return 0;
197 }
198 
199 
drv_temp_sensirion_sht30_ioctl(int cmd,unsigned long arg)200 static int drv_temp_sensirion_sht30_ioctl(int cmd, unsigned long arg)
201 {
202     switch (cmd) {
203         case SENSOR_IOCTL_GET_INFO:{
204             /* fill the dev info here */
205             dev_sensor_info_t *info = (dev_sensor_info_t *)arg;
206             info->model = "SHT30";
207             info->unit = dCelsius;
208         }break;
209         default:
210             return -1;
211     }
212 
213     LOG("%s %s successfully \n", SENSOR_STR, __func__);
214     return 0;
215 }
216 
drv_humi_sensirion_sht30_irq_handle(void)217 static void drv_humi_sensirion_sht30_irq_handle(void)
218 {
219     /* no handle so far */
220 }
221 
drv_humi_sensirion_sht30_open(void)222 static int drv_humi_sensirion_sht30_open(void)
223 {
224     LOG("%s %s successfully \n", SENSOR_STR, __func__);
225 
226     return 0;
227 }
228 
drv_humi_sensirion_sht30_close(void)229 static int drv_humi_sensirion_sht30_close(void)
230 {
231     LOG("%s %s successfully \n", SENSOR_STR, __func__);
232 
233     return 0;
234 }
235 
drv_humi_sensirion_sht30_read(void * buf,size_t len)236 static int drv_humi_sensirion_sht30_read(void *buf, size_t len)
237 {
238     int ret = 0;
239     const size_t size = sizeof(humidity_data_t);
240     humidity_data_t *pdata = (humidity_data_t*)buf;
241 
242     if (buf == NULL){
243         return -1;
244     }
245 
246     if (len < size){
247         return -1;
248     }
249 
250     ret = drv_sht30_update_data(&sht30_ctx);
251     if (ret != 0)
252         return -1;
253 
254     pdata->h = g_sht30_data_new.humidity / 100;
255 
256     pdata->timestamp = aos_now_ms();
257 
258     return (int)size;
259 }
260 
drv_humi_sensirion_sht30_write(const void * buf,size_t len)261 static int drv_humi_sensirion_sht30_write(const void *buf, size_t len)
262 {
263     (void)buf;
264     (void)len;
265     return 0;
266 }
267 
drv_humi_sensirion_sht30_ioctl(int cmd,unsigned long arg)268 static int drv_humi_sensirion_sht30_ioctl(int cmd, unsigned long arg)
269 {
270     switch (cmd) {
271         case SENSOR_IOCTL_GET_INFO:{
272             /* fill the dev info here */
273             dev_sensor_info_t *info = (dev_sensor_info_t *)arg;
274             info->model = "SHT30";
275             info->unit = permillage;
276         }break;
277         default:
278             return -1;
279     }
280 
281     LOG("%s %s successfully \n", SENSOR_STR, __func__);
282     return 0;
283 }
284 
drv_temp_sensirion_sht30_init(void)285 int drv_temp_sensirion_sht30_init(void)
286 {
287     int ret = 0;
288     sensor_obj_t sensor_temp;
289     memset(&sensor_temp,0, sizeof(sensor_temp));
290 
291     if (!(g_init_bitwise & (1 << FLAG_INIT_TEMP))) {
292         /* fill the sensor_temp obj parameters here */
293         sensor_temp.tag = TAG_DEV_TEMP;
294         sensor_temp.path = dev_temp_path;
295         sensor_temp.io_port = I2C_PORT;
296         sensor_temp.open = drv_temp_sensirion_sht30_open;
297         sensor_temp.close = drv_temp_sensirion_sht30_close;
298         sensor_temp.read = drv_temp_sensirion_sht30_read;
299         sensor_temp.write = drv_temp_sensirion_sht30_write;
300         sensor_temp.ioctl = drv_temp_sensirion_sht30_ioctl;
301         sensor_temp.irq_handle = drv_temp_sensirion_sht30_irq_handle;
302 
303         ret = sensor_create_obj(&sensor_temp);
304         if (unlikely(ret)) {
305             return -1;
306         }
307 
308         g_init_bitwise |= 1 << FLAG_INIT_TEMP;
309     }
310 
311     LOG("%s %s successfully \n", SENSOR_STR, __func__);
312     return 0;
313 }
314 
drv_humi_sensirion_sht30_init(void)315 int drv_humi_sensirion_sht30_init(void)
316 {
317     int ret = 0;
318     sensor_obj_t sensor_humi;
319     memset(&sensor_humi, 0, sizeof(sensor_humi));
320     if (!(g_init_bitwise & (1 << FLAG_INIT_HUMI))) {
321         /* fill the sensor_humi obj parameters here */
322         sensor_humi.tag = TAG_DEV_HUMI;
323         sensor_humi.path = dev_humi_path;
324         sensor_humi.io_port = I2C_PORT;
325         sensor_humi.open = drv_humi_sensirion_sht30_open;
326         sensor_humi.close = drv_humi_sensirion_sht30_close;
327         sensor_humi.read = drv_humi_sensirion_sht30_read;
328         sensor_humi.write = drv_humi_sensirion_sht30_write;
329         sensor_humi.ioctl = drv_humi_sensirion_sht30_ioctl;
330         sensor_humi.irq_handle = drv_humi_sensirion_sht30_irq_handle;
331 
332         ret = sensor_create_obj(&sensor_humi);
333         if (unlikely(ret)) {
334             return -1;
335         }
336 
337         g_init_bitwise |= 1 << FLAG_INIT_HUMI;
338     }
339 
340     LOG("%s %s successfully \n", SENSOR_STR, __func__);
341     return 0;
342 }
343 
344 SENSOR_DRV_ADD(drv_humi_sensirion_sht30_init);
345 SENSOR_DRV_ADD(drv_temp_sensirion_sht30_init);