sht21: driver for the SHT21 humidity & temp sensor
Change-Id: Ia71168e394a7b260019e74973db6c9d75d3d4482
This commit is contained in:
parent
845aabfe65
commit
3bdd1ae659
8 changed files with 719 additions and 2 deletions
|
@ -31,7 +31,8 @@ case $#:$1 in
|
|||
eepromb2s54 eepromb2s55 eepromb2s56 eepromb2s57 \
|
||||
eepromb3s50 eepromb3s51 eepromb3s52 eepromb3s53 \
|
||||
eepromb3s54 eepromb3s55 eepromb3s56 eepromb3s57 \
|
||||
tsl2550b1s39 tsl2550b2s39 tsl2550b3s39
|
||||
tsl2550b1s39 tsl2550b2s39 tsl2550b3s39 \
|
||||
sht21b1s40 sht21b2s40 sht21b3s40
|
||||
;;
|
||||
0:|1:-\?)
|
||||
cat >&2 <<EOF
|
||||
|
@ -41,6 +42,7 @@ Where key is one of the following:
|
|||
fb0 # Make /dev/fb0
|
||||
i2c-1 i2c-2 i2c-3 # Make /dev/i2c-[1-3]
|
||||
tsl2550b{1,3}s39 # TSL2550 Ambient Light Sensors
|
||||
sht21b{1,3}s40 # SHT21 Relative Humidity and Temperature Sensors
|
||||
fd0 fd1 ... # Floppy devices for drive 0, 1, ...
|
||||
fd0p0 fd1p0 ... # Make floppy partitions fd0p[0-3], fd1p[0-3], ...
|
||||
c0d0 c0d1 ... # Make disks c0d0, c0d1, ...
|
||||
|
@ -315,6 +317,13 @@ do
|
|||
$e mknod tsl2550b${b}s39 c ${m} 0
|
||||
$e chmod 444 tsl2550b${b}s39
|
||||
;;
|
||||
sht21b[1-3]s40)
|
||||
b=`expr $dev : 'sht21b\\(.*\\)s40'` #bus number
|
||||
m=`expr ${b} + 49`
|
||||
$e mknod sht21b${b}s40 c ${m} 0
|
||||
$e chmod 444 sht21b${b}s40
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "$0: don't know about $dev" >&2
|
||||
ex=1
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
./usr/sbin/i2c minix-sys
|
||||
./usr/sbin/lan8710a minix-sys
|
||||
./usr/sbin/random minix-sys
|
||||
./usr/sbin/sht21 minix-sys
|
||||
./usr/sbin/tda19988 minix-sys
|
||||
./usr/sbin/tps65217 minix-sys
|
||||
./usr/sbin/tps65950 minix-sys
|
||||
|
|
|
@ -24,7 +24,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
|
|||
|
||||
.if ${MACHINE_ARCH} == "earm"
|
||||
SUBDIR= cat24c256 fb gpio i2c mmc lan8710a log readclock \
|
||||
tda19988 tps65217 tps65950 tsl2550 tty random
|
||||
sht21 tda19988 tps65217 tps65950 tsl2550 tty random
|
||||
.endif
|
||||
|
||||
.endif # ${MKIMAGEONLY} != "yes"
|
||||
|
|
14
drivers/sht21/Makefile
Normal file
14
drivers/sht21/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Makefile for the sht21 humidity and temp sensor found on the Weather Cape.
|
||||
PROG= sht21
|
||||
SRCS= sht21.c
|
||||
|
||||
DPADD+= ${LIBI2CDRIVER} ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS}
|
||||
LDADD+= -li2cdriver -lchardriver -lsys -ltimers
|
||||
|
||||
MAN=
|
||||
|
||||
BINDIR?= /usr/sbin
|
||||
|
||||
CPPFLAGS+= -I${NETBSDSRCDIR}
|
||||
|
||||
.include <minix.service.mk>
|
67
drivers/sht21/README.txt
Normal file
67
drivers/sht21/README.txt
Normal file
|
@ -0,0 +1,67 @@
|
|||
SHT21 Driver (Relative Humidity and Temperature Sensor)
|
||||
=======================================================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This is the driver for the relative humidity and temperature sensor commonly
|
||||
found on the WeatherCape expansion board for the BeagleBone.
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
This driver implements the character device interface. It supports reading
|
||||
through /dev/sht21b{1,3}s40. When read from, it returns a string containing
|
||||
a data label, a colon, and the sensor value.
|
||||
|
||||
Example output of `cat /dev/sht21b3s40`:
|
||||
|
||||
TEMPERATURE : 35.014
|
||||
HUMIDITY : 25.181
|
||||
|
||||
Temperature is expressed in Celsius (a.k.a. centigrade). Valid values are
|
||||
-40.000 to 125.000.
|
||||
|
||||
Humidity is expressed as a percentage. Valid values are 0.000 to 100.000.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
Intense activity causes the chip to heat up, affecting the temperature reading.
|
||||
In order to prevent the chip from self-heating more than 0.1C, the sensor
|
||||
values will only be read once per second. Subsequent reads within the same
|
||||
second will return cached temperature and humidity values.
|
||||
|
||||
The measurement resolution is configurable in the chip, but this driver just
|
||||
uses the default maximum resolutions (12-bit for Humidity, 14-bit for
|
||||
temperature). It could probably be implemented with an ioctl() or by passing
|
||||
an argument via the service command, but it doesn't seem too useful at this
|
||||
time. See the data sheet for the trade-off between faster conversion time and
|
||||
lower resolution.
|
||||
|
||||
In testing, the temperature sensor reported a value several degrees higher
|
||||
than an indoor thermometer placed nearby. It doesn't appear to be a bug in the
|
||||
driver as the Linux driver reports similar temperature. Additionally, the
|
||||
BMP085 temperature sensor on the same cape reports a temperature about 2
|
||||
degrees lower than the SHT21. This could be due to heat produced by the
|
||||
BeagleBone heating the cape slightly or maybe just a bad chip on the test
|
||||
board.
|
||||
|
||||
Testing the Code
|
||||
----------------
|
||||
|
||||
The driver should have been started by a script in /etc/rc.capes/ If not,
|
||||
this is how you start up an instance:
|
||||
|
||||
cd /dev && MAKEDEV sht21b3s40
|
||||
/bin/service up /usr/sbin/sht21 -label sht21.3.40 -dev /dev/sht21b3s40 \
|
||||
-args 'bus=3 address=0x40'
|
||||
|
||||
Getting the sensor value:
|
||||
|
||||
cat /dev/sht21b3s40
|
||||
|
||||
Killing an instance:
|
||||
|
||||
/bin/service down sht21.3.40
|
||||
|
618
drivers/sht21/sht21.c
Normal file
618
drivers/sht21/sht21.c
Normal file
|
@ -0,0 +1,618 @@
|
|||
/* Driver for the SHT21 Relative Humidity and Temperature Sensor */
|
||||
|
||||
#include <minix/ds.h>
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/i2c.h>
|
||||
#include <minix/i2cdriver.h>
|
||||
#include <minix/chardriver.h>
|
||||
#include <minix/log.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* Device Commands
|
||||
*/
|
||||
|
||||
/*
|
||||
* The trigger commands start a measurement. 'Hold' ties up the bus while the
|
||||
* measurement is being performed while 'no hold' requires the driver to poll
|
||||
* the chip until the data is ready. Hold is faster and requires less message
|
||||
* passing while no hold frees up the bus while the measurement is in progress.
|
||||
* The worst case conversion times are 85 ms for temperature and 29 ms for
|
||||
* humidity. Typical conversion times are about 75% of the worst case times.
|
||||
*
|
||||
* The driver uses the 'hold' versions of the trigger commands.
|
||||
*/
|
||||
#define CMD_TRIG_T_HOLD 0xe3
|
||||
#define CMD_TRIG_RH_HOLD 0xe5
|
||||
#define CMD_TRIG_T_NOHOLD 0xf3
|
||||
#define CMD_TRIG_RH_NOHOLD 0xf5
|
||||
|
||||
/* Read and write the user register contents */
|
||||
#define CMD_WR_USR_REG 0xe6
|
||||
#define CMD_RD_USR_REG 0xe7
|
||||
|
||||
/* Resets the chip */
|
||||
#define CMD_SOFT_RESET 0xfe
|
||||
|
||||
/* Status bits included in the measurement need to be masked in calculation */
|
||||
#define STATUS_BITS_MASK 0x0003
|
||||
|
||||
/*
|
||||
* The user register has some reserved bits that the device changes over
|
||||
* time. The driver must preserve the value of those bits when writing to
|
||||
* the user register.
|
||||
*/
|
||||
#define USR_REG_RESERVED_MASK ((1<<3)|(1<<4)|(1<<5))
|
||||
|
||||
/* End of Battery flag is set when the voltage drops below 2.25V. */
|
||||
#define USR_REG_EOB_MASK (1<<6)
|
||||
|
||||
/* When powered up and communicating, the register should have only the
|
||||
* 'Disable OTP Reload' bit set
|
||||
*/
|
||||
#define EXPECTED_PWR_UP_TEST_VAL (1<<1)
|
||||
|
||||
/* Define some constants for the different sensor types on the chip. */
|
||||
enum sht21_sensors
|
||||
{ SHT21_T, SHT21_RH };
|
||||
|
||||
/* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
|
||||
static struct log log = {
|
||||
.name = "sht21",
|
||||
.log_level = LEVEL_INFO,
|
||||
.log_func = default_log
|
||||
};
|
||||
|
||||
/* device slave address is fixed at 0x40 */
|
||||
static i2c_addr_t valid_addrs[2] = {
|
||||
0x40, 0x00
|
||||
};
|
||||
|
||||
/* Buffer to store output string returned when reading from device file. */
|
||||
#define BUFFER_LEN 64
|
||||
char buffer[BUFFER_LEN + 1];
|
||||
|
||||
/* the bus that this device is on (counting starting at 1) */
|
||||
static uint32_t bus;
|
||||
|
||||
/* slave address of the device */
|
||||
static i2c_addr_t address;
|
||||
|
||||
/* endpoint for the driver for the bus itself. */
|
||||
static endpoint_t bus_endpoint;
|
||||
|
||||
/* Sampling causes self-heating. To limit the self-heating to < 0.1C, the
|
||||
* data sheet suggests limiting sampling to 2 samples per second. Since
|
||||
* the driver samples temperature and relative humidity at the same time,
|
||||
* it's measure function does at most 1 pair of samples per second. It uses
|
||||
* this timestamp to see if a measurement was taken less than 1 second ago.
|
||||
*/
|
||||
static time_t last_sample_time = 0;
|
||||
|
||||
/*
|
||||
* Cache temperature and relative humidity readings. These values are returned
|
||||
* when the last_sample_time == current_time to keep the chip activity below
|
||||
* 10% to help prevent self-heating.
|
||||
*/
|
||||
static int32_t cached_t = 0.0;
|
||||
static int32_t cached_rh = 0.0;
|
||||
|
||||
/*
|
||||
* An 8-bit CRC is used to validate the readings.
|
||||
*/
|
||||
#define CRC8_POLYNOMIAL 0x131
|
||||
#define CRC8_INITIAL_CRC 0x00
|
||||
|
||||
/* main driver functions */
|
||||
static int sht21_init(void);
|
||||
static int soft_reset(void);
|
||||
static int usr_reg_read(uint8_t * usr_reg_val);
|
||||
static int sensor_read(enum sht21_sensors sensor, int32_t * measurement);
|
||||
static int measure(void);
|
||||
|
||||
/* CRC functions */
|
||||
static uint8_t crc8(uint8_t crc, uint8_t byte);
|
||||
static int checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc);
|
||||
|
||||
/* libchardriver callbacks */
|
||||
static struct device *sht21_prepare(dev_t UNUSED(dev));
|
||||
static int sht21_transfer(endpoint_t endpt, int opcode, u64_t position,
|
||||
iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
|
||||
unsigned int UNUSED(flags));
|
||||
static int sht21_other(message * m);
|
||||
|
||||
/* SEF functions */
|
||||
static int sef_cb_lu_state_save(int);
|
||||
static int lu_state_restore(void);
|
||||
static int sef_cb_init(int type, sef_init_info_t * info);
|
||||
static void sef_local_startup(void);
|
||||
|
||||
/* Entry points to this driver from libchardriver. */
|
||||
static struct chardriver sht21_tab = {
|
||||
.cdr_open = do_nop,
|
||||
.cdr_close = do_nop,
|
||||
.cdr_ioctl = nop_ioctl,
|
||||
.cdr_prepare = sht21_prepare,
|
||||
.cdr_transfer = sht21_transfer,
|
||||
.cdr_cleanup = nop_cleanup,
|
||||
.cdr_alarm = nop_alarm,
|
||||
.cdr_cancel = nop_cancel,
|
||||
.cdr_select = nop_select,
|
||||
.cdr_other = sht21_other
|
||||
};
|
||||
|
||||
static struct device sht21_device = {
|
||||
.dv_base = 0,
|
||||
.dv_size = 0
|
||||
};
|
||||
|
||||
/*
|
||||
* Sends the chip a soft reset command and waits 15 ms for the chip to reset.
|
||||
*/
|
||||
static int
|
||||
soft_reset(void)
|
||||
{
|
||||
int r;
|
||||
minix_i2c_ioctl_exec_t ioctl_exec;
|
||||
|
||||
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
|
||||
|
||||
/* Write to chip */
|
||||
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
|
||||
ioctl_exec.iie_addr = address;
|
||||
|
||||
/* No command bytes for writing to this chip */
|
||||
ioctl_exec.iie_cmdlen = 0;
|
||||
|
||||
/* Set the byte to write */
|
||||
ioctl_exec.iie_buf[0] = CMD_SOFT_RESET;
|
||||
ioctl_exec.iie_buflen = 1;
|
||||
|
||||
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "soft_reset() failed (r=%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* soft reset takes up to 15 ms to complete. */
|
||||
micro_delay(15000);
|
||||
|
||||
log_debug(&log, "Soft Reset Complete\n");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain the contents of the usr register and store it in usr_reg_val.
|
||||
*/
|
||||
static int
|
||||
usr_reg_read(uint8_t * usr_reg_val)
|
||||
{
|
||||
int r;
|
||||
minix_i2c_ioctl_exec_t ioctl_exec;
|
||||
|
||||
if (usr_reg_val == NULL) {
|
||||
log_warn(&log, "usr_reg_read() called with NULL pointer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
|
||||
|
||||
/* Read from chip */
|
||||
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
|
||||
ioctl_exec.iie_addr = address;
|
||||
|
||||
/* Send the read from user register command */
|
||||
ioctl_exec.iie_cmd[0] = CMD_RD_USR_REG;
|
||||
ioctl_exec.iie_cmdlen = 1;
|
||||
|
||||
/* Read the register contents into iie_buf */
|
||||
ioctl_exec.iie_buflen = 1;
|
||||
|
||||
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "usr_reg_read() failed (r=%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*usr_reg_val = ioctl_exec.iie_buf[0];
|
||||
|
||||
log_trace(&log, "Read 0x%x from USR_REG\n", *usr_reg_val);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a soft reset and reads the contents of the user register to ensure
|
||||
* that the chip is in a good state and working properly.
|
||||
*/
|
||||
static int
|
||||
sht21_init(void)
|
||||
{
|
||||
int r;
|
||||
uint8_t usr_reg_val;
|
||||
|
||||
r = soft_reset();
|
||||
if (r != OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = usr_reg_read(&usr_reg_val);
|
||||
if (r != OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for End of Battery flag. */
|
||||
if ((usr_reg_val & USR_REG_EOB_MASK) == USR_REG_EOB_MASK) {
|
||||
log_warn(&log, "End of Battery Alarm\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check that the non-reserved bits are in the default state. */
|
||||
if ((usr_reg_val & ~USR_REG_RESERVED_MASK) != EXPECTED_PWR_UP_TEST_VAL) {
|
||||
log_warn(&log, "USR_REG has non-default values after reset\n");
|
||||
log_warn(&log, "Expected 0x%x | Actual 0x%x",
|
||||
EXPECTED_PWR_UP_TEST_VAL,
|
||||
(usr_reg_val & ~USR_REG_RESERVED_MASK));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the sensor, check the CRC, convert the ADC value into the final
|
||||
* representation, and store the result in measurement.
|
||||
*/
|
||||
static int
|
||||
sensor_read(enum sht21_sensors sensor, int32_t * measurement)
|
||||
{
|
||||
int r;
|
||||
uint8_t cmd;
|
||||
uint8_t val_hi, val_lo;
|
||||
uint16_t val;
|
||||
uint8_t expected_crc;
|
||||
minix_i2c_ioctl_exec_t ioctl_exec;
|
||||
|
||||
switch (sensor) {
|
||||
case SHT21_T:
|
||||
cmd = CMD_TRIG_T_HOLD;
|
||||
break;
|
||||
case SHT21_RH:
|
||||
cmd = CMD_TRIG_RH_HOLD;
|
||||
break;
|
||||
default:
|
||||
log_warn(&log, "sensor_read() called with bad sensor type.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (measurement == NULL) {
|
||||
log_warn(&log, "sensor_read() called with NULL pointer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
|
||||
|
||||
/* Read from chip */
|
||||
ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
|
||||
ioctl_exec.iie_addr = address;
|
||||
|
||||
/* Send the trigger command */
|
||||
ioctl_exec.iie_cmd[0] = cmd;
|
||||
ioctl_exec.iie_cmdlen = 1;
|
||||
|
||||
/* Read the results */
|
||||
ioctl_exec.iie_buflen = 3;
|
||||
|
||||
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "sensor_read() failed (r=%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
expected_crc = ioctl_exec.iie_buf[2];
|
||||
|
||||
r = checksum(ioctl_exec.iie_buf, 2, expected_crc);
|
||||
if (r != OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
val_hi = ioctl_exec.iie_buf[0];
|
||||
val_lo = ioctl_exec.iie_buf[1];
|
||||
val = ((val_hi << 8) | val_lo);
|
||||
|
||||
val &= ~STATUS_BITS_MASK; /* clear status bits */
|
||||
|
||||
log_debug(&log, "Read VAL:0x%x CRC:0x%x\n", val, expected_crc);
|
||||
|
||||
/* Convert the ADC value to the actual value. */
|
||||
if (cmd == CMD_TRIG_T_HOLD) {
|
||||
*measurement = (int32_t)
|
||||
((-46.85 + ((175.72 / 65536) * ((float) val))) * 1000.0);
|
||||
log_debug(&log, "Measured Temperature %d mC\n", *measurement);
|
||||
} else if (cmd == CMD_TRIG_RH_HOLD) {
|
||||
*measurement =
|
||||
(int32_t) ((-6.0 +
|
||||
((125.0 / 65536) * ((float) val))) * 1000.0);
|
||||
log_debug(&log, "Measured Humidity %d m%%\n", *measurement);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
measure(void)
|
||||
{
|
||||
int r;
|
||||
time_t sample_time;
|
||||
int32_t t, rh;
|
||||
|
||||
log_debug(&log, "Taking a measurement...");
|
||||
|
||||
sample_time = time(NULL);
|
||||
if (sample_time == last_sample_time) {
|
||||
log_debug(&log, "measure() called too soon, using cache.\n");
|
||||
return OK;
|
||||
}
|
||||
|
||||
r = sensor_read(SHT21_T, &t);
|
||||
if (r != OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = sensor_read(SHT21_RH, &rh);
|
||||
if (r != OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save measured values */
|
||||
cached_t = t;
|
||||
cached_rh = rh;
|
||||
last_sample_time = time(NULL);
|
||||
|
||||
log_debug(&log, "Measurement completed\n");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an updated checksum for the given crc and byte.
|
||||
*/
|
||||
static uint8_t
|
||||
crc8(uint8_t crc, uint8_t byte)
|
||||
{
|
||||
int i;
|
||||
|
||||
crc ^= byte;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
|
||||
if ((crc & 0x80) == 0x80) {
|
||||
crc = (crc << 1) ^ CRC8_POLYNOMIAL;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the CRC of an array of bytes and compare it to expected_crc.
|
||||
* If the computed CRC matches expected_crc, then return OK, otherwise EINVAL.
|
||||
*/
|
||||
static int
|
||||
checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc)
|
||||
{
|
||||
int i;
|
||||
uint8_t crc;
|
||||
|
||||
crc = CRC8_INITIAL_CRC;
|
||||
|
||||
log_debug(&log, "Checking CRC\n");
|
||||
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
crc = crc8(crc, bytes[i]);
|
||||
}
|
||||
|
||||
if (crc == expected_crc) {
|
||||
log_debug(&log, "CRC OK\n");
|
||||
return OK;
|
||||
} else {
|
||||
log_warn(&log,
|
||||
"Bad CRC -- Computed CRC: 0x%x | Expected CRC: 0x%x\n",
|
||||
crc, expected_crc);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct device *
|
||||
sht21_prepare(dev_t UNUSED(dev))
|
||||
{
|
||||
return &sht21_device;
|
||||
}
|
||||
|
||||
static int
|
||||
sht21_transfer(endpoint_t endpt, int opcode, u64_t position,
|
||||
iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
|
||||
unsigned int UNUSED(flags))
|
||||
{
|
||||
int bytes, r;
|
||||
|
||||
r = measure();
|
||||
if (r != OK) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
memset(buffer, '\0', BUFFER_LEN + 1);
|
||||
snprintf(buffer, BUFFER_LEN, "%-16s: %d.%03d\n%-16s: %d.%03d\n",
|
||||
"TEMPERATURE", cached_t / 1000, cached_t % 1000, "HUMIDITY",
|
||||
cached_rh / 1000, cached_rh % 1000);
|
||||
|
||||
log_trace(&log, "%s", buffer);
|
||||
|
||||
bytes = strlen(buffer) - position < iov->iov_size ?
|
||||
strlen(buffer) - position : iov->iov_size;
|
||||
|
||||
if (bytes <= 0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case DEV_GATHER_S:
|
||||
r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0,
|
||||
(vir_bytes) (buffer + position), bytes);
|
||||
iov->iov_size -= bytes;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
sht21_other(message * m)
|
||||
{
|
||||
int r;
|
||||
|
||||
switch (m->m_type) {
|
||||
case NOTIFY_MESSAGE:
|
||||
if (m->m_source == DS_PROC_NR) {
|
||||
log_debug(&log,
|
||||
"bus driver changed state, update endpoint\n");
|
||||
i2cdriver_handle_bus_update(&bus_endpoint, bus,
|
||||
address);
|
||||
}
|
||||
r = OK;
|
||||
break;
|
||||
default:
|
||||
log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
|
||||
r = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
sef_cb_lu_state_save(int UNUSED(state))
|
||||
{
|
||||
ds_publish_u32("bus", bus, DSF_OVERWRITE);
|
||||
ds_publish_u32("address", address, DSF_OVERWRITE);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
lu_state_restore(void)
|
||||
{
|
||||
/* Restore the state. */
|
||||
u32_t value;
|
||||
|
||||
ds_retrieve_u32("bus", &value);
|
||||
ds_delete_u32("bus");
|
||||
bus = (int) value;
|
||||
|
||||
ds_retrieve_u32("address", &value);
|
||||
ds_delete_u32("address");
|
||||
address = (int) value;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int
|
||||
sef_cb_init(int type, sef_init_info_t * UNUSED(info))
|
||||
{
|
||||
int r;
|
||||
|
||||
if (type == SEF_INIT_LU) {
|
||||
/* Restore the state. */
|
||||
lu_state_restore();
|
||||
}
|
||||
|
||||
/* look-up the endpoint for the bus driver */
|
||||
bus_endpoint = i2cdriver_bus_endpoint(bus);
|
||||
if (bus_endpoint == 0) {
|
||||
log_warn(&log, "Couldn't find bus driver.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* claim the device */
|
||||
r = i2cdriver_reserve_device(bus_endpoint, address);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
|
||||
address, r);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
r = sht21_init();
|
||||
if (r != OK) {
|
||||
log_warn(&log, "Device Init Failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (type != SEF_INIT_LU) {
|
||||
|
||||
/* sign up for updates about the i2c bus going down/up */
|
||||
r = i2cdriver_subscribe_bus_updates(bus);
|
||||
if (r != OK) {
|
||||
log_warn(&log, "Couldn't subscribe to bus updates\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
i2cdriver_announce(bus);
|
||||
log_debug(&log, "announced\n");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void
|
||||
sef_local_startup(void)
|
||||
{
|
||||
/*
|
||||
* Register init callbacks. Use the same function for all event types
|
||||
*/
|
||||
sef_setcb_init_fresh(sef_cb_init);
|
||||
sef_setcb_init_lu(sef_cb_init);
|
||||
sef_setcb_init_restart(sef_cb_init);
|
||||
|
||||
/*
|
||||
* Register live update callbacks.
|
||||
*/
|
||||
/* Agree to update immediately when LU is requested in a valid state. */
|
||||
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
|
||||
/* Support live update starting from any standard state. */
|
||||
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
|
||||
/* Register a custom routine to save the state. */
|
||||
sef_setcb_lu_state_save(sef_cb_lu_state_save);
|
||||
|
||||
/* Let SEF perform startup. */
|
||||
sef_startup();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int r;
|
||||
|
||||
env_setargs(argc, argv);
|
||||
|
||||
r = i2cdriver_env_parse(&bus, &address, valid_addrs);
|
||||
if (r < 0) {
|
||||
log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n");
|
||||
log_warn(&log, "Example -args 'bus=1 address=0x40'\n");
|
||||
return EXIT_FAILURE;
|
||||
} else if (r > 0) {
|
||||
log_warn(&log,
|
||||
"Invalid slave address for device, expecting 0x40\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
sef_local_startup();
|
||||
|
||||
chardriver_task(&sht21_tab, CHARDRIVER_SYNC);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -641,6 +641,11 @@ service tsl2550
|
|||
ipc SYSTEM RS DS i2c;
|
||||
};
|
||||
|
||||
service sht21
|
||||
{
|
||||
ipc SYSTEM RS DS i2c;
|
||||
};
|
||||
|
||||
service vbox
|
||||
{
|
||||
system
|
||||
|
|
|
@ -69,6 +69,9 @@ enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY,
|
|||
#define TSL2550B1S39_MAJOR 47 /* 47 = /dev/tsl2550b1s39 (tsl2550) */
|
||||
#define TSL2550B2S39_MAJOR 48 /* 48 = /dev/tsl2550b2s39 (tsl2550) */
|
||||
#define TSL2550B3S39_MAJOR 49 /* 49 = /dev/tsl2550b3s39 (tsl2550) */
|
||||
#define SHT21B1S40_MAJOR 50 /* 50 = /dev/sht21b1s40 (sht21) */
|
||||
#define SHT21B2S40_MAJOR 51 /* 51 = /dev/sht21b2s40 (sht21) */
|
||||
#define SHT21B3S40_MAJOR 52 /* 52 = /dev/sht21b3s40 (sht21) */
|
||||
|
||||
|
||||
/* Minor device numbers for memory driver. */
|
||||
|
|
Loading…
Reference in a new issue