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" 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>"

View File

@ -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

View File

@ -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. """

View File

@ -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>

View File

@ -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)