/*
* /src/NTP/REPOSITORY/ntp4-dev/libparse/clk_rawdcf.c,v 4.18 2006/06/22 18:40:01 kardel RELEASE_20060622_A
*
* clk_rawdcf.c,v 4.18 2006/06/22 18:40:01 kardel RELEASE_20060622_A
*
* Raw DCF77 pulse clock support
*
* Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
* Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
static u_long
ext_bf(
unsigned char *buf,
int idx,
const unsigned char *zero
)
{
u_long sum = 0;
int i, first;
first = rawdcfcode[idx].offset;
for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--)
{
sum <<= 1;
sum |= (buf[i] != zero[i]);
}
return sum;
}
static unsigned
pcheck(
unsigned char *buf,
int idx,
const unsigned char *zero
)
{
int i,last;
unsigned psum = 1;
last = partab[idx+1].offset;
for (i = partab[idx].offset; i < last; i++)
psum ^= (buf[i] != zero[i]);
return psum;
}
static int/*BOOL*/
zeller_expand(
clocktime_t *clock_time,
unsigned int wd
)
{
unsigned int y = (unsigned int)clock_time->year;
unsigned int m = (unsigned int)clock_time->month - 1u;
unsigned int d = (unsigned int)clock_time->day - 1u;
unsigned int c;
/* Get weekday of date in 1st century by a variation on Zeller's
* congruence. All operands are non-negative, and the month
* formula is adjusted to use a divider of 32, so we can do a
* shift instead of a 'true' division:
*/
if ((m += 10u) >= 12u) /* shift base to 0000-03-01 */
m -= 12u;
else if (--y >= 100u)
y += 100;
d += y + (y >> 2) + 2u; /* year-related share */
d += (m * 83u + 16u) >> 5; /* month-related share */
/* The next step combines the exact division by modular inverse
* with the (mod 7) step in such way that no true division and
* only one multiplication is needed. The multiplier is
* M <- ceil((3*8)/7 * 2**29)
* and combines multiplication by invmod(5, 7) -> 3 and modulus
* by 7 transformation to (mod 8) in one step.
* Note that 252 == 0 (mod 7) and that 'd' is less than 185,
* so the number to invert and reduce is strictly positive. In
* the end, 'c' is number of centuries since start of a great
* cycle and must be in [0..3] or we had bad input.
*/
c = (((252u + wd - d) * 0x6db6db6eU) >> 29) & 7u;
if (c >= 4)
return FALSE;
/* undo calendar base shift now */
if ((m > 9u) && (++y >= 100u)) {
y -= 100u;
c = (c + 1u) & 3u;
}
/* combine year with centuries & map to [1970..2369] */
y += (c * 100u);
clock_time->year = (int)y + ((y < 370u) ? 2000 : 1600);
return TRUE;
}
if (size < 57)
{
#ifndef PARSEKERNEL
msyslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits", size);
#endif
return CVT_FAIL|CVT_BADFMT;
}
for (i = 0; i < size; i++)
{
if ((*s != *b) && (*s != *c))
{
/*
* we only have two types of bytes (ones and zeros)
*/
#ifndef PARSEKERNEL
msyslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion");
#endif
return CVT_FAIL|CVT_BADFMT;
}
if (*b) b++;
if (*c) c++;
s++;
}
case DCF_Z_MED:
clock_time->flags |= PARSEB_DST;
clock_time->utcoffset = -2*60*60;
break;
default:
parseprintf(DD_RAWDCF,("parse: convert_rawdcf: BAD TIME ZONE\n"));
return CVT_FAIL|CVT_BADFMT;
}
if (ext_bf(buffer, DCF_A1, dcfprm->zerobits))
clock_time->flags |= PARSEB_ANNOUNCE;
if (ext_bf(buffer, DCF_A2, dcfprm->zerobits))
clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */
if (ext_bf(buffer, DCF_R, dcfprm->zerobits))
clock_time->flags |= PARSEB_CALLBIT;
parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %02d:%02d, %02d.%02d.%02d, flags 0x%lx\n",
(int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year,
(u_long)clock_time->flags));
return CVT_OK;
}
else
{
/*
* bad format - not for us
*/
#ifndef PARSEKERNEL
msyslog(LOG_ERR, "parse: convert_rawdcf: start bit / parity check FAILED for \"%.*s\"", size, buffer);
#endif
return CVT_FAIL|CVT_BADFMT;
}
}
/*
* parse_cvt_fnc_t cvt_rawdcf
* raw dcf input routine - needs to fix up 50 baud
* characters for 1/0 decision
*/
static u_long
cvt_rawdcf(
unsigned char *buffer,
int size,
struct format *param,
clocktime_t *clock_time,
void *local
)
{
last_tcode_t *t = (last_tcode_t *)local;
unsigned char *s = (unsigned char *)buffer;
unsigned char *e = s + size;
const unsigned char *b = dcfparameter.onebits;
const unsigned char *c = dcfparameter.zerobits;
u_long rtc = CVT_NONE;
unsigned int i, lowmax, highmax, cutoff, span;
#define BITS 9
unsigned char histbuf[BITS];
/*
* the input buffer contains characters with runs of consecutive
* bits set. These set bits are an indication of the DCF77 pulse
* length. We assume that we receive the pulse at 50 Baud. Thus
* a 100ms pulse would generate a 4 bit train (20ms per bit and
* start bit)
* a 200ms pulse would create all zeroes (and probably a frame error)
*/
for (i = 0; i < BITS; i++)
{
histbuf[i] = 0;
}
cutoff = 0;
lowmax = 0;
while (s < e)
{
unsigned int ch = *s ^ 0xFF;
/*
* these lines are left as an excercise to the reader 8-)
*/
if (!((ch+1) & ch) || !*s)
{
/*
* parse_pps_fnc_t pps_rawdcf
*
* currently a very stupid version - should be extended to decode
* also ones and zeros (which is easy)
*/
/*ARGSUSED*/
static u_long
pps_rawdcf(
parse_t *parseio,
int status,
timestamp_t *ptime
)
{
if (!status) /* negative edge for simpler wiring (Rx->DCD) */
{
parseio->parse_dtime.parse_ptime = *ptime;
parseio->parse_dtime.parse_state |= PARSEB_PPS|PARSEB_S_PPS;
}
return CVT_NONE;
}
static long
calc_usecdiff(
timestamp_t *ref,
timestamp_t *base,
long offset
)
{
struct timeval delta;
long delta_usec = 0;
static u_long
snt_rawdcf(
parse_t *parseio,
timestamp_t *ptime
)
{
/*
* only synthesize if all of following conditions are met:
* - CVT_OK parse_status (we have a time stamp base)
* - ABS(ptime - tminute - (parse_index - 1) sec) < 500ms (spaced by 1 sec +- 500ms)
* - minute marker is available (confirms minute raster as base)
*/
last_tcode_t *t = (last_tcode_t *)parseio->parse_pdata;
long delta_usec = -1;