1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 //              David Freese, W1HKJ
4 //
5 // This file is part of flrig.
6 //
7 // flrig is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // flrig is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // aunsigned long int with this program.  If not, see <http://www.gnu.org/licenses/>.
19 // ----------------------------------------------------------------------------
20 
21 #include <iostream>
22 
23 #include "ICbase.h"
24 #include "debug.h"
25 #include "support.h"
26 #include "icons.h"
27 #include "tod_clock.h"
28 #include "trace.h"
29 #include "status.h"
30 #include "threads.h"
31 
32 pthread_mutex_t command_mutex = PTHREAD_MUTEX_INITIALIZER;
33 
34 //=============================================================================
35 
adjustCIV(uchar adr)36 void RIG_ICOM::adjustCIV(uchar adr)
37 {
38 	CIV = adr;
39 	pre_to[2] = ok[3] = bad[3] = pre_fm[3] = CIV;
40 }
41 
checkresponse()42 void RIG_ICOM::checkresponse()
43 {
44 	if (!progStatus.use_tcpip && !RigSerial->IsOpen())
45 		return;
46 
47 	if (replystr.rfind(ok) != string::npos)
48 		return;
49 
50 	string s1 = str2hex(cmd.c_str(), cmd.length());
51 	string s2 = str2hex(replystr.c_str(), replystr.length());
52 	LOG_ERROR("\nsent  %s\nreply %s", s1.c_str(), s2.c_str());
53 }
54 
sendICcommand(string cmd,int nbr)55 bool RIG_ICOM::sendICcommand(string cmd, int nbr)
56 {
57 	guard_lock reply_lock(&mutex_replystr);
58 
59 	int ret = sendCommand(cmd);
60 
61 	if (!progStatus.use_tcpip && !RigSerial->IsOpen())
62 		return false;
63 
64 	if (ret < nbr) {
65 		LOG_ERROR("Expected %d received %d", nbr, ret);
66 		return false;
67 	}
68 
69 	if (ret > nbr) respstr.erase(0, ret - nbr);
70 
71 // look for preamble at beginning
72 	if (respstr.rfind(pre_fm) == string::npos)  {
73 		LOG_ERROR("preamble: %s not in %s", pre_fm.c_str(), cmd.c_str());
74 		replystr.clear();
75 		return false;
76 	}
77 
78 // look for postamble
79 	if (respstr.rfind(post) == string::npos) {
80 		LOG_ERROR("postample: %s not at end of %s", post.c_str(), cmd.c_str());
81 		replystr.clear();
82 		return false;
83 	}
84 	replystr = respstr;
85 	return true;
86 }
87 
delayCommand(string cmd,int wait)88 void RIG_ICOM::delayCommand(string cmd, int wait)
89 {
90 	int oldwait = progStatus.comm_wait;
91 	progStatus.comm_wait += wait;
92 	sendCommand(cmd);
93 	progStatus.comm_wait = oldwait;
94 }
95 
96 #include <fstream>
97 
ICtrace(string cmd,string hexstr)98 void RIG_ICOM::ICtrace(string cmd, string hexstr)
99 {
100 	string s1 = str2hex(hexstr.c_str(), hexstr.length());
101 	rig_trace(2, cmd.c_str(), s1.c_str());
102 }
103 
waitFB(const char * sz,int timeout)104 bool RIG_ICOM::waitFB(const char *sz, int timeout)
105 {
106 	guard_lock cmd_lock(&command_mutex);
107 
108 	guard_lock reply_lock(&mutex_replystr);
109 //std::cout << ztime() << " waitFB( " << sz << ", " << timeout << " ): " << str2hex(cmd.c_str(), cmd.length()) << std::endl;
110 
111 	char sztemp[100];
112 	string returned = "";
113 	string tosend = cmd;
114 	unsigned long int msec_start = 0;
115 	int diff;
116 
117 	if (!progStatus.use_tcpip && !RigSerial->IsOpen()) {
118 		replystr = cmd;//returned;
119 		return false;
120 	}
121 	int num = cmd.length() + ok.length();
122 
123 	int wait_msec = progStatus.use_tcpip ? progStatus.tcpip_ping_delay : 0;
124 	wait_msec += 100;
125 	wait_msec += num * 11000.0 / RigSerial->Baud();
126 
127 	timeout += wait_msec;
128 
129 	unsigned long int loop_start;
130 
131 	msec_start = zmsec();
132 
133 	respstr.clear();
134 	sendCommand(cmd, 0);
135 	returned.clear();
136 	loop_start = zmsec();
137 	diff = zmsec() - loop_start;
138 
139 	while ( diff < timeout) { //wait_msec + 10 ) {
140 		returned.append(respstr);
141 		if (returned.find(ok) != string::npos) {
142 			replystr = returned;
143 			unsigned long int waited = zmsec() - msec_start;
144 			snprintf(sztemp, sizeof(sztemp), "%s ans in %ld ms, OK", sz, waited);
145 			showresp(DEBUG, HEX, sztemp, tosend, returned);
146 //std::cout << ztime() << " Response: " << str2hex(returned.c_str(), returned.length()) << std::endl;
147 			return true;
148 		}
149 		if (returned.find(bad) != string::npos) {
150 			replystr = returned;
151 			unsigned long int waited = zmsec() - msec_start;
152 			snprintf(sztemp, sizeof(sztemp), "%s ans in %ld ms, FAILED", sz, waited);
153 			showresp(ERR, HEX, sztemp, tosend, returned);
154 //std::cout << ztime() << " ERROR: " << str2hex(returned.c_str(), returned.length()) << std::endl;
155 			return false;
156 		}
157 		readResponse();
158 		diff = zmsec() - loop_start;
159 	}
160 
161 	diff = zmsec() - msec_start;
162 	replystr = returned;
163 	snprintf(sztemp, sizeof(sztemp), "%s TIMED OUT : %d ms", sz, diff);
164 	showresp(ERR, HEX, sztemp, tosend, returned);
165 //std::cout << ztime() << " TIMED OUT: " << str2hex(returned.c_str(), returned.length()) << std::endl;
166 
167 	return false;
168 }
169 
waitFOR(size_t n,const char * sz,int timeout)170 bool RIG_ICOM::waitFOR(size_t n, const char *sz, int timeout)
171 {
172 	guard_lock cmd_lock(&command_mutex);
173 
174 	guard_lock reply_lock(&mutex_replystr);
175 
176 //std::cout << ztime() << " waitFOR( " << n << ", " << sz << ", " << timeout << " ): " << str2hex(cmd.c_str(), cmd.length()) << std::endl;
177 
178 	char sztemp[100];
179 	string returned = "";
180 	string tosend = cmd;
181 	size_t num = n;
182 	int diff = 0;
183 	if (progStatus.comm_echo) num += cmd.length();
184 
185 	unsigned long int msec_start;
186 	unsigned long int repeat_start;
187 
188 	int delay = progStatus.use_tcpip ? progStatus.tcpip_ping_delay : 0;
189 	delay += 100;
190 	delay += num * 11000.0 / RigSerial->Baud();
191 
192 	if (!progStatus.use_tcpip && !RigSerial->IsOpen()) {
193 		replystr = cmd;
194 		return false;
195 	}
196 	if (timeout == 0) timeout = progStatus.comm_retries * delay;
197 	msec_start = zmsec();
198 
199 	repeat_start = zmsec();
200 	respstr.clear();
201 
202 	sendCommand(tosend, 0);
203 	returned = respstr;
204 
205 	while (int(zmsec() - repeat_start) < timeout) {
206 		if (returned.find(bad) != string::npos) {
207 			snprintf(sztemp, sizeof(sztemp), "%s : %d ms", sz, int(zmsec() - msec_start));
208 			showresp(ERR, HEX, sztemp, tosend, returned);
209 //std::cout << ztime() << " ERROR: " << str2hex(returned.c_str(), returned.length()) << std::endl;
210 			return false;
211 		}
212 		if (returned.length() >= num) {
213 			replystr = returned;
214 			snprintf(sztemp, sizeof(sztemp), "%s : %d ms", sz, int(zmsec() - msec_start));
215 			showresp(DEBUG, HEX, sztemp, tosend, returned);
216 //std::cout << ztime() << " Response: " << str2hex(returned.c_str(), returned.length()) << std::endl;
217 			return true;
218 		}
219 		if (readResponse())
220 			returned.append(respstr);
221 	}
222 
223 	diff = zmsec() - msec_start;
224 	replystr = returned;
225 	snprintf(sztemp, sizeof(sztemp), "%s TIMED OUT : %d ms", sz, diff);
226 	showresp(ERR, HEX, sztemp, tosend, returned);
227 //std::cout << ztime() << " " << sztemp << " " << str2hex(returned.c_str(), returned.length()) << std::endl;
228 
229 	return false;
230 }
231 
232 // exchange & equalize are available in these Icom xcvrs
233 // 718 706MKIIG 746 746PRO 756 756PRO 756PROII 756PROIII
234 // 910 7000 7100 7200 7300 7410 7600 7700 7800 9100
235 
236 // 5/04/18 dhf
237 
swapAB()238 void RIG_ICOM::swapAB()
239 {
240 	cmd = pre_to;
241 	cmd += 0x07; cmd += 0xB0;
242 	ICtrace("A<>B", cmd);
243 	cmd.append(post);
244 	int fil = filB;
245 	filB = filA;
246 	filA = fil;
247 	waitFB("A<>B");
248 	ICtrace("A<>B", replystr);
249 }
250 
A2B()251 void RIG_ICOM::A2B()
252 {
253 	cmd = pre_to;
254 	cmd += 0x07; cmd += 0xA0;
255 	ICtrace("A2B", cmd);
256 	cmd.append(post);
257 	if (useB) filA = filB;
258 	else      filB = filA;
259 	waitFB("Equalize vfos");
260 	ICtrace("A2B", replystr);
261 }
262 
tune_rig(int how)263 void RIG_ICOM::tune_rig(int how)
264 {
265 	cmd = pre_to;
266 	cmd.append("\x1c\x01");
267 	switch (how) {
268 		default:
269 		case 0:
270 			cmd += '\x00';
271 			break;
272 		case 1:
273 			cmd += '\x01';
274 			break;
275 		case 2:
276 			cmd += '\x02';
277 			break;
278 	}
279 	cmd.append( post );
280 	waitFB("tune rig");
281 	ICtrace("tune rig", replystr);
282 }
283 
get_tune()284 int RIG_ICOM::get_tune()
285 {
286 	string resp;
287 	string cstr = "\x1C\x01";
288 	cmd.assign(pre_to).append(cstr).append(post);
289 	resp.assign(pre_fm).append(cstr);
290 	int val = tune_;
291 	if (waitFOR(8, "get TUNE")) {
292 		size_t p = replystr.rfind(resp);
293 		if (p != string::npos)
294 			val = replystr[p + 6];
295 	}
296 	return (tune_ = val);
297 }
298 
hexstr(std::string s)299 std::string RIG_ICOM::hexstr(std::string s)
300 {
301 	return str2hex(s.c_str(), s.length());
302 }
303 
304