fileTools.py

Go to the documentation of this file.
00001 #!/usr/local/bin/python
00002 #
00003 # package fileTools.py
00004 #
00005 # This package creates an interface to the LAT filesystem from LICOS.
00006 #
00007 # Error tolerant APIs are provided to do the following
00008 #    Upload a file
00009 #    Download a file
00010 #    Delete a file
00011 #    List a directory
00012 #    Create a directory
00013 #    Delete a directory ( opt: also all files in it)
00014 
00015 
00016 __facility__ = "Online"
00017 __abstract__ = "File tools for ScriptEngine classes"
00018 __author__   = "J. Panetta <panetta@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00019 __date__     = "2005/11/1 00:08:27"
00020 __updated__  = "$Date: 2006/04/27 02:06:03 $"
00021 __version__  = "$Revision: 1.5 $"
00022 __release__  = "$Name: HEAD $"
00023 __credits__  = "SLAC"
00024 
00025 import LICOS.copyright_SLAC
00026 
00027 from LICOS.lib.cmdTlmDb.LCATcmdDb      import LCATcmdDb
00028 from LICOS.lib.cmdTlmDb.LCATtlmDb      import LCATtlmDb
00029 from LICOS.lib.cmdTlmDb.TelemetryEvent import TelemetryEvent
00030 from LICOS.lib.LATfunctions            import utcfromtimestamp
00031 
00032 import array
00033 import logging as log
00034 import os
00035 import struct
00036 import tempfile
00037 import time
00038 
00039 
00040 # enums from FILE traveler document
00041 FSW_DEVICE_BOOT  = 0  # Boot device
00042 FSW_DEVICE_RAM   = 1  # RAM disk
00043 FSW_DEVICE_EE0   = 2  # SIB EEPROM partition 0
00044 FSW_DEVICE_EE1   = 3  # SIB EEPROM partition 1
00045 FSW_DEVICE_TMP   = 4  # Host temp file system
00046 FSW_DEVICE_USR0  = 5  # User-defined device 0
00047 FSW_DEVICE_USR1  = 6  # User-defined device 1
00048 FSW_DEVICE_NAMES = ["boot", "ram", "ee0", "ee1", "tmp", "usr0", "usr1"  ]
00049 
00050 FSW_UNIT_SIU     = 0
00051 FSW_UNIT_EPU0    = 1
00052 FSW_UNIT_EPU1    = 2
00053 FSW_UNIT_EPU2    = 3
00054 FSW_UNIT_EPU3    = 4
00055 FSW_UNIT_NAMES = [ 'SIU ', 'EPU0', 'EPU1', 'EPU2', 'EPU3' ]
00056 
00057 # As per verbal agreement with Tony Waite (051108) INT can have
00058 #   directories 8-15 for it's own use.  Note:  Any directory > 15
00059 #   needs to be created
00060 INT_DIR_LATC     = 10
00061 INT_DIR_LCI      = 11
00062 
00063 FILETOOL_STANDARD_TIMEOUT = 60    # seconds
00064 
00065 # Define our tempfile paths for consistency
00066 if os.name == 'posix':
00067   FILETOOL_TMP_PATH = "/tmp"
00068 else:   # gotta be windows...
00069   FILETOOL_TMP_PATH = os.path.normpath(os.path.join('C:/', 'TEMP'))
00070 
00071 # executables to add FMX headers and compression to binary uploads
00072 if os.name == 'posix':
00073   FILETOOL_HDR_ALLOW = True
00074   FSW_ADD_HEADER_CMD = 'file_hdr_prefix'     # flight/SVC/symlnk/linux-gcc/exe/zcompress
00075   FSW_COMPRESS_CMD   = 'zcompress'           # flight/SVC/symlnk/linux-gcc/exe/file_hdr_prefix
00076 else:
00077   FILETOOL_HDR_ALLOW = False                 # do NOT allow addition of fsw headers from Windows
00078   FSW_ADD_HEADER_CMD = None
00079   FSW_COMPRESS_CMD   = None
00080 
00081 # hook for keeping track of an arbitrary file number (last part of a FswFileID)
00082 FILETOOL_ARBITRARY_FILENUMBER  = 0
00083 # hook for keeping track of an arbitrary FMX key  (not to be used with real FMX)
00084 FILETOOL_ARBITRARY_FMXID       = 0x20000000L
00085 
00086 
00087 def arbitraryFileID(seed=None):
00088   """!\brief Retrieve a semi-arbitrary FSW file Number to be used as input for FswFileID()
00089 
00090   \return  an integer
00091   """
00092   global FILETOOL_ARBITRARY_FILENUMBER
00093   if seed is not None:
00094     FILETOOL_ARBITRARY_FILENUMBER = seed
00095   # there is a max filenumber
00096   if FILETOOL_ARBITRARY_FILENUMBER > FswFileID.MASK_FILENUM:
00097     FILETOOL_ARBITRARY_FILENUMBER = 0
00098   id = FILETOOL_ARBITRARY_FILENUMBER
00099   FILETOOL_ARBITRARY_FILENUMBER += 1
00100   return id
00101 
00102 def arbitraryFmxID(seed=None):
00103   """!\brief Retrieve a semi-arbitrary FMX id to be used in creating an FMX header on the fly
00104 
00105   \return  an integer
00106   """
00107   global FILETOOL_ARBITRARY_FMXID
00108   if seed is not None:
00109     FILETOOL_ARBITRARY_FMXID = seed
00110   id = FILETOOL_ARBITRARY_FMXID
00111   FILETOOL_ARBITRARY_FMXID += 1
00112   return id
00113 
00114 class FswFile(object):
00115   """!\brief Functional interface to a generic file in FSW
00116   """
00117   def __init__(self, fid, bin, uploaded=False):
00118     """!\brief Constructor
00119 
00120     \param  fid       FswFileID for this file
00121     \param  bin       Raw binary representation of file
00122     \param  uploaded  True if file has been uploaded
00123     """
00124     self.__fid      = fid
00125     self.__bin      = bin
00126     self.__uploaded = False
00127 
00128   def fileID(self):
00129     """!\brief retrieve file ID
00130 
00131     \return a FswFileID object
00132     """
00133     return self.__fid
00134 
00135   def binary(self):
00136     """!\brief retrieve file data
00137 
00138     \return a raw binary string
00139     """
00140     return self.__bin
00141 
00142   def uploaded(self):
00143     """!\brief retrieve file upload status
00144 
00145     \return True if uploaded
00146     """
00147     return self.__uploaded
00148 
00149   def setUploaded(self, bool):
00150     """!\brief Set file upload status
00151 
00152     \param  bool True if file is uploaded
00153     """
00154     self.__uploaded = bool
00155 
00156   def write(self, stream):
00157     """!\brief write file to stream  (file descriptor)
00158 
00159     \param  stream  Any writable file descriptor
00160     """
00161     stream.write(self.__bin)
00162     stream.flush()    # because of buffering, string may not show up until flush() or close()
00163 
00164 class FswFileFromData(FswFile):
00165   """!\brief A memory resident FSW file interface
00166   """
00167   def __init__(self, fileID, fileDat, uploaded=False):
00168     """!\brief Constructor
00169 
00170     \param fileID    FswFileID for this file
00171     \param fileDat   The file's raw data
00172     \param uploaded  True if file has been uploaded
00173     """
00174     try:
00175       FswFile.__init__(self, fileID, fileDat, uploaded)
00176     except:
00177       raise
00178 
00179 class FswFileFromDisk(FswFile):
00180   """!\brief A disk resident FSW file interface
00181   """
00182   def __init__(self, fileID, fileName, uploaded=False):
00183     """!\brief Constructor
00184 
00185     \param fileID    FswFileID for this file
00186     \param fileName  A fully qualified file name to open
00187     \param uploaded  True if file has been uploaded
00188     """
00189     self.name = fileName
00190     try:
00191       self.file = open(fileName, 'rb')
00192       bin = self.file.read()
00193 
00194 
00195       FswFile.__init__(self, fileID, bin, uploaded)
00196     except Exception, e:
00197       raise
00198 
00199 class FswFileID(object):
00200   """!\brief Define a Flight Software File ID
00201 
00202   Defines the FSW file id, as specified in the FILE FSW traveler document
00203   """
00204   MASK_DEVICE    = 0x7
00205   MASK_DIRECTORY = 0x7F
00206   MASK_FILENUM   = 0x3FFFFF
00207   SHFT_DEVICE    = 29
00208   SHFT_DIRECTORY = 22
00209   SHFT_FILENUM   =  0
00210   def __init__(self, *argv, **argd):
00211     """!\brief Polymorphic constructor
00212 
00213     Takes 1 or 3 arguments {fileID} or {device,directory,fileNumber}
00214     Arguments can be either named or not.  A mix of both named and unnamed
00215     args is verboten.
00216 
00217     \param fileID    A LAT file ID (32 bit packed)
00218 
00219     \param device      Device to store file to [0..7]
00220     \param directory   Directory to store file to [0..0x7F]
00221     \param fileNumber  File Number [0..0x3FFFFF]
00222     """
00223     if len(argv) == 1:
00224       self.__fid = argv[0]
00225     elif len(argv) == 3:
00226       self.__fid = self.__computeFileID(argv[0], argv[1], argv[2])
00227     elif len(argd) == 1:
00228       self.__fid = argd['fileID']
00229     elif len(argd) == 3:
00230       self.__fid = self.__computeFileID( argd['device'], argd['directory'], argd['fileNumber'] )
00231     else:
00232       raise SyntaxError( "Incorrect arguments for FswFileID constructor: argv=%s, argd=%d" % (str(argv), str(argd)) )
00233 
00234   def __computeFileID(self, device, directory, filNum):
00235     """!\brief Compute the 32 bit FSW destination from component parts
00236     """
00237     if device & self.MASK_DEVICE != device:
00238       raise "Selected device number 0x%x is greater than the maximum of 0x7" % device
00239     if directory & self.MASK_DIRECTORY != directory:
00240       raise "Selected directory number 0x%x is greater than the maximum of 0x7F" % directory
00241     if filNum & self.MASK_FILENUM != filNum:
00242       raise "Selected file number 0x%x is greater than the maximum of 0x3fffff" % filNum
00243 
00244     dest = (device    << self.SHFT_DEVICE) + \
00245            (directory << self.SHFT_DIRECTORY) + \
00246            (filNum    << self.SHFT_FILENUM)
00247     return dest
00248 
00249   def id(self):
00250     """!\brief retrieve file ID
00251 
00252     \return 32 bit file ID
00253     """
00254     return self.__fid
00255 
00256   def device(self):
00257     """!\brief retrieve device
00258 
00259     \return 3 bit device
00260     """
00261     return (self.__fid >> self.SHFT_DEVICE ) & self.MASK_DEVICE
00262 
00263   def directory(self):
00264     """!\brief retrieve file ID
00265 
00266     \return 7 bit directory
00267     """
00268     return (self.__fid >> self.SHFT_DIRECTORY ) & self.MASK_DIRECTORY
00269 
00270   def fileNumber(self):
00271     """!\brief retrieve file ID
00272 
00273     \return 22 bit file Number
00274     """
00275     return (self.__fid >> self.SHFT_FILENUM ) & self.MASK_FILENUM
00276 
00277   def __str__(self):
00278     return '/%s/d%03d/f%07d' % \
00279            ( FSW_DEVICE_NAMES[self.device()], self.directory(), self.fileNumber())
00280 
00281 
00282 class FswDirectoryItem(object):
00283   """!\brief Representation of an item in an FSW directory
00284 
00285   REVISIT:  Make the members private and member functions?
00286   """
00287   __isdirTxt = [ '-', 'd' ]
00288   __roTxt    = [ 'w', '-' ]
00289   def __init__(self, fileID, ro, size, isdir, time, unit, blocks):
00290     """!\ Constructor
00291 
00292     \param fileID  A FswFileID object
00293     \param ro      file is ReadOnly flag (True/False)
00294     \param size    File size in bytes
00295     \param isdir   file is a directory flag  (True/False)
00296     \param time    File modification time in LAT epoch
00297     \param unit    File unit (i.e. FSW_UNIT_SIU)
00298     \param blocks  REVISIT::  file blocks, maybe unused?
00299     """
00300     self.id     = fileID
00301     self.ro     = ro
00302     self.size   = size
00303     self.isdir  = isdir
00304     self.time   = time
00305     self.unit   = unit
00306     self.blocks = blocks
00307 
00308   def dump(self, stream):
00309     """!\brief dump a directoryItem to a file descriptor.
00310 
00311     \param stream  Any file descriptor  (ie. sys.stdout)
00312     """
00313     msg = ""
00314     msg += self.__isdirTxt[self.isdir]
00315     msg += 'r'                            # always readable
00316     msg += self.__roTxt[self.ro]
00317     msg += ' %4s' % FSW_UNIT_NAMES[self.unit]
00318     msg += ' %10d' % self.size
00319     msg += ' %s' % utcfromtimestamp(int(self.time), 0).ctime()
00320     strid = str(self.id)
00321     if self.isdir: strid = strid[:-8]
00322     msg += ' %s' % strid
00323     print >> stream, msg
00324 
00325 
00326 class FswDirectory(object):
00327   """!\brief Representation of a FSW directory
00328 
00329   """
00330   def __init__(self, dirID):
00331     """!\ Constructor
00332 
00333     \param dirID  A FswFileID object
00334     """
00335     self.__id = dirID
00336     self.__files = []
00337 
00338   def addItem(self, f):
00339     """!\brief Add a file to this representation
00340 
00341     \param f  An FswDirectoryItem
00342     """
00343     if f not in self.__files:
00344       self.__files.append(f)
00345 
00346   def files(self):
00347     """!\brief return a list of all files in this directory rep
00348     """
00349     return self.__files
00350 
00351   def id(self):
00352     """!\brief retrieve file ID
00353 
00354     \return a FswFileID object
00355     """
00356     return self.__id
00357 
00358   def setId(self, id):
00359     """!\brief set the ID for this directory
00360 
00361     \param id   A FswFileID object
00362     """
00363     self.__id = id
00364 
00365   def dump(self, stream):
00366     """!\brief dump a directory to a file descriptor
00367 
00368     \param stream  Any file descriptor  (ie. sys.stdout)
00369     """
00370     msg = '/%s/d%03d' % ( FSW_DEVICE_NAMES[self.id().device()], self.id().directory())
00371     print >> stream, msg
00372     for item in self.__files:
00373       item.dump(stream)
00374 
00375 def addFmxHeader(inFile, doCompress=False, preCompressed=False, name=None,
00376                  type=None, key=None, timestamp=None):
00377   """!\brief Add an fmx header to a file.  compressing on the fly if requested
00378 
00379   \param  inFile         An FswFile object
00380   \param  doCompress     True/False  to compress on fly/not
00381   \param  preCompressed  True/False  if already compressed
00382   \param  name
00383   \param  type
00384   \param  key
00385   \param  timestamp
00386 
00387   \return An FswFile object with proper headers for upload
00388   """
00389   if not FILETOOL_HDR_ALLOW:
00390     raise RuntimeError('Adding an FMX header is not possible on non-unix systems')
00391 
00392   hdrCmd  = FSW_ADD_HEADER_CMD
00393   if hasattr(inFile, 'name'):  # passing a disk resident file
00394     rawFile = inFile
00395   else:
00396     rawFile  = tempfile.NamedTemporaryFile(mode='w+b')
00397     inFile.write(rawFile.file)
00398   hdrFile  = tempfile.NamedTemporaryFile(mode='w+b')
00399 
00400 
00401   if doCompress:
00402     # compress in tmpspace
00403     cmpFile  = tempfile.NamedTemporaryFile(mode='w+b')
00404 
00405     cmd  = FSW_COMPRESS_CMD
00406     cmd += ' %s' % rawFile.name
00407     cmd += ' %s' % cmpFile.name
00408     rc = os.system(cmd)
00409     rawFile = cmpFile
00410   if doCompress or preCompressed:
00411     hdrCmd += ' -c'
00412 
00413   # Various options for the header adding command
00414   if name is not None:
00415     hdrCmd += ' -n=%s' % name
00416   if type is not None:
00417     hdrCmd += ' -t=%s' % str(type)
00418   if key is not None:
00419     hdrCmd += ' -k=%s' % str(key)
00420   if timestamp is not None:
00421     hdrCmd += ' -s=%s' % str(timestamp)
00422 
00423   hdrCmd += ' %s' % rawFile.name
00424   hdrCmd += ' %s' % hdrFile.name
00425   rc = os.system(hdrCmd)
00426 
00427   retFile = FswFileFromDisk(inFile.fileID(), hdrFile.name)
00428 
00429   return retFile
00430 
00431 
00432 
00433 
00434 
00435 
00436 
00437 def downloadFile(app, unit, fileID):
00438   """!\brief Download a file from the LAT
00439 
00440   \param app         A testAppBase object  (your user application...)
00441   \param unit        LAT unit id to upload to
00442   \param fileID      An FswFileID object
00443   \return An FswFile object containing the data uploaded
00444   """
00445   class FileDump(object):
00446     def __init__(self, app):
00447       self.__app = app
00448       self.__fragments = {}
00449       self.__dumpSizes = {}
00450       self.__expectedID = None
00451       self.__dumpCTDBtelem = TelemetryEvent(app.getDiagHandler(),
00452                                             [app.lcatTlm.getApidFromName('LLFSDUMPCTDB')],
00453                                             self.dumpCTDB)
00454     def dumpCTDB(self, telemetry):
00455       # File chunks may be sent down out of order.
00456       # Cache each dump payload in a dictionary keyed on the file offset.
00457       pkt = self.__app.lcatTlm.decodeTelemetry(telemetry)
00458       offset = pkt.get_payload("LFSFDMPOFFSET")
00459       dumpSize = pkt.get_payload("LFSFDMPSIZE")
00460       # Check if this is part of the expected file
00461       dumpDev  = pkt.get_payload("LFSDMPDEV")
00462       dumpDir  = pkt.get_payload("LFSDMPDIR")
00463       dumpFile = pkt.get_payload("LFSDMPFILE")
00464       if dumpDev  != self.__expectedID.device() or \
00465          dumpDir  != self.__expectedID.directory() or \
00466          dumpFile != self.__expectedID.dumpFile():
00467         msg = "CTDB dump resulted in unexpected file: %s, expected %s" % \
00468               ( str(FswFileID(dumpDev, dumpDir, dumpFile)), self.__expectedID )
00469         raise RuntimeError(msg)
00470 
00471 
00472       dataMnems = ['LFSFDMPDATA%d' % i for i in xrange(390)]
00473       self.__fragments[offset] = ''.join(map(chr, map(pkt.get_payload, dataMnems)))
00474       self.__dumpSizes[offset] = dumpSize
00475 
00476     def dump(self, unit, fileID):
00477       self.__expectedID = fileID
00478       self.__dumpCTDBtelem.enable()
00479       LFS = self.__app.lcat.LFS
00480       LFS.LFSFILEDUMPC( LFSFILEID=fileID.id(), LFSUNIT=unit, LFSPAD16=0 )
00481       self.__app.waitForConfirmation(timeout = FILETOOL_STANDARD_TIMEOUT)
00482       offsets = self.__fragments.keys()
00483       offsets.sort()
00484       binary = ""
00485       for o in offsets:
00486         binary += self.__fragments[o][:self.__dumpSizes[o]]
00487 
00488       self.__dumpCTDBtelem.disable()
00489 
00490       return FswFileFromData(fileID, binary, uploaded=True)
00491 
00492   fd = FileDump(app)
00493 
00494   fswFile = fd.dump(unit, fileID)
00495 
00496   return fswFile
00497 
00498 def downloadFileToSSR(app, unit, fileID):
00499   """!\brief Download a file from the LAT
00500 
00501   \param app         A testAppBase object  (your user application...)
00502   \param unit        LAT unit id to upload to
00503   \param fileID      An FswFileID object
00504   \return status
00505   """
00506   LFS.LFSFILEDUMPS( LFSFILEID=fileID.id(), LFSunit=unit, LFSPAD16=0 )
00507   status = __checkLastCommandStatus(app)
00508   return status
00509 
00510 
00511 def uploadFileFromDisk(app, fileName, unit, fileID):
00512   """!\brief Upload a disk resident file with an FMX header
00513 
00514   \param app         A testAppBase object  (your user application...)
00515   \param fileName    Fully qualified file name
00516   \param unit        LAT unit id to upload to
00517   \param fileID      An FswFileID object
00518   \return An FswFile object containing the data uploaded
00519   """
00520   uplFile = None
00521   try:
00522     uplFile = FswFileFromDisk(fileID, fileName)
00523   except:
00524     raise
00525   else:
00526     uploadFile(app, uplFile, unit)
00527   return uplFile
00528 
00529 def uploadFileFromData(app, fileData, unit, fileID):
00530   """!\brief Upload a memory resident file with an FMX header (Typically received from MOOT)
00531 
00532   \param app         A testAppBase object  (your user application...)
00533   \param fileData    Binary representation of an FMX file
00534   \param unit        LAT unit id to upload to
00535   \param fileID      An FswFileID object
00536   \return An FswFile object containing the data uploaded
00537   """
00538   uplFile = None
00539   try:
00540     uplFile = FswFileFromData(fileID, fileData)
00541   except:
00542     raise
00543   else:
00544     uploadFile(app, uplFile, unit)
00545   return uplFile
00546 
00547 def cancelUpload(app, unit):
00548   """!\brief cancel any in process uploads
00549 
00550   \param app         A testAppBase object  (your user application...)
00551   \param fswFile     FswFile object
00552   \param unit        LAT unit id to upload to
00553   \return status
00554   """
00555   app.lcat.FILE.LFILUPLCANCEL(LFILEUNIT=unit)
00556   status = __checkLastCommandStatus(app)
00557   return status
00558 
00559 def uploadFile(app, fswFile, unit):
00560   """!\brief Upload a memory resident fsw file object
00561 
00562   \param app         A testAppBase object  (your user application...)
00563   \param fswFile     FswFile object
00564   \param unit        LAT unit id to upload to
00565   """
00566 
00567 
00568   # TODO:  JHP-  Check for uploaded?
00569   # if fswFile.uploaded():
00570   #   log.info("Fmx File 0x%x:%d has already been uploaded" % ( fswFile.fileId(), fswFile.fileId() )
00571   #   return True
00572 
00573   fileID = fswFile.fileID()
00574   uplStr = fswFile.binary()
00575 
00576   # cancel any pending transfers
00577   status = cancelUpload(app, unit)
00578   if not status:
00579     raise RuntimeError("Recieved bad status from cancelUpload.  Check previous warning.")
00580 
00581   # start file transfer command
00582   # fiddly code: 1: FSW uploads packets in multiples of 48 bytes.
00583   #              2: filuplstart must tell system *exactly* how much data to expect
00584   #              3: Round up to next 48 byte boundary
00585   dumpSize = len(fswFile.binary())
00586   d,m = divmod(dumpSize, 48)
00587   if m != 0:
00588     d += 1
00589   app.lcat.FILE.LFILUPLSTART(LFILESIZE=d*48)
00590   status = __checkLastCommandStatus(app)
00591   if not status:
00592     raise RuntimeError("Recieved bad status from upload start.  Check previous warning.")
00593 
00594   # loop over 48 byte chunks
00595   nDataBytes = 48
00596   chunk = 0
00597   offset = 0
00598   lastpacket = dumpSize // nDataBytes - 1
00599   while True:
00600     offset = chunk*nDataBytes
00601     if offset >= dumpSize:
00602       break
00603     if lastpacket > 0:
00604       if chunk == 0:
00605         seqFlags = 0x1 # first packet
00606       elif chunk == lastpacket:
00607         seqFlags = 0x2 # last packet
00608       else:
00609         seqFlags = 0x0 # middle packet
00610     else:
00611       seqFlags = 0x3     # not a sequence
00612     app.lcat.FILE.getCmdObj('LFILUPLDATA').seqFlags = seqFlags
00613     __uploadChunk(app, uplStr[offset:offset+nDataBytes], offset, nDataBytes)
00614     chunk += 1
00615 
00616   app.lcat.FILE.LFILUPLCOMMIT(LFILEUNIT=unit,
00617                               LFILEFLAGS=0,
00618                               LFILEID=fileID.id())
00619   status = __checkLastCommandStatus(app)
00620   if not status:
00621     raise RuntimeError("Received bad status from File Upload Commit.  Check previous warning")
00622 
00623 
00624   # don't forget to tell the file that it has been uploaded
00625   fswFile.setUploaded(True)
00626   return status
00627 
00628 
00629 def __uploadChunk(app, uplChunk, offset, nDataBytes):
00630   lChunk = len(uplChunk)
00631   if lChunk > nDataBytes:
00632     raise ValueError, "Length of a chunk can't be greater than %d bytes" % nDataBytes
00633   # Pad to nDataBytes bytes
00634   uplChunk = uplChunk + ( chr(0) * (nDataBytes-lChunk) )
00635   app.lcat.FILE.LFILUPLDATA(offset, *array.array('B',uplChunk).tolist())
00636 
00637   # from binascii import hexlify
00638   # print "chunk", offset, hexlify(uplChunk)
00639   # We do not get command confirmation for LFILUPLDATA telecommands
00640 
00641 def dumpDirectory(app, unit, directoryID, root=False):
00642   """!\brief Download a directory listing from the LAT
00643 
00644   \param app         A testAppBase object  (your user application...)
00645   \param unit        LAT unit id to upload to
00646   \param fileID      An FswFileID object with the correct directory set.
00647   \return An FswFile object containing the data uploaded
00648   """
00649   class DirDump(object):
00650     def __init__(self, app, root):
00651       self.__app  = app
00652       self.__root = root
00653       self.__rep = None
00654       self.__dumpSizes = {}
00655       if self.__root:
00656         wantedPacket = "LLFSROOTLIST"
00657       else:
00658         wantedPacket = "LLFSDIRLIST"
00659 
00660 
00661       self.__dumpDirTelem = TelemetryEvent(app.getDiagHandler(),
00662                                            [app.lcatTlm.getApidFromName(wantedPacket)],
00663                                            self.getPackets)
00664     def getPackets(self, telemetry):
00665       try:
00666         pkt = self.__app.lcatTlm.decodeTelemetry(telemetry)
00667         if self.__root:
00668           prefix = 'LFSRDMPF'
00669         else:
00670           prefix = 'LFSDDMP'
00671 
00672         device    = pkt.get_payload( prefix + "DEV" )
00673         directory = pkt.get_payload( prefix + "DIR" )
00674         fileNum   = pkt.get_payload( prefix + "FILE" )
00675         # Deal with LCAT inconsistencies
00676         if self.__root:
00677           prefix = prefix[:-1]
00678 
00679         ro        = pkt.get_payload( prefix + "ROFLG")
00680         size      = pkt.get_payload( prefix + "SIZE")
00681         isdir     = pkt.get_payload( prefix + "DIRFLG")
00682         t         = pkt.get_payload( prefix + "TIME")
00683         u         = pkt.get_payload( prefix + "UNIT")
00684         blocks    = 0  # pkt.get_payload( prefix + "BLOCKS")  # bad?  why?
00685         # print "cracked packet"
00686         self.__rep.addItem( FswDirectoryItem(FswFileID(device, directory, fileNum),
00687                                              ro, size, isdir, t, u, blocks) )
00688         # print "returning from getPa"
00689       except Exception, e:
00690         print e
00691         raise
00692 
00693     def dump(self, unit, dirID):
00694       self.__rep = FswDirectory( dirID=dirID )
00695       self.__dumpDirTelem.enable()
00696       self.__app.lcat.LFS.LFSDIRDUMP(LFSFILEID=dirID.id(),
00697                                      LFSUNIT=unit,
00698                                      LFSPAD16=0)
00699       self.__app.waitForConfirmation(timeout = FILETOOL_STANDARD_TIMEOUT)
00700       self.__dumpDirTelem.disable()
00701 
00702       return self.__rep
00703 
00704   dd = DirDump(app, root)
00705   dirRep = dd.dump(unit, directoryID)
00706   return dirRep
00707 
00708 def createDirectory(app, unit, directoryID):
00709   """!\brief create a directory on a LAT file system
00710 
00711   \param app         A testAppBase object  (your user application...)
00712   \param unit        LAT unit id
00713   \param fileID      An FswFileID object with the correct directory set.
00714   \return status     True if it worked, False if not.
00715   """
00716   app.lcat.LFS.LFSDIRCREATE(LFSUNIT=unit,
00717                             LFSFILEID=directoryID.id(),
00718                             LFSPAD16=0)
00719   status = app.waitForConfirmation(timeout = FILETOOL_STANDARD_TIMEOUT)
00720   return status
00721 
00722 def deleteDirectory(app, unit, directoryID, force=False):
00723   """!\brief Delete a directory on a LAT filesystem
00724 
00725   \param app          A testAppBase object  (your user application...)
00726   \param unit         LAT unit id to upload to
00727   \param directoryID  An FswFileID object with the correct directory set.
00728   \return status      True if success, False if failure
00729   """
00730   status = True
00731   if force:
00732     # Remove all files in this directory
00733     dirRep = dumpDirectory(app, unit, directoryID)
00734     for f in dirRep.files():
00735       status = deleteFile(app, unit, f.id)
00736       if not status:
00737         break
00738   if status:
00739     # log.debug("deleting directory %s" % directoryID)
00740     app.lcat.LFS.LFSDIRDELETE(LFSUNIT=unit,
00741                               LFSFILEID=directoryID.id(),
00742                               LFSPAD16=0)
00743     status = __checkLastCommandStatus(app)
00744   return status
00745 
00746 def deleteFile(app, unit, fileID):
00747   """!\brief Delete a file on a LAT filesystem
00748 
00749   \param app         A testAppBase object  (your user application...)
00750   \param unit        LAT unit id to upload to
00751   \param fileID      An FswFileID object
00752   \return status     True if success, False if failure
00753   """
00754   app.lcat.LFS.LFSFILEDELETE(LFSUNIT=unit,
00755                              LFSFILEID=fileID.id(),
00756                              LFSPAD16=0)
00757   status = __checkLastCommandStatus(app)
00758   return status
00759 
00760 def copyFile(app, unit, source, dest):
00761   """!\brief  Copy a file on any LAT unit
00762 
00763   \param app         A testAppBase object  (your user application...)
00764   \param unit        LAT unit id to upload to
00765   \param source      An FswFileID object corresponding to the source file
00766   \param dest        An FswFileID object corresponding to the destination file
00767   \return status     True if success, False if failure
00768   """
00769   status = True
00770   app.lcat.LFS.LFSFILECOPY(LFSUNIT=unit,
00771                            LFSSRCFILEID=source.id(),
00772                            LFSDESTFILEID=dest.id(),
00773                            LFSPAD16=0)
00774   status = __checkLastCommandStatus(app)
00775 
00776   return status
00777 
00778 def __checkLastCommandStatus(app):
00779   # boilerplate code that waits for completion on a command
00780   #   and checks the completion status.  If bad, log a warning
00781   status = True
00782   status = app.waitForConfirmation(timeout = FILETOOL_STANDARD_TIMEOUT)
00783   statusMsg = app.getConfirmationMsg()
00784   if not app.lcatTlm.msgIsSuccess(statusMsg):
00785     log.warning(app.lcatTlm.msgByValue(statusMsg))
00786     status=False
00787   return status
00788 

Generated on Thu Apr 27 20:52:41 2006 for LICOS L02-01-00 by doxygen 1.4.6-NO