Utilities for drawing on 4 Adafruit 8x8 LED Backpack displays as one
1#!/usr/bin/env ruby
2#
3# Copyright (c) 2012, Sungjin Han <meinside@gmail.com> (Matrix8x8)
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9# * Redistributions of source code must retain the above copyright notice,
10# this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# * Neither the name of meinside nor the names of its contributors may be
15# used to endorse or promote products derived from this software without
16# specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31require "i2c/i2c"
32require "i2c/backends/i2c-dev"
33
34class Matrix8x8
35 # Registers
36 HT16K33_REGISTER_DISPLAY_SETUP = 0x80
37 HT16K33_REGISTER_SYSTEM_SETUP = 0x20
38 HT16K33_REGISTER_DIMMING = 0xE0
39
40 # Blink rate
41 HT16K33_BLINKRATE_OFF = 0x00
42 HT16K33_BLINKRATE_2HZ = 0x01
43 HT16K33_BLINKRATE_1HZ = 0x02
44 HT16K33_BLINKRATE_HALFHZ = 0x03
45
46 MAX_COL = 8
47 MAX_ROW = 8
48
49 attr_accessor :device, :address
50
51 def self.board_revision
52 File.open("/proc/cpuinfo", "r"){|file|
53 return ["2", "3"].include?(file.each_line.find{|x| x =~ /^Revision/ }
54 .strip[-1]) ? 1 : 2
55 }
56 end
57
58 def self.i2c_device_path
59 case self.board_revision
60 when 1
61 return "/dev/i2c-0"
62 when 2
63 return "/dev/i2c-1"
64 end
65 end
66
67 def initialize(device = self.i2c_device_path, address = 0x70,
68 options = {blink_rate: HT16K33_BLINKRATE_OFF, brightness: 15})
69 if device.kind_of? String
70 @device = ::I2C.create(device)
71 else
72 [ :read, :write ].each do |m|
73 raise IncompatibleDeviceException,
74 "Missing #{m} method in device object." unless device.respond_to?(m)
75 end
76 @device = device
77 end
78 @address = address
79
80 # turn on oscillator
81 @device.write(@address, HT16K33_REGISTER_SYSTEM_SETUP | 0x01, 0x00, 0x00)
82
83 # set blink rate and brightness
84 set_blink_rate(options[:blink_rate])
85 set_brightness(options[:brightness])
86
87 if block_given?
88 yield self
89 end
90 end
91
92 def set_blink_rate(rate)
93 rate = HT16K33_BLINKRATE_OFF if rate > HT16K33_BLINKRATE_HALFHZ
94 @device.write(@address, HT16K33_REGISTER_DISPLAY_SETUP | 0x01 | (rate << 1),
95 0x00, 0x00)
96 end
97
98 def set_brightness(brightness)
99 brightness = 15 if brightness > 15
100 @device.write(@address, HT16K33_REGISTER_DIMMING | brightness, 0x00, 0x00)
101 end
102
103 def clear
104 (0...MAX_ROW).each{|n| write(n, 0x00, 0x00) }
105 end
106
107 def fill
108 (0...MAX_ROW).each{|n| write(n, 0xFF, 0xFF) }
109 end
110
111 def write(row, value, value2)
112 @device.write(@address, row * 2, value)
113 @device.write(@address, row * 2 + 1, value2)
114 end
115
116 def read(row)
117 @device.read(@address, 2, row * 2).unpack("C*")
118 end
119end