XEphem/GUI/xephem/scope.c

888 lines
26 KiB
C

/* this file glues XEphem to INDI.
*/
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/RowColumn.h>
#include <Xm/Separator.h>
#include <Xm/Scale.h>
#include <Xm/SelectioB.h>
#include <Xm/ToggleB.h>
#include <Xm/PushB.h>
#include <Xm/TextF.h>
#include "xephem.h"
static void sc_create_w (void);
static void sc_help_cb (Widget w, XtPointer client, XtPointer call);
static void oneConfigRow (Widget rc_w, Widget *tb_wp, XtCallbackProc cb,
char *savereg, char *prompt, char *name, Widget *v_wp, Widget *m_wp,
Widget *b_wp);
static int getINDIprop (Widget tf_w, char **dev, char **prop, char **ele);
static int getINDIele (Widget w1, Widget w2, char **dev, char **prop,
char *ele[]);
static INumber *findNumber (INumberVectorProperty *nvp, char *name);
static double toINDIValue (double localv, Widget m_w, Widget b_w);
static double fromINDIValue (double indiv, Widget m_w, Widget b_w);
static void jd_cb (Widget w, XtPointer client, XtPointer call);
static void posixtm_cb (Widget w, XtPointer client, XtPointer call);
static void ll_cb (Widget w, XtPointer client, XtPointer call);
static void wx_cb (Widget w, XtPointer client, XtPointer call);
static void marker_cb (Widget w, XtPointer client, XtPointer call);
static void marker_tcb (XtPointer client, XtIntervalId *id);
static void close_cb (Widget w, XtPointer client, XtPointer call);
static Widget scopeshell_w; /* overall shell */
static Widget host_w; /* INDI tcp/ip host TF */
static Widget port_w; /* INDI tcp/ip port TF */
static Widget jdv_w; /* INDI JD value */
static Widget jdm_w; /* INDI JD slope */
static Widget jdb_w; /* INDI JD offset */
static Widget posixtmv_w; /* INDI POSIX time value */
static Widget latv_w; /* INDI latitude value */
static Widget latm_w; /* INDI latitude slope */
static Widget latb_w; /* INDI latitude offset */
static Widget lngv_w; /* INDI longitude value */
static Widget lngm_w; /* INDI longitude slope */
static Widget lngb_w; /* INDI longitude offset */
static Widget tempv_w; /* INDI temperature value */
static Widget tempm_w; /* INDI temperature slope */
static Widget tempb_w; /* INDI temperature offset */
static Widget presv_w; /* INDI pressure value */
static Widget presm_w; /* INDI pressure slope */
static Widget presb_w; /* INDI pressure offset */
static Widget rav_w; /* INDI ra value */
static Widget ram_w; /* INDI ra slope */
static Widget rab_w; /* INDI ra offset */
static Widget decv_w; /* INDI dec value */
static Widget decm_w; /* INDI dec slope */
static Widget decb_w; /* INDI dec offset */
static Widget edbv_w; /* INDI edb value */
static Widget gotorav_w; /* INDI goto ra value */
static Widget gotoram_w; /* INDI goto ra slope */
static Widget gotorab_w; /* INDI goto ra offset */
static Widget gotodecv_w; /* INDI goto dec value */
static Widget gotodecm_w; /* INDI goto dec slope */
static Widget gotodecb_w; /* INDI goto dec offset */
static Widget edbon_w; /* TB whether edb GOTO is on */
static Widget rdon_w; /* TB whether ra/dec GOTO is on */
static Widget teleod_w; /* TB whether ra/dec sent as EOD else J2000 */
static Widget markeron_w; /* TB whether skyview marker is on */
static XtIntervalId marker_tid; /* timer to display sky marker */
#define MARK_INT 333 /* marker update interval, ms */
static char scopecategory[] = "INDI Configuration";
void
sc_manage()
{
if (!scopeshell_w)
sc_create_w();
XtPopup (scopeshell_w, XtGrabNone);
set_something (scopeshell_w, XmNiconic, (XtArgVal)False);
}
void
sc_unmanage()
{
if (scopeshell_w)
XtPopdown (scopeshell_w);
}
/* return malloced name of host and port to connect to INDI services.
* N.B. caller must XtFree() each
*/
void
sc_gethost (char **host, char **port)
{
if (!host_w)
sc_create_w();
*host = XmTextFieldGetString (host_w);
*port = XmTextFieldGetString (port_w);
}
/* return whether we are sending goto commands */
int
sc_isGotoOn()
{
if (!scopeshell_w)
sc_create_w();
return (XmToggleButtonGetState(edbon_w) ||
XmToggleButtonGetState(rdon_w));
}
/* send the given object to INDI if On and alt>0.
*/
void
sc_goto (op)
Obj *op;
{
char buf[1024];
/* check whether enabled */
if (!sc_isGotoOn())
return;
/* assert */
if (!op) {
printf ("sc_goto called with no op\n");
abort();
}
/* send as edb if on */
if (XmToggleButtonGetState (edbon_w)) {
char *dev, *prop, *ele;
db_write_line (op, buf);
if (!getINDIprop (edbv_w, &dev, &prop, &ele)) {
char *bp = buf;
if (indi_setTProperty (dev, prop, &ele, &bp, 1, buf) < 0) {
xe_msg (1, "%s", buf);
XmToggleButtonSetState (edbon_w, False, True);
}
}
}
/* send as INDI if on */
if (XmToggleButtonGetState (rdon_w)) {
Now *np = mm_get_now();
char *dev, *prop, *ele[2];
double v[2];
double ra, dec;
/* convert op to desired telescope's coords */
ra = op->f_RA;
dec = op->f_dec;
if (XmToggleButtonGetState(teleod_w)) {
/* telescope wants apparent @ EOD */
if (epoch != EOD) {
as_ap (np, op->f_epoch, &ra, &dec);
} /* else op is already apparent */
} else {
/* telescope wants astrometric @ 2000 */
if (epoch == EOD) {
ap_as (np, J2000, &ra, &dec);
} else {
precess (op->f_epoch, J2000, &ra, &dec);
}
}
/* scale to INDI coords */
v[0] = toINDIValue (ra, gotoram_w, gotorab_w);
v[1] = toINDIValue (dec, gotodecm_w, gotodecb_w);
/* send INDI ra/dec elements */
if (getINDIele (gotorav_w, gotodecv_w, &dev, &prop, ele) < 0) {
XmToggleButtonSetState (rdon_w, False, True);
return;
}
if (indi_setNProperty (dev, prop, ele, v, 2, buf) < 0) {
xe_msg (1, "%s", buf);
XmToggleButtonSetState (edbon_w, False, True);
}
/* clean up */
XtFree (dev);
XtFree (prop);
XtFree (ele[0]);
XtFree (ele[1]);
}
}
/* called to put up or remove the watch cursor. */
void
sc_cursor (c)
Cursor c;
{
Window win;
if (scopeshell_w && (win = XtWindow(scopeshell_w)) != 0) {
Display *dsp = XtDisplay(scopeshell_w);
if (c)
XDefineCursor (dsp, win, c);
else
XUndefineCursor (dsp, win);
}
}
/* create the main scope dialog.
* init Running TB according to whether process is already running.
*/
static void
sc_create_w()
{
Widget rc_w, f_w, sep_w;
Widget scopef_w;
Widget w;
Arg args[20];
int n;
/* create shell and form */
n = 0;
XtSetArg (args[n], XmNallowShellResize, True); n++;
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
XtSetArg (args[n], XmNtitle, "xephem INDI configuration"); n++;
XtSetArg (args[n], XmNiconName, "INDI conf"); n++;
XtSetArg (args[n], XmNdeleteResponse, XmUNMAP); n++;
scopeshell_w = XtCreatePopupShell ("INDIConfig",
topLevelShellWidgetClass, toplevel_w, args, n);
setup_icon (scopeshell_w);
set_something (scopeshell_w, XmNcolormap, (XtArgVal)xe_cm);
sr_reg (scopeshell_w, "XEphem*INDIConfig.x", scopecategory, 0);
sr_reg (scopeshell_w, "XEphem*INDIConfig.y", scopecategory, 0);
n = 0;
XtSetArg (args[n], XmNverticalSpacing, 5); n++;
XtSetArg (args[n], XmNmarginHeight, 10); n++;
XtSetArg (args[n], XmNmarginWidth, 10); n++;
scopef_w = XmCreateForm (scopeshell_w, "ScF", args, n);
XtAddCallback (scopef_w, XmNhelpCallback, sc_help_cb, 0);
XtManageChild (scopef_w);
/* big vertical RC */
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
rc_w = XmCreateRowColumn (scopef_w, "SRC", args, n);
XtManageChild (rc_w);
/* host/port form */
n = 0;
f_w = XmCreateForm (rc_w, "SHPF", args, n);
XtManageChild (f_w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
w = XmCreateLabel (f_w, "SHL", args, n);
set_xmstring (w, XmNlabelString, "Host:");
XtManageChild (w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, w); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNrightPosition, 70); n++;
host_w = XmCreateTextField (f_w, "Host", args, n);
wtip (host_w, "Network host for connecting to INDI server");
fixTextCursor (host_w);
sr_reg (host_w, NULL, scopecategory, 1);
XtManageChild (host_w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, host_w); n++;
XtSetArg (args[n], XmNleftOffset, 5); n++;
w = XmCreateLabel (f_w, "SPL", args, n);
set_xmstring (w, XmNlabelString, "Port:");
XtManageChild (w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, w); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
port_w = XmCreateTextField (f_w, "Port", args, n);
wtip (host_w, "Network port number for connecting to INDI server");
fixTextCursor (port_w);
sr_reg (port_w, NULL, scopecategory, 1);
XtManageChild (port_w);
n = 0;
w = XmCreateLabel (rc_w, "SGap", args, n);
set_xmstring (w, XmNlabelString, " ");
XtManageChild (w);
/* config entries */
oneConfigRow (rc_w, NULL, jd_cb, NULL,
"Send computer time as JD once to",
"JD", &jdv_w, &jdm_w, &jdb_w);
oneConfigRow (rc_w, NULL, posixtm_cb, NULL,
"Send computer time as POSIX once to",
"POSIXTM", &posixtmv_w, NULL, NULL);
oneConfigRow (rc_w, NULL, ll_cb, NULL,
"Send lat and long once to",
"Latitude", &latv_w, &latm_w, &latb_w);
oneConfigRow (rc_w, NULL, NULL, NULL, NULL,
"Longitude", &lngv_w, &lngm_w, &lngb_w);
oneConfigRow (rc_w, NULL, wx_cb, NULL,
"Get temp and pressure once from",
"Temperature", &tempv_w, &tempm_w,&tempb_w);
oneConfigRow (rc_w, NULL, NULL, NULL, NULL,
"Pressure", &presv_w,&presm_w,&presb_w);
oneConfigRow (rc_w, &edbon_w, NULL, "EnableEDB",
"Enable sending edb target to",
"EDB", &edbv_w, NULL, NULL);
oneConfigRow (rc_w, &rdon_w, NULL, "EnableRADec",
"Enable sending RA/Dec goto to",
"GotoRA", &gotorav_w, &gotoram_w, &gotorab_w);
oneConfigRow (rc_w, &teleod_w, NULL, "TelEOD",
"Tel uses EOD, else J2000",
"GotoDec", &gotodecv_w, &gotodecm_w, &gotodecb_w);
oneConfigRow (rc_w, &markeron_w, marker_cb, "SkyMarker",
"Enable Sky marker from",
"SkyRA", &rav_w, &ram_w, &rab_w);
oneConfigRow (rc_w, NULL, NULL, NULL, NULL,
"SkyDec", &decv_w, &decm_w, &decb_w);
/* start listening right away if default for sky marker is On.
* also manage keep-vis option in skyview
*/
if (XmToggleButtonGetState (markeron_w)) {
marker_tid = XtAppAddTimeOut (xe_app, MARK_INT, marker_tcb, 0);
sv_showkeeptelvis (1);
}
/* bottom controls */
n = 0;
f_w = XmCreateForm (rc_w, "SHPF", args, n);
XtManageChild (f_w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNtopOffset, 5); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
sep_w = XmCreateSeparator (f_w, "Sep", args, n);
XtManageChild (sep_w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNtopWidget, sep_w); n++;
XtSetArg (args[n], XmNtopOffset, 10); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomOffset, 5); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNleftPosition, 25); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNrightPosition, 35); n++;
w = XmCreatePushButton (f_w, "Close", args, n);
XtAddCallback (w, XmNactivateCallback, close_cb, NULL);
XtManageChild (w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNtopWidget, sep_w); n++;
XtSetArg (args[n], XmNtopOffset, 10); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomOffset, 5); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNleftPosition, 65); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNrightPosition, 75); n++;
w = XmCreatePushButton (f_w, "Help", args, n);
XtAddCallback (w, XmNactivateCallback, sc_help_cb, NULL);
XtManageChild (w);
}
/* add a row to the configuration table.
*/
static void
oneConfigRow (
Widget rc_w, /* table RC */
Widget *tb_wp, /* TB widget, or NULL */
XtCallbackProc cb, /* tb callback, or NULL */
char *savereg, /* name of persisent TB, or NULL */
char *prompt, /* tb label, or NULL */
char *name, /* base of widget names */
Widget *v_wp, /* indi property value TF widget */
Widget *m_wp, /* slope TF widget, or NULL */
Widget *b_wp) /* intercept TF widget, or NULL */
{
Widget w, f_w;
Arg args[20];
char tfname[64];
int n;
/* main form */
n = 0;
f_w = XmCreateForm (rc_w, "SRCF", args, n);
XtManageChild (f_w);
/* toggle button on left, if we have prompt */
if (prompt) {
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
w = XmCreateToggleButton (f_w, savereg?savereg:"SFTB", args, n);
if (cb)
XtAddCallback (w, XmNvalueChangedCallback, cb, NULL);
set_xmstring (w, XmNlabelString, prompt);
XtManageChild (w);
if (tb_wp)
*tb_wp = w;
if (savereg)
sr_reg (w, NULL, scopecategory, 1);
}
/* value and optional slope and intercept TFs */
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNleftPosition, 40); n++;
XtSetArg (args[n], XmNcolumns, 40); n++;
sprintf (tfname, "%sValue", name);
*v_wp = XmCreateTextField (f_w, tfname, args, n);
fixTextCursor (*v_wp);
sr_reg (*v_wp, NULL, scopecategory, 1);
wtip (*v_wp, "INDI Device.Property.Element for this quantity");
XtManageChild (*v_wp);
if (m_wp && b_wp) {
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, *v_wp); n++;
w = XmCreateLabel (f_w, "SM", args, n);
set_xmstring (w, XmNlabelString, " x ");
XtManageChild (w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, w); n++;
XtSetArg (args[n], XmNcolumns, 8); n++;
sprintf (tfname, "%sSlope", name);
*m_wp = XmCreateTextField (f_w, tfname, args, n);
sr_reg (*m_wp, NULL, scopecategory, 1);
fixTextCursor (*m_wp);
wtip (*m_wp, "Scale multiplier applied to INDI value");
XtManageChild (*m_wp);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, *m_wp); n++;
w = XmCreateLabel (f_w, "SL", args, n);
set_xmstring (w, XmNlabelString, " + ");
XtManageChild (w);
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, w); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNcolumns, 8); n++;
sprintf (tfname, "%sOffset", name);
*b_wp = XmCreateTextField (f_w, tfname, args, n);
sr_reg (*b_wp, NULL, scopecategory, 1);
fixTextCursor (*b_wp);
wtip (*b_wp, "Offset added to INDI value");
XtManageChild (*b_wp);
}
}
/* called when the help button is hit */
/* ARGSUSED */
static void
sc_help_cb (w, client, call)
Widget w;
XtPointer client;
XtPointer call;
{
static char *msg[] = {
"Configure how INDI services connect with XEphem."
};
hlp_dialog ("SkyView_telescope", msg, sizeof(msg)/sizeof(msg[0]));
}
/* callback to send JD */
static void
jd_cb (Widget w, XtPointer client, XtPointer call)
{
char *dev, *prop, *ele;
char buf[1024];
Now now;
double v;
/* act like a pushbutton */
if (!XmToggleButtonGetState(w))
return;
XmToggleButtonSetState (w, False, True);
/* gather property name */
if (getINDIprop (jdv_w, &dev, &prop, &ele) < 0)
return;
/* convert computer mjd to indi jd and send */
time_fromsys (&now);
v = toINDIValue (now.n_mjd, jdm_w, jdb_w);
if (indi_setNProperty (dev, prop, &ele, &v, 1, buf) < 0)
xe_msg (1, "%s", buf);
/* clean up */
XtFree (dev);
XtFree (prop);
XtFree (ele);
}
/* callback to send time in POSIX format */
static void
posixtm_cb (Widget w, XtPointer client, XtPointer call)
{
char *dev, *prop, *ele;
char buf[1024], *bp = buf;
int mm, yy, d, h, m, s;
double dd, dh, dm, ds;
Now now;
/* act like a pushbutton */
if (!XmToggleButtonGetState(w))
return;
XmToggleButtonSetState (w, False, True);
/* gather property name */
if (getINDIprop (posixtmv_w, &dev, &prop, &ele) < 0)
return;
/* convert computer mjd to POSIX and send */
time_fromsys (&now);
mjd_cal (now.n_mjd, &mm, &dd, &yy);
d = (int)dd;
dh = (dd - d)*24.;
h = (int)dh;
dm = (dh - h)*60.;
m = (int)dm;
ds = (dm - m)*60.;
if (ds >= 59.5) {
s = 0;
if (++m == 60) {
m = 0;
h += 1; /* TODO: roll date if hits 24 */
}
} else
s = (int)ds;
sprintf (buf, "%4d-%02d-%02dT%02d:%02d:%02d", yy, mm, d, h, m, s);
if (indi_setTProperty (dev, prop, &ele, &bp, 1, buf) < 0)
xe_msg (1, "%s", buf);
/* clean up */
XtFree (dev);
XtFree (prop);
XtFree (ele);
}
/* callback to send lat/long */
static void
ll_cb (Widget w, XtPointer client, XtPointer call)
{
Now *np = mm_get_now();
char *dev, *prop, *ele[2];
double v[2];
char buf[1024];
/* act like a pushbutton */
if (!XmToggleButtonGetState(w))
return;
XmToggleButtonSetState (w, False, True);
/* get INDI elements with lat/long */
if (getINDIele (latv_w, lngv_w, &dev, &prop, ele) < 0)
return;
v[0] = toINDIValue (lat, latm_w, latb_w);
v[1] = toINDIValue (lng, lngm_w, lngb_w);
if (indi_setNProperty (dev, prop, ele, v, 2, buf) < 0)
xe_msg (1, "%s", buf);
/* clean up */
XtFree (dev);
XtFree (prop);
XtFree (ele[0]);
XtFree (ele[1]);
}
/* set our temp/pres from INDI */
static void
wx_cb (Widget w, XtPointer client, XtPointer call)
{
INumberVectorProperty *wxp;
char *dev, *prop, *ele[2];
/* act like a pushbutton */
if (!XmToggleButtonGetState(w))
return;
XmToggleButtonSetState (w, False, True);
/* get INDI elements with current temp/pres */
if (getINDIele (tempv_w, presv_w, &dev, &prop, ele) < 0)
return;
wxp = indi_getNProperty (dev, prop);
if (wxp) {
INumber *tnp = findNumber (wxp, ele[0]);
if (tnp) {
INumber *pnp = findNumber (wxp, ele[1]);
if (pnp) {
Now *np = mm_get_now();
temp = fromINDIValue (tnp->value, tempm_w, tempb_w);
pressure = fromINDIValue (pnp->value, presm_w, presb_w);
redraw_screen (1);
} else {
xe_msg (1, "INDI: %s.%s.%s not found", dev,prop,ele[1]);
}
} else {
xe_msg (1, "INDI: %s.%s.%s not found", dev,prop,ele[0]);
}
}
/* clean up */
XtFree (dev);
XtFree (prop);
XtFree (ele[0]);
XtFree (ele[1]);
}
static void
close_cb (Widget w, XtPointer client, XtPointer call)
{
XtPopdown (scopeshell_w);
}
/* toggle whether to display the sky marker */
static void
marker_cb (Widget w, XtPointer client, XtPointer call)
{
int on = XmToggleButtonGetState (w);
/* always remove any old timer */
if (marker_tid) {
XtRemoveTimeOut (marker_tid);
marker_tid = (XtIntervalId)0;
}
/* start fresh if turning on */
if (on)
marker_tid = XtAppAddTimeOut (xe_app, MARK_INT, marker_tcb, 0);
/* only show keep-vis in skyview is marker is on */
sv_showkeeptelvis(on);
}
/* timer callback to put up the sky marker.
* ok if properties not available now
*/
static void
marker_tcb (XtPointer client, XtIntervalId *id)
{
char *dev, *prop, *ele[2];
int ok = 1;
/* if connected, get names of ra/dec properties */
if (indi_connected() == 0) {
if (getINDIele (rav_w,decv_w,&dev,&prop,ele) < 0)
ok = 0; /* already issued xe_msg() */
else {
/* get the live vector, ok if not available yet */
INumberVectorProperty *rap = indi_getNProperty (dev, prop);
if (rap) {
/* extract the ra/dec values */
INumber *rnp = findNumber (rap, ele[0]);
if (rnp) {
INumber *dnp = findNumber (rap, ele[1]);
if (dnp) {
Now *np = mm_get_now();
Obj o;
/* get telescope's coords */
double ra = fromINDIValue (rnp->value, ram_w, rab_w);
double dec = fromINDIValue (dnp->value, decm_w,decb_w);
/* convert from telescope's coords to astrometric J2000 */
if (XmToggleButtonGetState(teleod_w)) {
/* telescope is sending us apparent at EOD */
ap_as (np, J2000, &ra, &dec);
} /* else no change, telescope already sending us astrometric @ J2000 */
/* find sky fields */
memset (&o, 0, sizeof(o));
o.f_RA = ra;
o.f_dec = dec;
o.o_type = FIXED;
o.f_epoch = J2000;
obj_cir (np, &o);
/* mark, on screen */
sv_scopeMark (&o);
} else {
xe_msg(1,"INDI:%s.%s.%s not found",dev,prop,ele[1]);
ok = 0;
}
} else {
xe_msg (1, "INDI: %s.%s.%s not found", dev,prop,ele[0]);
ok = 0;
}
}
/* clean up */
XtFree (dev);
XtFree (prop);
XtFree (ele[0]);
XtFree (ele[1]);
}
}
/* repeat if ok */
if (ok)
marker_tid = XtAppAddTimeOut (xe_app, MARK_INT, marker_tcb, 0);
else
XmToggleButtonSetState (markeron_w, False, True);
}
/* get the name of the INDI d.p.e(s) described by TF w1 and possibly w2.
* return 0 if ok else issue xe_msg() and return -1.
* N.B. if return 0 caller must XtFree() each pointer
*/
static int
getINDIele (Widget w1, Widget w2, char **dev, char **prop, char *ele[])
{
char *dev1, *prop1;
char *dev2, *prop2;
char *myele[2];
/* gather property names */
if (getINDIprop (w1, &dev1, &prop1, &myele[0]) < 0)
return (-1);
if (w2 && getINDIprop (w2, &dev2, &prop2, &myele[1]) < 0) {
XtFree (dev1);
XtFree (prop1);
XtFree (myele[0]);
return (-1);
}
/* if two then must be the same */
if (w2 && (strcmp (dev1,dev2) || strcmp (prop1,prop2))) {
xe_msg (1, "Properties %s.%s and %s.%s must match to be atomic",
dev1, prop1, dev2, prop2);
XtFree (dev1);
XtFree (prop1);
XtFree (myele[0]);
XtFree (dev2);
XtFree (prop2);
XtFree (myele[1]);
return (-1);
}
/* ok */
*dev = dev1;
*prop = prop1;
ele[0] = myele[0];
if (w2)
ele[1] = myele[1];
return (0);
}
/* extract the device.property.element name from the given text field.
* return 0 if ok else issue xe_msg() and return -1.
* N.B. if return 0 caller must XtFree() each pointer
*/
static int
getINDIprop (Widget tf_w, char **dev, char **prop, char **ele)
{
char *string = XmTextFieldGetString (tf_w);
char devstr[64], propstr[64], elestr[64];
int ok;
ok = sscanf (string, "%[^.].%[^.].%s", devstr, propstr, elestr) == 3;
if (!ok) {
xe_msg (1, "%s:\nINDI format must be dev.prop.element", string);
}
XtFree (string);
if (ok) {
*dev = XtNewString (devstr);
*prop = XtNewString (propstr);
*ele = XtNewString (elestr);
return (0);
}
return (-1);
}
/* find a particular INumber in a INumberVector */
static INumber *
findNumber (INumberVectorProperty *nvp, char *name)
{
INumber *np;
for (np = nvp->np; np < &nvp->np[nvp->nnp]; np++)
if (strcmp (np->name, name) == 0)
return (np);
return (NULL);
}
/* convert the given local number to its INDI value using the slope and offset
* values in the given TF widgets
*/
static double
toINDIValue (double localv, Widget m_w, Widget b_w)
{
char *mstr = XmTextFieldGetString (m_w);
char *bstr = XmTextFieldGetString (b_w);
double indiv = (localv - atod(bstr))/atod(mstr);
XtFree (mstr);
XtFree (bstr);
return (indiv);
}
/* convert the given INDI number to its local value using the slope and offset
* values in the given TF widgets
*/
static double
fromINDIValue (double indiv, Widget m_w, Widget b_w)
{
char *mstr = XmTextFieldGetString (m_w);
char *bstr = XmTextFieldGetString (b_w);
double localv = indiv*atod(mstr) + atod(bstr);
XtFree (mstr);
XtFree (bstr);
return (localv);
}
/* For RCS Only -- Do Not Edit */
static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: scope.c,v $ $Date: 2021/12/14 19:10:55 $ $Revision: 1.29 $ $Name: $"};