rsrec 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -0,0 +1,10 @@
1
+ === 0.0.2 / 2013-05-18
2
+ * Minor cleanup
3
+ * Updated gem dependencies
4
+ * Added coverage analysis in the tests
5
+ * Increased test coverage
6
+ * split the version in it's own file
7
+
8
+ === 0.0.1 / 2012-06-19
9
+ * Initial release
10
+ * Parses SREC files and does all the checks
@@ -0,0 +1,6 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ lib/rsrec.rb
5
+ lib/rsrec/version.rb
6
+ test/test_rsrec.rb
@@ -0,0 +1,48 @@
1
+ = rsrec
2
+
3
+ https://github.com/damphyr/rsrec
4
+
5
+ == DESCRIPTION:
6
+
7
+ Parser for the Motorola S-Record format
8
+
9
+ == REQUIREMENTS:
10
+
11
+ None, this is pure Ruby man!
12
+
13
+ == INSTALL:
14
+
15
+ * sudo gem install rsrec
16
+
17
+ == What the hell is SREC?
18
+ It's a hex text encoding for binary data. Really something you would use in embedded systems.
19
+
20
+ For more on the format check http://en.wikipedia.org/wiki/SREC_(file_format)
21
+
22
+ == Why?
23
+ Cause we need to parse these things and peek and poke at specific addresses before flashing. And it's a text format, which makes Ruby ideal.
24
+
25
+ == LICENSE:
26
+
27
+ (The MIT License)
28
+
29
+ Copyright (c) 2012 Vassilis Rizopoulos
30
+
31
+ Permission is hereby granted, free of charge, to any person obtaining
32
+ a copy of this software and associated documentation files (the
33
+ 'Software'), to deal in the Software without restriction, including
34
+ without limitation the rights to use, copy, modify, merge, publish,
35
+ distribute, sublicense, and/or sell copies of the Software, and to
36
+ permit persons to whom the Software is furnished to do so, subject to
37
+ the following conditions:
38
+
39
+ The above copyright notice and this permission notice shall be
40
+ included in all copies or substantial portions of the Software.
41
+
42
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
43
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
44
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
45
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
46
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
47
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
48
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,154 @@
1
+ require 'rsrec/version'
2
+ module S19
3
+ class SRecordError < RuntimeError
4
+ end
5
+
6
+ #Represents a line in the S-Record format
7
+ #
8
+ #http://en.wikipedia.org/wiki/SREC_%28file_format%29
9
+ class SRecord
10
+ attr_reader :binary,:data,:record_type,:byte_count,:address
11
+ def initialize rtype,addr,data
12
+ self.record_type= rtype
13
+ @address = addr
14
+ self.data=data
15
+ end
16
+
17
+ def to_s
18
+ "S#{@record_type}#{"%02x"% @byte_count}#{format_address}#{@data}#{crc}".upcase
19
+ end
20
+ #Returns the S-Record CRC
21
+ def crc
22
+ SRecord.calculate_crc("#{"%02x"% @byte_count}#{format_address}#{@data}")
23
+ end
24
+ #Parses a single line in SREC format and returns an SRecord instance
25
+ def self.parse text_data
26
+ text_data.chomp!
27
+ #duplicate because we're slicing and dicing and throwing stuff away
28
+ line=text_data.dup
29
+ #the (0..0) is for 1.8.7 compatibility, in 1.9 it gives the sliced char back
30
+ if line.slice!(0..0)=='S'
31
+ record_type = line.slice!(0..0).to_i
32
+ #convert everything to hex
33
+ #take out the byte count
34
+ line.slice!(0..1).to_i(16)
35
+ address = calculate_address(record_type,line)
36
+ #take out the crc
37
+ line.slice!(-2..-1)
38
+ data = line
39
+ check_crc(text_data)
40
+ return SRecord.new(record_type,address,data)
41
+ else
42
+ raise SRecordError,"Line without leading S"
43
+ end
44
+ end
45
+ #True if the record is of type 1,2 or 3
46
+ def data_record?
47
+ [1,2,3].include?(@record_type)
48
+ end
49
+ private
50
+ #Set the data.
51
+ #
52
+ #pld is just the payload in hex text format (2nhex digits pro byte)
53
+ def data= pld
54
+ @data=pld
55
+ @binary=SRecord.extract_data(pld)
56
+ #number of bytes in address+data+checksum (checksum is 1 byte)
57
+ @byte_count=format_address.size/2+@binary.size+1
58
+ end
59
+ #Raises SRecordError if supplied with an invalid record type
60
+ def record_type= rtype
61
+ case rtype
62
+ when 0,1,2,3,4,5,6,7,8,9
63
+ @record_type=rtype
64
+ else
65
+ raise SRecordError,"Invalid record type: '#{rtype}'. Should be a number"
66
+ end
67
+ end
68
+ #String representation of the address left padded with 0s
69
+ def format_address
70
+ case @record_type
71
+ when 0,1,5,9
72
+ return "%04x"% @address
73
+ when 2,8
74
+ return "%06x"% @address
75
+ when 3,7
76
+ return "%08x"% @address
77
+ end
78
+ end
79
+ #Gets 2n chars and converts them to hex
80
+ #
81
+ #n depends on the record type
82
+ def self.calculate_address record_type,line
83
+ case record_type
84
+ when 0,1,5,9
85
+ #2 character pairs
86
+ address=line.slice!(0..3).to_i(16)
87
+ when 2,8
88
+ #3 character pairs
89
+ address=line.slice!(0..5).to_i(16)
90
+ when 3,7
91
+ #4 character pairs
92
+ address=line.slice!(0..7).to_i(16)
93
+ else
94
+ raise SRecordError,"Cannot calculate address. Unknown record type #{@record_type}"
95
+ end
96
+ return address
97
+ end
98
+ #From an SREC text line calculate the CRC and check it against the embedded CRC
99
+ def self.check_crc raw_data
100
+ line = raw_data.dup
101
+ #chop of the S, the record type and the crc
102
+ line.slice!(0..1)
103
+ crc=line.slice!(-2..-1)
104
+ calculated_crc=calculate_crc(line)
105
+ if calculated_crc.upcase == crc.upcase
106
+ return crc
107
+ else
108
+ raise SRecordError, "CRC failure: #{calculated_crc} instead of #{crc}"
109
+ end
110
+ end
111
+
112
+ def self.calculate_crc line_data
113
+ data=extract_data(line_data)
114
+ data_sum=data.inject(0){|sum,item| sum + item}
115
+ #least significant byte is
116
+ lsb=data_sum & 0xFF
117
+ #1's complement of lsb and in hex string format
118
+ ("%02x"% (lsb^0xFF)).upcase
119
+ end
120
+ #Converts 2n hex characters in n bytes
121
+ def self.extract_data data_string
122
+ line=data_string.dup
123
+ binary=[]
124
+ while !line.empty?
125
+ data_chars = line.slice!(0..1)
126
+ binary<<data_chars.to_i(16)
127
+ end
128
+ return binary
129
+ end
130
+ end
131
+
132
+ class MotFile
133
+ attr_reader :records
134
+ def initialize records=[]
135
+ @records=records
136
+ end
137
+ def to_s
138
+ @records.each_with_object(""){|record,msg| msg<<"#{record}\n"}
139
+ end
140
+ #Just the data records
141
+ def data_records
142
+ @records.select{|rec| rec.data_record?}.compact
143
+ end
144
+ #The total size of the image in bytes
145
+ def image_size
146
+ data_records.last.address+data_records.last.binary.size-data_records.first.address
147
+ end
148
+ #Parses a .mot file in memory, returns MotFile
149
+ def self.from_file filename
150
+ records=File.readlines(filename).map{|line| SRecord.parse(line)}
151
+ MotFile.new(records)
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,8 @@
1
+ module S19
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 2
6
+ STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
7
+ end
8
+ end
@@ -0,0 +1,57 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),"..","lib")
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ require "test/unit"
5
+ require "rsrec"
6
+
7
+ class TestRsrec < Test::Unit::TestCase
8
+ def test_version
9
+ assert_equal(S19::Version::STRING, "#{S19::Version::MAJOR}.#{S19::Version::MINOR}.#{S19::Version::TINY}")
10
+ end
11
+
12
+ def test_srecord
13
+ test_record="S00E00005065726675736F726D6F744B"
14
+ srec=nil
15
+ assert_nothing_raised(S19::SRecordError) { srec=S19::SRecord.parse(test_record) }
16
+ assert_not_nil(srec)
17
+ assert_equal(test_record, srec.to_s)
18
+ assert_equal(0, srec.record_type)
19
+ assert_equal(14, srec.byte_count)
20
+ assert_equal("4B", srec.crc)
21
+ assert(!srec.data_record?, "Not a data record")
22
+ end
23
+
24
+ def test_srecord_crc
25
+ test_record="S00E00005065726675736F726D6F744A"
26
+ srec=nil
27
+ assert_raise(S19::SRecordError) { srec=S19::SRecord.parse(test_record) }
28
+ end
29
+
30
+ def test_trimming
31
+ test_record="S00E00005065726675736F726D6F744B\n"
32
+ assert_nothing_raised(S19::SRecordError) { S19::SRecord.parse(test_record) }
33
+ test_record="S00E00005065726675736F726D6F744B\r"
34
+ assert_nothing_raised(S19::SRecordError) { S19::SRecord.parse(test_record) }
35
+ test_record="S00E00005065726675736F726D6F744B\r\n"
36
+ assert_nothing_raised(S19::SRecordError) { S19::SRecord.parse(test_record) }
37
+ end
38
+
39
+ def test_format_checks
40
+ test_record="BF00726D6F744A"
41
+ assert_raise(S19::SRecordError) { S19::SRecord.parse(test_record) }
42
+ assert_raise(S19::SRecordError) { S19::SRecord.new(15,0x0405,"FOO") }
43
+ end
44
+
45
+ def test_data_records
46
+ test_record="S11F001C4BFFFFE5398000007D83637880010014382100107C0803A64E800020E9"
47
+ srec=nil
48
+ assert_nothing_raised(S19::SRecordError) { srec=S19::SRecord.parse(test_record) }
49
+ assert(srec.data_record?, "A data record")
50
+ test_record="S5030003F9"
51
+ assert_nothing_raised(S19::SRecordError) { srec=S19::SRecord.parse(test_record) }
52
+ assert(!srec.data_record?, "Not a data record")
53
+ test_record="S9030000FC"
54
+ assert_nothing_raised(S19::SRecordError) { srec=S19::SRecord.parse(test_record) }
55
+ assert(!srec.data_record?, "Not a data record")
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rsrec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vassilis Rizopoulos
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdoc
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '4.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '4.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: hoe
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.6'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.6'
46
+ description: ! 'https://github.com/damphyr/rsrec
47
+
48
+
49
+ == DESCRIPTION:
50
+
51
+
52
+ Parser for the Motorola S-Record format
53
+
54
+
55
+ == REQUIREMENTS:
56
+
57
+
58
+ None, this is pure Ruby man!'
59
+ email:
60
+ - vassilisrizopoulos@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files:
64
+ - History.txt
65
+ - Manifest.txt
66
+ - README.txt
67
+ files:
68
+ - History.txt
69
+ - Manifest.txt
70
+ - README.txt
71
+ - lib/rsrec.rb
72
+ - lib/rsrec/version.rb
73
+ - test/test_rsrec.rb
74
+ - .gemtest
75
+ homepage: http://github.com/damphyr/rsrec
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options:
79
+ - --main
80
+ - README.txt
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ segments:
90
+ - 0
91
+ hash: -639295409136969064
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project: rsrec
100
+ rubygems_version: 1.8.25
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: rsrec provides classes for parsing Motorola's S-Record format
104
+ test_files:
105
+ - test/test_rsrec.rb