ws2812 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|