1 /*
2  *  Hamlib WiNRADiO backend - main file for interface through /dev/winradio API
3  *  Copyright (C) 2001 pab@users.sourceforge.net
4  *  Derived from hamlib code (C) 2000-2009 Stephane Fillod.
5  *
6  *
7  *   This library is free software; you can redistribute it and/or
8  *   modify it under the terms of the GNU Lesser General Public
9  *   License as published by the Free Software Foundation; either
10  *   version 2.1 of the License, or (at your option) any later version.
11  *
12  *   This library 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 GNU
15  *   Lesser General Public License for more details.
16  *
17  *   You should have received a copy of the GNU Lesser General Public
18  *   License along with this library; if not, write to the Free Software
19  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22 
23 #include "winradio.h"   /* config.h */
24 
25 #include <stdlib.h>
26 #include <string.h>  /* String function definitions */
27 #ifdef HAVE_SYS_IOCTL_H
28 #include <sys/ioctl.h>
29 #endif
30 #include <math.h>
31 
32 #include "hamlib/rig.h"
33 #include "serial.h"
34 #include "misc.h"
35 #include "register.h"
36 
37 
38 
39 #ifdef WINRADIO_IOCTL
40 
41 #include <linradio/wrapi.h>
42 #include <linradio/radio_ioctl.h>
43 
44 #define DEFAULT_WINRADIO_PATH "/dev/winradio0"
45 
wr_rig_init(RIG * rig)46 int wr_rig_init(RIG *rig)
47 {
48     rig->state.rigport.type.rig = RIG_PORT_DEVICE;
49     strncpy(rig->state.rigport.pathname, DEFAULT_WINRADIO_PATH,
50             HAMLIB_FILPATHLEN - 1);
51 
52     return RIG_OK;
53 }
54 
wr_set_freq(RIG * rig,vfo_t vfo,freq_t freq)55 int wr_set_freq(RIG *rig, vfo_t vfo, freq_t freq)
56 {
57     unsigned long f;
58 
59     if (freq > GHz(4.2))
60     {
61         return -RIG_EINVAL;
62     }
63 
64     f = (unsigned long)freq;
65 
66     if (ioctl(rig->state.rigport.fd, RADIO_SET_FREQ, &f)) { return -RIG_EINVAL; }
67 
68     return RIG_OK;
69 }
70 
wr_get_freq(RIG * rig,vfo_t vfo,freq_t * freq)71 int wr_get_freq(RIG *rig, vfo_t vfo, freq_t *freq)
72 {
73     unsigned long f;
74 
75     if (ioctl(rig->state.rigport.fd, RADIO_GET_FREQ, &f) < 0) { return -RIG_EINVAL; }
76 
77     *freq = (freq_t)f;
78     return RIG_OK;
79 }
80 
wr_set_mode(RIG * rig,vfo_t vfo,rmode_t mode,pbwidth_t width)81 int wr_set_mode(RIG *rig, vfo_t vfo, rmode_t mode, pbwidth_t width)
82 {
83     unsigned long m;
84 
85     switch (mode)
86     {
87     case RIG_MODE_AM:  m = RMD_AM; break;
88 
89     case RIG_MODE_CW:  m = RMD_CW; break;
90 
91     case RIG_MODE_LSB: m = RMD_LSB; break;
92 
93     case RIG_MODE_USB: m = RMD_USB; break;
94 
95     case RIG_MODE_WFM: m = RMD_FMW; break;
96 
97     case RIG_MODE_FM:
98         switch (width)
99         {
100         case RIG_PASSBAND_NORMAL:
101         case (int)kHz(17):
102         case (int)kHz(15): m = RMD_FMN; break;
103 
104         case (int)kHz(6): m = RMD_FM6; break;
105 
106         case (int)kHz(50): m = RMD_FMM; break;
107 
108         default: return -RIG_EINVAL;
109         }
110 
111         break;
112 
113     default: return -RIG_EINVAL;
114     }
115 
116     if (ioctl(rig->state.rigport.fd, RADIO_SET_MODE, &m)) { return -RIG_EINVAL; }
117 
118     return  RIG_OK;
119 }
120 
wr_get_mode(RIG * rig,vfo_t vfo,rmode_t * mode,pbwidth_t * width)121 int wr_get_mode(RIG *rig, vfo_t vfo, rmode_t *mode, pbwidth_t *width)
122 {
123     unsigned long m;
124 
125     if (ioctl(rig->state.rigport.fd, RADIO_GET_MODE, &m)) { return -RIG_EINVAL; }
126 
127     *width = RIG_PASSBAND_NORMAL;
128 
129     switch (m)
130     {
131     case RMD_CW: *mode = RIG_MODE_CW; break;
132 
133     case RMD_AM: *mode = RIG_MODE_AM; break;
134 
135     case RMD_FMN: *mode = RIG_MODE_FM; break; /* 15kHz or 17kHz on WR-3100 */
136 
137     case RMD_FM6: *mode = RIG_MODE_FM; break; /* 6kHz */
138 
139     case RMD_FMM: *mode = RIG_MODE_FM; break; /* 50kHz */
140 
141     case RMD_FMW: *mode = RIG_MODE_WFM; break;
142 
143     case RMD_LSB: *mode = RIG_MODE_LSB; break;
144 
145     case RMD_USB: *mode = RIG_MODE_USB; break;
146 
147     default: return -RIG_EINVAL;
148     }
149 
150     if (*width == RIG_PASSBAND_NORMAL)
151     {
152         *width = rig_passband_normal(rig, *mode);
153     }
154 
155     return RIG_OK;
156 }
157 
wr_set_powerstat(RIG * rig,powerstat_t status)158 int wr_set_powerstat(RIG *rig, powerstat_t status)
159 {
160     unsigned long p = 1;
161     p = status == RIG_POWER_ON ? 1 : 0;
162 
163     if (ioctl(rig->state.rigport.fd, RADIO_SET_POWER, &p)) { return -RIG_EINVAL; }
164 
165     return RIG_OK;
166 }
wr_get_powerstat(RIG * rig,powerstat_t * status)167 int wr_get_powerstat(RIG *rig, powerstat_t *status)
168 {
169     unsigned long p;
170 
171     if (ioctl(rig->state.rigport.fd, RADIO_GET_POWER, &p)) { return -RIG_EINVAL; }
172 
173     *status = p ? RIG_POWER_ON : RIG_POWER_OFF;
174     return RIG_OK;
175 }
176 
wr_set_func(RIG * rig,vfo_t vfo,setting_t func,int status)177 int wr_set_func(RIG *rig, vfo_t vfo, setting_t func, int status)
178 {
179     switch (func)
180     {
181     case RIG_FUNC_FAGC:
182     {
183         unsigned long v = status ? 1 : 0;
184 
185         if (ioctl(rig->state.rigport.fd, RADIO_SET_AGC, &v)) { return -RIG_EINVAL; }
186 
187         return RIG_OK;
188     }
189 
190     default:
191         return -RIG_EINVAL;
192     }
193 }
194 
wr_get_func(RIG * rig,vfo_t vfo,setting_t func,int * status)195 int wr_get_func(RIG *rig, vfo_t vfo, setting_t func, int *status)
196 {
197     switch (func)
198     {
199     case RIG_FUNC_FAGC:
200     {
201         unsigned long v;
202 
203         if (ioctl(rig->state.rigport.fd, RADIO_GET_AGC, &v)) { return -RIG_EINVAL; }
204 
205         *status = v;
206         return RIG_OK;
207     }
208 
209     default:
210         return -RIG_EINVAL;
211     }
212 }
213 
214 
wr_set_level(RIG * rig,vfo_t vfo,setting_t level,value_t val)215 int wr_set_level(RIG *rig, vfo_t vfo, setting_t level, value_t val)
216 {
217     switch (level)
218     {
219     case RIG_LEVEL_AF:
220     {
221         unsigned long v;
222 
223         if (ioctl(rig->state.rigport.fd, RADIO_GET_MAXVOL, &v)) { return -RIG_EINVAL; }
224 
225         v *= val.f;
226 
227         if (ioctl(rig->state.rigport.fd, RADIO_SET_VOL, &v)) { return -RIG_EINVAL; }
228 
229         return RIG_OK;
230     }
231 
232     case RIG_LEVEL_ATT:
233     {
234         unsigned long v = val.i ? 1 : 0;
235 
236         if (ioctl(rig->state.rigport.fd, RADIO_SET_ATTN, &v)) { return -RIG_EINVAL; }
237 
238         return RIG_OK;
239     }
240 
241     case RIG_LEVEL_IF:
242     {
243         long v = val.i;
244 
245         if (ioctl(rig->state.rigport.fd, RADIO_SET_IFS, &v)) { return -RIG_EINVAL; }
246 
247         return RIG_OK;
248     }
249 
250     case RIG_LEVEL_RF:
251     {
252         long v = val.f * 100; /* iMaxIFGain on wHWVer > RHV_3150 */
253 
254         if (ioctl(rig->state.rigport.fd, RADIO_SET_IFG, &v)) { return -RIG_EINVAL; }
255 
256         return RIG_OK;
257     }
258 
259     default:
260         return -RIG_EINVAL;
261     }
262 }
263 
wr_get_level(RIG * rig,vfo_t vfo,setting_t level,value_t * val)264 int wr_get_level(RIG *rig, vfo_t vfo, setting_t level, value_t *val)
265 {
266     switch (level)
267     {
268     case RIG_LEVEL_AF:
269     {
270         unsigned long v, mv;
271 
272         if (ioctl(rig->state.rigport.fd, RADIO_GET_MAXVOL, &mv)) { return -RIG_EINVAL; }
273 
274         if (ioctl(rig->state.rigport.fd, RADIO_GET_VOL, &v)) { return -RIG_EINVAL; }
275 
276         val->f = (float)v / mv;
277         return RIG_OK;
278     }
279 
280     case RIG_LEVEL_ATT:
281     {
282         unsigned long v;
283 
284         if (ioctl(rig->state.rigport.fd, RADIO_GET_VOL, &v)) { return -RIG_EINVAL; }
285 
286         val->i = v ? rig->state.attenuator[0] : 0;
287         return RIG_OK;
288     }
289 
290     case RIG_LEVEL_STRENGTH:
291     {
292         unsigned long v;
293 
294         if (ioctl(rig->state.rigport.fd, RADIO_GET_SS, &v)) { return -RIG_EINVAL; }
295 
296         val->i = v - 60; /* 0..120, Hamlib assumes S9 = 0dB */
297         return RIG_OK;
298     }
299 
300     case RIG_LEVEL_IF:
301     {
302         long v;
303 
304         if (ioctl(rig->state.rigport.fd, RADIO_GET_IFS, &v)) { return -RIG_EINVAL; }
305 
306         val->i = v;
307         return RIG_OK;
308     }
309 
310     case RIG_LEVEL_RF:
311     {
312         long v;
313 
314         if (ioctl(rig->state.rigport.fd, RADIO_GET_IFG, &v)) { return -RIG_EINVAL; }
315 
316         val->f = (float)v / 100; /* iMaxIFGain on wHWVer > RHV_3150 */
317         return RIG_OK;
318     }
319 
320     default:
321         return -RIG_EINVAL;
322     }
323 }
324 
325 /*
326  * FIXME: static buf does not allow reentrancy!
327  */
wr_get_info(RIG * rig)328 const char *wr_get_info(RIG *rig)
329 {
330     static char buf[100];
331 
332     if (ioctl(rig->state.rigport.fd, RADIO_GET_DESCR, buf) < 0) { return "?"; }
333 
334     return buf;
335 }
336 
337 #endif  /* WINRADIO_IOCTL */
338 
DECLARE_INITRIG_BACKEND(winradio)339 DECLARE_INITRIG_BACKEND(winradio)
340 {
341     rig_debug(RIG_DEBUG_VERBOSE, "%s: _init called\n", __func__);
342 
343 #ifdef WINRADIO_IOCTL
344     rig_register(&wr1000_caps);
345     rig_register(&wr1500_caps);
346     rig_register(&wr1550_caps);
347     rig_register(&wr3100_caps);
348     rig_register(&wr3150_caps);
349     rig_register(&wr3500_caps);
350     rig_register(&wr3700_caps);
351 #endif  /* WINRADIO_IOCTL */
352 
353     /* Receivers with DLL only available under Windows */
354 #ifdef _WIN32
355 #ifdef __CYGWIN__
356     rig_register(&g303_caps);
357     rig_register(&g305_caps);
358 #endif
359 #endif
360 
361     /* Available on Linux and MS Windows */
362 #ifndef OTHER_POSIX
363     rig_register(&g313_caps);
364 #endif
365 
366     return RIG_OK;
367 }
368