00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 __facility__ = "Online"
00017 __abstract__ = "FILE related mnemonics"
00018 __author__ = "Selim Tuvi <stuvi@slac.stanford.edu> SLAC - GLAST LAT I&T/Online"
00019 __date__ = "2005/07/23 00:08:27"
00020 __updated__ = "$Date: 2006/04/28 01:29:35 $"
00021 __version__ = "$Revision: 1.18 $"
00022 __release__ = "$Name: HEAD $"
00023 __credits__ = "SLAC"
00024
00025 import LICOS.copyright_SLAC
00026
00027 import array
00028 import logging as log
00029 import os
00030 import tempfile
00031 import time
00032
00033 from cmdTlmDb import CmdPkg
00034
00035 from LICOS.lib.LATconstants import *
00036 from LICOS.lib.cmdTlmDb.TelemetryEvent import TelemetryEvent
00037 from LICOS.lib.LATfunctions import utcfromtimestamp
00038
00039
00040 if os.name == 'posix':
00041 FILETOOL_TMP_PATH = "/tmp"
00042 else:
00043 FILETOOL_TMP_PATH = os.path.normpath(os.path.join('C:/', 'TEMP'))
00044
00045
00046 if os.name == 'posix':
00047 FILETOOL_HDR_ALLOW = True
00048 FSW_ADD_HEADER_CMD = 'file_hdr_prefix'
00049 FSW_COMPRESS_CMD = 'zcompress'
00050 else:
00051 FILETOOL_HDR_ALLOW = False
00052 FSW_ADD_HEADER_CMD = None
00053 FSW_COMPRESS_CMD = None
00054
00055
00056 FILETOOL_ARBITRARY_FILENUMBER = 0
00057
00058 FILETOOL_ARBITRARY_FMXID = 0x20000000L
00059
00060
00061 FILE_PBC_FILESTAT = { FSW_UNIT_SIU : [ "LBTHKP", "LPBCFILESTAT", "" ],
00062 FSW_UNIT_EPU0: [ "LBTEPU0HKP", "LPBC0FILESTAT", "diag" ],
00063 FSW_UNIT_EPU1: [ "LBTEPU1HKP", "LPBC1FILESTAT", "diag" ],
00064 FSW_UNIT_EPU2: [ "LBTEPU2HKP", "LPBC2FILESTAT", "diag" ],
00065 }
00066
00067
00068 class FILE(CmdPkg):
00069 """!\brief FILE telecommand package class
00070
00071 Provides access to FILE telecommands.
00072 """
00073 def __init__(self, db):
00074 """!\brief FILE constructor.
00075
00076 \param db Wrapper database object for the generated module
00077 containing command and telemetry database classes.
00078 """
00079 CmdPkg.__init__(self, db)
00080 self.__primaryBoot=False
00081
00082
00083
00084 def downloadFile(self, unit, fileID):
00085 """!\brief Download a file from the LAT
00086
00087 \param unit LAT unit id to upload to
00088 \param fileID An FswFileID object
00089 \return An FswFile object containing the data uploaded
00090 """
00091 class FileDump(object):
00092 def __init__(self, master):
00093 self.__master = master
00094 self.__cmdDb = master.getCmdDb()
00095 self.__fragments = {}
00096 self.__dumpSizes = {}
00097 self.__expectedID = None
00098 self.__dumpCTDBtelem = TelemetryEvent(self.__cmdDb.getVsc().getDiagHandler(),
00099 [self.__cmdDb.getVsc().getTlmDb().getApidFromName('LLFSDUMPCTDB')],
00100 self.dumpCTDB)
00101 def dumpCTDB(self, telemetry):
00102
00103
00104 try:
00105 pkt = self.__cmdDb.getVsc().getTlmDb().decodeTelemetry(telemetry)
00106 offset = pkt.get_payload("LFSFDMPOFFSET")
00107 dumpSize = pkt.get_payload("LFSFDMPSIZE")
00108
00109
00110 dumpDev = pkt.get_payload("LFSFDMPDEV")
00111 dumpDir = pkt.get_payload("LFSFDMPDIR")
00112 dumpFile = pkt.get_payload("LFSFDMPFILE")
00113
00114 if dumpDev != self.__expectedID.device() or \
00115 dumpDir != self.__expectedID.directory() or \
00116 dumpFile != self.__expectedID.fileNumber():
00117 msg = "CTDB dump resulted in unexpected file: %s, expected %s" % \
00118 ( str(FswFileID(dumpDev, dumpDir, dumpFile)), self.__expectedID )
00119 raise RuntimeError(msg)
00120
00121 dataMnems = ['LFSFDMPDATA%d' % i for i in xrange(390)]
00122 self.__fragments[offset] = ''.join(map(chr, map(pkt.get_payload, dataMnems)))
00123 self.__dumpSizes[offset] = dumpSize
00124
00125 except Exception, e:
00126 print e
00127 raise
00128
00129 def dump(self, unit, fileID):
00130 self.__expectedID = fileID
00131 self.__dumpCTDBtelem.enable()
00132 LFS = self.__cmdDb.LFS
00133
00134
00135 expSize = None
00136 dir = self.__cmdDb.FILE.dumpDirectory(unit,fileID)
00137 files = dir.files()
00138 for f in files:
00139 if f.id.id() == fileID.id():
00140 expSize = f.size
00141
00142 LFS.LFSFILEDUMPC( LFSFILEID=fileID.id(),
00143 LFSUNIT=unit,
00144 LFSPAD16=0 )
00145
00146
00147 timeWait = 0
00148 oldSize = 0
00149 downSize = sum(self.__dumpSizes.values())
00150 while downSize < expSize and timeWait < SHORT_TIMEOUT*5:
00151
00152 if downSize > oldSize:
00153 timeWait = 0
00154 time.sleep(0.1)
00155 timeWait += 0.1
00156 downSize = sum(self.__dumpSizes.values())
00157
00158
00159 offsets = self.__fragments.keys()
00160 offsets.sort()
00161 binary = ""
00162 for o in offsets:
00163 binary += self.__fragments[o][:self.__dumpSizes[o]]
00164
00165 status = self.__master.checkLastCommandStatus()
00166 self.__dumpCTDBtelem.disable()
00167
00168 return FswFileFromData(fileID, binary, uploaded=True)
00169
00170 fd = FileDump(self.getCmdDb())
00171
00172 fswFile = fd.dump(self.__LFSUNIT(unit), fileID)
00173
00174 return fswFile
00175
00176
00177 def downloadFileToSSR(self, unit, fileID):
00178 """!\brief Download a file from the LAT
00179
00180 \param app A testAppBase object (your user application...)
00181 \param unit LAT unit id to upload to
00182 \param fileID An FswFileID object
00183 \return status
00184 """
00185 self.getCmdDb().LFS.LFSFILEDUMPS( LFSFILEID=fileID.id(),
00186 LFSunit=self.__LFSUNIT(unit),
00187 LFSPAD16=0 )
00188 status = self.checkLastCommandStatus()
00189 return status
00190
00191 def dumpDirectory(self, unit, directoryID, root=False):
00192 """!\brief Download a directory listing from the LAT
00193
00194 \param unit LAT unit id to upload to
00195 \param fileID An FswFileID object with the correct directory set.
00196 \return An FswFile object containing the data uploaded
00197 """
00198 class DirDump(object):
00199 def __init__(self, master, root):
00200 self.__master = master
00201 self.__cmdDb = master.getCmdDb()
00202 self.__root = root
00203 self.__rep = None
00204 self.__lastTime = time.time()
00205 self.__dumpSizes = {}
00206 if self.__root:
00207 wantedPacket = "LLFSROOTLIST"
00208 else:
00209 wantedPacket = "LLFSDIRLIST"
00210
00211
00212 self.__dumpDirTelem = TelemetryEvent(self.__cmdDb.getVsc().getDiagHandler(),
00213 [self.__cmdDb.getVsc().getTlmDb().getApidFromName(wantedPacket)],
00214 self.getPackets)
00215 def getPackets(self, telemetry):
00216 self.__lastTime = time.time()
00217 try:
00218 pkt = self.__cmdDb.getVsc().getTlmDb().decodeTelemetry(telemetry)
00219 if self.__root:
00220 prefix = 'LFSRDMPF'
00221 else:
00222 prefix = 'LFSDDMP'
00223
00224 device = pkt.get_payload( prefix + "DEV" )
00225 directory = pkt.get_payload( prefix + "DIR" )
00226 fileNum = pkt.get_payload( prefix + "FILE" )
00227
00228 if self.__root:
00229 prefix = prefix[:-1]
00230
00231 ro = pkt.get_payload( prefix + "ROFLG")
00232 size = pkt.get_payload( prefix + "SIZE")
00233 isdir = pkt.get_payload( prefix + "DIRFLG")
00234 t = pkt.get_payload( prefix + "TIME")
00235 u = pkt.get_payload( prefix + "UNIT")
00236 blocks = 0
00237
00238
00239 id = FswFileID(device, directory, fileNum)
00240 item = FswDirectoryItem(id,
00241 ro, size, isdir, t, u, blocks)
00242
00243 self.__rep.addItem(item)
00244
00245
00246
00247 if not self.__root:
00248 dataMnems = [prefix+ 'FHDR%d' %i for i in xrange(32)]
00249 hdr = ''.join(map(chr, map(pkt.get_payload, dataMnems)))
00250 item.header = hdr
00251
00252 except Exception, e:
00253 print e
00254 raise
00255
00256 def dump(self, unit, dirID):
00257 self.__rep = FswDirectory( dirID=dirID )
00258 self.__dumpDirTelem.enable()
00259 self.__cmdDb.LFS.LFSDIRDUMP(LFSFILEID=dirID.id(),
00260 LFSUNIT=unit,
00261 LFSPAD16=0)
00262
00263 while True:
00264 if time.time() - self.__lastTime > 2.0:
00265 break
00266 else:
00267 time.sleep(0.1)
00268 status = self.__master.checkLastCommandStatus()
00269
00270 time.sleep(1)
00271
00272 self.__dumpDirTelem.disable()
00273
00274 return self.__rep
00275
00276 dd = DirDump(self.getCmdDb(), root)
00277 dirRep = dd.dump(self.__LFSUNIT(unit), directoryID)
00278 return dirRep
00279
00280 def createDirectory(self, unit, directoryID):
00281 """!\brief create a directory on a LAT file system
00282
00283 \param unit LAT unit id
00284 \param directoryID An FswFileID object with the correct directory set.
00285 \return status True if it worked, False if not.
00286 """
00287 if directoryID.directory() not in FSW_DIR_RANGE:
00288 log.error("%s attempted to create directory %d which is out of the allowed range" %\
00289 ("FILE.createDirectory", directoryID.directory()) )
00290 return False
00291
00292 self.getCmdDb().LFS.LFSDIRCREATE(LFSUNIT=self.__LFSUNIT(unit),
00293 LFSFILEID=directoryID.id(),
00294 LFSPAD16=0)
00295 status = self.checkLastCommandStatus()
00296 return status
00297
00298 def deleteDirectory(self, unit, directoryID, force=False):
00299 """!\brief Delete a directory on a LAT filesystem
00300
00301 \param unit LAT unit id to upload to
00302 \param directoryID An FswFileID object with the correct directory set.
00303 \return status True if success, False if failure
00304 """
00305 if directoryID.directory() not in FSW_DIR_RANGE:
00306 log.error("%s attempted to delete directory %d which is out of the allowed range" %\
00307 ("FILE.deleteDirectory", directoryID.directory()) )
00308 return False
00309
00310 status = True
00311 if force:
00312
00313 dirRep = self.dumpDirectory(unit, directoryID)
00314 for f in dirRep.files():
00315 status = self.deleteFile(unit, f.id)
00316 if not status:
00317 break
00318 if status:
00319
00320 self.getCmdDb().LFS.LFSDIRDELETE(LFSUNIT=self.__LFSUNIT(unit),
00321 LFSFILEID=directoryID.id(),
00322 LFSPAD16=0)
00323 status = self.checkLastCommandStatus()
00324
00325 return status
00326
00327
00328 def uploadFileFromDisk(self, fileName, unit, fileID):
00329 """!\brief Upload a disk resident file with an FMX header
00330
00331 \param app A testAppBase object (your user application...)
00332 \param fileName Fully qualified file name
00333 \param unit LAT unit id to upload to
00334 \param fileID An FswFileID object
00335 \return An FswFile object containing the data uploaded
00336 """
00337 uplFile = None
00338 try:
00339 uplFile = FswFileFromDisk(fileID, fileName)
00340 except:
00341 raise
00342 else:
00343 self.uploadFile(uplFile, unit)
00344 return uplFile
00345
00346 def uploadFileFromData(self, fileData, unit, fileID):
00347 """!\brief Upload a memory resident file with an FMX header (Typically received from MOOT)
00348
00349 \param app A testAppBase object (your user application...)
00350 \param fileData Binary representation of an FMX file
00351 \param unit LAT unit id to upload to
00352 \param fileID An FswFileID object
00353 \return An FswFile object containing the data uploaded
00354 """
00355 uplFile = None
00356 try:
00357 uplFile = FswFileFromData(fileID, fileData)
00358 except:
00359 raise
00360 else:
00361 self.uploadFile(uplFile, unit)
00362 return uplFile
00363
00364 def cancelUpload(self, unit):
00365 """!\brief cancel any in process uploads
00366
00367 \param app A testAppBase object (your user application...)
00368 \param fswFile FswFile object
00369 \param unit LAT unit id to upload to
00370 \return status
00371 """
00372 self.LFILUPLCANCEL(LFILEUNIT=self.__LFSUNIT(unit))
00373 status = self.checkLastCommandStatus()
00374 return status
00375
00376 def uploadFile(self, fswFile, unit):
00377 """!\brief Upload a memory resident fsw file object
00378
00379 \param app A testAppBase object (your user application...)
00380 \param fswFile FswFile object
00381 \param unit LAT unit id to upload to
00382 \return status
00383 """
00384
00385
00386
00387
00388
00389
00390 fileID = fswFile.fileID()
00391 uplStr = fswFile.binary()
00392 status = True
00393
00394
00395
00396
00397
00398 epuUnits = ( FSW_UNIT_EPU0, FSW_UNIT_EPU1, FSW_UNIT_EPU2, FSW_UNIT_EPU3 )
00399 status = self.cancelUpload(unit)
00400 if unit in epuUnits:
00401
00402 cachePB = self.__primaryBoot
00403 self.__primaryBoot = False
00404 status &= self.cancelUpload(FSW_UNIT_SIU)
00405 self.__primaryBoot = cachePB
00406 if not status:
00407 print status
00408 raise RuntimeError("Recieved bad status from cancelUpload. Check previous warning.")
00409
00410
00411
00412
00413
00414 dumpSize = len(fswFile.binary())
00415 d,m = divmod(dumpSize, 48)
00416 if m != 0:
00417 d += 1
00418 self.LFILUPLSTART(LFILESIZE=d*48)
00419 status = self.checkLastCommandStatus()
00420 if not status:
00421 raise RuntimeError("Recieved bad status from upload start. Check previous warning.")
00422
00423
00424 nDataBytes = 48
00425 chunk = 0
00426 offset = 0
00427 lastpacket = dumpSize // nDataBytes - 1
00428 while True:
00429 offset = chunk*nDataBytes
00430 if offset >= dumpSize:
00431 break
00432 if lastpacket > 0:
00433 if chunk == 0:
00434 seqFlags = 0x1
00435 elif chunk == lastpacket:
00436 seqFlags = 0x2
00437 else:
00438 seqFlags = 0x0
00439 else:
00440 seqFlags = 0x3
00441 self.getCmdObj('LFILUPLDATA').seqFlags = seqFlags
00442 self.__uploadChunk(uplStr[offset:offset+nDataBytes], offset, nDataBytes)
00443 chunk += 1
00444
00445
00446
00447 uploadTimeout = max(STANDARD_TIMEOUT, chunk*(1./8.)+STANDARD_TIMEOUT)
00448
00449
00450
00451 if unit in epuUnits:
00452 log.debug("Uploading to %s. Sending to SIU RAM first" % FSW_UNIT_NAMES[unit])
00453
00454 tempSiuID = FswFileID( device = FSW_DEVICE_RAM,
00455 directory = 15,
00456 fileNumber = FswFileID.MASK_FILENUM)
00457
00458 cachePB = self.__primaryBoot
00459 self.__primaryBoot = False
00460
00461 self.LFILUPLCOMMIT( LFILEUNIT=self.__LFSUNIT(FSW_UNIT_SIU),
00462 LFILEFLAGS=0,
00463 LFILEID=tempSiuID.id())
00464 status = self.checkLastCommandStatus()
00465
00466 self.LFILUPLEPU(LFILEUNIT=self.__LFSUNIT(unit),
00467 LFILEPAD16 = 0,
00468 LFILEID = tempSiuID.id())
00469 status = self.checkLastCommandStatus()
00470
00471 self.__primaryBoot = cachePB
00472
00473
00474 log.debug("committing to unit:%s, flags:%s, id:%s. This may take up to %d seconds." % ( unit, 0, str(fileID), uploadTimeout))
00475 self.LFILUPLCOMMIT(LFILEUNIT=self.__LFSUNIT(unit),
00476 LFILEFLAGS=0,
00477 LFILEID=fileID.id())
00478
00479
00480
00481
00482
00483 if self.__primaryBoot:
00484 pkt, tlm, handler = FILE_PBC_FILESTAT[unit]
00485 self.__fileState = -9999999
00486 vsc = self.getCmdDb().getVsc()
00487 def inlinePBCHandler(telemetry):
00488 try:
00489 pkt = self.getCmdDb().getVsc().getTlmDb().decodeTelemetry(telemetry)
00490 self.__fileState = pkt.get_payload(tlm)
00491 except Exception, e:
00492 self.__fileState = -9999999
00493
00494
00495 if handler == "diag":
00496 handler = vsc.getDiagHandler()
00497 else:
00498 handler = vsc.getTelemHandler()
00499 pbtTelem = TelemetryEvent(handler,
00500 [vsc.getTlmDb().getApidFromName(pkt),],
00501 inlinePBCHandler)
00502
00503
00504 totWait = 0
00505 pbtTelem.enable()
00506 time.sleep(1)
00507 while self.__fileState != 0:
00508 totWait += 1
00509 time.sleep(1)
00510 if totWait > uploadTimeout:
00511 status = False
00512 break
00513 pbtTelem.disable()
00514 else:
00515
00516 status = self.checkLastCommandStatus(timeout = uploadTimeout)
00517 if not status:
00518 raise RuntimeError("Received bad status from File Upload Commit. Check previous warning")
00519
00520
00521 if status: status = fswFile.setUploaded(True)
00522 return status
00523
00524 def copyFile(self, unit, source, dest, destUnit=None):
00525 """!\brief Copy a file on any LAT unit
00526
00527 \param app A testAppBase object (your user application...)
00528 \param unit LAT unit id to upload to
00529 \param source An FswFileID object corresponding to the source file
00530 \param dest An FswFileID object corresponding to the destination file
00531 \param destUnit Unit to copy to (Default = None ==> same unit)
00532 \return status True if success, False if failure
00533 """
00534 status = True
00535 LFS = self.getCmdDb().LFS
00536 FILE = self.getCmdDb().FILE
00537 if destUnit is None:
00538 LFS.LFSFILECOPY(LFSUNIT=self.__LFSUNIT(unit),
00539 LFSSRCFILEID=source.id(),
00540 LFSDESTFILEID=dest.id(),
00541 LFSPAD16=0)
00542 status &= self.checkLastCommandStatus()
00543 else:
00544
00545 self.cancelUpload(destUnit)
00546
00547 self.LFILUPLEPU(LFILEUNIT=self.__LFSUNIT(destUnit),
00548 LFILEPAD16 = 0,
00549 LFILEID = source.id())
00550 status &= self.checkLastCommandStatus()
00551 if not status:
00552 log.warning("bad status in copyFile")
00553 return status
00554 time.sleep(5)
00555 self.LFILUPLCOMMIT( LFILEUNIT=self.__LFSUNIT(destUnit),
00556 LFILEFLAGS = 0,
00557 LFILEID = dest.id())
00558 status &= self.checkLastCommandStatus()
00559
00560
00561 return status
00562
00563 def deleteFile(self, unit, fileID):
00564 """!\brief Delete a file on a LAT filesystem
00565
00566 \param app A testAppBase object (your user application...)
00567 \param unit LAT unit id to upload to
00568 \param fileID An FswFileID object
00569 \return status True if success, False if failure
00570 """
00571 self.getCmdDb().LFS.LFSFILEDELETE(LFSUNIT=self.__LFSUNIT(unit),
00572 LFSFILEID=fileID.id(),
00573 LFSPAD16=0)
00574 status = self.checkLastCommandStatus()
00575 return status
00576
00577 def __LFSUNIT(self, realUnit, tranID=0):
00578
00579 return ( (realUnit & 0xf) << 12 | (tranID & 0xfff) )
00580
00581 def __uploadChunk(self, uplChunk, offset, nDataBytes):
00582 lChunk = len(uplChunk)
00583 if lChunk > nDataBytes:
00584 raise ValueError, "Length of a chunk can't be greater than %d bytes" % nDataBytes
00585
00586 if (nDataBytes-lChunk):
00587 uplChunk = uplChunk + ( chr(0) * (nDataBytes-lChunk) )
00588 l = array.array('B',uplChunk).tolist()
00589 self.LFILUPLDATA(offset, *l)
00590
00591
00592
00593
00594
00595 def checkLastCommandStatus(self, timeout=STANDARD_TIMEOUT):
00596
00597
00598 status = True
00599 if self.__primaryBoot:
00600 print "WARNING: command completion disabled"
00601 import time
00602 time.sleep(1)
00603 return status
00604 app = self.getCmdDb()
00605 app.waitForConfirmation(timeout)
00606 statusMsg = app.getConfirmationMsg()
00607 if not app.getVsc().getTlmDb().msgIsSuccess(statusMsg):
00608 log.warning(app.getVsc().getTlmDb().msgByValue(statusMsg))
00609 status=False
00610 return status
00611
00612 def setPrimaryBoot(self, bool):
00613 self.__primaryBoot = bool
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 class FswFile(object):
00624 """!\brief Functional interface to a generic file in FSW
00625 """
00626 def __init__(self, fid, bin, uploaded=False):
00627 """!\brief Constructor
00628
00629 \param fid FswFileID for this file
00630 \param bin Raw binary representation of file
00631 \param uploaded True if file has been uploaded
00632 """
00633 self.__fid = fid
00634 self.__bin = bin
00635 self.__uploaded = uploaded
00636
00637 def fileID(self):
00638 """!\brief retrieve file ID
00639
00640 \return a FswFileID object
00641 """
00642 return self.__fid
00643
00644 def binary(self):
00645 """!\brief retrieve file data
00646
00647 \return a raw binary string
00648 """
00649 return self.__bin
00650
00651 def uploaded(self):
00652 """!\brief retrieve file upload status
00653
00654 \return True if uploaded
00655 """
00656 return self.__uploaded
00657
00658 def setUploaded(self, bool):
00659 """!\brief Set file upload status
00660
00661 \param bool True if file is uploaded
00662 \return True if this succeeds
00663 """
00664 self.__uploaded = bool
00665 return True
00666
00667 def write(self, stream):
00668 """!\brief write file to stream (file descriptor)
00669
00670 \param stream Any writable file descriptor
00671 """
00672 stream.write(self.__bin)
00673 stream.flush()
00674
00675 class FswFileFromData(FswFile):
00676 """!\brief A memory resident FSW file interface
00677 """
00678 def __init__(self, fileID, fileDat, uploaded=False):
00679 """!\brief Constructor
00680
00681 \param fileID FswFileID for this file
00682 \param fileDat The file's raw data
00683 \param uploaded True if file has been uploaded
00684 """
00685 try:
00686 FswFile.__init__(self, fileID, fileDat, uploaded)
00687 except:
00688 raise
00689
00690 class FswFileFromDisk(FswFile):
00691 """!\brief A disk resident FSW file interface
00692 """
00693 def __init__(self, fileID, fileName, uploaded=False):
00694 """!\brief Constructor
00695
00696 \param fileID FswFileID for this file
00697 \param fileName A fully qualified file name to open
00698 \param uploaded True if file has been uploaded
00699 """
00700 self.name = fileName
00701 try:
00702 self.file = open(fileName, 'rb')
00703 bin = self.file.read()
00704 FswFile.__init__(self, fileID, bin, uploaded)
00705 except Exception, e:
00706 raise
00707
00708
00709
00710 class FswFileID(object):
00711 """!\brief Define a Flight Software File ID
00712
00713 Defines the FSW file id, as specified in the FILE FSW traveler document
00714 """
00715 MASK_DEVICE = 0x7
00716 MASK_DIRECTORY = 0x7F
00717 MASK_FILENUM = 0x3FFFFF
00718 SHFT_DEVICE = 29
00719 SHFT_DIRECTORY = 22
00720 SHFT_FILENUM = 0
00721 def __init__(self, *argv, **argd):
00722 """!\brief Polymorphic constructor
00723
00724 Takes 1 or 3 arguments {fileID} or {device,directory,fileNumber}
00725 Arguments can be either named or not. A mix of both named and unnamed
00726 args is verboten.
00727
00728 \param fileID A LAT file ID (32 bit packed)
00729
00730 \param device Device to store file to [0..7]
00731 \param directory Directory to store file to [0..0x7F]
00732 \param fileNumber File Number [0..0x3FFFFF]
00733 """
00734 if len(argv) == 1:
00735 self.__fid = argv[0]
00736 elif len(argv) == 3:
00737 self.__fid = self.__computeFileID(argv[0], argv[1], argv[2])
00738 elif len(argd) == 1:
00739 self.__fid = argd['fileID']
00740 elif len(argd) == 3:
00741 self.__fid = self.__computeFileID( argd['device'], argd['directory'], argd['fileNumber'] )
00742 else:
00743 raise SyntaxError( "Incorrect arguments for FswFileID constructor: argv=%s, argd=%d" % (str(argv), str(argd)) )
00744
00745 def __computeFileID(self, device, directory, filNum):
00746 """!\brief Compute the 32 bit FSW destination from component parts
00747 """
00748
00749
00750 if device & self.MASK_DEVICE != device:
00751 raise "Selected device number 0x%x is greater than the maximum of 0x7" % device
00752 if directory & self.MASK_DIRECTORY != directory:
00753 raise "Selected directory number 0x%x is greater than the maximum of 0x7F" % directory
00754 if directory not in FSW_DIR_RANGE + [ FSW_DIR_ROOT ]:
00755 raise "Selected directory number 0x%x not in allowed directory range of [0..6f, 7f]" % directory
00756 if filNum & self.MASK_FILENUM != filNum:
00757 raise "Selected file number 0x%x is greater than the maximum of 0x3fffff" % filNum
00758
00759 dest = (device << self.SHFT_DEVICE) + \
00760 (directory << self.SHFT_DIRECTORY) + \
00761 (filNum << self.SHFT_FILENUM)
00762 return dest
00763
00764 def id(self):
00765 """!\brief retrieve file ID
00766
00767 \return 32 bit file ID
00768 """
00769 return self.__fid
00770
00771 def device(self):
00772 """!\brief retrieve device
00773
00774 \return 3 bit device
00775 """
00776 return (self.__fid >> self.SHFT_DEVICE ) & self.MASK_DEVICE
00777
00778 def directory(self):
00779 """!\brief retrieve file ID
00780
00781 \return 7 bit directory
00782 """
00783 return (self.__fid >> self.SHFT_DIRECTORY ) & self.MASK_DIRECTORY
00784
00785 def fileNumber(self):
00786 """!\brief retrieve file ID
00787
00788 \return 22 bit file Number
00789 """
00790 return (self.__fid >> self.SHFT_FILENUM ) & self.MASK_FILENUM
00791
00792 def __str__(self):
00793 return '/%s/d%03d/f%07d' % \
00794 ( FSW_DEVICE_NAMES[self.device()], self.directory(), self.fileNumber())
00795
00796
00797 class FswDirectoryItem(object):
00798 """!\brief Representation of an item in an FSW directory
00799
00800 REVISIT: Make the members private and member functions?
00801 """
00802 __isdirTxt = [ '-', 'd' ]
00803 __roTxt = [ 'w', '-' ]
00804 def __init__(self, fileID, ro, size, isdir, time, unit, blocks):
00805 """!\ Constructor
00806
00807 \param fileID A FswFileID object
00808 \param ro file is ReadOnly flag (True/False)
00809 \param size File size in bytes
00810 \param isdir file is a directory flag (True/False)
00811 \param time File modification time in LAT epoch
00812 \param unit File unit (i.e. FSW_UNIT_SIU)
00813 \param blocks REVISIT:: file blocks, maybe unused?
00814 """
00815 self.id = fileID
00816 self.ro = ro
00817 self.size = size
00818 self.isdir = isdir
00819 self.time = time
00820 self.unit = unit
00821 self.blocks = blocks
00822 self.header = None
00823
00824 def dump(self, stream):
00825 """!\brief dump a directoryItem to a file descriptor.
00826
00827 \param stream Any file descriptor (ie. sys.stdout)
00828 """
00829 msg = ""
00830 msg += self.__isdirTxt[self.isdir]
00831 msg += 'r' # always readable
00832 msg += self.__roTxt[self.ro]
00833 msg += ' %4s' % FSW_UNIT_NAMES[self.unit]
00834 msg += ' %10d' % self.size
00835 try:
00836 msg += ' %s' % utcfromtimestamp(int(self.time), 0).ctime()
00837 except:
00838 msg += ' %s' % utcfromtimestamp(0, 0).ctime()
00839 strid = str(self.id)
00840 if self.isdir: strid = strid[:-8]
00841 msg += ' %s' % strid
00842 print >> stream, msg
00843
00844
00845 class FswDirectory(object):
00846 """!\brief Representation of a FSW directory
00847
00848 """
00849 def __init__(self, dirID):
00850 """!\ Constructor
00851
00852 \param dirID A FswFileID object
00853 """
00854 self.__id = dirID
00855 self.__files = []
00856
00857 def addItem(self, f):
00858 """!\brief Add a file to this representation
00859
00860 \param f An FswDirectoryItem
00861 """
00862 if f not in self.__files:
00863 self.__files.append(f)
00864
00865 def files(self):
00866 """!\brief return a list of all files in this directory rep
00867 """
00868 return self.__files
00869
00870 def id(self):
00871 """!\brief retrieve file ID
00872
00873 \return a FswFileID object
00874 """
00875 return self.__id
00876
00877 def setId(self, id):
00878 """!\brief set the ID for this directory
00879
00880 \param id A FswFileID object
00881 """
00882 self.__id = id
00883
00884 def dump(self, stream):
00885 """!\brief dump a directory to a file descriptor
00886
00887 \param stream Any file descriptor (ie. sys.stdout)
00888 """
00889 msg = '/%s/d%03d' % ( FSW_DEVICE_NAMES[self.id().device()], self.id().directory())
00890 print >> stream, msg
00891 for item in self.__files:
00892 item.dump(stream)
00893
00894 def addFmxHeader(inFile, doCompress=False, preCompressed=False, name=None,
00895 type=None, key=None, timestamp=None):
00896 """!\brief Add an fmx header to a file. compressing on the fly if requested
00897
00898 \param inFile An FswFile object
00899 \param doCompress True/False to compress on fly/not
00900 \param preCompressed True/False if already compressed
00901 \param name
00902 \param type
00903 \param key
00904 \param timestamp
00905
00906 \return An FswFile object with proper headers for upload
00907 """
00908 if not FILETOOL_HDR_ALLOW:
00909 raise RuntimeError('Adding an FMX header is not possible on non-unix systems')
00910
00911 hdrCmd = FSW_ADD_HEADER_CMD
00912 if hasattr(inFile, 'name'):
00913 rawFile = inFile
00914 else:
00915 rawFile = tempfile.NamedTemporaryFile(mode='w+b')
00916 inFile.write(rawFile.file)
00917 hdrFile = tempfile.NamedTemporaryFile(mode='w+b')
00918
00919
00920 if doCompress:
00921
00922 cmpFile = tempfile.NamedTemporaryFile(mode='w+b')
00923
00924 cmd = FSW_COMPRESS_CMD
00925 cmd += ' %s' % rawFile.name
00926 cmd += ' %s' % cmpFile.name
00927 rc = os.system(cmd)
00928 rawFile = cmpFile
00929 if doCompress or preCompressed:
00930 hdrCmd += ' -c'
00931
00932
00933 if name is not None:
00934 hdrCmd += ' -n=%s' % name
00935 if type is not None:
00936 hdrCmd += ' -t=%s' % str(type)
00937 if key is not None:
00938 hdrCmd += ' -k=%s' % str(key)
00939 if timestamp is not None:
00940 hdrCmd += ' -s=%s' % str(timestamp)
00941
00942 hdrCmd += ' %s' % rawFile.name
00943 hdrCmd += ' %s' % hdrFile.name
00944 rc = os.system(hdrCmd)
00945
00946 retFile = FswFileFromDisk(inFile.fileID(), hdrFile.name)
00947
00948 return retFile
00949
00950