1 #include "OmniRigTransceiver.hpp"
2 
3 #include <QDebug>
4 #include <objbase.h>
5 #include <QThread>
6 #include <QEventLoop>
7 
8 #include "qt_helpers.hpp"
9 
10 #include "moc_OmniRigTransceiver.cpp"
11 
12 namespace
13 {
14   auto constexpr OmniRig_transceiver_one_name = "OmniRig Rig 1";
15   auto constexpr OmniRig_transceiver_two_name = "OmniRig Rig 2";
16 }
17 
map_mode(OmniRig::RigParamX param)18 auto OmniRigTransceiver::map_mode (OmniRig::RigParamX param) -> MODE
19 {
20   if (param & OmniRig::PM_CW_U)
21     {
22       return CW_R;
23     }
24   else if (param & OmniRig::PM_CW_L)
25     {
26       return CW;
27     }
28   else if (param & OmniRig::PM_SSB_U)
29     {
30       return USB;
31     }
32   else if (param & OmniRig::PM_SSB_L)
33     {
34       return LSB;
35     }
36   else if (param & OmniRig::PM_DIG_U)
37     {
38       return DIG_U;
39     }
40   else if (param & OmniRig::PM_DIG_L)
41     {
42       return DIG_L;
43     }
44   else if (param & OmniRig::PM_AM)
45     {
46       return AM;
47     }
48   else if (param & OmniRig::PM_FM)
49     {
50       return FM;
51     }
52   CAT_ERROR ("unrecognized mode");
53   throw_qstring (tr ("OmniRig: unrecognized mode"));
54   return UNK;
55 }
56 
map_mode(MODE mode)57 OmniRig::RigParamX OmniRigTransceiver::map_mode (MODE mode)
58 {
59   switch (mode)
60     {
61     case AM: return OmniRig::PM_AM;
62     case CW: return OmniRig::PM_CW_L;
63     case CW_R: return OmniRig::PM_CW_U;
64     case USB: return OmniRig::PM_SSB_U;
65     case LSB: return OmniRig::PM_SSB_L;
66     case FSK: return OmniRig::PM_DIG_L;
67     case FSK_R: return OmniRig::PM_DIG_U;
68     case DIG_L: return OmniRig::PM_DIG_L;
69     case DIG_U: return OmniRig::PM_DIG_U;
70     case FM: return OmniRig::PM_FM;
71     case DIG_FM: return OmniRig::PM_FM;
72     default: break;
73     }
74   return OmniRig::PM_SSB_U; // quieten compiler grumble
75 }
76 
register_transceivers(logger_type *,TransceiverFactory::Transceivers * registry,unsigned id1,unsigned id2)77 void OmniRigTransceiver::register_transceivers (logger_type *,
78                                                 TransceiverFactory::Transceivers * registry,
79                                                 unsigned id1, unsigned id2)
80 {
81   (*registry)[OmniRig_transceiver_one_name] = TransceiverFactory::Capabilities {
82     id1
83     , TransceiverFactory::Capabilities::none // COM isn't serial or network
84     , true             // does PTT
85     , false            // doesn't select mic/data (use OmniRig config file)
86     , true             // can remote control RTS nd DTR
87     , true             // asynchronous interface
88   };
89   (*registry)[OmniRig_transceiver_two_name] = TransceiverFactory::Capabilities {
90     id2
91     , TransceiverFactory::Capabilities::none // COM isn't serial or network
92     , true             // does PTT
93     , false            // doesn't select mic/data (use OmniRig config file)
94     , true             // can remote control RTS nd DTR
95     , true             // asynchronous interface
96   };
97 }
98 
OmniRigTransceiver(logger_type * the_logger,std::unique_ptr<TransceiverBase> wrapped,RigNumber n,TransceiverFactory::PTTMethod ptt_type,QString const & ptt_port,QObject * parent)99 OmniRigTransceiver::OmniRigTransceiver (logger_type * the_logger,
100                                         std::unique_ptr<TransceiverBase> wrapped,
101                                         RigNumber n, TransceiverFactory::PTTMethod ptt_type,
102                                         QString const& ptt_port, QObject * parent)
103   : TransceiverBase {the_logger, parent}
104   , wrapped_ {std::move (wrapped)}
105   , use_for_ptt_ {TransceiverFactory::PTT_method_CAT == ptt_type || ("CAT" == ptt_port && (TransceiverFactory::PTT_method_RTS == ptt_type || TransceiverFactory::PTT_method_DTR == ptt_type))}
106   , ptt_type_ {ptt_type}
107   , rig_number_ {n}
108   , readable_params_ {0}
109   , writable_params_ {0}
110   , send_update_signal_ {false}
111   , reversed_ {false}
112 {
113   CoInitializeEx (nullptr, 0 /*COINIT_APARTMENTTHREADED*/); // required because Qt only does this for GUI thread
114   CAT_TRACE ("constructed");
115 }
116 
~OmniRigTransceiver()117 OmniRigTransceiver::~OmniRigTransceiver ()
118 {
119   CAT_TRACE ("destroying");
120   CoUninitialize ();
121 }
122 
do_start()123 int OmniRigTransceiver::do_start ()
124 {
125   CAT_TRACE ("starting");
126   try
127     {
128       if (wrapped_) wrapped_->start (0);
129 
130       omni_rig_.reset (new OmniRig::OmniRigX {this});
131       if (omni_rig_->isNull ())
132         {
133           CAT_ERROR ("failed to start COM server");
134           throw_qstring (tr ("Failed to start OmniRig COM server"));
135         }
136 
137       // COM/OLE exceptions get signaled
138       connect (&*omni_rig_, SIGNAL (exception (int, QString, QString, QString)), this, SLOT (handle_COM_exception (int, QString, QString, QString)));
139 
140       // IOmniRigXEvent interface signals
141       connect (&*omni_rig_, SIGNAL (VisibleChange ()), this, SLOT (handle_visible_change ()));
142       connect (&*omni_rig_, SIGNAL (RigTypeChange (int)), this, SLOT (handle_rig_type_change (int)));
143       connect (&*omni_rig_, SIGNAL (StatusChange (int)), this, SLOT (handle_status_change (int)));
144       connect (&*omni_rig_, SIGNAL (ParamsChange (int, int)), this, SLOT (handle_params_change (int, int)));
145       connect (&*omni_rig_
146                , SIGNAL (CustomReply (int, QVariant const&, QVariant const&))
147                , this, SLOT (handle_custom_reply (int, QVariant const&, QVariant const&)));
148 
149       CAT_INFO ("OmniRig s/w version: " << static_cast<quint16> (omni_rig_->SoftwareVersion () >> 16)
150                 << '.' << static_cast<quint16> (omni_rig_->SoftwareVersion () & 0xffff)
151                 << " i/f version: " << static_cast<int> (omni_rig_->InterfaceVersion () >> 8 & 0xff)
152                 << '.' << static_cast<int> (omni_rig_->InterfaceVersion () && 0xff));
153 
154       // fetch the interface of the RigX CoClass and instantiate a proxy object
155       switch (rig_number_)
156         {
157         case One: rig_.reset (new OmniRig::RigX (omni_rig_->Rig1 ())); break;
158         case Two: rig_.reset (new OmniRig::RigX (omni_rig_->Rig2 ())); break;
159         }
160 
161       Q_ASSERT (rig_);
162       Q_ASSERT (!rig_->isNull ());
163 
164       // COM/OLE exceptions get signaled
165       connect (&*rig_, SIGNAL (exception (int, QString, QString, QString)), this, SLOT (handle_COM_exception (int, QString, QString, QString)));
166 
167       offline_timer_.reset (new QTimer); // instantiate here as constructor runs in wrong thread
168       offline_timer_->setSingleShot (true);
169       connect (offline_timer_.data (), &QTimer::timeout, [this] () {offline ("Rig went offline");});
170 
171       for (int i = 0; i < 5; ++i)
172         {
173           // leave some time for Omni-Rig to do its first poll
174           QThread::msleep (250);
175           if (OmniRig::ST_ONLINE == rig_->Status ())
176             {
177               break;
178             }
179         }
180 
181       if (OmniRig::ST_ONLINE != rig_->Status ())
182         {
183           CAT_ERROR ("rig not online");
184           throw_qstring ("OmniRig: " + rig_->StatusStr ());
185         }
186 
187       if (use_for_ptt_ && (TransceiverFactory::PTT_method_DTR == ptt_type_ || TransceiverFactory::PTT_method_RTS == ptt_type_))
188         {
189           // fetch the interface for the serial port if we need it for PTT
190           port_.reset (new OmniRig::PortBits (rig_->PortBits ()));
191 
192           Q_ASSERT (port_);
193           Q_ASSERT (!port_->isNull ());
194 
195           // COM/OLE exceptions get signaled
196           connect (&*port_, SIGNAL (exception (int, QString, QString, QString)), this, SLOT (handle_COM_exception (int, QString, QString, QString)));
197 
198           CAT_TRACE ("OmniRig RTS state: " << port_->Rts ());
199 
200           // remove locking because it doesn't seem to work properly
201           // if (!port_->Lock ()) // try to take exclusive use of the OmniRig serial port for PTT
202           //   {
203           //     CAT_WARNING ("Failed to get exclusive use of serial port for PTT from OmniRig");
204           //   }
205 
206           // start off so we don't accidentally key the radio
207           if (TransceiverFactory::PTT_method_DTR == ptt_type_)
208             {
209               port_->SetDtr (false);
210             }
211           else      // RTS
212             {
213               port_->SetRts (false);
214             }
215         }
216 
217       rig_type_ = rig_->RigType ();
218       readable_params_ = rig_->ReadableParams ();
219       writable_params_ = rig_->WriteableParams ();
220 
221       CAT_INFO (QString {"OmniRig initial rig type: %1 readable params=0x%2 writable params=0x%3 for rig %4"}
222          .arg (rig_type_)
223          .arg (readable_params_, 8, 16, QChar ('0'))
224          .arg (writable_params_, 8, 16, QChar ('0'))
225          .arg (rig_number_));
226       update_rx_frequency (rig_->GetRxFrequency ());
227       int resolution {0};
228       if (OmniRig::PM_UNKNOWN == rig_->Vfo ()
229           && (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
230           == (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
231         {
232           // start with VFO A (probably MAIN) on rigs that we
233           // can't query VFO but can set explicitly
234           rig_->SetVfo (OmniRig::PM_VFOA);
235         }
236       auto f = state ().frequency ();
237       if (f % 10) return resolution; // 1Hz resolution
238       auto test_frequency = f - f % 100 + 55;
239       if (OmniRig::PM_FREQ & writable_params_)
240         {
241           rig_->SetFreq (test_frequency);
242         }
243       else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
244         {
245           rig_->SetFreqB (test_frequency);
246         }
247       else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
248         {
249           rig_->SetFreqA (test_frequency);
250         }
251       else
252         {
253           throw_qstring (tr ("OmniRig: don't know how to set rig frequency"));
254         }
255       switch (rig_->GetRxFrequency () - test_frequency)
256         {
257         case -5: resolution = -1; break;  // 10Hz truncated
258         case 5: resolution = 1; break;    // 10Hz rounded
259         case -15: resolution = -2; break; // 20Hz truncated
260         case -55: resolution = -2; break; // 100Hz truncated
261         case 45: resolution = 2; break;   // 100Hz rounded
262         }
263       if (1 == resolution)  // may be 20Hz rounded
264         {
265           test_frequency = f - f % 100 + 51;
266           if (OmniRig::PM_FREQ & writable_params_)
267             {
268               rig_->SetFreq (test_frequency);
269             }
270           else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
271             {
272               rig_->SetFreqB (test_frequency);
273             }
274           else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
275             {
276               rig_->SetFreqA (test_frequency);
277             }
278           if (9 == rig_->GetRxFrequency () - test_frequency)
279             {
280               resolution = 2;   // 20Hz rounded
281             }
282         }
283       if (OmniRig::PM_FREQ & writable_params_)
284         {
285           rig_->SetFreq (f);
286         }
287       else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
288         {
289           rig_->SetFreqB (f);
290         }
291       else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
292         {
293           rig_->SetFreqA (f);
294         }
295       update_rx_frequency (f);
296       CAT_TRACE ("started");
297 
298       return resolution;
299     }
300   catch (...)
301     {
302       CAT_TRACE ("start threw exception");
303       throw;
304     }
305 }
306 
do_stop()307 void OmniRigTransceiver::do_stop ()
308 {
309   CAT_TRACE ("stopping");
310   QThread::msleep (200);        // leave some time for pending
311                                 // commands at the server end
312 
313   offline_timer_.reset ();      // destroy here rather than in
314                                 // destructor as destructor runs in
315                                 // wrong thread
316 
317   if (port_ && !port_->isNull ())
318     {
319       // port_->Unlock ();   // release serial port
320       port_->clear ();
321       port_.reset ();
322     }
323   if (omni_rig_ && !omni_rig_->isNull ())
324     {
325       if (rig_ && !rig_->isNull ())
326         {
327           rig_->clear ();
328           rig_.reset ();
329           CAT_TRACE ("rig_ reset");
330         }
331       omni_rig_->clear ();
332       omni_rig_.reset ();
333     }
334 
335   if (wrapped_) wrapped_->stop ();
336 
337   CAT_TRACE ("stopped");
338 }
339 
handle_COM_exception(int code,QString source,QString desc,QString help)340 void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help)
341 {
342   CAT_ERROR ((QString::number (code) + " at " + source + ": " + desc + " (" + help + ')'));
343   throw_qstring (tr ("OmniRig COM/OLE error: %1 at %2: %3 (%4)").arg (QString::number (code)).arg (source). arg (desc). arg (help));
344 }
345 
handle_visible_change()346 void OmniRigTransceiver::handle_visible_change ()
347 {
348   if (!omni_rig_ || omni_rig_->isNull ()) return;
349   CAT_TRACE ("visibility change: visibility =" << omni_rig_->DialogVisible ());
350 }
351 
handle_rig_type_change(int rig_number)352 void OmniRigTransceiver::handle_rig_type_change (int rig_number)
353 {
354   CAT_TRACE ("rig type change: rig =" << rig_number);
355   if (rig_number_ == rig_number)
356     {
357       if (!rig_ || rig_->isNull ()) return;
358       readable_params_ = rig_->ReadableParams ();
359       writable_params_ = rig_->WriteableParams ();
360       CAT_INFO (QString {"rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
361         .arg (rig_->RigType ())
362         .arg (readable_params_, 8, 16, QChar ('0'))
363         .arg (writable_params_, 8, 16, QChar ('0'))
364         .arg (rig_number));
365     }
366 }
367 
handle_status_change(int rig_number)368 void OmniRigTransceiver::handle_status_change (int rig_number)
369 {
370   CAT_TRACE (QString {"status change for rig %1"}.arg (rig_number));
371   if (rig_number_ == rig_number)
372     {
373       if (!rig_ || rig_->isNull ()) return;
374       auto const& status = rig_->StatusStr ();
375       CAT_TRACE ("OmniRig status change: new status = " << status);
376       if (OmniRig::ST_ONLINE != rig_->Status ())
377         {
378           if (!offline_timer_->isActive ())
379             {
380               // Omni-Rig is prone to reporting the rig offline and
381               // then recovering autonomously, so we will give it a
382               // few seconds to make its mind up
383               offline_timer_->start (10000);
384             }
385         }
386       else
387         {
388           offline_timer_->stop (); // good to go again
389         }
390       // else
391       //   {
392       //     update_rx_frequency (rig_->GetRxFrequency ());
393       //     update_complete ();
394       //     CAT_TRACE ("frequency:" << state ().frequency ());
395       //   }
396     }
397 }
398 
handle_params_change(int rig_number,int params)399 void OmniRigTransceiver::handle_params_change (int rig_number, int params)
400 {
401   CAT_TRACE (QString {"params change: params=0x%1 for rig %2"}
402         .arg (params, 8, 16, QChar ('0'))
403         .arg (rig_number)
404         << "state before:" << state ());
405   if (rig_number_ == rig_number)
406     {
407       if (!rig_ || rig_->isNull ()) return;
408       //      starting_ = false;
409       TransceiverState old_state {state ()};
410       auto need_frequency = false;
411 
412       if (params & OmniRig::PM_VFOAA)
413         {
414           CAT_TRACE ("VFOAA");
415           update_split (false);
416           reversed_ = false;
417           update_rx_frequency (rig_->FreqA ());
418           update_other_frequency (rig_->FreqB ());
419         }
420       if (params & OmniRig::PM_VFOAB)
421         {
422           CAT_TRACE ("VFOAB");
423           update_split (true);
424           reversed_ = false;
425           update_rx_frequency (rig_->FreqA ());
426           update_other_frequency (rig_->FreqB ());
427         }
428       if (params & OmniRig::PM_VFOBA)
429         {
430           CAT_TRACE ("VFOBA");
431           update_split (true);
432           reversed_ = true;
433           update_other_frequency (rig_->FreqA ());
434           update_rx_frequency (rig_->FreqB ());
435         }
436       if (params & OmniRig::PM_VFOBB)
437         {
438           CAT_TRACE ("VFOBB");
439           update_split (false);
440           reversed_ = true;
441           update_other_frequency (rig_->FreqA ());
442           update_rx_frequency (rig_->FreqB ());
443         }
444       if (params & OmniRig::PM_VFOA)
445         {
446           CAT_TRACE ("VFOA");
447           reversed_ = false;
448           need_frequency = true;
449         }
450       if (params & OmniRig::PM_VFOB)
451         {
452           CAT_TRACE ("VFOB");
453           reversed_ = true;
454           need_frequency = true;
455         }
456 
457       if (params & OmniRig::PM_FREQ)
458         {
459           need_frequency = true;
460         }
461       if (params & OmniRig::PM_FREQA)
462         {
463           auto f = rig_->FreqA ();
464           CAT_TRACE ("FREQA = " << f);
465           if (reversed_)
466             {
467               update_other_frequency (f);
468             }
469           else
470             {
471               update_rx_frequency (f);
472             }
473         }
474       if (params & OmniRig::PM_FREQB)
475         {
476           auto f = rig_->FreqB ();
477           CAT_TRACE ("FREQB = " << f);
478           if (reversed_)
479             {
480               update_rx_frequency (f);
481             }
482           else
483             {
484               update_other_frequency (f);
485             }
486         }
487       if (need_frequency)
488         {
489           if (readable_params_ & OmniRig::PM_FREQA)
490             {
491               auto f = rig_->FreqA ();
492               if (f)
493                 {
494                   CAT_TRACE ("FREQA = " << f);
495                   if (reversed_)
496                     {
497                       update_other_frequency (f);
498                     }
499                   else
500                     {
501                       update_rx_frequency (f);
502                     }
503                 }
504             }
505           if (readable_params_ & OmniRig::PM_FREQB)
506             {
507               auto f = rig_->FreqB ();
508               if (f)
509                 {
510                   CAT_TRACE ("FREQB = " << f);
511                   if (reversed_)
512                     {
513                       update_rx_frequency (f);
514                     }
515                   else
516                     {
517                       update_other_frequency (f);
518                     }
519                 }
520             }
521           if (readable_params_ & OmniRig::PM_FREQ && !state ().ptt ())
522             {
523               auto f = rig_->Freq ();
524               if (f)
525                 {
526                   CAT_TRACE ("FREQ = " << f);
527                   update_rx_frequency (f);
528                 }
529             }
530         }
531       if (params & OmniRig::PM_PITCH)
532         {
533           CAT_TRACE ("PITCH");
534         }
535       if (params & OmniRig::PM_RITOFFSET)
536         {
537           CAT_TRACE ("RITOFFSET");
538         }
539       if (params & OmniRig::PM_RIT0)
540         {
541           CAT_TRACE ("RIT0");
542         }
543       if (params & OmniRig::PM_VFOEQUAL)
544         {
545           auto f = readable_params_ & OmniRig::PM_FREQA ? rig_->FreqA () : rig_->Freq ();
546           auto m = map_mode (rig_->Mode ());
547           CAT_TRACE (QString {"VFOEQUAL f=%1 m=%2"}.arg (f).arg (m));
548           update_rx_frequency (f);
549           update_other_frequency (f);
550           update_mode (m);
551         }
552       if (params & OmniRig::PM_VFOSWAP)
553         {
554           CAT_TRACE ("VFOSWAP");
555           auto f = state ().tx_frequency ();
556           update_other_frequency (state ().frequency ());
557           update_rx_frequency (f);
558           update_mode (map_mode (rig_->Mode ()));
559         }
560       if (params & OmniRig::PM_SPLITON)
561         {
562           CAT_TRACE ("SPLITON");
563           update_split (true);
564         }
565       if (params & OmniRig::PM_SPLITOFF)
566         {
567           CAT_TRACE ("SPLITOFF");
568           update_split (false);
569         }
570       if (params & OmniRig::PM_RITON)
571         {
572           CAT_TRACE ("RITON");
573         }
574       if (params & OmniRig::PM_RITOFF)
575         {
576           CAT_TRACE ("RITOFF");
577         }
578       if (params & OmniRig::PM_XITON)
579         {
580           CAT_TRACE ("XITON");
581         }
582       if (params & OmniRig::PM_XITOFF)
583         {
584           CAT_TRACE ("XITOFF");
585         }
586       if (params & OmniRig::PM_RX)
587         {
588           CAT_TRACE ("RX");
589           update_PTT (false);
590         }
591       if (params & OmniRig::PM_TX)
592         {
593           CAT_TRACE ("TX");
594           update_PTT ();
595         }
596       if (params & OmniRig::PM_CW_U)
597         {
598           CAT_TRACE ("CW-R");
599           update_mode (CW_R);
600         }
601       if (params & OmniRig::PM_CW_L)
602         {
603           CAT_TRACE ("CW");
604           update_mode (CW);
605         }
606       if (params & OmniRig::PM_SSB_U)
607         {
608           CAT_TRACE ("USB");
609           update_mode (USB);
610         }
611       if (params & OmniRig::PM_SSB_L)
612         {
613           CAT_TRACE ("LSB");
614           update_mode (LSB);
615         }
616       if (params & OmniRig::PM_DIG_U)
617         {
618           CAT_TRACE ("DATA-U");
619           update_mode (DIG_U);
620         }
621       if (params & OmniRig::PM_DIG_L)
622         {
623           CAT_TRACE ("DATA-L");
624           update_mode (DIG_L);
625         }
626       if (params & OmniRig::PM_AM)
627         {
628           CAT_TRACE ("AM");
629           update_mode (AM);
630         }
631       if (params & OmniRig::PM_FM)
632         {
633           CAT_TRACE ("FM");
634           update_mode (FM);
635         }
636 
637       if (old_state != state () || send_update_signal_)
638         {
639           update_complete ();
640           send_update_signal_ = false;
641         }
642       CAT_TRACE ("OmniRig params change: state after:" << state ());
643     }
644 }
645 
handle_custom_reply(int rig_number,QVariant const & command,QVariant const & reply)646 void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& command, QVariant const& reply)
647 {
648   (void)command;
649   (void)reply;
650 
651   if (rig_number_ == rig_number)
652     {
653       if (!rig_ || rig_->isNull ()) return;
654       CAT_TRACE ("custom command" << command.toString ()
655                  << "with reply" << reply.toString ()
656                  << QString ("for rig %1").arg (rig_number));
657       CAT_TRACE ("rig number:" << rig_number_ << ':' << state ());
658     }
659 }
660 
do_ptt(bool on)661 void OmniRigTransceiver::do_ptt (bool on)
662 {
663   CAT_TRACE (on << state ());
664   if (use_for_ptt_ && TransceiverFactory::PTT_method_CAT == ptt_type_)
665     {
666       CAT_TRACE ("set PTT");
667       if (rig_ && !rig_->isNull ())
668         {
669           rig_->SetTx (on ? OmniRig::PM_TX : OmniRig::PM_RX);
670         }
671     }
672   else
673     {
674       if (port_ && !port_->isNull ())
675         {
676           if (TransceiverFactory::PTT_method_RTS == ptt_type_)
677             {
678               CAT_TRACE ("set RTS");
679               port_->SetRts (on);
680             }
681           else      // "DTR"
682             {
683               CAT_TRACE ("set DTR");
684               port_->SetDtr (on);
685             }
686         }
687       else if (wrapped_)
688         {
689           CAT_TRACE ("set PTT using basic transceiver");
690           TransceiverState new_state {wrapped_->state ()};
691           new_state.ptt (on);
692           wrapped_->set (new_state, 0);
693         }
694     }
695   update_PTT (on);
696 }
697 
do_frequency(Frequency f,MODE m,bool)698 void OmniRigTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
699 {
700   CAT_TRACE (f << ' ' << state ());
701   if (!rig_ || rig_->isNull ()) return;
702   if (UNK != m)
703     {
704       do_mode (m);
705     }
706   if (OmniRig::PM_FREQ & writable_params_)
707     {
708       rig_->SetFreq (f);
709       update_rx_frequency (f);
710     }
711   else if (reversed_ && (OmniRig::PM_FREQB & writable_params_))
712     {
713       rig_->SetFreqB (f);
714       update_rx_frequency (f);
715     }
716   else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_))
717     {
718       rig_->SetFreqA (f);
719       update_rx_frequency (f);
720     }
721   else
722     {
723       throw_qstring (tr ("OmniRig: don't know how to set rig frequency"));
724     }
725 }
726 
do_tx_frequency(Frequency tx,MODE m,bool)727 void OmniRigTransceiver::do_tx_frequency (Frequency tx, MODE m, bool /*no_ignore*/)
728 {
729   CAT_TRACE (tx << ' ' << state ());
730   if (!rig_ || rig_->isNull ()) return;
731   bool split {tx != 0};
732   if (split)
733     {
734       if (UNK != m)
735         {
736           do_mode (m);
737           if (OmniRig::PM_UNKNOWN == rig_->Vfo ())
738             {
739               if (writable_params_ & OmniRig::PM_VFOEQUAL)
740                 {
741                   // nothing to do here because OmniRig will use VFO
742                   // equalize to set the mode of the Tx VFO for us
743                 }
744               else if ((writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
745                    == (OmniRig::PM_VFOA | OmniRig::PM_VFOB))
746                 {
747                   rig_->SetVfo (OmniRig::PM_VFOB);
748                   do_mode (m);
749                   rig_->SetVfo (OmniRig::PM_VFOA);
750                 }
751               else if (writable_params_ & OmniRig::PM_VFOSWAP)
752                 {
753                   rig_->SetVfo (OmniRig::PM_VFOSWAP);
754                   do_mode (m);
755                   rig_->SetVfo (OmniRig::PM_VFOSWAP);
756                 }
757             }
758         }
759       CAT_TRACE ("set SPLIT mode on");
760       rig_->SetSplitMode (state ().frequency (), tx);
761       update_other_frequency (tx);
762       update_split (true);
763     }
764   else
765     {
766       CAT_TRACE ("set SPLIT mode off");
767       rig_->SetSimplexMode (state ().frequency ());
768       update_split (false);
769     }
770   bool notify {false};
771   if (readable_params_ & OmniRig::PM_FREQ || !(readable_params_ & (OmniRig::PM_FREQA | OmniRig::PM_FREQB)))
772     {
773       update_other_frequency (tx); // async updates won't return this
774       // so just store it and hope
775       // operator doesn't change the
776       // "back" VFO on rig
777       notify = true;
778     }
779   if (!((OmniRig::PM_VFOAB | OmniRig::PM_VFOBA | OmniRig::PM_SPLITON) & readable_params_))
780     {
781       CAT_TRACE ("setting SPLIT manually");
782       update_split (split); // we can't read it so just set and
783       // hope op doesn't change it
784       notify = true;
785     }
786   if (notify)
787     {
788       update_complete ();
789     }
790 }
791 
do_mode(MODE mode)792 void OmniRigTransceiver::do_mode (MODE mode)
793 {
794   CAT_TRACE (mode << ' ' << state ());
795   if (!rig_ || rig_->isNull ()) return;
796   // TODO: G4WJS OmniRig doesn't seem to have any capability of tracking/setting VFO B mode
797   auto mapped = map_mode (mode);
798   if (mapped & writable_params_)
799     {
800       rig_->SetMode (mapped);
801       update_mode (mode);
802     }
803   else
804     {
805       offline ("OmniRig invalid mode");
806     }
807 }
808