bmp085: driver for the BMP085 temp&pressure sensor

Change-Id: I5c297a7f4f8cea2549e537df30a5c7bf5b9d8b51
This commit is contained in:
Thomas Cort 2013-08-20 10:43:51 -04:00
parent 3bdd1ae659
commit 471dc65ada
8 changed files with 893 additions and 3 deletions

View file

@ -32,7 +32,8 @@ case $#:$1 in
eepromb3s50 eepromb3s51 eepromb3s52 eepromb3s53 \
eepromb3s54 eepromb3s55 eepromb3s56 eepromb3s57 \
tsl2550b1s39 tsl2550b2s39 tsl2550b3s39 \
sht21b1s40 sht21b2s40 sht21b3s40
sht21b1s40 sht21b2s40 sht21b3s40 \
bmp085b1s77 bmp085b2s77 bmp085b3s77
;;
0:|1:-\?)
cat >&2 <<EOF
@ -43,6 +44,7 @@ Where key is one of the following:
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
bmp085b{1,3}s77 # BMP085 Pressure 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, ...
@ -323,7 +325,12 @@ do
$e mknod sht21b${b}s40 c ${m} 0
$e chmod 444 sht21b${b}s40
;;
bmp085b[1-3]s77)
b=`expr $dev : 'bmp085b\\(.*\\)s77'` #bus number
m=`expr ${b} + 52`
$e mknod bmp085b${b}s77 c ${m} 0
$e chmod 444 bmp085b${b}s77
;;
*)
echo "$0: don't know about $dev" >&2
ex=1

View file

@ -105,6 +105,7 @@
./usr/lib/libpadconf_pic.a minix-sys
./usr/man/man1/eepromread.1 minix-sys
./usr/mdec minix-sys
./usr/sbin/bmp085 minix-sys
./usr/sbin/cat24c256 minix-sys
./usr/sbin/fb minix-sys
./usr/sbin/gpio minix-sys

View file

@ -23,7 +23,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
.endif
.if ${MACHINE_ARCH} == "earm"
SUBDIR= cat24c256 fb gpio i2c mmc lan8710a log readclock \
SUBDIR= bmp085 cat24c256 fb gpio i2c mmc lan8710a log readclock \
sht21 tda19988 tps65217 tps65950 tsl2550 tty random
.endif

14
drivers/bmp085/Makefile Normal file
View file

@ -0,0 +1,14 @@
# Makefile for the bmp085 pressure and temp sensor found on the Weather Cape.
PROG= bmp085
SRCS= bmp085.c
DPADD+= ${LIBI2CDRIVER} ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS}
LDADD+= -li2cdriver -lchardriver -lsys -ltimers
MAN=
BINDIR?= /usr/sbin
CPPFLAGS+= -I${NETBSDSRCDIR}
.include <minix.service.mk>

63
drivers/bmp085/README.txt Normal file
View file

@ -0,0 +1,63 @@
BMP085 Driver (Pressure and Temperature Sensor)
===============================================
Overview
--------
This is the driver for the pressure 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/bmp085b{1,3}s77. When read from, it returns a string containing
a data label, a colon, and the sensor value.
Example output of `cat /dev/bmp085b3s77`:
TEMPERATURE : 23.1
PRESSURE : 69964
Temperature is expressed in Celsius (a.k.a. centigrade). The resolution is
0.1C.
Pressure is expressed in Pascals. Valid values are 30000 to 110000.
The resolution is 3 Pa.
Limitations
-----------
The measurement resolution is configurable in the chip, but this driver just
uses standard mode. 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-offs between conversion time,
power consumption, and resolution.
While only the BMP085 is supported at present, the BMP085's predecessor,
SMD500, should be easy to support in this driver with some small changes
to the calculations and coefficients.
As with the SHT21's temperature sensor, the BMP085's temperature sensor
appears to be heated a couple of degrees by the BeagleBone. After power-on,
the readings rise slightly and then level off a few degrees above room
temperature.
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 bmp085b3s77
/bin/service up /usr/sbin/bmp085 -label bmp085.3.77 -dev /dev/bmp085b3s77 \
-args 'bus=3 address=0x77'
Getting the sensor value:
cat /dev/bmp085b3s77
Killing an instance:
/bin/service down bmp085.3.77

After

Width:  |  Height:  |  Size: 1.9 KiB

797
drivers/bmp085/bmp085.c Normal file
View file

@ -0,0 +1,797 @@
/* Driver for the BMP085 Preassure 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>
/* Control Register for triggering a measurement */
#define CTRL_REG 0xf4
/* temperature sensor - it only has one 'mode' - conversion time 4.5 ms */
#define CMD_TRIG_T 0x2e
#define UDELAY_T (4500)
/* pressure sensor - ultra low power mode - conversion time 4.5 ms */
#define CMD_TRIG_P_ULP 0x34
#define MODE_ULP 0x00
#define UDELAY_ULP (4500)
/* pressure sensor - standard mode - conversion time 7.5 ms */
#define CMD_TRIG_P_STD 0x74
#define MODE_STD 0x01
#define UDELAY_STD (7500)
/* pressure sensor - high resolution mode - conversion time 13.5 ms */
#define CMD_TRIG_P_HR 0xb4
#define MODE_HR 0x02
#define UDELAY_HR (13500)
/* pressure sensor - ultra high resolution mode - conversion time 25.5 ms */
#define CMD_TRIG_P_UHR 0xf4
#define MODE_UHR 0x03
#define UDELAY_UHR (25500)
/* Values for the different modes of operation */
struct pressure_cmd
{
uint8_t cmd;
uint8_t mode;
uint16_t udelay;
};
/* Table of available modes and their parameters. */
static struct pressure_cmd pressure_cmds[4] = {
{CMD_TRIG_P_ULP, MODE_ULP, UDELAY_ULP},
{CMD_TRIG_P_STD, MODE_STD, UDELAY_STD},
{CMD_TRIG_P_HR, MODE_HR, UDELAY_HR},
{CMD_TRIG_P_UHR, MODE_UHR, UDELAY_UHR}
};
/* Default to standard mode.
* There isn't code to configure the resolution at runtime, but it should
* easy to implement by setting p_cmd to the right element of pressure_cmds.
*/
static struct pressure_cmd *p_cmd = &pressure_cmds[MODE_STD];
/* Chip Identification */
#define CHIPID_REG 0xd0
#define BMP085_CHIPID 0x55
/*
* There is also a version register at 0xd1, but documentation seems to be
* lacking. The sample code says high 4 bytes are AL version and low 4 are ML.
*/
/* Calibration coefficients
*
* These are unique to each chip and must be read when starting the driver.
* Validate them by checking that none are 0x0000 nor 0xffff. Types and
* names are from the datasheet.
*/
struct calibration
{
int16_t ac1;
int16_t ac2;
int16_t ac3;
uint16_t ac4;
uint16_t ac5;
uint16_t ac6;
int16_t b1;
int16_t b2;
int16_t mb;
int16_t mc;
int16_t md;
} cal;
/* Register locations for calibration coefficients */
#define AC1_MSB_REG 0xaa
#define AC1_LSB_REG 0xab
#define AC2_MSB_REG 0xac
#define AC2_LSB_REG 0xad
#define AC3_MSB_REG 0xae
#define AC3_LSB_REG 0xaf
#define AC4_MSB_REG 0xb0
#define AC4_LSB_REG 0xb1
#define AC5_MSB_REG 0xb2
#define AC5_LSB_REG 0xb3
#define AC6_MSB_REG 0xb4
#define AC6_LSB_REG 0xb5
#define B1_MSB_REG 0xb6
#define B1_LSB_REG 0xb7
#define B2_MSB_REG 0xb8
#define B2_LSB_REG 0xb9
#define MB_MSB_REG 0xba
#define MB_LSB_REG 0xbb
#define MC_MSB_REG 0xbc
#define MC_LSB_REG 0xbd
#define MD_MSB_REG 0xbe
#define MD_LSB_REG 0xbf
#define CAL_COEF_FIRST AC1_MSB_REG
#define CAL_COEF_LAST MD_LSB_REG
#define CAL_COEF_IS_VALID(x) (x != 0x0000 && x != 0xffff)
#define SENSOR_VAL_MSB_REG 0xf6
#define SENSOR_VAL_LSB_REG 0xf7
#define SENSOR_VAL_XLSB_REG 0xf8
/* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
static struct log log = {
.name = "bmp085",
.log_level = LEVEL_INFO,
.log_func = default_log
};
/* Only one valid slave address. It isn't configurable. */
static i2c_addr_t valid_addrs[5] = {
0x77, 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;
/* main device functions */
static int bmp085_init(void);
static int version_check(void);
static int read_cal_coef(void);
static int measure(int32_t * temperature, int32_t * pressure);
/* libchardriver callbacks */
static struct device *bmp085_prepare(dev_t UNUSED(dev));
static int bmp085_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 bmp085_other(message * m);
/* i2c bus access */
static int reg_read(uint8_t reg, uint8_t * val);
static int reg_read16(uint8_t reg, uint16_t * val);
static int reg_read24(uint8_t reg, uint32_t * val);
static int reg_write(uint8_t reg, uint8_t val);
/* SEF Function */
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 bmp085_tab = {
.cdr_open = do_nop,
.cdr_close = do_nop,
.cdr_ioctl = nop_ioctl,
.cdr_prepare = bmp085_prepare,
.cdr_transfer = bmp085_transfer,
.cdr_cleanup = nop_cleanup,
.cdr_alarm = nop_alarm,
.cdr_cancel = nop_cancel,
.cdr_select = nop_select,
.cdr_other = bmp085_other
};
static struct device bmp085_device = {
.dv_base = 0,
.dv_size = 0
};
static int
reg_read(uint8_t reg, uint8_t * val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "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;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 1 byte */
ioctl_exec.iie_buflen = 1;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read() failed (r=%d)\n", r);
return -1;
}
*val = ioctl_exec.iie_buf[0];
log_trace(&log, "Read 0x%x from reg 0x%x\n", *val, reg);
return OK;
}
static int
reg_read16(uint8_t reg, uint16_t * val)
{
int r;
uint8_t msb, lsb;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "reg_read16() 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;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 2 bytes */
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read16() failed (r=%d)\n", r);
return -1;
}
msb = ioctl_exec.iie_buf[0];
lsb = ioctl_exec.iie_buf[1];
*val = ((msb << 8) | lsb);
log_trace(&log, "Read 0x%x from reg 0x%x\n", *val, reg);
return OK;
}
static int
reg_read24(uint8_t reg, uint32_t * val)
{
int r;
uint8_t msb, lsb, xlsb;
minix_i2c_ioctl_exec_t ioctl_exec;
if (val == NULL) {
log_warn(&log, "reg_read24() 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;
/* write the register address */
ioctl_exec.iie_cmd[0] = reg;
ioctl_exec.iie_cmdlen = 1;
/* read 3 bytes */
ioctl_exec.iie_buflen = 3;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_read24() failed (r=%d)\n", r);
return -1;
}
msb = ioctl_exec.iie_buf[0];
lsb = ioctl_exec.iie_buf[1];
xlsb = ioctl_exec.iie_buf[2];
*val = ((msb << 16) | (lsb << 8) | xlsb);
log_trace(&log, "Read 0x%x from reg 0x%x\n", *val, reg);
return OK;
}
static int
reg_write(uint8_t reg, uint8_t val)
{
int r;
minix_i2c_ioctl_exec_t ioctl_exec;
memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
/* Read from chip */
ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
ioctl_exec.iie_addr = address;
/* no commands here */
ioctl_exec.iie_cmdlen = 0;
/* write register and value */
ioctl_exec.iie_buf[0] = reg;
ioctl_exec.iie_buf[1] = val;
ioctl_exec.iie_buflen = 2;
r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
if (r != OK) {
log_warn(&log, "reg_write() failed (r=%d)\n", r);
return -1;
}
log_trace(&log, "Wrote 0x%x to reg 0x%x\n", val, reg);
return OK;
}
/*
* Initialize the driver. Checks the CHIPID against a known value and
* reads the calibration coefficients.
*
* The chip does have a soft reset register (0xe0), but there
* doesn't appear to be any documentation or example usage for it.
*/
static int
bmp085_init(void)
{
int r;
int32_t t, p;
r = version_check();
if (r != OK) {
return EXIT_FAILURE;
}
r = read_cal_coef();
if (r != OK) {
return EXIT_FAILURE;
}
return OK;
}
static int
version_check(void)
{
int r;
uint8_t chipid;
r = reg_read(CHIPID_REG, &chipid);
if (r != OK) {
log_warn(&log, "Couldn't read CHIPID\n");
return -1;
}
if (chipid != BMP085_CHIPID) {
log_warn(&log, "Bad CHIPID\n");
return -1;
}
log_debug(&log, "CHIPID OK\n");
return OK;
}
/*
* Read the calibration data from the chip. Each individual chip has a unique
* set of calibration parameters that get used to compute the true temperature
* and pressure.
*/
static int
read_cal_coef(void)
{
int r;
/* Populate the calibration struct with values */
r = reg_read16(AC1_MSB_REG, &cal.ac1);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac1 = %d\n", cal.ac1);
r = reg_read16(AC2_MSB_REG, &cal.ac2);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac2 = %d\n", cal.ac2);
r = reg_read16(AC3_MSB_REG, &cal.ac3);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac3 = %d\n", cal.ac3);
r = reg_read16(AC4_MSB_REG, &cal.ac4);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac4 = %u\n", cal.ac4);
r = reg_read16(AC5_MSB_REG, &cal.ac5);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac5 = %u\n", cal.ac5);
r = reg_read16(AC6_MSB_REG, &cal.ac6);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.ac6 = %u\n", cal.ac6);
r = reg_read16(B1_MSB_REG, &cal.b1);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.b1 = %d\n", cal.b1);
r = reg_read16(B2_MSB_REG, &cal.b2);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.b2 = %d\n", cal.b2);
r = reg_read16(MB_MSB_REG, &cal.mb);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.mb = %d\n", cal.mb);
r = reg_read16(MC_MSB_REG, &cal.mc);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.mc = %d\n", cal.mc);
r = reg_read16(MD_MSB_REG, &cal.md);
if (r != OK) {
return -1;
}
log_debug(&log, "cal.md = %d\n", cal.md);
/* Validate. Data sheet says values should not be 0x0000 nor 0xffff */
if (!CAL_COEF_IS_VALID(cal.ac1) ||
!CAL_COEF_IS_VALID(cal.ac2) ||
!CAL_COEF_IS_VALID(cal.ac3) ||
!CAL_COEF_IS_VALID(cal.ac4) ||
!CAL_COEF_IS_VALID(cal.ac5) ||
!CAL_COEF_IS_VALID(cal.ac6) ||
!CAL_COEF_IS_VALID(cal.b1) ||
!CAL_COEF_IS_VALID(cal.b2) ||
!CAL_COEF_IS_VALID(cal.mb) ||
!CAL_COEF_IS_VALID(cal.mc) || !CAL_COEF_IS_VALID(cal.md)) {
log_warn(&log, "Invalid calibration data found on chip.\n");
return -1;
}
log_debug(&log, "Read Cal Data OK\n");
return OK;
}
/*
* Measure the uncompensated temperature and uncompensated pressure from the
* chip and apply the formulas to determine the true temperature and pressure.
* Note, the data sheet is light on the details when it comes to defining the
* meaning of each variable, so this function has a lot of cryptic names in it.
*/
static int
measure(int32_t * temperature, int32_t * pressure)
{
int r;
/* Types are given in the datasheet. Their long translates to 32-bits */
int16_t ut; /* uncompensated temperature */
int32_t up; /* uncompensated pressure */
int32_t x1;
int32_t x2;
int32_t x3;
int32_t b3;
uint32_t b4;
int32_t b5;
int32_t b6;
uint32_t b7;
int32_t t; /* true temperature (in 0.1C) */
int32_t p; /* true pressure (in Pa) */
log_debug(&log, "Triggering Temp Reading...\n");
/* trigger temperature reading */
r = reg_write(CTRL_REG, CMD_TRIG_T);
if (r != OK) {
log_warn(&log, "Failed to trigger temperature reading.\n");
return -1;
}
micro_delay(UDELAY_T);
/* trigger temperature reading */
r = reg_write(CTRL_REG, CMD_TRIG_T);
if (r != OK) {
log_warn(&log, "Failed to trigger temperature reading.\n");
return -1;
}
/* wait for sampling to be completed. */
micro_delay(UDELAY_T);
/* read the uncompensated temperature */
r = reg_read16(SENSOR_VAL_MSB_REG, &ut);
if (r != OK) {
log_warn(&log, "Failed to read temperature.\n");
return -1;
}
log_debug(&log, "ut = %d\n", ut);
log_debug(&log, "Triggering Pressure Reading...\n");
/* trigger pressure reading */
r = reg_write(CTRL_REG, p_cmd->cmd);
if (r != OK) {
log_warn(&log, "Failed to trigger pressure reading.\n");
return -1;
}
/* wait for sampling to be completed. */
micro_delay(p_cmd->udelay);
/* read the uncompensated pressure */
r = reg_read24(SENSOR_VAL_MSB_REG, &up);
if (r != OK) {
log_warn(&log, "Failed to read pressure.\n");
return -1;
}
/* shift by 8 - oversampling setting */
up = (up >> (8 - p_cmd->mode));
log_debug(&log, "up = %d\n", up);
/* convert uncompensated temperature to true temperature */
x1 = ((ut - cal.ac6) * cal.ac5) / (1 << 15);
x2 = (cal.mc * (1 << 11)) / (x1 + cal.md);
b5 = x1 + x2;
t = (b5 + 8) / (1 << 4);
/* save the result */
*temperature = t;
log_debug(&log, "t = %d\n", t);
/* Convert uncompensated pressure to true pressure.
* This is really how the data sheet suggests doing it.
* There is no alternative approach suggested. Other open
* source drivers I've found use this method.
*/
b6 = b5 - 4000;
x1 = ((cal.b2 * ((b6 * b6) >> 12)) >> 11);
x2 = ((cal.ac2 * b6) >> 11);
x3 = x1 + x2;
b3 = (((((cal.ac1 * 4) + x3) << p_cmd->mode) + 2) >> 2);
x1 = ((cal.ac3 * b6) >> 13);
x2 = ((cal.b1 * ((b6 * b6) >> 12)) >> 16);
x3 = (((x1 + x2) + 2) >> 2);
b4 = ((cal.ac4 * ((uint32_t) (x3 + 32768))) >> 15);
b7 = ((uint32_t) up - b3) * (50000 >> p_cmd->mode);
p = (b7 < 0x80000000) ? (b7 * 2) / b4 : (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = ((x1 * 3038) >> 16);
x2 = ((-7357 * p) >> 16);
p = p + ((x1 + x2 + 3791) >> 4);
*pressure = p;
log_debug(&log, "p = %d\n", p);
return OK;
}
static struct device *
bmp085_prepare(dev_t UNUSED(dev))
{
return &bmp085_device;
}
static int
bmp085_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;
uint32_t temperature, pressure;
r = measure(&temperature, &pressure);
if (r != OK) {
return EIO;
}
memset(buffer, '\0', BUFFER_LEN + 1);
snprintf(buffer, BUFFER_LEN, "%-16s: %d.%01d\n%-16s: %d\n",
"TEMPERATURE", temperature / 10, temperature % 10, "PRESSURE",
pressure);
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
bmp085_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 = bmp085_init();
if (r != OK) {
log_warn(&log, "Couldn't initialize device\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=0x77'\n");
log_warn(&log, "Example -args 'bus=1 address=0x77'\n");
return EXIT_FAILURE;
} else if (r > 0) {
log_warn(&log,
"Invalid slave address for device, expecting 0x77\n");
return EXIT_FAILURE;
}
sef_local_startup();
chardriver_task(&bmp085_tab, CHARDRIVER_SYNC);
return 0;
}

View file

@ -646,6 +646,11 @@ service sht21
ipc SYSTEM RS DS i2c;
};
service bmp085
{
ipc SYSTEM RS DS i2c;
};
service vbox
{
system

View file

@ -72,6 +72,9 @@ enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY,
#define SHT21B1S40_MAJOR 50 /* 50 = /dev/sht21b1s40 (sht21) */
#define SHT21B2S40_MAJOR 51 /* 51 = /dev/sht21b2s40 (sht21) */
#define SHT21B3S40_MAJOR 52 /* 52 = /dev/sht21b3s40 (sht21) */
#define BMP085B1S77_MAJOR 53 /* 53 = /dev/bmp085b1s77 (bmp085) */
#define BMP085B2S77_MAJOR 54 /* 54 = /dev/bmp085b2s77 (bmp085) */
#define BMP085B3S77_MAJOR 55 /* 55 = /dev/bmp085b3s77 (bmp085) */
/* Minor device numbers for memory driver. */