diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index d7c419cc..5fb7fb2e 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -142,6 +142,9 @@ struct linuxdvb_satconf */ int ls_lnb_poweroff; uint32_t ls_max_rotor_move; + int ls_site_lat_south; + int ls_site_lon_west; + int ls_site_altitude; /* * Position diff --git a/src/input/mpegts/linuxdvb/linuxdvb_rotor.c b/src/input/mpegts/linuxdvb/linuxdvb_rotor.c index ae426954..0715e598 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_rotor.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_rotor.c @@ -120,12 +120,6 @@ const idclass_t linuxdvb_rotor_usals_class = .name = "Satellite Longitude", .off = offsetof(linuxdvb_rotor_t, lr_sat_lon), }, - { - .type = PT_DBL, - .id = "zero_lon", - .name = "Zero Sat Longitude", - .off = offsetof(linuxdvb_rotor_t, lr_zero_lon), - }, { .type = PT_U16, .id = "rate", @@ -219,73 +213,164 @@ linuxdvb_rotor_gotox_tune return linuxdvb_rotor_grace((linuxdvb_diseqc_t*)lr,lm); } +static inline +double to_radians( double val ) +{ + return ((val * M_PI) / 180.0); +} + +static inline +double to_degrees( double val ) +{ + return ((val * 180.0) / M_PI); +} + +static inline +double to_rev( double val ) +{ + return val - floor(val / 360.0) * 360; +} + +static +void usals_sat_azimuth_and_elevation + ( double site_lat, double site_lon, double site_alt, double sat_lon, + double *azimuth, double *elevation ) +{ + const double f = 1.00 / 298.257; // Earth flattening factor + const double r_sat = 42164.57; // Distance from earth centre to satellite + const double r_eq = 6378.14; // Earth radius + + const double a0 = 0.58804392; + const double a1 = -0.17941557; + const double a2 = 0.29906946E-1; + const double a3 = -0.25187400E-2; + const double a4 = 0.82622101E-4; + + double sin_site_lat = sin(to_radians(site_lat)); + double cos_site_lat = cos(to_radians(site_lat)); + double Rstation = r_eq / sqrt(1.00 - f*(2.00-f)*sin_site_lat*sin_site_lat); + double Ra = (Rstation+site_alt)*cos_site_lat; + double Rz = Rstation*(1.00-f)*(1.00-f)*sin_site_lat; + double alfa_rx = r_sat*cos(to_radians(sat_lon-site_lon)) - Ra; + double alfa_ry = r_sat*sin(to_radians(sat_lon-site_lon)); + double alfa_rz = -Rz; + double alfa_r_north = -alfa_rx*sin_site_lat + alfa_rz*cos_site_lat; + + double alfa_r_zenith = alfa_rx*cos_site_lat + alfa_rz*sin_site_lat; + double El_geometric = to_degrees(atan(alfa_r_zenith/sqrt(alfa_r_north*alfa_r_north+alfa_ry*alfa_ry))); + double x = fabs(El_geometric+0.589); + double refraction = fabs(a0+a1*x+a2*x*x+a3*x*x*x+a4*x*x*x*x); + + *azimuth = 0.00; + if (alfa_r_north < 0) + *azimuth = 180+to_degrees(atan(alfa_ry/alfa_r_north)); + else + *azimuth = to_rev(360+to_degrees(atan(alfa_ry/alfa_r_north))); + + *elevation = 0.00; + if (El_geometric > 10.2) + *elevation = El_geometric+0.01617*(cos(to_radians(fabs(El_geometric)))/ + sin(to_radians(fabs(El_geometric)))); + else + *elevation = El_geometric+refraction; + if (alfa_r_zenith < -3000) + *elevation = -99; +} + +/* + * Site Latitude + * Site Longtitude + * Site Altitude + * Satellite Longtitute + */ +static double +usals_sat_angle( double site_lat, double site_lon, + double site_alt, double sat_lon ) +{ + double azimuth, elevation; + + usals_sat_azimuth_and_elevation(site_lat, site_lon, site_alt, sat_lon, + &azimuth, &elevation); + + tvhtrace("diseqc", "rotor angle azimuth %.4f elevation %.4f", azimuth, elevation); + + double rad_azimuth = to_radians(azimuth); + double rad_elevation = to_radians(elevation); + double rad_site_lat = to_radians(site_lat); + double cos_elevation = cos(rad_elevation); + double a, b, value; + + a = -cos_elevation * sin(rad_azimuth); + b = sin(rad_elevation) * cos(rad_site_lat) - + cos_elevation * sin(rad_site_lat) * cos(rad_azimuth); + + value = 180 + to_degrees(atan(a/b)); + + if (azimuth > 270) { + value = value + 180; + if (value > 360) + value = 360 - (value-360); + } + if (azimuth < 90) + value = 180 - value; + + if (value < 180) { + return round(fabs(180 - value) * 10.0); + } else { + return -round(fabs(180 - value) * 10.0); + } + + return value; +} + /* USALS */ static int linuxdvb_rotor_usals_tune ( linuxdvb_rotor_t *lr, dvb_mux_t *lm, linuxdvb_satconf_ele_t *ls, int fd ) { - /* - * Code originally written in PR #238 by Jason Millard jsm174 - * - * USALS rotor logic adapted from tune-s2 - * http://updatelee.blogspot.com/2010/09/tune-s2.html - * - * Antenna Alignment message data format: - * http://www.dvb.org/technology/standards/A155-3_DVB-RCS2_Higher_layer_satellite_spec.pdf - */ + static const uint8_t xtable[10] = + { 0x00, 0x02, 0x03, 0x05, 0x06, 0x08, 0x0A, 0x0B, 0x0D, 0x0E }; -#define TO_DEG(x) ((x * 180.0) / M_PI) -#define TO_RAD(x) ((x * M_PI) / 180.0) - + double site_lat = lr->lr_site_lat; + double site_lon = lr->lr_site_lon; + double sat_lon = lr->lr_sat_lon; + double motor_angle; + uint32_t tmp, cmd; int i; - - static const double r_eq = 6378.14; - static const double r_sat = 42164.57; - double lat = TO_RAD(lr->lr_site_lat); - double lon = TO_RAD(lr->lr_site_lon); - double pos = TO_RAD(lr->lr_sat_lon - lr->lr_zero_lon); - - double dishVector[3] = { - (r_eq * cos(lat)), - 0, - (r_eq * sin(lat)), - }; - - double satVector[3] = { - (r_sat * cos(lon - pos)), - (r_sat * sin(lon - pos)), - 0 - }; - - double satPointing[3] = { - (satVector[0] - dishVector[0]), - (satVector[1] - dishVector[1]), - (satVector[2] - dishVector[2]) - }; - - double motor_angle = TO_DEG(atan(satPointing[1] / satPointing[0])); - - int sixteenths = ((fabs(motor_angle) * 16.0) + 0.5); - - int angle_1 = (((motor_angle > 0.0) ? 0xd0 : 0xe0) | (sixteenths >> 8)); - int angle_2 = (sixteenths & 0xff); - - tvhtrace("diseqc", "rotor USALS site lat %0.4f%c site lon %0.4f%c sat lon %0.1f%c zero %0.1f%c", - fabs(lr->lr_site_lat), (lr->lr_site_lat > 0.0) ? 'N' : 'S', - fabs(lr->lr_site_lon), (lr->lr_site_lon > 0.0) ? 'E' : 'W', - fabs(lr->lr_sat_lon), (lr->lr_sat_lon > 0.0) ? 'E' : 'W', - fabs(lr->lr_zero_lon), (lr->lr_zero_lon > 0.0) ? 'E' : 'W'); - if (linuxdvb_rotor_check_orbital_pos(lm, ls)) return 0; - tvhtrace("diseqc", "rotor USALS goto %0.1f%c (motor %0.2f %sclockwise)", + if (ls->lse_parent->ls_site_lat_south) + site_lat = -site_lat; + if (ls->lse_parent->ls_site_lon_west) + site_lon = 360 - site_lon; + if (sat_lon < 0) + sat_lon = 360 - sat_lon; + + motor_angle = usals_sat_angle(lr->lr_site_lat, lr->lr_site_lon, + ls->lse_parent->ls_site_altitude, + lr->lr_sat_lon); + + if (site_lat >= 0) { + tmp = round(fabs(180 - motor_angle) * 10.0); + cmd = ((tmp / 10) * 0x10 + xtable[tmp % 10]) | + (motor_angle < 180 ? 0xE000 : 0xD000); + } else if (motor_angle < 180) { + tmp = round(fabs(motor_angle) * 10.0); + cmd = ((tmp / 10) * 0x10 + xtable[tmp % 10]) | 0xD000; + } else { + tmp = round(fabs(360 - motor_angle) * 10.0); + cmd = ((tmp / 10) * 0x10 + xtable[tmp % 10]) | 0xE000; + } + + tvhtrace("diseqc", "rotor USALS goto %0.1f%c (motor %0.1f %sclockwise)", fabs(lr->lr_sat_lon), (lr->lr_sat_lon > 0.0) ? 'E' : 'W', - motor_angle, (motor_angle > 0.0) ? "counter-" : ""); + ((double)tmp / 10.0), (cmd & 0xE000) == 0xE000 ? "counter-" : ""); for (i = 0; i <= ls->lse_parent->ls_diseqc_repeats; i++) { - if (linuxdvb_diseqc_send(fd, 0xE0, 0x31, 0x6E, 2, angle_1, angle_2)) { + if (linuxdvb_diseqc_send(fd, 0xE0, 0x31, 0x6E, 2, + (cmd >> 8) & 0xff, cmd & 0xff)) { tvherror("diseqc", "failed to send USALS command"); return -1; } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c index df8ec774..e200348e 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c @@ -239,6 +239,30 @@ const idclass_t linuxdvb_satconf_class = .opts = PO_ADVANCED, .def.u32 = 120 }, + { + .type = PT_BOOL, + .id = "site_lat_south", + .name = "Latitude Direction South", + .off = offsetof(linuxdvb_satconf_t, ls_site_lat_south), + .opts = PO_ADVANCED, + .def.i = 0 + }, + { + .type = PT_BOOL, + .id = "site_lat_south", + .name = "Longtitude Direction West", + .off = offsetof(linuxdvb_satconf_t, ls_site_lon_west), + .opts = PO_ADVANCED, + .def.i = 0 + }, + { + .type = PT_INT, + .id = "site_altitude", + .name = "Altitude (meters)", + .off = offsetof(linuxdvb_satconf_t, ls_site_altitude), + .opts = PO_ADVANCED, + .def.i = 0 + }, {} } };