libusb 0.1.1-x86-mingw32 → 0.1.2-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ === 0.1.2 / 2012-03-14
2
+
3
+ * Mark all blocking functions as blocking in FFI, so that parallel threads are not blocked
4
+ * Add method Device#open_interface
5
+ * Add block variant to #claim_interface
6
+ * update API documentation
7
+
1
8
  === 0.1.1 / 2011-12-09
2
9
 
3
10
  * avoid ffi calls with :blocking=>true, als long as it isn't stable on win32
data/Manifest.txt CHANGED
@@ -13,3 +13,4 @@ test/test_libusb_descriptors.rb
13
13
  test/test_libusb_gc.rb
14
14
  test/test_libusb_iso_transfer.rb
15
15
  test/test_libusb_mass_storage.rb
16
+ test/test_libusb_mass_storage2.rb
data/README.rdoc CHANGED
@@ -17,7 +17,7 @@ LIBUSB for Ruby is covered by the GNU Lesser General Public License version 3.
17
17
 
18
18
  == FEATURES:
19
19
  * Access to descriptors of devices, configurations, interfaces, settings and endpoints
20
- * Synchronous and asynchronous communication for bulk, control and interrupt transfers
20
+ * Synchronous and asynchronous communication for bulk, control, interrupt and isochronous transfers
21
21
  * Compatibility layer for ruby-usb[http://www.a-k-r.org/ruby-usb/] (API based on libusb-0.1). See {::USB} for description.
22
22
 
23
23
  == SYNOPSIS:
@@ -27,9 +27,9 @@ LIBUSB for Ruby is covered by the GNU Lesser General Public License version 3.
27
27
  usb = LIBUSB::Context.new
28
28
  device = usb.devices(:idVendor => 0x04b4, :idProduct => 0x8613).first
29
29
  device.open do |handle|
30
- handle.claim_interface(0)
31
- handle.control_transfer(:bmRequestType => 0x40, :bRequest => 0xa0, :wValue => 0xe600, :wIndex => 0x0000, :dataOut => 1.chr)
32
- handle.release_interface(0)
30
+ handle.claim_interface(0) do
31
+ handle.control_transfer(:bmRequestType => 0x40, :bRequest => 0xa0, :wValue => 0xe600, :wIndex => 0x0000, :dataOut => 1.chr)
32
+ end
33
33
  end
34
34
  {LIBUSB::Context#devices} is used to get all or only particular devices.
35
35
  After opening the {LIBUSB::Device} the resulting {LIBUSB::DevHandle} can be
@@ -55,9 +55,9 @@ maximum packet size.
55
55
 
56
56
  == REQUIREMENTS:
57
57
 
58
- * libusb version 1.0 or greater
58
+ * libusb version 1.0 or greater (bundled with Windows binary gem)
59
59
  * FFI-gem[http://github.com/ffi/ffi]
60
- * Linux, MacOSX or Windows system
60
+ * Linux, MacOSX or Windows system with Ruby MRI 1.8.7/1.9.x or JRuby
61
61
 
62
62
  == INSTALL:
63
63
 
@@ -65,8 +65,7 @@ maximum packet size.
65
65
 
66
66
  In order to use LIBUSB, you need the libusb-1.0 library (but not its header files).
67
67
  * On Debian and Ubuntu system, install the +libusb-1.0-0+ package.
68
- * The gem for Windows comes with a precompiled +libusb.dll+ and can be used
69
- together with a precompiled FFI-gem, so there is no need for a compiler.
68
+ * The gem for Windows comes with a precompiled +libusb.dll+, so there is no need for a compiler.
70
69
 
71
70
  Latest code can be used in this way:
72
71
 
data/Rakefile CHANGED
@@ -93,9 +93,8 @@ file LIBUSB_MAKEFILE => LIBUSB_CONFIGURE do |t|
93
93
  options = [
94
94
  '--target=i386-mingw32',
95
95
  "--host=#{Rake::ExtensionCompiler.mingw_host}",
96
+ "--build=#{RbConfig::CONFIG["host"]}",
96
97
  ]
97
- build_host = `sh config.guess`.chomp
98
- options << "--build=#{build_host}" unless build_host.to_s.empty?
99
98
 
100
99
  configure_path = STATIC_LIBUSB_BUILDDIR + 'configure'
101
100
  cmd = [ configure_path.to_s, *options ]
data/lib/libusb-1.0.dll CHANGED
Binary file
data/lib/libusb.rb CHANGED
@@ -18,7 +18,7 @@ require 'ffi'
18
18
 
19
19
 
20
20
  module LIBUSB
21
- VERSION = "0.1.1"
21
+ VERSION = "0.1.2"
22
22
 
23
23
  module Call
24
24
  extend FFI::Library
@@ -165,15 +165,15 @@ module LIBUSB
165
165
  attach_function 'libusb_close', [:pointer], :void
166
166
  attach_function 'libusb_get_device', [:libusb_device_handle], :pointer
167
167
 
168
- attach_function 'libusb_set_configuration', [:libusb_device_handle, :int], :int
168
+ attach_function 'libusb_set_configuration', [:libusb_device_handle, :int], :int, :blocking=>true
169
169
  attach_function 'libusb_claim_interface', [:libusb_device_handle, :int], :int
170
- attach_function 'libusb_release_interface', [:libusb_device_handle, :int], :int
170
+ attach_function 'libusb_release_interface', [:libusb_device_handle, :int], :int, :blocking=>true
171
171
 
172
172
  attach_function 'libusb_open_device_with_vid_pid', [:pointer, :int, :int], :pointer
173
173
 
174
- attach_function 'libusb_set_interface_alt_setting', [:libusb_device_handle, :int, :int], :int
175
- attach_function 'libusb_clear_halt', [:libusb_device_handle, :int], :int
176
- attach_function 'libusb_reset_device', [:libusb_device_handle], :int
174
+ attach_function 'libusb_set_interface_alt_setting', [:libusb_device_handle, :int, :int], :int, :blocking=>true
175
+ attach_function 'libusb_clear_halt', [:libusb_device_handle, :int], :int, :blocking=>true
176
+ attach_function 'libusb_reset_device', [:libusb_device_handle], :int, :blocking=>true
177
177
 
178
178
  attach_function 'libusb_kernel_driver_active', [:libusb_device_handle, :int], :int
179
179
  attach_function 'libusb_detach_kernel_driver', [:libusb_device_handle, :int], :int
@@ -186,7 +186,7 @@ module LIBUSB
186
186
  attach_function 'libusb_cancel_transfer', [:pointer], :int
187
187
  attach_function 'libusb_free_transfer', [:pointer], :void
188
188
 
189
- attach_function 'libusb_handle_events', [:libusb_context], :int
189
+ attach_function 'libusb_handle_events', [:libusb_context], :int, :blocking=>true
190
190
 
191
191
 
192
192
  callback :libusb_transfer_cb_fn, [:pointer], :void
@@ -971,7 +971,7 @@ module LIBUSB
971
971
  LIBUSB.raise_error res, "in libusb_get_device_descriptor" if res!=0
972
972
  end
973
973
 
974
- # Open a device and obtain a device handle.
974
+ # Open the device and obtain a device handle.
975
975
  #
976
976
  # A handle allows you to perform I/O on the device in question.
977
977
  # This is a non-blocking function; no requests are sent over the bus.
@@ -996,6 +996,21 @@ module LIBUSB
996
996
  end
997
997
  end
998
998
 
999
+ # Open the device and claim an interface.
1000
+ #
1001
+ # This is a convenience method to {Device#open} and {DevHandle#claim_interface}.
1002
+ # Must be called with a block. When the block has finished, the interface
1003
+ # will be released and the device will be closed.
1004
+ #
1005
+ # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you wish to claim
1006
+ def open_interface(interface)
1007
+ open do |dev|
1008
+ dev.claim_interface(interface) do
1009
+ yield dev
1010
+ end
1011
+ end
1012
+ end
1013
+
999
1014
  # Get the number of the bus that a device is connected to.
1000
1015
  def bus_number
1001
1016
  Call.libusb_get_bus_number(@pDev)
@@ -1199,11 +1214,20 @@ module LIBUSB
1199
1214
  #
1200
1215
  # This is a non-blocking function.
1201
1216
  #
1217
+ # If called with a block, the device handle is passed through to the block
1218
+ # and the interface is released when the block has finished.
1219
+ #
1202
1220
  # @param [Interface, Fixnum] interface the interface or it's bInterfaceNumber you wish to claim
1203
1221
  def claim_interface(interface)
1204
1222
  interface = interface.bInterfaceNumber if interface.respond_to? :bInterfaceNumber
1205
1223
  res = Call.libusb_claim_interface(@pHandle, interface)
1206
1224
  LIBUSB.raise_error res, "in libusb_claim_interface" if res!=0
1225
+ return self unless block_given?
1226
+ begin
1227
+ yield self
1228
+ ensure
1229
+ release_interface(interface)
1230
+ end
1207
1231
  end
1208
1232
 
1209
1233
  # Release an interface previously claimed with {DevHandle#claim_interface}.
@@ -1272,8 +1296,7 @@ module LIBUSB
1272
1296
  # to activate or the bInterfaceNumber of the previously-claimed interface
1273
1297
  # @param [Fixnum, nil] alternate_setting the bAlternateSetting of the alternate setting to activate
1274
1298
  # (only if first param is a Fixnum)
1275
- def set_interface_alt_setting(setting_or_interface_number,
1276
- alternate_setting=nil)
1299
+ def set_interface_alt_setting(setting_or_interface_number, alternate_setting=nil)
1277
1300
  alternate_setting ||= setting_or_interface_number.bAlternateSetting if setting_or_interface_number.respond_to? :bAlternateSetting
1278
1301
  setting_or_interface_number = setting_or_interface_number.bInterfaceNumber if setting_or_interface_number.respond_to? :bInterfaceNumber
1279
1302
  res = Call.libusb_set_interface_alt_setting(@pHandle, setting_or_interface_number, alternate_setting)
@@ -1356,7 +1379,7 @@ alternate_setting=nil)
1356
1379
  # The direction of the transfer is inferred from the direction bits of the
1357
1380
  # endpoint address.
1358
1381
  #
1359
- # For bulk reads, the :dataIn param indicates the maximum length of data you are
1382
+ # For bulk reads, the +:dataIn+ param indicates the maximum length of data you are
1360
1383
  # expecting to receive. If less data arrives than expected, this function will
1361
1384
  # return that data.
1362
1385
  #
@@ -1373,6 +1396,8 @@ alternate_setting=nil)
1373
1396
  # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
1374
1397
  # @param [String] :dataOut the data to send with an outgoing transfer
1375
1398
  # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1399
+ # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
1400
+ # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
1376
1401
  #
1377
1402
  # @return [Fixnum] Number of bytes sent for an outgoing transfer
1378
1403
  # @return [String] Received data for an ingoing transfer
@@ -1412,7 +1437,7 @@ alternate_setting=nil)
1412
1437
  # The direction of the transfer is inferred from the direction bits of the
1413
1438
  # endpoint address.
1414
1439
  #
1415
- # For interrupt reads, the :dataIn param indicates the maximum length of data you
1440
+ # For interrupt reads, the +:dataIn+ param indicates the maximum length of data you
1416
1441
  # are expecting to receive. If less data arrives than expected, this function will
1417
1442
  # return that data.
1418
1443
  #
@@ -1431,6 +1456,8 @@ alternate_setting=nil)
1431
1456
  # @param [Endpoint, Fixnum] :endpoint the (address of a) valid endpoint to communicate with
1432
1457
  # @param [String] :dataOut the data to send with an outgoing transfer
1433
1458
  # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1459
+ # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
1460
+ # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
1434
1461
  #
1435
1462
  # @return [Fixnum] Number of bytes sent for an outgoing transfer
1436
1463
  # @return [String] Received data for an ingoing transfer
@@ -1467,7 +1494,7 @@ alternate_setting=nil)
1467
1494
 
1468
1495
  # Perform a USB control transfer.
1469
1496
  #
1470
- # The direction of the transfer is inferred from the bmRequestType field of the
1497
+ # The direction of the transfer is inferred from the +:bmRequestType+ field of the
1471
1498
  # setup packet.
1472
1499
  #
1473
1500
  # @param [Fixnum] :bmRequestType the request type field for the setup packet
@@ -1479,7 +1506,7 @@ alternate_setting=nil)
1479
1506
  # @param [Fixnum] :dataIn the number of bytes expected to receive with an ingoing transfer
1480
1507
  # (excluding setup packet)
1481
1508
  # @param [Fixnum] :timeout timeout (in millseconds) that this function should wait before giving
1482
- # up due to no response being received. For an unlimited timeout, use value 0.
1509
+ # up due to no response being received. For an unlimited timeout, use value 0. Defaults to 1000 ms.
1483
1510
  #
1484
1511
  # @return [Fixnum] Number of bytes sent (excluding setup packet) for outgoing transfer
1485
1512
  # @return [String] Received data (without setup packet) for ingoing transfer
@@ -215,7 +215,7 @@ class TestLibusbMassStorage < Test::Unit::TestCase
215
215
  end
216
216
  end
217
217
  assert_raise(CSWError, LIBUSB::ERROR_TIMEOUT) do
218
- invalid_command
218
+ bulk_transfer(:endpoint=>endpoint_in, :dataIn=>123)
219
219
  end
220
220
  th.kill
221
221
  dev.clear_halt(endpoint_in)
@@ -0,0 +1,69 @@
1
+ # This file is part of Libusb for Ruby.
2
+ #
3
+ # Libusb for Ruby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # Libusb for Ruby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public License
14
+ # along with Libusb for Ruby. If not, see <http://www.gnu.org/licenses/>.
15
+ #
16
+
17
+ require "test/unit"
18
+ require "libusb"
19
+
20
+ class TestLibusbMassStorage2 < Test::Unit::TestCase
21
+ include LIBUSB
22
+
23
+ attr_accessor :usb
24
+ attr_accessor :device
25
+
26
+ def setup
27
+ @usb = Context.new
28
+ @usb.debug = 3
29
+ @device = usb.devices( :bClass=>CLASS_MASS_STORAGE, :bSubClass=>[0x06,0x01], :bProtocol=>0x50 ).last
30
+ abort "no mass storage device found" unless @device
31
+
32
+ # Ensure kernel driver is detached
33
+ device.open do |dev|
34
+ if RUBY_PLATFORM=~/linux/i && dev.kernel_driver_active?(0)
35
+ dev.detach_kernel_driver(0)
36
+ end
37
+ end
38
+ end
39
+
40
+ def teardown
41
+ end
42
+
43
+ def test_open_with_block
44
+ device.open do |dev|
45
+ assert_kind_of DevHandle, dev
46
+ assert_kind_of String, dev.string_descriptor_ascii(1)
47
+ end
48
+ end
49
+
50
+ def test_claim_interface_with_block
51
+ res = device.open do |dev|
52
+ dev.claim_interface(0) do |dev2|
53
+ assert_kind_of DevHandle, dev2
54
+ assert_kind_of String, dev2.string_descriptor_ascii(1)
55
+ 12345
56
+ end
57
+ end
58
+ assert_equal 12345, res, "Block versions should pass through the result"
59
+ end
60
+
61
+ def test_open_interface
62
+ res = device.open_interface(0) do |dev|
63
+ assert_kind_of DevHandle, dev
64
+ assert_kind_of String, dev.string_descriptor_ascii(1)
65
+ 12345
66
+ end
67
+ assert_equal 12345, res, "Block versions should pass through the result"
68
+ end
69
+ end
metadata CHANGED
@@ -1,60 +1,80 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: libusb
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 2
10
+ version: 0.1.2
6
11
  platform: x86-mingw32
7
- authors:
12
+ authors:
8
13
  - Lars Kanis
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2011-12-09 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2012-03-14 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: ffi
16
- requirement: &20041800 !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '1.0'
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 15
29
+ segments:
30
+ - 1
31
+ - 0
32
+ version: "1.0"
22
33
  type: :runtime
23
- prerelease: false
24
- version_requirements: *20041800
25
- - !ruby/object:Gem::Dependency
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
26
36
  name: rake-compiler
27
- requirement: &20040960 !ruby/object:Gem::Requirement
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
28
39
  none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
32
- version: '0.6'
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 7
44
+ segments:
45
+ - 0
46
+ - 6
47
+ version: "0.6"
33
48
  type: :development
34
- prerelease: false
35
- version_requirements: *20040960
36
- - !ruby/object:Gem::Dependency
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
37
51
  name: hoe
38
- requirement: &20040440 !ruby/object:Gem::Requirement
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
39
54
  none: false
40
- requirements:
41
- - - ~>
42
- - !ruby/object:Gem::Version
43
- version: '2.12'
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 47
59
+ segments:
60
+ - 2
61
+ - 8
62
+ - 0
63
+ version: 2.8.0
44
64
  type: :development
45
- prerelease: false
46
- version_requirements: *20040440
47
- description: LIBUSB is a Ruby binding that gives Ruby programmers access to all functionality
48
- of libusb, version 1.0
49
- email:
65
+ version_requirements: *id003
66
+ description: LIBUSB is a Ruby binding that gives Ruby programmers access to all functionality of libusb, version 1.0
67
+ email:
50
68
  - kanis@comcard.de
51
69
  executables: []
70
+
52
71
  extensions: []
53
- extra_rdoc_files:
72
+
73
+ extra_rdoc_files:
54
74
  - History.txt
55
75
  - Manifest.txt
56
76
  - README.rdoc
57
- files:
77
+ files:
58
78
  - .autotest
59
79
  - .gemtest
60
80
  - COPYING
@@ -70,40 +90,48 @@ files:
70
90
  - test/test_libusb_gc.rb
71
91
  - test/test_libusb_iso_transfer.rb
72
92
  - test/test_libusb_mass_storage.rb
73
- - test/test_libusb_keyboard.rb
93
+ - test/test_libusb_mass_storage2.rb
74
94
  - lib/libusb-1.0.dll
75
95
  homepage: http://github.com/larskanis/libusb
76
96
  licenses: []
97
+
77
98
  post_install_message:
78
- rdoc_options:
99
+ rdoc_options:
79
100
  - --main
80
101
  - README.rdoc
81
102
  - --charset=UTF-8
82
- require_paths:
103
+ require_paths:
83
104
  - lib
84
- required_ruby_version: !ruby/object:Gem::Requirement
105
+ required_ruby_version: !ruby/object:Gem::Requirement
85
106
  none: false
86
- requirements:
87
- - - ! '>='
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ hash: 3
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
115
  none: false
92
- requirements:
93
- - - ! '>='
94
- - !ruby/object:Gem::Version
95
- version: '0'
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
96
123
  requirements: []
124
+
97
125
  rubyforge_project: libusb
98
- rubygems_version: 1.8.10
126
+ rubygems_version: 1.7.2
99
127
  signing_key:
100
128
  specification_version: 3
101
129
  summary: Access USB devices from Ruby via libusb-1.0
102
- test_files:
103
- - test/test_libusb_compat_mass_storage.rb
104
- - test/test_libusb_gc.rb
130
+ test_files:
131
+ - test/test_libusb_compat.rb
105
132
  - test/test_libusb_iso_transfer.rb
133
+ - test/test_libusb_mass_storage2.rb
106
134
  - test/test_libusb_descriptors.rb
107
- - test/test_libusb_compat.rb
108
- - test/test_libusb_keyboard.rb
109
135
  - test/test_libusb_mass_storage.rb
136
+ - test/test_libusb_compat_mass_storage.rb
137
+ - test/test_libusb_gc.rb
@@ -1,50 +0,0 @@
1
- # This test requires a connected, but not mounted mass storage device with
2
- # read/write access allowed. Based on the following specifications:
3
- # http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
4
- # http://en.wikipedia.org/wiki/SCSI_command
5
- #
6
-
7
- require "test/unit"
8
- require "libusb"
9
-
10
- class TestLibusbKeyboard < Test::Unit::TestCase
11
- include LIBUSB
12
-
13
- attr_accessor :usb
14
- attr_accessor :device
15
- attr_accessor :dev
16
- attr_accessor :endpoint_in
17
- attr_accessor :endpoint_out
18
-
19
- def setup
20
- @usb = Context.new
21
- @usb.debug = 3
22
-
23
- @device = usb.devices( :bDeviceClass=>CLASS_HID, :bDeviceProtocol=>1 ).first
24
- abort "no keyboard device found" unless @device
25
-
26
- @endpoint_in = @device.endpoints.find{|ep| ep.bEndpointAddress&ENDPOINT_IN != 0 }.bEndpointAddress
27
- @endpoint_out = @device.endpoints.find{|ep| ep.bEndpointAddress&ENDPOINT_IN == 0 }.bEndpointAddress
28
-
29
- @dev = @device.open
30
-
31
- if RUBY_PLATFORM=~/linux/i && dev.kernel_driver_active?(0)
32
- dev.detach_kernel_driver(0)
33
- end
34
- dev.claim_interface(0)
35
-
36
- # clear any pending data
37
- dev.clear_halt(endpoint_in)
38
- end
39
-
40
- def teardown
41
- dev.release_interface(0) if dev
42
- dev.close if dev
43
- end
44
-
45
- def test_read
46
- data_length = 8
47
- recv = dev.interrupt_transfer(:endpoint=>endpoint_in, :dataIn=>data_length)
48
- p recv
49
- end
50
- end