1 // Copyright (c) Charles J. Cliffe
2 // SPDX-License-Identifier: GPL-2.0+
3 
4 #include "RigThread.h"
5 
6 std::vector<const struct rig_caps *> RigThread::rigCaps;
7 
RigThread()8 RigThread::RigThread() {
9     freq = wxGetApp().getFrequency();
10     newFreq = freq;
11     freqChanged.store(true);
12     termStatus = 0;
13     controlMode.store(true);
14     followMode.store(true);
15     centerLock.store(false);
16     followModem.store(false);
17     errorState.store(false);
18     errorMessage = "";
19 }
20 
21 RigThread::~RigThread() = default;
22 
enumerate()23 RigList &RigThread::enumerate() {
24     if (RigThread::rigCaps.empty()) {
25         rig_set_debug(RIG_DEBUG_ERR);
26         rig_load_all_backends();
27 
28         rig_list_foreach(RigThread::add_hamlib_rig, nullptr);
29         std::sort(RigThread::rigCaps.begin(), RigThread::rigCaps.end(), rigGreater());
30         std::cout << "Loaded " << RigThread::rigCaps.size() << " rig models via hamlib." << std::endl;
31     }
32     return RigThread::rigCaps;
33 }
34 
add_hamlib_rig(const struct rig_caps * rc,void *)35 int RigThread::add_hamlib_rig(const struct rig_caps *rc, void* /* f */)
36 {
37     rigCaps.push_back(rc);
38     return 1;
39 }
40 
initRig(rig_model_t rig_model,std::string rig_file,int serial_rate)41 void RigThread::initRig(rig_model_t rig_model, std::string rig_file, int serial_rate) {
42     rigModel = rig_model;
43     rigFile = rig_file;
44     serialRate = serial_rate;
45 }
46 
setErrorStateFromHamlibCode(int errcode)47 void RigThread::setErrorStateFromHamlibCode(int errcode) {
48     errorState.store(true);
49     switch (abs(errcode)) {
50         case RIG_EINVAL:
51             errorMessage = "Invalid parameter specified.";
52             break; /*!< invalid parameter */
53         case RIG_ECONF:
54             errorMessage = "Invalid configuration i.e. serial, etc.";
55             break; /*!< invalid configuration (serial,..) */
56         case RIG_ENOMEM:
57             errorMessage = "Out of memory.";
58             break; /*!< memory shortage */
59         case RIG_ENIMPL:
60             errorMessage = "Function Not Yet Implemented.";
61             break; /*!< function not implemented, but will be */
62         case RIG_ETIMEOUT:
63             errorMessage = "Communication timed out.";
64             break; /*!< communication timed out */
65         case RIG_EIO:
66             errorMessage = "I/O error (Open failed?)";
67             break; /*!< IO error, including open failed */
68         case RIG_EINTERNAL:
69             errorMessage = "Internal hamlib error :(";
70             break; /*!< Internal Hamlib error, huh! */
71         case RIG_EPROTO:
72             errorMessage = "Protocol Error.";
73             break; /*!< Protocol error */
74         case RIG_ERJCTED:
75             errorMessage = "Command rejected by rig.";
76             break; /*!< Command rejected by the rig */
77         case RIG_ETRUNC:
78             errorMessage = "Argument truncated.";
79             break; /*!< Command performed, but arg truncated */
80         case RIG_ENAVAIL:
81             errorMessage = "Function not available.";
82             break; /*!< function not available */
83         case RIG_ENTARGET:
84             errorMessage = "VFO not targetable.";
85             break; /*!< VFO not targetable */
86         case RIG_BUSERROR:
87             errorMessage = "Error talking on the bus.";
88             break; /*!< Error talking on the bus */
89         case RIG_BUSBUSY:
90             errorMessage = "Collision on the bus.";
91             break; /*!< Collision on the bus */
92         case RIG_EARG:
93             errorMessage = "Invalid rig handle.";
94             break; /*!< NULL RIG handle or any invalid pointer parameter in get arg */
95         case RIG_EVFO:
96             errorMessage = "Invalid VFO.";
97             break; /*!< Invalid VFO */
98         case RIG_EDOM:
99             errorMessage = "Argument out of domain of function.";
100             break; /*!< Argument out of domain of func */
101     }
102 
103     std::cout << "Rig error: " << errorMessage << std::endl;
104 }
105 
run()106 void RigThread::run() {
107     int retcode, status;
108 
109     termStatus = 0;
110     errorState.store(false);
111 
112     std::cout << "Rig thread starting." << std::endl;
113 
114     rig = rig_init(rigModel);
115 	strncpy(rig->state.rigport.pathname, rigFile.c_str(), FILPATHLEN - 1);
116 	rig->state.rigport.parm.serial.rate = serialRate;
117 	retcode = rig_open(rig);
118 
119     if (retcode != 0) {
120         setErrorStateFromHamlibCode(retcode);
121         IOThread::terminate();
122         return;
123     }
124 
125 	char *info_buf = (char *)rig_get_info(rig);
126 
127     if (info_buf) {
128         std::cout << "Rig info: " << info_buf << std::endl;
129     } else {
130         std::cout << "Rig info was NULL." << std::endl;
131     }
132 
133     while (!stopping) {
134         std::this_thread::sleep_for(std::chrono::milliseconds(150));
135 
136         auto activeDemod = wxGetApp().getDemodMgr().getActiveContextModem();
137         auto lastDemod = wxGetApp().getDemodMgr().getCurrentModem();
138 
139         if (freqChanged.load() && (controlMode.load() || setOneShot.load())) {
140             status = rig_get_freq(rig, RIG_VFO_CURR, &freq);
141             if (status == 0 && !stopping) {
142 
143                 if (freq != newFreq && setOneShot.load()) {
144                     freq = newFreq;
145                     rig_set_freq(rig, RIG_VFO_CURR, freq);
146     //                std::cout << "Set Rig Freq: %f" <<  newFreq << std::endl;
147                 }
148 
149                 freqChanged.store(false);
150                 setOneShot.store(false);
151             } else {
152                 if (status == -RIG_ENIMPL) {
153                     std::cout << "Rig does not support rig_get_freq?" << std::endl;
154                 } else {
155                     termStatus = status;
156                     break;
157                 }
158             }
159         } else {
160             freq_t checkFreq;
161 
162             status = rig_get_freq(rig, RIG_VFO_CURR, &checkFreq);
163 
164             if (status == 0 && !stopping) {
165                 if (checkFreq != freq && followMode.load()) {
166                     freq = checkFreq;
167                     if (followModem.load()) {
168                         if (lastDemod) {
169                             lastDemod->setFrequency(freq);
170                             lastDemod->updateLabel(freq);
171                             lastDemod->setFollow(true);
172                         }
173                     } else {
174                         wxGetApp().setFrequency((long long)checkFreq);
175                     }
176                 } else if (wxGetApp().getFrequency() != freq && controlMode.load() && !centerLock.load() && !followModem.load()) {
177                     freq = wxGetApp().getFrequency();
178                     status = rig_set_freq(rig, RIG_VFO_CURR, freq);
179                     if (status == -RIG_ENIMPL) {
180                         std::cout << "Rig does not support rig_set_freq?" << std::endl;
181                     } else if (status != 0) {
182                         termStatus = status;
183                         break;
184                     }
185                 } else if (followModem.load()) {
186                     if (lastDemod) {
187                         if (lastDemod->getFrequency() != freq) {
188                             lastDemod->setFrequency(freq);
189                             lastDemod->updateLabel(freq);
190                             lastDemod->setFollow(true);
191                         }
192                     }
193                 }
194             } else {
195                 if (status == -RIG_ENIMPL) {
196                     std::cout << "Rig does not support rig_get_freq?" << std::endl;
197                 } else {
198                     termStatus = status;
199                     break;
200                 }
201             }
202         }
203 
204         if (!centerLock.load() && followModem.load() && wxGetApp().getFrequency() != freq && (lastDemod && lastDemod != activeDemod)) {
205             wxGetApp().setFrequency((long long)freq);
206         }
207 
208 //        std::cout <<  "Rig Freq: " << freq << std::endl;
209     }
210 
211     rig_close(rig);
212     rig_cleanup(rig);
213 
214     if (termStatus != 0) {
215         setErrorStateFromHamlibCode(termStatus);
216     }
217 
218     std::cout << "Rig thread exiting status " << termStatus << "." << std::endl;
219 }
220 
getFrequency()221 freq_t RigThread::getFrequency() {
222     if (freqChanged.load() && (setOneShot.load() || controlMode.load())) {
223         return newFreq;
224     } else {
225         return freq;
226     }
227 }
228 
setFrequency(freq_t new_freq,bool oneShot)229 void RigThread::setFrequency(freq_t new_freq, bool oneShot) {
230     newFreq = new_freq;
231     freqChanged.store(true);
232     setOneShot.store(oneShot);
233 }
234 
setControlMode(bool cMode)235 void RigThread::setControlMode(bool cMode) {
236     controlMode.store(cMode);
237 }
238 
getControlMode()239 bool RigThread::getControlMode() {
240     return controlMode.load();
241 }
242 
setFollowMode(bool fMode)243 void RigThread::setFollowMode(bool fMode) {
244     followMode.store(fMode);
245 }
246 
getFollowMode()247 bool RigThread::getFollowMode() {
248     return followMode.load();
249 }
250 
setCenterLock(bool cLock)251 void RigThread::setCenterLock(bool cLock) {
252     centerLock.store(cLock);
253 }
254 
getCenterLock()255 bool RigThread::getCenterLock() {
256     return centerLock.load();
257 }
258 
setFollowModem(bool mFollow)259 void RigThread::setFollowModem(bool mFollow) {
260     followModem.store(mFollow);
261 }
262 
getFollowModem()263 bool RigThread::getFollowModem() {
264     return followModem.load();
265 }
266 
267 
getErrorState()268 bool RigThread::getErrorState() {
269     return errorState.load();
270 }
271 
getErrorMessage()272 std::string RigThread::getErrorMessage() {
273     return errorMessage;
274 }
275