#define POS_HOLD_AVERAGE 10000
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined(REFCLOCK) && defined(CLOCK_ONCORE) && defined(HAVE_PPSAPI)
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_refclock.h"
#include "ntp_stdlib.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/stat.h>
#ifdef ONCORE_SHMEM_STATUS
# ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
# ifndef MAP_FAILED
# define MAP_FAILED ((u_char *) -1)
# endif
# endif
#endif
#ifdef HAVE_PPSAPI
# ifdef HAVE_TIMEPPS_H
# include <timepps.h>
# else
# ifdef HAVE_SYS_TIMEPPS_H
# include <sys/timepps.h>
# endif
# endif
#endif
#ifdef HAVE_SYS_SIO_H
# include <sys/sio.h>
#endif
#ifdef HAVE_SYS_TERMIOS_H
# include <sys/termios.h>
#endif
#ifdef HAVE_SYS_PPSCLOCK_H
# include <sys/ppsclock.h>
#endif
#ifndef HAVE_STRUCT_PPSCLOCKEV
struct ppsclockev {
# ifdef HAVE_STRUCT_TIMESPEC
struct timespec tv;
# else
struct timeval tv;
# endif
u_int serial;
};
#endif
enum receive_state {
ONCORE_NO_IDEA,
ONCORE_ID_SENT,
ONCORE_RESET_SENT,
ONCORE_TEST_SENT,
ONCORE_INIT,
ONCORE_ALMANAC,
ONCORE_RUN
};
enum site_survey_state {
ONCORE_SS_UNKNOWN,
ONCORE_SS_TESTING,
ONCORE_SS_HW,
ONCORE_SS_SW,
ONCORE_SS_DONE
};
enum oncore_model {
ONCORE_BASIC,
ONCORE_PVT6,
ONCORE_VP,
ONCORE_UT,
ONCORE_UTPLUS,
ONCORE_GT,
ONCORE_GTPLUS,
ONCORE_SL,
ONCORE_M12,
ONCORE_UNKNOWN
};
struct RSM {
u_char posn0D;
u_char posn2D;
u_char posn3D;
u_char bad_almanac;
u_char bad_fix;
};
enum posn_mode {
MODE_UNKNOWN,
MODE_0D,
MODE_2D,
MODE_3D
};
struct instance {
int unit;
struct refclockproc *pp;
struct peer *peer;
int ttyfd;
int ppsfd;
int statusfd;
#ifdef HAVE_PPSAPI
pps_handle_t pps_h;
pps_params_t pps_p;
#endif
enum receive_state o_state;
enum posn_mode mode;
enum site_survey_state site_survey;
int Bj_day;
u_long delay;
long offset;
u_char *shmem;
char *shmem_fname;
u_int shmem_Cb;
u_int shmem_Ba;
u_int shmem_Ea;
u_int shmem_Ha;
u_char shmem_first;
u_char shmem_reset;
u_char shmem_Posn;
double ss_lat;
double ss_long;
double ss_ht;
double dH;
int ss_count;
u_char posn_set;
enum oncore_model model;
u_int version;
u_int revision;
u_char chan;
s_char traim;
u_char traim_delay;
struct RSM rsm;
u_char printed;
u_char polled;
int pollcnt;
u_int ev_serial;
int Rcvptr;
u_char Rcvbuf[500];
u_char Ea[160];
u_char En[70];
u_char Cj[300];
u_char As;
u_char Ay;
u_char Az;
u_char have_dH;
u_char init_type;
s_char saw_tooth;
u_int timeout;
u_char count;
s_char assert;
u_int saw_At;
};
#define rcvbuf instance->Rcvbuf
#define rcvptr instance->Rcvptr
static void oncore_consume P((struct instance *));
static void oncore_poll P((int, struct peer *));
static void oncore_read_config P((struct instance *));
static void oncore_receive P((struct recvbuf *));
static void oncore_sendmsg P((int fd, u_char *, size_t));
static void oncore_shutdown P((int, struct peer *));
static int oncore_start P((int, struct peer *));
static void oncore_get_timestamp P((struct instance *, long, long));
static void oncore_init_shmem P((struct instance *));
static void oncore_print_As P((struct instance *));
static void oncore_msg_any P((struct instance *, u_char *, size_t, int));
static void oncore_msg_As P((struct instance *, u_char *, size_t));
static void oncore_msg_At P((struct instance *, u_char *, size_t));
static void oncore_msg_Ay P((struct instance *, u_char *, size_t));
static void oncore_msg_Az P((struct instance *, u_char *, size_t));
static void oncore_msg_BaEaHa P((struct instance *, u_char *, size_t));
static void oncore_msg_Bj P((struct instance *, u_char *, size_t));
static void oncore_msg_BnEn P((struct instance *, u_char *, size_t));
static void oncore_msg_CaFaIa P((struct instance *, u_char *, size_t));
static void oncore_msg_Cb P((struct instance *, u_char *, size_t));
static void oncore_msg_Cf P((struct instance *, u_char *, size_t));
static void oncore_msg_Cj P((struct instance *, u_char *, size_t));
static void oncore_msg_Cj_id P((struct instance *, u_char *, size_t));
static void oncore_msg_Cj_init P((struct instance *, u_char *, size_t));
static void oncore_msg_Gj P((struct instance *, u_char *, size_t));
static void oncore_msg_Sz P((struct instance *, u_char *, size_t));
struct refclock refclock_oncore = {
oncore_start,
oncore_shutdown,
oncore_poll,
noentry,
noentry,
noentry,
NOFLAGS
};
static struct msg_desc {
const char flag[3];
const int len;
void (*handler) P((struct instance *, u_char *, size_t));
const char *fmt;
int shmem;
} oncore_messages[] = {
{ "Ea", 76, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdimsdimsdsC" },
{ "Ba", 68, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmvvhhddtntimsdimsdimsdimsdimsdimsdsC" },
{ "Ha", 154, oncore_msg_BaEaHa, "mdyyhmsffffaaaaoooohhhhmmmmaaaaoooohhhhmmmmVVvvhhddntimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddimsiddssrrccooooTTushmvvvvvvC" },
{ "En", 69, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffsffffsffffC" },
{ "Bn", 59, oncore_msg_BnEn, "otaapxxxxxxxxxxpysreensffffsffffsffffsffffsffffsffffC" },
{ "Ab", 10, 0, "" },
{ "Ac", 11, 0, "" },
{ "Ad", 11, 0, "" },
{ "Ae", 11, 0, "" },
{ "Af", 15, 0, "" },
{ "As", 20, oncore_msg_As, "" },
{ "At", 8, oncore_msg_At, "" },
{ "Au", 12, 0, "" },
{ "Av", 8, 0, "" },
{ "Aw", 8, 0, "" },
{ "Ay", 11, oncore_msg_Ay, "" },
{ "Az", 11, oncore_msg_Az, "" },
{ "AB", 8, 0, "" },
{ "Bb", 92, 0, "" },
{ "Bj", 8, oncore_msg_Bj, "" },
{ "Ca", 9, oncore_msg_CaFaIa, "" },
{ "Cb", 33, oncore_msg_Cb, "" },
{ "Cf", 7, oncore_msg_Cf, "" },
{ "Cg", 8, 0, "" },
{ "Ch", 9, 0, "" },
{ "Cj", 294, oncore_msg_Cj, "" },
{ "Ek", 71, 0, "" },
{ "Fa", 9, oncore_msg_CaFaIa, "" },
{ "Gd", 8, 0, "" },
{ "Gj", 21, oncore_msg_Gj, "" },
{ "Ia", 10, oncore_msg_CaFaIa, "" },
{ "Sz", 8, oncore_msg_Sz, "" },
{ {0}, 7, 0, "" }
};
u_char oncore_cmd_Ad[] = { 'A', 'd', 0,0,0,0 };
u_char oncore_cmd_Ae[] = { 'A', 'e', 0,0,0,0 };
u_char oncore_cmd_Af[] = { 'A', 'f', 0,0,0,0, 0 };
u_char oncore_cmd_Ga[] = { 'G', 'a', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
static u_char oncore_cmd_At0[] = { 'A', 't', 0 };
static u_char oncore_cmd_At1[] = { 'A', 't', 1 };
static u_char oncore_cmd_At2[] = { 'A', 't', 2 };
u_char oncore_cmd_As[] = { 'A', 's', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 };
u_char oncore_cmd_Asx[]= { 'A', 's', 0x7f, 0xff, 0xff, 0xff,
0x7f, 0xff, 0xff, 0xff,
0x7f, 0xff, 0xff, 0xff, 0xff };
u_char oncore_cmd_Au[] = { 'A', 'u', 0,0,0,0,0 };
u_char oncore_cmd_Av0[] = { 'A', 'v', 0 };
u_char oncore_cmd_Av1[] = { 'A', 'v', 1 };
u_char oncore_cmd_Gd0[] = { 'G', 'd', 0 };
u_char oncore_cmd_Gd1[] = { 'G', 'd', 1 };
u_char oncore_cmd_Gd2[] = { 'G', 'd', 2 };
u_char oncore_cmd_Aw[] = { 'A', 'w', 1 };
u_char oncore_cmd_Be[] = { 'B', 'e', 1 };
u_char oncore_cmd_Ay[] = { 'A', 'y', 0, 0, 0, 0 };
u_char oncore_cmd_Ayx[] = { 'A', 'y', 0xff, 0xff, 0xff, 0xff };
u_char oncore_cmd_Az[] = { 'A', 'z', 0, 0, 0, 0 };
u_char oncore_cmd_Azx[] = { 'A', 'z', 0xff, 0xff, 0xff, 0xff };
u_char oncore_cmd_AB[] = { 'A', 'B', 4 };
u_char oncore_cmd_Bb[] = { 'B', 'b', 1 };
u_char oncore_cmd_Bj[] = { 'B', 'j', 0 };
u_char oncore_cmd_Gj[] = { 'G', 'j' };
static u_char oncore_cmd_Cf[] = { 'C', 'f' };
u_char oncore_cmd_Cg[] = { 'C', 'g', 1 };
static u_char oncore_cmd_Cj[] = { 'C', 'j' };
static u_char oncore_cmd_Ea[] = { 'E', 'a', 1 };
static u_char oncore_cmd_Ba[] = { 'B', 'a', 1 };
static u_char oncore_cmd_Ha[] = { 'H', 'a', 1 };
static u_char oncore_cmd_Ea0[] = { 'E', 'a', 0 };
static u_char oncore_cmd_Ba0[] = { 'B', 'a', 0 };
u_char oncore_cmd_Ek[] = { 'E', 'k', 0 };
static u_char oncore_cmd_En[] = { 'E', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static u_char oncore_cmd_En0[] = { 'E', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static u_char oncore_cmd_Bn[] = { 'B', 'n', 1, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static u_char oncore_cmd_Bn0[] = { 'B', 'n', 0, 1, 0,10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static u_char oncore_cmd_Ca[] = { 'C', 'a' };
static u_char oncore_cmd_Fa[] = { 'F', 'a' };
static u_char oncore_cmd_Ia[] = { 'I', 'a' };
#define DEVICE1 "/dev/oncore.serial.%d"
#define DEVICE2 "/dev/oncore.pps.%d"
#define INIT_FILE "/etc/ntp.oncore"
#define SPEED B9600
#define w32_buf(buf,w) { u_int i_tmp; \
i_tmp = (w<0) ? (~(-w)+1) : (w); \
(buf)[0] = (i_tmp >> 24) & 0xff; \
(buf)[1] = (i_tmp >> 16) & 0xff; \
(buf)[2] = (i_tmp >> 8) & 0xff; \
(buf)[3] = (i_tmp ) & 0xff; \
}
#define w32(buf) (((buf)[0]&0xff) << 24 | \
((buf)[1]&0xff) << 16 | \
((buf)[2]&0xff) << 8 | \
((buf)[3]&0xff) )
#define buf_w32(buf) (((buf)[0]&0200) ? (-(~w32(buf)+1)) : w32(buf))
extern int pps_assert;
extern int pps_hardpps;
static int
oncore_start(
int unit,
struct peer *peer
)
{
register struct instance *instance;
struct refclockproc *pp;
int fd1, fd2, mode;
char device1[30], device2[30];
const char *cp;
struct stat stat1, stat2;
(void)sprintf(device1, DEVICE1, unit);
(void)sprintf(device2, DEVICE2, unit);
if (stat(device1, &stat1)) {
perror("ONCORE: stat fd1");
exit(1);
}
if (stat(device2, &stat2)) {
perror("ONCORE: stat fd2");
exit(1);
}
if ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino)) {
if (!(fd1 = refclock_open(device1, SPEED, LDISC_RAW
#if !defined(HAVE_PPSAPI) && !defined(TIOCDCDTIMESTAMP)
| LDISC_PPS
#endif
))) {
perror("ONCORE: fd1");
exit(1);
}
fd2 = fd1;
} else {
if (!(fd1=refclock_open(device1, SPEED, LDISC_RAW))) {
perror("ONCORE: fd1");
exit(1);
}
if ((fd2=open(device2, O_RDWR)) < 0) {
perror("ONCORE: fd2");
exit(1);
}
}
if (!(instance = (struct instance *) malloc(sizeof *instance))) {
perror("malloc");
close(fd1);
return (0);
}
memset((char *) instance, 0, sizeof *instance);
pp = peer->procptr;
pp->unitptr = (caddr_t) instance;
instance->pp = pp;
instance->unit = unit;
instance->peer = peer;
instance->o_state = ONCORE_NO_IDEA;
cp = "state = ONCORE_NO_IDEA";
record_clock_stats(&(instance->peer->srcadr), cp);
instance->ttyfd = fd1;
instance->ppsfd = fd2;
instance->Bj_day = -1;
instance->assert = pps_assert;
instance->traim = -1;
instance->model = ONCORE_UNKNOWN;
instance->mode = MODE_UNKNOWN;
instance->site_survey = ONCORE_SS_UNKNOWN;
peer->precision = -26;
peer->minpoll = 4;
peer->maxpoll = 4;
pp->clockdesc = "Motorola Oncore GPS Receiver";
memcpy((char *)&pp->refid, "GPS\0", (size_t) 4);
oncore_read_config(instance);
#ifdef HAVE_PPSAPI
if (time_pps_create(fd2, &instance->pps_h) < 0) {
perror("time_pps_create");
return(0);
}
if (time_pps_getcap(instance->pps_h, &mode) < 0) {
msyslog(LOG_ERR,
"refclock_ioctl: time_pps_getcap failed: %m");
return (0);
}
if (time_pps_getparams(instance->pps_h, &instance->pps_p) < 0) {
msyslog(LOG_ERR,
"refclock_ioctl: time_pps_getparams failed: %m");
return (0);
}
if (instance->assert) {
instance->pps_p.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
instance->pps_p.assert_offset.tv_sec = 0;
instance->pps_p.assert_offset.tv_nsec = 0;
} else {
instance->pps_p.mode = PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
instance->pps_p.clear_offset.tv_sec = 0;
instance->pps_p.clear_offset.tv_nsec = 0;
}
instance->pps_p.mode |= PPS_TSFMT_TSPEC;
instance->pps_p.mode &= mode;
if (time_pps_setparams(instance->pps_h, &instance->pps_p) < 0) {
perror("time_pps_setparams");
exit(1);
}
if (pps_device && pps_device[0]) {
if (stat(pps_device, &stat1)) {
perror("ONCORE: stat pps_device");
return(0);
}
if (pps_hardpps && ((stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino))) {
int i;
if (instance->assert)
i = PPS_CAPTUREASSERT;
else
i = PPS_CAPTURECLEAR;
if (i&mode) {
if (time_pps_kcbind(instance->pps_h, PPS_KC_HARDPPS, i,
PPS_TSFMT_TSPEC) < 0) {
msyslog(LOG_ERR,
"refclock_ioctl: time_pps_kcbind failed: %m");
return (0);
}
pps_enable = 1;
}
}
}
#endif
pp->io.clock_recv = oncore_receive;
pp->io.srcclock = (caddr_t)peer;
pp->io.datalen = 0;
pp->io.fd = fd1;
if (!io_addclock(&pp->io)) {
perror("io_addclock");
(void) close(fd1);
free(instance);
return (0);
}
oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
instance->o_state = ONCORE_ID_SENT;
cp = "state = ONCORE_ID SENT";
record_clock_stats(&(instance->peer->srcadr), cp);
instance->timeout = 4;
instance->pollcnt = 2;
return (1);
}
static void
oncore_read_config(
struct instance *instance
)
{
FILE *fd;
char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160];
int i, sign, lat_flg, long_flg, ht_flg, mode;
double f1, f2, f3;
sprintf(device, "%s%d", INIT_FILE, instance->unit);
if ((fd=fopen(device, "r")) == NULL) {
sprintf(device, "%s.%d", INIT_FILE, instance->unit);
if ((fd=fopen(device, "r")) == NULL) {
if ((fd=fopen(INIT_FILE, "r")) == NULL) {
instance->init_type = 4;
return;
}
}
}
mode = 0;
lat_flg = long_flg = ht_flg = 0;
while (fgets(line, 100, fd)) {
if ((cp = strchr(line, '#')))
*cp = '\0';
for (i = strlen(line);
i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]);
)
line[--i] = '\0';
for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++)
continue;
if (!*cc)
continue;
for (ca = cc; *ca; ca++) {
if (isascii((int)*ca)) {
if (islower((int)*ca)) {
*ca = toupper(*ca);
} else if (isspace((int)*ca) || (*ca == '='))
break;
}
}
for (; *ca && isascii((int)*ca) && (isspace((int)*ca) || (*ca == '=')); ca++)
continue;
if (!strncmp(cc, "STATUS", (size_t) 6) || !strncmp(cc, "SHMEM", (size_t) 5)) {
i = strlen(ca);
instance->shmem_fname = (char *) malloc((unsigned) (i+1));
strcpy(instance->shmem_fname, ca);
continue;
}
for (cp = ca; *cp; cp++)
if (isascii((int)*cp) && islower((int)*cp))
*cp = toupper(*cp);
if (!strncmp(cc, "LAT", (size_t) 3)) {
f1 = f2 = f3 = 0;
sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
sign = 1;
if (f1 < 0) {
f1 = -f1;
sign = -1;
}
instance->ss_lat = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1));
lat_flg++;
} else if (!strncmp(cc, "LON", (size_t) 3)) {
f1 = f2 = f3 = 0;
sscanf(ca, "%lf %lf %lf", &f1, &f2, &f3);
sign = 1;
if (f1 < 0) {
f1 = -f1;
sign = -1;
}
instance->ss_long = sign*1000*(fabs(f3) + 60*(fabs(f2) + 60*f1));
long_flg++;
} else if (!strncmp(cc, "HT", (size_t) 2)) {
f1 = 0;
units[0] = '\0';
sscanf(ca, "%lf %1s", &f1, units);
if (units[0] == 'F')
f1 = 0.3048 * f1;
instance->ss_ht = 100 * f1;
ht_flg++;
} else if (!strncmp(cc, "DELAY", (size_t) 5)) {
f1 = 0;
units[0] = '\0';
sscanf(ca, "%lf %1s", &f1, units);
if (units[0] == 'N')
;
else if (units[0] == 'U')
f1 = 1000 * f1;
else if (units[0] == 'M')
f1 = 1000000 * f1;
else
f1 = 1000000000 * f1;
if (f1 < 0 || f1 > 1.e9)
f1 = 0;
if (f1 < 0 || f1 > 999999) {
sprintf(Msg, "PPS Cable delay of %fns out of Range, ignored", f1);
record_clock_stats(&(instance->peer->srcadr), Msg);
} else
instance->delay = f1;
} else if (!strncmp(cc, "OFFSET", (size_t) 6)) {
f1 = 0;
units[0] = '\0';
sscanf(ca, "%lf %1s", &f1, units);
if (units[0] == 'N')
;
else if (units[0] == 'U')
f1 = 1000 * f1;
else if (units[0] == 'M')
f1 = 1000000 * f1;
else
f1 = 1000000000 * f1;
if (f1 < 0 || f1 > 1.e9)
f1 = 0;
if (f1 < 0 || f1 > 999999999.) {
sprintf(Msg, "PPS Offset of %fns out of Range, ignored", f1);
record_clock_stats(&(instance->peer->srcadr), Msg);
} else
instance->offset = f1;
} else if (!strncmp(cc, "MODE", (size_t) 4)) {
sscanf(ca, "%d", &mode);
if (mode < 0 || mode > 4)
mode = 4;
} else if (!strncmp(cc, "ASSERT", (size_t) 6)) {
instance->assert = 1;
} else if (!strncmp(cc, "CLEAR", (size_t) 5)) {
instance->assert = 0;
} else if (!strncmp(cc, "POSN2D", (size_t) 6)) {
instance->shmem_Posn = 2;
} else if (!strncmp(cc, "POSN3D", (size_t) 6)) {
instance->shmem_Posn = 3;
} else if (!strncmp(cc, "CHAN", (size_t) 4)) {
sscanf(ca, "%d", &i);
if ((i == 6) || (i == 8) || (i == 12))
instance->chan = i;
} else if (!strncmp(cc, "TRAIM", (size_t) 5)) {
instance->traim = 1;
if (!strcmp(ca, "NO") || !strcmp(ca, "OFF"))
instance->traim = 0;
}
}
fclose(fd);
instance->posn_set = 1;
if ((lat_flg || long_flg || ht_flg) && !(lat_flg * long_flg * ht_flg)) {
printf("ONCORE: incomplete data on %s\n", INIT_FILE);
instance->posn_set = 0;
if (mode == 1 || mode == 3) {
sprintf(Msg, "Input Mode = %d, but no/incomplete position, mode set to %d", mode, mode+1);
record_clock_stats(&(instance->peer->srcadr), Msg);
mode++;
}
}
instance->init_type = mode;
sprintf(Msg, "Input mode = %d", mode);
record_clock_stats(&(instance->peer->srcadr), Msg);
}
static void
oncore_init_shmem(
struct instance *instance
)
{
#ifdef ONCORE_SHMEM_STATUS
int i, l, n;
char *buf;
struct msg_desc *mp;
size_t oncore_shmem_length;
if (instance->shmem_first)
return;
instance->shmem_first++;
if ((instance->statusfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
perror(instance->shmem_fname);
return;
}
n = 1;
for (mp = oncore_messages; mp->flag[0]; mp++) {
mp->shmem = n;
if (!strcmp(mp->flag, "Cb")) {
instance->shmem_Cb = n;
n += (mp->len + 3) * 34;
}
if (!strcmp(mp->flag, "Ba")) {
instance->shmem_Ba = n;
n += (mp->len + 3) * 3;
}
if (!strcmp(mp->flag, "Ea")) {
instance->shmem_Ea = n;
n += (mp->len + 3) * 3;
}
if (!strcmp(mp->flag, "Ha")) {
instance->shmem_Ha = n;
n += (mp->len + 3) * 3;
}
n += (mp->len + 3);
}
oncore_shmem_length = n + 2;
fprintf(stderr, "ONCORE: SHMEM length: %d bytes\n", (int) oncore_shmem_length);
buf = malloc(oncore_shmem_length);
if (buf == NULL) {
perror("malloc");
return;
}
memset(buf, 0, sizeof(buf));
i = write(instance->statusfd, buf, oncore_shmem_length);
if (i != oncore_shmem_length) {
perror(instance->shmem_fname);
return;
}
free(buf);
instance->shmem = (u_char *) mmap(0, oncore_shmem_length,
PROT_READ | PROT_WRITE,
#ifdef MAP_HASSEMAPHORE
MAP_HASSEMAPHORE |
#endif
MAP_SHARED,
instance->statusfd, (off_t)0);
if (instance->shmem == (u_char *)MAP_FAILED) {
instance->shmem = 0;
close (instance->statusfd);
return;
}
for (mp = oncore_messages; mp->flag[0]; mp++) {
l = mp->shmem;
instance->shmem[l + 0] = mp->len >> 8;
instance->shmem[l + 1] = mp->len & 0xff;
instance->shmem[l + 2] = 0;
instance->shmem[l + 3] = '@';
instance->shmem[l + 4] = '@';
instance->shmem[l + 5] = mp->flag[0];
instance->shmem[l + 6] = mp->flag[1];
if (!strcmp(mp->flag, "Cb") || !strcmp(mp->flag, "Ba") || !strcmp(mp->flag, "Ea") || !strcmp(mp->flag, "Ha")) {
if (!strcmp(mp->flag, "Cb"))
n = 35;
else
n = 4;
for (i = 1; i < n; i++) {
instance->shmem[l + i * (mp->len+3) + 0] = mp->len >> 8;
instance->shmem[l + i * (mp->len+3) + 1] = mp->len & 0xff;
instance->shmem[l + i * (mp->len+3) + 2] = 0;
instance->shmem[l + i * (mp->len+3) + 3] = '@';
instance->shmem[l + i * (mp->len+3) + 4] = '@';
instance->shmem[l + i * (mp->len+3) + 5] = mp->flag[0];
instance->shmem[l + i * (mp->len+3) + 6] = mp->flag[1];
}
}
}
#endif
}
static void
oncore_shutdown(
int unit,
struct peer *peer
)
{
register struct instance *instance;
struct refclockproc *pp;
pp = peer->procptr;
instance = (struct instance *) pp->unitptr;
io_closeclock(&pp->io);
free(instance);
}
static void
oncore_poll(
int unit,
struct peer *peer
)
{
struct instance *instance;
instance = (struct instance *) peer->procptr->unitptr;
if (instance->timeout) {
char *cp;
instance->timeout--;
if (instance->timeout == 0) {
cp = "Oncore: No response from @@Cj, shutting down driver";
record_clock_stats(&(instance->peer->srcadr), cp);
oncore_shutdown(unit, peer);
} else {
oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
cp = "Oncore: Resend @@Cj";
record_clock_stats(&(instance->peer->srcadr), cp);
}
return;
}
if (!instance->pollcnt)
refclock_report(peer, CEVNT_TIMEOUT);
else
instance->pollcnt--;
peer->procptr->polls++;
instance->polled = 1;
}
static void
oncore_receive(
struct recvbuf *rbufp
)
{
size_t i;
u_char *p;
struct peer *peer;
struct instance *instance;
peer = (struct peer *)rbufp->recv_srcclock;
instance = (struct instance *) peer->procptr->unitptr;
p = (u_char *) &rbufp->recv_space;
#if 0
if (debug > 4) {
int i;
printf("ONCORE: >>>");
for(i=0; i<rbufp->recv_length; i++)
printf("%02x ", p[i]);
printf("\n");
printf("ONCORE: >>>");
for(i=0; i<rbufp->recv_length; i++)
printf("%03o ", p[i]);
printf("\n");
}
#endif
i = rbufp->recv_length;
if (rcvbuf+rcvptr+i > &rcvbuf[sizeof rcvbuf])
i = sizeof(rcvbuf) - rcvptr;
memcpy(rcvbuf+rcvptr, p, i);
rcvptr += i;
oncore_consume(instance);
}
static void
oncore_consume(
struct instance *instance
)
{
int i, j, m;
unsigned l;
while (rcvptr >= 7) {
if (rcvbuf[0] != '@' || rcvbuf[1] != '@') {
for (i=1; i < rcvptr-1; i++)
if (rcvbuf[i] == '@' && rcvbuf[i+1] == '@')
break;
if (debug > 4)
printf("ONCORE[%d]: >>> skipping %d chars\n", instance->unit, i);
if (i != rcvptr)
memcpy(rcvbuf, rcvbuf+i, (size_t)(rcvptr-i));
rcvptr -= i;
continue;
}
l = sizeof(oncore_messages)/sizeof(oncore_messages[0]) -1;
for(m=0; m<l; m++)
if (!strncmp(oncore_messages[m].flag, (char *)(rcvbuf+2), (size_t) 2))
break;
if (m == l) {
if (debug > 4)
printf("ONCORE[%d]: >>> Unknown MSG, skipping 4 (%c%c)\n", instance->unit, rcvbuf[2], rcvbuf[3]);
memcpy(rcvbuf, rcvbuf+4, (size_t) 4);
rcvptr -= 4;
continue;
}
l = oncore_messages[m].len;
#if 0
if (debug > 3)
printf("ONCORE[%d]: GOT: %c%c %d of %d entry %d\n", instance->unit, rcvbuf[2], rcvbuf[3], rcvptr, l, m);
#endif
if (rcvptr < l)
return;
if (rcvbuf[l-2] != '\r' || rcvbuf[l-1] != '\n') {
if (debug)
printf("ONCORE[%d]: NO <CR><LF> at end of message\n", instance->unit);
} else {
j = 0;
for (i = 2; i < l-3; i++)
j ^= rcvbuf[i];
if (j == rcvbuf[l-3]) {
if (instance->shmem != NULL) {
instance->shmem[oncore_messages[m].shmem + 2]++;
memcpy(instance->shmem + oncore_messages[m].shmem + 3,
rcvbuf, (size_t) l);
}
oncore_msg_any(instance, rcvbuf, (size_t) (l-3), m);
if (oncore_messages[m].handler)
oncore_messages[m].handler(instance, rcvbuf, (size_t) (l-3));
} else if (debug) {
printf("ONCORE[%d]: Checksum mismatch! calc %o is %o\n", instance->unit, j, rcvbuf[l-3]);
printf("ONCORE[%d]: @@%c%c ", instance->unit, rcvbuf[2], rcvbuf[3]);
for (i=4; i<l; i++)
printf("%03o ", rcvbuf[i]);
printf("\n");
}
}
if (l != rcvptr)
memcpy(rcvbuf, rcvbuf+l, (size_t) (rcvptr-l));
rcvptr -= l;
}
}
static void
oncore_sendmsg(
int fd,
u_char *ptr,
size_t len
)
{
u_char cs = 0;
printf("ONCORE: Send @@%c%c %d\n", ptr[0], ptr[1], (int) len);
write(fd, "@@", (size_t) 2);
write(fd, ptr, len);
while (len--)
cs ^= *ptr++;
write(fd, &cs, (size_t) 1);
write(fd, "\r\n", (size_t) 2);
}
static void
oncore_msg_any(
struct instance *instance,
u_char *buf,
size_t len,
int idx
)
{
int i;
const char *fmt = oncore_messages[idx].fmt;
const char *p;
#ifdef HAVE_GETCLOCK
struct timespec ts;
#endif
struct timeval tv;
if (debug > 3) {
#ifdef HAVE_GETCLOCK
(void) getclock(TIMEOFDAY, &ts);
tv.tv_sec = ts.tv_sec;
tv.tv_usec = ts.tv_nsec / 1000;
#else
GETTIMEOFDAY(&tv, 0);
#endif
printf("ONCORE[%d]: %ld.%06ld\n", instance->unit, (long) tv.tv_sec, (long) tv.tv_usec);
if (!*fmt) {
printf(">>@@%c%c ", buf[2], buf[3]);
for(i=2; i < len && i < 2400 ; i++)
printf("%02x", buf[i]);
printf("\n");
return;
} else {
printf("##");
for (p = fmt; *p; p++) {
putchar(*p);
putchar('_');
}
printf("\n%c%c", buf[2], buf[3]);
i = 4;
for (p = fmt; *p; p++) {
printf("%02x", buf[i++]);
}
printf("\n");
}
}
}
static void
oncore_msg_Cb(
struct instance *instance,
u_char *buf,
size_t len
)
{
int i;
if (instance->shmem == NULL)
return;
if (buf[4] == 5)
i = buf[5];
else if (buf[4] == 4 && buf[5] <= 5)
i = buf[5] + 24;
else if (buf[4] == 4 && buf[5] <= 10)
i = buf[5] + 23;
else
i = 34;
i *= 36;
instance->shmem[instance->shmem_Cb + i + 2]++;
memcpy(instance->shmem + instance->shmem_Cb + i + 3, buf, (size_t) (len + 3));
}
static void
oncore_msg_Cj(
struct instance *instance,
u_char *buf,
size_t len
)
{
memcpy(instance->Cj, buf, len);
instance->timeout = 0;
if (instance->o_state == ONCORE_ID_SENT)
oncore_msg_Cj_id(instance, buf, len);
else if (instance->o_state == ONCORE_INIT)
oncore_msg_Cj_init(instance, buf, len);
}
static void
oncore_msg_Cj_id(
struct instance *instance,
u_char *buf,
size_t len
)
{
char *cp, *cp1, *cp2, Model[21], Msg[160];
int mode;
instance->Cj[294] = '\0';
for (cp=(char *)instance->Cj; cp< (char *) &instance->Cj[294]; ) {
cp1 = strchr(cp, '\r');
if (!cp1)
cp1 = (char *)&instance->Cj[294];
*cp1 = '\0';
record_clock_stats(&(instance->peer->srcadr), cp);
*cp1 = '\r';
cp = cp1+2;
}
instance->version = atoi(&instance->Cj[83]);
instance->revision = atoi(&instance->Cj[111]);
for (cp=&instance->Cj[160]; *cp == ' '; cp++)
;
cp1 = cp;
cp2 = Model;
for (; !isspace((int)*cp) && cp-cp1 < 20; cp++, cp2++)
*cp2 = *cp;
*cp2 = '\0';
cp = 0;
if (!strncmp(Model, "PVT6", (size_t) 4)) {
cp = "PVT6";
instance->model = ONCORE_PVT6;
} else if (Model[0] == 'A') {
cp = "Basic";
instance->model = ONCORE_BASIC;
} else if (Model[0] == 'B' || !strncmp(Model, "T8", (size_t) 2)) {
cp = "VP";
instance->model = ONCORE_VP;
} else if (!strncmp(Model, "P1", (size_t) 2)) {
cp = "M12";
instance->model = ONCORE_M12;
} else if (Model[0] == 'R') {
if (Model[5] == 'N') {
cp = "GT";
instance->model = ONCORE_GT;
} else if ((Model[1] == '3' || Model[1] == '4') && Model[5] == 'G') {
cp = "GT+";
instance->model = ONCORE_GTPLUS;
} else if ((Model[1] == '5' && Model[5] == 'U') || (Model[1] == '1' && Model[5] == 'A')) {
cp = "UT";
instance->model = ONCORE_UT;
} else if (Model[1] == '5' && Model[5] == 'G') {
cp = "UT+";
instance->model = ONCORE_UTPLUS;
} else if (Model[1] == '6' && Model[5] == 'G') {
cp = "SL";
instance->model = ONCORE_SL;
} else {
cp = "Unknown";
instance->model = ONCORE_UNKNOWN;
}
} else {
cp = "Unknown";
instance->model = ONCORE_UNKNOWN;
}
sprintf(Msg, "This looks like an Oncore %s with version %d.%d firmware.", cp, instance->version, instance->revision);
record_clock_stats(&(instance->peer->srcadr), Msg);
if (instance->chan == 0) {
instance->chan = 8;
if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
instance->chan = 6;
else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
instance->chan = 8;
else if (instance->model == ONCORE_M12)
instance->chan = 12;
}
if (instance->traim == -1) {
instance->traim = 0;
if (instance->model == ONCORE_BASIC || instance->model == ONCORE_PVT6)
instance->traim = 0;
else if (instance->model == ONCORE_VP || instance->model == ONCORE_UT || instance->model == ONCORE_UTPLUS)
instance->traim = 1;
else if (instance->model == ONCORE_M12)
instance->traim = 0;
}
sprintf(Msg, "Channels = %d, TRAIM = %s", instance->chan,
((instance->traim < 0) ? "UNKNOWN" : ((instance->traim > 0) ? "ON" : "OFF")));
record_clock_stats(&(instance->peer->srcadr), Msg);
if (instance->model == ONCORE_M12 && instance->version == 1 && instance->revision <= 3) {
instance->shmem_fname = 0;
cp = "*** SHMEM turned off for ONCORE M12 ***";
record_clock_stats(&(instance->peer->srcadr), cp);
}
if (instance->shmem_fname);
oncore_init_shmem(instance);
if (instance->shmem)
cp = "SHMEM is available";
else
cp = "SHMEM is NOT available";
record_clock_stats(&(instance->peer->srcadr), cp);
#ifdef HAVE_PPSAPI
if (instance->assert)
cp = "Timing on Assert.";
else
cp = "Timing on Clear.";
record_clock_stats(&(instance->peer->srcadr), cp);
#endif
mode = instance->init_type;
if (mode == 3 || mode == 4) {
oncore_sendmsg(instance->ttyfd, oncore_cmd_Cf, sizeof(oncore_cmd_Cf));
instance->o_state = ONCORE_RESET_SENT;
cp = "state = ONCORE_RESET_SENT";
record_clock_stats(&(instance->peer->srcadr), cp);
} else {
if (instance->chan == 6)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
else if (instance->chan == 8)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
else if (instance->chan == 12)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
instance->o_state = ONCORE_TEST_SENT;
cp = "state = ONCORE_TEST_SENT";
record_clock_stats(&(instance->peer->srcadr), cp);
instance->timeout = 4;
}
}
static void
oncore_msg_Cj_init(
struct instance *instance,
u_char *buf,
size_t len
)
{
char *cp, Cmd[20], Msg[160];
int mode;
oncore_sendmsg(instance->ttyfd, oncore_cmd_Cg, sizeof(oncore_cmd_Cg));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Bb, sizeof(oncore_cmd_Bb));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ek, sizeof(oncore_cmd_Ek));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Aw, sizeof(oncore_cmd_Aw));
oncore_sendmsg(instance->ttyfd, oncore_cmd_AB, sizeof(oncore_cmd_AB));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Be, sizeof(oncore_cmd_Be));
if (instance->chan == 12)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0));
else {
oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
}
mode = instance->init_type;
if (debug) {
printf("ONCORE[%d]: INIT mode = %d\n", instance->unit, mode);
printf("ONCORE[%d]: chan = %d\n", instance->unit, instance->chan);
}
if (instance->posn_set) {
switch (mode) {
case 0:
break;
case 1:
case 2:
case 3:
case 4:
memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As));
w32_buf(&Cmd[2], (int) instance->ss_lat);
w32_buf(&Cmd[6], (int) instance->ss_long);
w32_buf(&Cmd[10], (int) instance->ss_ht);
Cmd[14] = 0;
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As));
memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au));
w32_buf(&Cmd[2], (int) instance->ss_ht);
Cmd[6] = 0;
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au));
if (instance->chan == 12) {
memcpy(Cmd, oncore_cmd_Ga, sizeof(oncore_cmd_Ga));
w32_buf(&Cmd[2], (int) instance->ss_lat);
w32_buf(&Cmd[6], (int) instance->ss_long);
w32_buf(&Cmd[10], (int) instance->ss_ht);
Cmd[14] = 0;
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ga));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
} else {
memcpy(Cmd, oncore_cmd_Ad, sizeof(oncore_cmd_Ad));
w32_buf(&Cmd[2], (int) instance->ss_lat);
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ad));
memcpy(Cmd, oncore_cmd_Ae, sizeof(oncore_cmd_Ae));
w32_buf(&Cmd[2], (int) instance->ss_long);
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ae));
memcpy(Cmd, oncore_cmd_Af, sizeof(oncore_cmd_Af));
w32_buf(&Cmd[2], (int) instance->ss_ht);
Cmd[6] = 0;
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Af));
oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
}
break;
}
}
switch (mode) {
case 0:
instance->site_survey = ONCORE_SS_DONE;
break;
case 1:
case 3:
instance->site_survey = ONCORE_SS_DONE;
break;
case 2:
case 4:
if (instance->chan == 12) {
instance->site_survey = ONCORE_SS_SW;
sprintf(Msg, "Initiating software 3D site survey (%d samples)", POS_HOLD_AVERAGE);
record_clock_stats(&(instance->peer->srcadr), Msg);
} else {
instance->site_survey = ONCORE_SS_TESTING;
oncore_sendmsg(instance->ttyfd, oncore_cmd_At2, sizeof(oncore_cmd_At2));
}
break;
}
if (mode != 0) {
memcpy(Cmd, oncore_cmd_Az, sizeof(oncore_cmd_Az));
w32_buf(&Cmd[2], instance->delay);
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Az));
if (instance->offset) {
if (instance->model == ONCORE_VP || instance->model == ONCORE_UT ||
instance->model == ONCORE_UTPLUS) {
memcpy(Cmd, oncore_cmd_Ay, sizeof(oncore_cmd_Ay));
w32_buf(&Cmd[2], instance->offset);
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Ay));
} else {
cp = "Can only set PPS OFFSET for VP/UT/UT+, offset ignored";
record_clock_stats(&(instance->peer->srcadr), cp);
instance->offset = 0;
}
}
}
if (instance->chan == 6) {
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba, sizeof(oncore_cmd_Ba));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea0, sizeof(oncore_cmd_Ea0));
oncore_sendmsg(instance->ttyfd, oncore_cmd_En0, sizeof(oncore_cmd_En0));
} else if (instance->chan == 8) {
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ea, sizeof(oncore_cmd_Ea));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ba0, sizeof(oncore_cmd_Ba0));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn0, sizeof(oncore_cmd_Bn0));
} else if (instance->chan == 12)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ha, sizeof(oncore_cmd_Ha));
instance->count = 1;
instance->o_state = ONCORE_ALMANAC;
cp = "state = ONCORE_ALMANAC";
record_clock_stats(&(instance->peer->srcadr), cp);
}
static void
oncore_msg_Cf(
struct instance *instance,
u_char *buf,
size_t len
)
{
const char *cp;
if (instance->o_state == ONCORE_RESET_SENT) {
if (instance->chan == 6)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ca, sizeof(oncore_cmd_Ca));
else if (instance->chan == 8)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Fa, sizeof(oncore_cmd_Fa));
else if (instance->chan == 12)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ia, sizeof(oncore_cmd_Ia));
instance->o_state = ONCORE_TEST_SENT;
cp = "state = ONCORE_TEST_SENT";
record_clock_stats(&(instance->peer->srcadr), cp);
}
}
static void
oncore_msg_CaFaIa(
struct instance *instance,
u_char *buf,
size_t len
)
{
char *cp;
if (instance->o_state == ONCORE_TEST_SENT) {
int antenna;
instance->timeout = 0;
if (debug > 2) {
if (buf[2] == 'I')
printf("ONCORE[%d]: >>@@%ca %x %x %x\n", instance->unit, buf[2], buf[4], buf[5], buf[6]);
else
printf("ONCORE[%d]: >>@@%ca %x %x\n", instance->unit, buf[2], buf[4], buf[5]);
}
antenna = buf[4] & 0xc0;
antenna >>= 6;
buf[4] &= ~0xc0;
if (buf[4] || buf[5] || ((buf[2] == 'I') && buf[6])) {
cp = "ONCORE: Self Test Failed, shutting down driver";
record_clock_stats(&(instance->peer->srcadr), cp);
oncore_shutdown(instance->unit, instance->peer);
return;
}
if (antenna) {
char *cp1, Msg[160];
cp1 = (antenna == 0x1) ? "(Over Current)" :
((antenna == 0x2) ? "(Under Current)" : "(No Voltage)");
cp = "ONCORE: Self Test, NonFatal Antenna Problems ";
strcpy(Msg, cp);
strcat(Msg, cp1);
record_clock_stats(&(instance->peer->srcadr), Msg);
}
oncore_sendmsg(instance->ttyfd, oncore_cmd_Cj, sizeof(oncore_cmd_Cj));
instance->o_state = ONCORE_INIT;
cp = "state = ONCORE_INIT";
record_clock_stats(&(instance->peer->srcadr), cp);
}
}
static void
oncore_msg_BaEaHa(
struct instance *instance,
u_char *buf,
size_t len
)
{
const char *cp;
char Msg[160], Cmd[20];
u_char *vp;
size_t Len;
if (instance->count) {
if (instance->count++ < 5)
return;
instance->count = 0;
}
if (instance->o_state != ONCORE_ALMANAC && instance->o_state != ONCORE_RUN)
return;
Len = len+3;
memcpy(instance->Ea, buf, Len);
if (buf[2] == 'B') {
if (instance->Ea[64]&0x8)
instance->mode = MODE_0D;
else if (instance->Ea[64]&0x10)
instance->mode = MODE_2D;
else if (instance->Ea[64]&0x20)
instance->mode = MODE_3D;
} else if (buf[2] == 'E') {
if (instance->Ea[72]&0x8)
instance->mode = MODE_0D;
else if (instance->Ea[72]&0x10)
instance->mode = MODE_2D;
else if (instance->Ea[72]&0x20)
instance->mode = MODE_3D;
} else if (buf[2] == 'H') {
int bits;
bits = (instance->Ea[129]>>5) & 0x7;
if (bits == 0x4)
instance->mode = MODE_0D;
else if (bits == 0x6)
instance->mode = MODE_2D;
else if (bits == 0x7)
instance->mode = MODE_3D;
}
vp = (u_char) 0;
if (instance->chan == 6) {
instance->rsm.bad_almanac = instance->Ea[64]&0x1;
instance->rsm.bad_fix = instance->Ea[64]&0x52;
vp = &instance->shmem[instance->shmem_Ba];
} else if (instance->chan == 8) {
instance->rsm.bad_almanac = instance->Ea[72]&0x1;
instance->rsm.bad_fix = instance->Ea[72]&0x52;
vp = &instance->shmem[instance->shmem_Ea];
} else if (instance->chan == 12) {
int bits1, bits2;
bits1 = (instance->Ea[129]>>5) & 0x7;
bits2 = instance->Ea[130];
instance->rsm.bad_almanac = (bits2 & 0x80);
instance->rsm.bad_fix = (bits2 & 0x8) || (bits1 == 0x2);
vp = &instance->shmem[instance->shmem_Ha];
#if 0
fprintf(stderr, "ONCORE: DEBUG BITS: (%x %x), (%x %x), %x %x %x %x %x\n",
instance->Ea[129], instance->Ea[130], bits1, bits2, instance->mode == MODE_0D, instance->mode == MODE_2D,
instance->mode == MODE_3D, instance->rsm.bad_almanac, instance->rsm.bad_fix);
#endif
}
if (!instance->have_dH) {
int GPS, MSL;
instance->have_dH++;
if (instance->chan == 12) {
GPS = buf_w32(&instance->Ea[39]);
MSL = buf_w32(&instance->Ea[43]);
} else {
GPS = buf_w32(&instance->Ea[23]);
MSL = buf_w32(&instance->Ea[27]);
}
instance->dH = GPS - MSL;
instance->dH /= 100.;
if (MSL) {
sprintf(Msg, "dH = (GPS - MSL) = %.2fm", instance->dH);
record_clock_stats(&(instance->peer->srcadr), Msg);
}
if (instance->chan != 12 && !instance->saw_At) {
cp = "Not Good, no @@At command, must be a GT/GT+";
record_clock_stats(&(instance->peer->srcadr), cp);
oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
}
}
if (instance->site_survey == ONCORE_SS_TESTING) {
sprintf(Msg, "Initiating software 3D site survey (%d samples)",
POS_HOLD_AVERAGE);
record_clock_stats(&(instance->peer->srcadr), Msg);
instance->site_survey = ONCORE_SS_SW;
instance->ss_lat = instance->ss_long = instance->ss_ht = 0;
oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
}
if (instance->shmem) {
int i;
i = 0;
if (instance->mode == MODE_0D)
i = 1;
else if (instance->mode == MODE_2D)
i = 2;
else if (instance->mode == MODE_3D)
i = 3;
if (i) {
i *= (Len+3);
vp[i + 2]++;
memcpy(&vp[i+3], buf, Len);
}
}
if (instance->o_state == ONCORE_ALMANAC) {
if (instance->rsm.bad_almanac) {
if (debug)
printf("ONCORE: waiting for almanac\n");
return;
} else {
if (instance->traim != 0) {
if (instance->chan == 6)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Bn, sizeof(oncore_cmd_Bn));
else if (instance->chan == 8)
oncore_sendmsg(instance->ttyfd, oncore_cmd_En, sizeof(oncore_cmd_En));
if (instance->traim == -1)
instance->traim_delay = 1;
}
instance->o_state = ONCORE_RUN;
cp = "state = ONCORE_RUN";
record_clock_stats(&(instance->peer->srcadr), cp);
}
}
if (instance->traim_delay) {
if (instance->traim_delay++ > 5) {
instance->traim = 0;
instance->traim_delay = 0;
cp = "ONCORE: Did not detect TRAIM response, TRAIM = OFF";
record_clock_stats(&(instance->peer->srcadr), cp);
}
}
instance->pp->year = buf[6]*256+buf[7];
instance->pp->day = ymd2yd(buf[6]*256+buf[7], buf[4], buf[5]);
instance->pp->hour = buf[8];
instance->pp->minute = buf[9];
instance->pp->second = buf[10];
if ((instance->site_survey == ONCORE_SS_HW) && !(instance->Ea[37] & 0x20)) {
record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
instance->site_survey = ONCORE_SS_DONE;
}
if (!instance->printed && instance->site_survey == ONCORE_SS_DONE) {
instance->printed = 1;
if (instance->saw_At)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Asx, sizeof(oncore_cmd_Asx));
else
oncore_print_As(instance);
oncore_sendmsg(instance->ttyfd, oncore_cmd_Ayx, sizeof(oncore_cmd_Ayx));
oncore_sendmsg(instance->ttyfd, oncore_cmd_Azx, sizeof(oncore_cmd_Azx));
}
if (instance->Bj_day != buf[5]) {
instance->Bj_day = buf[5];
if (instance->chan == 12)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Gj, sizeof(oncore_cmd_Gj));
else {
if ((buf[4] == 6) || (buf[4] == 12))
oncore_sendmsg(instance->ttyfd, oncore_cmd_Bj, sizeof(oncore_cmd_Bj));
}
}
if (instance->shmem && instance->shmem_Posn && (instance->site_survey == ONCORE_SS_DONE)) {
if (instance->pp->second%15 == 3) {
instance->shmem_reset = 1;
if (instance->chan == 12) {
if (instance->shmem_Posn == 2)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd2, sizeof(oncore_cmd_Gd2));
else
oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd0, sizeof(oncore_cmd_Gd0));
} else {
if (instance->saw_At) {
oncore_sendmsg(instance->ttyfd, oncore_cmd_At0, sizeof(oncore_cmd_At0));
if (instance->shmem_Posn == 2)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
} else
oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
}
} else if (instance->shmem_reset || (instance->mode != MODE_0D)) {
instance->shmem_reset = 0;
if (instance->chan == 12)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
else {
if (instance->saw_At) {
if (instance->mode == MODE_2D)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Av0, sizeof(oncore_cmd_Av0));
oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
} else
oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
}
}
}
if (instance->traim == 0)
oncore_get_timestamp(instance, instance->offset, instance->offset);
if (instance->site_survey != ONCORE_SS_SW)
return;
if (instance->rsm.bad_fix)
return;
if (instance->mode != MODE_3D)
return;
instance->ss_lat += buf_w32(&instance->Ea[15]);
instance->ss_long += buf_w32(&instance->Ea[19]);
instance->ss_ht += buf_w32(&instance->Ea[23]);
instance->ss_count++;
if (instance->ss_count != POS_HOLD_AVERAGE)
return;
instance->ss_lat /= POS_HOLD_AVERAGE;
instance->ss_long /= POS_HOLD_AVERAGE;
instance->ss_ht /= POS_HOLD_AVERAGE;
sprintf(Msg, "Surveyed posn: lat %.3f long %.3f ht %.3f",
instance->ss_lat, instance->ss_long, instance->ss_ht);
record_clock_stats(&(instance->peer->srcadr), Msg);
memcpy(Cmd, oncore_cmd_As, sizeof(oncore_cmd_As));
w32_buf(&Cmd[2], (int) instance->ss_lat);
w32_buf(&Cmd[6], (int) instance->ss_long);
w32_buf(&Cmd[10], (int) instance->ss_ht);
Cmd[14] = 0;
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_As));
memcpy(Cmd, oncore_cmd_Au, sizeof(oncore_cmd_Au));
w32_buf(&Cmd[2], (int) instance->ss_ht);
Cmd[6] = 0;
oncore_sendmsg(instance->ttyfd, Cmd, sizeof(oncore_cmd_Au));
if (instance->chan == 12)
oncore_sendmsg(instance->ttyfd, oncore_cmd_Gd1, sizeof(oncore_cmd_Gd1));
else {
if (instance->saw_At)
oncore_sendmsg(instance->ttyfd, oncore_cmd_At1, sizeof(oncore_cmd_At1));
else
oncore_sendmsg(instance->ttyfd, oncore_cmd_Av1, sizeof(oncore_cmd_Av1));
}
record_clock_stats(&(instance->peer->srcadr), "Now in 0D mode");
instance->site_survey = ONCORE_SS_DONE;
}
static void
oncore_msg_BnEn(
struct instance *instance,
u_char *buf,
size_t len
)
{
long dt1, dt2;
char *cp;
if (instance->o_state != ONCORE_RUN)
return;
if (instance->traim_delay) {
instance->traim = 1;
instance->traim_delay = 0;
cp = "ONCORE: Detected TRAIM, TRAIM = ON";
record_clock_stats(&(instance->peer->srcadr), cp);
}
memcpy(instance->En, buf, len);
if (instance->En[21])
return;
dt1 = instance->saw_tooth + instance->offset;
instance->saw_tooth = (s_char) instance->En[25];
dt2 = instance->saw_tooth + instance->offset;
oncore_get_timestamp(instance, dt1, dt2);
}
static void
oncore_get_timestamp(
struct instance *instance,
long dt1,
long dt2
)
{
int Rsm;
u_long i, j;
l_fp ts, ts_tmp;
double dmy;
#ifdef HAVE_STRUCT_TIMESPEC
struct timespec *tsp = 0;
#else
struct timeval *tsp = 0;
#endif
#ifdef HAVE_PPSAPI
int current_mode;
pps_params_t current_params;
struct timespec timeout;
pps_info_t pps_i;
#else
#ifdef HAVE_CIOGETEV
struct ppsclockev ev;
int r = CIOGETEV;
#endif
#ifdef HAVE_TIOCGPPSEV
struct ppsclockev ev;
int r = TIOCGPPSEV;
#endif
#if TIOCDCDTIMESTAMP
struct timeval tv;
#endif
#endif
if ((instance->site_survey == ONCORE_SS_DONE) && (instance->mode != MODE_0D))
return;
if (instance->rsm.bad_almanac)
return;
#ifdef HAVE_PPSAPI
j = instance->ev_serial;
timeout.tv_sec = 0;
timeout.tv_nsec = 0;
if (time_pps_fetch(instance->pps_h, PPS_TSFMT_TSPEC, &pps_i,
&timeout) < 0) {
printf("ONCORE: time_pps_fetch failed\n");
return;
}
if (instance->assert) {
tsp = &pps_i.assert_timestamp;
if (debug > 2) {
i = (u_long) pps_i.assert_sequence;
#ifdef HAVE_STRUCT_TIMESPEC
printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
instance->unit, i, j,
(long)tsp->tv_sec, (long)tsp->tv_nsec);
#else
printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
instance->unit, i, j,
(long)tsp->tv_sec, (long)tsp->tv_usec);
#endif
}
if (pps_i.assert_sequence == j) {
printf("ONCORE: oncore_get_timestamp, error serial pps\n");
return;
}
instance->ev_serial = pps_i.assert_sequence;
} else {
tsp = &pps_i.clear_timestamp;
if (debug > 2) {
i = (u_long) pps_i.clear_sequence;
#ifdef HAVE_STRUCT_TIMESPEC
printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%09ld\n",
instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_nsec);
#else
printf("ONCORE[%d]: serial/j (%lu, %lu) %ld.%06ld\n",
instance->unit, i, j, (long)tsp->tv_sec, (long)tsp->tv_usec);
#endif
}
if (pps_i.clear_sequence == j) {
printf("ONCORE: oncore_get_timestamp, error serial pps\n");
return;
}
instance->ev_serial = pps_i.clear_sequence;
}
dmy = tsp->tv_nsec;
dmy /= 1e9;
ts.l_uf = dmy * 4294967296.0;
ts.l_ui = tsp->tv_sec;
#if 0
alternate code for previous 4 lines is
dmy = 1.0e-9*tsp->tv_nsec;
DTOLFP(dmy, &ts);
dmy = tsp->tv_sec;
DTOLFP(dmy, &ts_tmp);
L_ADD(&ts, &ts_tmp);
or more simply
dmy = 1.0e-9*tsp->tv_nsec;
DTOLFP(dmy, &ts);
ts.l_ui = tsp->tv_sec;
#endif
#else
# if defined(HAVE_TIOCGPPSEV) || defined(HAVE_CIOGETEV)
j = instance->ev_serial;
if (ioctl(instance->ppsfd, r, (caddr_t) &ev) < 0) {
perror("ONCORE: IOCTL:");
return;
}
tsp = &ev.tv;
if (debug > 2)
#ifdef HAVE_STRUCT_TIMESPEC
printf("ONCORE: serial/j (%d, %d) %ld.%09ld\n",
ev.serial, j, tsp->tv_sec, tsp->tv_nsec);
#else
printf("ONCORE: serial/j (%d, %d) %ld.%06ld\n",
ev.serial, j, tsp->tv_sec, tsp->tv_usec);
#endif
if (ev.serial == j) {
printf("ONCORE: oncore_get_timestamp, error serial pps\n");
return;
}
instance->ev_serial = ev.serial;
TVTOTS(tsp, &ts);
# else
# if defined(TIOCDCDTIMESTAMP)
if(ioctl(instance->ppsfd, TIOCDCDTIMESTAMP, &tv) < 0) {
perror("ONCORE: ioctl(TIOCDCDTIMESTAMP)");
return;
}
tsp = &tv;
TVTOTS(tsp, &ts);
# else
#error "Cannot compile -- no PPS mechanism configured!"
# endif
# endif
#endif
#ifdef HAVE_PPSAPI
if (instance->assert)
instance->pps_p.assert_offset.tv_nsec = -dt2;
else
instance->pps_p.clear_offset.tv_nsec = -dt2;
if (time_pps_getcap(instance->pps_h, ¤t_mode) < 0) {
msyslog(LOG_ERR,
"refclock_ioctl: time_pps_getcap failed: %m");
return;
}
if (time_pps_getparams(instance->pps_h, ¤t_params) < 0) {
msyslog(LOG_ERR,
"refclock_ioctl: time_pps_getparams failed: %m");
return;
}
current_params.mode |= instance->pps_p.mode;
current_params.mode &= current_mode;
current_params.assert_offset.tv_sec = 0;
current_params.assert_offset.tv_nsec = -dt2;
current_params.clear_offset.tv_sec = 0;
current_params.clear_offset.tv_nsec = -dt2;
if (time_pps_setparams(instance->pps_h, ¤t_params))
perror("time_pps_setparams");
#else
dmy = -1.0e-9*dt1;
DTOLFP(dmy, &ts_tmp);
L_ADD(&ts, &ts_tmp);
#endif
ts.l_ui += JAN_1970;
instance->pp->lastrec = ts;
instance->pp->msec = 0;
ts_tmp = ts;
ts_tmp.l_ui = 0;
LFPTOD(&ts_tmp, dmy);
j = 1.0e9*dmy;
Rsm = 0;
if (instance->chan == 6)
Rsm = instance->Ea[64];
else if (instance->chan == 8)
Rsm = instance->Ea[72];
else if (instance->chan == 12)
Rsm = ((instance->Ea[129]<<8) | instance->Ea[130]);
if (instance->chan == 6 || instance->chan == 8) {
sprintf(instance->pp->a_lastcode,
"%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d traim %d sigma %d neg-sawtooth %3d sat %d%d%d%d%d%d%d%d",
ts.l_ui, j,
instance->pp->year, instance->pp->day,
instance->pp->hour, instance->pp->minute, instance->pp->second,
(long) tsp->tv_sec % 60,
Rsm, 0.1*(256*instance->Ea[35]+instance->Ea[36]),
instance->Ea[38], instance->Ea[39], instance->En[21],
instance->En[23]*256+instance->En[24], (s_char) instance->En[25],
instance->Ea[41], instance->Ea[45], instance->Ea[49], instance->Ea[53],
instance->Ea[57], instance->Ea[61], instance->Ea[65], instance->Ea[69]
);
} else if (instance->chan == 12) {
sprintf(instance->pp->a_lastcode,
"%u.%09lu %d %d %2d %2d %2d %2ld rstat %02x dop %4.1f nsat %2d,%d sat %d%d%d%d%d%d%d%d%d%d%d%d",
ts.l_ui, j,
instance->pp->year, instance->pp->day,
instance->pp->hour, instance->pp->minute, instance->pp->second,
(long) tsp->tv_sec % 60,
Rsm, 0.1*(256*instance->Ea[53]+instance->Ea[54]),
instance->Ea[55], instance->Ea[56],
instance->Ea[58], instance->Ea[64], instance->Ea[70], instance->Ea[76],
instance->Ea[82], instance->Ea[88], instance->Ea[94], instance->Ea[100],
instance->Ea[106], instance->Ea[112], instance->Ea[118], instance->Ea[124]
);
}
if (debug > 2) {
int n;
n = strlen(instance->pp->a_lastcode);
printf("ONCORE[%d]: len = %d %s\n", instance->unit, n, instance->pp->a_lastcode);
}
if (!refclock_process(instance->pp)) {
refclock_report(instance->peer, CEVNT_BADTIME);
return;
}
record_clock_stats(&(instance->peer->srcadr), instance->pp->a_lastcode);
instance->pollcnt = 2;
if (instance->polled) {
instance->polled = 0;
refclock_receive(instance->peer);
}
}
static void
oncore_msg_At(
struct instance *instance,
u_char *buf,
size_t len
)
{
instance->saw_At = 1;
if (instance->site_survey == ONCORE_SS_TESTING) {
if (buf[4] == 2) {
record_clock_stats(&(instance->peer->srcadr),
"Initiating hardware 3D site survey");
instance->site_survey = ONCORE_SS_HW;
}
}
}
static void
oncore_msg_Bj(
struct instance *instance,
u_char *buf,
size_t len
)
{
const char *cp;
switch(buf[4]) {
case 1:
instance->peer->leap = LEAP_ADDSECOND;
cp = "Set peer.leap to LEAP_ADDSECOND";
break;
case 2:
instance->peer->leap = LEAP_DELSECOND;
cp = "Set peer.leap to LEAP_DELSECOND";
break;
case 0:
default:
instance->peer->leap = LEAP_NOWARNING;
cp = "Set peer.leap to LEAP_NOWARNING";
break;
}
record_clock_stats(&(instance->peer->srcadr), cp);
}
static void
oncore_msg_Gj(
struct instance *instance,
u_char *buf,
size_t len
)
{
int dt;
char Msg[160], *cp;
static char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly",
"Aug", "Sep", "Oct", "Nov", "Dec" };
dt = buf[5] - buf[4];
#if 1
sprintf(Msg, "ONCORE[%d]: Leap Sec Msg: %d %d %d %d %d %d %d %d %d %d",
instance->unit,
buf[4], buf[5], 256*buf[6]+buf[7], buf[8], buf[9], buf[10],
(buf[14]+256*(buf[13]+256*(buf[12]+256*buf[11]))),
buf[15], buf[16], buf[17]);
record_clock_stats(&(instance->peer->srcadr), Msg);
#endif
if (dt) {
sprintf(Msg, "ONCORE[%d]: Leap second (%d) scheduled for %d%s%d at %d:%d:%d",
instance->unit,
dt, buf[9], Month[buf[8]], 256*buf[6]+buf[7],
buf[15], buf[16], buf[17]);
record_clock_stats(&(instance->peer->srcadr), Msg);
}
instance->peer->leap = LEAP_NOWARNING;
cp = "Set peer.leap to LEAP_NOWARNING";
if (buf[6] == instance->Ea[6] && buf[7] == instance->Ea[7] &&
buf[8] == instance->Ea[4]) {
if (dt) {
if (dt < 0) {
instance->peer->leap = LEAP_DELSECOND;
cp = "Set peer.leap to LEAP_DELSECOND";
} else {
instance->peer->leap = LEAP_ADDSECOND;
cp = "Set peer.leap to LEAP_ADDSECOND";
}
}
}
record_clock_stats(&(instance->peer->srcadr), cp);
}
static void
oncore_msg_As(
struct instance *instance,
u_char *buf,
size_t len
)
{
if (!instance->printed || instance->As)
return;
instance->As = 1;
instance->ss_lat = buf_w32(&buf[4]);
instance->ss_long = buf_w32(&buf[8]);
instance->ss_ht = buf_w32(&buf[12]);
oncore_print_As(instance);
}
static void
oncore_print_As(
struct instance *instance
)
{
char Msg[120], ew, ns;
double xd, xm, xs, yd, ym, ys, hm, hft;
int idx, idy, is, imx, imy;
long lat, lon;
record_clock_stats(&(instance->peer->srcadr), "Posn:");
ew = 'E';
lon = instance->ss_long;
if (lon < 0) {
ew = 'W';
lon = -lon;
}
ns = 'N';
lat = instance->ss_lat;
if (lat < 0) {
ns = 'S';
lat = -lat;
}
hm = instance->ss_ht/100.;
hft= hm/0.3048;
xd = lat/3600000.;
yd = lon/3600000.;
sprintf(Msg, "Lat = %c %11.7fdeg, Long = %c %11.7fdeg, Alt = %5.2fm (%5.2fft) GPS", ns, xd, ew, yd, hm, hft);
record_clock_stats(&(instance->peer->srcadr), Msg);
idx = xd;
idy = yd;
imx = lat%3600000;
imy = lon%3600000;
xm = imx/60000.;
ym = imy/60000.;
sprintf(Msg, "Lat = %c %3ddeg %7.4fm, Long = %c %3ddeg %8.5fm, Alt = %7.2fm (%7.2fft) GPS", ns, idx, xm, ew, idy, ym, hm, hft);
record_clock_stats(&(instance->peer->srcadr), Msg);
imx = xm;
imy = ym;
is = lat%60000;
xs = is/1000.;
is = lon%60000;
ys = is/1000.;
sprintf(Msg, "Lat = %c %3ddeg %2dm %5.2fs, Long = %c %3ddeg %2dm %5.2fs, Alt = %7.2fm (%7.2fft) GPS", ns, idx, imx, xs, ew, idy, imy, ys, hm, hft);
record_clock_stats(&(instance->peer->srcadr), Msg);
}
static void
oncore_msg_Ay(
struct instance *instance,
u_char *buf,
size_t len
)
{
char Msg[120];
if (!instance->printed || instance->Ay)
return;
instance->Ay = 1;
instance->offset = buf_w32(&buf[4]);
sprintf(Msg, "PPS Offset is set to %ld ns", instance->offset);
record_clock_stats(&(instance->peer->srcadr), Msg);
}
static void
oncore_msg_Az(
struct instance *instance,
u_char *buf,
size_t len
)
{
char Msg[120];
if (!instance->printed || instance->Az)
return;
instance->Az = 1;
instance->delay = buf_w32(&buf[4]);
sprintf(Msg, "Cable delay is set to %ld ns", instance->delay);
record_clock_stats(&(instance->peer->srcadr), Msg);
}
static void
oncore_msg_Sz(
struct instance *instance,
u_char *buf,
size_t len
)
{
const char *cp;
cp = "Oncore: System Failure at Power On";
if (instance && instance->peer) {
record_clock_stats(&(instance->peer->srcadr), cp);
oncore_shutdown(instance->unit, instance->peer);
}
}
#else
int refclock_oncore_bs;
#endif