Initial release

git-svn-id: https://hamlib.svn.sourceforge.net/svnroot/hamlib/trunk@812 7ae35d74-ebe9-4afe-98af-79ac388436b8
Hamlib-1.1.3
Stéphane Fillod, F8CFE 2001-12-27 21:46:25 +00:00
rodzic 532602372b
commit e66509d2c5
5 zmienionych plików z 1465 dodań i 0 usunięć

268
src/locator.c 100644
Wyświetl plik

@ -0,0 +1,268 @@
/**
* \file src/locator.c
* \brief Ham Radio Control Libraries interface
* \author Stephane Fillod
* \date 2000-2001
*
* Hamlib interface is a frontend implementing wrapper functions.
*/
/*
* Hamlib Interface - locator and bearing conversion calls
* Copyright (c) 2001 by Stephane Fillod
*
* $Id: locator.c,v 1.1 2001-12-27 21:46:25 fillods Exp $
*
* Code to determine bearing and range was taken from the Great Circle,
* by S. R. Sampson, N5OWK.
* Ref: "Air Navigation", Air Force Manual 51-40, 1 February 1987
* Ref: "ARRL Satellite Experimenters Handbook", August 1990
*
* Code to calculate distance and azimuth between two Maidenhead locators,
* taken from wwl, by IK0ZSN Mirko Caserta.
*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <hamlib/rotator.h>
#define RADIAN (180.0 / M_PI)
/* arc length for 1 degree, 60 Nautical Miles */
#define ARC_IN_KM 111.2
/*
* degrees >360, minutes > 60, and seconds > 60 are allowed
*/
double dms2dec(int degrees, int minutes, int seconds)
{
return (double)degrees + minutes/60.0 + seconds/3600.0;
}
/*
* guarantee: dec2dms will make sure 0<=degress<360,
* 0<=minutes<60, 0<=seconds<0
*/
void dec2dms(double dec, int *degrees, int *minutes, int *seconds)
{
if (!degrees || !minutes || !seconds)
return;
dec = fmod(dec, 360);
*degrees = (int)floor(dec);
dec -= *degrees;
dec *= 60;
*minutes = (int)floor(dec);
dec -= *minutes;
dec *= 60;
*seconds = (int)floor(dec);
}
/*
* 4 characters and 6 characters are accepted
*/
int locator2longlat(double *longitude, double *latitude, const char *locator)
{
char loc[6];
if (locator[4] != '\0' && locator[6] != '\0')
return -1;
loc[0] = toupper(locator[0]);
loc[1] = toupper(locator[1]);
loc[2] = locator[2];
loc[3] = locator[3];
if (locator[4] != '\0') {
loc[4] = toupper(locator[4]);
loc[5] = toupper(locator[5]);
} else {
loc[4] = 'A';
loc[5] = 'A';
}
if (loc[0] < 'A' || loc[0] > 'Z' ||
loc[1] < 'A' || loc[1] > 'Z' ||
loc[2] < '0' || loc[2] > '9' ||
loc[3] < '0' || loc[3] > '9' ||
loc[4] < 'A' || loc[4] > 'Z' ||
loc[5] < 'A' || loc[5] > 'Z' ) {
return -1;
}
*longitude = 20.0 * (loc[0]-'A') - 180.0 + 2.0 * (loc[2]-'0') +
(loc[4]-'A')/12.0 + 1.0;
*latitude = 10.0 * (loc[1]-'A') - 90.0 + (loc[3]-'0') +
(loc[5]-'A')/24.0 + 1.0/48.0;
return 0;
}
/*
* locator must be at least 6 chars long
*/
int longlat2locator(double longitude, double latitude, char *locator)
{
#if 0
double t,s;
t = 20.0 * (loc[0]-'A') - 180.0 + 2.0 * (loc[2]-'0') +
(loc[4]-'A')/12.0 + 1.0;
*longitude = t;
s = 10.0 * (loc[1]-'A') - 90.0 + (loc[3]-'0') +
(loc[5]-'A')/24.0 + 1.0/48.0;
*latitude = s;
#endif
strcpy (locator, "MM00mm");
return 0;
}
/*
* 1 towards 2
* returns qrb in km
* and azimuth in decimal degrees
*/
/*
* This version also takes into consideration the two points
* being close enough to be in the near-field, and the antipodal points,
* which are easily calculated. These last points were made
* in discussions with John Allison who makes the nice MAPIT program.
*/
int qrb(double lon1, double lat1, double lon2, double lat2,
double *bearing, double *azimuth)
{
double delta_long, tmp, arc, cosaz, az;
if (!bearing || !azimuth)
return -1;
if ((lat1 > 90.0 || lat1 < -90.0) || (lat2 > 90.0 || lat2 < -90.0))
return -1;
if ((lon1 > 180.0 || lon1 < -180.0) || (lon2 > 180.0 || lon2 < -180.0))
return -1;
/* Prevent ACOS() Domain Error */
if (lat1 == 90.0)
lat1 = 89.99;
else if (lat1 == -90.0)
lat1 = -89.99;
if (lat2 == 90.0)
lat2 = 89.99;
else if (lat2 == -90.0)
lat2 = -89.99;
/*
* Convert variables to Radians
*/
lat1 /= RADIAN;
lon1 /= RADIAN;
lat2 /= RADIAN;
lon2 /= RADIAN;
delta_long = lon2 - lon1;
tmp = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(delta_long);
if (tmp > .999999) {
/* Station points coincide, use an Omni! */
*bearing = 0.0;
*azimuth = 0.0;
return 0;
}
if (tmp < -.999999) {
/*
* points are antipodal, it's straight down.
* Station is equal distance in all Azimuths.
* So take 180 Degrees of arc times 60 nm,
* and you get 10800 nm, or whatever units...
*/
*bearing = 180.0*ARC_IN_KM;
*azimuth = 0.0;
return 0;
}
arc = acos(tmp);
/*
* One degree of arc is 60 Nautical miles
* at the surface of the earth, 111.2 km, or 69.1 sm
* This method is easier than the one in the handbook
*/
/* Short Path */
*bearing = ARC_IN_KM * RADIAN * arc;
/*
* Long Path
*
* distlp = (ARC_IN_KM * 360.0) - distsp;
*/
cosaz = (sin(lat2) - (sin(lat1) * cos(arc))) /
(sin(arc) * cos(lat1));
if (cosaz > .999999)
az = 0.0;
else if (cosaz < -.999999)
az = 180.0;
else
az = acos(cosaz) * RADIAN;
/*
* Handbook had the test ">= 0.0" which looks backwards??
*/
if (sin(delta_long) < 0.0) {
*azimuth = az;
} else {
*azimuth = 360.0 - az;
}
return 0;
}
double bearing_long_path(double bearing)
{
return (ARC_IN_KM * 360.0) - bearing;
}
double azimuth_long_path(double azimuth)
{
return 360.0-azimuth;
}

273
src/rot_conf.c 100644
Wyświetl plik

@ -0,0 +1,273 @@
/*
* Hamlib Interface - configuration interface
* Copyright (c) 2000,2001 by Stephane Fillod and Frank Singleton
*
* $Id: rot_conf.c,v 1.1 2001-12-27 21:46:25 fillods Exp $
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <hamlib/rotator.h>
#include "rot_conf.h"
/*
* Place holder for now. Here will be defined all the configuration
* options available in the rot->state struct.
*/
static const struct confparams rotfrontend_cfg_params[] = {
{ TOK_ROT_PATHNAME, "rot_pathname", "Rig path name",
"Path name to the device file of the rotator",
"/dev/rotator", RIG_CONF_STRING,
},
{ TOK_WRITE_DELAY, "write_delay", "Write delay",
"Delay in ms between each byte sent out",
"0", RIG_CONF_NUMERIC, { n: { 0, 1000, 1 } }
},
{ TOK_POST_WRITE_DELAY, "post_write_delay", "Post write delay",
"Delay in ms between each command sent out",
"0", RIG_CONF_NUMERIC, { n: { 0, 1000, 1 } }
},
{ TOK_TIMEOUT, "timeout", "Timeout", "Timeout in ms",
"0", RIG_CONF_NUMERIC, { n: { 0, 10000, 1 } }
},
{ TOK_RETRY, "retry", "Retry", "Max number of retry",
"0", RIG_CONF_NUMERIC, { n: { 0, 10, 1 } }
},
{ TOK_SERIAL_SPEED, "serial_speed", "Serial speed",
"Serial port baud rate",
"0", RIG_CONF_NUMERIC, { n: { 300, 115200, 1 } }
},
{ TOK_DATA_BITS, "data_bits", "Serial data bits",
"Serial port data bits",
"8", RIG_CONF_NUMERIC, { n: { 5, 8, 1 } }
},
{ TOK_STOP_BITS, "stop_bits", "Serial stop bits",
"Serial port stop bits",
"1", RIG_CONF_NUMERIC, { n: { 0, 3, 1 } }
},
{ TOK_PARITY, "serial_parity", "Serial parity",
"Serial port parity",
"None", RIG_CONF_COMBO, { c: {{ "None", "Odd", "Even", NULL }} }
},
{ TOK_HANDSHAKE, "serial_handshake", "Serial handshake",
"Serial port handshake",
"None", RIG_CONF_COMBO, { c: {{ "None", "XONXOFF", "Hardware", NULL }} }
},
{ RIG_CONF_END, NULL, }
};
/*
* frontrot_set_conf
* assumes rot!=NULL, val!=NULL
* TODO: check format of val before doing atoi().
*/
int frontrot_set_conf(ROT *rot, token_t token, const char *val)
{
const struct rot_caps *caps;
struct rot_state *rs;
caps = rot->caps;
rs = &rot->state;
switch(token) {
case TOK_ROT_PATHNAME:
strcpy(rs->rotport.pathname, val);
break;
case TOK_WRITE_DELAY:
rs->rotport.write_delay = atoi(val);
break;
case TOK_POST_WRITE_DELAY:
rs->rotport.post_write_delay = atoi(val);
break;
case TOK_TIMEOUT:
rs->rotport.timeout = atoi(val);
break;
case TOK_RETRY:
rs->rotport.retry = atoi(val);
break;
case TOK_SERIAL_SPEED:
rs->rotport.parm.serial.rate = atoi(val);
break;
case TOK_DATA_BITS:
rs->rotport.parm.serial.data_bits = atoi(val);
break;
case TOK_STOP_BITS:
rs->rotport.parm.serial.stop_bits = atoi(val);
break;
case TOK_PARITY:
if (!strncmp(val, "None", 8))
rs->rotport.parm.serial.parity = RIG_PARITY_NONE;
else if (!strncmp(val, "Odd", 8))
rs->rotport.parm.serial.parity = RIG_PARITY_ODD;
else if (!strncmp(val, "Even", 8))
rs->rotport.parm.serial.parity = RIG_PARITY_EVEN;
else
return -RIG_EINVAL;
break;
case TOK_HANDSHAKE:
if (!strncmp(val, "None", 8))
rs->rotport.parm.serial.handshake = RIG_HANDSHAKE_NONE;
else if (!strncmp(val, "XONXOFF", 8))
rs->rotport.parm.serial.handshake = RIG_HANDSHAKE_XONXOFF;
else if (!strncmp(val, "Hardware", 8))
rs->rotport.parm.serial.handshake = RIG_HANDSHAKE_HARDWARE;
else
return -RIG_EINVAL;
break;
default:
return -RIG_EINVAL;
}
return RIG_OK;
}
/*
* frontrot_get_conf
* assumes rot!=NULL, val!=NULL
*/
int frontrot_get_conf(ROT *rot, token_t token, char *val)
{
const struct rot_caps *caps;
struct rot_state *rs;
const char *s;
caps = rot->caps;
rs = &rot->state;
switch(token) {
case TOK_ROT_PATHNAME:
strcpy(val, rs->rotport.pathname);
break;
case TOK_WRITE_DELAY:
sprintf(val, "%d", rs->rotport.write_delay);
break;
case TOK_POST_WRITE_DELAY:
sprintf(val, "%d", rs->rotport.post_write_delay);
break;
case TOK_TIMEOUT:
sprintf(val, "%d", rs->rotport.timeout);
break;
case TOK_RETRY:
sprintf(val, "%d", rs->rotport.retry);
break;
case TOK_SERIAL_SPEED:
sprintf(val, "%d", rs->rotport.parm.serial.rate);
break;
case TOK_DATA_BITS:
sprintf(val, "%d", rs->rotport.parm.serial.data_bits);
break;
case TOK_STOP_BITS:
sprintf(val, "%d", rs->rotport.parm.serial.stop_bits);
break;
case TOK_PARITY:
switch (rs->rotport.parm.serial.parity) {
case RIG_PARITY_NONE: s = "None"; break;
case RIG_PARITY_ODD: s = "Odd"; break;
case RIG_PARITY_EVEN: s = "Even"; break;
default: return -RIG_EINVAL;
}
strcpy(val, s);
break;
case TOK_HANDSHAKE:
switch (rs->rotport.parm.serial.handshake) {
case RIG_HANDSHAKE_NONE: s = "None"; break;
case RIG_HANDSHAKE_XONXOFF: s = "XONXOFF"; break;
case RIG_HANDSHAKE_HARDWARE: s = "Hardware"; break;
default: return -RIG_EINVAL;
}
strcpy(val, s);
break;
default:
return -RIG_EINVAL;
}
return RIG_OK;
}
/*
* rot_token_foreach
* executes cfunc on all the elements stored in the conf table
* start first with backend conf table, then finish with frontend table
*/
int rot_token_foreach(ROT *rot, int (*cfunc)(const struct confparams *, rig_ptr_t), rig_ptr_t data)
{
const struct confparams *cfp;
if (!rot || !rot->caps || !cfunc)
return -RIG_EINVAL;
for (cfp = rot->caps->cfgparams; cfp && cfp->name; cfp++)
if ((*cfunc)(cfp, data) == 0)
return RIG_OK;
for (cfp = rotfrontend_cfg_params; cfp->name; cfp++)
if ((*cfunc)(cfp, data) == 0)
return RIG_OK;
return RIG_OK;
}
/*
* lookup conf token by its name, return pointer to confparams struct.
*
* lookup backend config table first, then fall back to frontend.
* TODO: should use Lex to speed it up, strcmp hurts!
*/
const struct confparams *rot_confparam_lookup(ROT *rot, const char *name)
{
const struct confparams *cfp;
if (!rot || !rot->caps)
return NULL;
for (cfp = rot->caps->cfgparams; cfp && cfp->name; cfp++)
if (!strcmp(cfp->name, name))
return cfp;
for (cfp = rotfrontend_cfg_params; cfp->name; cfp++)
if (!strcmp(cfp->name, name))
return cfp;
return NULL;
}
/*
* Simple lookup returning token id assicated with name
*/
token_t rot_token_lookup(ROT *rot, const char *name)
{
const struct confparams *cfp;
cfp = rot_confparam_lookup(rot, name);
if (!cfp)
return RIG_CONF_END;
return cfp->token;
}

48
src/rot_conf.h 100644
Wyświetl plik

@ -0,0 +1,48 @@
/*
* Hamlib Interface - configuration header
* Copyright (c) 2000,2001 by Stephane Fillod and Frank Singleton
*
* $Id: rot_conf.h,v 1.1 2001-12-27 21:46:25 fillods Exp $
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef _ROT_CONF_H
#define _ROT_CONF_H 1
#include <hamlib/rotator.h>
int frontrot_set_conf(ROT *rot, token_t token, const char *val);
int frontrot_get_conf(ROT *rot, token_t token, char *val);
#define ROT_TOKEN_FRONTEND RIG_TOKEN_FRONTEND
#define TOK_ROT_PATHNAME ROT_TOKEN_FRONTEND(10)
#define TOK_WRITE_DELAY ROT_TOKEN_FRONTEND(12)
#define TOK_POST_WRITE_DELAY ROT_TOKEN_FRONTEND(13)
#define TOK_TIMEOUT ROT_TOKEN_FRONTEND(14)
#define TOK_RETRY ROT_TOKEN_FRONTEND(15)
#define TOK_SERIAL_SPEED ROT_TOKEN_FRONTEND(30)
#define TOK_DATA_BITS ROT_TOKEN_FRONTEND(31)
#define TOK_STOP_BITS ROT_TOKEN_FRONTEND(32)
#define TOK_PARITY ROT_TOKEN_FRONTEND(33)
#define TOK_HANDSHAKE ROT_TOKEN_FRONTEND(34)
#endif /* _ROT_CONF_H */

343
src/rot_reg.c 100644
Wyświetl plik

@ -0,0 +1,343 @@
/*
* Hamlib Interface - provides registering for dynamically loadable backends.
* Copyright (c) 2000,2001 by Stephane Fillod and Frank Singleton
*
* $Id: rot_reg.c,v 1.1 2001-12-27 21:46:25 fillods Exp $
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
/* This is libtool's dl wrapper */
#include <ltdl.h>
#include <hamlib/rotator.h>
#ifndef PATH_MAX
# define PATH_MAX 1024
#endif
#define ROT_BACKEND_MAX 32
/*
* ROT_BACKEND_LIST is defined in rotlist.h, please keep it up to data,
* ie. each time you give birth to a new backend
* Also, it should be possible to register "external" backend,
* that is backend that were not known by Hamlib at compile time.
* Maybe, rotlist.h should reserve some numbers for them? --SF
*/
static struct {
int be_num;
const char *be_name;
rot_model_t (*be_probe)(port_t *);
} rot_backend_list[ROT_BACKEND_MAX] = ROT_BACKEND_LIST;
/*
* This struct to keep track of known rot models.
* It is chained, and used in a hash table, see below.
*/
struct rot_list {
const struct rot_caps *caps;
lt_dlhandle handle; /* handle returned by lt_dlopen() */
struct rot_list *next;
};
#define ROTLSTHASHSZ 16
#define HASH_FUNC(a) ((a)%ROTLSTHASHSZ)
/*
* The rot_hash_table is a hash table pointing to a list of next==NULL
* terminated caps.
*/
static struct rot_list *rot_hash_table[ROTLSTHASHSZ] = { NULL, };
static int rot_lookup_backend(rot_model_t rot_model);
/*
* Basically, this is a hash insert function that doesn't check for dup!
*/
int rot_register(const struct rot_caps *caps)
{
int hval;
struct rot_list *p;
if (!caps)
return -RIG_EINVAL;
rot_debug(RIG_DEBUG_VERBOSE, "rot_register (%d)\n",caps->rot_model);
#ifndef DONT_WANT_DUP_CHECK
if (rot_get_caps(caps->rot_model)!=NULL)
return -RIG_EINVAL;
#endif
p = (struct rot_list*)malloc(sizeof(struct rot_list));
if (!p)
return -RIG_ENOMEM;
hval = HASH_FUNC(caps->rot_model);
p->caps = caps;
p->handle = NULL;
p->next = rot_hash_table[hval];
rot_hash_table[hval] = p;
return RIG_OK;
}
/*
* Get rot capabilities.
* ie. rot_hash_table lookup
*/
const struct rot_caps *rot_get_caps(rot_model_t rot_model)
{
struct rot_list *p;
for (p = rot_hash_table[HASH_FUNC(rot_model)]; p; p=p->next) {
if (p->caps->rot_model == rot_model)
return p->caps;
}
return NULL; /* sorry, caps not registered! */
}
/*
* lookup for backend index in rot_backend_list table,
* according to BACKEND_NUM
* return -1 if not found.
*/
static int rot_lookup_backend(rot_model_t rot_model)
{
int i;
for (i=0; i<ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++) {
if (ROT_BACKEND_NUM(rot_model) ==
rot_backend_list[i].be_num)
return i;
}
return -1;
}
/*
* rot_check_backend
* check the backend declaring this model has been loaded
* and if not loaded already, load it!
* This permits seamless operation in rot_init.
*/
int rot_check_backend(rot_model_t rot_model)
{
const struct rot_caps *caps;
int be_idx;
int retval;
/* already loaded ? */
caps = rot_get_caps(rot_model);
if (caps)
return RIG_OK;
be_idx = rot_lookup_backend(rot_model);
/*
* Never heard about this backend family!
*/
if (be_idx == -1) {
rot_debug(RIG_DEBUG_VERBOSE, "rot_check_backend: unsupported "
"backend %d for model %d\n",
ROT_BACKEND_NUM(rot_model), rot_model
);
return -RIG_ENAVAIL;
}
retval = rot_load_backend(rot_backend_list[be_idx].be_name);
return retval;
}
int rot_unregister(rot_model_t rot_model)
{
int hval;
struct rot_list *p,*q;
hval = HASH_FUNC(rot_model);
q = NULL;
for (p = rot_hash_table[hval]; p; p=p->next) {
if (p->caps->rot_model == rot_model) {
if (q == NULL)
rot_hash_table[hval] = p->next;
else
q->next = p->next;
free(p);
return RIG_OK;
}
q = p;
}
return -RIG_EINVAL; /* sorry, caps not registered! */
}
/*
* rot_list_foreach
* executes cfunc on all the elements stored in the rot hash list
*/
int rot_list_foreach(int (*cfunc)(const struct rot_caps*, rig_ptr_t),rig_ptr_t data)
{
struct rot_list *p;
int i;
if (!cfunc)
return -RIG_EINVAL;
for (i=0; i<ROTLSTHASHSZ; i++) {
for (p=rot_hash_table[i]; p; p=p->next)
if ((*cfunc)(p->caps,data) == 0)
return RIG_OK;
}
return RIG_OK;
}
/*
* rot_probe_all
* called straight by rot_probe
*/
rot_model_t rot_probe_all(port_t *p)
{
int i;
rot_model_t rot_model;
for (i=0; i<ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++) {
if (rot_backend_list[i].be_probe) {
rot_model = (*rot_backend_list[i].be_probe)(p);
if (rot_model != ROT_MODEL_NONE)
return rot_model;
}
}
return ROT_MODEL_NONE;
}
int rot_load_all_backends()
{
int i;
for (i=0; i<ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++) {
rot_load_backend(rot_backend_list[i].be_name);
}
return RIG_OK;
}
#define MAXFUNCNAMELEN 64
/*
* rot_load_backend
* Dynamically load a rot backend through dlopen mechanism
*/
int rot_load_backend(const char *be_name)
{
/*
* determine PREFIX and POSTFIX values from configure script
*/
#ifdef __CYGWIN__
# define PREFIX "cyghamlib-"
# define POSTFIX ".dll"
#else
# define PREFIX "libhamlib-"
# define POSTFIX ".la"
#endif
lt_dlhandle be_handle;
int (*be_init)(rig_ptr_t);
int status;
char libname[PATH_MAX];
char initfname[MAXFUNCNAMELEN] = "init_";
char probefname[MAXFUNCNAMELEN] = "probe_";
int i;
/*
* lt_dlinit may be called several times
*/
LTDL_SET_PRELOADED_SYMBOLS();
status = lt_dlinit();
if (status) {
rot_debug(RIG_DEBUG_ERR, "rot_backend_load: lt_dlinit for %s "
"failed: %s\n", be_name, lt_dlerror());
return -RIG_EINTERNAL;
}
rot_debug(RIG_DEBUG_VERBOSE, "rot: loading backend %s\n",be_name);
/*
* add hamlib directory here
*/
snprintf (libname, sizeof (libname), PREFIX"%s", be_name);
be_handle = lt_dlopenext (libname);
/*
* external module not found? try dlopenself for backends
* compiled in static
*/
if (!be_handle)
be_handle = lt_dlopen (NULL);
if (!be_handle) {
rot_debug(RIG_DEBUG_ERR, "rot: lt_dlopen(\"%s\") failed (%s)\n",
libname, lt_dlerror());
return -RIG_EINVAL;
}
strncat(initfname, be_name, MAXFUNCNAMELEN);
be_init = (int (*)(rig_ptr_t)) lt_dlsym (be_handle, initfname);
if (!be_init) {
rot_debug(RIG_DEBUG_ERR, "rot: dlsym(%s) failed (%s)\n",
initfname, lt_dlerror());
lt_dlclose(be_handle);
return -RIG_EINVAL;
}
/*
* register probe function if present
* NOTE: rot_load_backend might have been called upon a backend
* not in rotlist.h! In this case, do nothing.
*/
for (i=0; i<ROT_BACKEND_MAX && rot_backend_list[i].be_name; i++) {
if (!strncmp(be_name, rot_backend_list[i].be_name, 64)) {
strncat(probefname, be_name, MAXFUNCNAMELEN);
rot_backend_list[i].be_probe = (rot_model_t (*)(port_t *))
lt_dlsym (be_handle, probefname);
break;
}
}
status = (*be_init)(be_handle);
return status;
}

533
src/rotator.c 100644
Wyświetl plik

@ -0,0 +1,533 @@
/**
* \file src/rotator.c
* \brief Ham Radio Control Libraries interface
* \author Stephane Fillod
* \date 2000-2001
*
* Hamlib interface is a frontend implementing rotator wrapper functions.
*/
/*
* Hamlib Interface - main file
* Copyright (c) 2000,2001 by Stephane Fillod and Frank Singleton
*
* $Id: rotator.c,v 1.1 2001-12-27 21:46:25 fillods Exp $
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <hamlib/rotator.h>
#include <serial.h>
#include "rot_conf.h"
#define DEFAULT_SERIAL_PORT "/dev/rotator"
/*
* Data structure to track the opened rot (by rot_open)
*/
struct opened_rot_l {
ROT *rot;
struct opened_rot_l *next;
};
static struct opened_rot_l *opened_rot_list = { NULL };
/*
* track which rot is opened (with rot_open)
* needed at least for transceive mode
*/
static int add_opened_rot(ROT *rot)
{
struct opened_rot_l *p;
p = (struct opened_rot_l *)malloc(sizeof(struct opened_rot_l));
if (!p)
return -RIG_ENOMEM;
p->rot = rot;
p->next = opened_rot_list;
opened_rot_list = p;
return RIG_OK;
}
static int remove_opened_rot(ROT *rot)
{
struct opened_rot_l *p,*q;
q = NULL;
for (p=opened_rot_list; p; p=p->next) {
if (p->rot == rot) {
if (q == NULL) {
opened_rot_list = opened_rot_list->next;
} else {
q->next = p->next;
}
free(p);
return RIG_OK;
}
q = p;
}
return -RIG_EINVAL; /* Not found in list ! */
}
/**
* \brief execs cfunc() on each opened rot
* \param cfunc The function to be executed on each rot
* \param data Data pointer to be passed to cfunc()
*
* Calls cfunc() function for each opened rot.
* The contents of the opened rot table
* is processed in random order according to a function
* pointed to by \a cfunc, whic is called with two arguments,
* the first pointing to the #ROT handle, the second
* to a data pointer \a data.
* If \a data is not needed, then it can be set to NULL.
* The processing of the opened rot table is stopped
* when cfunc() returns 0.
* \internal
*
* \return always RIG_OK.
*/
int foreach_opened_rot(int (*cfunc)(ROT *, rig_ptr_t), rig_ptr_t data)
{
struct opened_rot_l *p;
for (p=opened_rot_list; p; p=p->next) {
if ((*cfunc)(p->rot,data) == 0)
return RIG_OK;
}
return RIG_OK;
}
/**
* \brief allocate a new #ROT handle
* \param rot_model The rot model for this new handle
*
* Allocates a new #ROT handle and initializes the associated data
* for \a rot_model.
*
* \return a pointer to the #ROT handle otherwise NULL if memory allocation
* failed or \a rot_model is unknown (e.g. backend autoload failed).
*
* \sa rot_cleanup(), rot_open()
*/
ROT *rot_init(rot_model_t rot_model)
{
ROT *rot;
const struct rot_caps *caps;
struct rot_state *rs;
int retcode;
rot_debug(RIG_DEBUG_VERBOSE,"rot:rot_init called \n");
rot_check_backend(rot_model);
caps = rot_get_caps(rot_model);
if (!caps)
return NULL;
/*
* okay, we've found it. Allocate some memory and set it to zeros,
* and especially the initialize the callbacks
*/
rot = calloc(1, sizeof(ROT));
if (rot == NULL) {
/*
* FIXME: how can the caller know it's a memory shortage,
* and not "rot not found" ?
*/
return NULL;
}
rot->caps = caps;
/*
* populate the rot->state
* TODO: read the Preferences here!
*/
rs = &rot->state;
rs->comm_state = 0;
rs->rotport.type.rig = caps->port_type; /* default from caps */
strncpy(rs->rotport.pathname, DEFAULT_SERIAL_PORT, FILPATHLEN);
rs->rotport.parm.serial.rate = caps->serial_rate_max; /* fastest ! */
rs->rotport.parm.serial.data_bits = caps->serial_data_bits;
rs->rotport.parm.serial.stop_bits = caps->serial_stop_bits;
rs->rotport.parm.serial.parity = caps->serial_parity;
rs->rotport.parm.serial.handshake = caps->serial_handshake;
rs->rotport.write_delay = caps->write_delay;
rs->rotport.post_write_delay = caps->post_write_delay;
rs->rotport.timeout = caps->timeout;
rs->rotport.retry = caps->retry;
rs->min_el = caps->min_el;
rs->min_el = caps->min_el;
rs->min_az = caps->min_az;
rs->min_az = caps->min_az;
rs->rotport.fd = -1;
/*
* let the backend a chance to setup his private data
* This must be done only once defaults are setup,
* so the backend init can override rot_state.
*/
if (caps->rot_init != NULL) {
retcode = caps->rot_init(rot);
if (retcode != RIG_OK) {
rot_debug(RIG_DEBUG_VERBOSE,"rot:backend_init failed!\n");
/* cleanup and exit */
free(rot);
return NULL;
}
}
return rot;
}
/**
* \brief open the communication to the rot
* \param rot The #ROT handle of the radio to be opened
*
* Opens communication to a radio which \a ROT handle has been passed
* by argument.
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \retval RIG_EINVAL \a rot is NULL or unconsistent.
* \retval RIG_ENIMPL port type communication is not implemented yet.
*
* \sa rot_init(), rot_close()
*/
int rot_open(ROT *rot)
{
const struct rot_caps *caps;
struct rot_state *rs;
int status;
azimuth_t az;
elevation_t el;
rot_debug(RIG_DEBUG_VERBOSE,"rot:rot_open called \n");
if (!rot || !rot->caps)
return -RIG_EINVAL;
caps = rot->caps;
rs = &rot->state;
if (rs->comm_state)
return -RIG_EINVAL;
rs->rotport.fd = -1;
switch(rs->rotport.type.rig) {
case RIG_PORT_SERIAL:
status = serial_open(&rs->rotport);
if (status != 0)
return status;
break;
case RIG_PORT_DEVICE:
status = open(rs->rotport.pathname, O_RDWR, 0);
if (status < 0)
return -RIG_EIO;
rs->rotport.fd = status;
break;
case RIG_PORT_NONE:
case RIG_PORT_RPC:
break; /* ez :) */
case RIG_PORT_NETWORK: /* not implemented yet! */
return -RIG_ENIMPL;
default:
return -RIG_EINVAL;
}
add_opened_rot(rot);
rs->comm_state = 1;
/*
* Maybe the backend has something to initialize
* In case of failure, just close down and report error code.
*/
if (caps->rot_open != NULL) {
status = caps->rot_open(rot);
if (status != RIG_OK) {
rot_close(rot);
return status;
}
}
/*
* trigger state->current_az/current_el first retrieval
*/
rot_get_position(rot, &az, &el);
return RIG_OK;
}
/**
* \brief close the communication to the rot
* \param rot The #ROT handle of the radio to be closed
*
* Closes communication to a radio which \a ROT handle has been passed
* by argument that was previously open with rot_open().
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa rot_cleanup(), rot_open()
*/
int rot_close(ROT *rot)
{
const struct rot_caps *caps;
struct rot_state *rs;
rot_debug(RIG_DEBUG_VERBOSE,"rot:rot_close called \n");
if (!rot || !rot->caps)
return -RIG_EINVAL;
caps = rot->caps;
rs = &rot->state;
if (!rs->comm_state)
return -RIG_EINVAL;
/*
* Let the backend say 73s to the rot.
* and ignore the return code.
*/
if (caps->rot_close)
caps->rot_close(rot);
if (rs->rotport.fd != -1) {
if (!rs->rotport.stream)
fclose(rs->rotport.stream); /* this closes also fd */
else
close(rs->rotport.fd);
rs->rotport.fd = -1;
rs->rotport.stream = NULL;
}
remove_opened_rot(rot);
rs->comm_state = 0;
return RIG_OK;
}
/**
* \brief release a rot handle and free associated memory
* \param rot The #ROT handle of the radio to be closed
*
* Releases a rot struct which port has eventualy been closed already
* with rot_close().
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa rot_init(), rot_close()
*/
int rot_cleanup(ROT *rot)
{
rot_debug(RIG_DEBUG_VERBOSE,"rot:rot_cleanup called \n");
if (!rot || !rot->caps)
return -RIG_EINVAL;
/*
* check if they forgot to close the rot
*/
if (rot->state.comm_state)
rot_close(rot);
/*
* basically free up the priv struct
*/
if (rot->caps->rot_cleanup)
rot->caps->rot_cleanup(rot);
free(rot);
return RIG_OK;
}
/**
* \brief set a rotator configuration parameter
* \param rot The rot handle
* \param token The parameter
* \param val The value to set the parameter to
*
* Sets a configuration parameter.
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa rot_get_conf()
*/
int rot_set_conf(ROT *rot, token_t token, const char *val)
{
if (!rot || !rot->caps)
return -RIG_EINVAL;
if (RIG_IS_TOKEN_FRONTEND(token))
return frontrot_set_conf(rot, token, val);
if (rot->caps->set_conf == NULL)
return -RIG_ENAVAIL;
return rot->caps->set_conf(rot, token, val);
}
/**
* \brief get the value of a configuration parameter
* \param rot The rot handle
* \param token The parameter
* \param val The location where to store the value of config \a token
*
* Retrieves the value of a configuration paramter associated with \a token.
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa rot_set_conf()
*/
int rot_get_conf(ROT *rot, token_t token, char *val)
{
if (!rot || !rot->caps || !val)
return -RIG_EINVAL;
if (RIG_IS_TOKEN_FRONTEND(token))
return frontrot_get_conf(rot, token, val);
if (rot->caps->get_conf == NULL)
return -RIG_ENAVAIL;
return rot->caps->get_conf(rot, token, val);
}
/**
* \brief set the azimuth and elevation of the rotator
* \param rot The rot handle
* \param azimuth The azimuth to set to
* \param elevation The elevation to set to
*
* Sets the azimuth and elevation of the rotator.
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa rot_get_position()
*/
int rot_set_position (ROT *rot, azimuth_t azimuth, elevation_t elevation)
{
const struct rot_caps *caps;
if (!rot || !rot->caps)
return -RIG_EINVAL;
caps = rot->caps;
if (caps->set_position == NULL)
return -RIG_ENAVAIL;
return caps->set_position(rot, azimuth, elevation);
}
/**
* \brief get the azimuth and elevation of the rotator
* \param rot The rot handle
* \param azimuth The location where to store the current azimuth
* \param elevation The location where to store the current elevation
*
* Retrieves the current azimuth and elevation of the rotator.
*
* \return RIG_OK if the operation has been sucessful, otherwise
* a negative value if an error occured (in which case, cause is
* set appropriately).
*
* \sa rot_set_position()
*/
int rot_get_position (ROT *rot, azimuth_t *azimuth, elevation_t *elevation)
{
const struct rot_caps *caps;
if (!rot || !rot->caps || !azimuth || !elevation)
return -RIG_EINVAL;
caps = rot->caps;
if (caps->get_position == NULL)
return -RIG_ENAVAIL;
return caps->get_position(rot, azimuth, elevation);
}
/**
* \brief get general information from the rotator
* \param rot The rot handle
*
* Retrieves some general information from the rotator.
* This can include firmware revision, exact model name, or just nothing.
*
* \return a pointer to static memory containing the ASCIIZ string
* if the operation has been sucessful, otherwise NULL if an error occured
* or get_info not part of capabilities.
*/
const char* rot_get_info(ROT *rot)
{
if (!rot || !rot->caps)
return NULL;
if (rot->caps->get_info == NULL)
return NULL;
return rot->caps->get_info(rot);
}