Add FrequencyList methods to retrieve band name sets

Start to rationalize the new WSPR code with the data models.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5475 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2015-05-31 11:51:40 +00:00
parent f1858dbb4f
commit 7abcef5057
6 changed files with 178 additions and 124 deletions

View File

@ -195,3 +195,29 @@ QVariant Bands::headerData (int section, Qt::Orientation orientation, int role)
return result;
}
QString Bands::const_iterator::operator * ()
{
return ADIF_bands[row_].name_;
}
bool Bands::const_iterator::operator != (const_iterator const& rhs) const
{
return row_ != rhs.row_;
}
auto Bands::const_iterator::operator ++ () -> const_iterator&
{
++row_;
return *this;
}
auto Bands::begin () const -> Bands::const_iterator
{
return const_iterator (0);
}
auto Bands::end () const -> Bands::const_iterator
{
return const_iterator (table_rows ());
}

View File

@ -32,6 +32,23 @@ class Bands final
public:
using Frequency = Radio::Frequency;
// an iterator that meets the requirements of the C++ for range statement
class const_iterator
{
public:
const_iterator (int row)
: row_ {row}
{
}
QString operator * ();
bool operator != (const_iterator const&) const;
const_iterator& operator ++ ();
private:
int row_;
};
explicit Bands (QObject * parent = nullptr);
//
@ -40,6 +57,10 @@ public:
QString find (Frequency) const; // find band Frequency is in
static QString const& oob ();
// Iterators
const_iterator begin () const;
const_iterator end () const;
// Custom role for sorting.
static int constexpr SortRole = Qt::UserRole;

View File

@ -173,8 +173,26 @@ int FrequencyList::best_working_frequency (Frequency f) const
auto const& target_band = m_->bands_->find (f);
if (!target_band.isEmpty ())
{
// find a frequency in the same band that is allowed for the
// target mode
// find a frequency in the same band that is allowed
for (int row = 0; row < rowCount (); ++row)
{
auto const& source_row = mapToSource (index (row, 0)).row ();
auto const& band = m_->bands_->find (m_->frequency_list_[source_row].frequency_);
if (band == target_band)
{
return row;
}
}
}
return result;
}
int FrequencyList::best_working_frequency (QString const& target_band) const
{
int result {-1};
if (!target_band.isEmpty ())
{
// find a frequency in the same band that is allowed
for (int row = 0; row < rowCount (); ++row)
{
auto const& source_row = mapToSource (index (row, 0)).row ();
@ -553,3 +571,23 @@ auto FrequencyList::end () const -> FrequencyList::const_iterator
{
return const_iterator (this, rowCount ());
}
auto FrequencyList::all_bands () const -> BandSet
{
BandSet result;
for (auto const& item : m_->frequency_list_)
{
result << m_->bands_->find (item.frequency_);
}
return result;
}
auto FrequencyList::filtered_bands () const -> BandSet
{
BandSet result;
for (auto const& item : *this)
{
result << m_->bands_->find (item.frequency_);
}
return result;
}

View File

@ -14,18 +14,21 @@ class Bands;
//
// Class FrequencyList
//
// Encapsulates a collection of frequencies. The implementation is a
// table containing the list of Frequency type elements which is
// editable and a second column which is an immutable double
// representation of the corresponding Frequency item scaled to
// mega-Hertz.
// Encapsulates a collection of frequencies with associated modes.
// The implementation is a table containing the list of Frequency and
// mode tuples which are editable. A third column is modeled in the
// model which is an immutable double representation of the
// corresponding Frequency item scaled to mega-Hertz.
//
// The list is ordered.
// The list is ordered. A filter on mode is available and is set by
// the filter(Mode) method. The Mode value Modes::NULL_MODE passes
// all rows in the filter.
//
// Responsibilities
//
// Stores internally a list of unique frequencies. Provides methods
// to add and delete list elements.
// Stores internally a list of unique frequency mode tuples.
// Provides methods to add and delete list elements. Provides range
// iterators for a filtered view of the underlying table.
//
// Collaborations
//
@ -47,6 +50,7 @@ public:
Mode mode_;
};
using FrequencyItems = QList<Item>;
using BandSet = QSet<QString>;
enum Column {mode_column, frequency_column, frequency_mhz_column};
@ -81,16 +85,26 @@ public:
// Note that these iterators are on the final sorted and filtered
// rows, if you need to access the underlying unfiltered and
// unsorted frequencies then use the frequency_list() member to
// access the underlying list of rows
// access the underlying list of rows.
const_iterator begin () const;
const_iterator end () const;
// Bands of the frequencies
BandSet all_bands () const;
BandSet filtered_bands () const;
// Find the row of the nearest best working frequency given a
// frequency and mode
// frequency. Returns -1 if no suitable working frequency is found
// in the list.
int best_working_frequency (Frequency) const;
// Find the row of the nearest best working frequency given a band
// name. Returns -1 if no suitable working frequency is found in the
// list.
int best_working_frequency (QString const& band) const;
// Set filter
void filter (Mode);
Q_SLOT void filter (Mode);
// Reset
Q_SLOT void reset_to_defaults ();

View File

@ -52,6 +52,9 @@ namespace
Radio::Frequency constexpr default_frequency {14076000};
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#]*"};
// These 10 bands are the hopping candidates and are globally coordinated
QStringList const hopping_bands = {"160m","80m","60m","40m","30m","20m","17m","15m","12m","10m"};
bool message_is_73 (int type, QStringList const& msg_parts)
{
return type >= 0
@ -390,20 +393,8 @@ MainWindow::MainWindow(bool multiple, QSettings * settings, QSharedMemory *shdme
m_uploading=false;
m_hopTest=false;
m_bTxTime=false;
m_band00=-1;
m_rxDone=false;
m_fWSPR["160"]=1.8366; //WSPR frequencies
m_fWSPR["80"]=3.5926;
m_fWSPR["60"]=5.2872;
m_fWSPR["40"]=7.0386;
m_fWSPR["30"]=10.1387;
m_fWSPR["20"]=14.0956;
m_fWSPR["17"]=18.1046;
m_fWSPR["15"]=21.0946;
m_fWSPR["12"]=24.9246;
m_fWSPR["10"]=28.1246;
signalMeter = new SignalMeter(ui->meterFrame);
signalMeter->resize(50, 160);
@ -2224,16 +2215,8 @@ void MainWindow::startTx2()
transmit (snr);
signalMeter->setValue(0);
if(m_mode.mid(0,4)=="WSPR" and !m_tune) {
<<<<<<< variant A
t = " Transmitting " + m_mode + " ----------------------- " +
QString {m_config.bands ()->find (m_dialFreq)->name_};
>>>>>>> variant B
t = " Transmiting " + m_mode + " ----------------------- " +
m_config.bands ()->find (m_dialFreq);
####### Ancestor
t = " Transmiting " + m_mode + " ----------------------- " +
QString {m_config.bands ()->find (m_dialFreq)->name_};
======= end
ui->decodedTextBrowser->append(t.rightJustified (71, '-'));
QFile f {m_dataDir.absoluteFilePath ("ALL_WSPR.TXT")};
@ -3821,14 +3804,15 @@ void MainWindow::pskSetLocal ()
{
// find the station row, if any, that matches the band we are on
auto stations = m_config.stations ();
auto matches = stations->match (stations->index (0, 0)
auto matches = stations->match (stations->index (0, StationList::band_column)
, Qt::DisplayRole
, ui->bandComboBox->currentText ()
, 1
, Qt::MatchExactly);
QString antenna_description;
if (!matches.isEmpty ()) {
antenna_description = stations->index (matches.first ().row (), 2).data ().toString ();
antenna_description = stations->index (matches.first ().row ()
, StationList::description_column).data ().toString ();
}
psk_Reporter->setLocalStation(m_config.my_callsign (), m_config.my_grid (),
antenna_description, QString {"WSJT-X v" + version() + " " +
@ -4274,7 +4258,6 @@ void MainWindow::on_cbBandHop_toggled(bool b)
void MainWindow::bandHopping()
{
QString bandName[]={"160","80","60","40","30","20","17","15","12","10"};
QDateTime t = QDateTime::currentDateTimeUtc();
QString date = t.date().toString("yyyy MMM dd").trimmed();
QString utc = t.time().toString().trimmed();
@ -4286,9 +4269,8 @@ void MainWindow::bandHopping()
float sec=t.time().second() + 0.001*t.time().msec();
float uth=nhr + nmin/60.0 + sec/3600.0;
int isun;
int iband0,iband;
int iband0;
int ntxnext;
int i,j;
static int icall=0;
if(m_hopTest) uth+= 2.0*icall/60.0;
@ -4296,7 +4278,7 @@ void MainWindow::bandHopping()
// Find grayline status, isun: 0=Sunrise, 1=Day, 2=Sunset, 3=Night
hopping_(&nyear, &month, &nday, &uth,
const_cast <char *> (m_config.my_grid ().toLatin1().constData()),
m_config.my_grid ().toLatin1().constData(),
&m_grayDuration, &m_pctx, &isun, &iband0, &ntxnext, 6);
@ -4306,97 +4288,72 @@ void MainWindow::bandHopping()
m_nrx=1;
}
if( m_bandHopping ) {
QString bname;
QStringList s;
if(isun==0) s=m_sunriseBands;
if(isun==1) s=m_dayBands;
if(isun==2) s=m_sunsetBands;
if(isun==3) s=m_nightBands;
if( m_bandHopping ) {
QStringList s;
if(isun==0) s=m_sunriseBands;
if(isun==1) s=m_dayBands;
if(isun==2) s=m_sunsetBands;
if(isun==3) s=m_nightBands;
Frequency f0=0;
iband=-1;
for(i=0; i<s.length(); i++) { //See if designated band is active
if(s.at(i)==bandName[iband0]) {
f0=(Frequency)1000000*m_fWSPR[bandName[iband0]]+0.5;
bname=s.at(i);
iband=iband0;
QString new_band;
if (s.contains (hopping_bands[iband0])) { //See if designated band is active
new_band = hopping_bands[iband0];
}
}
//If designated band is not active, choose one that is active
if(iband==-1) {
for(i=0; i<s.length(); i++) {
j=qrand() % s.length();
bname=s.at(j);
f0=(Frequency)1000000*m_fWSPR[bname]+0.5;
if(s.at(j)!=bandName[m_band00]) break;
}
for(i=0; i<10; i++) {
if(bname==bandName[i]) {
iband=i;
break;
else {
// If designated band is not active, choose one that is active
// and in the hopping list
for (auto i = 0; i < s.size (); ++i) { // arbitrary number of iterations
auto const& bname = s[qrand() % s.size ()]; // pick a random band
if (bname != m_band00 && hopping_bands.contains (bname)) {
new_band = bname;
break;
}
}
}
}
qDebug () << "bandHopping: m_band00:" << m_band00 << "new candidate band:" << new_band;
QThread::msleep(1500);
QThread::msleep(1500);
// qDebug() << nhr << nmin << int(sec) << bname << f0 << 0.000001*f0;
// qDebug() << nhr << nmin << int(sec) << m_band00 << f0 << 0.000001*f0;
m_band00=iband;
auto frequencies = m_config.frequencies ();
// Iterate the filtered-by-mode FrequencyList model
for (int row = 0; row < frequencies->rowCount (); ++row) {
// Lookup the underlying source model index from the filtered model index
auto const& source_index = frequencies->mapToSource (frequencies->index (row, FrequencyList::frequency_column));
// and use it to directly access the list of frequencies that the
// FrequencyList model wraps (we could also use the model data()
// member using the EditRole of the frequency_column but this way
// avoids going via a QVariant item)
auto const& f = frequencies->frequency_list ()[source_index.row ()].frequency_;
if(f==f0) {
on_bandComboBox_activated(row); //Set new band
// qDebug() << nhr << nmin << int(sec) << "Band selected" << i << 0.000001*f0 << 0.000001*f;
break;
auto const& row = m_config.frequencies ()->best_working_frequency (new_band);
if (row >= 0) { // band is configured
m_band00 = new_band;
ui->bandComboBox->setCurrentIndex (row);
on_bandComboBox_activated (row);
m_cmnd="";
QFile f1 {m_appDir + "/user_hardware.bat"};
if(f1.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware.bat ") + m_band00;
}
QFile f2 {m_appDir + "/user_hardware.cmd"};
if(f2.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware.cmd ") + m_band00;
}
QFile f3 {m_appDir + "/user_hardware.exe"};
if(f3.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware.exe ") + m_band00;
}
QFile f4 {m_appDir + "/user_hardware"};
if(f4.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware ") + m_band00;
}
if(m_cmnd!="") p3.start(m_cmnd); // Execute user's hardware controller
// Produce a short tuneup signal
m_tuneup = false;
if (m_tuneBands.contains (m_band00)) {
m_tuneup = true;
on_tuneButton_clicked (true);
tuneATU_Timer->start (2500);
}
}
}
m_cmnd="";
QFile f1 {m_appDir + "/user_hardware.bat"};
if(f1.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware.bat ") + bname;
// Display grayline status
QString dailySequence[4]={"Sunrise grayline","Day","Sunset grayline","Night"};
auto_tx_label->setText(dailySequence[isun]);
}
QFile f2 {m_appDir + "/user_hardware.cmd"};
if(f2.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware.cmd ") + bname;
}
QFile f3 {m_appDir + "/user_hardware.exe"};
if(f3.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware.exe ") + bname;
}
QFile f4 {m_appDir + "/user_hardware"};
if(f4.exists()) {
m_cmnd=QDir::toNativeSeparators (m_appDir + "/user_hardware ") + bname;
}
if(m_cmnd!="") p3.start(m_cmnd); // Execute user's hardware controller
// Displat grayline status
QString dailySequence[4]={"Sunrise grayline","Day","Sunset grayline","Night"};
auto_tx_label->setText(dailySequence[isun]);
// Produce a short tuneup signal
s=m_tuneBands;
m_tuneup=false;
for(int i=0; i<s.length(); i++) {
if(s.at(i)==bname) m_tuneup=true;
}
if(m_tuneup) {
on_tuneButton_clicked(true);
tuneATU_Timer->start(2500);
}
} //endif m_bandHopping
}
void MainWindow::on_pushButton_clicked()

View File

@ -328,7 +328,7 @@ private:
qint32 m_pctx;
qint32 m_nseq;
qint32 m_grayDuration;
qint32 m_band00;
QString m_band00;
bool m_btxok; //True if OK to transmit
bool m_diskData;
@ -454,8 +454,6 @@ private:
QStringList m_nightBands;
QStringList m_tuneBands;
QMap<QString,double> m_fWSPR;
QHash<QString,bool> m_pfx;
QHash<QString,bool> m_sfx;
@ -552,7 +550,7 @@ extern "C" {
void wspr_downsample_(short int d2[], int* k);
void savec2_(char* fname, int* m_TRseconds, double* m_dialFreq, int len1);
void hopping_(int* nyear, int* month, int* nday, float* uth, char* MyGrid,
void hopping_(int* nyear, int* month, int* nday, float* uth, char const * MyGrid,
int* nduration, int* npctx, int* isun, int* iband,
int* ntxnext, int len);
}