Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/ntpd/refclock_fg.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * refclock_fg - clock driver for the Forum Graphic GPS datating station
3
 */
4
5
#ifdef HAVE_CONFIG_H
6
# include <config.h>
7
#endif
8
9
#if defined(REFCLOCK) && defined(CLOCK_FG)
10
11
#include "ntpd.h"
12
#include "ntp_io.h"
13
#include "ntp_refclock.h"
14
#include "ntp_calendar.h"
15
#include "ntp_stdlib.h"
16
17
/*
18
 * This driver supports the Forum Graphic GPS dating station.
19
 * More information about FG GPS is available on http://www.forumgraphic.com
20
 * Contact das@amt.ru for any question about this driver.
21
 */
22
23
/*
24
 * Interface definitions
25
 */
26
#define DEVICE    "/dev/fgclock%d"
27
0
#define PRECISION (-10)  /* precision assumed (about 1 ms) */
28
0
#define REFID   "GPS"
29
0
#define DESCRIPTION "Forum Graphic GPS dating station"
30
0
#define LENFG   26  /* timecode length */
31
0
#define SPEED232        B9600   /* uart speed (9600 baud) */
32
33
/*
34
 * Function prototypes
35
 */
36
static  int   fg_init   (int);
37
static  int   fg_start  (int, struct peer *);
38
static  void  fg_shutdown (int, struct peer *);
39
static  void  fg_poll   (int, struct peer *);
40
static  void  fg_receive  (struct recvbuf *);
41
42
/* 
43
 * Forum Graphic unit control structure
44
 */
45
46
struct fgunit {
47
  int pollnum;  /* Use peer.poll instead? */
48
  int status;   /* Hug to check status information on GPS */
49
  int y2kwarn;  /* Y2K bug */
50
};
51
52
/* 
53
 * Queries definition
54
 */
55
static char fginit[] = { 0x10, 0x48, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56
0, 0, 0, 0, 0, 0, 0, 0, 0 };
57
static char fgdate[] = { 0x10, 0x44, 0x10, 0x0D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58
0, 0, 0, 0, 0, 0, 0, 0, 0 };
59
60
/*
61
 * Transfer vector
62
 */
63
struct  refclock refclock_fg = {
64
  fg_start,   /* start up driver */
65
  fg_shutdown,    /* shut down driver */
66
  fg_poll,    /* transmit poll message */
67
  noentry,    /* not used */
68
  noentry,    /* initialize driver (not used) */
69
  noentry,    /* not used */
70
  NOFLAGS     /* not used */
71
};
72
73
/*
74
 * fg_init - Initialization of FG GPS.
75
 */
76
77
static int
78
fg_init(
79
  int fd
80
  )
81
0
{
82
0
  if (write(fd, fginit, LENFG) != LENFG)
83
0
    return 0;
84
85
0
  return 1;
86
0
}
87
88
/*
89
 * fg_start - open the device and initialize data for processing
90
 */
91
static int
92
fg_start(
93
  int unit,
94
  struct peer *peer
95
  )
96
0
{
97
0
  struct refclockproc *pp;
98
0
  struct fgunit *up;
99
0
  int fd;
100
0
  char device[20];
101
102
103
  /*
104
   * Open device file for reading.
105
   */
106
0
  snprintf(device, sizeof(device), DEVICE, unit);
107
108
0
  DPRINTF(1, ("starting FG with device %s\n",device));
109
110
0
  fd = refclock_open(device, SPEED232, LDISC_CLK);
111
0
  if (fd <= 0)
112
0
    return (0);
113
  
114
  /*
115
   * Allocate and initialize unit structure
116
   */
117
118
0
  up = emalloc(sizeof(struct fgunit));
119
0
  memset(up, 0, sizeof(struct fgunit));
120
0
  pp = peer->procptr;
121
0
  pp->unitptr = up;
122
0
  pp->io.clock_recv = fg_receive;
123
0
  pp->io.srcclock = peer;
124
0
  pp->io.datalen = 0;
125
0
  pp->io.fd = fd;
126
0
  if (!io_addclock(&pp->io)) {
127
0
    close(fd);
128
0
    pp->io.fd = -1;
129
0
    return 0;
130
0
  }
131
132
  
133
  /*
134
   * Initialize miscellaneous variables
135
   */
136
0
  peer->precision = PRECISION;
137
0
  pp->clockdesc = DESCRIPTION;
138
0
  memcpy(&pp->refid, REFID, 3);
139
0
  up->pollnum = 0;
140
  
141
  /* 
142
   * Setup dating station to use GPS receiver.
143
   * GPS receiver should work before this operation.
144
   */
145
0
  if(!fg_init(pp->io.fd))
146
0
    refclock_report(peer, CEVNT_FAULT);
147
148
0
  return (1);
149
0
}
150
151
152
/*
153
 * fg_shutdown - shut down the clock
154
 */
155
static void
156
fg_shutdown(
157
  int unit,
158
  struct peer *peer
159
  )
160
0
{
161
0
  struct refclockproc *pp;
162
0
  struct fgunit *up;
163
  
164
0
  pp = peer->procptr;
165
0
  up = pp->unitptr;
166
0
  if (pp->io.fd != -1)
167
0
    io_closeclock(&pp->io);
168
0
  if (up != NULL)
169
0
    free(up);
170
0
}
171
172
173
/*
174
 * fg_poll - called by the transmit procedure
175
 */
176
static void
177
fg_poll(
178
  int unit,
179
  struct peer *peer
180
  )
181
0
{
182
0
  struct refclockproc *pp;
183
  
184
0
  pp = peer->procptr;
185
186
  /*
187
   * Time to poll the clock. The FG clock responds to a
188
   * "<DLE>D<DLE><CR>" by returning a timecode in the format specified
189
   * above. If nothing is heard from the clock for two polls,
190
   * declare a timeout and keep going.
191
   */
192
193
0
  if (write(pp->io.fd, fgdate, LENFG) != LENFG)
194
0
    refclock_report(peer, CEVNT_FAULT);
195
0
  else
196
0
    pp->polls++;
197
198
  /*
199
  if (pp->coderecv == pp->codeproc) {
200
    refclock_report(peer, CEVNT_TIMEOUT);
201
    return;
202
  }
203
  */
204
205
0
  record_clock_stats(&peer->srcadr, pp->a_lastcode);
206
  
207
0
  return;
208
209
0
}
210
211
/*
212
 * fg_receive - receive data from the serial interface
213
 */
214
static void
215
fg_receive(
216
  struct recvbuf *rbufp
217
  )
218
0
{
219
0
  struct refclockproc *pp;
220
0
  struct fgunit *up;
221
0
  struct peer *peer;
222
0
  char *bpt;
223
224
  /*
225
   * Initialize pointers and read the timecode and timestamp
226
   * We can't use gtlin function because we need bynary data in buf */
227
228
0
  peer = rbufp->recv_peer;
229
0
  pp = peer->procptr;
230
0
  up = pp->unitptr;
231
232
  /*
233
   * Below hug to implement receiving of status information
234
   */
235
0
  if(!up->pollnum) {
236
0
    up->pollnum++;
237
0
    return;
238
0
  }
239
240
  
241
0
  if (rbufp->recv_length < (LENFG - 2)) {
242
0
    refclock_report(peer, CEVNT_BADREPLY);
243
0
    return; /* The reply is invalid discard it. */
244
0
  }
245
246
  /* Below I trying to find a correct reply in buffer.
247
   * Sometime GPS reply located in the beginnig of buffer,
248
   * sometime you can find it with some offset.
249
   */
250
251
0
  bpt = (char *)rbufp->recv_space.X_recv_buffer;
252
0
  while (*bpt != '\x10')
253
0
    bpt++;
254
255
0
#define BP2(x) ( bpt[x] & 15 )
256
0
#define BP1(x) (( bpt[x] & 240 ) >> 4)
257
  
258
0
  pp->year = BP1(2) * 10 + BP2(2);
259
  
260
0
  if (pp->year == 94) {
261
0
    refclock_report(peer, CEVNT_BADREPLY);
262
0
    if (!fg_init(pp->io.fd))
263
0
      refclock_report(peer, CEVNT_FAULT);
264
0
    return;
265
     /* GPS is just powered up. The date is invalid -
266
     discarding it. Initilize GPS one more time */
267
    /* Sorry - this driver will broken in 2094 ;) */
268
0
  } 
269
  
270
0
  if (pp->year < 99)
271
0
    pp->year += 100;
272
273
0
  pp->year +=  1900;
274
0
  pp->day = 100 * BP2(3) + 10 * BP1(4) + BP2(4);
275
276
/*
277
   After Jan, 10 2000 Forum Graphic GPS receiver had a very strange
278
   benahour. It doubles day number for an hours in replys after 10:10:10 UTC
279
   and doubles min every hour at HH:10:ss for a minute.
280
   Hope it is a problem of my unit only and not a Y2K problem of FG GPS. 
281
   Below small code to avoid such situation.
282
*/
283
0
  if (up->y2kwarn > 10)
284
0
    pp->hour = BP1(6)*10 + BP2(6);
285
0
  else
286
0
    pp->hour = BP1(5)*10 + BP2(5);
287
288
0
  if ((up->y2kwarn > 10) && (pp->hour == 10)) {
289
0
    pp->minute = BP1(7)*10 + BP2(7);
290
0
    pp->second = BP1(8)*10 + BP2(8);
291
0
    pp->nsec = (BP1(9)*10 + BP2(9)) * 1000000;
292
0
    pp->nsec += BP1(10) * 1000;
293
0
  } else {
294
0
    pp->hour = BP1(5)*10 + BP2(5);
295
0
    pp->minute = BP1(6)*10 + BP2(6);
296
0
    pp->second = BP1(7)*10 + BP2(7);
297
0
    pp->nsec = (BP1(8)*10 + BP2(8)) * 1000000;
298
0
    pp->nsec += BP1(9) * 1000;
299
0
  }
300
301
0
  if ((pp->hour == 10) && (pp->minute == 10)) {
302
0
    up->y2kwarn++;
303
0
  }
304
305
0
  snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
306
0
     "%d %d %d %d %d", pp->year, pp->day, pp->hour,
307
0
     pp->minute, pp->second);
308
0
  pp->lencode = strlen(pp->a_lastcode);
309
  /*get_systime(&pp->lastrec);*/
310
311
0
#ifdef DEBUG
312
0
  if (debug)
313
0
    printf("fg: time is %04d/%03d %02d:%02d:%02d UTC\n",
314
0
           pp->year, pp->day, pp->hour, pp->minute, pp->second);
315
0
#endif
316
0
  pp->disp =  (10e-6);
317
0
  pp->lastrec = rbufp->recv_time; /* Is it better than get_systime()? */
318
  /* pp->leap = LEAP_NOWARNING; */
319
320
  /*
321
   * Process the new sample in the median filter and determine the
322
   * timecode timestamp.
323
   */
324
325
0
  if (!refclock_process(pp))
326
0
    refclock_report(peer, CEVNT_BADTIME);
327
0
  pp->lastref = pp->lastrec;
328
0
  refclock_receive(peer);
329
0
  return;
330
0
}
331
332
333
#else
334
int refclock_fg_bs;
335
#endif /* REFCLOCK */