1 /*
2 * Hamlib ts7400 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 <sys/time.h>
31 #include <time.h>
32
33 #include <hamlib/rotator.h>
34 #include "serial.h"
35 #include "misc.h"
36 #include "register.h"
37
38 #include "ts7400.h"
39
40 struct ts7400_rot_priv_data
41 {
42 azimuth_t az;
43 elevation_t el;
44
45 struct timeval tv; /* time last az/el update */
46 azimuth_t target_az;
47 elevation_t target_el;
48 };
49
50
51
ts7400_rot_init(ROT * rot)52 static int ts7400_rot_init(ROT *rot)
53 {
54 struct ts7400_rot_priv_data *priv;
55
56 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
57
58 rot->state.priv = (struct ts7400_rot_priv_data *)
59 malloc(sizeof(struct ts7400_rot_priv_data));
60
61 if (!rot->state.priv)
62 {
63 return -RIG_ENOMEM;
64 }
65
66 priv = rot->state.priv;
67
68 rot->state.rotport.type.rig = RIG_PORT_NONE;
69
70 priv->az = priv->el = 0;
71
72 priv->target_az = priv->target_el = 0;
73
74 return RIG_OK;
75 }
76
ts7400_rot_cleanup(ROT * rot)77 static int ts7400_rot_cleanup(ROT *rot)
78 {
79 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
80
81 if (rot->state.priv)
82 {
83 free(rot->state.priv);
84 }
85
86 rot->state.priv = NULL;
87
88 return RIG_OK;
89 }
90
ts7400_rot_open(ROT * rot)91 static int ts7400_rot_open(ROT *rot)
92 {
93 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
94
95 return RIG_OK;
96 }
97
ts7400_rot_close(ROT * rot)98 static int ts7400_rot_close(ROT *rot)
99 {
100 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
101
102 return RIG_OK;
103 }
104
ts7400_rot_set_position(ROT * rot,azimuth_t az,elevation_t el)105 static int ts7400_rot_set_position(ROT *rot, azimuth_t az, elevation_t el)
106 {
107 struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)
108 rot->state.priv;
109
110 rig_debug(RIG_DEBUG_VERBOSE, "%s called: %.2f %.2f\n", __func__,
111 az, el);
112
113 priv->target_az = az;
114 priv->target_el = el;
115
116 gettimeofday(&priv->tv, NULL);
117
118 return RIG_OK;
119 }
120
121
122 /*
123 * Get position of rotor, simulating slow rotation
124 */
ts7400_rot_get_position(ROT * rot,azimuth_t * az,elevation_t * el)125 static int ts7400_rot_get_position(ROT *rot, azimuth_t *az, elevation_t *el)
126 {
127 struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)
128 rot->state.priv;
129 struct timeval tv;
130 unsigned elapsed; /* ms */
131
132 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
133
134 if (priv->az == priv->target_az &&
135 priv->el == priv->target_el)
136 {
137 *az = priv->az;
138 *el = priv->el;
139 return RIG_OK;
140 }
141
142 gettimeofday(&tv, NULL);
143
144 elapsed = (tv.tv_sec - priv->tv.tv_sec) * 1000 +
145 (tv.tv_usec - priv->tv.tv_usec) / 1000;
146
147 /*
148 * Simulate rotation speed of 360 deg per minute
149 */
150 #define DEG_PER_MS (360./60/1000)
151
152 if (fabs(priv->target_az - priv->az) / DEG_PER_MS <= elapsed)
153 {
154 /* target reached */
155 priv->az = priv->target_az;
156 }
157 else
158 {
159 if (priv->az < priv->target_az)
160 {
161 priv->az += (azimuth_t)elapsed * DEG_PER_MS;
162 }
163 else
164 {
165 priv->az -= (azimuth_t)elapsed * DEG_PER_MS;
166 }
167 }
168
169 if (fabs(priv->target_el - priv->el) / DEG_PER_MS <= elapsed)
170 {
171 /* target reached */
172 priv->el = priv->target_el;
173 }
174 else
175 {
176 if (priv->el < priv->target_el)
177 {
178 priv->el += (elevation_t)elapsed * DEG_PER_MS;
179 }
180 else
181 {
182 priv->el -= (elevation_t)elapsed * DEG_PER_MS;
183 }
184 }
185
186 *az = priv->az;
187 *el = priv->el;
188
189 priv->tv = tv;
190
191 return RIG_OK;
192 }
193
194
ts7400_rot_stop(ROT * rot)195 static int ts7400_rot_stop(ROT *rot)
196 {
197 struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)
198 rot->state.priv;
199 azimuth_t az;
200 elevation_t el;
201
202 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
203
204 ts7400_rot_get_position(rot, &az, &el);
205
206 priv->target_az = priv->az = az;
207 priv->target_el = priv->el = el;
208
209 return RIG_OK;
210 }
211
212
ts7400_rot_park(ROT * rot)213 static int ts7400_rot_park(ROT *rot)
214 {
215 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
216
217 /* Assume home is 0,0 */
218 ts7400_rot_set_position(rot, 0, 0);
219
220 return RIG_OK;
221 }
222
ts7400_rot_reset(ROT * rot,rot_reset_t reset)223 static int ts7400_rot_reset(ROT *rot, rot_reset_t reset)
224 {
225 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
226
227 return RIG_OK;
228 }
229
ts7400_rot_move(ROT * rot,int direction,int speed)230 static int ts7400_rot_move(ROT *rot, int direction, int speed)
231 {
232 struct ts7400_rot_priv_data *priv = (struct ts7400_rot_priv_data *)
233 rot->state.priv;
234
235 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
236 rig_debug(RIG_DEBUG_TRACE, "%s: Direction = %d, Speed = %d\n", __func__,
237 direction, speed);
238
239 switch (direction)
240 {
241 case ROT_MOVE_UP:
242 return ts7400_rot_set_position(rot, priv->target_az, 90);
243
244 case ROT_MOVE_DOWN:
245 return ts7400_rot_set_position(rot, priv->target_az, 0);
246
247 case ROT_MOVE_CCW:
248 return ts7400_rot_set_position(rot, -180, priv->target_el);
249
250 case ROT_MOVE_CW:
251 return ts7400_rot_set_position(rot, 180, priv->target_el);
252
253 default:
254 return -RIG_EINVAL;
255 }
256
257 return RIG_OK;
258 }
259
ts7400_rot_get_info(ROT * rot)260 static const char *ts7400_rot_get_info(ROT *rot)
261 {
262 rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
263
264 return "ts7400 rotator";
265 }
266
267
268
269 /*
270 * ts7400 rotator capabilities.
271 */
272
273 const struct rot_caps ts7400_rot_caps =
274 {
275 ROT_MODEL(ROT_MODEL_TS7400),
276 .model_name = "ts7400",
277 .mfg_name = "LA7LKA",
278 .version = "20200113.0",
279 .copyright = "LGPL",
280 .status = RIG_STATUS_BETA,
281 .rot_type = ROT_TYPE_AZEL,
282 .port_type = RIG_PORT_NONE,
283
284 .min_az = -180.,
285 .max_az = 180.,
286 .min_el = 0.,
287 .max_el = 90.,
288
289 .priv = NULL, /* priv */
290
291 .rot_init = ts7400_rot_init,
292 .rot_cleanup = ts7400_rot_cleanup,
293 .rot_open = ts7400_rot_open,
294 .rot_close = ts7400_rot_close,
295
296 .set_position = ts7400_rot_set_position,
297 .get_position = ts7400_rot_get_position,
298 .park = ts7400_rot_park,
299 .stop = ts7400_rot_stop,
300 .reset = ts7400_rot_reset,
301 .move = ts7400_rot_move,
302
303 .get_info = ts7400_rot_get_info,
304 };
305
DECLARE_INITROT_BACKEND(ts7400)306 DECLARE_INITROT_BACKEND(ts7400)
307 {
308 rig_debug(RIG_DEBUG_VERBOSE, "%s: _init called\n", __func__);
309
310 rot_register(&ts7400_rot_caps);
311
312 return RIG_OK;
313 }
314