1 /*
2  *  Hamlib Tentec backend - main file
3  *  Copyright (c) 2001-2009 by Stephane Fillod
4  *
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>  /* String function definitions */
29 #include <unistd.h>  /* UNIX standard function definitions */
30 #include <math.h>
31 
32 #include "hamlib/rig.h"
33 #include "serial.h"
34 #include "misc.h"
35 #include "cal.h"
36 #include "register.h"
37 
38 #include "tentec.h"
39 
40 static void tentec_tuning_factor_calc(RIG *rig);
41 
42 #define EOM "\015"  /* CR */
43 
44 #define TT_AM  '0'
45 #define TT_USB '1'
46 #define TT_LSB '2'
47 #define TT_CW  '3'
48 #define TT_FM  '4'
49 
50 static int tentec_filters[] =
51 {
52     6000, 5700, 5400, 5100, 4800, 4500, 4200, 3900, 3600, 3300, 3000, 2850, 2700, 2550, 2400,
53     2250, 2100, 1950, 1800,
54     1650, 1500, 1350, 1200, 1050, 900, 750, 675, 600, 525, 450, 375, 330, 300, 8000
55 };
56 
57 
58 
59 /*
60  * tentec_transaction
61  * read exactly data_len bytes
62  * We assume that rig!=NULL, rig->state!= NULL, data!=NULL, data_len!=NULL
63  * Otherwise, you'll get a nice seg fault. You've been warned!
64  */
tentec_transaction(RIG * rig,const char * cmd,int cmd_len,char * data,int * data_len)65 int tentec_transaction(RIG *rig, const char *cmd, int cmd_len, char *data,
66                        int *data_len)
67 {
68     int retval;
69     struct rig_state *rs;
70 
71     rs = &rig->state;
72 
73     rig_flush(&rs->rigport);
74 
75     retval = write_block(&rs->rigport, cmd, cmd_len);
76 
77     if (retval != RIG_OK)
78     {
79         return retval;
80     }
81 
82     /* no data expected, TODO: flush input? */
83     if (!data || !data_len)
84     {
85         return 0;
86     }
87 
88     retval = read_string(&rs->rigport, data, *data_len, NULL, 0);
89 
90     if (retval == -RIG_ETIMEOUT)
91     {
92         retval = 0;
93     }
94 
95     if (retval < 0)
96     {
97         return retval;
98     }
99 
100     *data_len = retval;
101 
102     return RIG_OK;
103 }
104 
105 
106 /*
107  * tentec_init:
108  * Basically, it just sets up *priv
109  */
tentec_init(RIG * rig)110 int tentec_init(RIG *rig)
111 {
112     struct tentec_priv_data *priv;
113 
114     rig->state.priv = (struct tentec_priv_data *)malloc(sizeof(
115                           struct tentec_priv_data));
116 
117     if (!rig->state.priv)
118     {
119         /* whoops! memory shortage! */
120         return -RIG_ENOMEM;
121     }
122 
123     priv = rig->state.priv;
124 
125     memset(priv, 0, sizeof(struct tentec_priv_data));
126 
127     /*
128      * set arbitrary initial status
129      */
130     priv->freq = MHz(10);
131     priv->mode = RIG_MODE_AM;
132     priv->width = kHz(6);
133     priv->pbt = 0;
134     priv->cwbfo = 1000;
135     priv->agc = RIG_AGC_MEDIUM; /* medium */
136     priv->lnvol = priv->spkvol = 0.0;   /* mute */
137 
138     /* tentec_tuning_factor_calc needs rig->state.priv */
139     tentec_tuning_factor_calc(rig);
140 
141     return RIG_OK;
142 }
143 
144 /*
145  * Tentec generic tentec_cleanup routine
146  * the serial port is closed by the frontend
147  */
tentec_cleanup(RIG * rig)148 int tentec_cleanup(RIG *rig)
149 {
150     if (rig->state.priv)
151     {
152         free(rig->state.priv);
153     }
154 
155     rig->state.priv = NULL;
156 
157     return RIG_OK;
158 }
159 
160 /*
161  * Tentec transceiver only open routine
162  * Restart and set program to execute.
163  */
tentec_trx_open(RIG * rig)164 int tentec_trx_open(RIG *rig)
165 {
166     int retval;
167 
168     /*
169      * be kind: use XX first, and do 'Dsp Program Execute' only
170      * in " DSP START" state.
171      */
172     retval = tentec_transaction(rig, "P1" EOM, 3, NULL, NULL);
173 
174     if (retval != RIG_OK)
175     {
176         return retval;
177     }
178 
179     return RIG_OK;
180 }
181 
182 
183 /*
184  * Tuning Factor Calculations
185  * assumes rig!=NULL, rig->state.priv!=NULL
186  * assumes priv->mode in supported modes.
187  */
tentec_tuning_factor_calc(RIG * rig)188 static void tentec_tuning_factor_calc(RIG *rig)
189 {
190     struct tentec_priv_data *priv;
191     freq_t tfreq;
192     int adjtfreq, mcor, fcor, cwbfo;
193 
194     priv = (struct tentec_priv_data *)rig->state.priv;
195     cwbfo = 0;
196 
197     /* computed fcor only used if mode is not CW */
198     fcor = (int)floor((double)priv->width / 2.0) + 200;
199 
200     switch (priv->mode)
201     {
202     case RIG_MODE_AM:
203     case RIG_MODE_FM:
204         mcor = 0; break;
205 
206     case RIG_MODE_CW:
207         mcor = -1; cwbfo = priv->cwbfo; fcor = 0; break;
208 
209     case RIG_MODE_LSB:
210         mcor = -1; break;
211 
212     case RIG_MODE_USB:
213         mcor = 1; break;
214 
215     default:
216         rig_debug(RIG_DEBUG_BUG, "%s: invalid mode %s\n", __func__,
217                   rig_strrmode(priv->mode));
218         mcor = 1; break;
219     }
220 
221     tfreq = priv->freq / (freq_t)Hz(1);
222 
223     adjtfreq = (int)tfreq - 1250 + (int)(mcor * (fcor + priv->pbt));
224 
225     priv->ctf = (adjtfreq / 2500) + 18000;
226     priv->ftf = (int)floor((double)(adjtfreq % 2500) * 5.46);
227     priv->btf = (int)floor((double)(fcor + priv->pbt + cwbfo + 8000) * 2.73);
228 }
229 
230 /*
231  * tentec_set_freq
232  * assumes rig!=NULL, rig->state.priv!=NULL
233  * assumes priv->mode in AM,CW,LSB or USB.
234  */
tentec_set_freq(RIG * rig,vfo_t vfo,freq_t freq)235 int tentec_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
236 {
237     struct tentec_priv_data *priv;
238     struct rig_state *rs = &rig->state;
239     int freq_len, retval;
240     char freqbuf[16];
241     freq_t old_freq;
242 
243     priv = (struct tentec_priv_data *)rig->state.priv;
244 
245     old_freq = priv->freq;
246     priv->freq = freq;
247     tentec_tuning_factor_calc(rig);
248 
249     freq_len = sprintf(freqbuf, "N%c%c%c%c%c%c" EOM,
250                        priv->ctf >> 8, priv->ctf & 0xff,
251                        priv->ftf >> 8, priv->ftf & 0xff,
252                        priv->btf >> 8, priv->btf & 0xff);
253 
254     retval = write_block(&rs->rigport, freqbuf, freq_len);
255 
256     if (retval != RIG_OK)
257     {
258         priv->freq = old_freq;
259         return retval;
260     }
261 
262     return RIG_OK;
263 }
264 
265 /*
266  * tentec_get_freq
267  * Assumes rig!=NULL, freq!=NULL
268  */
tentec_get_freq(RIG * rig,vfo_t vfo,freq_t * freq)269 int tentec_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
270 {
271     struct tentec_priv_data *priv = (struct tentec_priv_data *)rig->state.priv;
272 
273     *freq = priv->freq;
274 
275     return RIG_OK;
276 }
277 
278 /*
279  * tentec_set_mode
280  * Assumes rig!=NULL
281  */
tentec_set_mode(RIG * rig,vfo_t vfo,rmode_t mode,pbwidth_t width)282 int tentec_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
283 {
284     struct tentec_priv_data *priv = (struct tentec_priv_data *)rig->state.priv;
285     struct rig_state *rs = &rig->state;
286     char ttmode;
287     rmode_t saved_mode;
288     pbwidth_t saved_width;
289     int mdbuf_len, ttfilter = -1, retval;
290     char mdbuf[32];
291 
292     switch (mode)
293     {
294     case RIG_MODE_USB:      ttmode = TT_USB; break;
295 
296     case RIG_MODE_LSB:      ttmode = TT_LSB; break;
297 
298     case RIG_MODE_CW:       ttmode = TT_CW; break;
299 
300     case RIG_MODE_AM:       ttmode = TT_AM; break;
301 
302     case RIG_MODE_FM:       ttmode = TT_FM; break;
303 
304     default:
305         rig_debug(RIG_DEBUG_ERR,
306                   "%s: unsupported mode %s\n", __func__, rig_strrmode(mode));
307         return -RIG_EINVAL;
308     }
309 
310     /* backup current values
311      * in case we fail to write to port
312      */
313     saved_mode = priv->mode;
314     saved_width = priv->width;
315 
316     if (width != RIG_PASSBAND_NOCHANGE)
317     {
318         if (width == RIG_PASSBAND_NORMAL)
319         {
320             width = rig_passband_normal(rig, mode);
321         }
322 
323         for (ttfilter = 0; tentec_filters[ttfilter] != 0; ttfilter++)
324         {
325             if (tentec_filters[ttfilter] == width)
326             {
327                 break;
328             }
329         }
330 
331         if (tentec_filters[ttfilter] != width)
332         {
333             rig_debug(RIG_DEBUG_ERR,
334                       "%s: unsupported width %d\n", __func__, (int)width);
335             return -RIG_EINVAL;
336         }
337 
338         priv->width = width;
339     }
340 
341     priv->mode = mode;
342 
343     tentec_tuning_factor_calc(rig);
344 
345     if (width != RIG_PASSBAND_NOCHANGE)
346     {
347         mdbuf_len = sprintf(mdbuf,  "W%c" EOM
348                             "N%c%c%c%c%c%c" EOM
349                             "M%c" EOM,
350                             ttfilter,
351                             priv->ctf >> 8, priv->ctf & 0xff,
352                             priv->ftf >> 8, priv->ftf & 0xff,
353                             priv->btf >> 8, priv->btf & 0xff,
354                             ttmode);
355         retval = write_block(&rs->rigport, mdbuf, mdbuf_len);
356 
357         if (retval != RIG_OK)
358         {
359             priv->mode = saved_mode;
360             priv->width = saved_width;
361             return retval;
362         }
363     }
364     else
365     {
366         mdbuf_len = sprintf(mdbuf,
367                             "N%c%c%c%c%c%c" EOM
368                             "M%c" EOM,
369                             priv->ctf >> 8, priv->ctf & 0xff,
370                             priv->ftf >> 8, priv->ftf & 0xff,
371                             priv->btf >> 8, priv->btf & 0xff,
372                             ttmode);
373         retval = write_block(&rs->rigport, mdbuf, mdbuf_len);
374 
375         if (retval != RIG_OK)
376         {
377             priv->mode = saved_mode;
378             return retval;
379         }
380     }
381 
382     return RIG_OK;
383 }
384 
385 /*
386  * tentec_get_mode
387  * Assumes rig!=NULL, mode!=NULL
388  */
tentec_get_mode(RIG * rig,vfo_t vfo,rmode_t * mode,pbwidth_t * width)389 int tentec_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
390 {
391     struct tentec_priv_data *priv = (struct tentec_priv_data *)rig->state.priv;
392 
393     *mode = priv->mode;
394     *width = priv->width;
395 
396     return RIG_OK;
397 }
398 
399 
400 /*
401  * tentec_set_level
402  * Assumes rig!=NULL
403  * FIXME: cannot support PREAMP and ATT both at same time (make sens though)
404  */
tentec_set_level(RIG * rig,vfo_t vfo,setting_t level,value_t val)405 int tentec_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val)
406 {
407     struct tentec_priv_data *priv = (struct tentec_priv_data *)rig->state.priv;
408     struct rig_state *rs = &rig->state;
409     int cmd_len, retval = RIG_OK;
410     char cmdbuf[32];
411 
412     /* Optimize:
413      *   sort the switch cases with the most frequent first
414      */
415     switch (level)
416     {
417     case RIG_LEVEL_AGC:
418         /* default to MEDIUM */
419         cmd_len = sprintf(cmdbuf, "G%c" EOM,
420                           val.i == RIG_AGC_SLOW ? '1' : (
421                               val.i == RIG_AGC_FAST ? '3' : '2'));
422         retval = write_block(&rs->rigport, cmdbuf, cmd_len);
423 
424         if (retval == RIG_OK)
425         {
426             priv->agc = val.i;
427         }
428 
429         return retval;
430 
431     case RIG_LEVEL_AF:
432         /* FIXME: support also separate Lineout setting
433          * -> need to create RIG_LEVEL_LINEOUT ?
434          */
435         cmd_len = sprintf(cmdbuf, "C\x7f%c" EOM, (int)((1.0 - val.f) * 63.0));
436         retval = write_block(&rs->rigport, cmdbuf, cmd_len);
437 
438         if (retval == RIG_OK)
439         {
440             priv->lnvol = priv->spkvol = val.f;
441         }
442 
443         return retval;
444 
445     case RIG_LEVEL_IF:
446         priv->pbt = val.i;
447         retval = tentec_set_freq(rig, vfo, priv->freq);
448         return retval;
449 
450     case RIG_LEVEL_CWPITCH:
451         priv->cwbfo = val.i;
452 
453         if (priv->mode == RIG_MODE_CW)
454         {
455             retval = tentec_set_freq(rig, vfo, priv->freq);
456         }
457 
458         return retval;
459 
460     default:
461         rig_debug(RIG_DEBUG_ERR, "%s: unsupported set_level %s\n", __func__,
462                   rig_strlevel(level));
463         return -RIG_EINVAL;
464     }
465 
466     return RIG_OK;
467 }
468 
469 
470 /*
471  * tentec_get_level
472  * Assumes rig!=NULL, val!=NULL
473  */
tentec_get_level(RIG * rig,vfo_t vfo,setting_t level,value_t * val)474 int tentec_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val)
475 {
476     struct tentec_priv_data *priv = (struct tentec_priv_data *)rig->state.priv;
477     int retval, lvl_len;
478     unsigned char lvlbuf[32];
479 
480 
481     /* Optimize:
482      *   sort the switch cases with the most frequent first
483      */
484     switch (level)
485     {
486     case RIG_LEVEL_RAWSTR:
487         /* read A/D converted value */
488         lvl_len = 4;
489         retval = tentec_transaction(rig, "X" EOM, 2, (char *) lvlbuf, &lvl_len);
490 
491         if (retval != RIG_OK)
492         {
493             return retval;
494         }
495 
496         if (lvl_len != 3)
497         {
498             rig_debug(RIG_DEBUG_ERR, "tentec_get_level: wrong answer"
499                       "len=%d\n", lvl_len);
500             return -RIG_ERJCTED;
501         }
502 
503         lvlbuf[3] = '\0';
504         rig_debug(RIG_DEBUG_VERBOSE, "tentec_get_level: cmd=%c,hi=%d,lo=%d\n",
505                   lvlbuf[0], lvlbuf[1], lvlbuf[2]);
506         val->i = (lvlbuf[1] << 8) + lvlbuf[2];
507         break;
508 
509     case RIG_LEVEL_AGC:
510         val->i = priv->agc;
511         break;
512 
513     case RIG_LEVEL_AF:
514         val->f = priv->spkvol;
515         break;
516 
517     case RIG_LEVEL_IF:
518         val->i = priv->pbt;
519         break;
520 
521     case RIG_LEVEL_CWPITCH:
522         val->i = priv->cwbfo;
523         break;
524 
525     default:
526         rig_debug(RIG_DEBUG_ERR, "%s: unsupported get_level %s\n", __func__,
527                   rig_strlevel(level));
528         return -RIG_EINVAL;
529     }
530 
531     return RIG_OK;
532 }
533 
534 
535 /*
536  * tentec_get_info
537  * Assumes rig!=NULL
538  */
tentec_get_info(RIG * rig)539 const char *tentec_get_info(RIG *rig)
540 {
541     static char buf[100];   /* FIXME: reentrancy */
542     int firmware_len, retval;
543 
544     /*
545      * protocol version
546      */
547     firmware_len = 10;
548     retval = tentec_transaction(rig, "?" EOM, 2, buf, &firmware_len);
549 
550     if ((retval != RIG_OK) || (firmware_len > 10))
551     {
552         rig_debug(RIG_DEBUG_ERR, "tentec_get_info: ack NG, len=%d\n",
553                   firmware_len);
554         return NULL;
555     }
556 
557     return buf;
558 }
559 
560 
561 /*
562  * initrigs_tentec is called by rig_backend_load
563  */
DECLARE_INITRIG_BACKEND(tentec)564 DECLARE_INITRIG_BACKEND(tentec)
565 {
566     rig_debug(RIG_DEBUG_VERBOSE, "%s: _init called\n", __func__);
567 
568     rig_register(&tt550_caps);
569     rig_register(&tt516_caps);
570     rig_register(&tt565_caps);
571     rig_register(&tt538_caps);
572     rig_register(&tt585_caps);
573     rig_register(&tt588_caps);
574     rig_register(&tt599_caps);
575     rig_register(&rx320_caps);
576     rig_register(&rx331_caps);
577     rig_register(&rx340_caps);
578     rig_register(&rx350_caps);
579 
580     return RIG_OK;
581 }
582 
583