Module data_recording
[hide private]
[frames] | no frames]

Source Code for Module data_recording

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2006 Joe Pham <djpham@bitpim.org> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: data_recording.py 4624 2008-06-30 03:55:35Z djpham $ 
  9   
 10  """ 
 11  Handle data recording stuff 
 12  """ 
 13   
 14  # System modules 
 15  import cPickle 
 16  import struct 
 17  import threading 
 18  import time 
 19   
 20  # wx modules 
 21   
 22  # BitPim modules 
 23  import common 
 24  import pubsub 
 25   
 26  # constants 
 27  DR_Version=(0, 0, 1, 0) # 00.10 
 28  DR_Signature='BitPimDR' 
 29  DR_Rec_Marker='<-->' 
 30  DR_Type_All=0xff 
 31  DR_Type_Note=0x01 
 32  DR_Type_Write=0x02 
 33  DR_Type_Read=0x04 
 34  DR_Type_Read_ATResponse=0x08 
 35  DR_Type_Read_Some=0x10 
 36  DR_Type_Read_Until=0x20 
 37  DR_Type_Data=0x40 
 38  DR_Type_Name={ 
 39      DR_Type_Note: 'Note', 
 40      DR_Type_Write: 'Write', 
 41      DR_Type_Read: 'Read', 
 42      DR_Type_Read_ATResponse: 'Read ATResponse', 
 43      DR_Type_Read_Some: 'Read Some', 
 44      DR_Type_Read_Until: 'Read Until', 
 45      DR_Type_Data: 'Data', 
 46      } 
 47   
 48  # exceptions 
49 -class DataRecordingError(Exception):
50 - def __init__(self, value):
51 Exception.__init__(self, value)
52 53 # global varaibales 54 DR_On=False 55 DR_Play=False 56 _the_recorder=None 57 _the_player=None 58 59 # public routines 60
61 -def record_to_file(file_name, append=False):
62 "start a data recording session into the specified file" 63 global DR_On, _the_recorder 64 if DR_On and _the_recorder: 65 _the_recorder.stop() 66 _rec=DR_Rec_File(file_name, append) 67 _rec.start() 68 pubsub.publish(pubsub.DR_RECORD, data=_rec)
69
70 -def playback_from_file(file_name):
71 "start a playback session from the specified file" 72 global DR_Play, _the_player 73 if DR_Play and _the_player: 74 _the_player.stop() 75 _player=DR_Read_File(file_name) 76 _player.start() 77 pubsub.publish(pubsub.DR_PLAY, data=_player)
78
79 -def stop():
80 "stop a recording and/or playback session" 81 global DR_Play, DR_On, _the_recorder, _the_player 82 if DR_On and _the_recorder: 83 _the_recorder.stop() 84 if DR_Play and _the_player: 85 _the_player.stop() 86 pubsub.publish(pubsub.DR_STOP)
87
88 -def register(start_recording=None, start_playback=None, stop=None):
89 if start_recording: 90 pubsub.subscribe(start_recording, pubsub.DR_RECORD) 91 if start_playback: 92 pubsub.subscribe(start_playback, pubsub.DR_PLAY) 93 if stop: 94 pubsub.subscribe(stop, pubsub.DR_STOP)
95
96 -def unregister(start_recording=None, start_playback=None, stop=None):
97 if start_recording: 98 pubsub.unsubscribe(start_recording) 99 if start_playback: 100 pubsub.unsubscribe(start_playback) 101 if stop: 102 pubsub.unsubscribe(stop)
103
104 -def get_data(data_type):
105 global DR_Play, _the_player 106 # return the next data packet of the type data_type 107 if DR_Play and _the_player: 108 return _the_player.get_data(data_type) 109 raise DataRecordingError('Data Playback not active')
110
111 -def get_headers():
112 # return a list of headers used for setting the start point 113 global DR_Play, _the_player 114 if DR_Play and _the_player: 115 return _the_player.get_headers() 116 raise DataRecordingError('Data Playback not active')
117
118 -def set_start(start):
119 # set/reset the start point of the recording file 120 global DR_Play, _the_player 121 if DR_Play and _the_player: 122 _the_player.set_start(start) 123 else: 124 raise DataRecordingError('Data Playback not active')
125
126 -def record(dr_type, dr_data, dr_class=None):
127 global DR_On, _the_recorder 128 if DR_On and _the_recorder: 129 _the_recorder.record(dr_type, dr_data, dr_class) 130 elif __debug__: 131 raise DataRecordingError('Data Recording not active')
132
133 -def filename():
134 "return the current file name being used for recording or playback" 135 if _the_recorder: 136 return _the_recorder._file_name 137 elif _the_player: 138 return _the_player._file_name
139 140 #-------------------------------------------------------------------------------
141 -class DR_Record(object):
142 - def __init__(self, dr_type, dr_data, klass=None):
143 self._type=dr_type 144 self._data=dr_data 145 self._time=time.time() 146 if klass: 147 try: 148 self._class_module=klass.__module__ 149 self._class_name=klass.__name__ 150 except: 151 klass=klass.__class__ 152 self._class_module=klass.__module__ 153 self._class_name=klass.__name__ 154 else: 155 self._class_module=None 156 self._class_name=None
157
158 - def get(self):
159 return self._data
160 - def set(self, data):
161 self._data=data
162 - def __repr__(self):
163 # return a string rep suitable for log, protocol log, and analyzer 164 # display 165 t=time.localtime(self._time) 166 _s="%d:%02d:%02d.%03d " % (t[3], t[4], t[5], 167 int((self._time-int(self._time))*1000)) 168 if self._type==DR_Type_Note: 169 _s+=self._data 170 else: 171 # data 172 _s+=" %s - %d bytes\n" % (DR_Type_Name.get(self._type, 'Data'), 173 len(self._data)) 174 if self._class_module and self._class_name: 175 _s+="<#! %s.%s !#>\n" % (self._class_module, self._class_name) 176 _s+=common.datatohexstring(self._data) 177 _s+='\n' 178 return _s
179 - def summary(self):
180 # return a summary string of this record 181 global DR_Type_Name 182 t=time.localtime(self._time) 183 _s="%d:%02d:%02d.%03d " % (t[3], t[4], t[5], 184 int((self._time-int(self._time))*1000)) 185 if self._type==DR_Type_Note: 186 _s+=self._data 187 else: 188 _s+=DR_Type_Name.get(self._type, '<Unknown>') 189 if len(_s)>80: 190 _s=_s[:75]+'<...>' 191 return _s
192 193 #-------------------------------------------------------------------------------
194 -class DR_File(object):
195 - def __init__(self, file_name):
196 self._file_name=file_name 197 self._file=None 198 self._valid=False
199
200 - def _check_header(self):
201 # check to ensure that this file has the right header 202 try: 203 return file(self._file_name, 'rb').read(len(DR_Signature))==DR_Signature 204 except IOError: 205 return False 206 except: 207 if __debug__: 208 raise 209 return False
210
211 - def stop(self):
212 global DR_On 213 self._file.close() 214 DR_On=False
215 216 #-------------------------------------------------------------------------------
217 -class DR_Rec_File(DR_File):
218 - def __init__(self, file_name, append=False):
219 super(DR_Rec_File, self).__init__(file_name) 220 self._pause=None 221 if not append: 222 self._file=file(self._file_name, 'wb') 223 self._write_header() 224 self._valid=True 225 else: 226 if self._check_header(): 227 self._file=file(self._file_name, 'ab') 228 self._valid=True 229 else: 230 self._valid=False
231
232 - def _write_header(self):
233 # write the header to this file 234 self._file.write(DR_Signature) 235 _s='' 236 for e in DR_Version: 237 _s+=struct.pack('B', e) 238 self._file.write(_s)
239
240 - def can_record(self):
241 return bool(self._valid and self._file)
242 243
244 - def record(self, dr_type, dr_data, dr_class=None):
245 if self._pause and (self._pause & dr_type): 246 # not recording this type 247 return 248 if self._file: 249 _t=threading.Thread(target=self._write_record, 250 args=(dr_type, dr_data, dr_class)) 251 _t.start()
252
253 - def _write_record(self, dr_type, dr_data, dr_class=None):
254 _rec=DR_Record(dr_type, dr_data, dr_class) 255 _s=cPickle.dumps(_rec) 256 self._file.write(DR_Rec_Marker+struct.pack('<L', len(_s))+_s)
257
258 - def stop(self):
259 global DR_On, _the_recorder 260 self._file.close() 261 self._file=None 262 self._valid=False 263 DR_On=False 264 _the_recorder=None
265
266 - def start(self):
267 global DR_On, _the_recorder 268 if self._file is None and self._file_name: 269 self._file=file(self._file_name, 'ab') 270 self._valid=True 271 DR_On=True 272 _the_recorder=self
273
274 - def pause(self, data_type=DR_Type_All):
275 self._pause_type=data_type
276 - def unpause(self):
277 self._pause=None
278 279 #-------------------------------------------------------------------------------
280 -class DR_Read_File(DR_File):
281 - def __init__(self, file_name):
282 super(DR_Read_File, self).__init__(file_name) 283 if self._check_header(): 284 self._valid=True 285 self._file=file(self._file_name, 'rb') 286 else: 287 self._valid=False 288 self._data=[] 289 self._read_data() 290 self._start_index=0 291 self._end_index=len(self._data) 292 self._current_index=0
293
294 - def _read_rec(self):
295 # read one DR record and return 296 _marker=self._file.read(len(DR_Rec_Marker)) 297 if _marker!=DR_Rec_Marker: 298 # marker not found 299 return None 300 try: 301 _slen=self._file.read(struct.calcsize('L')) 302 _data_len=struct.unpack('<L', _slen)[0] 303 _sdata=self._file.read(_data_len) 304 return cPickle.loads(_sdata) 305 except (MemoryError, cPickle.UnpicklingError): 306 return None 307 except: 308 if __debug__: 309 raise 310 return None
311
312 - def _read_data(self):
313 # read from the file and recontruct the data 314 # first,get pass the header 315 self._file.seek(len(DR_Signature)+len(DR_Version)) 316 _rec=self._read_rec() 317 while _rec: 318 self._data.append(_rec) 319 _rec=self._read_rec() 320 self._file.close()
321
322 - def get_string_data(self):
323 # return all the data as a big string for display purposes 324 _s='' 325 for e in self._data: 326 _s+=`e` 327 return _s
328 - def get_headers(self):
329 # return a list of headers 330 return [x.summary() for x in self._data]
331
332 - def set_start(self, start_idx):
333 self._start_index=start_idx 334 self._current_index=start_idx
335
336 - def start(self):
337 global DR_Play, _the_player 338 self._current_index=self._start_index 339 DR_Play=True 340 _the_player=self
341
342 - def stop(self):
343 global DR_Play, _the_player 344 DR_Play=False 345 _the_player=None
346
347 - def get_data(self, data_type):
348 # return the data of the type 'data_type' 349 if self._current_index>=self._end_index: 350 # end of data 351 raise DataRecordingError('No more data available for playback') 352 _idx=self._current_index 353 for i,e in enumerate(self._data[_idx:]): 354 if e._type==data_type: 355 self._current_index+=i+1 356 return e.get() 357 # no such data 358 raise DataRecordingError('Failed to find playback data type')
359