⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 refclock_neoclock4x.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * * Refclock_neoclock4x.c * - NeoClock4X driver for DCF77 or FIA Timecode * * Date: 2004-04-07 v1.14 * * see http://www.linum.com/redir/jump/id=neoclock4x&action=redir * for details about the NeoClock4X device * * Copyright (C) 2002-2004 by Linum Software GmbH <neoclock4x@linum.com> * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * */#ifdef HAVE_CONFIG_H# include "config.h"#endif#if defined(REFCLOCK) && (defined(CLOCK_NEOCLOCK4X))#include <unistd.h>#include <sys/time.h>#include <sys/types.h>#include <termios.h>#include <sys/ioctl.h>#include <ctype.h>#include "ntpd.h"#include "ntp_io.h"#include "ntp_control.h"#include "ntp_refclock.h"#include "ntp_unixtime.h"#include "ntp_stdlib.h"#if defined HAVE_SYS_MODEM_H# include <sys/modem.h># ifndef __QNXNTO__#  define TIOCMSET MCSETA#  define TIOCMGET MCGETA#  define TIOCM_RTS MRTS# endif#endif#ifdef HAVE_TERMIOS_H# ifdef TERMIOS_NEEDS__SVID3#  define _SVID3# endif# include <termios.h># ifdef TERMIOS_NEEDS__SVID3#  undef _SVID3# endif#endif#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif/* * NTP version 4.20 change the pp->msec field to pp->nsec. * To allow to support older ntp versions with this sourcefile * you can define NTP_REP_420 to allow this driver to compile * with ntp version back to 4.1.2. * */#if 0#define NTP_PRE_420#endif/* * If you want the driver for whatever reason to not use * the TX line to send anything to your NeoClock4X * device you must tell the NTP refclock driver which * firmware you NeoClock4X device uses. * * If you want to enable this feature change the "#if 0" * line to "#if 1" and make sure that the defined firmware * matches the firmware off your NeoClock4X receiver! * */#if 0#define NEOCLOCK4X_FIRMWARE                NEOCLOCK4X_FIRMWARE_VERSION_A#endif/* at this time only firmware version A is known */#define NEOCLOCK4X_FIRMWARE_VERSION_A      'A'#define NEOCLOCK4X_TIMECODELEN 37#define NEOCLOCK4X_OFFSET_SERIAL            3#define NEOCLOCK4X_OFFSET_RADIOSIGNAL       9#define NEOCLOCK4X_OFFSET_DAY              12#define NEOCLOCK4X_OFFSET_MONTH            14#define NEOCLOCK4X_OFFSET_YEAR             16#define NEOCLOCK4X_OFFSET_HOUR             18#define NEOCLOCK4X_OFFSET_MINUTE           20#define NEOCLOCK4X_OFFSET_SECOND           22#define NEOCLOCK4X_OFFSET_HSEC             24#define NEOCLOCK4X_OFFSET_DOW              26#define NEOCLOCK4X_OFFSET_TIMESOURCE       28#define NEOCLOCK4X_OFFSET_DSTSTATUS        29#define NEOCLOCK4X_OFFSET_QUARZSTATUS      30#define NEOCLOCK4X_OFFSET_ANTENNA1         31#define NEOCLOCK4X_OFFSET_ANTENNA2         33#define NEOCLOCK4X_OFFSET_CRC              35#define NEOCLOCK4X_DRIVER_VERSION          "1.14 (2004-04-07)"struct neoclock4x_unit {  l_fp	laststamp;	/* last receive timestamp */  short	unit;		/* NTP refclock unit number */  u_long polled;	/* flag to detect noreplies */  char	leap_status;	/* leap second flag */  int	recvnow;  char  firmware[80];  char  firmwaretag;  char  serial[7];  char  radiosignal[4];  char  timesource;  char  dststatus;  char  quarzstatus;  int   antenna1;  int   antenna2;  int   utc_year;  int   utc_month;  int   utc_day;  int   utc_hour;  int   utc_minute;  int   utc_second;  int   utc_msec;};static	int	neoclock4x_start        P((int, struct peer *));static	void	neoclock4x_shutdown	P((int, struct peer *));static	void	neoclock4x_receive	P((struct recvbuf *));static	void	neoclock4x_poll		P((int, struct peer *));static	void	neoclock4x_control      P((int, struct refclockstat *, struct refclockstat *, struct peer *));static int      neol_atoi_len           P((const char str[], int *, int));static int      neol_hexatoi_len        P((const char str[], int *, int));static void     neol_jdn_to_ymd         P((unsigned long, int *, int *, int *));static void     neol_localtime          P((unsigned long, int* , int*, int*, int*, int*, int*));static unsigned long neol_mktime        P((int, int, int, int, int, int));#if 0static void     neol_mdelay             P((int));#endif#if !defined(NEOCLOCK4X_FIRMWARE)static int      neol_query_firmware     P((int, int, char *, int));static int      neol_check_firmware     P((int, const char*, char *));#endifstruct refclock refclock_neoclock4x = {  neoclock4x_start,	/* start up driver */  neoclock4x_shutdown,	/* shut down driver */  neoclock4x_poll,	/* transmit poll message */  neoclock4x_control,  noentry,		/* initialize driver (not used) */  noentry,		/* not used */  NOFLAGS			/* not used */};static intneoclock4x_start(int unit,		 struct peer *peer){  struct neoclock4x_unit *up;  struct refclockproc *pp;  int fd;  char dev[20];  int sl232;#if defined(HAVE_TERMIOS)  struct termios termsettings;#endif#if !defined(NEOCLOCK4X_FIRMWARE)  int tries;#endif  (void) snprintf(dev, sizeof(dev)-1, "/dev/neoclock4x-%d", unit);  /* LDISC_STD, LDISC_RAW   * Open serial port. Use CLK line discipline, if available.   */  fd = refclock_open(dev, B2400, LDISC_STD);  if(fd <= 0)    {      return (0);    }#if defined(HAVE_TERMIOS)#if 1  if(tcgetattr(fd, &termsettings) < 0)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit);      (void) close(fd);      return (0);    }  /* 2400 Baud 8N2 */  termsettings.c_iflag = IGNBRK | IGNPAR | ICRNL;  termsettings.c_oflag = 0;  termsettings.c_cflag = CS8 | CSTOPB | CLOCAL | CREAD;  (void)cfsetispeed(&termsettings, (u_int)B2400);  (void)cfsetospeed(&termsettings, (u_int)B2400);  if(tcsetattr(fd, TCSANOW, &termsettings) < 0)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit);      (void) close(fd);      return (0);    }#else  if(tcgetattr(fd, &termsettings) < 0)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit);      (void) close(fd);      return (0);    }  /* 2400 Baud 8N2 */  termsettings.c_cflag &= ~PARENB;  termsettings.c_cflag |= CSTOPB;  termsettings.c_cflag &= ~CSIZE;  termsettings.c_cflag |= CS8;  if(tcsetattr(fd, TCSANOW, &termsettings) < 0)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit);      (void) close(fd);      return (0);    }#endif#elif defined(HAVE_SYSV_TTYS)  if(ioctl(fd, TCGETA, &termsettings) < 0)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): (TCGETA) can't query serial port settings: %m", unit);      (void) close(fd);      return (0);    }  /* 2400 Baud 8N2 */  termsettings.c_cflag &= ~PARENB;  termsettings.c_cflag |= CSTOPB;  termsettings.c_cflag &= ~CSIZE;  termsettings.c_cflag |= CS8;  if(ioctl(fd, TCSETA, &termsettings) < 0)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): (TSGETA) can't set serial port 2400 8N2: %m", unit);      (void) close(fd);      return (0);    }#else  msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set port to 2400 8N2 with this OS!", unit);  (void) close(fd);  return (0);#endif#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))  /* turn on RTS, and DTR for power supply */  /* NeoClock4x is powered from serial line */  if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit);      (void) close(fd);      return (0);    }#ifdef TIOCM_RTS  sl232 = sl232 | TIOCM_DTR | TIOCM_RTS;	/* turn on RTS, and DTR for power supply */#else  sl232 = sl232 | CIOCM_DTR | CIOCM_RTS;	/* turn on RTS, and DTR for power supply */#endif  if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1)    {      msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit);      (void) close(fd);      return (0);    }#else  msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set DTR/RTS to power NeoClock4X with this OS!",	  unit);  (void) close(fd);  return (0);#endif  up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit));  if(!(up))    {      msyslog(LOG_ERR, "NeoClock4X(%d): can't allocate memory for: %m",unit);      (void) close(fd);      return (0);    }  memset((char *)up, 0, sizeof(struct neoclock4x_unit));  pp = peer->procptr;  pp->clockdesc = "NeoClock4X";  pp->unitptr = (caddr_t)up;  pp->io.clock_recv = neoclock4x_receive;  pp->io.srcclock = (caddr_t)peer;  pp->io.datalen = 0;  pp->io.fd = fd;  /*   * no fudge time is given by user!   * use 169.583333 ms to compensate the serial line delay   * formula is:   * 2400 Baud / 11 bit = 218.18 charaters per second   *  (NeoClock4X timecode len)   */  pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0;  /*   * Initialize miscellaneous variables   */  peer->precision = -10;  peer->burst = NSTAGE;  memcpy((char *)&pp->refid, "neol", 4);  up->leap_status = 0;  up->unit = unit;  strcpy(up->firmware, "?");  up->firmwaretag = '?';  strcpy(up->serial, "?");  strcpy(up->radiosignal, "?");  up->timesource  = '?';  up->dststatus   = '?';  up->quarzstatus = '?';  up->antenna1    = -1;  up->antenna2    = -1;  up->utc_year    = 0;  up->utc_month   = 0;  up->utc_day     = 0;  up->utc_hour    = 0;  up->utc_minute  = 0;  up->utc_second  = 0;  up->utc_msec    = 0;#if defined(NEOCLOCK4X_FIRMWARE)#if NEOCLOCK4X_FIRMWARE == NEOCLOCK4X_FIRMWARE_VERSION_A  strcpy(up->firmware, "(c) 2002 NEOL S.A. FRANCE / L0.01 NDF:A:* (compile time)");  up->firmwaretag = 'A';#else  msyslog(LOG_EMERG, "NeoClock4X(%d): Unkown firmware defined at compile time for NeoClock4X",	  unit);  (void) close(fd);  pp->io.fd = -1;  free(pp->unitptr);  pp->unitptr = NULL;  return (0);#endif#else  for(tries=0; tries < 5; tries++)    {      NLOG(NLOG_CLOCKINFO)	msyslog(LOG_INFO, "NeoClock4X(%d): checking NeoClock4X firmware version (%d/5)", unit, tries);      /* wait 3 seconds for receiver to power up */      sleep(3);      if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware)))	{	  break;	}    }  /* can I handle this firmware version? */  if(!neol_check_firmware(up->unit, up->firmware, &up->firmwaretag))    {      (void) close(fd);      pp->io.fd = -1;      free(pp->unitptr);      pp->unitptr = NULL;      return (0);    }#endif  if(!io_addclock(&pp->io))    {      msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m", unit);      (void) close(fd);      pp->io.fd = -1;      free(pp->unitptr);      pp->unitptr = NULL;      return (0);    }  NLOG(NLOG_CLOCKINFO)    msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit);  return (1);}static voidneoclock4x_shutdown(int unit,		   struct peer *peer){  struct neoclock4x_unit *up;  struct refclockproc *pp;  int sl232;  if(NULL != peer)    {      pp = peer->procptr;      if(pp != NULL)        {          up = (struct neoclock4x_unit *)pp->unitptr;          if(up != NULL)            {              if(-1 !=  pp->io.fd)                {#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))                  /* turn on RTS, and DTR for power supply */                  /* NeoClock4x is powered from serial line */                  if(ioctl(pp->io.fd, TIOCMGET, (caddr_t)&sl232) == -1)                    {                      msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m",                              unit);                    }#ifdef TIOCM_RTS                  /* turn on RTS, and DTR for power supply */                  sl232 &= ~(TIOCM_DTR | TIOCM_RTS);#else                  /* turn on RTS, and DTR for power supply */                  sl232 &= ~(CIOCM_DTR | CIOCM_RTS);#endif                  if(ioctl(pp->io.fd, TIOCMSET, (caddr_t)&sl232) == -1)                    {                      msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m",                              unit);                    }#endif                  io_closeclock(&pp->io);                }              free(up);              pp->unitptr = NULL;            }        }    }  msyslog(LOG_ERR, "NeoClock4X(%d): shutdown", unit);  NLOG(NLOG_CLOCKINFO)    msyslog(LOG_INFO, "NeoClock4X(%d): receiver shutdown done", unit);}static voidneoclock4x_receive(struct recvbuf *rbufp){  struct neoclock4x_unit *up;  struct refclockproc *pp;  struct peer *peer;  unsigned long calc_utc;  int day;  int month;	/* ddd conversion */  int c;  int dsec;  unsigned char calc_chksum;  int recv_chksum;  peer = (struct peer *)rbufp->recv_srcclock;  pp = peer->procptr;  up = (struct neoclock4x_unit *)pp->unitptr;  /* wait till poll interval is reached */  if(0 == up->recvnow)    return;  /* reset poll interval flag */  up->recvnow = 0;  /* read last received timecode */  pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);  pp->leap = LEAP_NOWARNING;  if(NEOCLOCK4X_TIMECODELEN != pp->lencode)    {      NLOG(NLOG_CLOCKEVENT)	msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s",		up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode);      refclock_report(peer, CEVNT_BADREPLY);      return;    }  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2);  /* calculate checksum */  calc_chksum = 0;  for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++)    {      calc_chksum += pp->a_lastcode[c];    }  if(recv_chksum != calc_chksum)    {      NLOG(NLOG_CLOCKEVENT)	msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s",		up->unit, pp->a_lastcode);      refclock_report(peer, CEVNT_BADREPLY);      return;    }  /* Allow synchronization even is quartz clock is   * never initialized.   * WARNING: This is dangerous!   */  up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS];  if(0==(pp->sloppyclockflag & CLK_FLAG2))    {      if('I' != up->quarzstatus)	{	  NLOG(NLOG_CLOCKEVENT)	    msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s",		    up->unit, pp->a_lastcode);	  pp->leap = LEAP_NOTINSYNC;	  refclock_report(peer, CEVNT_BADDATE);	  return;	}    }  if('I' != up->quarzstatus)    {      NLOG(NLOG_CLOCKEVENT)	msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s",		up->unit, pp->a_lastcode);    }  /*   * If NeoClock4X is not synchronized to a radio clock   * check if we're allowed to synchronize with the quartz   * clock.   */  up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE];  if(0==(pp->sloppyclockflag & CLK_FLAG2))    {      if('A' != up->timesource)	{	  /* not allowed to sync with quartz clock */	  if(0==(pp->sloppyclockflag & CLK_FLAG1))	    {	      refclock_report(peer, CEVNT_BADTIME);	      pp->leap = LEAP_NOTINSYNC;	      return;	    }	}    }  /* this should only used when first install is done */  if(pp->sloppyclockflag & CLK_FLAG4)    {      msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s",	      up->unit, pp->a_lastcode);    }  /* 123456789012345678901234567890123456789012345 */  /* S/N123456DCF1004021010001202ASX1213CR\r\n */  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2);  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2);  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2);  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2);  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -