1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <atomic.h>
18 #include <gpio.h>
19 #include <nanohubPacket.h>
20 #include <plat/exti.h>
21 #include <plat/gpio.h>
22 #include <platform.h>
23 #include <plat/syscfg.h>
24 #include <sensors.h>
25 #include <seos.h>
26 #include <slab.h>
27 #include <i2c.h>
28 #include <timer.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <variant/variant.h>
32
33 #define SI7034A10_APP_ID APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 22)
34
35 /* Sensor defs */
36 #define SI7034_ID_SAMPLE 0xFF
37 #define SI7034_ID_PROD 0x22
38
39 #define SI7034_RESET_CMD 0xFE
40 #define SI7034_READID_0_CMD 0xFC
41 #define SI7034_READID_1_CMD 0xC9
42 #define SI7034_READDATA_0_CMD 0x7C
43 #define SI7034_READDATA_1_CMD 0xA2
44
45 #define SI7034_HUMIGRADES(humi_val) ((humi_val * 12500) >> 13)
46 #define SI7034_CENTIGRADES(temp_val) (((temp_val * 21875) >> 13) - 45000)
47
48 #define INFO_PRINT(fmt, ...) \
49 do { \
50 osLog(LOG_INFO, "%s " fmt, "[SI7034]", ##__VA_ARGS__); \
51 } while (0);
52
53 #define DEBUG_PRINT(fmt, ...) \
54 do { \
55 if (SI7034_DBG_ENABLED) { \
56 osLog(LOG_DEBUG, "%s " fmt, "[SI7034]", ##__VA_ARGS__); \
57 } \
58 } while (0);
59
60 #define ERROR_PRINT(fmt, ...) \
61 do { \
62 osLog(LOG_ERROR, "%s " fmt, "[SI7034]", ##__VA_ARGS__); \
63 } while (0);
64
65 /* DO NOT MODIFY, just to avoid compiler error if not defined using FLAGS */
66 #ifndef SI7034_DBG_ENABLED
67 #define SI7034_DBG_ENABLED 0
68 #endif /* SI7034_DBG_ENABLED */
69
70 enum si7034SensorEvents
71 {
72 EVT_SENSOR_I2C = EVT_APP_START + 1,
73 EVT_SENSOR_HUMIDITY_TIMER,
74 EVT_SENSOR_TEMP_TIMER,
75 EVT_TEST,
76 };
77
78 enum si7034SensorState {
79 SENSOR_BOOT,
80 SENSOR_VERIFY_ID,
81 SENSOR_READ_SAMPLES,
82 };
83
84 #ifndef SI7034A10_I2C_BUS_ID
85 #error "SI7034A10_I2C_BUS_ID is not defined; please define in variant.h"
86 #endif
87
88 #ifndef SI7034A10_I2C_SPEED
89 #define SI7034A10_I2C_SPEED 400000
90 #endif
91
92 #ifndef SI7034A10_I2C_ADDR
93 #define SI7034A10_I2C_ADDR 0x70
94 #endif
95
96 enum si7034SensorIndex {
97 HUMIDITY = 0,
98 TEMP,
99 NUM_OF_SENSOR,
100 };
101
102 struct si7034Sensor {
103 uint32_t handle;
104 };
105
106 #define SI7034_MAX_PENDING_I2C_REQUESTS 4
107 #define SI7034_MAX_I2C_TRANSFER_SIZE 6
108
109 struct I2cTransfer
110 {
111 size_t tx;
112 size_t rx;
113 int err;
114 uint8_t txrxBuf[SI7034_MAX_I2C_TRANSFER_SIZE];
115 uint8_t state;
116 bool inUse;
117 };
118
119 /* Task structure */
120 struct si7034Task {
121 uint32_t tid;
122
123 /* timer */
124 uint32_t humiTimerHandle;
125 uint32_t tempTimerHandle;
126
127 /* sensor flags */
128 bool humiOn;
129 bool humiReading;
130 bool tempOn;
131 bool tempReading;
132
133 struct I2cTransfer transfers[SI7034_MAX_PENDING_I2C_REQUESTS];
134
135 /* sensors */
136 struct si7034Sensor sensors[NUM_OF_SENSOR];
137 };
138
139 static struct si7034Task mTask;
140
141 // Allocate a buffer and mark it as in use with the given state, or return NULL
142 // if no buffers available. Must *not* be called from interrupt context.
allocXfer(uint8_t state)143 static struct I2cTransfer *allocXfer(uint8_t state)
144 {
145 size_t i;
146
147 for (i = 0; i < ARRAY_SIZE(mTask.transfers); i++) {
148 if (!mTask.transfers[i].inUse) {
149 mTask.transfers[i].inUse = true;
150 mTask.transfers[i].state = state;
151 return &mTask.transfers[i];
152 }
153 }
154
155 ERROR_PRINT("Ran out of i2c buffers!");
156 return NULL;
157 }
158
releaseXfer(struct I2cTransfer * xfer)159 static inline void releaseXfer(struct I2cTransfer *xfer)
160 {
161 xfer->inUse = false;
162 }
163
i2cCallback(void * cookie,size_t tx,size_t rx,int err)164 static void i2cCallback(void *cookie, size_t tx, size_t rx, int err)
165 {
166 struct I2cTransfer *xfer = cookie;
167
168 xfer->tx = tx;
169 xfer->rx = rx;
170 xfer->err = err;
171
172 osEnqueuePrivateEvt(EVT_SENSOR_I2C, cookie, NULL, mTask.tid);
173 if (err != 0)
174 ERROR_PRINT("i2c error (tx: %d, rx: %d, err: %d)\n", tx, rx, err);
175 }
176
si7034_i2c_read(uint8_t addr0,uint8_t addr1,uint8_t state)177 static bool si7034_i2c_read(uint8_t addr0, uint8_t addr1, uint8_t state)
178 {
179 struct I2cTransfer *xfer = allocXfer(state);
180 int ret = -1;
181
182 if (xfer != NULL) {
183 xfer->txrxBuf[0] = addr0;
184 xfer->txrxBuf[1] = addr1;
185 ret = i2cMasterTxRx(SI7034A10_I2C_BUS_ID, SI7034A10_I2C_ADDR,
186 xfer->txrxBuf, 2, xfer->txrxBuf, 6, i2cCallback, xfer);
187 if (ret) {
188 releaseXfer(xfer);
189 return false;
190 }
191 }
192
193 return (ret == -1) ? false : true;
194 }
195
si7034_i2c_write(uint8_t data,uint8_t state)196 static bool si7034_i2c_write(uint8_t data, uint8_t state)
197 {
198 struct I2cTransfer *xfer = allocXfer(state);
199 int ret = -1;
200
201 if (xfer != NULL) {
202 xfer->txrxBuf[0] = data;
203 ret = i2cMasterTx(SI7034A10_I2C_BUS_ID, SI7034A10_I2C_ADDR,
204 xfer->txrxBuf, 1, i2cCallback, xfer);
205 if (ret) {
206 releaseXfer(xfer);
207 return false;
208 }
209 }
210
211 return (ret == -1) ? false : true;
212 }
213
214 /* Sensor Info */
sensorHumiTimerCallback(uint32_t timerId,void * data)215 static void sensorHumiTimerCallback(uint32_t timerId, void *data)
216 {
217 osEnqueuePrivateEvt(EVT_SENSOR_HUMIDITY_TIMER, data, NULL, mTask.tid);
218 }
219
sensorTempTimerCallback(uint32_t timerId,void * data)220 static void sensorTempTimerCallback(uint32_t timerId, void *data)
221 {
222 osEnqueuePrivateEvt(EVT_SENSOR_TEMP_TIMER, data, NULL, mTask.tid);
223 }
224
225 #define DEC_INFO(name, type, axis, inter, samples, rates) \
226 .sensorName = name, \
227 .sensorType = type, \
228 .numAxis = axis, \
229 .interrupt = inter, \
230 .minSamples = samples, \
231 .supportedRates = rates
232
233 static uint32_t si7034Rates[] = {
234 SENSOR_HZ(0.1),
235 SENSOR_HZ(1.0f),
236 SENSOR_HZ(5.0f),
237 SENSOR_HZ(10.0f),
238 SENSOR_HZ(25.0f),
239 0
240 };
241
242 // should match "supported rates in length" and be the timer length for that rate in nanosecs
243 static const uint64_t si7034RatesRateVals[] =
244 {
245 10 * 1000000000ULL,
246 1 * 1000000000ULL,
247 1000000000ULL / 5,
248 1000000000ULL / 10,
249 1000000000ULL / 25,
250 };
251
252
253 static const struct SensorInfo si7034SensorInfo[NUM_OF_SENSOR] =
254 {
255 { DEC_INFO("Humidity", SENS_TYPE_HUMIDITY, NUM_AXIS_EMBEDDED, NANOHUB_INT_NONWAKEUP,
256 300, si7034Rates) },
257 { DEC_INFO("Temperature", SENS_TYPE_AMBIENT_TEMP, NUM_AXIS_EMBEDDED, NANOHUB_INT_NONWAKEUP,
258 20, si7034Rates) },
259 };
260
261 /* Sensor Operations */
humiPower(bool on,void * cookie)262 static bool humiPower(bool on, void *cookie)
263 {
264 DEBUG_PRINT("%s: %d\n", __func__, on);
265
266 if (mTask.humiTimerHandle) {
267 timTimerCancel(mTask.humiTimerHandle);
268 mTask.humiTimerHandle = 0;
269 mTask.humiReading = false;
270 }
271 mTask.humiOn = on;
272 return sensorSignalInternalEvt(mTask.sensors[HUMIDITY].handle,
273 SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0);
274 }
275
humiFwUpload(void * cookie)276 static bool humiFwUpload(void *cookie)
277 {
278 DEBUG_PRINT("%s\n", __func__);
279
280 return sensorSignalInternalEvt(mTask.sensors[HUMIDITY].handle,
281 SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
282 }
283
humiSetRate(uint32_t rate,uint64_t latency,void * cookie)284 static bool humiSetRate(uint32_t rate, uint64_t latency, void *cookie)
285 {
286 DEBUG_PRINT("%s %ld (%lld)\n", __func__, rate, latency);
287
288 if (mTask.humiTimerHandle)
289 timTimerCancel(mTask.humiTimerHandle);
290
291 mTask.humiTimerHandle = timTimerSet(sensorTimerLookupCommon(si7034Rates,
292 si7034RatesRateVals, rate), 0, 50, sensorHumiTimerCallback, NULL, false);
293
294 return sensorSignalInternalEvt(mTask.sensors[HUMIDITY].handle,
295 SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
296 }
297
humiFlush(void * cookie)298 static bool humiFlush(void *cookie)
299 {
300 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HUMIDITY), SENSOR_DATA_EVENT_FLUSH, NULL);
301 }
302
tempPower(bool on,void * cookie)303 static bool tempPower(bool on, void *cookie)
304 {
305 DEBUG_PRINT("%s: %d\n", __func__, on);
306
307 if (mTask.tempTimerHandle) {
308 timTimerCancel(mTask.tempTimerHandle);
309 mTask.tempTimerHandle = 0;
310 mTask.tempReading = false;
311 }
312 mTask.tempOn = on;
313 return sensorSignalInternalEvt(mTask.sensors[TEMP].handle,
314 SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0);
315 }
316
tempFwUpload(void * cookie)317 static bool tempFwUpload(void *cookie)
318 {
319 DEBUG_PRINT("%s\n", __func__);
320
321 return sensorSignalInternalEvt(mTask.sensors[TEMP].handle,
322 SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
323 }
324
tempSetRate(uint32_t rate,uint64_t latency,void * cookie)325 static bool tempSetRate(uint32_t rate, uint64_t latency, void *cookie)
326 {
327 DEBUG_PRINT("%s %ld (%lld)\n", __func__, rate, latency);
328
329 if (mTask.tempTimerHandle)
330 timTimerCancel(mTask.tempTimerHandle);
331
332 mTask.tempTimerHandle = timTimerSet(sensorTimerLookupCommon(si7034Rates,
333 si7034RatesRateVals, rate), 0, 50, sensorTempTimerCallback, NULL, false);
334
335 return sensorSignalInternalEvt(mTask.sensors[TEMP].handle,
336 SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
337 }
338
tempFlush(void * cookie)339 static bool tempFlush(void *cookie)
340 {
341 return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_AMBIENT_TEMP), SENSOR_DATA_EVENT_FLUSH, NULL);
342 }
343
344 #define DEC_OPS(power, firmware, rate, flush, cal, cfg) \
345 .sensorPower = power, \
346 .sensorFirmwareUpload = firmware, \
347 .sensorSetRate = rate, \
348 .sensorFlush = flush, \
349 .sensorCalibrate = cal, \
350 .sensorCfgData = cfg
351
352 static const struct SensorOps si7034SensorOps[NUM_OF_SENSOR] =
353 {
354 { DEC_OPS(humiPower, humiFwUpload, humiSetRate, humiFlush, NULL, NULL) },
355 { DEC_OPS(tempPower, tempFwUpload, tempSetRate, tempFlush, NULL, NULL) },
356 };
357
handleI2cEvent(const void * evtData)358 static void handleI2cEvent(const void *evtData)
359 {
360 struct I2cTransfer *xfer = (struct I2cTransfer *)evtData;
361 union EmbeddedDataPoint sample;
362 uint32_t value;
363 uint8_t i;
364
365 switch (xfer->state) {
366 case SENSOR_BOOT:
367 if (!si7034_i2c_read(SI7034_READID_0_CMD, SI7034_READID_1_CMD, SENSOR_VERIFY_ID)) {
368 DEBUG_PRINT("Not able to read ID\n");
369 return;
370 }
371 break;
372
373 case SENSOR_VERIFY_ID:
374 /* Check the sensor ID */
375 if (xfer->err != 0)
376 return;
377 INFO_PRINT("Device ID = (%02x)\n", xfer->txrxBuf[0]);
378 if ((xfer->txrxBuf[0] != SI7034_ID_SAMPLE) &&
379 (xfer->txrxBuf[0] != SI7034_ID_PROD))
380 break;
381 INFO_PRINT("detected\n");
382 for (i = 0; i < NUM_OF_SENSOR; i++)
383 sensorRegisterInitComplete(mTask.sensors[i].handle);
384
385 /* TEST the environment in standalone mode */
386 if (SI7034_DBG_ENABLED) {
387 mTask.humiOn = mTask.tempOn = true;
388 osEnqueuePrivateEvt(EVT_TEST, NULL, NULL, mTask.tid);
389 }
390 break;
391
392 case SENSOR_READ_SAMPLES:
393 if (mTask.humiOn && mTask.humiReading) {
394 value = ((uint32_t)(xfer->txrxBuf[3]) << 8) | xfer->txrxBuf[4];
395 value = SI7034_HUMIGRADES(value);
396 value = (value > 100000) ? 100000 : value;
397 DEBUG_PRINT("Humidity = %u\n", (unsigned)value);
398 sample.fdata = (float)value / 1000.0f;
399
400 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HUMIDITY), sample.vptr, NULL);
401 }
402
403 if (mTask.tempOn && mTask.tempReading) {
404 value = ((uint32_t)(xfer->txrxBuf[0]) << 8) | xfer->txrxBuf[1];
405 value = SI7034_CENTIGRADES(value);
406 DEBUG_PRINT("Temp = %u\n", (unsigned)value);
407 sample.fdata = (float)value / 1000.0f;
408
409 osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_AMBIENT_TEMP), sample.vptr, NULL);
410 }
411
412 mTask.humiReading = mTask.tempReading = false;
413 break;
414
415 default:
416 break;
417 }
418
419 releaseXfer(xfer);
420 }
421
handleEvent(uint32_t evtType,const void * evtData)422 static void handleEvent(uint32_t evtType, const void* evtData)
423 {
424 switch (evtType) {
425 case EVT_APP_START:
426 osEventUnsubscribe(mTask.tid, EVT_APP_START);
427 si7034_i2c_write(SI7034_RESET_CMD, SENSOR_BOOT);
428 break;
429
430 case EVT_SENSOR_I2C:
431 handleI2cEvent(evtData);
432 break;
433
434 case EVT_SENSOR_HUMIDITY_TIMER:
435 DEBUG_PRINT("EVT_SENSOR_HUMIDITY_TIMER\n");
436
437 if (!mTask.humiOn)
438 break;
439 /* Start sampling for a value */
440 if (!mTask.humiReading && !mTask.tempReading)
441 si7034_i2c_read(SI7034_READDATA_0_CMD, SI7034_READDATA_1_CMD, SENSOR_READ_SAMPLES);
442 mTask.humiReading = true;
443 break;
444
445 case EVT_SENSOR_TEMP_TIMER:
446 DEBUG_PRINT("EVT_SENSOR_TEMP_TIMER\n");
447
448 if (!mTask.tempOn)
449 break;
450 /* Start sampling for a value */
451 if (!mTask.humiReading && !mTask.tempReading)
452 si7034_i2c_read(SI7034_READDATA_0_CMD, SI7034_READDATA_1_CMD, SENSOR_READ_SAMPLES);
453 mTask.tempReading = true;
454 break;
455
456 case EVT_TEST:
457 DEBUG_PRINT("EVT_TEST\n");
458
459 humiSetRate(SENSOR_HZ(1), 0, NULL);
460 tempSetRate(SENSOR_HZ(1), 0, NULL);
461 break;
462
463 default:
464 break;
465 }
466 }
467
startTask(uint32_t task_id)468 static bool startTask(uint32_t task_id)
469 {
470 uint8_t i;
471
472 mTask.tid = task_id;
473
474 DEBUG_PRINT("task started\n");
475
476 mTask.humiOn = mTask.humiReading = false;
477 mTask.tempOn = mTask.tempReading = false;
478
479 /* Init the communication part */
480 i2cMasterRequest(SI7034A10_I2C_BUS_ID, SI7034A10_I2C_SPEED);
481
482 for (i = 0; i < NUM_OF_SENSOR; i++) {
483 mTask.sensors[i].handle =
484 sensorRegister(&si7034SensorInfo[i], &si7034SensorOps[i], NULL, false);
485 }
486
487 osEventSubscribe(mTask.tid, EVT_APP_START);
488
489 return true;
490 }
491
endTask(void)492 static void endTask(void)
493 {
494 uint8_t i;
495
496 DEBUG_PRINT("task ended\n");
497
498 for (i = 0; i < NUM_OF_SENSOR; i++) {
499 sensorUnregister(mTask.sensors[i].handle);
500 }
501 }
502
503 INTERNAL_APP_INIT(SI7034A10_APP_ID, 0, startTask, endTask, handleEvent);
504