217 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			217 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | #include "adif.h" | ||
|  | 
 | ||
|  | #include <QFile> | ||
|  | #include <QTextStream> | ||
|  | #include <QDateTime> | ||
|  | #include <QDebug> | ||
|  | 
 | ||
|  | /* | ||
|  | <CALL:4>W1XT<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>DM33<MODE:4>JT65<RST_RCVD:3>-21<RST_SENT:3>-14<QSO_DATE:8>20110422<TIME_ON:6>041712<TIME_OFF:6>042435<TX_PWR:1>4<COMMENT:34>1st JT65A QSO.   Him: mag loop 20W<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor> | ||
|  | <CALL:6>IK1SOW<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>JN35<MODE:4>JT65<RST_RCVD:3>-19<RST_SENT:3>-11<QSO_DATE:8>20110422<TIME_ON:6>052501<TIME_OFF:6>053359<TX_PWR:1>3<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor> | ||
|  | <CALL:6:S>W4ABC> ... | ||
|  | */ | ||
|  | 
 | ||
|  | void ADIF::init(QString const& filename) | ||
|  | { | ||
|  |     _filename = filename; | ||
|  |     _data.clear();  | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | QString ADIF::extractField(QString const& record, QString const& fieldName) const | ||
|  | { | ||
|  |     int fieldNameIndex = record.indexOf (fieldName + ':', 0, Qt::CaseInsensitive); | ||
|  |     if (fieldNameIndex >=0) | ||
|  |     { | ||
|  |         int closingBracketIndex = record.indexOf('>',fieldNameIndex); | ||
|  |         int fieldLengthIndex = record.indexOf(':',fieldNameIndex);  // find the size delimiter | ||
|  |         int dataTypeIndex = -1; | ||
|  |         if (fieldLengthIndex >= 0) | ||
|  |         { | ||
|  |           dataTypeIndex = record.indexOf(':',fieldLengthIndex+1);  // check for a second : indicating there is a data type | ||
|  |           if (dataTypeIndex > closingBracketIndex) | ||
|  |             dataTypeIndex = -1; // second : was found but it was beyond the closing > | ||
|  |         } | ||
|  | 
 | ||
|  |         if ((closingBracketIndex > fieldNameIndex) && (fieldLengthIndex > fieldNameIndex) && (fieldLengthIndex< closingBracketIndex)) | ||
|  |         { | ||
|  |             int fieldLengthCharCount = closingBracketIndex - fieldLengthIndex -1; | ||
|  |             if (dataTypeIndex >= 0) | ||
|  |               fieldLengthCharCount -= 2; // data type indicator is always a colon followed by a single character | ||
|  |             QString fieldLengthString = record.mid(fieldLengthIndex+1,fieldLengthCharCount); | ||
|  |             int fieldLength = fieldLengthString.toInt(); | ||
|  |             if (fieldLength > 0) | ||
|  |             { | ||
|  |               QString field = record.mid(closingBracketIndex+1,fieldLength); | ||
|  |               return field; | ||
|  |             } | ||
|  |        } | ||
|  |     } | ||
|  |     return ""; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | void ADIF::load() | ||
|  | { | ||
|  |     _data.clear(); | ||
|  |     QFile inputFile(_filename); | ||
|  |     if (inputFile.open(QIODevice::ReadOnly)) | ||
|  |     { | ||
|  |       QTextStream in(&inputFile); | ||
|  |       QString buffer; | ||
|  |       bool pre_read {false}; | ||
|  |       int end_position {-1}; | ||
|  | 
 | ||
|  |       // skip optional header record | ||
|  |       do | ||
|  |         { | ||
|  |           buffer += in.readLine () + '\n'; | ||
|  |           if (buffer.startsWith (QChar {'<'})) // denotes no header | ||
|  |             { | ||
|  |               pre_read = true; | ||
|  |             } | ||
|  |           else | ||
|  |             { | ||
|  |               end_position = buffer.indexOf ("<EOH>", 0, Qt::CaseInsensitive); | ||
|  |             } | ||
|  |         } | ||
|  |       while (!in.atEnd () && !pre_read && end_position < 0); | ||
|  |       if (!pre_read)            // found header | ||
|  |         { | ||
|  |           buffer.remove (0, end_position + 5); | ||
|  |         } | ||
|  |       while (buffer.size () || !in.atEnd ()) | ||
|  |         { | ||
|  |           do | ||
|  |             { | ||
|  |               end_position = buffer.indexOf ("<EOR>", 0, Qt::CaseInsensitive); | ||
|  |               if (!in.atEnd () && end_position < 0) | ||
|  |                 { | ||
|  |                   buffer += in.readLine () + '\n'; | ||
|  |                 } | ||
|  |             } | ||
|  |           while (!in.atEnd () && end_position < 0); | ||
|  |           int record_length {end_position >= 0 ? end_position + 5 : -1}; | ||
|  |           auto record = buffer.left (record_length).trimmed (); | ||
|  |           auto next_record = buffer.indexOf (QChar {'<'}, record_length); | ||
|  |           buffer.remove (0, next_record >=0 ? next_record : buffer.size ()); | ||
|  |           record = record.mid (record.indexOf (QChar {'<'})); | ||
|  |           add (extractField (record, "CALL") | ||
|  |                , extractField (record, "BAND") | ||
|  |                , extractField (record, "MODE") | ||
|  |                , extractField (record, "QSO_DATE")); | ||
|  |         } | ||
|  |         inputFile.close (); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& date) | ||
|  | { | ||
|  |     QSO q; | ||
|  |     q.call = call; | ||
|  |     q.band = band; | ||
|  |     q.mode = mode; | ||
|  |     q.date = date; | ||
|  |     if (q.call.size ()) | ||
|  |       { | ||
|  |         _data.insert(q.call,q); | ||
|  |         // qDebug() << "Added as worked:" << call << band << mode << date; | ||
|  |       } | ||
|  | } | ||
|  | 
 | ||
|  | // return true if in the log same band and mode (where JT65 == JT9) | ||
|  | bool ADIF::match(QString const& call, QString const& band, QString const& mode) const | ||
|  | { | ||
|  |     QList<QSO> qsos = _data.values(call); | ||
|  |     if (qsos.size()>0) | ||
|  |     { | ||
|  |         QSO q; | ||
|  |         foreach(q,qsos) | ||
|  |         { | ||
|  |             if (     (band.compare(q.band,Qt::CaseInsensitive) == 0) | ||
|  |                   || (band=="") | ||
|  |                   || (q.band=="")) | ||
|  |             { | ||
|  |                 if ( | ||
|  |                      ( | ||
|  |                        ((mode.compare("JT65",Qt::CaseInsensitive)==0) || | ||
|  |                         (mode.compare("JT9",Qt::CaseInsensitive)==0)  || | ||
|  |                         (mode.compare("FT8",Qt::CaseInsensitive)==0)) | ||
|  |                        && | ||
|  |                        ((q.mode.compare("JT65",Qt::CaseInsensitive)==0) || | ||
|  |                         (q.mode.compare("JT9",Qt::CaseInsensitive)==0)  || | ||
|  |                         (q.mode.compare("FT8",Qt::CaseInsensitive)==0)) | ||
|  |                      ) | ||
|  |                         || (mode.compare(q.mode,Qt::CaseInsensitive)==0) | ||
|  |                         || (mode=="") | ||
|  |                         || (q.mode=="") | ||
|  |                     ) | ||
|  |                 return true; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |     return false; | ||
|  | }     | ||
|  | 
 | ||
|  | QList<QString> ADIF::getCallList() const | ||
|  | { | ||
|  |     QList<QString> p; | ||
|  |     QMultiHash<QString,QSO>::const_iterator i = _data.constBegin(); | ||
|  |      while (i != _data.constEnd()) | ||
|  |      { | ||
|  |          p << i.key(); | ||
|  |          ++i; | ||
|  |      } | ||
|  |     return p; | ||
|  | }    | ||
|  |      | ||
|  | int ADIF::getCount() const | ||
|  | { | ||
|  |     return _data.size(); | ||
|  | }    | ||
|  |      | ||
|  | 
 | ||
|  | // open ADIF file and append the QSO details. Return true on success | ||
|  | bool ADIF::addQSOToFile(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, QString const& band, | ||
|  |                         QString const& comments, QString const& name, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid, QString const& m_txPower) | ||
|  | { | ||
|  |     QFile f2(_filename); | ||
|  |     if (!f2.open(QIODevice::Text | QIODevice::Append)) | ||
|  |         return false; | ||
|  |     else | ||
|  |     { | ||
|  |         QTextStream out(&f2); | ||
|  |         if (f2.size()==0) | ||
|  |             out << "WSJT-X ADIF Export<eoh>" << endl;  // new file | ||
|  | 
 | ||
|  |         QString t; | ||
|  |         t="<call:" + QString::number(hisCall.length()) + ">" + hisCall; | ||
|  |         t+=" <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid; | ||
|  |         t+=" <mode:" + QString::number(mode.length()) + ">" + mode; | ||
|  |         t+=" <rst_sent:" + QString::number(rptSent.length()) + ">" + rptSent; | ||
|  |         t+=" <rst_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd; | ||
|  |         t+=" <qso_date:8>" + dateTimeOn.date ().toString ("yyyyMMdd"); | ||
|  |         t+=" <time_on:6>" + dateTimeOn.time ().toString ("hhmmss"); | ||
|  |         t+=" <qso_date_off:8>" + dateTimeOff.date ().toString ("yyyyMMdd"); | ||
|  |         t+=" <time_off:6>" + dateTimeOff.time ().toString ("hhmmss"); | ||
|  |         t+=" <band:" + QString::number(band.length()) + ">" + band; | ||
|  |         t+=" <freq:" + QString::number(strDialFreq.length()) + ">" + strDialFreq; | ||
|  |         t+=" <station_callsign:" + QString::number(m_myCall.length()) + ">" + | ||
|  |                 m_myCall; | ||
|  |         t+=" <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" + | ||
|  |                 m_myGrid; | ||
|  |         if(m_txPower!="") t+= " <tx_pwr:" + QString::number(m_txPower.length()) + | ||
|  |                 ">" + m_txPower; | ||
|  |         if(comments!="") t+=" <comment:" + QString::number(comments.length()) + | ||
|  |                 ">" + comments; | ||
|  |         if(name!="") t+=" <name:" + QString::number(name.length()) + | ||
|  |                 ">" + name; | ||
|  |         t+=" <eor>"; | ||
|  |         out << t << endl; | ||
|  |         f2.close(); | ||
|  |     } | ||
|  |     return true; | ||
|  | } |