summaryrefslogtreecommitdiffstats
path: root/sensors/barometer/barometer-bmp085.vala
blob: 92ea91755caec2acf57da30d12ea02ffe752c758 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* Copyright 2012, Sebastian Reichel <sre@ring0.de>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

public class BMP085 : I2CDevice, Barometer {
	public uint8 oversampling_setting = 0x03;
	private Calibration cal = Calibration();

	private int64 next_temp_measurement;
	private int raw_temp;
	private int raw_pressure;

	private int64 temp_correction_coefficient;

	struct Calibration {
		int16 AC1;
		int16 AC2;
		int16 AC3;
		uint16 AC4;
		uint16 AC5;
		uint16 AC6;
		int16 B1;
		int16 B2;
		int16 MB;
		int16 MC;
		int16 MD;
	}

	public BMP085(uint8 dev, uint8 addr = 0x77) throws I2CError {
			base(dev, addr);
			read_calibration_values();
	}

	private void read_calibration_values() throws I2CError {
		var data = get_block(0xaa, 22);
		cal.AC1 =  data[0] << 8 | data[1];
		cal.AC2 =  data[2] << 8 | data[3];
		cal.AC3 =  data[4] << 8 | data[5];
		cal.AC4 =  data[6] << 8 | data[7];
		cal.AC5 =  data[8] << 8 | data[9];
		cal.AC6 = data[10] << 8 | data[11];
		cal.B1  = data[12] << 8 | data[13];
		cal.B2  = data[14] << 8 | data[15];
		cal.MB  = data[16] << 8 | data[17];
		cal.MC  = data[18] << 8 | data[19];

		cal.MD  = data[20] << 8 | data[21];
	}

	private void msleep(uint msecs) {
		Posix.usleep(msecs*1000);
	}

	private void update_raw_temperature() throws I2CError {
		set_byte(0xf4, 0x2e);
		msleep(5);
		var data = get_block(0xf6, 2);
		raw_temp = data[0] << 8 | data[1];
		next_temp_measurement = time_t() + 1;
	}

	private void update_raw_pressure() throws I2CError {
		set_byte(0xf4, 0x34 + (oversampling_setting<<6));
		msleep(2+(3 << oversampling_setting<<1));
		var data = get_block(0xf6, 3);
		raw_pressure = data[0] << 16 | data[1] << 8 | data[2];
		raw_pressure >>= 8-oversampling_setting;
	}

	public int32 get_temperature() throws I2CError {
		if(next_temp_measurement+1 < time_t())
			update_raw_temperature();

		int64 x1 = ((raw_temp - cal.AC6) * cal.AC5) >> 15;
		int64 x2 = (cal.MC << 11) / (x1 + cal.MD);
		temp_correction_coefficient = x1 + x2 - 4000;

		return (int32) (x1+x2+8) >> 4;
	}

	public int32 get_pressure() throws I2CError {
		int64 x1, x2, x3, b3, p;
		uint64 b4, b7;

		if(next_temp_measurement+1 < time_t())
			get_temperature();

		update_raw_pressure();

		x1 = (temp_correction_coefficient * temp_correction_coefficient) >> 12;
		x1 *= cal.B2;
		x1 >>= 11;

		x2 = cal.AC2 * temp_correction_coefficient;
		x2 >>= 11;

		x3 = x1 + x2;

		b3 = (((((int64)cal.AC1) * 4 + x3) << oversampling_setting) + 2) >> 2;

		x1 = (cal.AC3 * temp_correction_coefficient) >> 13;
		x2 = (cal.B1 * ((temp_correction_coefficient * temp_correction_coefficient) >> 12)) >> 16;
		x3 = (x1 + x2 + 2) >> 2;
		b4 = (cal.AC4 * (uint64)(x3 + 32768)) >> 15;

		b7 = ((uint64)raw_pressure - b3) * (50000 >> oversampling_setting);
		p = (int64) ((b7 < 0x80000000) ? ((b7 << 1) / b4) : ((b7 / b4) * 2));

		x1 = p >> 8;
		x1 *= x1;
		x1 = (x1 * 3038) >> 16;
		x2 = (-7357 * p) >> 16;
		p += (x1 + x2 + 3791) >> 4;

		return (int32) p;
	}
}