Class: MTP::Protocol
- Inherits:
-
Object
- Object
- MTP::Protocol
- Defined in:
- lib/mtp/protocol.rb
Defined Under Namespace
Classes: EndPoints, Transaction
Constant Summary collapse
- @@logger =
Logger.new(STDERR)
Instance Attribute Summary collapse
-
#device ⇒ Object
readonly
Returns the value of attribute device.
Class Method Summary collapse
Instance Method Summary collapse
- #close ⇒ Object
- #configuration ⇒ Object
-
#info {|data| ... } ⇒ Object
do not use normal procedure as we need to determine if we use splitted header / data.
-
#initialize(device, usb_device) ⇒ Protocol
constructor
A new instance of Protocol.
- #interface ⇒ Object
- #logger ⇒ Object
- #open ⇒ Object
- #raw_read ⇒ Object
- #raw_read_io(io, size, &block) ⇒ Object
- #raw_send(raw_packet, &block) ⇒ Object
- #raw_send_io(io, size, &block) ⇒ Object
- #receive ⇒ Object
- #reset_end_points ⇒ Object
- #send(request) ⇒ Object
- #split_data_packets? ⇒ Boolean
- #transaction ⇒ Object
- #transaction_id ⇒ Object
Constructor Details
#initialize(device, usb_device) ⇒ Protocol
Returns a new instance of Protocol.
135 136 137 138 139 140 141 142 143 |
# File 'lib/mtp/protocol.rb', line 135 def initialize(device, usb_device) @device = device @transaction_id = 0 @split_data_packets = false @usb_handle = nil @usb_device = usb_device @timeout = 10000 logger.info("new device #{@usb_device.product}") end |
Instance Attribute Details
#device ⇒ Object (readonly)
Returns the value of attribute device.
134 135 136 |
# File 'lib/mtp/protocol.rb', line 134 def device @device end |
Class Method Details
.logger ⇒ Object
9 10 11 |
# File 'lib/mtp/protocol.rb', line 9 def self.logger @@logger end |
.mtp?(usb_device, timeout = 1000) ⇒ Boolean
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/mtp/protocol.rb', line 99 def self.mtp?(usb_device, timeout = 1000) ret = true usb_device.open do |usb| # check for MS OS descriptors mod = usb.get_string_simple(238) if mod.nil? or mod[0,4] != "MSFT" logger.debug("Microsoft OS Descriptor invalid") ret = false break end bVendorCode = mod[7] result = "\0" * 0x20 expd = usb.usb_control_msg(USB::USB_ENDPOINT_IN|USB::USB_RECIP_DEVICE|USB::USB_TYPE_VENDOR, bVendorCode, 0, 4, result, timeout) unless expd > 0x15 and result[0x12,3] == "MTP" logger.debug("Microsoft Extended Descriptor invalid") ret = false break end result = "\0" * 0x20 expd = usb.usb_control_msg(USB::USB_ENDPOINT_IN|USB::USB_RECIP_DEVICE|USB::USB_TYPE_VENDOR, bVendorCode, 0, 5, result, timeout) unless expd > 0x15 and result[0x12,3] == "MTP" logger.debug("Microsoft Extended Descriptor invalid") ret = false break end end ret end |
Instance Method Details
#close ⇒ Object
285 286 287 288 289 290 291 |
# File 'lib/mtp/protocol.rb', line 285 def close logger.debug("low level close") reset_end_points @usb_handle.release_interface(interface.settings.first) @usb_handle.usb_reset @usb_handle.usb_close end |
#configuration ⇒ Object
149 150 151 |
# File 'lib/mtp/protocol.rb', line 149 def configuration @usb_device.configurations.first end |
#info {|data| ... } ⇒ Object
do not use normal procedure as we need to determine if we use splitted header / data
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/mtp/protocol.rb', line 249 def info request = Request.for("GetDeviceInfo") request.transaction_id = 0 send(request) data = receive raise CommandError.new(self, request, data, "expected a data packet") unless data.is_a?(Data) if data.payload.empty? logger.debug("device split packet headers from payload") @split_data_packets = true data.payload = raw_read end response = receive yield data if block_given? end |
#interface ⇒ Object
153 154 155 |
# File 'lib/mtp/protocol.rb', line 153 def interface @usb_device.interfaces.first end |
#open ⇒ Object
266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/mtp/protocol.rb', line 266 def open logger.debug("low level open") @usb_handle = @usb_device.usb_open begin @usb_handle.set_configuration(configuration) @usb_handle.claim_interface(interface.settings.first) @end_points = EndPoints.new(self) rescue Exception => e close end self end |
#raw_read ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/mtp/protocol.rb', line 204 def raw_read read = packet_size = @end_points.in.wMaxPacketSize raw_packet = "" # packet is received when we receive an emtpy packet # or a packet whose size is smaller than the packet size while read == packet_size buffer = "\0" * packet_size read = @usb_handle.usb_bulk_read(@end_points.in.bEndpointAddress, buffer, @timeout) if read.zero? logger.warn("packet match max packet size, need to send NULL packet") end raw_packet << buffer[0, read] end raw_packet end |
#raw_read_io(io, size, &block) ⇒ Object
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/mtp/protocol.rb', line 221 def raw_read_io(io, size, &block) read = packet_size = @end_points.in.wMaxPacketSize total = 0 # packet is received when we receive an emtpy packet # or a packet whose size is smaller than the packet size while read == packet_size buffer = "\0" * packet_size read = @usb_handle.usb_bulk_read(@end_points.in.bEndpointAddress, buffer, @timeout) if read.zero? logger.warn("packet match max packet size, need to send NULL packet") end io.write(buffer[0, read]) total += read yield total, size if block_given? end end |
#raw_send(raw_packet, &block) ⇒ Object
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/mtp/protocol.rb', line 163 def raw_send(raw_packet, &block) raw_packet = raw_packet.clone if (raw_packet.length % @end_points.out.wMaxPacketSize).zero? send_empty_packet = true logger.warn("packet match max packet size, need to send NULL packet") end written, total = 0, raw_packet.length until raw_packet.empty? if (wrt = @usb_handle.usb_bulk_write(@end_points.out.bEndpointAddress, raw_packet.slice!(0, @end_points.out.wMaxPacketSize), @timeout)) < 0 raise WriteError.new(self) end written += wrt yield written, total if block_given? end end |
#raw_send_io(io, size, &block) ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/mtp/protocol.rb', line 180 def raw_send_io(io, size, &block) packet_size = @end_points.out.wMaxPacketSize written = 0 until (str = io.read(packet_size)).nil? if (wrt = @usb_handle.usb_bulk_write(@end_points.out.bEndpointAddress, str, @timeout)) < 0 raise WriteError.new(self) end written += wrt yield written, size if block_given? end end |
#receive ⇒ Object
239 240 241 242 243 244 245 |
# File 'lib/mtp/protocol.rb', line 239 def receive raw_packet = raw_read response = Container.parse(raw_packet) logger.debug(sprintf("<= %-8s: 0x%08x, 0x%04x - %s", (response.is_a?(Data) ? "DATA" : "RESPONSE"), response.transaction_id, response.code, response.code.name)) response end |
#reset_end_points ⇒ Object
279 280 281 282 283 |
# File 'lib/mtp/protocol.rb', line 279 def reset_end_points @usb_handle.usb_clear_halt(@end_points.out.bEndpointAddress) @usb_handle.usb_clear_halt(@end_points.in.bEndpointAddress) @usb_handle.usb_clear_halt(@end_points.interrupt.bEndpointAddress) end |
#send(request) ⇒ Object
192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/mtp/protocol.rb', line 192 def send(request) unless request.is_a?(Data) or request.code.name == "GetDeviceInfo" raise UnsupportedRequest.new(self, request) unless @device.support?(request.code) request.transaction_id = transaction_id end raw_send(request.pack) logger.debug(sprintf("=> %-8s: 0x%08x, 0x%04x - %s", (request.is_a?(Data) ? "DATA" : "REQUEST"), request.transaction_id, request.code, request.code.name)) request end |
#split_data_packets? ⇒ Boolean
145 146 147 |
# File 'lib/mtp/protocol.rb', line 145 def split_data_packets? @split_data_packets end |
#transaction ⇒ Object
293 294 295 |
# File 'lib/mtp/protocol.rb', line 293 def transaction Transaction.new(self) end |
#transaction_id ⇒ Object
157 158 159 160 161 |
# File 'lib/mtp/protocol.rb', line 157 def transaction_id tid = @transaction_id @transaction_id = (tid % 0xffffffff) + 1 tid end |