Improved packet tracing output (added byte count and packet count)

Added support for the df command
This commit is contained in:
Kovid Goyal 2006-11-07 08:10:02 +00:00
parent 1c8319a5a4
commit df077ebfbe
5 changed files with 154 additions and 29 deletions

View File

@ -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"
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"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"

View File

@ -47,13 +47,19 @@ The public interface of class L{PRS500Device} defines the methods for performing
import usb, sys
from array import array
from prstypes import AcknowledgeBulkRead, Answer, Command, DeviceInfo, DirOpen, DirRead, DirClose, \
FileOpen, FileClose, FileRead, IdAnswer, ListAnswer, \
ListResponse, LongCommand, FileProperties, PathQuery, Response, \
ShortCommand, DeviceInfoQuery
from prstypes import *
from errors import *
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):
""" 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 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)
if bytes_sent != len(command):
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))
if self._log_packets: print "Response\n%s\n--\n"%response
if self._log_packets: _log_packet(response, "Response")
return response
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.
"""
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
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")):
dirs[len(dirs):] = self.list(file.path, recurse=True)
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

View File

@ -85,7 +85,7 @@ class TransferBuffer(list):
0700 0100 0000 0000 0000 0000 0c00 0000 ................
0200 0000 0400 0000 4461 7461 ........Data
"""
ans, ascii = "", ""
ans, ascii = ": ".rjust(10,"0"), ""
for i in range(0, len(self), 2):
for b in range(2):
try:
@ -95,10 +95,10 @@ class TransferBuffer(list):
ans = ans + " "
if (i+2)%16 == 0:
if i+2 < len(self):
ans += " " + ascii + "\n"
ans += " " + ascii + "\n" + (TransferBuffer.phex(i+2)+": ").rjust(10, "0")
ascii = ""
last_line = ans[ans.rfind("\n")+1:]
padding = 40 - len(last_line)
padding = 50 - len(last_line)
ans += "".ljust(padding) + " " + ascii
return ans.strip()
@ -271,6 +271,43 @@ class ShortCommand(Command):
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):
""" Open a directory for reading its contents """
@ -795,6 +832,31 @@ class DeviceInfo(Answer):
return src[0:src.find('\x00')]
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):
""" Defines the structure of packets that contain items in a list. """

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-3.9.dtd">
<!-- Project file for project pr5-500 -->
<!-- Saved: 2006-10-31, 21:14:19 -->
<!-- Project file for project prs-500 -->
<!-- Saved: 2006-11-07, 00:09:05 -->
<!-- Copyright (C) 2006 Kovid Goyal, kovid@kovidgoyal.net -->
<Project version="3.9">
<ProgLanguage mixed="0">Python</ProgLanguage>
@ -12,16 +12,31 @@
<Email>kovid@kovidgoyal.net</Email>
<Sources>
<Source>
<Name>libprs500/communicate.py</Name>
<Dir>libprs500</Dir>
<Name>communicate.py</Name>
</Source>
<Source>
<Name>libprs500/terminfo.py</Name>
<Dir>libprs500</Dir>
<Name>terminfo.py</Name>
</Source>
<Source>
<Name>libprs500/prstypes.py</Name>
<Dir>libprs500</Dir>
<Name>prstypes.py</Name>
</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>
</Sources>
<Forms>
@ -31,9 +46,16 @@
<Interfaces>
</Interfaces>
<Others>
<Other>
<Name>epydoc.conf</Name>
</Other>
<Other>
<Name>epydoc-pdf.conf</Name>
</Other>
</Others>
<MainScript>
<Name>libprs500/communicate.py</Name>
<Dir>scripts</Dir>
<Name>prs500.py</Name>
</MainScript>
<Vcs>
<VcsType>Subversion</VcsType>
@ -96,9 +118,9 @@ s.</VcsOtherData>
</Vcs>
<FiletypeAssociations>
<FiletypeAssociation pattern="*.ui.h" type="FORMS" />
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
<FiletypeAssociation pattern="*.ui" type="FORMS" />
<FiletypeAssociation pattern="*.idl" type="INTERFACES" />
<FiletypeAssociation pattern="*.ptl" type="SOURCES" />
<FiletypeAssociation pattern="*.py" type="SOURCES" />
</FiletypeAssociations>
</Project>

View File

@ -16,6 +16,16 @@ from libprs500.errors import ArgumentError
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):
def __init__(self, file, term):
self.term = term
@ -56,13 +66,7 @@ class FileFormatter(object):
def human_readable_size():
doc=""" File size in human readable form """
def fget(self):
if self.size < 1024: divisor, suffix = 1, ""
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
human_readable(self.size)
return property(**locals())
@apply
@ -161,7 +165,7 @@ def main():
term = TerminalController()
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)
parser.add_option("--log-packets", help="print out packet stream to stdout", dest="log_packets", action="store_true", default=False)
parser.remove_option("-h")
@ -174,7 +178,16 @@ def main():
command = args[0]
args = args[1:]
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.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)