📄 refclock_oncore.c
字号:
/* OK, we now create the NEW SHMEM. */ if ((instance->shmemfd = open(instance->shmem_fname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) { perror(instance->shmem_fname); return; } /* see how big it needs to be */ n = 1; for (mp=oncore_messages; mp->flag[0]; mp++) { mp->shmem = n; /* Allocate space for multiplexed almanac, and 0D/2D/3D @@Ea records */ 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); } shmem_length = n + 2; fprintf(stderr, "ONCORE: SHMEM length: %ld bytes\n", (long) shmem_length); buf = malloc(shmem_length); if (buf == NULL) { perror("malloc"); close(instance->shmemfd); return; } memset(buf, 0, shmem_length); /* next build the new SHMEM buffer in memory */ for (mp=oncore_messages; mp->flag[0]; mp++) { l = mp->shmem; buf[l + 0] = mp->len >> 8; buf[l + 1] = mp->len & 0xff; buf[l + 2] = 0; buf[l + 3] = '@'; buf[l + 4] = '@'; buf[l + 5] = mp->flag[0]; buf[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++) { buf[l + i * (mp->len+3) + 0] = mp->len >> 8; buf[l + i * (mp->len+3) + 1] = mp->len & 0xff; buf[l + i * (mp->len+3) + 2] = 0; buf[l + i * (mp->len+3) + 3] = '@'; buf[l + i * (mp->len+3) + 4] = '@'; buf[l + i * (mp->len+3) + 5] = mp->flag[0]; buf[l + i * (mp->len+3) + 6] = mp->flag[1]; } } } /* we now walk thru the two buffers (shmem_old and buf, soon to become shmem) * copying the data in shmem_old to buf. When we are done we write it out * and free both buffers. * If the structures change (an addition or deletion) I will stop copying. * The two will be the same unless we add/subtract from the oncore_messages list * so this should work most of the time, and takes a lot less code than doing it right. */ if (shmem_old) { for (cp=buf+4, cp1=shmem_old+4; (n = 256*(*(cp-3)) + *(cp-2)); cp+=(n+3), cp1+=(n+3)) { n1 = 256*(*(cp1-3)) + *(cp1-2); if (n1 != n || strncmp(cp, cp1, 4)) break; memcpy(cp, cp1, (size_t) n); } free(shmem_old); } i = write(instance->shmemfd, buf, shmem_length); free(buf); if (i != shmem_length) { perror(instance->shmem_fname); close(instance->shmemfd); return; } instance->shmem = (u_char *) mmap(0, shmem_length, PROT_READ | PROT_WRITE,#ifdef MAP_HASSEMAPHORE MAP_HASSEMAPHORE |#endif MAP_SHARED, instance->shmemfd, (off_t)0); if (instance->shmem == (u_char *)MAP_FAILED) { instance->shmem = 0; close(instance->shmemfd); return; } sprintf(Msg, "SHMEM (size = %ld) is CONFIGURED and available as %s", (long) shmem_length, instance->shmem_fname); record_clock_stats(&(instance->peer->srcadr), Msg);}#endif /* ONCORE_SHMEM_STATUS *//* * Read Input file if it exists. */static voidoncore_read_config( struct instance *instance ){/* * First we try to open the configuration file * /etc/oncoreN * where N is the unit number viz 127.127.30.N. * If we don't find it we try * /etc/ntp.oncore.N * and then * /etc/ntp.oncore * * If we don't find any then we don't have the cable delay or PPS offset * and we choose MODE (4) below. * * Five Choices for MODE * (0) ONCORE is preinitialized, don't do anything to change it. * nb, DON'T set 0D mode, DON'T set Delay, position... * (1) NO RESET, Read Position, delays from data file, lock it in, go to 0D mode. * (2) NO RESET, Read Delays from data file, do SITE SURVEY to get position, * lock this in, go to 0D mode. * (3) HARD RESET, Read Position, delays from data file, lock it in, go to 0D mode. * (4) HARD RESET, Read Delays from data file, do SITE SURVEY to get position, * lock this in, go to 0D mode. * NB. If a POSITION is specified in the config file with mode=(2,4) [SITE SURVEY] * then this position is set as the INITIAL position of the ONCORE. * This can reduce the time to first fix. * ------------------------------------------------------------------------------- * Note that an Oncore UT without a battery backup retains NO information if it is * power cycled, with a Battery Backup it remembers the almanac, etc. * For an Oncore VP, there is an eeprom that will contain this data, along with the * option of Battery Backup. * So a UT without Battery Backup is equivalent to doing a HARD RESET on each * power cycle, since there is nowhere to store the data. * ------------------------------------------------------------------------------- * * If we open one or the other of the files, we read it looking for * MODE, LAT, LON, (HT, HTGPS, HTMSL), DELAY, OFFSET, ASSERT, CLEAR, HARDPPS, * STATUS, POSN3D, POSN2D, CHAN, TRAIM * then initialize using method MODE. For Mode = (1,3) all of (LAT, LON, HT) must * be present or mode reverts to (2,4). * * Read input file. * * # is comment to end of line * = allowed between 1st and 2nd fields. * * Expect to see one line with 'MODE' as first field, followed by an integer * in the range 0-4 (default = 4). * * Expect to see two lines with 'LONG', 'LAT' followed by 1-3 fields. * All numbers are floating point. * DDD.ddd * DDD MMM.mmm * DDD MMM SSS.sss * * Expect to see one line with 'HT' as first field, * followed by 1-2 fields. First is a number, the second is 'FT' or 'M' * for feet or meters. HT is the height above the GPS ellipsoid. * If the receiver reports height in both GPS and MSL, then we will report * the difference GPS-MSL on the clockstats file. * * There is an optional line, starting with DELAY, followed * by 1 or two fields. The first is a number (a time) the second is * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. * DELAY is cable delay, typically a few tens of ns. * * There is an optional line, starting with OFFSET, followed * by 1 or two fields. The first is a number (a time) the second is * 'MS', 'US' or 'NS' for miliseconds, microseconds or nanoseconds. * OFFSET is the offset of the PPS pulse from 0. (only fully implemented * with the PPSAPI, we need to be able to tell the Kernel about this * offset if the Kernel PLL is in use, but can only do this presently * when using the PPSAPI interface. If not using the Kernel PLL, * then there is no problem. * * There is an optional line, with either ASSERT or CLEAR on it, which * determine which transition of the PPS signal is used for timing by the * PPSAPI. If neither is present, then ASSERT is assumed. * ASSERT/CLEAR can also be set with FLAG2 of the ntp.conf input. * For Flag2, ASSERT=0, and hence is default. * * There is an optional line, with HARDPPS on it. Including this line causes * the PPS signal to control the kernel PLL. * HARDPPS can also be set with FLAG3 of the ntp.conf input. * For Flag3, 0 is disabled, and the default. * * There are three options that have to do with using the shared memory option. * First, to enable the option there must be a SHMEM line with a file name. * The file name is the file associated with the shared memory. * * In shared memory, there is one 'record' for each returned variable. * For the @@Ea data there are three 'records' containing position data. * There will always be data in the record corresponding to the '0D' @@Ea record, * and the user has a choice of filling the '3D' record by specifying POSN3D, * or the '2D' record by specifying POSN2D. In either case the '2D' or '3D' * record is filled once every 15s. * * Two additional variables that can be set are CHAN and TRAIM. These should be * set correctly by the code examining the @@Cj record, but we bring them out here * to allow the user to override either the # of channels, or the existence of TRAIM. * CHAN expects to be followed by in integer: 6, 8, or 12. TRAIM expects to be * followed by YES or NO. * * There is an optional line with MASK on it followed by one integer field in the * range 0 to 89. This sets the satellite mask angle and will determine the minimum * elevation angle for satellites to be tracked by the receiver. The default value * is 10 deg for the VP and 0 deg for all other receivers. * * So acceptable input would be * # these are my coordinates (RWC) * LON -106 34.610 * LAT 35 08.999 * HT 1589 # could equally well say HT 5215 FT * DELAY 60 ns */ FILE *fd; char *cp, *cc, *ca, line[100], units[2], device[20], Msg[160], **cpp; char *dirs[] = { "/etc/ntp", "/etc", 0 }; int i, sign, lat_flg, long_flg, ht_flg, mode, mask; double f1, f2, f3; fd = NULL; /* just to shutup gcc complaint */ for (cpp=dirs; *cpp; cpp++) { cp = *cpp; sprintf(device, "%s/ntp.oncore.%d", cp, instance->unit); /* try "ntp.oncore.0 */ if ((fd=fopen(device, "r"))) break; sprintf(device, "%s/ntp.oncore%d", cp, instance->unit); /* try "ntp.oncore0" */ if ((fd=fopen(device, "r"))) break; sprintf(device, "%s/ntp.oncore", cp); /* and finally "ntp.oncore" */ if ((fd=fopen(device, "r"))) break; } if (!fd) { /* no inputfile, default to the works ... */ instance->init_type = 4; return; } mode = mask = 0; lat_flg = long_flg = ht_flg = 0; while (fgets(line, 100, fd)) { /* Remove comments */ if ((cp = strchr(line, '#'))) *cp = '\0'; /* Remove trailing space */ for (i = strlen(line); i > 0 && isascii((int)line[i - 1]) && isspace((int)line[i - 1]); ) line[--i] = '\0'; /* Remove leading space */ for (cc = line; *cc && isascii((int)*cc) && isspace((int)*cc); cc++) continue; /* Stop if nothing left */ if (!*cc) continue; /* Uppercase the command and find the arg */ for (ca = cc; *ca; ca++) { if (isascii((int)*ca)) { if (islower((int)*ca)) { *ca = toupper(*ca); } else if (isspace((int)*ca) || (*ca == '=')) break; } } /* Remove space (and possible =) leading the arg */ 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; } /* Uppercase argument as well */ 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)); /*miliseconds*/ 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)); /*miliseconds*/ 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; /* cm */ 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; /* delay in ns */ } 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; /* offset in ns */ } 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, "HARDPPS", (size_t) 7)) { instance->hardpps = 1; } 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_in = i; } else if (!strncmp(cc, "TRAIM", (size_t) 5)) { instance->traim_in = 1; /* so TRAIM alone is YES */ if (!strcmp(ca, "NO") || !strcmp(ca, "OFF")) /* Yes/No, On/Off */ instance->traim_in = 0; } else if (!strncmp(cc, "MASK", (size_t) 4)) { sscanf(ca, "%d", &mask); if (mask > -1 && mask < 90) instance->Ag = mask; /* Satellite mask angle */ } } fclose(fd); /* * OK, have read all of data file, and extracted the good stuff. * If lat/long/ht specified they ALL must be specified for mode = (1,3). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -