CtSaving.h 15.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//###########################################################################
// This file is part of LImA, a Library for Image Acquisition
//
// Copyright (C) : 2009-2011
// European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// FRANCE
//
// This is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//###########################################################################
papillon's avatar
 
papillon committed
22
23
24
#ifndef CTSAVING_H
#define CTSAVING_H

25
26
27
28
#include <map>
#include <list>
#include <string>
#include <fstream>
Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
29
#include <ios>
papillon's avatar
 
papillon committed
30

31
#include "LimaCompatibility.h"
32
#include "ThreadUtils.h"
33
#include "CtControl.h"
34
#include "HwSavingCtrlObj.h"
35

Sebastien Petitdemange's avatar
Sebastien Petitdemange committed
36
struct Data;
37
class TaskEventCallback;
38
class SinkTaskBase;
papillon's avatar
 
papillon committed
39

40
namespace lima {
41
42
43
44
  /** @brief Saving management
   *
   * With this class you manage the image saving in different format
   */
45
  class LIMACORE_API CtSaving 
seb's avatar
seb committed
46
47
48
  {
    DEB_CLASS_NAMESPC(DebModControl,"Saving","Control");

49
50
51
52
    friend class CtControl;
  public:
    CtSaving(CtControl&);
    ~CtSaving();
53
54
55
56
57
58
59

    enum ManagedMode
      {
	Software,		///< Saving will be managed by Lima Core (Control)
	Hardware		///< Saving will be managed by Hardware or Camera SDK
      };

seb's avatar
seb committed
60
61
    enum FileFormat 
      {
62
	HARDWARE_SPECIFIC = -1,	///< extended hardware format (ADSC,MarCCD...) @see setHardwareFormat
63
64
65
66
	RAW,			///< Raw format (no header)
	EDF,			///< EDF format (Esrf Data Format)
	CBFFormat,		///< CBF format
	NXS,			///< Soleil Nexus format
67
	FITS,			///< Flexible Image Transport Layer (NOST)
68
	EDFGZ,			///< EDF format with gzip compression
seb's avatar
seb committed
69
70
71
72
      };

    enum SavingMode 
      {
73
74
75
	Manual,			///< No automatic saving, you should call CtSaving::writeFrame
	AutoFrame,		///< Save a frame just after it acquisition
	AutoHeader,		///< Save the frame if header and the data of the frame is available 
seb's avatar
seb committed
76
      };
papillon's avatar
 
papillon committed
77
	
seb's avatar
seb committed
78
79
    enum OverwritePolicy 
      {
80
81
82
	Abort,			///< Abort acquisition if file already exist
	Overwrite,		///< Overwrite old files
	Append,			///< Append new data at the end of already existing files
seb's avatar
seb committed
83
84
      };	

85
    struct LIMACORE_API Parameters 
86
    {
87
88
89
      std::string directory;	///< base path where the files will be saved
      std::string prefix;	///< prefix of the filename
      std::string suffix;	///< suffix of the filename
90
      ImageType   imageType;
91
92
93
94
95
96
      long nextNumber;		///< next file number
      FileFormat fileFormat;	///< the saving format (EDF,CBF...)
      SavingMode savingMode;	///< saving mode (automatic,manual...)
      OverwritePolicy overwritePolicy; ///< how you the saving react it find existing filename
      std::string indexFormat;	///< ie: %.4d if you want 4 digits
      long framesPerFile;	///< the number of images save in one files
97
98
99
100
      long nbframes;
      
      Parameters();
      void checkValid() const;
101
    };
102
    
103
104
105
    typedef std::pair<std::string, std::string> HeaderValue;
    typedef std::map<std::string,std::string> HeaderMap;
    typedef std::map<long,Data> FrameMap;
papillon's avatar
 
papillon committed
106

107
    // --- file parameters
papillon's avatar
 
papillon committed
108

109
110
    void setParameters(const Parameters &pars, int stream_idx=0);
    void getParameters(Parameters& pars, int stream_idx=0) const;
papillon's avatar
 
papillon committed
111

112
113
    void setDirectory(const std::string &directory, int stream_idx=0);
    void getDirectory(std::string& directory, int stream_idx=0) const;
papillon's avatar
 
papillon committed
114

115
116
    void setPrefix(const std::string &prefix, int stream_idx=0);
    void getPrefix(std::string& prefix, int stream_idx=0) const;
papillon's avatar
 
papillon committed
117

118
119
120
121
122
    void setSuffix(const std::string &suffix, int stream_idx=0);
    void getSuffix(std::string& suffix, int stream_idx=0) const;
    
    void setNextNumber(long number, int stream_idx=0);
    void getNextNumber(long& number, int stream_idx=0) const;
papillon's avatar
 
papillon committed
123

124
125
    void setFormat(FileFormat format, int stream_idx=0);
    void getFormat(FileFormat& format, int stream_idx=0) const;
papillon's avatar
 
papillon committed
126

127
128
129
    void getHardwareFormatList(std::list<std::string> &format_list) const;
    void setHardwareFormat(const std::string &format);
    void getHardwareFormat(std::string &format) const;
130
    // --- saving modes
papillon's avatar
 
papillon committed
131

132
133
    void setSavingMode(SavingMode mode);
    void getSavingMode(SavingMode& mode) const;
papillon's avatar
 
papillon committed
134

135
136
    bool hasAutoSaveMode()
    { return m_stream[0]->hasAutoSaveMode(); }
papillon's avatar
 
papillon committed
137

138
139
    void setOverwritePolicy(OverwritePolicy policy, int stream_idx=0);
    void getOverwritePolicy(OverwritePolicy& policy, int stream_idx=0) const;
papillon's avatar
 
papillon committed
140

141
142
143
144
    void setFramesPerFile(unsigned long frames_per_file, int stream_idx=0);
    void getFramePerFile(unsigned long& frames_per_file, 
			 int stream_idx=0) const;
    
145
146
    void setManagedMode(ManagedMode mode);
    void getManagedMode(ManagedMode &mode) const;
147
    // --- common headers
papillon's avatar
 
papillon committed
148

149
150
151
152
153
    void resetCommonHeader();
    void setCommonHeader(const HeaderMap &header);
    void updateCommonHeader(const HeaderMap &header);
    void getCommonHeader(HeaderMap& header) const;
    void addToCommonHeader(const HeaderValue &value);
papillon's avatar
   
papillon committed
154

155
    // --- frame headers
papillon's avatar
   
papillon committed
156

157
158
159
    void updateFrameHeader(long frame_nr, const HeaderMap &header);
    void addToFrameHeader(long frame_nr,const HeaderValue &value);
    void validateFrameHeader(long frame_nr);
160
161
    void getFrameHeader(long frame_nr, HeaderMap& header) const;
    void takeFrameHeader(long frame_nr, HeaderMap& header);
papillon's avatar
   
papillon committed
162

163
164
    void removeFrameHeader(long frame_nr);
    void removeAllFrameHeaders();
papillon's avatar
   
papillon committed
165

166
    void frameReady(Data&);
167
    void resetLastFrameNb();
papillon's avatar
   
papillon committed
168

169
170
    void setEndCallback(TaskEventCallback *);

171
172
173
174
175
176
    // --- internal common header
    void resetInternalCommonHeader();
    void addToInternalCommonHeader(const HeaderValue& value);
    template<class T>
    void addToInternalCommonHeader(const std::string &key,
				   const T&);
seb's avatar
Saving:    
seb committed
177
178
    // --- statistic

179
180
    void getWriteTimeStatistic(std::list<double>&, int stream_idx=0) const;
    void setStatisticHistorySize(int aSize, int stream_idx=0);
seb's avatar
Saving:    
seb committed
181
182
183
184

    // --- misc

    void clear();
Alejandro Homs Puron's avatar
Core:    
Alejandro Homs Puron committed
185
    //                  frame_nr == -1 => last frame
186
    void writeFrame(int frame_nr = -1, int nb_frames = 1,bool synchronous = true); 
Alejandro Homs Puron's avatar
Core:    
Alejandro Homs Puron committed
187

188

189
190
191
192
193
    void setStreamActive(int stream_idx, bool  active);
    void getStreamActive(int stream_idx, bool& active) const;

    class Stream;

194
    class LIMACORE_API SaveContainer
195
    {
seb's avatar
seb committed
196
197
      DEB_CLASS_NAMESPC(DebModControl,"Saving Container","Control");
    public:
198
      SaveContainer(Stream& stream);
seb's avatar
seb committed
199
      virtual ~SaveContainer();
200
      
seb's avatar
seb committed
201
202
203
204
205
      void open(const CtSaving::Parameters&);
      void close();
      void writeFile(Data&,CtSaving::HeaderMap &);
      void setStatisticSize(int aSize);
      void getStatistic(std::list<double>&) const;
206
      void getParameters(CtSaving::Parameters&) const;
seb's avatar
seb committed
207
      void clear();
208
209
210
211
212
213
      
      /** @brief should return true if container has compression or
       *  havy task to do before saving
       *  if return is true, getCompressionTask should return a Task
       * @see getCompressionTask
       */
214
      virtual bool needParallelCompression() const {return false;}
215
      /** @brief get a new compression task at each call.
216
217
       * this methode is not call if needParallelCompression return false
       *  @see needParallelCompression
218
219
       */
      virtual SinkTaskBase* getCompressionTask(const CtSaving::HeaderMap&) {return NULL;}
seb's avatar
seb committed
220
221
222

    protected:
      virtual bool _open(const std::string &filename,
223
			 std::ios_base::openmode flags) = 0;
seb's avatar
seb committed
224
225
226
227
      virtual void _close() = 0;
      virtual void _writeFile(Data &data,
			      CtSaving::HeaderMap &aHeader,
			      FileFormat) = 0;
228
      virtual void _clear() {};
seb's avatar
seb committed
229
230

      int			m_written_frames;
231
      Stream			&m_stream;
232
    private:
seb's avatar
seb committed
233
234
235
236
237
238
239
      std::list<double>		m_statistic_list;
      int			m_statistic_size;
      mutable Cond		m_cond;
      bool			m_file_opened;
    };
    friend class SaveContainer;

240
241
242
243
244
245
246
247
    enum ParameterType {
      Acq, Cache, Auto, 
    };

    enum TaskType {
      Save, Compression,
    };

248
    class LIMACORE_API Stream 
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
    {
      DEB_CLASS(DebModControl, "CtSaving::Stream");

    public:
      Stream(CtSaving& aCtSaving, int idx);
      ~Stream();

      int getIndex() const
      { return m_idx; }

      const Parameters& getParameters(ParameterType type) const;
      Parameters& getParameters(ParameterType type);
      void setParameters(const Parameters& pars);
      void updateParameters();

      void prepare();
      void createSaveContainer();
      void checkWriteAccess();
      
      bool needCompression()
      { return m_save_cnt->needParallelCompression(); }

      void setSavingError(CtControl::ErrorCode error)
      { m_saving._setSavingError(error); }

      SinkTaskBase *getTask(TaskType type, const HeaderMap& header);

      void compressionFinished(Data& data);
      void saveFinished(Data& data);
      int getNextNumber() const;

      bool isActive() const
      { return m_active; }
      void setActive(bool active);

      void writeFile(Data& data, HeaderMap& header);

      bool hasAutoSaveMode()
      { const Parameters& pars = getParameters(Cache);
	return pars.savingMode != Manual; 
      }

      void getStatistic(std::list<double>& stat_list) const
      { m_save_cnt->getStatistic(stat_list); }
      void setStatisticSize(int size) 
      { m_save_cnt->setStatisticSize(size); }

      void clear()
      { m_save_cnt->clear(); }

    private:
      class _SaveCBK;
      class _SaveTask;
      class _CompressionCBK;

      CtSaving&			m_saving;
      int			m_idx;

      SaveContainer 	       *m_save_cnt;
      _SaveCBK	 	       *m_saving_cbk;
      Parameters		m_pars;
      Parameters		m_reference_pars;
      Parameters		m_acquisition_pars;
      bool			m_pars_dirty_flag;
      bool			m_active;
      _CompressionCBK 	       *m_compression_cbk;
    };
    friend class Stream;

318
  private:
319
320
    class	_ManualBackgroundSaveTask;
    friend class _ManualBackgroundSaveTask;
321
322
    class	_NewFrameSaveCBK;
    friend class _NewFrameSaveCBK;
323
324
325
    typedef std::vector<SinkTaskBase *> TaskList;
    typedef std::map<long, long>	FrameCbkCountMap;
    typedef std::map<long, HeaderMap>	FrameHeaderMap;
326

327
    CtControl& 			m_ctrl;
328
329
330
331

    int				m_nb_stream;
    Stream		      **m_stream;

332
    HeaderMap			m_common_header;
333
    HeaderMap			m_internal_common_header;
334
    FrameHeaderMap		m_frame_headers;
335
336
337
338
339
    FrameMap			m_frame_datas;

    mutable Cond		m_cond;
    bool			m_ready_flag;
    long			m_last_frameid_saved;
340
341
342
343
    bool			m_need_compression;
    FrameCbkCountMap		m_nb_compression_cbk;
    int				m_nb_save_cbk;
    TaskEventCallback	       *m_end_cbk;
344
345
346
    bool			m_has_hwsaving;
    HwSavingCtrlObj*		m_hwsaving;
    _NewFrameSaveCBK*		m_new_frame_save_cbk;
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
    ManagedMode			m_managed_mode;	///< two option either harware (manage by SDK,hardware) or software (Lima core)
    std::string			m_specific_hardware_format;

      Stream& getStream(int stream_idx)
	{ bool stream_ok = (stream_idx >= 0) && (stream_idx < m_nb_stream);
	  return stream_ok ? *m_stream[stream_idx] : getStreamExc(stream_idx); }

      const Stream& getStream(int stream_idx) const
	{ bool stream_ok = (stream_idx >= 0) && (stream_idx < m_nb_stream);
	  return stream_ok ? *m_stream[stream_idx] : getStreamExc(stream_idx); }

      Stream& getStreamExc(int stream_idx) const;

      SavingMode getAcqSavingMode() const
      { return getStream(0).getParameters(Acq).savingMode; }

      ManagedMode getManagedMode() const
      { return m_managed_mode; }

      // --- from control
      void getSaveCounters(int& first_to_save, int& last_to_save)
      { AutoMutex lock(m_cond.mutex());
	first_to_save = last_to_save = -1;
	FrameMap::const_iterator it, end = m_frame_datas.end();
	for (it = m_frame_datas.begin(); it != end; ++it) {
	  if (it->first > last_to_save)
	    last_to_save = it->first;
	  if ((first_to_save == -1) || (it->first < first_to_save))
	    first_to_save = it->first;
	}
377
378
      }

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
      // --- internal call
      void _prepare();
      void _getCommonHeader(HeaderMap&);
      void _takeHeader(FrameHeaderMap::iterator&, HeaderMap& header,
		       bool keep_in_map);
      void _getTaskList(TaskType type, long frame_nr, const HeaderMap& header, 
			TaskList& task_list);
      void _postTaskList(Data&, const TaskList&);
      void _compressionFinished(Data&, Stream&);
      void _saveFinished(Data&, Stream&);
      void _setSavingError(CtControl::ErrorCode);
      void _updateParameters();
      void _synchronousSaving(Data&,HeaderMap&);
      bool _controlIsFault();
      bool _newFrameWrite(int);
      bool _checkHwFileFormat(const std::string&) const;
      void _ReadImage(Data&,int framenb);
seb's avatar
seb committed
396
  };
397

seb's avatar
seb committed
398
  inline std::ostream& operator<<(std::ostream &os,const CtSaving::Parameters &params)
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
    {
      const char *aFileFormatHumanPt;
      switch(params.fileFormat)
	{
	case CtSaving::EDF:
	  aFileFormatHumanPt = "EDF";break;
	case CtSaving::CBFFormat:
	  aFileFormatHumanPt = "CBF";break;
	case CtSaving::NXS:
	  aFileFormatHumanPt = "NXS";break;
	case CtSaving::FITS:
	  aFileFormatHumanPt = "FITS";break;
	case CtSaving::EDFGZ:
	  aFileFormatHumanPt = "EDF gzip";break;
	default:
	  aFileFormatHumanPt = "RAW";break;
	}

      const char *aSavingModeHumanPt;
      switch(params.savingMode)
	{
	case CtSaving::AutoFrame:
	  aSavingModeHumanPt = "Auto frame";break;
	case CtSaving::AutoHeader:
	  aSavingModeHumanPt = "Auto header";break;
	default: //	Manual
	  aSavingModeHumanPt = "Manual";break;
	}

      const char *anOverwritePolicyHumanPt;
      switch(params.overwritePolicy)
	{
	case CtSaving::Overwrite:
	  anOverwritePolicyHumanPt = "Overwrite";break;
	case CtSaving::Append:
	  anOverwritePolicyHumanPt = "Append";break;
	default:		// Abort
436
	  anOverwritePolicyHumanPt = "Abort";break;
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
	}

      os << "<"
	 << "directory=" << params.directory << ", "
	 << "prefix=" << params.prefix << ", "
	 << "suffix=" << params.suffix << ", "
	 << "nextNumber=" << params.nextNumber << ", "
	 << "fileFormat=" << params.fileFormat << "," << aFileFormatHumanPt << ", "
	 << "savingMode=" << params.savingMode << "," << aSavingModeHumanPt << ", "
	 << "overwritePolicy=" << params.overwritePolicy << "," << anOverwritePolicyHumanPt << ", "
	 << "framesPerFile=" << params.framesPerFile << ", "
	 << "nbframes=" << params.nbframes
	 << ">";
      return os;
    }
452

453
  inline bool operator ==(const CtSaving::Parameters& a,
454
			  const CtSaving::Parameters& b)
455
456
457
458
459
460
461
462
463
464
465
466
467
    {
      return ((a.directory       == b.directory)       &&
	      (a.prefix          == b.prefix)          &&
	      (a.suffix          == b.suffix)          &&
	      (a.imageType       == b.imageType)       &&
	      (a.nextNumber      == b.nextNumber)      &&
	      (a.fileFormat      == b.fileFormat)      &&
	      (a.savingMode      == b.savingMode)      &&
	      (a.overwritePolicy == b.overwritePolicy) &&
	      (a.indexFormat     == b.indexFormat)     &&
	      (a.framesPerFile   == b.framesPerFile)   &&
	      (a.nbframes        == b.nbframes));
    }
468

seb's avatar
seb committed
469
  inline std::ostream& operator<<(std::ostream &os,const CtSaving::HeaderMap &header)
470
471
472
473
474
475
476
477
    {
      os << "< ";
      for(CtSaving::HeaderMap::const_iterator i = header.begin();
	  i != header.end();++i)
	os << "(" << i->first << "," << i->second << ") ";
      os << ">";
      return os;
    }
seb's avatar
seb committed
478
479
480
481
482
  inline std::ostream& operator<<(std::ostream &os,const CtSaving::HeaderValue &value)
  {
    os << "< (" << value.first << "," << value.second << ") >";
    return os;
  }
483
484
485
486
487
488
489
490
491
492
493
494
495

  template<class T>
  void CtSaving::addToInternalCommonHeader(const std::string &key,
					   const T& obj)
  {
    AutoMutex aLock(m_cond.mutex());
    std::ostringstream str;
    str << obj;	
    const std::string& value = str.str();
    HeaderValue anEntry(key,value);
    m_internal_common_header.insert(anEntry);
  }

papillon's avatar
 
papillon committed
496
497
} // namespace lima

498
#endif // CTSAVING_H