Merge pull request #518 from code-posse/master

SatEL rotator support
pull/519/head^2
Michael Black 2021-01-25 11:15:17 -06:00 zatwierdzone przez GitHub
commit 14eb9af7fe
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
6 zmienionych plików z 391 dodań i 1 usunięć

Wyświetl plik

@ -52,7 +52,7 @@ dnl Beware of duplication should a backend directory include both rig and
dnl rotor definitions, e.g. "dummy". Optional backends will not be listed
dnl here but will be added later, e.g. "winradio".
RIG_BACKEND_LIST="rigs/adat rigs/alinco rigs/aor rigs/barrett rigs/dorji rigs/drake rigs/dummy rigs/elad rigs/flexradio rigs/icom rigs/icmarine rigs/jrc rigs/kachina rigs/kenwood rigs/kit rigs/lowe rigs/pcr rigs/prm80 rigs/racal rigs/rft rigs/rs rigs/skanti rigs/tapr rigs/tentec rigs/tuner rigs/uniden rigs/winradio rigs/wj rigs/yaesu"
ROT_BACKEND_LIST="rotators/amsat rotators/ars rotators/celestron rotators/cnctrk rotators/easycomm rotators/ether6 rotators/fodtrack rotators/gs232a rotators/heathkit rotators/m2 rotators/meade rotators/rotorez rotators/sartek rotators/spid rotators/ts7400 rotators/prosistel rotators/ioptron"
ROT_BACKEND_LIST="rotators/amsat rotators/ars rotators/celestron rotators/cnctrk rotators/easycomm rotators/ether6 rotators/fodtrack rotators/gs232a rotators/heathkit rotators/m2 rotators/meade rotators/rotorez rotators/sartek rotators/spid rotators/ts7400 rotators/prosistel rotators/ioptron rotators/satel"
# Amplifiers are all in the amplifiers directory
AMP_BACKEND_LIST="amplifiers/elecraft"
@ -842,6 +842,7 @@ rotators/sartek/Makefile
rotators/spid/Makefile
rotators/ts7400/Makefile
rotators/indi/Makefile
rotators/satel/Makefile
rigs/adat/Makefile
rigs/alinco/Makefile
rigs/aor/Makefile

Wyświetl plik

@ -491,6 +491,20 @@
#define ROT_MODEL_INDI ROT_MAKE_MODEL(ROT_INDI, 1)
/**
* \def ROT_MODEL_SATEL
* \brief A macro that returns the model number of the SatEL backend.
*
* The SatEL backend can be used with rotators that support the VE5FP
* interface.
*/
//! @cond Doxygen_Suppress
#define ROT_SATEL 21
#define ROT_BACKEND_SATEL "satel"
//! @endcond
#define ROT_MODEL_SATEL ROT_MAKE_MODEL(ROT_SATEL, 1)
/**

Wyświetl plik

@ -0,0 +1,6 @@
SATELSRC = satel.c satel.h
noinst_LTLIBRARIES = libhamlib-satel.la
libhamlib_satel_la_SOURCES = $(SATELSRC)
EXTRA_DIST = Android.mk

Wyświetl plik

@ -0,0 +1,339 @@
/*
* Hamlib SatEL backend - main file
* Copyright (c) 2021 Joshua Lynch
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "hamlib/rig.h"
#include <strings.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "hamlib/rotator.h"
#include "serial.h"
#include "misc.h"
#include "register.h"
#include "satel.h"
/**
* Protocol documentation.
*
* Apparently, the system is modeled after this one:
* An Inexpensive Az-El Rotator System
* "Dec, 1999, QST article by Jim Koehler, VE5FP
*
* '?' - returns 'SatEL\r\n'. a good test to see if there's
* connectivity.
*
* 'g' - enable motion. nothing happens without this enabled.
*
* 'z' - display rotator status. contains current Az/El among other
* things. here's an example:
*
* Motion ENABLED
* Mode 0 - azimuth break at NORTH
* Time: 2001/00/00 00:00:07
* Azimuth = 000 Absolute = 000
* Elevation = 000
*
* Number of stored positions: 00
*
*
* '*' - reset the rotator controller.
*
* 'pAZ EL\r\n' - tell the rotator where to point where AZ is the
* integer azimuth and EL is the integer
* elevation. e.g. 'p010 045\n'. the controller will
* report the current pointing status after the
* operation has completed.
*
* NOTE: The SatEL system changed a few commands as described in the
* user's manual. They are not used here. You can find the manual for
* this rotator here:
*
* http://www.codeposse.com/~jlynch/SatEL%20Az-EL.pdf
*
*/
/**
* Idiosyncrasies
*
* - the controller does zero input checking. you can put it into an
* incredibly bad state very easily.
*
* - the controller doesn't accept any data whilst moving the
* rotators. In fact, you can put the controller into a bad state on
* occasion if you try and send it commands while its slewing the
* rotators. this means we have a really long read timeout so we can
* wait for the rotators to slew around before accepting any more
* commands.
*
*/
#define BUF_SIZE 256
typedef struct satel_stat satel_stat_t;
struct satel_stat
{
bool motion_enabled;
int mode;
time_t time;
int absolute;
int az;
int el;
};
static int satel_read_status(ROT *rot, satel_stat_t *stat)
{
char resbuf[BUF_SIZE];
char *p;
int ret;
struct rot_state *rs;
rs = &rot->state;
// XXX skip for now
for (int i = 0; i < 3; i++)
{
ret = read_string(&rs->rotport, resbuf, BUF_SIZE, "\n", 1);
if (ret < 0)
return ret;
}
// read azimuth line
ret = read_string(&rs->rotport, resbuf, BUF_SIZE, "\n", 1);
if (ret < 0)
return ret;
p = resbuf + 10;
p[3] = '\0';
stat->az = (int)strtof(p, NULL);
// read elevation line
ret = read_string(&rs->rotport, resbuf, BUF_SIZE, "\n", 1);
if (ret < 0)
return ret;
p = resbuf + 12;
p[3] = '\0';
stat->el = (int)strtof(p, NULL);
// XXX skip for now
for (int i = 0; i < 2; i++)
{
ret = read_string(&rs->rotport, resbuf, BUF_SIZE, "\n", 1);
if (ret < 0)
return ret;
}
return RIG_OK;
}
static int satel_cmd(ROT *rot, char *cmd, int cmdlen, char *res, int reslen)
{
int ret;
struct rot_state *rs;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
rs = &rot->state;
rig_flush(&rs->rotport);
ret = write_block(&rs->rotport, cmd, cmdlen);
if (ret != RIG_OK)
return ret;
if (reslen > 0 && res != NULL)
{
ret = read_string(&rs->rotport, res, reslen, "\n", 1);
if (ret < 0)
return ret;
}
return RIG_OK;
}
static int satel_rot_open(ROT *rot)
{
char resbuf[BUF_SIZE];
int ret;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
// are we connected?
ret = satel_cmd(rot, "?", 1, resbuf, BUF_SIZE);
if (ret != RIG_OK)
return ret;
ret = strncasecmp("SatEL", resbuf, 5);
if (ret != 0)
return -RIG_EIO;
// yep, reset system
ret = satel_cmd(rot, "*", 1, NULL, 0);
if (ret != RIG_OK)
return ret;
// enable motion
ret = satel_cmd(rot, "g", 1, NULL, 0);
if (ret != RIG_OK)
return ret;
return RIG_OK;
}
static int satel_rot_set_position(ROT *rot, azimuth_t az, elevation_t el)
{
char cmdbuf[BUF_SIZE];
int ret;
satel_stat_t stat;
rig_debug(RIG_DEBUG_VERBOSE, "%s called: %.2f %.2f\n", __func__,
az, el);
snprintf(cmdbuf, BUF_SIZE, "p%d %d\r\n", (int)az, (int)el);
ret = satel_cmd(rot, cmdbuf, strlen(cmdbuf), NULL, 0);
if (ret != RIG_OK)
return ret;
// wait-for, read and discard the status message
ret = satel_read_status(rot, &stat);
if (ret < 0)
return ret;
return RIG_OK;
}
static int satel_rot_get_position(ROT *rot, azimuth_t *az, elevation_t *el)
{
int ret;
satel_stat_t stat;
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
ret = satel_cmd(rot, "z", 1, NULL, 0);
if (ret != RIG_OK)
return ret;
ret = satel_read_status(rot, &stat);
if (ret < 0)
return ret;
*az = stat.az;
*el = stat.el;
return RIG_OK;
}
static int satel_rot_stop(ROT *rot)
{
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
// send reset command
return satel_cmd(rot, "*", 1, NULL, 0);
}
static const char *satel_rot_get_info(ROT *rot)
{
rig_debug(RIG_DEBUG_VERBOSE, "%s called\n", __func__);
return "SatEL rotator";
}
/*
* Satel rotator capabilities.
*/
const struct rot_caps satel_rot_caps =
{
ROT_MODEL(ROT_MODEL_SATEL),
.model_name = "SatEL",
.mfg_name = "SatEL",
.version = "20210123.0",
.copyright = "LGPL",
.status = RIG_STATUS_ALPHA,
.rot_type = ROT_TYPE_AZEL,
.port_type = RIG_PORT_SERIAL,
.serial_rate_max = 9600,
.serial_rate_min = 9600,
.serial_data_bits = 8,
.serial_stop_bits = 1,
.serial_parity = RIG_PARITY_NONE,
.serial_handshake = RIG_HANDSHAKE_NONE,
.write_delay = 0,
.post_write_delay = 0,
.timeout = 60000,
.retry = 0,
.min_az = 0.,
.max_az = 360.,
.min_el = 0.,
.max_el = 90.,
.rot_open = satel_rot_open,
.get_position = satel_rot_get_position,
.set_position = satel_rot_set_position,
.stop = satel_rot_stop,
.get_info = satel_rot_get_info,
.priv = NULL, /* priv */
};
DECLARE_INITROT_BACKEND(satel)
{
rig_debug(RIG_DEBUG_VERBOSE, "%s: _init called\n", __func__);
rot_register(&satel_rot_caps);
return RIG_OK;
}

Wyświetl plik

@ -0,0 +1,28 @@
/*
* Hamlib SatEL backend - main header
* Copyright (c) 2021 Joshua Lynch
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef _ROT_SATEL_H
#define _ROT_SATEL_H 1
extern const struct rot_caps satel_rot_caps;
#endif /* _ROT_SATEL_H */

Wyświetl plik

@ -84,6 +84,7 @@ DEFINE_INITROT_BACKEND(cnctrk);
DEFINE_INITROT_BACKEND(prosistel);
DEFINE_INITROT_BACKEND(meade);
DEFINE_INITROT_BACKEND(ioptron);
DEFINE_INITROT_BACKEND(satel);
#if HAVE_LIBINDI
DEFINE_INITROT_BACKEND(indi);
#endif
@ -126,6 +127,7 @@ static struct
{ ROT_PROSISTEL, ROT_BACKEND_PROSISTEL, ROT_FUNCNAMA(prosistel) },
{ ROT_MEADE, ROT_BACKEND_MEADE, ROT_FUNCNAMA(meade) },
{ ROT_IOPTRON, ROT_BACKEND_IOPTRON, ROT_FUNCNAMA(ioptron) },
{ ROT_SATEL, ROT_BACKEND_SATEL, ROT_FUNCNAMA(satel) },
#if HAVE_LIBINDI
{ ROT_INDI, ROT_BACKEND_INDI, ROT_FUNCNAMA(indi) },
#endif