mirror of
https://github.com/Hamlib/Hamlib.git
synced 2024-09-25 04:17:28 +00:00
Initial release
git-svn-id: https://hamlib.svn.sourceforge.net/svnroot/hamlib/trunk@812 7ae35d74-ebe9-4afe-98af-79ac388436b8
This commit is contained in:
parent
532602372b
commit
e66509d2c5
268
src/locator.c
Normal file
268
src/locator.c
Normal file
@ -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
Normal file
273
src/rot_conf.c
Normal file
@ -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
Normal file
48
src/rot_conf.h
Normal file
@ -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
Normal file
343
src/rot_reg.c
Normal file
@ -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
Normal file
533
src/rotator.c
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user