mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Improved packet tracing output (added byte count and packet count)
Added support for the df command
This commit is contained in:
parent
1c8319a5a4
commit
df077ebfbe
@ -20,6 +20,6 @@ the following rule in C{/etc/udev/rules.d/90-local.rules} ::
|
|||||||
BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="plugdev"
|
BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="plugdev"
|
||||||
You may have to adjust the GROUP and the location of the rules file to suit your distribution.
|
You may have to adjust the GROUP and the location of the rules file to suit your distribution.
|
||||||
"""
|
"""
|
||||||
VERSION = "0.1"
|
VERSION = "0.1.1"
|
||||||
__docformat__ = "epytext"
|
__docformat__ = "epytext"
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
|
@ -47,13 +47,19 @@ The public interface of class L{PRS500Device} defines the methods for performing
|
|||||||
import usb, sys
|
import usb, sys
|
||||||
from array import array
|
from array import array
|
||||||
|
|
||||||
from prstypes import AcknowledgeBulkRead, Answer, Command, DeviceInfo, DirOpen, DirRead, DirClose, \
|
from prstypes import *
|
||||||
FileOpen, FileClose, FileRead, IdAnswer, ListAnswer, \
|
|
||||||
ListResponse, LongCommand, FileProperties, PathQuery, Response, \
|
|
||||||
ShortCommand, DeviceInfoQuery
|
|
||||||
from errors import *
|
from errors import *
|
||||||
|
|
||||||
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
||||||
|
_packet_number = 0 #: Keep track of the packet number of packet tracing
|
||||||
|
|
||||||
|
def _log_packet(packet, header, stream=sys.stderr):
|
||||||
|
""" Log C{packet} to stream C{stream}. Header should be a small word describing the type of packet. """
|
||||||
|
global _packet_number
|
||||||
|
_packet_number += 1
|
||||||
|
print >>stream, header, "(Packet #", str(_packet_number) + ")\n"
|
||||||
|
print >>stream, packet
|
||||||
|
print >>stream, "--"
|
||||||
|
|
||||||
class File(object):
|
class File(object):
|
||||||
""" Wrapper that allows easy access to all information about files/directories """
|
""" Wrapper that allows easy access to all information about files/directories """
|
||||||
@ -165,12 +171,12 @@ class PRS500Device(object):
|
|||||||
@param response_type: an object of type 'type'. The return packet from the device is returned as an object of type response_type.
|
@param response_type: an object of type 'type'. The return packet from the device is returned as an object of type response_type.
|
||||||
@param timeout: the time to wait for a response from the device, in milliseconds. If there is no response, a L{usb.USBError} is raised.
|
@param timeout: the time to wait for a response from the device, in milliseconds. If there is no response, a L{usb.USBError} is raised.
|
||||||
"""
|
"""
|
||||||
if self._log_packets: print "Command\n%s\n--\n"%command
|
if self._log_packets: _log_packet(command, "Command")
|
||||||
bytes_sent = self.handle.controlMsg(0x40, 0x80, command)
|
bytes_sent = self.handle.controlMsg(0x40, 0x80, command)
|
||||||
if bytes_sent != len(command):
|
if bytes_sent != len(command):
|
||||||
raise ControlError(desc="Could not send control request to device\n" + str(query.query))
|
raise ControlError(desc="Could not send control request to device\n" + str(query.query))
|
||||||
response = response_type(self.handle.controlMsg(0xc0, 0x81, Response.SIZE, timeout=timeout))
|
response = response_type(self.handle.controlMsg(0xc0, 0x81, Response.SIZE, timeout=timeout))
|
||||||
if self._log_packets: print "Response\n%s\n--\n"%response
|
if self._log_packets: _log_packet(response, "Response")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _send_validated_command(self, command, cnumber=None, response_type=Response, timeout=100):
|
def _send_validated_command(self, command, cnumber=None, response_type=Response, timeout=100):
|
||||||
@ -191,7 +197,7 @@ class PRS500Device(object):
|
|||||||
@param size: the expected size of the data packet.
|
@param size: the expected size of the data packet.
|
||||||
"""
|
"""
|
||||||
data = data_type(self.handle.bulkRead(PRS500Device.PRS500_BULK_IN_EP, size))
|
data = data_type(self.handle.bulkRead(PRS500Device.PRS500_BULK_IN_EP, size))
|
||||||
if self._log_packets: print "Answer\n%s\n--\n"%data
|
if self._log_packets: _log_packet(data, "Answer d->h")
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def _bulk_read(self, bytes, command_number=0x00, packet_size=4096, data_type=Answer):
|
def _bulk_read(self, bytes, command_number=0x00, packet_size=4096, data_type=Answer):
|
||||||
@ -364,3 +370,25 @@ class PRS500Device(object):
|
|||||||
if recurse and file.is_dir and not file.path.startswith(("/dev","/proc")):
|
if recurse and file.is_dir and not file.path.startswith(("/dev","/proc")):
|
||||||
dirs[len(dirs):] = self.list(file.path, recurse=True)
|
dirs[len(dirs):] = self.list(file.path, recurse=True)
|
||||||
return dirs
|
return dirs
|
||||||
|
|
||||||
|
def available_space(self):
|
||||||
|
"""
|
||||||
|
Get free space available on the mountpoints:
|
||||||
|
1. /Data/ Device memory
|
||||||
|
2. a:/ Memory Stick
|
||||||
|
3. b:/ SD Card
|
||||||
|
|
||||||
|
@return: A list of tuples. Each tuple has form ("location", free space, total space)
|
||||||
|
"""
|
||||||
|
return self._run_session(self._available_space)
|
||||||
|
|
||||||
|
def _available_space(self, args):
|
||||||
|
""" L{available_space} """
|
||||||
|
data = []
|
||||||
|
for path in ("/Data/", "a:/", "b:/"):
|
||||||
|
res = self._send_validated_command(FreeSpaceQuery(path),timeout=5000) # Timeout needs to be increased as it takes time to read card
|
||||||
|
buffer_size = 16 + res.data[2]
|
||||||
|
pkt = self._bulk_read(buffer_size, data_type=FreeSpaceAnswer, command_number=FreeSpaceQuery.NUMBER)[0]
|
||||||
|
data.append( (path, pkt.free_space, pkt.total) )
|
||||||
|
return data
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class TransferBuffer(list):
|
|||||||
0700 0100 0000 0000 0000 0000 0c00 0000 ................
|
0700 0100 0000 0000 0000 0000 0c00 0000 ................
|
||||||
0200 0000 0400 0000 4461 7461 ........Data
|
0200 0000 0400 0000 4461 7461 ........Data
|
||||||
"""
|
"""
|
||||||
ans, ascii = "", ""
|
ans, ascii = ": ".rjust(10,"0"), ""
|
||||||
for i in range(0, len(self), 2):
|
for i in range(0, len(self), 2):
|
||||||
for b in range(2):
|
for b in range(2):
|
||||||
try:
|
try:
|
||||||
@ -95,10 +95,10 @@ class TransferBuffer(list):
|
|||||||
ans = ans + " "
|
ans = ans + " "
|
||||||
if (i+2)%16 == 0:
|
if (i+2)%16 == 0:
|
||||||
if i+2 < len(self):
|
if i+2 < len(self):
|
||||||
ans += " " + ascii + "\n"
|
ans += " " + ascii + "\n" + (TransferBuffer.phex(i+2)+": ").rjust(10, "0")
|
||||||
ascii = ""
|
ascii = ""
|
||||||
last_line = ans[ans.rfind("\n")+1:]
|
last_line = ans[ans.rfind("\n")+1:]
|
||||||
padding = 40 - len(last_line)
|
padding = 50 - len(last_line)
|
||||||
ans += "".ljust(padding) + " " + ascii
|
ans += "".ljust(padding) + " " + ascii
|
||||||
return ans.strip()
|
return ans.strip()
|
||||||
|
|
||||||
@ -271,6 +271,43 @@ class ShortCommand(Command):
|
|||||||
|
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
|
class FreeSpaceQuery(Command):
|
||||||
|
""" Query the free space available """
|
||||||
|
NUMBER = 0x53 #; Command number
|
||||||
|
def __init__(self, path):
|
||||||
|
Command.__init__(self, 20 + len(path))
|
||||||
|
self.number=FreeSpaceQuery.NUMBER
|
||||||
|
self.type=0x01
|
||||||
|
self.length = 4 + len(path)
|
||||||
|
self.path_length = len(path)
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
@apply
|
||||||
|
def path_length():
|
||||||
|
doc =\
|
||||||
|
""" The length in bytes of the path to follow. C{unsigned int} stored at byte 16. """
|
||||||
|
def fget(self):
|
||||||
|
return self.unpack(start=16, fmt=DWORD)[0]
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
self.pack(val, start=16, fmt=DWORD)
|
||||||
|
|
||||||
|
return property(**locals())
|
||||||
|
|
||||||
|
@apply
|
||||||
|
def path():
|
||||||
|
doc =\
|
||||||
|
""" The path. Stored as a string at byte 20. """
|
||||||
|
|
||||||
|
def fget(self):
|
||||||
|
return self.unpack(start=20, fmt="<"+str(self.path_length)+"s")[0]
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
self.pack(val, start=20, fmt="<"+str(self.path_length)+"s")
|
||||||
|
|
||||||
|
return property(**locals())
|
||||||
|
|
||||||
|
|
||||||
class DirOpen(Command):
|
class DirOpen(Command):
|
||||||
|
|
||||||
""" Open a directory for reading its contents """
|
""" Open a directory for reading its contents """
|
||||||
@ -795,6 +832,31 @@ class DeviceInfo(Answer):
|
|||||||
return src[0:src.find('\x00')]
|
return src[0:src.find('\x00')]
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
|
class FreeSpaceAnswer(Answer):
|
||||||
|
@apply
|
||||||
|
def total():
|
||||||
|
doc =\
|
||||||
|
""" The total space in bytes. C{unsigned long long} stored in 8 bytes at byte 24 """
|
||||||
|
def fget(self):
|
||||||
|
return self.unpack(start=24, fmt=DDWORD)[0]
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
self.pack(val, start=24, fmt=DDWORD)
|
||||||
|
|
||||||
|
return property(**locals())
|
||||||
|
|
||||||
|
@apply
|
||||||
|
def free_space():
|
||||||
|
doc =\
|
||||||
|
""" The free space in bytes. C{unsigned long long} stored in 8 bytes at byte 32 """
|
||||||
|
def fget(self):
|
||||||
|
return self.unpack(start=32, fmt=DDWORD)[0]
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
self.pack(val, start=32, fmt=DDWORD)
|
||||||
|
|
||||||
|
return property(**locals())
|
||||||
|
|
||||||
class ListAnswer(Answer):
|
class ListAnswer(Answer):
|
||||||
|
|
||||||
""" Defines the structure of packets that contain items in a list. """
|
""" Defines the structure of packets that contain items in a list. """
|
||||||
|
40
prs-500.e3p
40
prs-500.e3p
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE Project SYSTEM "Project-3.9.dtd">
|
<!DOCTYPE Project SYSTEM "Project-3.9.dtd">
|
||||||
<!-- Project file for project pr5-500 -->
|
<!-- Project file for project prs-500 -->
|
||||||
<!-- Saved: 2006-10-31, 21:14:19 -->
|
<!-- Saved: 2006-11-07, 00:09:05 -->
|
||||||
<!-- Copyright (C) 2006 Kovid Goyal, kovid@kovidgoyal.net -->
|
<!-- Copyright (C) 2006 Kovid Goyal, kovid@kovidgoyal.net -->
|
||||||
<Project version="3.9">
|
<Project version="3.9">
|
||||||
<ProgLanguage mixed="0">Python</ProgLanguage>
|
<ProgLanguage mixed="0">Python</ProgLanguage>
|
||||||
@ -12,16 +12,31 @@
|
|||||||
<Email>kovid@kovidgoyal.net</Email>
|
<Email>kovid@kovidgoyal.net</Email>
|
||||||
<Sources>
|
<Sources>
|
||||||
<Source>
|
<Source>
|
||||||
<Name>libprs500/communicate.py</Name>
|
<Dir>libprs500</Dir>
|
||||||
|
<Name>communicate.py</Name>
|
||||||
</Source>
|
</Source>
|
||||||
<Source>
|
<Source>
|
||||||
<Name>libprs500/terminfo.py</Name>
|
<Dir>libprs500</Dir>
|
||||||
|
<Name>terminfo.py</Name>
|
||||||
</Source>
|
</Source>
|
||||||
<Source>
|
<Source>
|
||||||
<Name>libprs500/prstypes.py</Name>
|
<Dir>libprs500</Dir>
|
||||||
|
<Name>prstypes.py</Name>
|
||||||
</Source>
|
</Source>
|
||||||
<Source>
|
<Source>
|
||||||
<Name>libprs500/errors.py</Name>
|
<Dir>libprs500</Dir>
|
||||||
|
<Name>errors.py</Name>
|
||||||
|
</Source>
|
||||||
|
<Source>
|
||||||
|
<Dir>libprs500</Dir>
|
||||||
|
<Name>__init__.py</Name>
|
||||||
|
</Source>
|
||||||
|
<Source>
|
||||||
|
<Name>setup.py</Name>
|
||||||
|
</Source>
|
||||||
|
<Source>
|
||||||
|
<Dir>scripts</Dir>
|
||||||
|
<Name>prs500.py</Name>
|
||||||
</Source>
|
</Source>
|
||||||
</Sources>
|
</Sources>
|
||||||
<Forms>
|
<Forms>
|
||||||
@ -31,9 +46,16 @@
|
|||||||
<Interfaces>
|
<Interfaces>
|
||||||
</Interfaces>
|
</Interfaces>
|
||||||
<Others>
|
<Others>
|
||||||
|
<Other>
|
||||||
|
<Name>epydoc.conf</Name>
|
||||||
|
</Other>
|
||||||
|
<Other>
|
||||||
|
<Name>epydoc-pdf.conf</Name>
|
||||||
|
</Other>
|
||||||
</Others>
|
</Others>
|
||||||
<MainScript>
|
<MainScript>
|
||||||
<Name>libprs500/communicate.py</Name>
|
<Dir>scripts</Dir>
|
||||||
|
<Name>prs500.py</Name>
|
||||||
</MainScript>
|
</MainScript>
|
||||||
<Vcs>
|
<Vcs>
|
||||||
<VcsType>Subversion</VcsType>
|
<VcsType>Subversion</VcsType>
|
||||||
@ -96,9 +118,9 @@ s.</VcsOtherData>
|
|||||||
</Vcs>
|
</Vcs>
|
||||||
<FiletypeAssociations>
|
<FiletypeAssociations>
|
||||||
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
|
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
|
||||||
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
|
|
||||||
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
|
|
||||||
<FiletypeAssociation pattern="*.ui" type="FORMS" />
|
<FiletypeAssociation pattern="*.ui" type="FORMS" />
|
||||||
|
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
|
||||||
|
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
|
||||||
<FiletypeAssociation pattern="*.py" type="SOURCES" />
|
<FiletypeAssociation pattern="*.py" type="SOURCES" />
|
||||||
</FiletypeAssociations>
|
</FiletypeAssociations>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -16,6 +16,16 @@ from libprs500.errors import ArgumentError
|
|||||||
|
|
||||||
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
||||||
|
|
||||||
|
def human_readable(size):
|
||||||
|
""" Convert a size in bytes into a human readle form """
|
||||||
|
if size < 1024: divisor, suffix = 1, ""
|
||||||
|
elif size < 1024*1024: divisor, suffix = 1024., "K"
|
||||||
|
elif size < 1024*1024*1024: divisor, suffix = 1024*1024, "M"
|
||||||
|
elif size < 1024*1024*1024*1024: divisor, suffix = 1024*1024, "G"
|
||||||
|
size = str(size/divisor)
|
||||||
|
if size.find(".") > -1: size = size[:size.find(".")+2]
|
||||||
|
return size + suffix
|
||||||
|
|
||||||
class FileFormatter(object):
|
class FileFormatter(object):
|
||||||
def __init__(self, file, term):
|
def __init__(self, file, term):
|
||||||
self.term = term
|
self.term = term
|
||||||
@ -56,13 +66,7 @@ class FileFormatter(object):
|
|||||||
def human_readable_size():
|
def human_readable_size():
|
||||||
doc=""" File size in human readable form """
|
doc=""" File size in human readable form """
|
||||||
def fget(self):
|
def fget(self):
|
||||||
if self.size < 1024: divisor, suffix = 1, ""
|
human_readable(self.size)
|
||||||
elif self.size < 1024*1024: divisor, suffix = 1024., "K"
|
|
||||||
elif self.size < 1024*1024*1024: divisor, suffix = 1024*1024, "M"
|
|
||||||
elif self.size < 1024*1024*1024*1024: divisor, suffix = 1024*1024, "G"
|
|
||||||
size = str(self.size/divisor)
|
|
||||||
if size.find(".") > -1: size = size[:size.find(".")+2]
|
|
||||||
return size + suffix
|
|
||||||
return property(**locals())
|
return property(**locals())
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
@ -161,7 +165,7 @@ def main():
|
|||||||
term = TerminalController()
|
term = TerminalController()
|
||||||
cols = term.COLS
|
cols = term.COLS
|
||||||
|
|
||||||
parser = OptionParser(usage="usage: %prog command [options] args\n\ncommand is one of: info, ls, cp, cat or rm\n\n"+
|
parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand is one of: info, df, ls, cp, cat or rm\n\n"+
|
||||||
"For help on a particular command: %prog command", version="libprs500 version: " + VERSION)
|
"For help on a particular command: %prog command", version="libprs500 version: " + VERSION)
|
||||||
parser.add_option("--log-packets", help="print out packet stream to stdout", dest="log_packets", action="store_true", default=False)
|
parser.add_option("--log-packets", help="print out packet stream to stdout", dest="log_packets", action="store_true", default=False)
|
||||||
parser.remove_option("-h")
|
parser.remove_option("-h")
|
||||||
@ -174,7 +178,16 @@ def main():
|
|||||||
command = args[0]
|
command = args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
dev = PRS500Device(log_packets=options.log_packets)
|
dev = PRS500Device(log_packets=options.log_packets)
|
||||||
if command == "ls":
|
if command == "df":
|
||||||
|
dev.open()
|
||||||
|
data = dev.available_space()
|
||||||
|
dev.close()
|
||||||
|
print "Filesystem\tSize \tUsed \tAvail \tUse%"
|
||||||
|
for datum in data:
|
||||||
|
total, free, used, percent = human_readable(datum[2]), human_readable(datum[1]), human_readable(datum[2]-datum[1]), \
|
||||||
|
str(0 if datum[2]==0 else int(100*(datum[2]-datum[1])/(datum[2]*1.)))+"%"
|
||||||
|
print "%-10s\t%s\t%s\t%s\t%s"%(datum[0], total, used, free, percent)
|
||||||
|
elif command == "ls":
|
||||||
parser = OptionParser(usage="usage: %prog ls [options] path\n\npath must begin with /,a:/ or b:/")
|
parser = OptionParser(usage="usage: %prog ls [options] path\n\npath must begin with /,a:/ or b:/")
|
||||||
parser.add_option("--color", help="show ls output in color", dest="color", action="store_true", default=False)
|
parser.add_option("--color", help="show ls output in color", dest="color", action="store_true", default=False)
|
||||||
parser.add_option("-l", help="In addition to the name of each file, print the file type, permissions, and timestamp (the modification time unless other times are selected)", dest="ll", action="store_true", default=False)
|
parser.add_option("-l", help="In addition to the name of each file, print the file type, permissions, and timestamp (the modification time unless other times are selected)", dest="ll", action="store_true", default=False)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user