Skip to content

Commit 62ffb4d

Browse files
committed
add sensor code
1 parent 8dfddfc commit 62ffb4d

File tree

9 files changed

+353
-3
lines changed

9 files changed

+353
-3
lines changed

src/HTS221.jl

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# HTS221 humidity/temperature sensor.
2+
# See http://www.st.com/resource/en/datasheet/hts221.pdf
3+
4+
const HTS221_t_coef = Ref((NaN,NaN))
5+
const HTS221_h_coef = Ref((NaN,NaN))
6+
7+
function HTS221_calibrate()
8+
setaddr(HTS221_ADDRESS)
9+
@assert smbus_read(0x0F) == 0xbc
10+
11+
## read temp calibration data
12+
# raw values
13+
t0_raw = smbus_read_pair(0x3c)
14+
t1_raw = smbus_read_pair(0x3e)
15+
16+
# known °C
17+
u = smbus_read(0x35)
18+
t0_C = Float64(Int16(u & 0b0011) << 8 | smbus_read(0x32))/8
19+
t1_C = Float64(Int16(u & 0b1100) << 6 | smbus_read(0x33))/8
20+
21+
m_t = (t1_C - t0_C)/(Float64(t1_raw) - Float64(t0_raw))
22+
k_t = t1_C - m_t*t1_raw
23+
HTS221_t_coef[] = (m_t, k_t)
24+
25+
## read humidity calibration data
26+
h0_raw = smbus_read_pair(0x36)
27+
h1_raw = smbus_read_pair(0x3a)
28+
29+
h0_rH = Float64(smbus_read(0x30))/2
30+
h1_rH = Float64(smbus_read(0x31))/2
31+
32+
m_h = (h1_rH - h0_rH)/(Float64(h1_raw) - Float64(h0_raw))
33+
k_h = h1_rH - m_h*h1_raw
34+
HTS221_h_coef[] = (m_h, k_h)
35+
36+
return nothing
37+
end
38+
39+
function HTS221_raw_temp()
40+
setaddr(HTS221_ADDRESS)
41+
CTRL_REG1 = 0x20
42+
CTRL_REG2 = 0x21
43+
44+
smbus_write(CTRL_REG1, 0x00) # power down
45+
smbus_write(CTRL_REG1, 0x84) # power on, block update
46+
smbus_write(CTRL_REG2, 0x01) # one-shot aquisition
47+
48+
while true
49+
sleep(0.025)
50+
smbus_read(CTRL_REG2) == 0 && break # check if finished
51+
end
52+
t_raw = smbus_read_pair(0x2a)
53+
smbus_write(CTRL_REG1, 0x00) # power down
54+
return t_raw
55+
end
56+
57+
function HTS221_raw_humidity()
58+
setaddr(HTS221_ADDRESS)
59+
CTRL_REG1 = 0x20
60+
CTRL_REG2 = 0x21
61+
62+
smbus_write(CTRL_REG1, 0x00) # power down
63+
smbus_write(CTRL_REG1, 0x84) # power on, block update
64+
smbus_write(CTRL_REG2, 0x01) # one-shot aquisition
65+
66+
while true
67+
sleep(0.025)
68+
smbus_read(CTRL_REG2) == 0 && break # check if finished
69+
end
70+
h_raw = smbus_read_pair(0x28)
71+
smbus_write(CTRL_REG1, 0x00) # power down
72+
return h_raw
73+
end
74+
75+
"""
76+
HTS221_temperature()
77+
78+
The temperature (in °C) from the HTS221 sensor.
79+
"""
80+
function HTS221_temperature()
81+
(m_t, k_t) = HTS221_t_coef[]
82+
t_raw = HTS221_raw_temp()
83+
m_t*t_raw + k_t
84+
end
85+
86+
"""
87+
HTS221_humidity()
88+
89+
The relative humidity (as a percentage) from the HTS221 sensor.
90+
"""
91+
function HTS221_humidity()
92+
(m_h, k_h) = HTS221_h_coef[]
93+
h_raw = HTS221_raw_humidity()
94+
m_h*h_raw + k_h
95+
end

src/LPS25H.jl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# LPS25H pressure/temperature sensor
2+
# See http://www.st.com/resource/en/datasheet/lps25h.pdf
3+
4+
"""
5+
LPS25H_pressure()
6+
7+
The atmospheric pressure (in millibars) from the LPS25H sensor.
8+
"""
9+
function LPS25H_pressure()
10+
setaddr(LPS25H_ADDRESS)
11+
CTRL_REG1 = 0x20
12+
CTRL_REG2 = 0x21
13+
14+
smbus_write(CTRL_REG1, 0x00) # power down
15+
smbus_write(CTRL_REG1, 0x84) # power on, block update
16+
smbus_write(CTRL_REG2, 0x01) # one-shot aquisition
17+
18+
while true
19+
sleep(0.025)
20+
smbus_read(CTRL_REG2) == 0 && break # check if finished
21+
end
22+
23+
pressure = (Int32(smbus_read(0x2a)) << 16 | Int16(smbus_read(0x29)) << 8 | smbus_read(0x28)) / 4096
24+
25+
smbus_write(CTRL_REG1, 0x00) # power down
26+
return pressure
27+
end
28+
29+
"""
30+
HTS221_temperature()
31+
32+
The temperature (in °C) from the LPS25H sensor.
33+
"""
34+
function LPS25H_temperature()
35+
setaddr(LPS25H_ADDRESS)
36+
CTRL_REG1 = 0x20
37+
CTRL_REG2 = 0x21
38+
39+
smbus_write(CTRL_REG1, 0x00) # power down
40+
smbus_write(CTRL_REG1, 0x84) # power on, block update
41+
smbus_write(CTRL_REG2, 0x01) # one-shot aquisition
42+
43+
while true
44+
sleep(0.025)
45+
smbus_read(CTRL_REG2) == 0 && break # check if finished
46+
end
47+
48+
temp = 42.5 + (Int16(smbus_read(0x2c)) << 8 | smbus_read(0x2b)) / 480
49+
50+
smbus_write(CTRL_REG1, 0x00) # power down
51+
return temp
52+
end
53+
54+

src/SenseHat.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ __precompile__()
22
module SenseHat
33

44
export led_matrix, RGB565,
5-
Stick, StickEvent, sticktask, readstick
5+
Stick, StickEvent, sticktask, readstick,
6+
pressure, temperature, humidity
7+
8+
9+
include("ioctl.jl")
610

711
include("led.jl")
812
using .LED
@@ -11,4 +15,7 @@ include("led_extra.jl")
1115
include("stick.jl")
1216
using .Stick
1317

18+
include("sensors.jl")
19+
using .Sensors
20+
1421
end # module

src/ioctl.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
ioctl(f, request, arg)
3+
4+
A wrapper around the unix `ioctl` function:
5+
6+
- `f` should be either a file descriptor (a `Cint`), an `IOStream` or a `File` object
7+
8+
- `request` is a request code
9+
10+
- `arg` is either an integer (which will be passed as a `Cint`), or a buffer (which will
11+
be passed as a `Ptr{Void}`).
12+
13+
Will throw a `SystemError` if an error occurs. Otherwise returns a `Cint` (which is
14+
typically, though not always, 0).
15+
16+
"""
17+
function ioctl end
18+
19+
20+
function ioctl(fd::Cint, request::Integer, arg::Integer)
21+
ret = ccall(:ioctl, Cint, (Cint, Culong, Cint...), fd, request, arg)
22+
if ret < 0
23+
throw(SystemError("ioctl error"))
24+
end
25+
return ret
26+
end
27+
function ioctl(fd::Cint, request::Integer, arg)
28+
ret = ccall(:ioctl, Cint, (Cint, Culong, Ptr{Void}...), fd, request, arg)
29+
if ret < 0
30+
throw(SystemError("ioctl error"))
31+
end
32+
return ret
33+
end
34+
35+
ioctl(f::Union{Base.Filesystem.File, IOStream}, request::Integer, arg) =
36+
ioctl(fd(f), request, arg)
37+

src/led.jl

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
module LED
2+
3+
import ..ioctl
4+
25
export led_matrix, RGB565
36

47
using ColorTypes, FixedPointNumbers
@@ -18,7 +21,13 @@ function _led_fb_device()
1821
error("Sense Hat not found.")
1922
end
2023

21-
const LED_FB_DEVICE = _led_fb_device()
24+
const LED_FB_DEVICE_PATH = _led_fb_device()
25+
const LED_FB_DEVICE = Ref{IOStream}()
26+
27+
function __init__()
28+
LED_FB_DEVICE[] = open(LED_FB_DEVICE_PATH,"w+")
29+
end
30+
2231

2332

2433
typealias U5 UFixed{UInt8,5}
@@ -45,6 +54,8 @@ ColorTypes.blue(c::RGB565) = U5(c.data & 0x1f, Val{true})
4554
ColorTypes.ccolor{Csrc<:Colorant}(::Type{RGB565}, ::Type{Csrc}) = RGB565
4655
ColorTypes.base_color_type(::Type{RGB565}) = RGB565
4756

57+
58+
4859
"""
4960
led_matrix()
5061
@@ -55,6 +66,7 @@ arrays), it is generally preferable to assign it once into a `const` variable so
5566
minimise the number of open file handlers.
5667
5768
# Example
69+
5870
```
5971
using SenseHat
6072
using ColorTypes
@@ -67,7 +79,52 @@ LED[:] = RGB(0,0,0)
6779
```
6880
6981
"""
70-
led_matrix() = Mmap.mmap(LED_FB_DEVICE, Array{RGB565,2}, (8,8); grow=false)
82+
led_matrix() = Mmap.mmap(LED_FB_DEVICE[], Array{RGB565,2}, (8,8); grow=false)
83+
84+
85+
86+
87+
const FBIO_GET_GAMMA = 61696
88+
const FBIO_SET_GAMMA = 61697
89+
const FBIO_RESET_GAMMA = 61698
90+
91+
@enum(GammaScale, GAMMA_DEFAULT, GAMMA_LOW, GAMMA_USER)
92+
93+
"""
94+
getgamma()
95+
96+
Return the current gamma correction table for the Sense HAT LED matrix, as a vector of 32
97+
`UFixed{UInt8,5}` numbers.
98+
99+
"""
100+
function getgamma()
101+
buffer = zeros(UInt8, 32)
102+
ioctl(LED_FB_DEVICE[], FBIO_GET_GAMMA, buffer)
103+
return buffer
104+
end
105+
106+
"""
107+
setgamma(v::GammaScale)
108+
setgamma(table::Vector)
109+
110+
Set the gamma correction for the Sense HAT LED matrix. This can either be one of the
111+
predefined settings (`GAMMA_DEFAULT`, `GAMMA_LOW`, `GAMMA_USER`) or a table of values
112+
between 0 and 1 (the actual values will be converted to `UFixed{UInt8, 5}`).
113+
114+
"""
115+
function setgamma end
116+
117+
function setgamma(v::GammaScale)
118+
ioctl(LED_FB_DEVICE[], FBIO_RESET_GAMMA, Cint(v))
119+
return nothing
120+
end
121+
122+
function setgamma(table::Vector{U5})
123+
length(table) == 32 || error("Table must contain 32 values.")
124+
ioctl(LED_FB_DEVICE[], FBIO_SET_GAMMA, table)
125+
return nothing
126+
end
127+
setgamma(table::AbstractVector) = setgamma(convert(Vector{U5}, table))
71128

72129

73130

src/sensors.jl

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
module Sensors
2+
export humidity, temperature, pressure
3+
4+
5+
const I2C_DEVICE_PATH = "/dev/i2c-1"
6+
const I2C_DEVICE = Ref{IOStream}()
7+
const I2C_ADDR = Ref{UInt8}(0xff)
8+
9+
function __init__()
10+
I2C_DEVICE[] = open("/dev/i2c-1","r+")
11+
HTS221_calibrate()
12+
end
13+
14+
import ..ioctl
15+
include("smbus.jl")
16+
17+
const LPS25H_ADDRESS = 0x5c # Pressure/temp
18+
const HTS221_ADDRESS = 0x5f # Humidity/temp
19+
20+
function setaddr(addr::UInt8)
21+
if I2C_ADDR[] != addr
22+
ioctl(I2C_DEVICE[], I2C_SLAVE, addr)
23+
I2C_ADDR[] = addr
24+
end
25+
end
26+
27+
include("HTS221.jl")
28+
include("LPS25H.jl")
29+
30+
31+
"""
32+
humidity()
33+
34+
The relative humidity (as a percentage between 0 and 100).
35+
"""
36+
humidity() = HTS221_humidity()
37+
38+
"""
39+
temperature()
40+
41+
The temperature (in °C).
42+
"""
43+
temperature() = HTS221_temperature()
44+
45+
"""
46+
pressure()
47+
48+
The atmospheric pressure (in millibars).
49+
"""
50+
pressure() = LPS25H_pressure()
51+
52+
53+
end # module

src/smbus.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# A basic implementation of the SMBus interface
2+
# Based on the i2c-dev.h (the header only "static inline" version from i2c-tools)
3+
4+
const I2C_SMBUS_READ = 0x01
5+
const I2C_SMBUS_WRITE = 0x00
6+
7+
const I2C_SMBUS_BYTE = 0x01
8+
const I2C_SMBUS_BYTE_DATA = 0x02
9+
10+
const I2C_SLAVE = 0x0703
11+
const I2C_SMBUS = 0x0720
12+
13+
immutable SMBusData
14+
read_write ::UInt8
15+
command ::UInt8
16+
size ::UInt32
17+
data ::Ptr{UInt8}
18+
end
19+
20+
function smbus_read(cmd::UInt8)
21+
buffer = Ref(UInt8(0))
22+
data = SMBusData(I2C_SMBUS_READ, cmd, I2C_SMBUS_BYTE_DATA,
23+
Base.unsafe_convert(Ptr{UInt8}, buffer))
24+
ioctl(I2C_DEVICE[], I2C_SMBUS, Ref(data))
25+
return buffer[]
26+
end
27+
function smbus_read_pair(cmd::UInt8)
28+
lo = smbus_read(cmd)
29+
hi = smbus_read(cmd+UInt8(1))
30+
return Int16(hi)<<8 | lo
31+
end
32+
33+
function smbus_write(cmd::UInt8, val::UInt8)
34+
buffer = Ref(val)
35+
data = SMBusData(I2C_SMBUS_WRITE, cmd, I2C_SMBUS_BYTE_DATA,
36+
Base.unsafe_convert(Ptr{UInt8}, buffer))
37+
ioctl(I2C_DEVICE[], I2C_SMBUS, Ref(data))
38+
return 1
39+
end
40+

0 commit comments

Comments
 (0)