modem_protocols 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.
Files changed (3) hide show
  1. data/lib/modem_protocols.rb +322 -0
  2. data/test/test_xmodem.rb +241 -0
  3. metadata +56 -0
@@ -0,0 +1,322 @@
1
+ # Author:: Jonno Downes (jonno@jamtronix.com)
2
+ # License:: Mozilla Public License 1.1
3
+
4
+
5
+ require 'log4r'
6
+ include Log4r
7
+
8
+ module ModemProtocols
9
+
10
+ XMODEM_BLOCK_SIZE=128 #how many bytes (ecluding header & checksum) in each block?
11
+ XMODEM_MAX_TIMEOUTS=5 #how many timeouts in a row before the sender gives up?
12
+ XMODEM_MAX_ERRORS=10 #how many errors on a single block before the receiver gives up?
13
+
14
+ XMODEM_CRC_ATTEMPTS=3 #how many times should receiver attempt to use CRC?
15
+ LOG_NAME='ModemProtocols'
16
+ @timeout_seconds=5.0 #default timeout period
17
+
18
+ #how long does the protocol wait before giving up?
19
+ def ModemProtocols::timeout_seconds
20
+ @timeout_seconds
21
+ end
22
+
23
+ def ModemProtocols::timeout_seconds=(val)
24
+ @timeout_seconds=val
25
+ end
26
+
27
+
28
+
29
+
30
+ # receive a file using XMODEM protocol (block size = 128 bytes)
31
+ # remote:: must be an IO object connected to an XMODEM sender
32
+ # local:: must be an IO object - the inbound file (trimmed of any final padding) will be written to this
33
+ # options:: hash of options. options are: values :crc (use 16bit CRC instead of 8 bit checksum)
34
+ # - :mode=> :crc or :checksum (default is 8 bit checksum)
35
+ #
36
+
37
+ def ModemProtocols::xmodem_rx(remote,local,options=nil)
38
+
39
+
40
+ mode = ( (options.nil?) || options[:mode].nil? ) ? :checksum : options[:mode]
41
+
42
+ logger.debug "rx: XMODEM - #{mode}"
43
+ #flush the input buffer
44
+ loop do
45
+ break if (select([remote],nil,nil,0.01).nil?)
46
+ remote.getc
47
+ end
48
+
49
+
50
+ #trigger sending
51
+ case mode
52
+ when :crc
53
+ XMODEM_CRC_ATTEMPTS.times do |attempt|
54
+ remote.putc('C')
55
+ break unless (select([remote],nil,nil,timeout_seconds).nil?)
56
+ #if we don't get a response, fall back to checksum mode
57
+ if attempt==XMODEM_CRC_ATTEMPTS-1 then
58
+ logger.warn "rx: crc-16 request failed, falling back to checksum mode"
59
+ remote.putc(NAK)
60
+ mode=:checksum
61
+ end
62
+ end
63
+ else
64
+ remote.putc(NAK)
65
+ end
66
+
67
+ expected_block=1
68
+ error_count=0
69
+ last_block=""
70
+ data=""
71
+ loop do
72
+
73
+ begin
74
+ rx_cmd=xmodem_rx_getbyte(remote)
75
+
76
+ if rx_cmd==EOT then
77
+ remote.putc(ACK)
78
+ trimmed_block=last_block.sub(/(\x1A+)\Z/,'')
79
+ local<< trimmed_block#trim any trailing FILLER characters in last block
80
+ break
81
+ end
82
+
83
+ if rx_cmd!=SOH then
84
+ logger.warn "rx: expected SOH (0x#{SOH}) got 0x#{"%x" % rx_cmd} - pos = #{remote.pos}"
85
+ next
86
+ end
87
+
88
+ data=""
89
+ block=xmodem_rx_getbyte(remote)
90
+ block_check=xmodem_rx_getbyte(remote)
91
+ validity=:valid
92
+ validity=:invalid unless (block_check+block)==0xFF
93
+
94
+ logger.debug "rx: #{validity} block number 0x#{"%02x" % block} / block number check 0x#{"%02x" % block_check}"
95
+ logger.debug "rx: receiving block #{block} / expected block #{expected_block}"
96
+ raise RXSynchError if block!=expected_block && block!=((expected_block-1) % 0x100)
97
+
98
+ if (block==expected_block) && (validity==:valid) then
99
+ local<<last_block
100
+ last_block=""
101
+ end
102
+ XMODEM_BLOCK_SIZE.times do
103
+ b=(xmodem_rx_getbyte(remote))
104
+ data<<b
105
+ Thread.pass
106
+ end
107
+
108
+
109
+ check_ok=false
110
+
111
+ case mode
112
+ when :crc
113
+ rx_crc=(xmodem_rx_getbyte(remote)<<8)+xmodem_rx_getbyte(remote)
114
+ crc=ccitt16_crc(data)
115
+ check_ok=(crc==rx_crc)
116
+ if !check_ok then
117
+ logger.warn "invalid crc-16 for block #{block}: calculated 0x#{'%04x' % crc}, got 0x#{'%02x' % rx_crc}"
118
+ end
119
+ else
120
+ rx_checksum=xmodem_rx_getbyte(remote)
121
+ checksum=xmodem_checksum(data)
122
+ check_ok=(checksum==rx_checksum)
123
+ if !check_ok then
124
+ logger.warn "invalid checksum for block #{block}: calculated 0x#{'%02x' % checksum}, got 0x#{'%02x' % rx_checksum}"
125
+ end
126
+ end
127
+
128
+ if (check_ok) then
129
+ last_block=data
130
+ logger.debug "rx: #{mode} test passed for block #{block}"
131
+ remote.putc(ACK)
132
+ if (block==expected_block) then
133
+ expected_block=((expected_block+1) % 0x100)
134
+ error_count=0 #reset the error count
135
+ end
136
+ else
137
+ remote.putc(NAK)
138
+ error_count+=1
139
+ logger.warn "rx: checksum error # #{error_count} / max #{XMODEM_MAX_ERRORS}"
140
+ raise RXChecksumError.new("too many receive errors on block #{block}") if error_count>XMODEM_MAX_ERRORS
141
+ end
142
+ rescue RXTimeout
143
+ error_count+=1
144
+ logger.warn "rx: timeout error # #{error_count} / max #{XMODEM_MAX_ERRORS}"
145
+ raise RXTimeout("too many receive errors on block #{block}").new if error_count>XMODEM_MAX_ERRORS
146
+ end
147
+ end
148
+
149
+ logger.info "receive complete"
150
+ end
151
+
152
+ # send a file using standard XMODEM protocol (block size = 128 bytes)
153
+ # will use CRC mode if requested by sender, else use 8-bit checksum
154
+ # remote:: must be an IO object connected to an XMODEM receiver
155
+ # local:: must be an IO object containing the data to be sent
156
+ def ModemProtocols::xmodem_tx(remote,local)
157
+ block_number=1
158
+ current_block=""
159
+ sent_eot=false
160
+
161
+ XMODEM_BLOCK_SIZE.times do
162
+ b=(local.eof? ? FILLER : local.getc)
163
+ current_block<<b.chr
164
+ Thread.pass
165
+ end
166
+ checksum=xmodem_checksum(current_block)
167
+ mode=:checksum
168
+ loop do
169
+ logger.info "tx: waiting for ACK/NAK/CAN (eot_sent: #{sent_eot})"
170
+ if select([remote],nil,nil,timeout_seconds*XMODEM_MAX_TIMEOUTS).nil? then
171
+ raise RXTimeout.new("timeout waiting for input on tx (#{timeout_seconds*XMODEM_MAX_TIMEOUTS} seconds)") unless sent_eot
172
+ logger.info "tx: timeout waiting for ACK of EOT"
173
+ return
174
+ end
175
+ if remote.eof? then
176
+ logger.warn "tx: unexpected eof on input"
177
+ break
178
+ end
179
+ tx_cmd=remote.getc
180
+ logger.debug "tx: got 0x#{"%x" % tx_cmd}"
181
+ if tx_cmd==ACK then
182
+ if sent_eot then
183
+ logger.debug "tx: got ACK of EOT"
184
+ break
185
+ end
186
+
187
+ if local.eof? then
188
+ remote.putc(EOT)
189
+ logger.debug "tx: got ACK of last block"
190
+ sent_eot=true
191
+ next
192
+ end
193
+ block_number=((block_number+1)%0x100)
194
+ current_block=""
195
+ XMODEM_BLOCK_SIZE.times do
196
+ b=(local.eof? ? FILLER : local.getc)
197
+ current_block<<b
198
+ Thread.pass
199
+ end
200
+
201
+ elsif (block_number==1) && (tx_cmd==CRC_MODE) then
202
+ mode=:crc
203
+ logger.debug "tx: using crc-16 mode"
204
+ end
205
+
206
+ next unless [ACK,NAK,CRC_MODE].include?(tx_cmd)
207
+ logger.info "tx: sending block #{block_number}"
208
+ remote.putc(SOH) #start of block
209
+ remote.putc(block_number) #block number
210
+ remote.putc(0xff-block_number) #1's complement of block number
211
+ current_block.each_byte {|b| remote.putc(b)}
212
+ case mode
213
+ when :crc then
214
+ crc=ccitt16_crc(current_block)
215
+ remote.putc(crc>>8) #crc hi byte
216
+ remote.putc(crc & 0xFF) #crc lo byte
217
+ logger.debug "tx: crc-16 for block #{block_number}:#{ "%04x" % crc}"
218
+ else
219
+ checksum=xmodem_checksum(current_block)
220
+ remote.putc(checksum)
221
+ logger.debug "tx: checksum for block #{block_number}:#{ "%02x" % checksum}"
222
+ end
223
+
224
+ end
225
+ logger.info "transmit complete (eot_sent: #{sent_eot})"
226
+ end
227
+
228
+ #calculate an 8-bit XMODEM checksum
229
+ #this is just the sum of all bytes modulo 0x100
230
+ def ModemProtocols::xmodem_checksum(block)
231
+ raise RXChecksumError("checksum requested of invalid block {size should be #{XMODEM_BLOCK_SIZE}, was #{block.length}") unless block.length==XMODEM_BLOCK_SIZE
232
+ checksum=0
233
+ block.each_byte do |b|
234
+ checksum=(checksum+b)%0x100
235
+ end
236
+ checksum
237
+ end
238
+
239
+ #calculate a 16-bit CRC
240
+ def ModemProtocols::ccitt16_crc(block)
241
+ #cribbed from http://www.hadermann.be/blog/32/ruby-crc16-implementation/
242
+ raise RXChecksumError("checksum requested of invalid block {size should be #{XMODEM_BLOCK_SIZE}, was #{block.length}") unless block.length==XMODEM_BLOCK_SIZE
243
+ crc=0
244
+ block.each_byte{|x| crc = ((crc<<8) ^ CCITT_16[(crc>>8) ^ x])&0xffff}
245
+ crc
246
+ end
247
+
248
+ private
249
+
250
+ SOH = 0x01
251
+ STX = 0x02
252
+ EOT = 0x04
253
+ ACK = 0x06
254
+ NAK = 0x15
255
+ CAN = 0x18
256
+ CRC_MODE=0x43 #'C'
257
+ FILLER = 0x1A
258
+
259
+
260
+ CCITT_16 = [
261
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
262
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
263
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
264
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
265
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
266
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
267
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
268
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
269
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
270
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
271
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
272
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
273
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
274
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
275
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
276
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
277
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
278
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
279
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
280
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
281
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
282
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
283
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
284
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
285
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
286
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
287
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
288
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
289
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
290
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
291
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
292
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
293
+ ]
294
+
295
+
296
+
297
+ def ModemProtocols::xmodem_rx_getbyte(remote)
298
+
299
+ if (select([remote],nil,nil,timeout_seconds).nil?) then
300
+ remote.putc(NAK)
301
+ raise RXTimeout
302
+ end
303
+ raise RXSynchError if remote.eof?
304
+ remote.getc
305
+ end
306
+
307
+
308
+ def ModemProtocols::logger
309
+ Logger.new(LOG_NAME) if Logger[LOG_NAME].nil?
310
+ Logger[LOG_NAME]
311
+ end
312
+
313
+ class RXTimeout < RuntimeError
314
+ end
315
+
316
+ class RXChecksumError < RuntimeError
317
+ end
318
+
319
+ class RXSynchError < RuntimeError
320
+ end
321
+
322
+ end
@@ -0,0 +1,241 @@
1
+
2
+ #make sure the relevant folder with our libraries is in the require path
3
+ lib_path=File.expand_path(File.dirname(__FILE__)+"//..//lib")
4
+ $:.unshift(lib_path) unless $:.include?(lib_path)
5
+
6
+
7
+ require 'modem_protocols'
8
+ require 'test/unit'
9
+ require 'socket'
10
+
11
+
12
+ Thread.abort_on_exception = true
13
+
14
+
15
+ ModemProtocols::logger.outputters = Outputter.stdout
16
+
17
+
18
+ ModemProtocols::timeout_seconds=0.4 #so we don't wait so long for retransmissions
19
+ LOCAL_PORT=9999
20
+
21
+
22
+ module CorruptIn
23
+ attr_accessor :real_getc,:corruption_frequency
24
+
25
+ def getc
26
+ @char_count=0 if @char_count.nil?
27
+
28
+ raise "real_getc not initialised" if @real_getc.nil?
29
+ b=@real_getc.call
30
+ @char_count+=1
31
+ if ((@char_count % @corruption_frequency)==0) then
32
+ corrupted_char=0xff-b
33
+ $stdout.puts "corrupting : 0x%02x -> 0x%02x" % [b,corrupted_char]
34
+ b=corrupted_char
35
+ end
36
+ return b
37
+ end
38
+
39
+ end
40
+
41
+ module CorruptOut
42
+ attr_accessor :real_putc,:corruption_frequency
43
+
44
+ def putc (b)
45
+ @char_count=0 if @char_count.nil?
46
+
47
+ raise "real_putc not initialised" if @real_putc.nil?
48
+ @char_count+=1
49
+ if ((@char_count % @corruption_frequency)==0) then
50
+ corrupted_char=0xff-b
51
+ $stdout.puts "corrupting : 0x%02x -> 0x%02x" % [b,corrupted_char]
52
+ b=corrupted_char
53
+ end
54
+ @real_putc.call(b)
55
+
56
+ end
57
+ end
58
+
59
+
60
+ module DropIn
61
+ attr_accessor :real_getc,:drop_frequency
62
+
63
+ def getc
64
+ @char_count=0 if @char_count.nil?
65
+
66
+ raise "real_getc not initialised" if @real_getc.nil?
67
+ b=@real_getc.call
68
+ @char_count+=1
69
+ if ((@char_count % @drop_frequency)==0) then
70
+ $stdout.puts "dropping : 0x%02x " % [b]
71
+ @real_getc.call
72
+ end
73
+ return b
74
+ end
75
+ end
76
+
77
+ module DropOut
78
+ attr_accessor :real_putc,:drop_frequency
79
+
80
+ def putc (b)
81
+ @char_count=0 if @char_count.nil?
82
+
83
+ raise "real_putc not initialised" if @real_putc.nil?
84
+ @char_count+=1
85
+ if ((@char_count % @drop_frequency)==0) then
86
+ $stdout.puts "dropping : 0x%02x " % [b]
87
+ else
88
+ @real_putc.call(b)
89
+ end
90
+ end
91
+ end
92
+
93
+
94
+ class XmodemTests< Test::Unit::TestCase
95
+
96
+
97
+ def test_checksum
98
+ assert_equal(0,ModemProtocols::xmodem_checksum( "\000"*128))
99
+ assert_equal(128,ModemProtocols::xmodem_checksum("\001"*128))
100
+ assert_equal(0,ModemProtocols::xmodem_checksum("\002"*128))
101
+ assert_equal(128,ModemProtocols::xmodem_checksum("\003"*128))
102
+
103
+
104
+ end
105
+
106
+ @@server=nil
107
+ def sendfile(file)
108
+ if @@server.nil? then
109
+ @@server = TCPServer.new('localhost', LOCAL_PORT)
110
+ else
111
+ puts "reusing existing server"
112
+ end
113
+ session = @@server.accept
114
+ session.sync=true
115
+ puts "Connected (sendfile)"
116
+ ModemProtocols::xmodem_tx(session,file)
117
+ session.close
118
+
119
+ end
120
+
121
+ def acceptfile(file,error_type=nil,error_frequency=nil,rx_options=nil)
122
+ socket=TCPSocket.new('localhost', LOCAL_PORT)
123
+ socket.sync=true
124
+ puts "Connected (acceptfile)"
125
+ if !error_frequency.nil? then
126
+ real_getc=socket.method(:getc)
127
+
128
+ case error_type
129
+ when :corruption_in
130
+ real_getc=socket.method(:getc)
131
+ socket.extend(CorruptIn)
132
+ socket.corruption_frequency=error_frequency
133
+ socket.real_getc=real_getc
134
+ when :packet_loss_in
135
+ real_getc=socket.method(:getc)
136
+ socket.extend(DropIn)
137
+ socket.drop_frequency=error_frequency
138
+ socket.real_getc=real_getc
139
+ when :packet_loss_out
140
+ real_putc=socket.method(:putc)
141
+ socket.extend(DropOut)
142
+ socket.drop_frequency=error_frequency
143
+ socket.real_putc=real_putc
144
+ when :corruption_out
145
+ real_putc=socket.method(:putc)
146
+ socket.extend(CorruptOut)
147
+ socket.corruption_frequency=error_frequency
148
+ socket.real_putc=real_putc
149
+ else
150
+ raise "unknown error_type #{error_type}"
151
+ end
152
+ file.flush
153
+ end
154
+ ModemProtocols::xmodem_rx(socket,file,rx_options)
155
+ loop {Thread.pass} until socket.closed?
156
+
157
+ end
158
+
159
+ def do_test(tx_file,rx_file,error_type=nil,error_frequency=nil,rx_options=nil)
160
+ test_description="test type: #{error_type}"
161
+ test_description+=" (freq=#{error_frequency})" unless error_frequency.nil?
162
+ made_tx=false
163
+ made_rx=false
164
+ if !(tx_file.respond_to?(:getc))
165
+ tx_filename=tx_file
166
+ tx_file=File.new(tx_filename,"rb")
167
+ else
168
+ tx_filename=tx_file.class
169
+ tx_file.rewind
170
+ end
171
+
172
+
173
+ if !(rx_file.respond_to?(:putc))
174
+ rx_filename=rx_file
175
+ rx_file=File.new(rx_filename,"wb+")
176
+ else
177
+ rx_filename=rx_file.class
178
+ rx_file.rewind
179
+ end
180
+ puts "#{test_description} : #{tx_filename}->#{rx_filename}"
181
+
182
+
183
+ tx_thread=Thread.new {sendfile(tx_file)}
184
+ rx_thread=Thread.new {acceptfile(rx_file,error_type,error_frequency,rx_options)}
185
+ loop do
186
+ break unless tx_thread.alive?
187
+ break unless rx_thread.alive?
188
+ sleep(0.01) #wake up occasionally to get keyboard input, so we break on ^C
189
+ end
190
+ tx_file.rewind
191
+ rx_file.rewind
192
+ rx_filecontents=rx_file.read
193
+ tx_filecontents=tx_file.read
194
+ assert_equal(tx_filecontents.length,rx_filecontents.length,"file length correct after round trip")
195
+ assert_equal(tx_filecontents,rx_filecontents,"file contents correct after round trip")
196
+
197
+ tx_file.close if made_tx
198
+ rx_file.close if made_rx
199
+
200
+ end
201
+
202
+ def test_all
203
+ sample_text_file="sample.test.txt"
204
+ sample_bin_file="sample.test.bin"
205
+ f=File.new(sample_text_file,"w")
206
+ f<<File.new(__FILE__,"r").read
207
+ f.close
208
+
209
+ f=File.new(sample_bin_file,"wb")
210
+ 2000.times {|i| f<<(i%0x100).chr}
211
+ f.close
212
+
213
+ txstring_io=StringIO.new("this is a test string")
214
+ rxstring_io=StringIO.new("")
215
+
216
+ do_test(sample_text_file,"crc-simple.test.txt",nil,nil,{:mode=>:crc})
217
+ do_test(txstring_io,rxstring_io)
218
+ do_test(sample_text_file,"corrupt-crc.test.txt",:corruption_in,700,{:mode=>:crc})
219
+
220
+
221
+ do_test(txstring_io,rxstring_io)
222
+ do_test(sample_text_file,rxstring_io)
223
+ do_test(sample_text_file,"simple.test.txt")
224
+ do_test(sample_bin_file,"corrupt_out.test.bin",:corruption_out,4)
225
+ do_test(sample_text_file,"packet_loss_out.test.txt",:packet_loss_out,3)
226
+ do_test(sample_text_file,"packet_loss_in.test.txt",:packet_loss_in,200)
227
+
228
+
229
+ do_test(sample_text_file,"corrupt.test.txt",:corruption_in,700)
230
+ do_test(sample_text_file,"very_corrupt.test.txt",:corruption_in,200)
231
+
232
+ do_test(sample_bin_file,"simple.test.bin")
233
+ do_test(sample_bin_file,"corrupt.test.bin",:corruption_in,700)
234
+
235
+ bigstring=""
236
+ 512.times {|i| bigstring<<((i%0x100).chr*128)}
237
+ do_test(StringIO.new(bigstring),"bigfile.test.txt")
238
+
239
+ end
240
+ end
241
+
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: modem_protocols
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jonno Downes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-29 00:00:00 +11:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: jonno@jamtronix.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/modem_protocols.rb
26
+ - test/test_xmodem.rb
27
+ has_rdoc: true
28
+ homepage: http://petboardstuff.rubyforge.org
29
+ licenses: []
30
+
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: "0"
41
+ version:
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ requirements: []
49
+
50
+ rubyforge_project:
51
+ rubygems_version: 1.3.5
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: a pure ruby implementation of XMODEM
55
+ test_files: []
56
+