i2c-devices 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,137 @@
1
+ # coding: utf-8
2
+
3
+ require "i2c"
4
+
5
+ # I2C interface with HD44780 compatible commands
6
+ class HD44780 < I2CDevice
7
+ MAP = Hash[
8
+ [
9
+ "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚".split(//).map {|c|
10
+ c.force_encoding(Encoding::BINARY)
11
+ },
12
+ (0b10100001..0b11011111).map {|c|
13
+ c.chr
14
+ }
15
+ ].transpose
16
+ ]
17
+
18
+ def initialize(args={})
19
+ super
20
+ @lines = []
21
+ initialize_lcd
22
+ end
23
+
24
+ def initialize_lcd
25
+ function_set(1, 1, 0)
26
+ sleep 4.1e-3
27
+ function_set(1, 1, 0)
28
+ sleep 100e-6
29
+ function_set(1, 1, 0)
30
+ function_set(1, 1, 0)
31
+ display_on_off_control(1, 0, 0)
32
+ clear
33
+ end
34
+
35
+ def put_line(line, str, force=false)
36
+ str.force_encoding(Encoding::BINARY)
37
+ str.gsub!(/#{MAP.keys.join('|')}/, MAP)
38
+
39
+ str = "%- 16s" % str
40
+
41
+ if force || str != @lines[line]
42
+ # set ddram address
43
+ set_ddram_address(0x40 * line)
44
+ sleep 60e-6
45
+ i2cset(*str.unpack("C*").map {|i| [0x80, i] }.flatten)
46
+ sleep 60e-6
47
+ end
48
+ @lines[line] = str
49
+ end
50
+
51
+ # Usage:
52
+ # lcd.define_character(0, [
53
+ # 0,1,1,1,0,
54
+ # 1,0,0,0,1,
55
+ # 1,1,0,1,1,
56
+ # 1,0,1,0,1,
57
+ # 1,1,0,1,1,
58
+ # 1,0,0,0,1,
59
+ # 1,0,0,0,1,
60
+ # 0,1,1,1,0,
61
+ # ])
62
+ def define_character(n, array)
63
+ raise "n < 8" unless n < 8
64
+ raise "array size must be 40 (5x8)" unless array.size == 40
65
+
66
+ array = array.each_slice(5).map {|i|
67
+ i.inject {|r,i| (r << 1) + i }
68
+ }
69
+ set_cgram_address(8 * n)
70
+ sleep 60e-6
71
+ i2cset(*array.map {|i| [0x80, i] }.flatten)
72
+ sleep 60e-6
73
+ end
74
+
75
+ def clear
76
+ @lines.clear
77
+ clear_display
78
+ end
79
+
80
+ def clear_display
81
+ i2cset(0, 0b00000001)
82
+ sleep 2.16e-3
83
+ end
84
+
85
+ def return_home
86
+ i2cset(0, 0b00000010)
87
+ sleep 1.52e-3
88
+ end
89
+
90
+ # i_d : increment or decrement: 1: increment, 0: decrement
91
+ # s : shift entire display: 1: left, 0: right
92
+ def entry_mode_set(i_d, s)
93
+ i2cset(0, 0b00000100 | (i_d<<1) | (s))
94
+ sleep 60e-6
95
+ end
96
+
97
+ # d: set entire display on/off
98
+ # c: cursor on/off
99
+ # b: blink cursor
100
+ def display_on_off_control(d, c, b)
101
+ i2cset(0, 0b00001000 | (d<<2) | (c<<1) | (b))
102
+ sleep 60e-6
103
+ end
104
+
105
+ def cursor_or_display_shift(s_c, r_l)
106
+ i2cset(0, 0b00010000 | (s_c<<3) | (r_l<<2))
107
+ sleep 60e-6
108
+ end
109
+
110
+ # dl data_length: 1: 8bit, 0: 4bit
111
+ # n number_of_display_lines: 1: 2-line, 0: 1-line
112
+ # f character_font: 1: double font, 0: normal
113
+ def function_set(dl, n, f)
114
+ i2cset(0, 0b00100000 | (dl<<4) | (n<<3) | (f<<2))
115
+ sleep 60e-6
116
+ end
117
+
118
+ def set_cgram_address(address)
119
+ address = address & 0b00111111
120
+ i2cset(0, 0b01000000 | address)
121
+ sleep 60e-6
122
+ end
123
+
124
+ def set_ddram_address(address)
125
+ address = address & 0b01111111
126
+ i2cset(0, 0b10000000 | address)
127
+ sleep 60e-6
128
+ end
129
+
130
+ def read_busy_flag_and_address
131
+ read = i2cget(0b01000000)
132
+ {
133
+ :busy => (read & 0b10000000) != 0,
134
+ :address_counter => read & 0b01111111
135
+ }
136
+ end
137
+ end
@@ -0,0 +1,39 @@
1
+
2
+ require "i2c"
3
+
4
+ class MPL115A2 < I2CDevice
5
+ def initialize(args={})
6
+ args[:address] = 0x60
7
+ super
8
+ coefficient = i2cget(0x04, 8).unpack("n*")
9
+
10
+ @a0 = fixed_point(coefficient[0], 12)
11
+ @b1 = fixed_point(coefficient[1], 2)
12
+ @b2 = fixed_point(coefficient[2], 1)
13
+ @c12 = fixed_point(coefficient[3], 0) / (1<<9)
14
+ end
15
+
16
+ def fixed_point(fixed, int_bits)
17
+ msb = 15
18
+ deno = (1<<(msb-int_bits)).to_f
19
+ if (fixed & (1<<15)).zero?
20
+ fixed / deno
21
+ else
22
+ -( ( (~fixed & 0xffff) + 1) / deno )
23
+ end
24
+ end
25
+
26
+ def calculate_hPa
27
+ i2cset(0x12, 0x01) # CONVERT
28
+
29
+ sleep 0.003
30
+
31
+ data = i2cget(0x00, 4).unpack("n*")
32
+
33
+ p_adc = (data[0]) >> 6
34
+ t_adc = (data[1]) >> 6
35
+
36
+ p_comp = @a0 + (@b1 + @c12 * t_adc) * p_adc + @b2 * t_adc
37
+ hPa = p_comp * ( (1150 - 500) / 1023.0) + 500;
38
+ end
39
+ end
@@ -0,0 +1,198 @@
1
+ require "i2c"
2
+ =begin
3
+ Generic software I2C Driver based on /sys/class/gpio.
4
+ THIS MODULE WORKS WITH VERY SLOW SPEED ABOUT JUST 1kHz (normaly 100kHz).
5
+ =end
6
+
7
+ module I2CDevice::Driver
8
+ class GPIO
9
+ @@DEBUG = false
10
+
11
+ def self.export(pin)
12
+ File.open("/sys/class/gpio/export", "w") do |f|
13
+ f.syswrite(pin)
14
+ end
15
+ end
16
+
17
+ def self.unexport(pin)
18
+ File.open("/sys/class/gpio/unexport", "w") do |f|
19
+ f.syswrite(pin)
20
+ end
21
+ end
22
+
23
+ def self.direction(pin, direction)
24
+ # [:in, :out, :high, :low].include?(direction) or raise "direction must be :in, :out, :high or :low"
25
+ File.open("/sys/class/gpio/gpio#{pin}/direction", "w") do |f|
26
+ f.syswrite(direction)
27
+ end
28
+ end
29
+
30
+ def self.read(pin)
31
+ File.open("/sys/class/gpio/gpio#{pin}/value", "r") do |f|
32
+ f.sysread(1).to_i
33
+ end
34
+ end
35
+
36
+ def self.write(pin, val)
37
+ File.open("/sys/class/gpio/gpio#{pin}/value", "w") do |f|
38
+ f.syswrite(val && val.nonzero?? "1" : "0")
39
+ end
40
+ end
41
+
42
+ def self.finalizer(ports)
43
+ proc do
44
+ ports.each do |pin|
45
+ GPIO.unexport(pin)
46
+ end
47
+ end
48
+ end
49
+
50
+ attr_reader :sda, :scl, :speed
51
+
52
+ def initialize(opts={})
53
+ @sda = opts[:sda] or raise "opts[:sda] = [gpio pin number] is required"
54
+ @scl = opts[:scl] or raise "opts[:scl] = [gpio pin number] is required"
55
+ @speed = opts[:speed] || 1 # kHz but insane
56
+ @clock = 1.0 / (@speed * 1000)
57
+
58
+ begin
59
+ GPIO.export(@sda)
60
+ GPIO.export(@scl)
61
+ rescue Errno::EBUSY => e
62
+ end
63
+ ObjectSpace.define_finalizer(self, self.class.finalizer([@scl, @sda]))
64
+ begin
65
+ GPIO.direction(@sda, :high)
66
+ GPIO.direction(@scl, :high)
67
+ GPIO.direction(@sda, :in)
68
+ GPIO.direction(@scl, :in)
69
+ rescue Errno::EACCES => e # writing to gpio after export is failed in a while
70
+ retry
71
+ end
72
+ end
73
+
74
+ def i2cget(address, param, length=1)
75
+ ret = ""
76
+ start_condition
77
+ unless write( (address << 1) + 0)
78
+ raise I2CDevice::I2CIOError, "Unknown slave device (address:#{address})"
79
+ end
80
+ write(param)
81
+ stop_condition # AVR stucked with SCL low without this (Does not AVR support Sr condition?)
82
+ start_condition
83
+ unless write( (address << 1) + 1)
84
+ raise I2CDevice::I2CIOError, "Unknown slave device (address:#{address})"
85
+ end
86
+ length.times do |n|
87
+ ret << read(n != length - 1).chr
88
+ end
89
+ ret
90
+ ensure
91
+ stop_condition
92
+ end
93
+
94
+ def i2cset(address, *data)
95
+ sent = 0
96
+ start_condition
97
+ unless write( (address << 1) + 0)
98
+ raise I2CDevice::I2CIOError, "Unknown slave device (address:#{address})"
99
+ end
100
+ data.each do |c|
101
+ unless write(c)
102
+ break
103
+ end
104
+ sent += 1
105
+ end
106
+ sent
107
+ ensure
108
+ stop_condition
109
+ end
110
+
111
+ private
112
+
113
+ def start_condition
114
+ p :start_condition if @@DEBUG
115
+ sleep @clock
116
+ GPIO.direction(@sda, :in)
117
+ GPIO.direction(@scl, :in)
118
+ if GPIO.read(@scl) == 0
119
+ raise I2CDevice::I2CBUSBusy, "BUS is busy"
120
+ end
121
+
122
+ sleep @clock / 2
123
+ GPIO.direction(@scl, :high)
124
+ sleep @clock / 2
125
+ GPIO.direction(@sda, :low)
126
+ sleep @clock
127
+ end
128
+
129
+ def stop_condition
130
+ p :stop_condition if @@DEBUG
131
+ GPIO.direction(@scl, :low)
132
+ sleep @clock / 2
133
+ GPIO.direction(@sda, :low)
134
+ sleep @clock / 2
135
+ GPIO.direction(@scl, :in)
136
+ sleep @clock / 2
137
+ GPIO.direction(@sda, :in)
138
+ sleep @clock / 2
139
+ end
140
+
141
+ def write(byte)
142
+ p [:write, byte] if @@DEBUG
143
+ GPIO.direction(@scl, :low)
144
+ sleep @clock
145
+
146
+ 7.downto(0) do |n|
147
+ GPIO.direction(@sda, byte[n] == 1 ? :high : :low)
148
+ GPIO.direction(@scl, :in)
149
+ until GPIO.read(@scl) == 1
150
+ # clock streching
151
+ sleep @clock
152
+ end
153
+ sleep @clock
154
+ GPIO.direction(@scl, :low)
155
+ GPIO.write(@sda, false)
156
+ sleep @clock
157
+ end
158
+
159
+ GPIO.direction(@sda, :in)
160
+ GPIO.direction(@scl, :in)
161
+ sleep @clock / 2
162
+ ack = GPIO.read(@sda) == 0
163
+ sleep @clock / 2
164
+ while GPIO.read(@scl) == 0
165
+ sleep @clock
166
+ end
167
+ GPIO.direction(@scl, :low)
168
+ ack
169
+ end
170
+
171
+ def read(ack=true)
172
+ p [:read, ack] if @@DEBUG
173
+ ret = 0
174
+
175
+ GPIO.direction(@scl, :low)
176
+ sleep @clock
177
+ GPIO.direction(@sda, :in)
178
+
179
+ 8.times do
180
+ GPIO.direction(@scl, :in)
181
+ sleep @clock / 2
182
+ ret = (ret << 1) | GPIO.read(@sda)
183
+ sleep @clock / 2
184
+ GPIO.direction(@scl, :low)
185
+ sleep @clock
186
+ end
187
+
188
+ GPIO.direction(@sda, ack ? :low : :high)
189
+
190
+ GPIO.write(@scl, true)
191
+ sleep @clock
192
+ GPIO.write(@scl, false)
193
+ sleep @clock
194
+ ret
195
+ end
196
+ end
197
+ end
198
+
@@ -0,0 +1,53 @@
1
+
2
+ require "i2c"
3
+
4
+ module I2CDevice::Driver
5
+ class I2CDev
6
+ # ioctl command
7
+ # Ref. https://www.kernel.org/pub/linux/kernel/people/marcelo/linux-2.4/include/linux/i2c.h
8
+ I2C_RETRIES = 0x0701
9
+ I2C_TIMEOUT = 0x0702
10
+ I2C_SLAVE = 0x0703
11
+ I2C_SLAVE_FORCE = 0x0706
12
+ I2C_TENBIT = 0x0704
13
+ I2C_FUNCS = 0x0705
14
+ I2C_RDWR = 0x0707
15
+ I2C_SMBUS = 0x0720
16
+ I2C_UDELAY = 0x0705
17
+ I2C_MDELAY = 0x0706
18
+
19
+ def initialize(path=nil)
20
+ if path.nil?
21
+ path = Dir.glob("/dev/i2c-*").sort.last
22
+ end
23
+
24
+ unless File.exist?(path)
25
+ raise I2CDevice::I2CIOError, "/dev/i2c-0 is required"
26
+ end
27
+
28
+ @path = path
29
+ end
30
+
31
+ def i2cget(address, param, length)
32
+ i2c = File.open(@path, "r+")
33
+ i2c.ioctl(I2C_SLAVE, address)
34
+ i2c.syswrite(param.chr)
35
+ ret = i2c.sysread(length)
36
+ i2c.close
37
+ ret
38
+ rescue Errno::EIO => e
39
+ raise I2CDevice::I2CIOError, e.message
40
+ end
41
+
42
+ def i2cset(address, *data)
43
+ i2c = File.open(@path, "r+")
44
+ i2c.ioctl(I2C_SLAVE, address)
45
+ i2c.syswrite(data.pack("C*"))
46
+ i2c.close
47
+ rescue Errno::EIO => e
48
+ raise I2CDevice::I2CIOError, e.message
49
+ end
50
+ end
51
+ end
52
+
53
+
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ class MockI2CDevice
4
+ attr_reader :memory
5
+ attr_reader :ioctl
6
+ attr_reader :state
7
+
8
+ def initialize
9
+ @temp = Tempfile.new("i2c")
10
+ @ioctl = []
11
+ @memory = [ 0 ]
12
+ @address = nil
13
+ @state = nil
14
+ end
15
+
16
+ def path
17
+ @temp.path
18
+ end
19
+
20
+ def ioctl(cmd, arg)
21
+ @ioctl = [cmd, arg]
22
+ self
23
+ end
24
+
25
+ def open
26
+ @address = nil
27
+ @state = :init
28
+ self
29
+ end
30
+
31
+ def close
32
+ @address = nil
33
+ @state = nil
34
+ self
35
+ end
36
+
37
+ def syswrite(buf)
38
+ buf.unpack("C*").each do |c|
39
+ case @state
40
+ when :init
41
+ # p "@address = 0x%02x" % c
42
+ @address = c
43
+ @state = :wait
44
+ when :wait
45
+ # p "@memory[0x%02x] = 0b%08b" % [@address, c]
46
+ @memory[@address] = c
47
+ @address += 1
48
+ end
49
+ end
50
+ end
51
+
52
+ def sysread(size)
53
+ ret = []
54
+ case @state
55
+ when :init
56
+ raise "Invalid State"
57
+ when :wait
58
+ size.times do
59
+ ret << @memory[@address]
60
+ @address += 1
61
+ end
62
+ end
63
+ ret.pack("C*")
64
+ end
65
+ end
66
+
67
+