Project

General

Profile

RE: Rotor(Motor) Support Latest Information. ยป linuxdvb_rotor.c

o o, 2014-09-20 17:32

 
1
/*
2
 *  Tvheadend - Linux DVB DiseqC Rotor
3
 *
4
 *  Copyright (C) 2013 Adam Sutton
5
 *
6
 *  This program is free software: you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation, either version 3 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program 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
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
#include "tvheadend.h"
21
#include "linuxdvb_private.h"
22
#include "settings.h"
23

    
24
#include <sys/ioctl.h>
25
#include <sys/types.h>
26
#include <sys/stat.h>
27
#include <unistd.h>
28
#include <fcntl.h>
29
#include <assert.h>
30
#include <math.h>
31
#include <linux/dvb/frontend.h>
32

    
33
/* **************************************************************************
34
 * Class definition
35
 * *************************************************************************/
36

    
37
#define MAX_FAR_AWAY_SAT 5.0
38
double old_pos = MAX_FAR_AWAY_SAT; 
39

    
40
typedef struct linuxdvb_rotor
41
{
42
  linuxdvb_diseqc_t;
43

    
44
  /* USALS */
45
  double    lr_site_lat;
46
  double    lr_site_lon;
47
  double    lr_sat_lon;
48
  
49
  /* GOTOX */
50
  uint32_t  lr_position;
51

    
52
  uint32_t  lr_rate;
53

    
54
} linuxdvb_rotor_t;
55

    
56
static const char *
57
linuxdvb_rotor_class_get_title ( idnode_t *o )
58
{
59
  static char buf[256];
60
  linuxdvb_diseqc_t *ld = (linuxdvb_diseqc_t*)o;
61
  snprintf(buf, sizeof(buf), "Rotor: %s", ld->ld_type);
62
  return buf;
63
}
64

    
65
extern const idclass_t linuxdvb_diseqc_class;
66

    
67
const idclass_t linuxdvb_rotor_class = {
68
  .ic_super       = &linuxdvb_diseqc_class,
69
  .ic_class       = "linuxdvb_rotor",
70
  .ic_caption     = "DiseqC Rotor",
71
  .ic_get_title   = linuxdvb_rotor_class_get_title,
72
};
73

    
74
const idclass_t linuxdvb_rotor_gotox_class =
75
{
76
  .ic_super       = &linuxdvb_rotor_class,
77
  .ic_class       = "linuxdvb_rotor_gotox",
78
  .ic_caption     = "GOTOX Rotor",
79
  .ic_properties  = (const property_t[]) {
80
    {
81
      .type   = PT_U16,
82
      .id     = "position",
83
      .name   = "Position",
84
      .off    = offsetof(linuxdvb_rotor_t, lr_position),
85
    },
86
    {
87
      .type   = PT_U16,
88
      .id     = "rate",
89
      .name   = "Rate (millis/click)",
90
      .off    = offsetof(linuxdvb_rotor_t, lr_rate),
91
    },
92
    {}
93
  }
94
};
95

    
96
const idclass_t linuxdvb_rotor_usals_class =
97
{
98
  .ic_super       = &linuxdvb_rotor_class,
99
  .ic_class       = "linuxdvb_rotor_usals",
100
  .ic_caption     = "USALS Rotor",
101
  .ic_properties  = (const property_t[]) {
102
    {
103
      .type   = PT_DBL,
104
      .id     = "site_lat",
105
      .name   = "Site Latitude",
106
      .off    = offsetof(linuxdvb_rotor_t, lr_site_lat),
107
    },
108
    {
109
      .type   = PT_DBL,
110
      .id     = "site_lon",
111
      .name   = "Site Longitude",
112
      .off    = offsetof(linuxdvb_rotor_t, lr_site_lon),
113
    },
114
    {
115
      .type   = PT_DBL,
116
      .id     = "sat_lon",
117
      .name   = "Satellite Longitude",
118
      .off    = offsetof(linuxdvb_rotor_t, lr_sat_lon),
119
    },
120
    {
121
      .type   = PT_U16,
122
      .id     = "rate",
123
      .name   = "Rate (millis/deg)",
124
      .off    = offsetof(linuxdvb_rotor_t, lr_rate),
125
    },
126
 
127
    {}
128
  }
129
};
130

    
131
/* **************************************************************************
132
 * Class methods
133
 * *************************************************************************/
134

    
135
static int
136
linuxdvb_rotor_grace
137
  ( linuxdvb_diseqc_t *ld, dvb_mux_t *lm )
138
{
139
  linuxdvb_rotor_t *lr = (linuxdvb_rotor_t*)ld;
140
 // linuxdvb_satconf_t *ls = ld->ld_satconf->lse_parent;
141
  double newpos;
142
  int delta;
143
#if 0
144
  if (!ls->ls_orbital_dir || lr->lr_rate == 0)
145
    return 120;
146
#endif
147
  if (idnode_is_instance(&lr->ld_id, &linuxdvb_rotor_gotox_class))
148
    newpos = lr->lr_position;                /* GotoX */
149
  else
150
    // newpos = (lr->lr_sat_lon + 0.005) * 100; /* USALS */
151
       newpos = lr->lr_sat_lon;
152
#if 0
153
  if (ls->ls_orbital_dir == 'W')
154
    curpos = -(curpos);
155
   delta = abs(deltaI32(curpos, newpos));
156
#endif
157
     delta = fabs(ceil(newpos - old_pos));
158
     old_pos = newpos;
159

    
160
  /* ignore very small movements like 0.8W and 1W */
161
  if (delta <= 2)
162
    return 0;
163
  /* add one extra second, because of the rounding issue */
164
  // return ((lr->lr_rate*delta+999)/1000) + 1;
165

    
166
     return ((lr->lr_rate*delta)/1000) + 1;
167
}
168

    
169
static int
170
linuxdvb_rotor_check_orbital_pos
171
  ( dvb_mux_t *lm, linuxdvb_satconf_ele_t *ls )
172
{
173
  int  pos;
174
  char dir;
175

    
176

    
177
  if (dvb_network_get_orbital_pos(lm->mm_network, &pos, &dir) < 0)
178
    return 0;
179

    
180
  if (dir != ls->lse_parent->ls_orbital_dir)
181
    return 0;
182

    
183
  if (abs(pos - ls->lse_parent->ls_orbital_pos) > 2)
184
    return 0;
185

    
186
  tvhdebug("diseqc", "rotor already positioned to %i.%i%c",
187
                     pos / 10, pos % 10, dir);
188
  return 1;
189
}
190

    
191
/* GotoX */
192
static int
193
linuxdvb_rotor_gotox_tune
194
  ( linuxdvb_rotor_t *lr, dvb_mux_t *lm, linuxdvb_satconf_ele_t *ls, int fd )
195
{
196
  int i;
197

    
198
  if (linuxdvb_rotor_check_orbital_pos(lm, ls))
199
    return 0;
200

    
201
  for (i = 0; i <= ls->lse_parent->ls_diseqc_repeats; i++) {
202
    if (linuxdvb_diseqc_send(fd, 0xE0, 0x31, 0x6B, 1, (int)lr->lr_position)) {
203
      tvherror("diseqc", "failed to set GOTOX pos %d", lr->lr_position);
204
      return -1;
205
    }
206
    usleep(25000);
207
  }
208

    
209
  tvhdebug("diseqc", "rotor GOTOX pos %d sent", lr->lr_position);
210

    
211
  return linuxdvb_rotor_grace((linuxdvb_diseqc_t*)lr,lm);
212
}
213

    
214
/* USALS */
215
static int
216
linuxdvb_rotor_usals_tune
217
  ( linuxdvb_rotor_t *lr, dvb_mux_t *lm, linuxdvb_satconf_ele_t *ls, int fd )
218
{
219
  /*
220
   * Code originally written in PR #238 by Jason Millard jsm174
221
   *
222
   * USALS rotor logic adapted from tune-s2 
223
   * http://updatelee.blogspot.com/2010/09/tune-s2.html 
224
   *
225
   * Antenna Alignment message data format: 
226
   * http://www.dvb.org/technology/standards/A155-3_DVB-RCS2_Higher_layer_satellite_spec.pdf 
227
   */
228

    
229
#define TO_DEG(x) ((x * 180.0) / M_PI)
230
#define TO_RAD(x) ((x * M_PI) / 180.0)
231
  
232
  int i;
233
 
234
  static const double r_eq  = 6378.14;
235
  static const double r_sat = 42164.57;
236

    
237
  double lat = TO_RAD(lr->lr_site_lat);
238
  double lon = TO_RAD(lr->lr_site_lon);
239
  double pos = TO_RAD(lr->lr_sat_lon);
240
     
241
  double dishVector[3] = {
242
    (r_eq * cos(lat)),
243
    0,
244
    (r_eq * sin(lat)),
245
  };
246
     
247
  double satVector[3] = {
248
    (r_sat * cos(lon - pos)),
249
    (r_sat * sin(lon - pos)),
250
    0
251
  };
252

    
253
  double satPointing[3] = {
254
    (satVector[0] - dishVector[0]),
255
    (satVector[1] - dishVector[1]),
256
    (satVector[2] - dishVector[2])
257
  };
258

    
259
  double motor_angle = TO_DEG(atan(satPointing[1] / satPointing[0]));
260

    
261
  int sixteenths = ((fabs(motor_angle) * 16.0) + 0.5);
262

    
263
  int angle_1 = (((motor_angle > 0.0) ? 0xd0 : 0xe0) | (sixteenths >> 8));
264
  int angle_2 = (sixteenths & 0xff);
265

    
266
#if 0 
267
  if (linuxdvb_rotor_check_orbital_pos(lm, ls))
268
    return 0;
269
#endif
270

    
271
  if(lr->lr_sat_lon == old_pos) /* Dish already at same position, no need to move */
272
     return 0;
273

    
274
  tvhtrace("diseqc", "rotor USALS goto %0.1f%c (motor %0.2f %sclockwise)",
275
           fabs(lr->lr_sat_lon), (lr->lr_sat_lon > 0.0) ? 'E' : 'W',
276
           motor_angle, (motor_angle > 0.0) ? "counter-" : "");
277

    
278
  for (i = 0; i <= ls->lse_parent->ls_diseqc_repeats; i++) {
279
    if (linuxdvb_diseqc_send(fd, 0xE0, 0x31, 0x6E, 2, angle_1, angle_2)) {
280
      tvherror("diseqc", "failed to send USALS command");
281
      return -1;
282
    }
283
    usleep(25000);
284
  }
285

    
286
  return linuxdvb_rotor_grace((linuxdvb_diseqc_t*)lr,lm);
287

    
288
#undef TO_RAD
289
#undef TO_DEG
290
}
291

    
292
static int
293
linuxdvb_rotor_tune
294
  ( linuxdvb_diseqc_t *ld, dvb_mux_t *lm, linuxdvb_satconf_ele_t *ls, int fd )
295
{
296
  linuxdvb_rotor_t *lr = (linuxdvb_rotor_t*)ld;
297

    
298
  /* Force to 18v (quicker movement) */
299
  if (ioctl(fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18)) {
300
    tvherror("diseqc", "failed to set 18v for rotor movement");
301
    return -1;
302
  }
303
  usleep(15000);
304

    
305
  /* GotoX */
306
  if (idnode_is_instance(&lr->ld_id, &linuxdvb_rotor_gotox_class))
307
    return linuxdvb_rotor_gotox_tune(lr, lm, ls, fd);
308

    
309
  /* USALS */
310
  return linuxdvb_rotor_usals_tune(lr, lm, ls, fd);
311
}
312

    
313
/* **************************************************************************
314
 * Create / Config
315
 * *************************************************************************/
316

    
317
struct {
318
  const char      *name;
319
  const idclass_t *idc;
320
} linuxdvb_rotor_all[] = {
321
  {
322
    .name = "GOTOX",
323
    .idc  = &linuxdvb_rotor_gotox_class
324
  },
325
  {
326
    .name = "USALS",
327
    .idc  = &linuxdvb_rotor_usals_class
328
  }
329
};
330

    
331
htsmsg_t *
332
linuxdvb_rotor_list ( void *o )
333
{
334
  int i;
335
  htsmsg_t *m = htsmsg_create_list(); 
336
  htsmsg_add_str(m, NULL, "None");
337
  for (i = 0; i < ARRAY_SIZE(linuxdvb_rotor_all); i++)
338
    htsmsg_add_str(m, NULL, linuxdvb_rotor_all[i].name);
339
  return m;
340
}
341

    
342
linuxdvb_diseqc_t *
343
linuxdvb_rotor_create0
344
  ( const char *name, htsmsg_t *conf, linuxdvb_satconf_ele_t *ls )
345
{
346
  int i;
347
  linuxdvb_diseqc_t *ld = NULL;
348

    
349
  for (i = 0; i < ARRAY_SIZE(linuxdvb_rotor_all); i++) {
350
    if (!strcmp(name ?: "", linuxdvb_rotor_all[i].name)) {
351
      ld = linuxdvb_diseqc_create0(calloc(1, sizeof(linuxdvb_rotor_t)),
352
                                   NULL, linuxdvb_rotor_all[i].idc, conf,
353
                                   linuxdvb_rotor_all[i].name, ls);
354
      if (ld) {
355
        ld->ld_tune  = linuxdvb_rotor_tune;
356
        ld->ld_grace = linuxdvb_rotor_grace;
357
      }
358
    }
359
  }
360
                                 
361
  return ld;
362
}
363

    
364
void
365
linuxdvb_rotor_destroy ( linuxdvb_diseqc_t *lr )
366
{
367
  linuxdvb_diseqc_destroy(lr);
368
  free(lr);
369
}
370

    
371
/******************************************************************************
372
 * Editor Configuration
373
 *
374
 * vim:sts=2:ts=2:sw=2:et
375
 *****************************************************************************/
    (1-1/1)