"Initial commit to Gerrit"
[profile/ivi/gpsd.git] / driver_superstar2.c
1 /*
2  * This file is Copyright (c) 2010 by the GPSD project
3  * BSD terms apply: see the file COPYING in the distribution root for details.
4  */
5 #include <sys/types.h>
6
7 #include "gpsd_config.h"
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <math.h>
13 #include <ctype.h>
14 #ifndef S_SPLINT_S
15 #include <unistd.h>
16 #endif /* S_SPLINT_S */
17 #include <time.h>
18 #include <stdio.h>
19
20 #include "gpsd.h"
21
22 #if defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE)
23 #include "bits.h"
24 #include "driver_superstar2.h"
25
26 /*
27  * These routines are specific to this driver
28  */
29
30 static gps_mask_t superstar2_parse_input(struct gps_device_t *);
31 static gps_mask_t superstar2_dispatch(struct gps_device_t *,
32                                       unsigned char *, size_t);
33 static gps_mask_t superstar2_msg_ack(struct gps_device_t *,
34                                      unsigned char *, size_t);
35 static gps_mask_t superstar2_msg_navsol_lla(struct gps_device_t *,
36                                             unsigned char *, size_t);
37 static gps_mask_t superstar2_msg_timing(struct gps_device_t *,
38                                         unsigned char *, size_t);
39 static gps_mask_t superstar2_msg_svinfo(struct gps_device_t *,
40                                         unsigned char *, size_t);
41 static gps_mask_t superstar2_msg_iono_utc(struct gps_device_t *,
42                                           unsigned char *, size_t);
43 static gps_mask_t superstar2_msg_ephemeris(struct gps_device_t *,
44                                            unsigned char *, size_t);
45
46 /*
47  * These methods may be called elsewhere in gpsd
48  */
49 static ssize_t superstar2_control_send(struct gps_device_t *, char *, size_t);
50 static void superstar2_event_hook(struct gps_device_t *, event_t);
51 static bool superstar2_set_speed(struct gps_device_t *, speed_t, char, int);
52 static void superstar2_set_mode(struct gps_device_t *, int);
53 static ssize_t superstar2_write(struct gps_device_t *, char *, size_t);
54
55
56 /*
57  * Decode the message ACK message
58  */
59 static gps_mask_t
60 superstar2_msg_ack(struct gps_device_t *session UNUSED,
61                    unsigned char *buf, size_t data_len)
62 {
63     if (data_len == 11)
64         gpsd_report(LOG_PROG,
65                     "superstar2 #126 - "
66                     "ACK %d %d %d %d %d\n",
67                     buf[5], buf[6], buf[7], buf[8], buf[9]);
68     return 0;
69 }
70
71 /*
72  * Decode the navigation solution message. The ECEF version is intentionally
73  * unhandled. By suppressing evaluation of it, we gain the desirable feature
74  * that the fix update is atomic and exactly once per cycle.
75  */
76
77
78 static gps_mask_t
79 superstar2_msg_navsol_lla(struct gps_device_t *session,
80                           unsigned char *buf, size_t data_len)
81 {
82     gps_mask_t mask;
83     unsigned char flags;
84     union int_float i_f;
85     union long_double l_d;
86     double d;
87     struct tm tm;
88
89     if (data_len != 77)
90         return 0;
91
92     gpsd_report(LOG_PROG, "superstar2 #20 - user navigation data\n");
93     mask = 0;
94
95     /*@ +charint @*/
96     flags = (unsigned char)getub(buf, 72);
97     if ((flags & 0x0f) != 0x03) /* mode 3 is navigation */
98         return mask;
99     /*@ -charint @*/
100
101     /* extract time data */
102     (void)memset(&tm, '\0', sizeof(tm));
103     tm.tm_hour = (int)getub(buf, 4) & 0x1f;
104     tm.tm_min = (int)getub(buf, 5);
105     d = getled(buf, 6);
106     tm.tm_sec = (int)d;
107     tm.tm_mday = (int)getub(buf, 14);
108     tm.tm_mon = (int)getub(buf, 15) - 1;
109     tm.tm_year = (int)getleuw(buf, 16) - 1900;
110     session->newdata.time = timegm(&tm) + (d - tm.tm_sec);
111     mask |= TIME_IS;
112
113     /* extract the local tangential plane (ENU) solution */
114     session->newdata.latitude = getled(buf, 18) * RAD_2_DEG;
115     session->newdata.longitude = getled(buf, 26) * RAD_2_DEG;
116     session->newdata.altitude = getlef(buf, 34);
117     session->newdata.speed = getlef(buf, 38);
118     session->newdata.track = getlef(buf, 42) * RAD_2_DEG;
119     session->newdata.climb = getlef(buf, 54);
120     mask |= LATLON_IS | ALTITUDE_IS | SPEED_IS | TRACK_IS | CLIMB_IS;
121
122     session->gpsdata.satellites_used = (int)getub(buf, 71) & 0x0f;
123     /*@i3@*/ session->gpsdata.dop.hdop = getleuw(buf, 66) * 0.1;
124     /*@i3@*/ session->gpsdata.dop.vdop = getleuw(buf, 68) * 0.1;
125     /* other DOP if available */
126     mask |= DOP_IS | USED_IS;
127
128     flags = (unsigned char)getub(buf, 70);
129     switch (flags & 0x1f) {
130     case 2:
131         session->newdata.mode = MODE_3D;
132         session->gpsdata.status = STATUS_FIX;
133         break;
134     case 4:
135         session->newdata.mode = MODE_3D;
136         session->gpsdata.status = STATUS_DGPS_FIX;
137         break;
138     case 5:
139         session->newdata.mode = MODE_2D;
140         session->gpsdata.status = STATUS_DGPS_FIX;
141         break;
142     case 3:
143     case 6:
144         session->newdata.mode = MODE_2D;
145         session->gpsdata.status = STATUS_FIX;
146         break;
147     default:
148         session->gpsdata.status = STATUS_NO_FIX;
149         session->newdata.mode = MODE_NO_FIX;
150     }
151
152     mask |= MODE_IS | STATUS_IS;
153     gpsd_report(LOG_DATA,
154                 "NAVSOL_LLA: time=%.2f lat=%.2f lon=%.2f alt=%.2f track=%.2f speed=%.2f climb=%.2f mode=%d status=%d hdop=%.2f hdop=%.2f used=%d mask=%s\n",
155                 session->newdata.time,
156                 session->newdata.latitude,
157                 session->newdata.longitude,
158                 session->newdata.altitude,
159                 session->newdata.track,
160                 session->newdata.speed,
161                 session->newdata.climb,
162                 session->newdata.mode,
163                 session->gpsdata.status,
164                 session->gpsdata.dop.hdop,
165                 session->gpsdata.dop.vdop,
166                 session->gpsdata.satellites_used, gpsd_maskdump(mask));
167     return mask;
168 }
169
170 /**
171  * GPS Satellite Info
172  */
173 static gps_mask_t
174 superstar2_msg_svinfo(struct gps_device_t *session,
175                       unsigned char *buf, size_t data_len)
176 {
177     int i, st, nchan, nsv;
178
179     if (data_len != 67)
180         return 0;
181
182     gpsd_report(LOG_PROG, "superstar2 #33 - satellite data\n");
183
184     nchan = 12;
185     gpsd_zero_satellites(&session->gpsdata);
186     nsv = 0;                    /* number of actually used satellites */
187     for (i = st = 0; i < nchan; i++) {
188         /* get info for one channel/satellite */
189         int off = i * 5 + 5;
190         unsigned int porn;
191         if ((porn = (unsigned int)getub(buf, off) & 0x1f) == 0)
192             porn = (unsigned int)(getub(buf, off + 3) >> 1) + 87;
193
194         session->gpsdata.PRN[i] = (int)porn;
195         session->gpsdata.ss[i] = (float)getub(buf, off + 4);
196         session->gpsdata.elevation[i] = (int)getsb(buf, off + 1);
197         session->gpsdata.azimuth[i] = (unsigned short)getub(buf, off + 2) +
198             ((unsigned short)(getub(buf, off + 3) & 0x1) << 1);
199
200         /*@ +charint @*/
201         if ((getub(buf, off) & 0x60) == 0x60)
202             session->gpsdata.used[nsv++] = session->gpsdata.PRN[i];
203         /*@ -charint @*/
204
205         if (session->gpsdata.PRN[i])
206             st++;
207     }
208     session->gpsdata.skyview_time = NAN;
209     session->gpsdata.satellites_used = nsv;
210     session->gpsdata.satellites_visible = st;
211     gpsd_report(LOG_DATA,
212                 "SVINFO: visible=%d used=%d mask={SATELLITE|USED}\n",
213                 session->gpsdata.satellites_visible,
214                 session->gpsdata.satellites_used);
215     return SATELLITE_IS | USED_IS;
216 }
217
218 static gps_mask_t
219 superstar2_msg_version(struct gps_device_t *session,
220                        unsigned char *buf, size_t data_len)
221 {
222 #define SZ 16
223     char main_sw[SZ], hw_part[SZ], boot_sw[SZ], ser_num[SZ];
224
225     /*@ +charint @*/
226     /* byte 98 is device type, value = 3 means superstar2 */
227     if ((data_len != 101) || ((getub(buf, 98) & 0x0f) != 3))
228         return 0;
229     /*@ -charint @*/
230
231     (void)snprintf(main_sw, 15, "%s", (char *)buf + 4);
232     (void)snprintf(hw_part, 15, "%s", (char *)buf + 18);
233     (void)snprintf(boot_sw, 15, "%s", (char *)buf + 36);
234     (void)snprintf(ser_num, 14, "%s", (char *)buf + 73);
235
236     gpsd_report(LOG_PROG,
237                 "superstar2 #45 - "
238                 "hw part %s boot sw %s main sw %s ser num %s\n",
239                 hw_part, boot_sw, main_sw, ser_num);
240     (void)strlcpy(session->subtype, main_sw, sizeof(session->subtype));
241     gpsd_report(LOG_DATA, "VERSION: subtype='%s' mask={DEVEICEID}\n",
242                 session->subtype);
243     return DEVICEID_IS;
244 }
245
246 /**
247  * GPS Leap Seconds
248  */
249 static gps_mask_t
250 superstar2_msg_timing(struct gps_device_t *session, unsigned char *buf,
251                       size_t data_len)
252 {
253     gps_mask_t mask;
254     union long_double l_d;
255     double d;
256     struct tm tm;
257
258     if (data_len != 65)
259         return 0;
260
261     gpsd_report(LOG_PROG, "superstar2 #113 - timing status\n");
262     /*@ +charint @*/
263     if ((getub(buf, 55) & 0x30) != 0)
264         mask = 0;
265     /*@ -charint @*/
266     else {
267         /* extract time data */
268         (void)memset(&tm, '\0', sizeof(tm));
269         tm.tm_mday = (int)getsb(buf, 37);
270         tm.tm_mon = (int)getsb(buf, 38) - 1;
271         tm.tm_year = (int)getlesw(buf, 39) - 1900;
272
273         tm.tm_hour = (int)getsb(buf, 41);
274         tm.tm_min = (int)getsb(buf, 42);
275         d = getled(buf, 43);
276         tm.tm_sec = (int)d;
277         session->newdata.time = timegm(&tm);
278         session->context->leap_seconds = (int)getsb(buf, 20);
279         mask = TIME_IS;
280     }
281     gpsd_report(LOG_DATA, "TIMING: time=%.2f mask={TIME}\n",
282                 session->newdata.time);
283     return mask;
284 }
285
286 /**
287  * Raw Measurements
288  */
289 static gps_mask_t
290 superstar2_msg_measurement(struct gps_device_t *session, unsigned char *buf,
291                            size_t data_len UNUSED)
292 {
293     gps_mask_t mask = 0;
294 #ifdef RAW_ENABLE
295     int i, n;
296     unsigned long ul;
297     double t;
298     union long_double l_d;
299
300     gpsd_report(LOG_PROG, "superstar2 #23 - measurement block\n");
301
302     n = (int)getub(buf, 6);     /* number of measurements */
303     if ((n < 1) || (n > MAXCHANNELS)) {
304         gpsd_report(LOG_INF, "too many measurements\n");
305         return 0;
306     }
307     t = getled(buf, 7);         /* measurement time */
308     for (i = 0; i < n; i++) {
309         session->gpsdata.raw.mtime[i] = t;
310         session->gpsdata.PRN[i] = (int)getub(buf, 11 * i + 15) & 0x1f;
311         session->gpsdata.ss[i] = (double)getub(buf, 11 * i * 15 + 1) / 4.0;
312         session->gpsdata.raw.codephase[i] =
313             (double)getleul(buf, 11 * i * 15 + 2);
314         ul = (unsigned long)getleul(buf, 11 * i * 15 + 6);
315
316         session->gpsdata.raw.satstat[i] = (unsigned int)(ul & 0x03L);
317         session->gpsdata.raw.carrierphase[i] = (double)((ul >> 2) & 0x03ffL);
318         session->gpsdata.raw.pseudorange[i] = (double)(ul >> 12);
319     }
320
321     mask |= RAW_IS;
322 #endif /* RAW_ENABLE */
323     return mask;
324 }
325
326 /* request for ionospheric and utc time data #75 */
327 /*@ +charint @*/
328 static unsigned char iono_utc_msg[] = { 0x01, 0x4b, 0xb4, 0x00, 0x00, 0x01 };
329
330 /*@ -charint @*/
331
332
333 /**
334  * Ionospheric/UTC parameters
335  */
336 static gps_mask_t
337 superstar2_msg_iono_utc(struct gps_device_t *session, unsigned char *buf,
338                         size_t data_len UNUSED)
339 {
340     unsigned int i, u;
341
342     i = (unsigned int)getub(buf, 12);
343     u = (unsigned int)getub(buf, 21);
344     gpsd_report(LOG_PROG,
345                 "superstar2 #75 - ionospheric & utc data: iono %s utc %s\n",
346                 i ? "ok" : "bad", u ? "ok" : "bad");
347     session->driver.superstar2.last_iono = time(NULL);
348
349     return 0;
350 }
351
352
353 /**
354  * Ephemeris
355  */
356 static gps_mask_t
357 superstar2_msg_ephemeris(struct gps_device_t *session, unsigned char *buf,
358                          size_t data_len UNUSED)
359 {
360     unsigned int prn;
361     prn = (unsigned int)(getub(buf, 4) & 0x1f);
362     gpsd_report(LOG_PROG, "superstar2 #22 - ephemeris data - prn %u\n", prn);
363
364     /* ephemeris data updates fairly slowly, but when it does, poll UTC */
365     if ((time(NULL) - session->driver.superstar2.last_iono) > 60)
366         (void)superstar2_write(session, (char *)iono_utc_msg,
367                                sizeof(iono_utc_msg));
368
369     return ONLINE_IS;
370 }
371
372
373 static ssize_t
374 superstar2_write(struct gps_device_t *session, char *msg, size_t msglen)
375 {
376     unsigned short c = 0;
377     ssize_t i;
378
379     for (i = 0; i < (ssize_t) (msglen - 2); i++)
380         c += (unsigned short)msg[i];
381     c += 0x100;
382     msg[(int)msg[3] + 4] = (char)((c >> 8) & 0xff);
383     msg[(int)msg[3] + 5] = (char)(c & 0xff);
384     gpsd_report(LOG_IO, "writing superstar2 control type %d len %zu:%s\n",
385                 (int)msg[1] & 0x7f, msglen,
386                 gpsd_hexdump_wrapper(msg, msglen, LOG_IO));
387     return (i = gpsd_write(session, msg, msglen));
388 }
389
390 /**
391  * Parse the data from the device
392  */
393 gps_mask_t
394 superstar2_dispatch(struct gps_device_t * session, unsigned char *buf,
395                     size_t len)
396 {
397     int type;
398
399     if (len == 0)
400         return 0;
401
402     type = (int)buf[SUPERSTAR2_TYPE_OFFSET];
403     (void)snprintf(session->gpsdata.tag,
404                    sizeof(session->gpsdata.tag), "SS2-%d", type);
405
406     session->cycle_end_reliable = true;
407
408     switch (type) {
409     case SUPERSTAR2_ACK:        /* Message Acknowledgement */
410         return superstar2_msg_ack(session, buf, len);
411     case SUPERSTAR2_SVINFO:     /* Satellite Visibility Data */
412         return superstar2_msg_svinfo(session, buf, len);
413     case SUPERSTAR2_NAVSOL_LLA: /* Navigation Data */
414         return superstar2_msg_navsol_lla(session, buf,
415                                          len) | (CLEAR_IS | REPORT_IS);
416     case SUPERSTAR2_VERSION:    /* Hardware/Software Version */
417         return superstar2_msg_version(session, buf, len);
418     case SUPERSTAR2_TIMING:     /* Timing Parameters */
419         return superstar2_msg_timing(session, buf, len);
420     case SUPERSTAR2_MEASUREMENT:        /* Timing Parameters */
421         return superstar2_msg_measurement(session, buf, len);
422     case SUPERSTAR2_IONO_UTC:
423         return superstar2_msg_iono_utc(session, buf, len);
424     case SUPERSTAR2_EPHEMERIS:
425         return superstar2_msg_ephemeris(session, buf, len);
426
427     default:
428         gpsd_report(LOG_WARN,
429                     "unknown superstar2 packet id 0x%02x length %zd: %s\n",
430                     type, len, gpsd_hexdump_wrapper(buf, len, LOG_WARN));
431         return 0;
432     }
433 }
434
435 /**********************************************************
436  *
437  * Externally called routines below here
438  *
439  **********************************************************/
440 /*@ +charint @*/
441 /* canned config messages */
442 /* Initiate Link ID# 63 */
443 static unsigned char link_msg[] = { 0x01, 0x3f, 0xc0, 0x08,
444     0x55, 0x47, 0x50, 0x53, 0x2d, 0x30, 0x30, 0x30,
445     0x00, 0x00
446 };
447
448 /* Request Hardware/Software Identification ID# 45 */
449 static unsigned char version_msg[] = { 0x01, 0x2d, 0xd2, 0x00, 0x00, 0x01 };
450
451 /*@ -charint @*/
452
453 static void superstar2_event_hook(struct gps_device_t *session, event_t event)
454 {
455     if (event == event_wakeup) {
456         (void)superstar2_write(session, (char *)link_msg, sizeof(link_msg));
457         (void)usleep(320000);
458         (void)superstar2_write(session, (char *)version_msg,
459                                sizeof(version_msg));
460         return;
461     }
462
463     /* query firmware version */
464     if (event == event_identified)
465         (void)superstar2_write(session, (char *)version_msg,
466                                sizeof(version_msg));
467
468     /* FIX-ME: check to see if this really needs to be resent on reactivation */
469     if (event == event_identified || event == event_reactivate) {
470         /*@ +charint @*/
471         unsigned char svinfo_msg[] = { 0x01, 0xa1, 0x5e, 0x00, 0x00, 0x01 };
472         unsigned char timing_msg[] = { 0x01, 0xf1, 0x0e, 0x00, 0x00, 0x01 };
473         unsigned char navsol_lla_msg[] =
474             { 0x01, 0x94, 0x6b, 0x00, 0x00, 0x01 };
475         unsigned char ephemeris_msg[] =
476             { 0x01, 0x96, 0x69, 0x00, 0x00, 0x01 };
477         unsigned char measurement_msg[] =
478             { 0x01, 0x97, 0x68, 0x01, 0x00, 0x01, 0x01 };
479         /*@ -charint @*/
480
481         (void)superstar2_write(session, (char *)timing_msg,
482                                sizeof(timing_msg));
483         (void)superstar2_write(session, (char *)measurement_msg,
484                                sizeof(measurement_msg));
485         (void)superstar2_write(session, (char *)svinfo_msg,
486                                sizeof(svinfo_msg));
487         (void)superstar2_write(session, (char *)navsol_lla_msg,
488                                sizeof(navsol_lla_msg));
489         (void)superstar2_write(session, (char *)version_msg,
490                                sizeof(version_msg));
491         (void)superstar2_write(session, (char *)ephemeris_msg,
492                                sizeof(ephemeris_msg));
493         (void)superstar2_write(session, (char *)iono_utc_msg,
494                                sizeof(iono_utc_msg));
495         session->driver.superstar2.last_iono = time(NULL);
496     }
497 }
498
499 /*
500  * This is the entry point to the driver. When the packet sniffer recognizes
501  * a packet for this driver, it calls this method which passes the packet to
502  * the binary processor or the nmea processor, depending on the session type.
503  */
504 static gps_mask_t superstar2_parse_input(struct gps_device_t *session)
505 {
506     gps_mask_t st;
507
508     if (session->packet.type == SUPERSTAR2_PACKET) {
509         st = superstar2_dispatch(session, session->packet.outbuffer,
510                                  session->packet.length);
511         session->gpsdata.dev.driver_mode = MODE_BINARY;
512         return st;
513 #ifdef NMEA_ENABLE
514     } else if (session->packet.type == NMEA_PACKET) {
515         st = nmea_parse((char *)session->packet.outbuffer, session);
516         (void)gpsd_switch_driver(session, "Generic NMEA");
517         session->gpsdata.dev.driver_mode = MODE_NMEA;
518         return st;
519 #endif /* NMEA_ENABLE */
520     } else
521         return 0;
522 }
523
524 #ifdef ALLOW_CONTROLSEND
525 static ssize_t
526 superstar2_control_send(struct gps_device_t *session, char *msg,
527                         size_t msglen)
528 {
529     /*@ +charint -mayaliasunique @*/
530     session->msgbuf[0] = 0x1;   /* SOH */
531     session->msgbuf[1] = msg[0];
532     session->msgbuf[2] = msg[0] ^ 0xff;
533     session->msgbuf[3] = (char)(msglen + 1);
534     (void)memcpy(session->msgbuf + 4, msg + 1, msglen - 1);
535     session->msgbuflen = (size_t) (msglen + 5);
536     /*@ -charint +mayaliasunique @*/
537     return superstar2_write(session, session->msgbuf, session->msgbuflen);
538 }
539 #endif /* ALLOW_CONTROLSEND */
540
541 #ifdef ALLOW_RECONFIGURE
542 static bool superstar2_set_speed(struct gps_device_t *session,
543                                  speed_t speed, char parity, int stopbits)
544 {
545     /* parity and stopbit switching aren't available on this chip */
546     if (parity != session->gpsdata.dev.parity
547         || stopbits != (int)session->gpsdata.dev.stopbits) {
548         return false;
549     } else {
550         /*@ +charint @*/
551         unsigned char speed_msg[] =
552             { 0x01, 0x48, 0xB7, 0x01, 0x00, 0x00, 0x00 };
553
554         /* high bit 0 in the mode word means set NMEA mode */
555         speed_msg[4] = (unsigned char)(speed / 300);
556         /*@ -charint @*/
557         return (superstar2_write(session, (char *)speed_msg, 7) == 7);
558     }
559 }
560 #endif /* ALLOW_RECONFIGURE */
561
562 static void superstar2_set_mode(struct gps_device_t *session, int mode)
563 {
564     if (mode == MODE_NMEA) {
565         /*@ +charint @*/
566         unsigned char mode_msg[] =
567             { 0x01, 0x48, 0xB7, 0x01, 0x00, 0x00, 0x00 };
568
569         /* high bit 0 in the mode word means set NMEA mode */
570         mode_msg[4] = (unsigned char)(session->gpsdata.dev.baudrate / 300);
571         (void)superstar2_write(session, (char *)mode_msg, 7);
572         /*@ -charint @*/
573     } else {
574         session->back_to_nmea = false;
575     }
576 }
577
578 /* *INDENT-OFF* */
579 const struct gps_type_t superstar2_binary = {
580     /* Full name of type */
581     .type_name          = "SuperStarII binary",
582     /* Associated lexer packet type */
583     .packet_type        = SUPERSTAR2_PACKET,
584     /* Response string that identifies device (not active) */
585     .trigger            = NULL,
586     /* Number of satellite channels supported by the device */
587     .channels           = 12,
588     /* Startup-time device detector */
589     .probe_detect       = NULL,
590     /* Packet getter (using default routine) */
591     .get_packet         = generic_get,
592     /* Parse message packets */
593     .parse_packet       = superstar2_parse_input,
594     /* RTCM handler (using default routine) */
595     .rtcm_writer        = pass_rtcm,
596     /* Fire on various lifetime events */
597     .event_hook         = superstar2_event_hook,
598 #ifdef ALLOW_RECONFIGURE
599     /* Speed (baudrate) switch */
600     .speed_switcher     = superstar2_set_speed,
601     /* Switch to NMEA mode */
602     .mode_switcher      = superstar2_set_mode,
603     /* Message delivery rate switcher (not active) */
604     .rate_switcher      = NULL,
605     /* Minimum cycle time (not used) */
606     .min_cycle          = 1,
607 #endif /* ALLOW_RECONFIGURE */
608 #ifdef ALLOW_CONTROLSEND
609     /* Control string sender - should provide checksum and trailer */
610     .control_send       = superstar2_control_send,
611 #endif /* ALLOW_CONTROLSEND */
612 #ifdef NTPSHM_ENABLE
613     .ntp_offset     = NULL,             /* no method for NTP fudge factor */
614 #endif /* NTPSHM_ ENABLE */
615 };
616 /* *INDENT-ON* */
617 #endif /* defined(SUPERSTAR2_ENABLE) && defined(BINARY_ENABLE) */