UltraScan III
us_ramp.cpp
Go to the documentation of this file.
1 
3 #include "us_gui_settings.h"
4 #include "us_math2.h"
5 #include "us_util.h"
6 #include "us_ramp.h"
7 #include "us_settings.h"
8 // #include "us_convertio.h"
9 #include "stdio.h"
10 
11 #include <QDomDocument>
12 #include "us_crc.h"
13 #include "us_matrix.h"
14 
15 #ifdef WIN32
16  #define round(x) floor( (x) + 0.5 )
17 #endif
18 
19 // Generic constructor
21 {
22 // dbg_level = US_Settings::us_debug();
23 // DbgLv(0) << "MwDa: dbg_level" << dbg_level;
24 }
25 
26 
27 
29  QVector< US_mwlRamp::RampRawData* >& rawConvertedData,
30  QList< TripleInfo >& all_chaninfo,
31  QString runType,
32  QString runID,
33  QString dirname,
34  bool saveGUIDs
35  )
36 {
37  //qDebug() << "description"<<rawConvertedData[0]->description;
38  if ( rawConvertedData[ 0 ]->intarray.empty() )
39  return NODATA;
40 
41  // Write the data
42  int status;
43 
44  // Make sure directory is empty
45  QDir d( dirname );
46  QStringList rmvfilt( "*.ramp" );
47  QStringList rmvfiles = d.entryList( rmvfilt, QDir::Files, QDir::Name );
48  for ( int ii = 0; ii < rmvfiles.size(); ii++ )
49  if ( ! d.remove( rmvfiles[ ii ] ) )
50  //qDebug() << "Unable to remove file" << rmvfiles[ ii ];
51 
52 
53 
54  QString wavelnp = "";
55 
56  for ( int i = 0; i < all_chaninfo.size(); i++ )
57  {
58  if ( all_chaninfo[ i ].excluded ) continue;
59 
60  QString triple = all_chaninfo[ i ].tripleDesc;
61  QStringList parts = triple.split(" / ");
62 
63  QString cell = parts[ 0 ];
64  QString channel = parts[ 1 ];
65  QString filename;
66 
67  filename = runID + "."
68  + cell + "."
69  + channel + "."
70  + "ramp";
71  //qDebug()<<"tripledesc_filename_cellchan_cell_chan"<<all_chaninfo[i].tripleDesc<<i<<filename;
72 
73  // Same with solutionGUID
74  QRegExp rx( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" );
75  qDebug()<<"_______________________________________________________________________";
76  qDebug()<<"all_chaninfo[ i ].solution.saveStatus"<<all_chaninfo[ i ].solution.saveStatus;
77  qDebug()<<"US_Solution::NOT_SAVED "<<US_Solution::NOT_SAVED ;
78  qDebug()<<"!rx.exactMatch( all_chaninfo[ i ].solution.solutionGUID "<<!rx.exactMatch( all_chaninfo[ i ].solution.solutionGUID) ;
79 
80  if ( ( all_chaninfo[ i ].solution.saveStatus == US_Solution::NOT_SAVED ) ||
81  ( ! rx.exactMatch( all_chaninfo[ i ].solution.solutionGUID ) ) )
82  {
83  all_chaninfo[ i ].solution.solutionGUID = US_Util::new_guid();
84  all_chaninfo[ i ].solution.solutionDesc = "New Solution";
85  }
86 // //////////////////////////////////////////////////////////////////////////////
87  // Make sure solution is saved to disk
88  all_chaninfo[ i ].solution.saveToDisk();
89 
90  // Save the filename of this triple
91  all_chaninfo[ i ].tripleFilename = filename;
92  //size allchaninfo != size_alldata!? //KL
93 // qDebug()<<"i size_allchaninfo size_rawconverteddata"<<i<<all_chaninfo.size()<<rawConvertedData.size();
94  US_mwlRamp::RampRawData savecc = *rawConvertedData[i];
95  // Now write altered dataset
96  writeRawData( dirname + filename, savecc );
97 
98  }
99 
100  return OK;
101 }
102 
104 {
105  // Open the file for writing
106  QFile ff( file );
107  if ( ! ff.open( QIODevice::WriteOnly ) ) return CANTOPEN;
108  QDataStream ds( &ff );
109 
110  // Using quint32 to ensure same data size on all platforms
111  quint32 crc = 0xffffffffUL;
112 
113  // Write magic number
114  char magic[ 5 ] = "UCDA";
115  write( ds, magic, 4, crc );
116 
117  // Write format version
118  char fmt[ 3 ];
119  sprintf( fmt, "%2.2i", format_version );
120  write( ds, fmt, 2, crc );
121  //qDebug()<<"format"<<format_version;
122 
123 // // Write data type
124 // write( ds, data.type, 2, crc );
125 
126  // Write cell
127  char c = data.cell.toAscii();
128  int ic = c - '0';
129  write( ds, (const char*) &ic, 1, crc );
130 
131  // Write channel
132  c = data.chan.toAscii();
133  write( ds, (const char*)&c, 1, crc );
134 
135 // // Create and write a guid
136 // write( ds, data.rawGUID, 16, crc );
137 //
138  // Write description
139  char desc[ 240 ];
140  memset( desc, '\0', sizeof desc ); // bzero is not defined in WIN32
141 
142  QByteArray dd = data.description.toLatin1();
143  strncpy( desc, dd.data(), sizeof desc );
144  write( ds, desc, sizeof desc, crc );
145 
146 
148  // The unions below are a little tricky in order to get the
149  // c++ types and architecture endian-ness right. Floats
150  // are written to uf.f (union float - float ). Then the
151  // 4 bytes of the float are treated as a 32-bit unsigned int and
152  // converted to ui.u (union integer - unsigned ). Finally
153  // the ui.c type is to satify the c++ type for the write call.
154 
155  union
156  {
157  quint32 u;
158  float f;
159  } uf;
160 
161  union
162  {
163  char c[ 4 ];
164  uchar u[ 4 ];
165  } ui;
166 
167  uf.f = (float) data.temperature; // temperature
168  qToLittleEndian( uf.u, ui.u );
169  write( ds, ui.c, 4, crc );
170 
171  uf.f = (float) data.radius; // radius
172  qToLittleEndian( uf.u, ui.u );
173  write( ds, ui.c, 4, crc );
174 
175  uf.f = (float) data.meniscus; // meniscus
176  qToLittleEndian( uf.u, ui.u );
177  write( ds, ui.c, 4, crc );
178 
179  uf.f = (float) data.bottom; // bottom
180  qToLittleEndian( uf.u, ui.u );
181  write( ds, ui.c, 4, crc );
182 
183  double n = data.rpm.size(); // n * rpm/time/w2t
184  uf.f = (float) n;
185  qToLittleEndian( uf.u, ui.u );
186  write( ds, ui.c, 4, crc );
187 
188 
189  for (int i=0; i<(int)n; i++) // rpm array
190  {
191  uf.f = (float) data.rpm.at(i);
192  qToLittleEndian( uf.u, ui.u );
193  write( ds, ui.c, 4, crc );
194  }
195 
196  for (int i=0; i<(int)n; i++) // time array
197  {
198  uf.f = (float) data.time.at(i);
199  qToLittleEndian( uf.u, ui.u );
200  write( ds, ui.c, 4, crc );
201  }
202 
203  for (int i=0; i<(int)n; i++) // w2t array
204  {
205  uf.f = (float) data.w2t.at(i);
206  qToLittleEndian( uf.u, ui.u );
207  write( ds, ui.c, 4, crc );
208  }
209 
210  double n_wl = data.wl_array.size(); // n Wavelengths
211  uf.f = (float) n_wl;
212  qToLittleEndian( uf.u, ui.u );
213  write( ds, ui.c, 4, crc );
214  //qDebug()<<"dn_wl ui.c"<<n_wl<<ui.c;
215 
216  double wl_double;
217  for (int i=0; i<(int)n_wl; i++) // Wavelength array
218  {
219  wl_double = (double) data.wl_array.at(i);
220  uf.f = (float) wl_double;
221  qToLittleEndian( uf.u, ui.u );
222  write( ds, ui.c, 4, crc );
223  }
224 
225  data.intarray.resize(n_wl); // write measurement array
226  for (int lambda=0; lambda<n_wl; lambda++)
227  {
228  data.intarray.resize(n);
229  for (int i=0; i<n; i++)
230  {
231  uf.f = (float) data.intarray[lambda].at(i);
232  qToLittleEndian( uf.u, ui.u );
233  write( ds, ui.c, 4, crc );
234  }
235  }
236 
237 
238 // // Write out scan count
239 // qToLittleEndian( (quint16)data.scanData.size(), ui.u );
240 // write( ds, ui.c, 2, crc );
241 
242 // // Loop for each scan
243 // for ( int ii = 0; ii < data.scanData.size(); ii++ )
244 // writeScan( ds, data.scanData[ ii ], crc, pp );
245 //
246 // qToLittleEndian( crc, ui.u ); // crc
247 // ds.writeRawData( ui.c, 4 );
248 
249 
250  ff.close();
251  readRawData(file,data);
252 
253  return OK;
254 
255 }
256 
257 /*format parameter char[]
259  char magic 4
260  "%2.2i" format 2
261  int cell 1
262  char chan 1
263  char Latin1 description 240
264  float temperature 4
265  float radius 4
266  float meniscus 4
267  float bottom 4
268  float n-measurements 4
269  float rpm-array n*4
270  float time-array n*4
271  float w2t-array n*4
272  float n-wavelengths 4
273  float wl-array n_wl*4
274  float meas.-array n_wl*n*4
275 */
276 
278  QString dir,
279  QVector< US_mwlRamp::RampRawData >& rawConvertedData,
280  QList< TripleInfo >& all_chaninfo,
281  QString& runType
282  )
283 {
284  rawConvertedData.clear();
285 
286  QStringList nameFilters = QStringList( "*.ramp" );
287 
288  QDir d( dir );
289 
290  QStringList files = d.entryList( nameFilters,
291  QDir::Files | QDir::Readable, QDir::Name );
292 
293  if ( files.size() == 0 )
294  return NODATA;
295 
296 // // Get runType
297  QStringList part = files[ 0 ].split( "." );
298 // runType = part[ 1 ];
299 
300  // Set up cell / channel combinations
301  all_chaninfo.clear();
302  for ( int i = 0; i < files.size(); i++ )
303  {
304  part.clear();
305  part = files[ i ].split( "." );
306 // QString wl;
307 // if ( runType == "WA" )
308 // wl = QString::number( part[ 4 ].toDouble() / 1000.0 );
309 // else
310 // wl = part[ 4 ];
311 
312  TripleInfo t;
313 
314  t.tripleDesc = part[ 1 ] + " / " + part[ 2 ];
315  t.excluded = false;
316  //qDebug()<<"t.tripleDesc"<< t.tripleDesc;
317  all_chaninfo << t;
318  }
319 
320  // Read all data
321  QString file;
322  foreach ( file, files )
323  {
324  QString filename = dir + file;
326 
327  int result = US_Ramp::readRawData( filename, data );
328  if ( result != US_DataIO::OK )
329  return NOAUC;
330 
331  rawConvertedData << data;
332 // data.scanData.clear();
333  }
334 
335  return OK;
336 }
337 
338 int US_Ramp::readRawData( const QString file, US_mwlRamp::RampRawData& data )
339 {
340  QFile ff( file );
341 // qDebug()<<"_________________________________________________________file"<<file;
342  if ( ! ff.open( QIODevice::ReadOnly ) ) return CANTOPEN;
343  QDataStream ds( &ff );
344 
345  int err = OK;
346  quint32 crc = 0xffffffffUL;
347 
348  try
349  {
350  // Read magic number
351  char magic[ 4 ];
352  read( ds, magic, 4, crc );
353 // qDebug() <<"readmagic"<<magic;
354  if ( !strncmp( magic, "UCDA", 4 ) != 0 ) qDebug() <<"readmagic"<<magic;
355 
356  // Check the version number
357  unsigned char ver[ 2 ];
358  read( ds, (char*) ver, 2, crc );
359  quint32 version = ( ( ver[ 0 ] & 0x0f ) << 8 ) | ( ver[ 1 ] & 0x0f );
360  //qDebug() <<"readmagic"<<version;
361  if ( version != format_version ) qDebug() <<"this ramp data version is bad!"<<version; // throw BAD_VERSION;
362 //
363 // // Read and get the file type
364 // char type[ 3 ];
365 // read( ds, type, 2, crc );
366 // type[ 2 ] = '\0';
367 //
368 // QStringList types = QStringList() << "RA" << "IP" << "RI" << "FI"
369 // << "WA" << "WI";
370 //
371 // if ( ! types.contains( QString( type ) ) ) throw BADTYPE;
372 // strncpy( data.type, type, 2 );
373 //
374  // Get the cell
375  union
376  { char c[ 4 ];
377  int i;
378  } cell;
379 
380  cell.i = 0;
381 
382  read( ds, cell.c, 1, crc );
383  data.cell = (qFromLittleEndian( cell.i ))+'0';
384 // QChar cell3= cell2 + '0';
385  //qDebug()<<"readcell"<<data.cell;
386 
387  //reset orig chan first
388  data.chan = 'C';
389  // Get the channel
390  union
391  { char c[ 4 ];
392  int i;
393  } chan;
394 
395  chan.i = 0;
396 // char chan[1];
397  read( ds, chan.c, 1, crc );
398  data.chan = qFromLittleEndian( chan.i );
399  //qDebug()<<"readchan"<<data.chan;
400 //
401 // // Get the guid
402 // read( ds, data.rawGUID, 16, crc );
403 //
404  // Get the description
405  char desc[ 240 ];
406  read( ds, desc, 240, crc );
407  data.description = QString( desc );
408  qDebug()<<"readchan" << data.chan << data.description;
409 
410 
411 // Get the parameters to expand the values
412  union
413  {
414  char c[ 2 ];
415  quint16 I;
416  } si;
417 
418  union
419  {
420  char c[ 4 ];
421  qint32 I;
422  float f;
423  } u1;
424 
425  union
426  {
427  char c[ 4 ];
428  qint32 I;
429  float f;
430  } u2;
431 
432  read( ds, u1.c, 4, crc ); // temperature
433  u2.I = qFromLittleEndian( u1.I );
434  data.temperature = u2.f;
435 
436  read( ds, u1.c, 4, crc ); // radius
437  u2.I = qFromLittleEndian( u1.I );
438  data.radius = u2.f;
439 
440  read( ds, u1.c, 4, crc ); // meniscus
441  u2.I = qFromLittleEndian( u1.I );
442  data.meniscus = u2.f;
443 
444  read( ds, u1.c, 4, crc ); // bottom
445  u2.I = qFromLittleEndian( u1.I );
446  data.bottom = u2.f;
447 
448  double dn; // n points for rpm/time/w2t
449  read( ds, u1.c, 4, crc );
450  u2.I = qFromLittleEndian( u1.I );
451  dn = u2.f;
452  int n = (int)dn;
453  //qDebug() << "testdata.radius" <<dn<<n;
454 
455 
456 // data.rpm.resize(n); // rpm array
457  for (int i=0; i<n; i++)
458  {
459  read( ds, u1.c, 4, crc );
460  u2.I = qFromLittleEndian( u1.I );
461  data.rpm.append( u2.f);
462 // //qDebug()<<"rpm"<<data.rpm.at(i);
463  }
464 
465 // data.time.resize(n); // time array
466  for (int i=0; i<n; i++)
467  {
468  read( ds, u1.c, 4, crc );
469  u2.I = qFromLittleEndian( u1.I );
470  data.time.append( u2.f);
471 // //qDebug()<<"time"<<data.rpm.at(i);
472  }
473 
474 // data.w2t.resize(n); // w2t array
475  for (int i=0; i<n; i++)
476  {
477  read( ds, u1.c, 4, crc );
478  u2.I = qFromLittleEndian( u1.I );
479  data.w2t.append( u2.f);
480  qDebug()<<"w2t"<<data.w2t.at(i);
481  }
482 
483  double dn_wl; // n Wavelengths
484  read( ds, u1.c, 4, crc );
485  u2.I = qFromLittleEndian( u1.I );
486  dn_wl = u2.f;
487 
488  int n_wl = (int)dn_wl;
489 
490 
491  double wl_double;
492 // data.wl_array.resize(n_wl); // Wavelength array
493  for (int i=0; i<n_wl; i++)
494  {
495  read( ds, u1.c, 4, crc );
496  u2.I = qFromLittleEndian( u1.I );
497  wl_double = u2.f;
498  data.wl_array.append( (int)wl_double);
499 // //qDebug()<<"wavelength"<<data.wl_array.at(i);//<<wl_double<<data.wl_array.at(i);
500  }
501  qDebug()<<"size_wl_arr"<<data.wl_array.size();
502 
503  data.intarray.resize(n_wl);
504  for (int lambda=0; lambda<n_wl; lambda++)
505  {
506  for (int i=0; i<n; i++)
507  {
508  read( ds, u1.c, 4, crc );
509  u2.I = qFromLittleEndian( u1.I );
510  data.intarray[lambda].append( u2.f);
511 // //qDebug()<<"w2t meas_value"<<data.w2t.at(i)<<data.intarray[lambda].at(i);
512  }
513  }
514 
515 // // Read the crc
516 // quint32 read_crc;
517 // ds.readRawData( (char*) &read_crc , 4 );
518 // if ( crc != qFromLittleEndian( read_crc ) ) throw BADCRC;
519 //
520  } catch( ioError error )
521  {
522  err = error;
523  }
524 
525  ff.close();
526  return err;
527 }
528 
529 
530 // void US_Ramp::setTriples(
531 // QList< US_DataIO::BeckmanRawScan >& rawLegacyData,
532 // QList< TripleInfo >& triples,
533 // QString runType,
534 // double tolerance )
535 // {
536 // // Wavelength data is handled differently here
537 // if ( runType == "WA" )
538 // setCcrTriples( rawLegacyData, triples, tolerance );
539 // else
540 // setCcwTriples( rawLegacyData, triples, tolerance );
541 //
542 // }
543 //
544 // void US_Ramp::setCcwTriples(
545 // QList< US_DataIO::BeckmanRawScan >& rawLegacyData,
546 // QList< TripleInfo >& triples,
547 // double tolerance )
548 // {
549 // // Most triples are ccw
550 // triples.clear();
551 //
552 // // Get wavelengths
553 // QStringList wavelengths;
554 //
555 // for ( int i = 0; i < rawLegacyData.size(); i++ )
556 // {
557 // QString wl = QString::number( rawLegacyData[ i ].rpoint, 'f', 1 );
558 // wavelengths << wl;
559 // }
560 //
561 // // Merge wavelengths
562 // wavelengths.sort();
563 //
564 // QList< QList< double > > modes;
565 // QList< double > mode;
566 //
567 // for ( int i = 0; i < wavelengths.size(); i++ )
568 // {
569 // double wl = wavelengths[ i ].toDouble();
570 //
571 // if ( ! mode.empty() && fabs( mode.last() - wl ) > tolerance )
572 // {
573 // modes << mode;
574 // mode.clear();
575 // }
576 //
577 // mode << wl;
578 // }
579 //
580 // if ( mode.size() > 0 ) modes << mode;
581 //
582 // // Now we have a list of modes.
583 // // Average each list and round to the closest integer.
584 // QList< double > wl_average;
585 //
586 // for ( int i = 0; i < modes.size(); i++ )
587 // {
588 // double sum = 0.0;
589 //
590 // for ( int j = 0; j < modes[ i ].size(); j++ ) sum += modes[ i ][ j ];
591 //
592 // wl_average << (double) round( 10.0 * sum / modes[ i ].size() ) / 10.0;
593 // }
594 //
595 // // Now that we have a more reliable list of wavelengths, let's
596 // // find out the possible cell, channel, and wavelength combinations
597 // for ( int i = 0; i < rawLegacyData.size(); i++ )
598 // {
599 // QString cell = QString::number( rawLegacyData[ i ].cell );
600 // QString channel = QString( rawLegacyData[ i ].channel );
601 // double wl = rawLegacyData[ i ].rpoint;
602 // QString wavelength = "0";
603 //
604 // // find the average wavelength
605 // for ( int j = 0; j < wl_average.size(); j++ )
606 // {
607 // if ( fabs( wl_average[ j ] - wl ) < tolerance )
608 // {
609 // wavelength = QString::number( (int) round( wl_average[ j ] ) );
610 // break;
611 // }
612 // }
613 //
614 // QString t = cell + " / " + channel + " / " + wavelength;
615 // bool found = false;
616 // for ( int j = 0; j < triples.size(); j++ )
617 // {
618 // if ( triples[ j ].tripleDesc == t )
619 // found = true;
620 // }
621 // if ( ! found )
622 // {
623 // TripleInfo triple;
624 // triple.tripleDesc = t;
625 // triple.tripleID = triples.size(); // The next number
626 // triples << triple;
627 // }
628 // }
629 // }
630 //
631 // void US_Ramp::setCcrTriples(
632 // QList< US_DataIO::BeckmanRawScan >& rawLegacyData,
633 // QList< TripleInfo >& triples,
634 // double tolerance )
635 // {
636 // // First of all, wavelength triples are ccr.
637 // triples.clear();
638 //
639 // // Now get the radius values
640 // QStringList radii;
641 //
642 // for ( int i = 0; i < rawLegacyData.size(); i++ )
643 // {
644 // QString r = QString::number( rawLegacyData[ i ].rpoint, 'f', 1 );
645 // radii << r;
646 // }
647 //
648 // // Merge radii
649 //
650 // radii.sort();
651 //
652 // QList< QList< double > > modes;
653 // QList< double > mode;
654 //
655 // for ( int i = 0; i < radii.size(); i++ )
656 // {
657 // double r = radii[ i ].toDouble();
658 //
659 // if ( ! mode.empty() && fabs( mode.last() - r ) > tolerance )
660 // {
661 // modes << mode;
662 // mode.clear();
663 // }
664 //
665 // mode << r;
666 // }
667 //
668 // if ( mode.size() > 0 ) modes << mode;
669 //
670 // // Now we have a list of modes.
671 // // Average each list and round to the closest integer.
672 // QList< double > r_average;
673 //
674 // for ( int i = 0; i < modes.size(); i++ )
675 // {
676 // double sum = 0.0;
677 //
678 // for ( int j = 0; j < modes[ i ].size(); j++ ) sum += modes[ i ][ j ];
679 //
680 // r_average << (double) round( 10.0 * sum / modes[ i ].size() ) / 10.0;
681 // }
682 //
683 // // Now that we have a more reliable list of radii, let's
684 // // find out the possible cell, channel, and radius combinations
685 // for ( int i = 0; i < rawLegacyData.size(); i++ )
686 // {
687 // QString cell = QString::number( rawLegacyData[ i ].cell );
688 // QString channel = QString( rawLegacyData[ i ].channel );
689 // double r = rawLegacyData[ i ].rpoint;
690 // QString radius = "0";
691 //
692 // // find the average radius
693 // for ( int j = 0; j < r_average.size(); j++ )
694 // {
695 // if ( fabs( r_average[ j ] - r ) < tolerance )
696 // {
697 // radius = QString::number( r_average[ j ] );
698 // break;
699 // }
700 // }
701 //
702 // QString t = cell + " / " + channel + " / " + radius;
703 // bool found = false;
704 // for ( int j = 0; j < triples.size(); j++ )
705 // {
706 // if ( triples[ j ].tripleDesc == t )
707 // found = true;
708 // }
709 // if ( ! found )
710 // {
711 // TripleInfo triple;
712 // triple.tripleID = triples.size(); // The next number
713 // triple.tripleDesc = t;
714 // triples << triple;
715 // }
716 // }
717 // }
718 //
719 // void US_Ramp::setInterpolated ( unsigned char* bitmap, int location )
720 // {
721 // int byte = location / 8;
722 // int bit = location % 8;
723 //
724 // bitmap[ byte ] |= 1 << ( 7 - bit );
725 // }
726 
727 // Initializations
729 {
730  clear();
731 }
732 
734 {
735  tripleID = 0;
736  tripleDesc = QString( "" );
737  description = QString( "" );
738  excluded = false;
739  centerpiece = 0;
740  memset( tripleGUID, 0, 16 );
741  tripleFilename = QString( "" );
742  solution.clear();
743 }
744 
746 {
747  QString uuidc = US_Util::uuid_unparse( (unsigned char*)tripleGUID );
748 
749  qDebug() << "tripleID = " << tripleID << '\n'
750  << "tripleDesc = " << tripleDesc << '\n'
751  << "description = " << description << '\n'
752  << "centerpiece = " << centerpiece << '\n'
753  << "tripleGUID = " << QString( uuidc ) << '\n'
754  << "tripleFilename = " << tripleFilename << '\n'
755  << "solutionID = " << QString::number( solution.solutionID ) << '\n'
756  << "solutionGUID = " << solution.solutionGUID << '\n'
757  << "solutionDesc = " << solution.solutionDesc;
758 
759  if ( excluded ) qDebug() << "excluded";
760 }
761 
762 void US_Ramp::write( QDataStream& ds, const char* c, int len, quint32& crc )
763 {
764  ds.writeRawData( c, len );
765  crc = US_Crc::crc32( crc, (unsigned char*) c, len );
766 }
767 
768 void US_Ramp::read( QDataStream& ds, char* cc, int len, quint32& crc )
769 {
770  ds.readRawData( cc, len );
771  crc = US_Crc::crc32( crc, (uchar*) cc, len );
772 }