📄 refclock_neoclock4x.c
字号:
neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2); neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2);#if defined(NTP_PRE_420) pp->msec *= 10; /* convert 1/100s from neoclock to real miliseconds */#else pp->nsec = dsec * 10000; /* convert 1/100s from neoclock to nanoseconds */#endif memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3); up->radiosignal[3] = 0; memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6); up->serial[6] = 0; up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS]; neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2); neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2); /* Validate received values at least enough to prevent internal array-bounds problems, etc. */ if((pp->hour < 0) || (pp->hour > 23) || (pp->minute < 0) || (pp->minute > 59) || (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ || (day < 1) || (day > 31) || (month < 1) || (month > 12) || (pp->year < 0) || (pp->year > 99)) { /* Data out of range. */ NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s", up->unit, pp->a_lastcode); refclock_report(peer, CEVNT_BADDATE); return; } /* Year-2000 check not needed anymore. Same problem * will arise at 2099 but what should we do...? * * wrap 2-digit date into 4-digit * * if(pp->year < YEAR_PIVOT) * { * pp->year += 100; * } */ pp->year += 2000; /* adjust NeoClock4X local time to UTC */ calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second); calc_utc -= 3600; /* adjust NeoClock4X daylight saving time if needed */ if('S' == up->dststatus) calc_utc -= 3600; neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second); /* some preparations */ pp->day = ymd2yd(pp->year, month, day); pp->leap = 0; if(pp->sloppyclockflag & CLK_FLAG4) { msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03d", up->unit, pp->year, month, day, pp->hour, pp->minute, pp->second,#if defined(NTP_PRE_420) pp->msec#else pp->nsec/1000#endif ); } up->utc_year = pp->year; up->utc_month = month; up->utc_day = day; up->utc_hour = pp->hour; up->utc_minute = pp->minute; up->utc_second = pp->second;#if defined(NTP_PRE_420) up->utc_msec = pp->msec;#else up->utc_msec = pp->nsec/1000;#endif if(!refclock_process(pp)) { NLOG(NLOG_CLOCKEVENT) msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit); refclock_report(peer, CEVNT_FAULT); return; } refclock_receive(peer); /* report good status */ refclock_report(peer, CEVNT_NOMINAL); record_clock_stats(&peer->srcadr, pp->a_lastcode);}static voidneoclock4x_poll(int unit, struct peer *peer){ struct neoclock4x_unit *up; struct refclockproc *pp; pp = peer->procptr; up = (struct neoclock4x_unit *)pp->unitptr; pp->polls++; up->recvnow = 1;}static voidneoclock4x_control(int unit, struct refclockstat *in, struct refclockstat *out, struct peer *peer){ struct neoclock4x_unit *up; struct refclockproc *pp; if(NULL == peer) { msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); return; } pp = peer->procptr; if(NULL == pp) { msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); return; } up = (struct neoclock4x_unit *)pp->unitptr; if(NULL == up) { msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit); return; } if(NULL != in) { /* check to see if a user supplied time offset is given */ if(in->haveflags & CLK_HAVETIME1) { pp->fudgetime1 = in->fudgetime1; NLOG(NLOG_CLOCKINFO) msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.", unit, pp->fudgetime1); } /* notify */ if(pp->sloppyclockflag & CLK_FLAG1) { NLOG(NLOG_CLOCKINFO) msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is used to synchronize time if radio clock has no reception.", unit); } else { NLOG(NLOG_CLOCKINFO) msyslog(LOG_NOTICE, "NeoClock4X(%d): time is only adjusted with radio signal reception.", unit); } } if(NULL != out) { char *tt; char tmpbuf[80]; out->kv_list = (struct ctl_var *)0; out->type = REFCLK_NEOCLOCK4X; snprintf(tmpbuf, sizeof(tmpbuf)-1, "%04d-%02d-%02d %02d:%02d:%02d.%03d", up->utc_year, up->utc_month, up->utc_day, up->utc_hour, up->utc_minute, up->utc_second, up->utc_msec); tt = add_var(&out->kv_list, sizeof(tmpbuf)-1, RO|DEF); snprintf(tt, sizeof(tmpbuf)-1, "calc_utc=\"%s\"", tmpbuf); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "radiosignal=\"%s\"", up->radiosignal); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "antenna1=\"%d\"", up->antenna1); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "antenna2=\"%d\"", up->antenna2); tt = add_var(&out->kv_list, 40, RO|DEF); if('A' == up->timesource) snprintf(tt, 39, "timesource=\"radio\""); else if('C' == up->timesource) snprintf(tt, 39, "timesource=\"quartz\""); else snprintf(tt, 39, "timesource=\"unknown\""); tt = add_var(&out->kv_list, 40, RO|DEF); if('I' == up->quarzstatus) snprintf(tt, 39, "quartzstatus=\"synchronized\""); else if('X' == up->quarzstatus) snprintf(tt, 39, "quartzstatus=\"not synchronized\""); else snprintf(tt, 39, "quartzstatus=\"unknown\""); tt = add_var(&out->kv_list, 40, RO|DEF); if('S' == up->dststatus) snprintf(tt, 39, "dststatus=\"summer\""); else if('W' == up->dststatus) snprintf(tt, 39, "dststatus=\"winter\""); else snprintf(tt, 39, "dststatus=\"unknown\""); tt = add_var(&out->kv_list, 80, RO|DEF); snprintf(tt, 79, "firmware=\"%s\"", up->firmware); tt = add_var(&out->kv_list, 40, RO|DEF); snprintf(tt, 39, "firmwaretag=\"%c\"", up->firmwaretag); tt = add_var(&out->kv_list, 80, RO|DEF); snprintf(tt, 79, "driver version=\"%s\"", NEOCLOCK4X_DRIVER_VERSION); tt = add_var(&out->kv_list, 80, RO|DEF); snprintf(tt, 79, "serialnumber=\"%s\"", up->serial); }}static intneol_hexatoi_len(const char str[], int *result, int maxlen){ int hexdigit; int i; int n = 0; for(i=0; isxdigit((int)str[i]) && i < maxlen; i++) { hexdigit = isdigit((int)str[i]) ? toupper(str[i]) - '0' : toupper(str[i]) - 'A' + 10; n = 16 * n + hexdigit; } *result = n; return (n);}static intneol_atoi_len(const char str[], int *result, int maxlen){ int digit; int i; int n = 0; for(i=0; isdigit((int)str[i]) && i < maxlen; i++) { digit = str[i] - '0'; n = 10 * n + digit; } *result = n; return (n);}/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. * * [For the Julian calendar (which was used in Russia before 1917, * Britain & colonies before 1752, anywhere else before 1582, * and is still in use by some communities) leave out the * -year/100+year/400 terms, and add 10.] * * This algorithm was first published by Gauss (I think). * * WARNING: this function will overflow on 2106-02-07 06:28:16 on * machines were long is 32-bit! (However, as time_t is signed, we * will already get problems at other places on 2038-01-19 03:14:08) */static unsigned longneol_mktime(int year, int mon, int day, int hour, int min, int sec){ if (0 >= (int) (mon -= 2)) { /* 1..12 . 11,12,1..10 */ mon += 12; /* Puts Feb last since it has leap day */ year -= 1; } return ((( (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + year*365 - 719499 )*24 + hour /* now have hours */ )*60 + min /* now have minutes */ )*60 + sec; /* finally seconds */}static voidneol_localtime(unsigned long utc, int* year, int* month, int* day, int* hour, int* min, int* sec){ *sec = utc % 60; utc /= 60; *min = utc % 60; utc /= 60; *hour = utc % 24; utc /= 24; /* JDN Date 1/1/1970 */ neol_jdn_to_ymd(utc + 2440588L, year, month, day);}static voidneol_jdn_to_ymd(unsigned long jdn, int *yy, int *mm, int *dd){ unsigned long x, z, m, d, y; unsigned long daysPer400Years = 146097UL; unsigned long fudgedDaysPer4000Years = 1460970UL + 31UL; x = jdn + 68569UL; z = 4UL * x / daysPer400Years; x = x - (daysPer400Years * z + 3UL) / 4UL; y = 4000UL * (x + 1) / fudgedDaysPer4000Years; x = x - 1461UL * y / 4UL + 31UL; m = 80UL * x / 2447UL; d = x - 2447UL * m / 80UL; x = m / 11UL; m = m + 2UL - 12UL * x; y = 100UL * (z - 49UL) + y + x; *yy = (int)y; *mm = (int)m; *dd = (int)d;}#if 0/* * delay in milliseconds */static voidneol_mdelay(int milliseconds){ struct timeval tv; if(milliseconds) { tv.tv_sec = 0; tv.tv_usec = milliseconds * 1000; select(1, NULL, NULL, NULL, &tv); }}#endif#if !defined(NEOCLOCK4X_FIRMWARE)static intneol_query_firmware(int fd, int unit, char *firmware, int maxlen){ char tmpbuf[256]; int len; int lastsearch; unsigned char c; int last_c_was_crlf; int last_crlf_conv_len; int init; int read_errors; int flag = 0; int chars_read; /* wait a little bit */ sleep(1); if(-1 != write(fd, "V", 1)) { /* wait a little bit */ sleep(1); memset(tmpbuf, 0x00, sizeof(tmpbuf)); len = 0; lastsearch = 0; last_c_was_crlf = 0; last_crlf_conv_len = 0; init = 1; read_errors = 0; chars_read = 0; for(;;) { if(read_errors > 5) { msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit); strcpy(tmpbuf, "unknown due to timeout"); break; } if(chars_read > 500) { msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (garbage)", unit); strcpy(tmpbuf, "unknown due to garbage input"); break; } if(-1 == read(fd, &c, 1)) { if(EAGAIN != errno) { msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %s", unit ,strerror(errno)); read_errors++; } else { sleep(1); } continue; } else { chars_read++; } if(init) { if(0xA9 != c) /* wait for (c) char in input stream */ continue; strcpy(tmpbuf, "(c)"); len = 3; init = 0; continue; }#if 0 msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c);#endif if(0x0A == c || 0x0D == c) { if(last_c_was_crlf) { char *ptr; ptr = strstr(&tmpbuf[lastsearch], "S/N"); if(NULL != ptr) { tmpbuf[last_crlf_conv_len] = 0; flag = 1; break; } /* convert \n to / */ last_crlf_conv_len = len; tmpbuf[len++] = ' '; tmpbuf[len++] = '/'; tmpbuf[len++] = ' '; lastsearch = len; } last_c_was_crlf = 1; } else { last_c_was_crlf = 0; if(0x00 != c) tmpbuf[len++] = (char) c; } tmpbuf[len] = '\0'; if(len > sizeof(tmpbuf)-5) break; } } else { msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit); strcpy(tmpbuf, "unknown error"); } strncpy(firmware, tmpbuf, maxlen); firmware[maxlen] = '\0'; if(flag) { NLOG(NLOG_CLOCKINFO) msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware); } return (flag);}static intneol_check_firmware(int unit, const char *firmware, char *firmwaretag){ char *ptr; *firmwaretag = '?'; ptr = strstr(firmware, "NDF:"); if(NULL != ptr) { if((strlen(firmware) - strlen(ptr)) >= 7) { if(':' == *(ptr+5) && '*' == *(ptr+6)) *firmwaretag = *(ptr+4); } } if('A' != *firmwaretag) { msyslog(LOG_CRIT, "NeoClock4X(%d): firmware version \"%c\" not supported with this driver version!", unit, *firmwaretag); return (0); } return (1);}#endif#elseint refclock_neoclock4x_bs;#endif /* REFCLOCK *//* * History: * refclock_neoclock4x.c * * 2002/04/27 cjh * Revision 1.0 first release * * 2002/07/15 cjh * preparing for bitkeeper reposity * * 2002/09/09 cjh * Revision 1.1 * - don't assume sprintf returns an int anymore * - change the way the firmware version is read * - some customers would like to put a device called * data diode to the NeoClock4X device to disable * the write line. We need to now the firmware * version even in this case. We made a compile time * definition in this case. The code was previously * only available on request. * * 2003/01/08 cjh * Revision 1.11 * - changing xprinf to xnprinf to avoid buffer overflows * - change some logic * - fixed memory leaks if drivers can't initialize * * 2003/01/10 cjh * Revision 1.12 * - replaced ldiv * - add code to support FreeBSD * * 2003/07/07 cjh * Revision 1.13 * - fix reporting of clock status * changes. previously a bad clock * status was never reset. * * 2004/04/07 cjh * Revision 1.14 * - open serial port in a way * AIX and some other OS can * handle much better * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -