sd 0.0.1
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/bin/sd-util.rb +77 -0
- data/lib/sd.rb +246 -0
- metadata +49 -0
data/bin/sd-util.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: UTF-8
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
lib="sd"
|
8
|
+
if File.file? "./lib/#{lib}.rb"
|
9
|
+
require "./lib/#{lib}.rb"
|
10
|
+
puts "using local #{lib}"
|
11
|
+
local=true
|
12
|
+
else
|
13
|
+
require lib
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
options={}
|
18
|
+
|
19
|
+
|
20
|
+
$sd=Sd.new options
|
21
|
+
|
22
|
+
if not $sd.init
|
23
|
+
exit -1
|
24
|
+
else
|
25
|
+
pp $sd.ident
|
26
|
+
end
|
27
|
+
#cmd :send_status
|
28
|
+
|
29
|
+
b=4
|
30
|
+
|
31
|
+
if false
|
32
|
+
tb=1000
|
33
|
+
mul=5000
|
34
|
+
erase 0,tb*mul
|
35
|
+
|
36
|
+
rers=wers=0
|
37
|
+
start=Time.now.to_f
|
38
|
+
(0..tb).each do |j|
|
39
|
+
start2=Time.now.to_f
|
40
|
+
buf=[]
|
41
|
+
$blklen.times do |i|
|
42
|
+
buf << ((i+j)&0xff)
|
43
|
+
end
|
44
|
+
a=$blklen*j*mul
|
45
|
+
printf "%08X (%.3fMb) [%d]",a,a/1000000.0,j*mul
|
46
|
+
write a,buf
|
47
|
+
d=cmd :read_single_block,a
|
48
|
+
now=Time.now.to_f
|
49
|
+
if buf==d
|
50
|
+
printf "OK %.2f %.2f\n",now-start,now-start2
|
51
|
+
else
|
52
|
+
puts "ER"
|
53
|
+
wers+=1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
puts "Verify:"
|
57
|
+
start=Time.now.to_f
|
58
|
+
(0..tb).each do |j|
|
59
|
+
start2=Time.now.to_f
|
60
|
+
buf=[]
|
61
|
+
$blklen.times do |i|
|
62
|
+
buf << ((i+j)&0xff)
|
63
|
+
end
|
64
|
+
a=$blklen*j*mul
|
65
|
+
printf "%08X ",a
|
66
|
+
d=cmd :read_single_block,a
|
67
|
+
now=Time.now.to_f
|
68
|
+
if buf==d
|
69
|
+
printf "OK %.2f %.2f\n",now-start,now-start2
|
70
|
+
else
|
71
|
+
puts "ER"
|
72
|
+
rers+=1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
puts "Write Errs: #{wers}, Read Errs: #{rers}"
|
76
|
+
end
|
77
|
+
|
data/lib/sd.rb
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: UTF-8
|
3
|
+
|
4
|
+
require 'pp'
|
5
|
+
require 'time'
|
6
|
+
require 'pi_piper'
|
7
|
+
include PiPiper
|
8
|
+
|
9
|
+
class Sd
|
10
|
+
Cmds={
|
11
|
+
send_op_cond: {op: 1, retlen: 1},
|
12
|
+
send_csd: {op: 9, retlen: 1, data: :read, datalen:18},
|
13
|
+
send_cid: {op: 10, retlen: 1, data: :read, datalen:18},
|
14
|
+
send_status: {op: 13, retlen: 2},
|
15
|
+
set_blocklen: {op: 16, retlen: 1},
|
16
|
+
read_single_block: {op: 17, retlen: 1, data: :read},
|
17
|
+
write_block: {op: 24, retlen: 1, data: :write},
|
18
|
+
erase_start: {op: 32, retlen: 1},
|
19
|
+
erase_end: {op: 33, retlen: 1},
|
20
|
+
erase: {op: 38, retlen: 1, data: :busy},
|
21
|
+
send_scr: {op: 51, retlen: 1, data: :read, datalen:10},
|
22
|
+
app_cmd: {op: 55, retlen: 1},
|
23
|
+
read_ocr: {op: 58, retlen: 5},
|
24
|
+
}
|
25
|
+
|
26
|
+
def initialize(hash={})
|
27
|
+
hash[:blklen] = 512 if not hash[:blklen]
|
28
|
+
hash[:do] = 10 if not hash[:do]
|
29
|
+
hash[:di] = 9 if not hash[:di]
|
30
|
+
hash[:clk]= 11 if not hash[:clk]
|
31
|
+
hash[:cs] = 22 if not hash[:cs]
|
32
|
+
@blklen=hash[:blklen]
|
33
|
+
@options=hash
|
34
|
+
@cs =PiPiper::Pin.new(:pin => hash[:cs], :direction => :out)
|
35
|
+
@do =PiPiper::Pin.new(:pin => hash[:do], :direction => :out)
|
36
|
+
@clk=PiPiper::Pin.new(:pin => hash[:clk],:direction => :out)
|
37
|
+
@di =PiPiper::Pin.new(:pin => hash[:di], :direction => :in,:pull => :down)
|
38
|
+
@cs.on
|
39
|
+
@clk.off
|
40
|
+
@do.off
|
41
|
+
@SPI_CLOCK=2500000
|
42
|
+
end
|
43
|
+
|
44
|
+
def outbytes c,l,retlen=1
|
45
|
+
ret=[]
|
46
|
+
data=[]
|
47
|
+
cmd_data=[]
|
48
|
+
@cs.off
|
49
|
+
PiPiper::Spi.begin do
|
50
|
+
clock(2500000)
|
51
|
+
l.each do |b|
|
52
|
+
cmd_data << write(b)
|
53
|
+
end
|
54
|
+
write(0xff)
|
55
|
+
retlen.times do
|
56
|
+
data << write(0xff)
|
57
|
+
end
|
58
|
+
if c and c[:data] == :busy
|
59
|
+
tries=0
|
60
|
+
while (start=write(0xff))==0 do
|
61
|
+
if tries>10000
|
62
|
+
puts "Error: busy stuck (#{c},#{l})"
|
63
|
+
break
|
64
|
+
end
|
65
|
+
tries+=1
|
66
|
+
sleep 0.01
|
67
|
+
end
|
68
|
+
#puts "took #{tries} to unbusy"
|
69
|
+
elsif c and c[:data] == :read
|
70
|
+
data=[]
|
71
|
+
tries=0
|
72
|
+
while (start=write(0xff))!=0xfe do
|
73
|
+
if tries>1000
|
74
|
+
puts "Error: data read stuck with [0x#{start.to_s(16)}] (#{c},#{l}) tried #{tries}"
|
75
|
+
break
|
76
|
+
end
|
77
|
+
tries+=1
|
78
|
+
sleep 0.001
|
79
|
+
end
|
80
|
+
if start==0xfe
|
81
|
+
if c[:datalen]
|
82
|
+
c[:datalen].times do
|
83
|
+
data << write(0xff)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
(@blklen).times do
|
87
|
+
data << write(0xff)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
write(0xff)
|
91
|
+
write(0xff)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
@cs.on
|
96
|
+
data
|
97
|
+
end
|
98
|
+
|
99
|
+
def cmd cmd,val=0,retlen=nil
|
100
|
+
if not Cmds[cmd]
|
101
|
+
puts "Error: Unknown Command to SD: #{cmd}"
|
102
|
+
end
|
103
|
+
c=Cmds[cmd][:op]
|
104
|
+
retlen=Cmds[cmd][:retlen] if not retlen
|
105
|
+
l=[c|0x40]
|
106
|
+
l+=[val].pack("N").unpack("CCCC")
|
107
|
+
l<<1
|
108
|
+
data=outbytes Cmds[cmd],l,retlen
|
109
|
+
if @options[:verbose]
|
110
|
+
printf("%20.20s (%2d %08X): ",cmd,c,val)
|
111
|
+
data.each_with_index do |b,i|
|
112
|
+
printf("%02X ",b)# if i<30
|
113
|
+
end
|
114
|
+
puts ""
|
115
|
+
end
|
116
|
+
data
|
117
|
+
end
|
118
|
+
|
119
|
+
def hdump l
|
120
|
+
print "["
|
121
|
+
l.each do |b|
|
122
|
+
printf "%02X ", b
|
123
|
+
end
|
124
|
+
print "]\n"
|
125
|
+
end
|
126
|
+
|
127
|
+
def bdump l
|
128
|
+
print "["
|
129
|
+
l.each do |b|
|
130
|
+
printf "%08d ", b.to_s(2)
|
131
|
+
end
|
132
|
+
print "]\n"
|
133
|
+
end
|
134
|
+
|
135
|
+
def pickbits l,so,eo
|
136
|
+
sz=l.size*8
|
137
|
+
b=[]
|
138
|
+
s=sz-so-1
|
139
|
+
e=sz-eo-1
|
140
|
+
(s .. e).each do |bit|
|
141
|
+
byte=bit/8
|
142
|
+
oset=bit%8
|
143
|
+
bval= 1<<oset
|
144
|
+
v=(l[byte]&bval)==bval
|
145
|
+
if v
|
146
|
+
b=[1]+b
|
147
|
+
else
|
148
|
+
b=[0]+b
|
149
|
+
end
|
150
|
+
end
|
151
|
+
val=0
|
152
|
+
b.each do |bit|
|
153
|
+
val*=2
|
154
|
+
if bit==1
|
155
|
+
val|=1
|
156
|
+
end
|
157
|
+
end
|
158
|
+
#printf "%d:%d 0x%X (%d)\n",so,eo,val,val
|
159
|
+
val
|
160
|
+
end
|
161
|
+
|
162
|
+
def ident
|
163
|
+
info={}
|
164
|
+
ret=cmd :send_cid
|
165
|
+
if ret and ret!=[]
|
166
|
+
serno=""
|
167
|
+
ret[8...8+5].each do |b|
|
168
|
+
serno+=sprintf("%02X",b)
|
169
|
+
end
|
170
|
+
info=info.merge({
|
171
|
+
mid: ret[0].to_s(16),
|
172
|
+
oem:ret[1...1+2].pack("c*"),
|
173
|
+
pnm:ret[3...3+5].pack("c*"),
|
174
|
+
rev: ret[7],
|
175
|
+
serno: serno,
|
176
|
+
date: sprintf("%d/%d",2000+ret[14]/0x10,ret[14]&0xf),
|
177
|
+
})
|
178
|
+
end
|
179
|
+
ret=cmd :send_csd
|
180
|
+
if ret and ret!=[]
|
181
|
+
info[:block_size]=2**(pickbits ret[0..-3],83,80)
|
182
|
+
info[:block_count]=pickbits ret[0..-3],73,62
|
183
|
+
info[:capacity]=info[:block_count]*524288
|
184
|
+
info[:capacity_gb]=sprintf("%.1f",info[:block_count]*524288/(1000.0**3.0))
|
185
|
+
end
|
186
|
+
info
|
187
|
+
end
|
188
|
+
|
189
|
+
def boot
|
190
|
+
loop do
|
191
|
+
ret=outbytes nil,[0x40, 0, 0, 0, 0,0x95]
|
192
|
+
if ret[0]==0x01
|
193
|
+
break
|
194
|
+
end
|
195
|
+
end
|
196
|
+
loop do
|
197
|
+
ret=cmd :send_op_cond
|
198
|
+
if ret[0]==0x00
|
199
|
+
break
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def init
|
205
|
+
tries=0
|
206
|
+
ret=false
|
207
|
+
loop do
|
208
|
+
ret=cmd :read_ocr
|
209
|
+
if ret==[0,0,0,0,0]
|
210
|
+
if tries>10
|
211
|
+
puts "Error: Cannot Init SD Card"
|
212
|
+
ret=false
|
213
|
+
break
|
214
|
+
end
|
215
|
+
boot
|
216
|
+
sleep 0.01
|
217
|
+
else
|
218
|
+
break
|
219
|
+
end
|
220
|
+
tries+=1
|
221
|
+
end
|
222
|
+
if ret
|
223
|
+
cmd :set_blocklen,@blklen
|
224
|
+
end
|
225
|
+
ret
|
226
|
+
end
|
227
|
+
|
228
|
+
def erase from=0,till=0
|
229
|
+
return if till<=from
|
230
|
+
cmd :erase_start,from*@blklen
|
231
|
+
cmd :erase_end,till*@blklen
|
232
|
+
cmd :erase
|
233
|
+
end
|
234
|
+
def write addr=0,data=[]
|
235
|
+
return if not data or data==[]
|
236
|
+
buf=[0xfe]
|
237
|
+
buf+=data
|
238
|
+
buf << 0 #crc 2 bytes
|
239
|
+
buf << 0
|
240
|
+
buf << 0 #this will shift data response
|
241
|
+
|
242
|
+
cmd :write_block,addr
|
243
|
+
outbytes({data: :busy},buf)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ari Siitonen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-01-04 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Sd-card library for RPi in pure Ruby, supports SDHC via SPI, tested on
|
15
|
+
Raspberry Pi
|
16
|
+
email: jalopuuverstas@gmail.com
|
17
|
+
executables:
|
18
|
+
- sd-util.rb
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/sd.rb
|
23
|
+
- bin/sd-util.rb
|
24
|
+
homepage: https://github.com/arisi/sd
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 1.8.23
|
46
|
+
signing_key:
|
47
|
+
specification_version: 3
|
48
|
+
summary: sd-card library for RPi in pure Ruby
|
49
|
+
test_files: []
|