1 // ----------------------------------------------------------------------------
2 // Copyright (C) 2014
3 //              David Freese, W1HKJ
4 //
5 // 2015-10-04 adapted from FT890.cxx by Ernst F. Schroeder DJ7HS
6 //            the FT-900 has two vfos and can work split
7 //            but it cannot change the (hidden) alternate vfo
8 // 2015-12-03 1st stable version  DJ7HS
9 // 2016-04-03 call get_info() within get_vfoA and get_vfoB  DJ7HS
10 // 2017-06-16 changes in support.cxx made adaptations necessary  DJ7HS
11 //
12 // This file is part of flrig.
13 //
14 // flrig is free software; you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation; either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 // flrig is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // aunsigned long int with this program.  If not, see <http://www.gnu.org/licenses/>.
26 // ----------------------------------------------------------------------------
27 
28 #include "FT900.h"
29 #include "status.h"
30 
31 const char FT900name_[] = "FT-900";
32 
33 const char *FT900modes_[] = {
34 		"LSB", "USB", "CW", "CW-N", "AM", "AM-N", "FM", NULL};
35 static const int FT900_mode_val[] =  { 0, 1, 2, 3, 4, 5, 6 };
36 
37 static const char FT900_mode_type[] = { 'L', 'U', 'U', 'U', 'U', 'U', 'U' };
38 
39 static const char *FT900widths_[] =
40 { "wide", "narr", NULL};
41 
42 static const int FT900_bw_val[] =
43 { 0, 1 };
44 
RIG_FT900()45 RIG_FT900::RIG_FT900() {
46 	name_ = FT900name_;
47 	modes_ = FT900modes_;
48 	bandwidths_ = FT900widths_;
49 	comm_baudrate = BR4800;
50 	stopbits = 2;
51 	comm_retries = 2;
52 	comm_wait = 5;
53 	comm_timeout = 50;
54 	comm_rtscts = false;
55 	comm_rtsplus = false;
56 	comm_dtrplus = false;
57 	comm_catptt = true;
58 	comm_rtsptt = false;
59 	comm_dtrptt = false;
60 
61 	afreq = bfreq = A.freq = B.freq = 14070000;
62 	amode = bmode = A.imode = B.imode = 1;
63 	aBW = bBW = A.iBW = B.iBW = 0;
64 	precision = 10;
65 
66 	has_smeter =
67 	has_power_out =
68 	has_ptt_control =
69 	has_split =
70 	has_split_AB =
71 	has_getvfoAorB =
72 	has_get_info =
73 	has_mode_control = true;
74 
75 	precision = 10;
76 	ndigits = 7;
77 
78 }
79 
initialize()80 void RIG_FT900::initialize()
81 {
82 	progStatus.poll_split = 1;     // allow pollimg for split info
83 	progStatus.poll_vfoAorB = 1;   // allow pollimg for vfo info
84 }
85 
init_cmd()86 void RIG_FT900::init_cmd()
87 {
88 	cmd = "00000";
89 	for (size_t i = 0; i < 5; i++) cmd[i] = 0;
90 }
91 
selectA()92 void RIG_FT900::selectA()
93 {
94 	init_cmd();
95 	cmd[4] = 0x05;
96 	sendCommand(cmd);
97 	showresp(WARN, HEX, "select vfo A", cmd, replystr);
98 }
99 
selectB()100 void RIG_FT900::selectB()
101 {
102 	init_cmd();
103 	cmd[3] = 0x01;
104 	cmd[4] = 0x05;
105 	sendCommand(cmd);
106 	showresp(WARN, HEX, "select vfo B", cmd, replystr);
107 }
108 
set_split(bool val)109 void RIG_FT900::set_split(bool val)
110 {
111 	init_cmd();
112 	cmd[3] = val ? 0x01 : 0x00;
113 	cmd[4] = 0x01;
114 	sendCommand(cmd);
115 	if (val)
116 		showresp(WARN, HEX, "set split ON", cmd, replystr);
117 	else
118 		showresp(WARN, HEX, "set split OFF", cmd, replystr);
119 }
120 
get_split()121 int RIG_FT900::get_split()
122 {
123 	return splitison;
124 }
125 
get_vfoAorB()126 int  RIG_FT900::get_vfoAorB()
127 {
128 //  get flags for vfoAorB and split
129 	init_cmd();
130 	cmd[4] = 0xFA;
131 	int ret = waitN(5, 100, "get flags info", HEX);
132 //  after this command the FT-900 replies with 3 bytes of flags and 2 bytes of dummy data
133 	if (ret >= 5) {
134 		size_t p = ret - 5;
135 		int sp = replybuff[p];
136 		splitison = (sp & 0x04) ? 1 : 0;     // 1 if split is set
137 		vfoAorB = (sp & 0x40) ? 1 : 0;       // 0 if vfoA, 1 if vfoB is in use
138      	return vfoAorB;
139 	}
140 	return -1;                                // -1 signals error
141 }
142 
143 //void RIG_FT900::swapAB()    // works with a simple trick
144 //{
145 //	init_cmd();
146 //	cmd[4] = 0x85;			// copy active vfo to background vfo
147 //	sendCommand(cmd);
148 //	showresp(WARN, HEX, "copy active vfo to background vfo", cmd, replystr);
149 
150 //	if (!useB) {
151 //		queA.push(vfoB);
152 //		B = vfoA;
153 //	} else {
154 //		queB.push(vfoA);
155 //		A = vfoB;
156 //	}
157 //}
158 
check()159 bool RIG_FT900::check()
160 {
161 	init_cmd();
162 	cmd[3] = 0x03;
163 	cmd[4] = 0x10;
164 	int ret = waitN(18, 100, "check", HEX);
165 	if (ret >= 18) return true;
166 	return false;
167 }
168 
get_info()169 bool RIG_FT900::get_info()
170 {
171 //  get the vfo, mode and bandwidth information
172 	init_cmd();
173 	cmd[3] = 0x03;
174 	cmd[4] = 0x10;
175 //  after this command the FT-900 replies with 2 x 9 bytes of data
176 //  bytes 1..3 contain binary data for vfoA with 10 Hz resolution
177 //  bytes 10..12 contain binary data for vfoB with 10 Hz resolution
178 //  bytes 6 and 15 contain the mode and bytes 8 and 17 contain the bandwidth
179 
180 	int ret = waitN(18, 100, "get info", HEX);
181 
182 	if (ret >= 18) {
183 		size_t p = ret - 18;
184 		afreq = 0;
185 		bfreq = 0;
186 		for (size_t n = 1; n < 4; n++) {
187 			afreq = afreq * 256 + (unsigned char)replybuff[p + n];
188 			bfreq = bfreq * 256 + (unsigned char)replybuff[p + 9 + n];
189 		}
190 		afreq = afreq * 10.0;
191 		bfreq = bfreq * 10.0;
192 		aBW = 0;   // normal BW
193 //		mode data for vfoA is in byte 6
194 //      	bandwidth data is in byte 8
195 		int md = replybuff[p + 6];
196 		int bw = replybuff[p + 8];
197 		switch (md) {
198 			case 0 :   // LSB
199 				amode = 0;
200 				break;
201 			case 1 :   // USB
202 				amode = 1;
203 				break;
204 			case 2 :   // CW
205 				amode = (bw & 0x80) ? 3 : 2;
206 				aBW = (bw & 0x80) ? 1 : 0;
207 				break;
208 			case 3 :   // AM
209 				amode = (bw & 0x40) ? 5 : 4;
210 				aBW = (bw & 0x40) ? 1 : 0;
211 				break;
212 			case 4 :   // FM
213 				amode = 6;
214 				break;
215 			default :
216 				amode = 1;
217 		}
218 
219 		bBW = 0;
220 //		mode data for vfoB is in byte 15
221 //      	bandwidth data is in byte 17
222 		md = replybuff[p + 15];
223 		bw = replybuff[p + 17];
224 		switch (md) {
225 			case 0 :   // LSB
226 				bmode = 0;
227 				break;
228 			case 1 :   // USB
229 				bmode = 1;
230 				break;
231 			case 2 :   // CW
232 				bmode = (bw & 0x80) ? 3 : 2;
233 				bBW = (bw & 0x80) ? 1 : 0;
234 				break;
235 			case 3 :   // AM
236 				bmode = (bw & 0x40) ? 5 : 4;
237 				bBW = (bw & 0x40) ? 1 : 0;
238 				break;
239 			case 4 :   // FM
240 				bmode = 6;
241 				break;
242 			default :
243 				bmode = 1;
244 		}
245 
246 		A.freq = afreq;
247 		A.imode = amode;
248 		A.iBW = aBW;
249 
250 		B.freq = bfreq;
251 		B.imode = bmode;
252 		B.iBW = bBW;
253 
254 		return true;
255 	}
256 	return false;
257 }
258 
get_vfoA()259 unsigned long int RIG_FT900::get_vfoA ()
260 {
261 	return A.freq;
262 }
263 
set_vfoA(unsigned long int freq)264 void RIG_FT900::set_vfoA (unsigned long int freq)
265 {
266 	A.freq = freq;
267 	freq /=10; // FT-900 does not support 1 Hz resolution
268 	cmd = to_bcd_be(freq, 8);
269 	cmd += 0x0A;
270 	sendCommand(cmd);
271 	showresp(WARN, HEX, "set vfo A", cmd, replystr);
272 }
273 
get_modeA()274 int RIG_FT900::get_modeA()
275 {
276 	return A.imode;
277 }
278 
set_modeA(int val)279 void RIG_FT900::set_modeA(int val)
280 {
281 	A.imode = val;
282 	init_cmd();
283 	cmd[3] = FT900_mode_val[val];
284 	cmd[4] = 0x0C;
285 	sendCommand(cmd);
286 	showresp(WARN, HEX, "set mode A", cmd, replystr);
287 }
288 
get_vfoB()289 unsigned long int RIG_FT900::get_vfoB()
290 {
291 	return B.freq;
292 }
293 
set_vfoB(unsigned long int freq)294 void RIG_FT900::set_vfoB(unsigned long int freq)
295 {
296 	B.freq = freq;
297 	freq /=10; // FT-900 does not support 1 Hz resolution
298 	cmd = to_bcd_be(freq, 8);
299 	cmd += 0x0A;
300 	sendCommand(cmd);
301 	showresp(WARN, HEX, "set vfo B", cmd, replystr);
302 }
303 
set_modeB(int val)304 void RIG_FT900::set_modeB(int val)
305 {
306 	B.imode = val;
307 	init_cmd();
308 	cmd[3] = FT900_mode_val[val];
309 	cmd[4] = 0x0C;
310 	sendCommand(cmd);
311 	showresp(WARN, HEX, "set mode B", cmd, replystr);
312 }
313 
get_modeB()314 int  RIG_FT900::get_modeB()
315 {
316 	return B.imode;
317 }
318 
319 // Transceiver PTT on/off
set_PTT_control(int val)320 void RIG_FT900::set_PTT_control(int val)
321 {
322 // make sure no other vfo except either vfoA or vfoB is used for transmit
323      if (val) {
324           if (!useB) {
325                selectA();
326           } else {
327                selectB();
328           }
329      }
330 // make sure that in case of split the transmit mode is shown correctly
331      if (splitison) {
332           if (val) {
333                if (!useB) {
334                     vfo = &vfoB;
335                } else {
336                     vfo = &vfoA;
337                }
338           } else {
339                if (!useB) {
340                     vfo = &vfoA;
341                } else {
342                     vfo = &vfoB;
343                }
344           }
345           Fl::awake(setModeControl);
346      }
347 	init_cmd();
348 	if (val) cmd[3] = 1;
349 	else	 cmd[3] = 0;
350 	cmd[4] = 0x0F;
351 	sendCommand(cmd, 0);
352 	LOG_INFO("%s", str2hex(cmd.c_str(), 5));
353 	ptt_ = val;
354 }
355 
get_smeter()356 int RIG_FT900::get_smeter()
357 {
358 	init_cmd();
359 	cmd[4] = 0xF7;
360 	int ret = waitN(5, 100, "get smeter", HEX);
361 	if (ret < 5) return 0;
362 	int sval = (unsigned char)(replybuff[ret - 2]);
363 	sval = sval * 100 / 255;
364 	return sval;
365 }
366 
get_power_out()367 int RIG_FT900::get_power_out()
368 {
369 	init_cmd();
370 	cmd[4] = 0xF7;
371 	int ret = waitN(5, 100, "get pwr out", HEX);
372 	if (ret < 5) return 0;
373 	int sval = (unsigned char)(replybuff[ret - 2]);
374 	sval = sval * 100 / 255;
375 	return sval;
376 }
377