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