Utilities for drawing on 4 Adafruit 8x8 LED Backpack displays as one
1#!/usr/bin/env ruby
2
3require_relative "matrix8x8"
4require_relative "font3x5"
5
6class FourScreen
7 SC_ADDR_1 = 0x74
8 SC_ADDR_2 = 0x71
9 SC_ADDR_3 = 0x72
10 SC_ADDR_4 = 0x70
11
12 SC_ADDRS = [ SC_ADDR_4, SC_ADDR_3, SC_ADDR_2, SC_ADDR_1 ]
13
14 SC_WIDTH = 8
15 SC_HEIGHT = 8
16
17 OFF = 0
18 GREEN = 1
19 RED = 2
20 YELLOW = 3
21
22 attr_accessor :screens, :matrix
23
24 def initialize
25 @screens = SC_ADDRS.map{|addr|
26 Matrix8x8.new(Matrix8x8.i2c_device_path, addr)
27 }
28
29 clear(true)
30 read
31 end
32
33 def set_brightness(level)
34 @screens.each{|s| s.set_brightness(level) }
35 end
36
37 def clear(screen = false)
38 if screen
39 @screens.each{|s| s.clear }
40 end
41 @matrix = SC_HEIGHT.times.map{ Array.new(SC_WIDTH * SC_ADDRS.count, OFF) }
42 end
43
44 def read
45 @screens.each_with_index do |screen,x|
46 SC_WIDTH.times do |row|
47 vals = screen.read(row)
48
49 # 20 -> "10100" -> [ 1, 0, 1, 0, 0 ]
50 bits = vals[0].to_s(2).split("").map{|i| i.to_i }
51 bits2 = vals[1].to_s(2).split("").map{|i| i.to_i }
52
53 # [ 1, 0, 1, 0, 0 ] -> [ 0, 0, 0, 0, 0, 1, 0, 1 ]
54 while bits.length < SC_WIDTH
55 bits.unshift 0
56 end
57 while bits2.length < SC_WIDTH
58 bits2.unshift 0
59 end
60 bits.reverse!
61 bits2.reverse!
62
63 actual_row = (x * SC_WIDTH) + (SC_WIDTH - row) - 1
64 SC_WIDTH.times do |y|
65 if bits[y] == 1 && bits2[y] == 1
66 v = YELLOW
67 elsif bits[y] == 1 && bits2[y] == 0
68 v = GREEN
69 elsif bits[y] == 0 && bits2[y] == 1
70 v = RED
71 else
72 v = OFF
73 end
74
75 if @matrix[y][actual_row] != v
76 raise "expected #{y}x#{actual_row} to be #{v}, is " <<
77 "#{@matrix[y][actual_row]}"
78 end
79
80 @matrix[y][actual_row] = v
81 end
82 end
83 end
84 end
85
86 def to_s
87 o = ""
88 @matrix.each do |row|
89 row.each do |x|
90 if x == OFF
91 o << "."
92 elsif x == GREEN
93 o << "G"
94 elsif x == RED
95 o << "R"
96 elsif x == YELLOW
97 o << "Y"
98 end
99 end
100 o << "\n"
101 end
102 o
103 end
104
105 def set(col, row, val)
106 @matrix[row][col] = val
107 end
108
109 def set_brightness(val)
110 @screens.each{|s| s.set_brightness(val) }
111 end
112
113 def write
114 @screens.each_with_index do |screen,x|
115 SC_WIDTH.times do |col|
116 val = ""
117 val2 = ""
118 SC_HEIGHT.times do |row|
119 case @matrix[row][col + (x * SC_WIDTH)]
120 when OFF
121 val << "0"
122 val2 << "0"
123 when GREEN
124 val << "1"
125 val2 << "0"
126 when RED
127 val << "0"
128 val2 << "1"
129 when YELLOW
130 val << "1"
131 val2 << "1"
132 end
133 end
134
135 # "001010101" -> "101010100" -> 340
136 val = val.reverse.to_i(2)
137 val2 = val2.reverse.to_i(2)
138
139 row = SC_WIDTH - col - 1
140
141 screen.write(row, val, val2)
142 end
143 end
144 end
145
146 def draw_word(x, text, color)
147 text.to_s.each_char do |char|
148 col_size = 0
149
150 Font3x5::CHARS[char.ord].each_with_index do |cbits,row|
151 cbits.each_with_index do |bit,col|
152 self.set(x + col, row + 1, bit == 1 ? color : 0)
153 col_size = col
154 end
155 end
156
157 x += col_size + 2
158 end
159
160 x
161 end
162
163 def height
164 SC_HEIGHT
165 end
166
167 def width
168 SC_WIDTH * @screens.count
169 end
170end