ws2812 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/LICENSE.txt +339 -0
- data/README.md +41 -0
- data/Rakefile +39 -0
- data/examples/basic.rb +45 -0
- data/examples/binaryclock.rb +161 -0
- data/examples/digiclock.rb +167 -0
- data/examples/gamma-vs-direct.rb +31 -0
- data/examples/unicornhat-test.rb +47 -0
- data/ext/ws2812/COMPILING.txt +4 -0
- data/ext/ws2812/SOURCES.txt +2 -0
- data/ext/ws2812/board_info.c +143 -0
- data/ext/ws2812/board_info.h +6 -0
- data/ext/ws2812/clk.h +60 -0
- data/ext/ws2812/dma.c +79 -0
- data/ext/ws2812/dma.h +126 -0
- data/ext/ws2812/extconf.rb +24 -0
- data/ext/ws2812/gamma.h +20 -0
- data/ext/ws2812/gpio.h +108 -0
- data/ext/ws2812/lowlevel.i +48 -0
- data/ext/ws2812/lowlevel_wrap.c +3189 -0
- data/ext/ws2812/mailbox.c +311 -0
- data/ext/ws2812/mailbox.h +53 -0
- data/ext/ws2812/pwm.c +112 -0
- data/ext/ws2812/pwm.h +123 -0
- data/ext/ws2812/ws2811.c +685 -0
- data/ext/ws2812/ws2811.h +69 -0
- data/lib/ws2812.rb +20 -0
- data/lib/ws2812/basic.rb +195 -0
- data/lib/ws2812/color.rb +33 -0
- data/lib/ws2812/gamma_correction.rb +72 -0
- data/lib/ws2812/unicornhat.rb +209 -0
- metadata +114 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
3
|
+
require 'ws2812'
|
4
|
+
|
5
|
+
# Single 1x4 pixels binary "digit"
|
6
|
+
class BinaryDigit
|
7
|
+
def initialize(hat, x, y, color, off_color = nil)
|
8
|
+
off_color ||= Ws2812::Color.new(0, 0, 0)
|
9
|
+
@hat, @x, @y, @color, @off_color = hat, x, y, color, off_color
|
10
|
+
end
|
11
|
+
attr_reader :hat
|
12
|
+
attr_accessor :x, :y, :color, :off_color
|
13
|
+
|
14
|
+
def show(value, do_show = false, &pixel_set)
|
15
|
+
pixel_set ||= method(:default_pixel_set)
|
16
|
+
raise ArgumentError, "invalid value" unless (0..9).include?(value)
|
17
|
+
x = 0
|
18
|
+
0.upto(3) do |y|
|
19
|
+
if value[3-y].zero?
|
20
|
+
pixel_set.call(@hat,@x + x, @y + y, @off_color)
|
21
|
+
else
|
22
|
+
pixel_set.call(@hat,@x + x, @y + y, @color)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@hat.show if do_show
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_pixel_set(hat, x, y, color)
|
29
|
+
hat[x, y] = color
|
30
|
+
end
|
31
|
+
private :default_pixel_set
|
32
|
+
end
|
33
|
+
|
34
|
+
# Two BinaryDigits next to each other with no pixel gap
|
35
|
+
class TwoBinaryDigits
|
36
|
+
def initialize(hat, x, y, color, off_color = nil)
|
37
|
+
@tens = BinaryDigit.new(hat, x, y, color, off_color)
|
38
|
+
@singles = BinaryDigit.new(hat, x + 1, y, color, off_color)
|
39
|
+
@hat, @x, @y, @color = hat, x, y, color
|
40
|
+
end
|
41
|
+
attr_reader :hat, :x, :y, :color, :off_color
|
42
|
+
|
43
|
+
def show(value, do_show = false, &pixel_set)
|
44
|
+
tens_value = value / 10
|
45
|
+
@tens.show(tens_value, false, &pixel_set)
|
46
|
+
@singles.show(value % 10, false, &pixel_set)
|
47
|
+
@hat.show if do_show
|
48
|
+
end
|
49
|
+
|
50
|
+
def off_color
|
51
|
+
@tens.off_color
|
52
|
+
end
|
53
|
+
|
54
|
+
def off_color=(val)
|
55
|
+
@tens.off_color = @singles.off_color = val
|
56
|
+
end
|
57
|
+
|
58
|
+
def color=(val)
|
59
|
+
@tens.color = @singles.color = val
|
60
|
+
end
|
61
|
+
|
62
|
+
def x=(val)
|
63
|
+
@tens.x = val
|
64
|
+
@singles.x = val + 1
|
65
|
+
end
|
66
|
+
|
67
|
+
def y=(val)
|
68
|
+
@tens.y = @singles.y = val
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# A 6x4 matrix that represents binary clock
|
73
|
+
class BinaryClock
|
74
|
+
def initialize(hat, x, y, color)
|
75
|
+
@h = TwoBinaryDigits.new(hat, x, y, color)
|
76
|
+
@m = TwoBinaryDigits.new(hat, x+2, y, color)
|
77
|
+
@s = TwoBinaryDigits.new(hat, x+4, y, color)
|
78
|
+
end
|
79
|
+
|
80
|
+
def show(time)
|
81
|
+
@h.show(time.hour, false)
|
82
|
+
@m.show(time.min, false)
|
83
|
+
@s.show(time.sec, false)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# A 8x4 matrix that represents binary calendar (ddmmyyyy)
|
88
|
+
class BinaryCalendar
|
89
|
+
def initialize(hat, x, y, color)
|
90
|
+
@d = TwoBinaryDigits.new(hat, x, y, color)
|
91
|
+
@m = TwoBinaryDigits.new(hat, x+2, y, color)
|
92
|
+
@y1 = TwoBinaryDigits.new(hat, x+4, y, color)
|
93
|
+
@y2 = TwoBinaryDigits.new(hat, x+6, y, color)
|
94
|
+
end
|
95
|
+
|
96
|
+
def show(time)
|
97
|
+
@d.show(time.day, false)
|
98
|
+
@m.show(time.month, false)
|
99
|
+
@y1.show(time.year/100, false)
|
100
|
+
@y2.show(time.year%100, false)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if __FILE__ == $0
|
105
|
+
# Init
|
106
|
+
hat = Ws2812::UnicornHAT.new
|
107
|
+
hat.rotation = 180
|
108
|
+
hat.brightness = 20
|
109
|
+
|
110
|
+
frame = Ws2812::Color.new(0x00, 0x00, 0x66)
|
111
|
+
red = Ws2812::Color.new(0xff, 0, 0)
|
112
|
+
green = Ws2812::Color.new(0, 0xff, 0)
|
113
|
+
if true
|
114
|
+
# Calendar + Clock
|
115
|
+
calendar = BinaryCalendar.new(hat, 0, 0, green)
|
116
|
+
clock = BinaryClock.new(hat, 1, 4, red)
|
117
|
+
show_calendar = true
|
118
|
+
frame_proc = proc do
|
119
|
+
4.upto(7) do |y|
|
120
|
+
hat[0, y] = hat[7, y] = frame
|
121
|
+
end
|
122
|
+
end
|
123
|
+
else
|
124
|
+
# Just clock, with a frame around it
|
125
|
+
clock = BinaryClock.new(hat, 1, 2, red)
|
126
|
+
show_calendar = false
|
127
|
+
frame_proc = proc do
|
128
|
+
0.upto(7) do |x|
|
129
|
+
#hat[x, 7] = hat[x, 0] = frame
|
130
|
+
hat[x, 6] = hat[x, 1] = frame
|
131
|
+
end
|
132
|
+
2.upto(5) do |y|
|
133
|
+
hat[0, y] = hat[7, y] = frame
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
ot = nil
|
138
|
+
|
139
|
+
# Show it...
|
140
|
+
begin
|
141
|
+
loop do
|
142
|
+
t = Time.now
|
143
|
+
|
144
|
+
# set the display anew if hour/minute/sec changed
|
145
|
+
if ot.nil? || (ot.hour != t.hour || ot.min != t.min || ot.sec != t.sec)
|
146
|
+
ot = t
|
147
|
+
hat.clear(false)
|
148
|
+
clock.show(t)
|
149
|
+
calendar.show(t) if show_calendar
|
150
|
+
frame_proc.call
|
151
|
+
hat.show
|
152
|
+
end
|
153
|
+
|
154
|
+
sleep 0.1
|
155
|
+
end
|
156
|
+
rescue Interrupt
|
157
|
+
end
|
158
|
+
|
159
|
+
# cleanup
|
160
|
+
hat.clear
|
161
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
3
|
+
require 'ws2812'
|
4
|
+
|
5
|
+
# Single 3x5 pixels "digit" (think 7-segment display)
|
6
|
+
class Digit
|
7
|
+
n = nil # just to have the table below pretty
|
8
|
+
VALUES = {
|
9
|
+
n => [ 0b000, 0b000, 0b000, 0b000, 0b000, ],
|
10
|
+
0 => [ 0b111, 0b101, 0b101, 0b101, 0b111, ],
|
11
|
+
#1 => [ 0b010, 0b110, 0b010, 0b010, 0b010, ], # 1 in the middle
|
12
|
+
1 => [ 0b001, 0b011, 0b001, 0b001, 0b001, ], # 1 at the left
|
13
|
+
2 => [ 0b111, 0b001, 0b111, 0b100, 0b111, ],
|
14
|
+
3 => [ 0b111, 0b001, 0b111, 0b001, 0b111, ],
|
15
|
+
4 => [ 0b101, 0b101, 0b111, 0b001, 0b001, ],
|
16
|
+
5 => [ 0b111, 0b100, 0b111, 0b001, 0b111, ],
|
17
|
+
#6 => [ 0b111, 0b100, 0b111, 0b101, 0b111, ], # "full" six
|
18
|
+
6 => [ 0b100, 0b100, 0b111, 0b101, 0b111, ], # "sparse" six
|
19
|
+
7 => [ 0b111, 0b001, 0b001, 0b001, 0b001, ],
|
20
|
+
8 => [ 0b111, 0b101, 0b111, 0b101, 0b111, ],
|
21
|
+
#9 => [ 0b111, 0b101, 0b111, 0b001, 0b111, ], # "full" nine
|
22
|
+
9 => [ 0b111, 0b101, 0b111, 0b001, 0b001, ], # "sparse" nine
|
23
|
+
}
|
24
|
+
|
25
|
+
def initialize(hat, x, y, color, off_color = nil)
|
26
|
+
off_color ||= Ws2812::Color.new(0, 0, 0)
|
27
|
+
@hat, @x, @y, @color, @off_color = hat, x, y, color, off_color
|
28
|
+
end
|
29
|
+
attr_reader :hat
|
30
|
+
attr_accessor :x, :y, :color, :off_color
|
31
|
+
|
32
|
+
def show(value, do_show = false, &pixel_set)
|
33
|
+
pixel_set ||= method(:default_pixel_set)
|
34
|
+
raise ArgumentError, "invalid value" unless VALUES[value]
|
35
|
+
0.upto(4) do |y|
|
36
|
+
0.upto(2) do |x|
|
37
|
+
if VALUES[value][y][2-x].zero?
|
38
|
+
pixel_set.call(@hat,@x + x, @y + y, @off_color)
|
39
|
+
else
|
40
|
+
pixel_set.call(@hat,@x + x, @y + y, @color)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@hat.show if do_show
|
45
|
+
end
|
46
|
+
|
47
|
+
def default_pixel_set(hat, x, y, color)
|
48
|
+
hat[x, y] = color
|
49
|
+
end
|
50
|
+
private :default_pixel_set
|
51
|
+
end
|
52
|
+
|
53
|
+
# Two Digits next to each other with one pixel gap
|
54
|
+
# (think two 7-segment displays next to each other)
|
55
|
+
class TwoDigits
|
56
|
+
def initialize(hat, x, y, color, off_color = nil)
|
57
|
+
@tens = Digit.new(hat, x, y, color, off_color)
|
58
|
+
@singles = Digit.new(hat, x + 4, y, color, off_color)
|
59
|
+
@hat, @x, @y, @color = hat, x, y, color
|
60
|
+
@leading_zero = false
|
61
|
+
end
|
62
|
+
attr_reader :hat, :x, :y, :color, :off_color
|
63
|
+
attr_accessor :leading_zero
|
64
|
+
|
65
|
+
def show(value, do_show = false, &pixel_set)
|
66
|
+
tens_value = value / 10
|
67
|
+
tens_value = nil if !@leading_zero && tens_value.zero?
|
68
|
+
@tens.show(tens_value, false, &pixel_set)
|
69
|
+
@singles.show(value % 10, false, &pixel_set)
|
70
|
+
@hat.show if do_show
|
71
|
+
end
|
72
|
+
|
73
|
+
def off_color
|
74
|
+
@tens.off_color
|
75
|
+
end
|
76
|
+
|
77
|
+
def off_color=(val)
|
78
|
+
@tens.off_color = @singles.off_color = val
|
79
|
+
end
|
80
|
+
|
81
|
+
def color=(val)
|
82
|
+
@tens.color = @singles.color = val
|
83
|
+
end
|
84
|
+
|
85
|
+
def x=(val)
|
86
|
+
@tens.x = val
|
87
|
+
@singles.x = val + 4
|
88
|
+
end
|
89
|
+
|
90
|
+
def y=(val)
|
91
|
+
@tens.y = @singles.y = val
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
if __FILE__ == $0
|
96
|
+
# Init
|
97
|
+
hat = Ws2812::UnicornHAT.new
|
98
|
+
hat.rotation = 180
|
99
|
+
|
100
|
+
gc = Ws2812::GammaCorrection.new(20) # => "brightness" set to 20
|
101
|
+
hat.direct = true
|
102
|
+
# Note: I'm using direct mode with custom +gc+ here so I can better
|
103
|
+
# "animate" the pixels where hours and minutes overlap (both set)
|
104
|
+
#
|
105
|
+
# Without direct mode you're flying blind and changing the uncorrected
|
106
|
+
# values, while possible, looks fugly in lower brightness (i.e. 20)
|
107
|
+
black = gc.correct(Ws2812::Color.new(0, 0, 0))
|
108
|
+
red = gc.correct(Ws2812::Color.new(0xff, 0, 0))
|
109
|
+
green = gc.correct(Ws2812::Color.new(0, 0xaa, 0))
|
110
|
+
both = gc.correct(Ws2812::Color.new(0xff, 0xaa, 0))
|
111
|
+
h = TwoDigits.new(hat, 0, 0, red, black)
|
112
|
+
m = TwoDigits.new(hat, 1, 3, green, black)
|
113
|
+
m.leading_zero = true
|
114
|
+
|
115
|
+
# The following proc block allows us to merge individual red+green pixels
|
116
|
+
# into one aggregate "both" pixel (same Ws2812::Color instance). Thus
|
117
|
+
# allowing us to change one value (and then call +#push_all_pixels+) for
|
118
|
+
# update of the whole array.
|
119
|
+
green_ps = proc do |hat, x, y, color|
|
120
|
+
if hat[x, y] == red
|
121
|
+
hat[x, y] = both if color == green
|
122
|
+
# otherwise stays red
|
123
|
+
else
|
124
|
+
hat[x, y] = color
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
begin
|
129
|
+
ticks = 25
|
130
|
+
tick = 0
|
131
|
+
direction = 1
|
132
|
+
ot = nil
|
133
|
+
loop do
|
134
|
+
t = Time.now
|
135
|
+
|
136
|
+
# set the display anew if hour/minute changed
|
137
|
+
if ot.nil? || (ot.hour != t.hour || ot.min != t.min)
|
138
|
+
ot = t
|
139
|
+
hat.clear(false)
|
140
|
+
h.show(t.hour, false)
|
141
|
+
m.show(t.min, false, &green_ps)
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
# animate "both" pixels (where hour & minute overlay)
|
146
|
+
both.r = (red.r * tick.to_f/ticks).to_i
|
147
|
+
both.g = (green.g * ((ticks - tick).to_f/ticks)).to_i
|
148
|
+
both.r = both.g = 1 if both.r.zero? && both.g.zero?
|
149
|
+
hat.push_all_pixels
|
150
|
+
|
151
|
+
if direction > 0
|
152
|
+
direction = -1 if tick + 1 >= ticks
|
153
|
+
tick = tick + 1
|
154
|
+
else
|
155
|
+
direction = 1 if tick - 1 <= 0
|
156
|
+
tick = tick - 1
|
157
|
+
end
|
158
|
+
|
159
|
+
hat.show
|
160
|
+
sleep 0.1
|
161
|
+
end
|
162
|
+
rescue Interrupt
|
163
|
+
end
|
164
|
+
|
165
|
+
# cleanup
|
166
|
+
hat.clear
|
167
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
3
|
+
require 'ws2812'
|
4
|
+
|
5
|
+
# Init
|
6
|
+
n = 64 # num leds
|
7
|
+
ws = Ws2812::Basic.new(n, 18) # +n+ leds at pin 18, using defaults
|
8
|
+
ws.open
|
9
|
+
ws.brightness = 255
|
10
|
+
if ARGV.first
|
11
|
+
puts 'Using direct mode.'
|
12
|
+
puts 'Remove all positional parameters to switch to gamma-corrected mode.'
|
13
|
+
ws.direct = true
|
14
|
+
else
|
15
|
+
puts 'Using gamma-corrected mode.'
|
16
|
+
puts 'Add (any) positional parameter to switch to direct mode.'
|
17
|
+
end
|
18
|
+
|
19
|
+
# up...
|
20
|
+
0.upto(255) do |i|
|
21
|
+
ws[0..63] = Ws2812::Color.new(i, i, i)
|
22
|
+
ws.show
|
23
|
+
sleep 0.01
|
24
|
+
end
|
25
|
+
|
26
|
+
# and down...
|
27
|
+
255.downto(0) do |i|
|
28
|
+
ws[0..63] = Ws2812::Color.new(i, i, i)
|
29
|
+
ws.show
|
30
|
+
sleep 0.01
|
31
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
3
|
+
require 'ws2812'
|
4
|
+
|
5
|
+
# Init
|
6
|
+
hat = Ws2812::UnicornHAT.new
|
7
|
+
|
8
|
+
# first corner set to red
|
9
|
+
red = Ws2812::Color.new(0xff, 0, 0)
|
10
|
+
hat[0, 0] = red
|
11
|
+
hat[0, 1] = red
|
12
|
+
hat[1, 0] = red
|
13
|
+
|
14
|
+
# second to green
|
15
|
+
green = Ws2812::Color.new(0, 0xff, 0)
|
16
|
+
hat[6, 7] = green
|
17
|
+
hat[7, 7] = green
|
18
|
+
hat[7, 6] = green
|
19
|
+
|
20
|
+
# middle part
|
21
|
+
hat[3, 3] = red
|
22
|
+
hat[4, 4] = green
|
23
|
+
|
24
|
+
|
25
|
+
# show it
|
26
|
+
hat.show
|
27
|
+
|
28
|
+
sleep 0.5
|
29
|
+
|
30
|
+
# rotate around till ^C
|
31
|
+
puts "Spinning... ^C to terminate"
|
32
|
+
begin
|
33
|
+
loop do
|
34
|
+
# rotate around
|
35
|
+
for rot in [90, 180, 270, 0]
|
36
|
+
hat.rotation = rot
|
37
|
+
hat.show
|
38
|
+
|
39
|
+
sleep 0.5
|
40
|
+
end
|
41
|
+
end
|
42
|
+
rescue Interrupt
|
43
|
+
end
|
44
|
+
|
45
|
+
# Clear the display at the end
|
46
|
+
hat.clear
|
47
|
+
hat.show
|
@@ -0,0 +1,143 @@
|
|
1
|
+
/*
|
2
|
+
* This needs cleaning up and expanding. The MODEL_* defines shoudl be in
|
3
|
+
* board_info.h, it currently identifies everything not a B2 as a B, it
|
4
|
+
* should have an accessor function for the board model and revision, etc.
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <stdlib.h>
|
9
|
+
#include <stdarg.h>
|
10
|
+
#include <string.h>
|
11
|
+
|
12
|
+
#include "board_info.h"
|
13
|
+
|
14
|
+
enum
|
15
|
+
{
|
16
|
+
MODEL_UNKNOWN,
|
17
|
+
MODEL_A,
|
18
|
+
MODEL_A_PLUS,
|
19
|
+
MODEL_B,
|
20
|
+
MODEL_B_PLUS,
|
21
|
+
MODEL_B_2,
|
22
|
+
};
|
23
|
+
|
24
|
+
static int board_info_initialised = 0;
|
25
|
+
static int board_model = MODEL_UNKNOWN;
|
26
|
+
static int board_revision;
|
27
|
+
|
28
|
+
static void
|
29
|
+
fatal(char *fmt, ...)
|
30
|
+
{
|
31
|
+
va_list ap;
|
32
|
+
|
33
|
+
va_start(ap, fmt);
|
34
|
+
vfprintf(stderr, fmt, ap);
|
35
|
+
va_end(ap);
|
36
|
+
exit(1);
|
37
|
+
}
|
38
|
+
|
39
|
+
static unsigned get_dt_ranges(const char *filename, unsigned offset)
|
40
|
+
{
|
41
|
+
unsigned address = ~0;
|
42
|
+
FILE *fp = fopen(filename, "rb");
|
43
|
+
if (fp)
|
44
|
+
{
|
45
|
+
unsigned char buf[4];
|
46
|
+
fseek(fp, offset, SEEK_SET);
|
47
|
+
if (fread(buf, 1, sizeof buf, fp) == sizeof buf)
|
48
|
+
address = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
|
49
|
+
fclose(fp);
|
50
|
+
}
|
51
|
+
return address;
|
52
|
+
}
|
53
|
+
|
54
|
+
uint32_t board_info_peripheral_base_addr(void)
|
55
|
+
{
|
56
|
+
unsigned address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
|
57
|
+
|
58
|
+
board_info_init();
|
59
|
+
|
60
|
+
if (address == ~0)
|
61
|
+
{
|
62
|
+
if (board_model == MODEL_B_2)
|
63
|
+
return 0x3f000000;
|
64
|
+
else
|
65
|
+
return 0x20000000;
|
66
|
+
}
|
67
|
+
else
|
68
|
+
{
|
69
|
+
return address;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
uint32_t board_info_sdram_address(void)
|
74
|
+
{
|
75
|
+
unsigned address = get_dt_ranges("/proc/device-tree/axi/vc_mem/reg", 8);
|
76
|
+
|
77
|
+
board_info_init();
|
78
|
+
|
79
|
+
if (address == ~0)
|
80
|
+
{
|
81
|
+
if (board_model == MODEL_B_2)
|
82
|
+
return 0xc0000000;
|
83
|
+
else
|
84
|
+
return 0x40000000;
|
85
|
+
}
|
86
|
+
else
|
87
|
+
{
|
88
|
+
return address;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
int board_info_init(void)
|
93
|
+
{
|
94
|
+
char buf[128], revstr[128], modelstr[128];
|
95
|
+
char *ptr, *end, *res;
|
96
|
+
FILE *fp;
|
97
|
+
|
98
|
+
if (board_info_initialised)
|
99
|
+
return 0;
|
100
|
+
|
101
|
+
revstr[0] = modelstr[0] = '\0';
|
102
|
+
|
103
|
+
fp = fopen("/proc/cpuinfo", "r");
|
104
|
+
|
105
|
+
if (!fp)
|
106
|
+
fatal("Unable to open /proc/cpuinfo: %m\n");
|
107
|
+
|
108
|
+
while ((res = fgets(buf, 128, fp))) {
|
109
|
+
if (!strncasecmp("model name", buf, 8))
|
110
|
+
memcpy(modelstr, buf, 128);
|
111
|
+
else if (!strncasecmp(buf, "revision", 8))
|
112
|
+
memcpy(revstr, buf, 128);
|
113
|
+
}
|
114
|
+
fclose(fp);
|
115
|
+
|
116
|
+
if (modelstr[0] == '\0')
|
117
|
+
fatal("No 'Model name' record in /proc/cpuinfo\n");
|
118
|
+
if (revstr[0] == '\0')
|
119
|
+
fatal("No 'Revision' record in /proc/cpuinfo\n");
|
120
|
+
|
121
|
+
if (strstr(modelstr, "ARMv6"))
|
122
|
+
board_model = MODEL_B;
|
123
|
+
else if (strstr(modelstr, "ARMv7"))
|
124
|
+
board_model = MODEL_B_2;
|
125
|
+
else
|
126
|
+
fatal("Cannot parse the model name string\n");
|
127
|
+
|
128
|
+
ptr = revstr + strlen(revstr) - 3;
|
129
|
+
board_revision = strtol(ptr, &end, 16);
|
130
|
+
if (end != ptr + 2)
|
131
|
+
fatal("Failed to parse Revision string\n");
|
132
|
+
if (board_revision < 1)
|
133
|
+
fatal("Invalid board Revision\n");
|
134
|
+
else if (board_revision < 4)
|
135
|
+
board_revision = 1;
|
136
|
+
else
|
137
|
+
board_revision = 2;
|
138
|
+
|
139
|
+
board_info_initialised = 1;
|
140
|
+
|
141
|
+
return 0;
|
142
|
+
}
|
143
|
+
|