1 /*
2  *  Hamlib R&S backend - main file
3  *  Copyright (c) 2009-2010 by Stéphane 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 "register.h"
36 #include "num_stdio.h"
37 
38 #include "rs.h"
39 #include "gp2000.h"
40 
41 
42 #define BUFSZ 64
43 #define RESPSZ 64
44 
45 #define LF "\x0a"
46 #define CR "\x0d"
47 #define BOM CR
48 #define EOM CR
49 
50 /*
51  * R&S GB2 protocol ?
52  */
53 
54 
55 /*
56  * rs_transaction
57  * We assume that rig!=NULL, rig->state!= NULL, data!=NULL, data_len!=NULL
58  */
rs_transaction(RIG * rig,const char * cmd,int cmd_len,char * data,int * data_len)59 int rs_transaction(RIG *rig, const char *cmd, int cmd_len, char *data,
60                    int *data_len)
61 {
62     int retval;
63     struct rig_state *rs;
64 
65     rs = &rig->state;
66 
67     rig_flush(&rs->rigport);
68 
69     retval = write_block(&rs->rigport, cmd, cmd_len);
70 
71     if (retval != RIG_OK)
72     {
73         return retval;
74     }
75 
76 
77     /* no data expected */
78     if (!data || !data_len)
79     {
80         return RIG_OK;
81     }
82 
83     retval = read_string(&rs->rigport, data, BUFSZ, CR, 1);
84 
85     if (retval < 0)
86     {
87         return retval;
88     }
89 
90     *data_len = retval;
91 
92     return RIG_OK;
93 }
94 
95 /*
96  * rs_set_freq
97  * Assumes rig!=NULL
98  */
rs_set_freq(RIG * rig,vfo_t vfo,freq_t freq)99 int rs_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
100 {
101     char freqbuf[32];
102     int freq_len, retval;
103 
104     // cppcheck-suppress *
105     freq_len = sprintf(freqbuf, BOM "FREQ %"PRIll EOM, (int64_t)freq);
106     retval = rs_transaction(rig, freqbuf, freq_len, NULL, NULL);
107 
108     return retval;
109 }
110 
111 /*
112  * rs_get_freq
113  * Assumes rig!=NULL
114  */
rs_get_freq(RIG * rig,vfo_t vfo,freq_t * freq)115 int rs_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
116 {
117     char buf[RESPSZ];
118     int len, retval;
119 
120 #define FREQ_QUERY  BOM "FREQ?" EOM
121 
122     retval = rs_transaction(rig, FREQ_QUERY, strlen(FREQ_QUERY), buf, &len);
123 
124     if (retval < 0)
125     {
126         return retval;
127     }
128 
129     retval = (sscanf(buf, "%"SCNfreq, freq) == 1) ? RIG_OK : -RIG_EPROTO;
130 
131     return retval;
132 }
133 
134 /*
135  * rs_set_mode
136  * Assumes rig!=NULL
137  */
rs_set_mode(RIG * rig,vfo_t vfo,rmode_t mode,pbwidth_t width)138 int rs_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
139 {
140     char buf[32], *smode;
141     int len, retval;
142 
143     switch (mode)
144     {
145     case RIG_MODE_AM: smode = "AM"; break;
146 
147     case RIG_MODE_WFM:
148     case RIG_MODE_FM: smode = "FM"; break;
149 
150     case RIG_MODE_CW: smode = "CW"; break;
151 
152     case RIG_MODE_USB: smode = "USB"; break;
153 
154     case RIG_MODE_LSB: smode = "LSB"; break;
155 
156     default:
157         return -RIG_EINVAL;
158     }
159 
160     len = sprintf(buf, BOM "DEM %s" EOM, smode);
161     retval = rs_transaction(rig, buf, len, NULL, NULL);
162 
163     if (retval < 0)
164     {
165         return retval;
166     }
167 
168     if (width == RIG_PASSBAND_NOCHANGE) { return retval; }
169 
170     if (width == RIG_PASSBAND_NORMAL)
171     {
172         width = rig_passband_normal(rig, mode);
173     }
174 
175     if (width > 0)
176     {
177         len = sprintf(buf, BOM "BAND %d" EOM, (int) width);
178         retval = rs_transaction(rig, buf, len, NULL, NULL);
179     }
180 
181     return retval;
182 }
183 
184 /*
185  * rs_get_mode
186  * Assumes rig!=NULL
187  */
rs_get_mode(RIG * rig,vfo_t vfo,rmode_t * mode,pbwidth_t * width)188 int rs_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
189 {
190     char buf[RESPSZ];
191     int buf_len, retval;
192 
193 #define DEM_QUERY   BOM "DEM?" EOM
194 
195     retval = rs_transaction(rig, DEM_QUERY, strlen(DEM_QUERY), buf, &buf_len);
196 
197     if (retval < 0)
198     {
199         return retval;
200     }
201 
202     *mode = rig_parse_mode(buf);
203 
204 #define BAND_QUERY   BOM "BAND?" EOM
205     retval = rs_transaction(rig, BAND_QUERY, strlen(BAND_QUERY), buf, &buf_len);
206 
207     if (retval < 0)
208     {
209         return retval;
210     }
211 
212     *width = atoi(buf);
213 
214     return retval;
215 }
216 
217 
rs_set_func(RIG * rig,vfo_t vfo,setting_t func,int status)218 int rs_set_func(RIG *rig, vfo_t vfo, setting_t func, int status)
219 {
220     char buf[32], *sfunc;
221     int len, retval;
222 
223     switch (func)
224     {
225     case RIG_FUNC_AFC: sfunc = "FREQ:AFC"; break;
226 
227     case RIG_FUNC_SQL: sfunc = "OUTP:SQU"; break;
228 
229     case RIG_FUNC_LOCK: sfunc = "DISP:ENAB"; break;
230 
231     default:
232         return -RIG_EINVAL;
233     }
234 
235     len = sprintf(buf, BOM "%s %s" EOM, sfunc, status ? "ON" : "OFF");
236     retval = rs_transaction(rig, buf, len, NULL, NULL);
237 
238     return retval;
239 }
240 
rs_get_func(RIG * rig,vfo_t vfo,setting_t func,int * status)241 int rs_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status)
242 {
243     char buf[RESPSZ], *sfunc;
244     int buf_len, retval;
245 
246     switch (func)
247     {
248     case RIG_FUNC_AFC: sfunc = BOM "FREQ:AFC?" EOM; break;
249 
250     case RIG_FUNC_SQL: sfunc = BOM "OUTP:SQU?" EOM; break;
251 
252     case RIG_FUNC_LOCK: sfunc = BOM "DISP:ENAB?" EOM; break;
253 
254     default:
255         return -RIG_EINVAL;
256     }
257 
258     retval = rs_transaction(rig, sfunc, strlen(sfunc), buf, &buf_len);
259 
260     if (retval < 0)
261     {
262         return retval;
263     }
264 
265     *status = (!memcmp(buf, "ON", 2) || !memcmp(buf, "1", 1)) ? 1 : 0;
266 
267     return retval;
268 }
269 
rs_set_level(RIG * rig,vfo_t vfo,setting_t level,value_t val)270 int rs_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val)
271 {
272     char buf[32];
273     int len, retval;
274 
275     switch (level)
276     {
277     case RIG_LEVEL_ATT:
278         len = sprintf(buf, BOM "INP:ATT:STAT %s" EOM, val.i ? "ON" : "OFF");
279         break;
280 
281     case RIG_LEVEL_SQL:
282         /* dBuV */
283         len = sprintf(buf, BOM "OUTP:SQU:THR %d" EOM, (int)(20 + val.f * 20));
284         break;
285 
286     case RIG_LEVEL_AF:
287         len = num_sprintf(buf, BOM "SYST:AUD:VOL %.1f" EOM, val.f);
288         break;
289 
290     case RIG_LEVEL_AGC:
291     case RIG_LEVEL_RF:
292         return -RIG_ENIMPL;
293 
294     default:
295         return -RIG_EINVAL;
296     }
297 
298     retval = rs_transaction(rig, buf, len, NULL, NULL);
299 
300     return retval;
301 }
302 
rs_get_level(RIG * rig,vfo_t vfo,setting_t level,value_t * val)303 int rs_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val)
304 {
305     char buf[RESPSZ], *slevel;
306     int buf_len, retval;
307 
308     switch (level)
309     {
310     case RIG_LEVEL_STRENGTH: slevel = BOM "SENS:DATA? \"VOLT:AC\"" EOM; break;
311 
312     case RIG_LEVEL_ATT: slevel = BOM "INP:ATT:STAT?" EOM; break;
313 
314     case RIG_LEVEL_AF: slevel = BOM "SYST:AUD:VOL?" EOM; break;
315 
316     case RIG_LEVEL_SQL:
317     case RIG_LEVEL_AGC:
318     case RIG_LEVEL_RF:
319         return -RIG_ENIMPL;
320 
321     default:
322         return -RIG_EINVAL;
323     }
324 
325     retval = rs_transaction(rig, slevel, strlen(slevel), buf, &buf_len);
326 
327     if (retval < 0)
328     {
329         return retval;
330     }
331 
332     switch (level)
333     {
334     case RIG_LEVEL_STRENGTH:
335         /* assumes FORMAat:DATA ASCii
336          * result in dBuV, keep only integer part
337          */
338         sscanf(buf, "%d", &val->i);
339         val->i -= 34;
340         break;
341 
342     case RIG_LEVEL_ATT:
343         val->i = (!memcmp(buf, "ON", 2)
344                   || !memcmp(buf, "1", 1)) ? rig->state.attenuator[0] : 0;
345         break;
346 
347     case RIG_LEVEL_AF:
348         if (num_sscanf(buf, "%f", &val->f) != 1)
349         {
350             return -RIG_EPROTO;
351         }
352 
353         break;
354 
355     default:
356         return -RIG_EINVAL;
357     }
358 
359     return retval;
360 }
361 
rs_get_info(RIG * rig)362 const char *rs_get_info(RIG *rig)
363 {
364     static char infobuf[128];
365     int info_len, retval;
366 
367 #define ID_QUERY BOM "*IDN?" EOM
368 
369     retval = rs_transaction(rig, ID_QUERY, strlen(ID_QUERY), infobuf, &info_len);
370 
371     if (retval < 0)
372     {
373         return NULL;
374     }
375 
376     return infobuf;
377 }
378 
rs_reset(RIG * rig,reset_t reset)379 int rs_reset(RIG *rig, reset_t reset)
380 {
381     int retval;
382 
383 #define RST_CMD BOM "*RST" EOM
384 
385     retval = rs_transaction(rig, RST_CMD, strlen(RST_CMD), NULL, NULL);
386 
387     return retval;
388 }
389 
390 
391 /*
392  * initrigs_rs is called by rig_backend_load
393  */
DECLARE_INITRIG_BACKEND(rs)394 DECLARE_INITRIG_BACKEND(rs)
395 {
396     rig_debug(RIG_DEBUG_VERBOSE, "%s: _init called\n", __func__);
397 
398     rig_register(&esmc_caps);
399     rig_register(&eb200_caps);
400     rig_register(&xk2100_caps);
401 
402     return RIG_OK;
403 }
404 
405