@@ -171,6 +171,7 @@ def __init__(self, storage_path="/", rx_size=_DEFAULT_RX_BUF_SIZE, tx_size=_DEFA
171171
172172 def desc_cfg (self , desc , itf_num , ep_num , strs ):
173173 """Build the USB configuration descriptor for this interface."""
174+ print ("[MTP] Building descriptors: itf_num={}, ep_num={}" .format (itf_num , ep_num ))
174175 # Add the interface descriptor for MTP (PIMA 15740 Still Image)
175176 desc .interface (
176177 itf_num ,
@@ -186,6 +187,9 @@ def desc_cfg(self, desc, itf_num, ep_num, strs):
186187 self .ep_in = ep_num | _EP_IN_FLAG
187188 self .ep_intr = (ep_num + 1 ) | _EP_IN_FLAG
188189
190+ print ("[MTP] Endpoints assigned: ep_out=0x{:02x}, ep_in=0x{:02x}, ep_intr=0x{:02x}" .format (
191+ self .ep_out , self .ep_in , self .ep_intr ))
192+
189193 desc .endpoint (self .ep_out , "bulk" , _MAX_PACKET_SIZE , 0 )
190194 desc .endpoint (self .ep_in , "bulk" , _MAX_PACKET_SIZE , 0 )
191195 desc .endpoint (self .ep_intr , "interrupt" , 8 , 10 ) # 10ms interval for events
@@ -196,12 +200,15 @@ def num_eps(self):
196200
197201 def on_open (self ):
198202 """Called when the USB host configures the device."""
203+ print ("[MTP] Device configured by host" )
199204 super ().on_open ()
200205 # Start transfers for receiving commands and data
201206 self ._rx_xfer ()
207+ print ("[MTP] Interface ready, waiting for MTP commands" )
202208
203209 def on_reset (self ):
204210 """Called when the USB device is reset by the host."""
211+ print ("[MTP] Device reset by host" )
205212 super ().on_reset ()
206213 # Reset the session state
207214 self ._session_open = False
@@ -214,34 +221,62 @@ def on_reset(self):
214221 self ._send_object_handle = None
215222 self ._send_object_info = None
216223 self ._get_object_handle = None
224+ print ("[MTP] Session state cleared" )
217225
218226 def _rx_xfer (self ):
219227 """Submit a new transfer to receive data from the host."""
220228 if self .is_open () and not self .xfer_pending (self .ep_out ) and self ._rx .writable ():
221- self .submit_xfer (self .ep_out , self ._rx .pend_write (), self ._rx_cb )
229+ buf = self ._rx .pend_write ()
230+ print ("[MTP] Submitting OUT transfer, buffer size={}" .format (len (buf )))
231+ self .submit_xfer (self .ep_out , buf , self ._rx_cb )
232+ else :
233+ if not self .is_open ():
234+ print ("[MTP] Cannot submit OUT transfer - interface not open" )
235+ elif self .xfer_pending (self .ep_out ):
236+ print ("[MTP] Cannot submit OUT transfer - transfer already pending" )
237+ elif not self ._rx .writable ():
238+ print ("[MTP] Cannot submit OUT transfer - RX buffer full ({} bytes)" .format (self ._rx .readable ()))
222239
223240 def _rx_cb (self , ep , res , num_bytes ):
224241 """Callback when data is received from the host."""
242+ print ("[MTP] OUT transfer complete: res={}, bytes={}" .format (res , num_bytes ))
225243 if res == 0 :
226244 self ._rx .finish_write (num_bytes )
245+ print ("[MTP] Scheduling data processing" )
227246 schedule (self ._process_rx , None )
247+ else :
248+ print ("[MTP] OUT transfer failed with error {}" .format (res ))
228249 self ._rx_xfer () # Continue receiving
229250
230251 def _tx_xfer (self ):
231252 """Submit a new transfer to send data to the host."""
232253 if self .is_open () and not self .xfer_pending (self .ep_in ) and self ._tx .readable ():
233- self .submit_xfer (self .ep_in , self ._tx .pend_read (), self ._tx_cb )
254+ buf = self ._tx .pend_read ()
255+ print ("[MTP] Submitting IN transfer, data size={}" .format (len (buf )))
256+ self .submit_xfer (self .ep_in , buf , self ._tx_cb )
257+ else :
258+ if not self .is_open ():
259+ print ("[MTP] Cannot submit IN transfer - interface not open" )
260+ elif self .xfer_pending (self .ep_in ):
261+ print ("[MTP] Cannot submit IN transfer - transfer already pending" )
262+ elif not self ._tx .readable ():
263+ print ("[MTP] Cannot submit IN transfer - no data in TX buffer" )
234264
235265 def _tx_cb (self , ep , res , num_bytes ):
236266 """Callback when data has been sent to the host."""
267+ print ("[MTP] IN transfer complete: res={}, bytes={}" .format (res , num_bytes ))
237268 if res == 0 :
238269 self ._tx .finish_read (num_bytes )
270+ else :
271+ print ("[MTP] IN transfer failed with error {}" .format (res ))
239272 self ._tx_xfer () # Send more data if available
240273
241274 def _process_rx (self , _ ):
242275 """Process received data from the host."""
243276 # Check if there's enough data for a container header
244- if self ._rx .readable () < _CONTAINER_HEADER_SIZE :
277+ readable = self ._rx .readable ()
278+ if readable < _CONTAINER_HEADER_SIZE :
279+ print ("[MTP] Not enough data for container header ({} bytes)" .format (readable ))
245280 return
246281
247282 # Peek at the container header without consuming it yet
@@ -253,8 +288,20 @@ def _process_rx(self, _):
253288 code = struct .unpack_from ("<H" , header , 6 )[0 ]
254289 transaction_id = struct .unpack_from ("<I" , header , 8 )[0 ]
255290
291+ container_types = {
292+ _MTP_CONTAINER_TYPE_COMMAND : "COMMAND" ,
293+ _MTP_CONTAINER_TYPE_DATA : "DATA" ,
294+ _MTP_CONTAINER_TYPE_RESPONSE : "RESPONSE" ,
295+ _MTP_CONTAINER_TYPE_EVENT : "EVENT"
296+ }
297+
298+ container_type_str = container_types .get (container_type , "UNKNOWN" )
299+ print ("[MTP] Container header: length={}, type={}, code=0x{:04x}, transaction_id={}" .format (
300+ length , container_type_str , code , transaction_id ))
301+
256302 # Ensure we have the complete container
257303 if self ._rx .readable () < length :
304+ print ("[MTP] Waiting for complete container ({}/{} bytes)" .format (self ._rx .readable (), length ))
258305 return
259306
260307 # Now consume the container header
@@ -272,6 +319,25 @@ def _process_rx(self, _):
272319 params .append (param )
273320 self ._rx .finish_read (4 )
274321
322+ # Map code to operation name for common operations
323+ operation_names = {
324+ _MTP_OPERATION_GET_DEVICE_INFO : "GetDeviceInfo" ,
325+ _MTP_OPERATION_OPEN_SESSION : "OpenSession" ,
326+ _MTP_OPERATION_CLOSE_SESSION : "CloseSession" ,
327+ _MTP_OPERATION_GET_STORAGE_IDS : "GetStorageIDs" ,
328+ _MTP_OPERATION_GET_STORAGE_INFO : "GetStorageInfo" ,
329+ _MTP_OPERATION_GET_NUM_OBJECTS : "GetNumObjects" ,
330+ _MTP_OPERATION_GET_OBJECT_HANDLES : "GetObjectHandles" ,
331+ _MTP_OPERATION_GET_OBJECT_INFO : "GetObjectInfo" ,
332+ _MTP_OPERATION_GET_OBJECT : "GetObject" ,
333+ _MTP_OPERATION_DELETE_OBJECT : "DeleteObject" ,
334+ _MTP_OPERATION_SEND_OBJECT_INFO : "SendObjectInfo" ,
335+ _MTP_OPERATION_SEND_OBJECT : "SendObject"
336+ }
337+
338+ op_name = operation_names .get (code , "Unknown" )
339+ print ("[MTP] Received command: {} (0x{:04x}), params={}" .format (op_name , code , params ))
340+
275341 # Store operation info for processing
276342 self ._current_operation = code
277343 self ._current_params = params
@@ -285,11 +351,15 @@ def _process_rx(self, _):
285351 elif container_type == _MTP_CONTAINER_TYPE_DATA :
286352 if not self ._current_operation or self ._data_phase_complete :
287353 # Unexpected data phase
354+ print ("[MTP] Unexpected data phase, no operation in progress" )
288355 self ._send_response (_MTP_RESPONSE_GENERAL_ERROR )
289356 return
290357
291358 # Process the data phase
292359 data_size = length - _CONTAINER_HEADER_SIZE
360+ print ("[MTP] Data phase: size={} bytes for operation 0x{:04x}" .format (
361+ data_size , self ._current_operation ))
362+
293363 if self ._rx .readable () >= data_size :
294364 data = bytearray (data_size )
295365 view = memoryview (data )
@@ -304,10 +374,12 @@ def _process_rx(self, _):
304374 position += chunk
305375 remaining -= chunk
306376
377+ print ("[MTP] Data phase complete, processing {} bytes" .format (data_size ))
307378 self ._process_data_phase (data )
308379 else :
309380 # Not enough data received
310381 # Skip incomplete data
382+ print ("[MTP] Incomplete data received, skipping" )
311383 self ._rx .finish_read (self ._rx .readable ())
312384 self ._send_response (_MTP_RESPONSE_INCOMPLETE_TRANSFER )
313385
@@ -318,9 +390,28 @@ def _handle_command(self):
318390
319391 # Check if session is open (required for most operations)
320392 if not self ._session_open and op != _MTP_OPERATION_OPEN_SESSION and op != _MTP_OPERATION_GET_DEVICE_INFO :
393+ print ("[MTP] Rejecting command 0x{:04x} - session not open" .format (op ))
321394 self ._send_response (_MTP_RESPONSE_SESSION_NOT_OPEN )
322395 return
323396
397+ # Map the operation code to a name for better debug messages
398+ operation_names = {
399+ _MTP_OPERATION_GET_DEVICE_INFO : "GetDeviceInfo" ,
400+ _MTP_OPERATION_OPEN_SESSION : "OpenSession" ,
401+ _MTP_OPERATION_CLOSE_SESSION : "CloseSession" ,
402+ _MTP_OPERATION_GET_STORAGE_IDS : "GetStorageIDs" ,
403+ _MTP_OPERATION_GET_STORAGE_INFO : "GetStorageInfo" ,
404+ _MTP_OPERATION_GET_NUM_OBJECTS : "GetNumObjects" ,
405+ _MTP_OPERATION_GET_OBJECT_HANDLES : "GetObjectHandles" ,
406+ _MTP_OPERATION_GET_OBJECT_INFO : "GetObjectInfo" ,
407+ _MTP_OPERATION_GET_OBJECT : "GetObject" ,
408+ _MTP_OPERATION_DELETE_OBJECT : "DeleteObject" ,
409+ _MTP_OPERATION_SEND_OBJECT_INFO : "SendObjectInfo" ,
410+ _MTP_OPERATION_SEND_OBJECT : "SendObject"
411+ }
412+ op_name = operation_names .get (op , "Unknown" )
413+ print ("[MTP] Processing command: {} (0x{:04x})" .format (op_name , op ))
414+
324415 # Handle operations
325416 if op == _MTP_OPERATION_GET_DEVICE_INFO :
326417 self ._cmd_get_device_info ()
@@ -348,6 +439,7 @@ def _handle_command(self):
348439 self ._cmd_send_object ()
349440 else :
350441 # Operation not supported
442+ print ("[MTP] Unsupported operation: 0x{:04x}" .format (op ))
351443 self ._send_response (_MTP_RESPONSE_OPERATION_NOT_SUPPORTED )
352444
353445 def _process_data_phase (self , data ):
@@ -465,24 +557,34 @@ def _cmd_get_device_info(self):
465557 def _cmd_open_session (self , params ):
466558 """Handle OpenSession command."""
467559 if not params :
560+ print ("[MTP] OpenSession: No parameters provided" )
468561 self ._send_response (_MTP_RESPONSE_INVALID_PARAMETER )
469562 return
470563
471564 session_id = params [0 ]
565+ print ("[MTP] OpenSession: Requested session_id={}" .format (session_id ))
472566
473567 if session_id == 0 :
568+ print ("[MTP] OpenSession: Rejecting invalid session ID (0)" )
474569 self ._send_response (_MTP_RESPONSE_INVALID_PARAMETER )
475570 elif self ._session_open :
571+ print ("[MTP] OpenSession: Session already open (id={})" .format (self ._session_id ))
476572 self ._send_response (_MTP_RESPONSE_SESSION_ALREADY_OPEN )
477573 else :
574+ print ("[MTP] OpenSession: Opening new session with id={}" .format (session_id ))
478575 self ._session_open = True
479576 self ._session_id = session_id
480- self . _send_response ( _MTP_RESPONSE_OK )
577+
481578 # Refresh the object list when opening a session
579+ print ("[MTP] OpenSession: Refreshing object list" )
482580 self ._refresh_object_list ()
581+ print ("[MTP] OpenSession: Found {} objects" .format (len (self ._object_handles )))
582+
583+ self ._send_response (_MTP_RESPONSE_OK )
483584
484585 def _cmd_close_session (self ):
485586 """Handle CloseSession command."""
587+ print ("[MTP] CloseSession: Closing session {}" .format (self ._session_id ))
486588 self ._session_open = False
487589 self ._session_id = 0
488590 self ._send_response (_MTP_RESPONSE_OK )
@@ -955,6 +1057,7 @@ def _process_send_object(self, data):
9551057 def _send_data (self , data , final = True ):
9561058 """Send data phase of an MTP transaction."""
9571059 if not self .is_open ():
1060+ print ("[MTP] Cannot send data - interface not open" )
9581061 return False
9591062
9601063 # Create container header
@@ -967,11 +1070,21 @@ def _send_data(self, data, final=True):
9671070 self ._current_operation , # Operation code
9681071 self ._transaction_id ) # Transaction ID
9691072
1073+ print ("[MTP] Sending DATA container: length={}, operation=0x{:04x}, transaction_id={}{}" .format (
1074+ total_len , self ._current_operation , self ._transaction_id ,
1075+ ", final=True" if final else "" ))
1076+
9701077 # Send header
9711078 self ._tx .write (container )
9721079
9731080 # Send data
9741081 if data :
1082+ if len (data ) > 64 :
1083+ print ("[MTP] Data payload: {} bytes (first 64 bytes: {})" .format (
1084+ len (data ), [hex (b ) for b in data [:64 ]]))
1085+ else :
1086+ print ("[MTP] Data payload: {} bytes: {}" .format (
1087+ len (data ), [hex (b ) for b in data ]))
9751088 self ._tx .write (data )
9761089
9771090 # Start transfer
@@ -982,12 +1095,38 @@ def _send_data(self, data, final=True):
9821095 def _send_response (self , response_code , params = None ):
9831096 """Send response phase of an MTP transaction."""
9841097 if not self .is_open ():
1098+ print ("[MTP] Cannot send response - interface not open" )
9851099 return False
1100+
1101+ # Map response code to string for better debug messages
1102+ response_names = {
1103+ _MTP_RESPONSE_OK : "OK" ,
1104+ _MTP_RESPONSE_GENERAL_ERROR : "GeneralError" ,
1105+ _MTP_RESPONSE_SESSION_NOT_OPEN : "SessionNotOpen" ,
1106+ _MTP_RESPONSE_INVALID_TRANSACTION_ID : "InvalidTransactionID" ,
1107+ _MTP_RESPONSE_OPERATION_NOT_SUPPORTED : "OperationNotSupported" ,
1108+ _MTP_RESPONSE_PARAMETER_NOT_SUPPORTED : "ParameterNotSupported" ,
1109+ _MTP_RESPONSE_INCOMPLETE_TRANSFER : "IncompleteTransfer" ,
1110+ _MTP_RESPONSE_INVALID_STORAGE_ID : "InvalidStorageID" ,
1111+ _MTP_RESPONSE_INVALID_OBJECT_HANDLE : "InvalidObjectHandle" ,
1112+ _MTP_RESPONSE_STORE_FULL : "StoreFull" ,
1113+ _MTP_RESPONSE_STORE_READ_ONLY : "StoreReadOnly" ,
1114+ _MTP_RESPONSE_PARTIAL_DELETION : "PartialDeletion" ,
1115+ _MTP_RESPONSE_STORE_NOT_AVAILABLE : "StoreNotAvailable" ,
1116+ _MTP_RESPONSE_SPECIFICATION_BY_FORMAT_UNSUPPORTED : "SpecificationByFormatUnsupported" ,
1117+ _MTP_RESPONSE_INVALID_PARENT_OBJECT : "InvalidParentObject" ,
1118+ _MTP_RESPONSE_INVALID_PARAMETER : "InvalidParameter" ,
1119+ _MTP_RESPONSE_SESSION_ALREADY_OPEN : "SessionAlreadyOpen"
1120+ }
1121+ response_name = response_names .get (response_code , "Unknown" )
9861122
9871123 # Calculate response length
9881124 param_count = len (params ) if params else 0
9891125 total_len = _CONTAINER_HEADER_SIZE + param_count * 4
9901126
1127+ print ("[MTP] Sending RESPONSE: {} (0x{:04x}), transaction_id={}, params={}" .format (
1128+ response_name , response_code , self ._transaction_id , params if params else "None" ))
1129+
9911130 # Create and fill container header
9921131 container = bytearray (total_len )
9931132 struct .pack_into ("<IHHI" , container , 0 ,
@@ -1015,6 +1154,8 @@ def _send_response(self, response_code, params=None):
10151154
10161155 def _refresh_object_list (self ):
10171156 """Scan the filesystem and rebuild the object handle mapping."""
1157+ print ("[MTP] Refreshing object list from storage path: {}" .format (self ._storage_path ))
1158+
10181159 # Reset object handles
10191160 self ._object_handles = {}
10201161 self ._parent_map = {}
@@ -1025,9 +1166,12 @@ def _refresh_object_list(self):
10251166 self ._next_object_handle += 1
10261167 self ._object_handles [root_handle ] = self ._storage_path
10271168 self ._parent_map [root_handle ] = 0 # No parent
1169+ print ("[MTP] Added root directory with handle {}" .format (root_handle ))
10281170
10291171 # Walk the directory tree
10301172 self ._scan_directory (self ._storage_path , root_handle )
1173+
1174+ print ("[MTP] Object scan complete, found {} objects" .format (len (self ._object_handles )))
10311175
10321176 def _scan_directory (self , path , parent_handle ):
10331177 """Recursively scan a directory and add objects to handle maps."""
@@ -1038,6 +1182,7 @@ def _scan_directory(self, path, parent_handle):
10381182
10391183 # List all entries in this directory
10401184 entries = os .listdir (path )
1185+ print ("[MTP] Scanning directory: {}, found {} entries" .format (path , len (entries )))
10411186
10421187 for entry in entries :
10431188 full_path = path + entry
@@ -1055,15 +1200,19 @@ def _scan_directory(self, path, parent_handle):
10551200 self ._object_handles [handle ] = full_path
10561201 self ._parent_map [handle ] = parent_handle
10571202
1203+ entry_type = "directory" if is_dir else "file"
1204+ print ("[MTP] Added {} '{}' with handle {}" .format (entry_type , full_path , handle ))
1205+
10581206 # Recursively scan subdirectories
10591207 if is_dir :
10601208 self ._scan_directory (full_path , handle )
1061- except :
1209+ except Exception as e :
10621210 # Skip entries that cause errors
1211+ print ("[MTP] Error scanning entry '{}': {}" .format (full_path , str (e )))
10631212 continue
1064- except :
1065- # Ignore errors during directory scan
1066- pass
1213+ except Exception as e :
1214+ # Log errors during directory scan
1215+ print ( "[MTP] Error scanning directory '{}': {}" . format ( path , str ( e )))
10671216
10681217 def _get_format_by_path (self , path ):
10691218 """Determine MTP format code based on file extension."""
0 commit comments