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