0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2006 Joe Pham <djpham@bitpim.org> 0004 ### 0005 ### This program is free software; you can redistribute it and/or modify 0006 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0007 ### 0008 ### $Id: data_recording.py 4624 2008-06-30 03:55:35Z djpham $ 0009 0010 """ 0011 Handle data recording stuff 0012 """ 0013 0014 # System modules 0015 import cPickle 0016 import struct 0017 import threading 0018 import time 0019 0020 # wx modules 0021 0022 # BitPim modules 0023 import common 0024 import pubsub 0025 0026 # constants 0027 DR_Version=(0, 0, 1, 0) # 00.10 0028 DR_Signature='BitPimDR' 0029 DR_Rec_Marker='<-->' 0030 DR_Type_All=0xff 0031 DR_Type_Note=0x01 0032 DR_Type_Write=0x02 0033 DR_Type_Read=0x04 0034 DR_Type_Read_ATResponse=0x08 0035 DR_Type_Read_Some=0x10 0036 DR_Type_Read_Until=0x20 0037 DR_Type_Data=0x40 0038 DR_Type_Name={ 0039 DR_Type_Note: 'Note', 0040 DR_Type_Write: 'Write', 0041 DR_Type_Read: 'Read', 0042 DR_Type_Read_ATResponse: 'Read ATResponse', 0043 DR_Type_Read_Some: 'Read Some', 0044 DR_Type_Read_Until: 'Read Until', 0045 DR_Type_Data: 'Data', 0046 } 0047 0048 # exceptions 0049 class DataRecordingError(Exception): 0050 def __init__(self, value): 0051 Exception.__init__(self, value) 0052 0053 # global varaibales 0054 DR_On=False 0055 DR_Play=False 0056 _the_recorder=None 0057 _the_player=None 0058 0059 # public routines 0060 0061 def record_to_file(file_name, append=False): 0062 "start a data recording session into the specified file" 0063 global DR_On, _the_recorder 0064 if DR_On and _the_recorder: 0065 _the_recorder.stop() 0066 _rec=DR_Rec_File(file_name, append) 0067 _rec.start() 0068 pubsub.publish(pubsub.DR_RECORD, data=_rec) 0069 0070 def playback_from_file(file_name): 0071 "start a playback session from the specified file" 0072 global DR_Play, _the_player 0073 if DR_Play and _the_player: 0074 _the_player.stop() 0075 _player=DR_Read_File(file_name) 0076 _player.start() 0077 pubsub.publish(pubsub.DR_PLAY, data=_player) 0078 0079 def stop(): 0080 "stop a recording and/or playback session" 0081 global DR_Play, DR_On, _the_recorder, _the_player 0082 if DR_On and _the_recorder: 0083 _the_recorder.stop() 0084 if DR_Play and _the_player: 0085 _the_player.stop() 0086 pubsub.publish(pubsub.DR_STOP) 0087 0088 def register(start_recording=None, start_playback=None, stop=None): 0089 if start_recording: 0090 pubsub.subscribe(start_recording, pubsub.DR_RECORD) 0091 if start_playback: 0092 pubsub.subscribe(start_playback, pubsub.DR_PLAY) 0093 if stop: 0094 pubsub.subscribe(stop, pubsub.DR_STOP) 0095 0096 def unregister(start_recording=None, start_playback=None, stop=None): 0097 if start_recording: 0098 pubsub.unsubscribe(start_recording) 0099 if start_playback: 0100 pubsub.unsubscribe(start_playback) 0101 if stop: 0102 pubsub.unsubscribe(stop) 0103 0104 def get_data(data_type): 0105 global DR_Play, _the_player 0106 # return the next data packet of the type data_type 0107 if DR_Play and _the_player: 0108 return _the_player.get_data(data_type) 0109 raise DataRecordingError('Data Playback not active') 0110 0111 def get_headers(): 0112 # return a list of headers used for setting the start point 0113 global DR_Play, _the_player 0114 if DR_Play and _the_player: 0115 return _the_player.get_headers() 0116 raise DataRecordingError('Data Playback not active') 0117 0118 def set_start(start): 0119 # set/reset the start point of the recording file 0120 global DR_Play, _the_player 0121 if DR_Play and _the_player: 0122 _the_player.set_start(start) 0123 else: 0124 raise DataRecordingError('Data Playback not active') 0125 0126 def record(dr_type, dr_data, dr_class=None): 0127 global DR_On, _the_recorder 0128 if DR_On and _the_recorder: 0129 _the_recorder.record(dr_type, dr_data, dr_class) 0130 elif __debug__: 0131 raise DataRecordingError('Data Recording not active') 0132 0133 def filename(): 0134 "return the current file name being used for recording or playback" 0135 if _the_recorder: 0136 return _the_recorder._file_name 0137 elif _the_player: 0138 return _the_player._file_name 0139 0140 #------------------------------------------------------------------------------- 0141 class DR_Record(object): 0142 def __init__(self, dr_type, dr_data, klass=None): 0143 self._type=dr_type 0144 self._data=dr_data 0145 self._time=time.time() 0146 if klass: 0147 try: 0148 self._class_module=klass.__module__ 0149 self._class_name=klass.__name__ 0150 except: 0151 klass=klass.__class__ 0152 self._class_module=klass.__module__ 0153 self._class_name=klass.__name__ 0154 else: 0155 self._class_module=None 0156 self._class_name=None 0157 0158 def get(self): 0159 return self._data 0160 def set(self, data): 0161 self._data=data 0162 def __repr__(self): 0163 # return a string rep suitable for log, protocol log, and analyzer 0164 # display 0165 t=time.localtime(self._time) 0166 _s="%d:%02d:%02d.%03d " % (t[3], t[4], t[5], 0167 int((self._time-int(self._time))*1000)) 0168 if self._type==DR_Type_Note: 0169 _s+=self._data 0170 else: 0171 # data 0172 _s+=" %s - %d bytes\n" % (DR_Type_Name.get(self._type, 'Data'), 0173 len(self._data)) 0174 if self._class_module and self._class_name: 0175 _s+="<#! %s.%s !#>\n" % (self._class_module, self._class_name) 0176 _s+=common.datatohexstring(self._data) 0177 _s+='\n' 0178 return _s 0179 def summary(self): 0180 # return a summary string of this record 0181 global DR_Type_Name 0182 t=time.localtime(self._time) 0183 _s="%d:%02d:%02d.%03d " % (t[3], t[4], t[5], 0184 int((self._time-int(self._time))*1000)) 0185 if self._type==DR_Type_Note: 0186 _s+=self._data 0187 else: 0188 _s+=DR_Type_Name.get(self._type, '<Unknown>') 0189 if len(_s)>80: 0190 _s=_s[:75]+'<...>' 0191 return _s 0192 0193 #------------------------------------------------------------------------------- 0194 class DR_File(object): 0195 def __init__(self, file_name): 0196 self._file_name=file_name 0197 self._file=None 0198 self._valid=False 0199 0200 def _check_header(self): 0201 # check to ensure that this file has the right header 0202 try: 0203 return file(self._file_name, 'rb').read(len(DR_Signature))==DR_Signature 0204 except IOError: 0205 return False 0206 except: 0207 if __debug__: 0208 raise 0209 return False 0210 0211 def stop(self): 0212 global DR_On 0213 self._file.close() 0214 DR_On=False 0215 0216 #------------------------------------------------------------------------------- 0217 class DR_Rec_File(DR_File): 0218 def __init__(self, file_name, append=False): 0219 super(DR_Rec_File, self).__init__(file_name) 0220 self._pause=None 0221 if not append: 0222 self._file=file(self._file_name, 'wb') 0223 self._write_header() 0224 self._valid=True 0225 else: 0226 if self._check_header(): 0227 self._file=file(self._file_name, 'ab') 0228 self._valid=True 0229 else: 0230 self._valid=False 0231 0232 def _write_header(self): 0233 # write the header to this file 0234 self._file.write(DR_Signature) 0235 _s='' 0236 for e in DR_Version: 0237 _s+=struct.pack('B', e) 0238 self._file.write(_s) 0239 0240 def can_record(self): 0241 return bool(self._valid and self._file) 0242 0243 0244 def record(self, dr_type, dr_data, dr_class=None): 0245 if self._pause and (self._pause & dr_type): 0246 # not recording this type 0247 return 0248 if self._file: 0249 _t=threading.Thread(target=self._write_record, 0250 args=(dr_type, dr_data, dr_class)) 0251 _t.start() 0252 0253 def _write_record(self, dr_type, dr_data, dr_class=None): 0254 _rec=DR_Record(dr_type, dr_data, dr_class) 0255 _s=cPickle.dumps(_rec) 0256 self._file.write(DR_Rec_Marker+struct.pack('<L', len(_s))+_s) 0257 0258 def stop(self): 0259 global DR_On, _the_recorder 0260 self._file.close() 0261 self._file=None 0262 self._valid=False 0263 DR_On=False 0264 _the_recorder=None 0265 0266 def start(self): 0267 global DR_On, _the_recorder 0268 if self._file is None and self._file_name: 0269 self._file=file(self._file_name, 'ab') 0270 self._valid=True 0271 DR_On=True 0272 _the_recorder=self 0273 0274 def pause(self, data_type=DR_Type_All): 0275 self._pause_type=data_type 0276 def unpause(self): 0277 self._pause=None 0278 0279 #------------------------------------------------------------------------------- 0280 class DR_Read_File(DR_File): 0281 def __init__(self, file_name): 0282 super(DR_Read_File, self).__init__(file_name) 0283 if self._check_header(): 0284 self._valid=True 0285 self._file=file(self._file_name, 'rb') 0286 else: 0287 self._valid=False 0288 self._data=[] 0289 self._read_data() 0290 self._start_index=0 0291 self._end_index=len(self._data) 0292 self._current_index=0 0293 0294 def _read_rec(self): 0295 # read one DR record and return 0296 _marker=self._file.read(len(DR_Rec_Marker)) 0297 if _marker!=DR_Rec_Marker: 0298 # marker not found 0299 return None 0300 try: 0301 _slen=self._file.read(struct.calcsize('L')) 0302 _data_len=struct.unpack('<L', _slen)[0] 0303 _sdata=self._file.read(_data_len) 0304 return cPickle.loads(_sdata) 0305 except (MemoryError, cPickle.UnpicklingError): 0306 return None 0307 except: 0308 if __debug__: 0309 raise 0310 return None 0311 0312 def _read_data(self): 0313 # read from the file and recontruct the data 0314 # first,get pass the header 0315 self._file.seek(len(DR_Signature)+len(DR_Version)) 0316 _rec=self._read_rec() 0317 while _rec: 0318 self._data.append(_rec) 0319 _rec=self._read_rec() 0320 self._file.close() 0321 0322 def get_string_data(self): 0323 # return all the data as a big string for display purposes 0324 _s='' 0325 for e in self._data: 0326 _s+=`e` 0327 return _s 0328 def get_headers(self): 0329 # return a list of headers 0330 return [x.summary() for x in self._data] 0331 0332 def set_start(self, start_idx): 0333 self._start_index=start_idx 0334 self._current_index=start_idx 0335 0336 def start(self): 0337 global DR_Play, _the_player 0338 self._current_index=self._start_index 0339 DR_Play=True 0340 _the_player=self 0341 0342 def stop(self): 0343 global DR_Play, _the_player 0344 DR_Play=False 0345 _the_player=None 0346 0347 def get_data(self, data_type): 0348 # return the data of the type 'data_type' 0349 if self._current_index>=self._end_index: 0350 # end of data 0351 raise DataRecordingError('No more data available for playback') 0352 _idx=self._current_index 0353 for i,e in enumerate(self._data[_idx:]): 0354 if e._type==data_type: 0355 self._current_index+=i+1 0356 return e.get() 0357 # no such data 0358 raise DataRecordingError('Failed to find playback data type') 0359
Generated by PyXR 0.9.4