1 /*
2  *  Hamlib Netrotctl 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 <stdlib.h>
27 #include <string.h>  /* String function definitions */
28 #include <unistd.h>  /* UNIX standard function definitions */
29 #include <math.h>
30 #include <errno.h>
31 
32 #include "hamlib/rotator.h"
33 #include "iofunc.h"
34 #include "misc.h"
35 #include "network.h"
36 #include "serial.h"
37 
38 #include "rot_dummy.h"
39 
40 #define CMD_MAX 32
41 #define BUF_MAX 64
42 
43 /*
44  * Helper function with protocol return code parsing
45  */
netrotctl_transaction(ROT * rot,char * cmd,int len,char * buf)46 static int netrotctl_transaction(ROT *rot, char *cmd, int len, char *buf)
47 {
48     int ret;
49 
50     /* flush anything in the read buffer before command is sent */
51     rig_flush(&rot->state.rotport);
52 
53     ret = write_block(&rot->state.rotport, cmd, len);
54 
55     if (ret != RIG_OK)
56     {
57         return ret;
58     }
59 
60     ret = read_string(&rot->state.rotport, buf, BUF_MAX, "\n", sizeof("\n"));
61 
62     if (ret < 0)
63     {
64         return ret;
65     }
66 
67     if (!memcmp(buf, NETROTCTL_RET, strlen(NETROTCTL_RET)))
68     {
69         return atoi(buf + strlen(NETROTCTL_RET));
70     }
71 
72     return ret;
73 }
74 
netrotctl_open(ROT * rot)75 static int netrotctl_open(ROT *rot)
76 {
77     int ret, len;
78     struct rot_state *rs = &rot->state;
79     int prot_ver;
80     char cmd[CMD_MAX];
81     char buf[BUF_MAX];
82 
83     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
84 
85 
86     len = sprintf(cmd, "\\dump_state\n");
87 
88     ret = netrotctl_transaction(rot, cmd, len, buf);
89 
90     if (ret <= 0)
91     {
92         return (ret < 0) ? ret : -RIG_EPROTO;
93     }
94 
95     prot_ver = atoi(buf);
96 #define ROTCTLD_PROT_VER 0
97 
98     if (prot_ver < ROTCTLD_PROT_VER)
99     {
100         return -RIG_EPROTO;
101     }
102 
103     ret = read_string(&rot->state.rotport, buf, BUF_MAX, "\n", sizeof("\n"));
104 
105     if (ret <= 0)
106     {
107         return (ret < 0) ? ret : -RIG_EPROTO;
108     }
109 
110     ret = read_string(&rot->state.rotport, buf, BUF_MAX, "\n", sizeof("\n"));
111 
112     if (ret <= 0)
113     {
114         return (ret < 0) ? ret : -RIG_EPROTO;
115     }
116 
117     rs->min_az = atof(buf);
118 
119     ret = read_string(&rot->state.rotport, buf, BUF_MAX, "\n", sizeof("\n"));
120 
121     if (ret <= 0)
122     {
123         return (ret < 0) ? ret : -RIG_EPROTO;
124     }
125 
126     rs->max_az = atof(buf);
127 
128     ret = read_string(&rot->state.rotport, buf, BUF_MAX, "\n", sizeof("\n"));
129 
130     if (ret <= 0)
131     {
132         return (ret < 0) ? ret : -RIG_EPROTO;
133     }
134 
135     rs->min_el = atof(buf);
136 
137     ret = read_string(&rot->state.rotport, buf, BUF_MAX, "\n", sizeof("\n"));
138 
139     if (ret <= 0)
140     {
141         return (ret < 0) ? ret : -RIG_EPROTO;
142     }
143 
144     rs->max_el = atof(buf);
145 
146     return RIG_OK;
147 }
148 
netrotctl_close(ROT * rot)149 static int netrotctl_close(ROT *rot)
150 {
151     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
152 
153     /* clean signoff, no read back */
154     write_block(&rot->state.rotport, "q\n", 2);
155 
156     return RIG_OK;
157 }
158 
netrotctl_set_position(ROT * rot,azimuth_t az,elevation_t el)159 static int netrotctl_set_position(ROT *rot, azimuth_t az, elevation_t el)
160 {
161     int ret, len;
162     char cmd[CMD_MAX];
163     char buf[BUF_MAX];
164 
165     rig_debug(RIG_DEBUG_VERBOSE, "%s called: %f %f\n", __func__,
166               az, el);
167 
168     len = sprintf(cmd, "P %f %f\n", az, el);
169 
170     ret = netrotctl_transaction(rot, cmd, len, buf);
171 
172     if (ret > 0)
173     {
174         return -RIG_EPROTO;
175     }
176     else
177     {
178         return ret;
179     }
180 }
181 
netrotctl_get_position(ROT * rot,azimuth_t * az,elevation_t * el)182 static int netrotctl_get_position(ROT *rot, azimuth_t *az, elevation_t *el)
183 {
184     int ret, len;
185     char cmd[CMD_MAX];
186     char buf[BUF_MAX];
187 
188     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
189 
190     len = sprintf(cmd, "p\n");
191 
192     ret = netrotctl_transaction(rot, cmd, len, buf);
193 
194     if (ret <= 0)
195     {
196         return (ret < 0) ? ret : -RIG_EPROTO;
197     }
198 
199     *az = atof(buf);
200 
201     ret = read_string(&rot->state.rotport, buf, BUF_MAX, "\n", sizeof("\n"));
202 
203     if (ret <= 0)
204     {
205         return (ret < 0) ? ret : -RIG_EPROTO;
206     }
207 
208     *el = atof(buf);
209 
210     return RIG_OK;
211 }
212 
213 
netrotctl_stop(ROT * rot)214 static int netrotctl_stop(ROT *rot)
215 {
216     int ret, len;
217     char cmd[CMD_MAX];
218     char buf[BUF_MAX];
219 
220     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
221 
222     len = sprintf(cmd, "S\n");
223 
224     ret = netrotctl_transaction(rot, cmd, len, buf);
225 
226     if (ret > 0)
227     {
228         return -RIG_EPROTO;
229     }
230     else
231     {
232         return ret;
233     }
234 }
235 
236 
netrotctl_park(ROT * rot)237 static int netrotctl_park(ROT *rot)
238 {
239     int ret, len;
240     char cmd[CMD_MAX];
241     char buf[BUF_MAX];
242 
243     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
244 
245     len = sprintf(cmd, "K\n");
246 
247     ret = netrotctl_transaction(rot, cmd, len, buf);
248 
249     if (ret > 0)
250     {
251         return -RIG_EPROTO;
252     }
253     else
254     {
255         return ret;
256     }
257 }
258 
netrotctl_reset(ROT * rot,rot_reset_t reset)259 static int netrotctl_reset(ROT *rot, rot_reset_t reset)
260 {
261     int ret, len;
262     char cmd[CMD_MAX];
263     char buf[BUF_MAX];
264 
265     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
266 
267     len = sprintf(cmd, "R %d\n", reset);
268 
269     ret = netrotctl_transaction(rot, cmd, len, buf);
270 
271     if (ret > 0)
272     {
273         return -RIG_EPROTO;
274     }
275     else
276     {
277         return ret;
278     }
279 }
280 
netrotctl_move(ROT * rot,int direction,int speed)281 static int netrotctl_move(ROT *rot, int direction, int speed)
282 {
283     int ret, len;
284     char cmd[CMD_MAX];
285     char buf[BUF_MAX];
286 
287     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
288 
289     len = sprintf(cmd, "M %d %d\n", direction, speed);
290 
291     ret = netrotctl_transaction(rot, cmd, len, buf);
292 
293     if (ret > 0)
294     {
295         return -RIG_EPROTO;
296     }
297     else
298     {
299         return ret;
300     }
301 }
302 
netrotctl_get_info(ROT * rot)303 static const char *netrotctl_get_info(ROT *rot)
304 {
305     int ret, len;
306     char cmd[CMD_MAX];
307     static char buf[BUF_MAX];
308 
309     rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
310 
311     len = sprintf(cmd, "_\n");
312 
313     ret = netrotctl_transaction(rot, cmd, len, buf);
314 
315     if (ret < 0)
316     {
317         return NULL;
318     }
319 
320     buf [ret] = '\0';
321 
322     return buf;
323 }
324 
325 
326 
327 /*
328  * NET rotctl capabilities.
329  */
330 
331 const struct rot_caps netrotctl_caps =
332 {
333     ROT_MODEL(ROT_MODEL_NETROTCTL),
334     .model_name =     "NET rotctl",
335     .mfg_name =       "Hamlib",
336     .version =        "20200528.0",
337     .copyright =      "LGPL",
338     .status =         RIG_STATUS_STABLE,
339     .rot_type =       ROT_TYPE_OTHER,
340     .port_type =      RIG_PORT_NETWORK,
341     .timeout = 2000,
342     .retry =   3,
343 
344     .min_az =     -180.,
345     .max_az =     180.,
346     .min_el =     0.,
347     .max_el =     90.,
348 
349     .priv =  NULL,    /* priv */
350 
351     /* .rot_init =     netrotctl_init, */
352     /* .rot_cleanup =  netrotctl_cleanup, */
353     .rot_open =     netrotctl_open,
354     .rot_close =    netrotctl_close,
355 
356     .set_position =     netrotctl_set_position,
357     .get_position =     netrotctl_get_position,
358     .park =     netrotctl_park,
359     .stop =     netrotctl_stop,
360     .reset =    netrotctl_reset,
361     .move =     netrotctl_move,
362 
363     .get_info =      netrotctl_get_info,
364 };
365 
366