📄 refclock_chu.c
字号:
noentry, /* not used (old chu_control) */ noentry, /* initialize driver (not used) */ noentry, /* not used (old chu_buginfo) */ NOFLAGS /* not used */};/* * chu_start - open the devices and initialize data for processing */static intchu_start( int unit, /* instance number (not used) */ struct peer *peer /* peer structure pointer */ ){ struct chuunit *up; struct refclockproc *pp; char device[20]; /* device name */ int fd; /* file descriptor */#ifdef ICOM int temp;#endif /* ICOM */#ifdef HAVE_AUDIO int fd_audio; /* audio port file descriptor */ int i; /* index */ double step; /* codec adjustment */ /* * Open audio device. */ fd_audio = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit);#ifdef DEBUG if (fd_audio > 0 && debug) audio_show();#endif /* * Open serial port in raw mode. */ if (fd_audio > 0) { fd = fd_audio; } else { sprintf(device, DEVICE, unit); fd = refclock_open(device, SPEED232, LDISC_RAW); }#else /* HAVE_AUDIO */ /* * Open serial port in raw mode. */ sprintf(device, DEVICE, unit); fd = refclock_open(device, SPEED232, LDISC_RAW);#endif /* HAVE_AUDIO */ if (fd <= 0) return (0); /* * Allocate and initialize unit structure */ if (!(up = (struct chuunit *) emalloc(sizeof(struct chuunit)))) { close(fd); return (0); } memset((char *)up, 0, sizeof(struct chuunit)); pp = peer->procptr; pp->unitptr = (caddr_t)up; pp->io.clock_recv = chu_receive; pp->io.srcclock = (caddr_t)peer; pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { close(fd); free(up); return (0); } /* * Initialize miscellaneous variables */ peer->precision = PRECISION; pp->clockdesc = DESCRIPTION; strcpy(up->ident, "CHU"); memcpy(&peer->refid, up->ident, 4); DTOLFP(CHAR, &up->charstamp);#ifdef HAVE_AUDIO /* * The companded samples are encoded sign-magnitude. The table * contains all the 256 values in the interest of speed. We do * this even if the audio codec is not available. C'est la lazy. */ up->fd_audio = fd_audio; up->gain = 127; up->comp[0] = up->comp[OFFSET] = 0.; up->comp[1] = 1; up->comp[OFFSET + 1] = -1.; up->comp[2] = 3; up->comp[OFFSET + 2] = -3.; step = 2.; for (i = 3; i < OFFSET; i++) { up->comp[i] = up->comp[i - 1] + step; up->comp[OFFSET + i] = -up->comp[i]; if (i % 16 == 0) step *= 2.; } DTOLFP(1. / SECOND, &up->tick);#endif /* HAVE_AUDIO */#ifdef ICOM temp = 0;#ifdef DEBUG if (debug > 1) temp = P_TRACE;#endif if (peer->ttl > 0) { if (peer->ttl & 0x80) up->fd_icom = icom_init("/dev/icom", B1200, temp); else up->fd_icom = icom_init("/dev/icom", B9600, temp); } if (up->fd_icom > 0) { if (chu_newchan(peer, 0) != 0) { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) msyslog(LOG_NOTICE, "icom: radio not found"); up->errflg = CEVNT_FAULT; close(up->fd_icom); up->fd_icom = 0; } else { NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) msyslog(LOG_NOTICE, "icom: autotune enabled"); } }#endif /* ICOM */ return (1);}/* * chu_shutdown - shut down the clock */static voidchu_shutdown( int unit, /* instance number (not used) */ struct peer *peer /* peer structure pointer */ ){ struct chuunit *up; struct refclockproc *pp; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; if (up == NULL) return; io_closeclock(&pp->io);#ifdef ICOM if (up->fd_icom > 0) close(up->fd_icom);#endif /* ICOM */ free(up);}/* * chu_receive - receive data from the audio or serial device */static voidchu_receive( struct recvbuf *rbufp /* receive buffer structure pointer */ ){#ifdef HAVE_AUDIO struct chuunit *up; struct refclockproc *pp; struct peer *peer; peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * If the audio codec is warmed up, the buffer contains codec * samples which need to be demodulated and decoded into CHU * characters using the software UART. Otherwise, the buffer * contains CHU characters from the serial port, so the software * UART is bypassed. In this case the CPU will probably run a * few degrees cooler. */ if (up->fd_audio > 0) chu_audio_receive(rbufp); else chu_serial_receive(rbufp);#else chu_serial_receive(rbufp);#endif /* HAVE_AUDIO */}#ifdef HAVE_AUDIO/* * chu_audio_receive - receive data from the audio device */static voidchu_audio_receive( struct recvbuf *rbufp /* receive buffer structure pointer */ ){ struct chuunit *up; struct refclockproc *pp; struct peer *peer; double sample; /* codec sample */ u_char *dpt; /* buffer pointer */ int bufcnt; /* buffer counter */ l_fp ltemp; /* l_fp temp */ peer = (struct peer *)rbufp->recv_srcclock; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * Main loop - read until there ain't no more. Note codec * samples are bit-inverted. */ DTOLFP((double)rbufp->recv_length / SECOND, <emp); L_SUB(&rbufp->recv_time, <emp); up->timestamp = rbufp->recv_time; dpt = rbufp->recv_buffer; for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) { sample = up->comp[~*dpt++ & 0xff]; /* * Clip noise spikes greater than MAXSIG. If no clips, * increase the gain a tad; if the clips are too high, * decrease a tad. */ if (sample > MAXSIG) { sample = MAXSIG; up->clipcnt++; } else if (sample < -MAXSIG) { sample = -MAXSIG; up->clipcnt++; } chu_rf(peer, sample); L_ADD(&up->timestamp, &up->tick); /* * Once each second ride gain. */ up->seccnt = (up->seccnt + 1) % SECOND; if (up->seccnt == 0) { pp->second = (pp->second + 1) % 60; chu_gain(peer); } } /* * Set the input port and monitor gain for the next buffer. */ if (pp->sloppyclockflag & CLK_FLAG2) up->port = 2; else up->port = 1; if (pp->sloppyclockflag & CLK_FLAG3) up->mongain = MONGAIN; else up->mongain = 0;}/* * chu_rf - filter and demodulate the FSK signal * * This routine implements a 300-baud Bell 103 modem with mark 2225 Hz * and space 2025 Hz. It uses a bandpass filter followed by a soft * limiter, FM discriminator and lowpass filter. A maximum likelihood * decoder samples the baseband signal at eight times the baud rate and * detects the start bit of each character. * * The filters are built for speed, which explains the rather clumsy * code. Hopefully, the compiler will efficiently implement the move- * and-muiltiply-and-add operations. */static voidchu_rf( struct peer *peer, /* peer structure pointer */ double sample /* analog sample */ ){ struct refclockproc *pp; struct chuunit *up; struct surv *sp; /* * Local variables */ double signal; /* bandpass signal */ double limit; /* limiter signal */ double disc; /* discriminator signal */ double lpf; /* lowpass signal */ double span; /* UART signal span */ double dist; /* UART signal distance */ int i, j; pp = peer->procptr; up = (struct chuunit *)pp->unitptr; /* * Bandpass filter. 4th-order elliptic, 500-Hz bandpass centered * at 2125 Hz. Passband ripple 0.3 dB, stopband ripple 50 dB. */ signal = (up->bpf[8] = up->bpf[7]) * 5.844676e-01; signal += (up->bpf[7] = up->bpf[6]) * 4.884860e-01; signal += (up->bpf[6] = up->bpf[5]) * 2.704384e+00; signal += (up->bpf[5] = up->bpf[4]) * 1.645032e+00; signal += (up->bpf[4] = up->bpf[3]) * 4.644557e+00; signal += (up->bpf[3] = up->bpf[2]) * 1.879165e+00; signal += (up->bpf[2] = up->bpf[1]) * 3.522634e+00; signal += (up->bpf[1] = up->bpf[0]) * 7.315738e-01; up->bpf[0] = sample - signal; signal = up->bpf[0] * 6.176213e-03 + up->bpf[1] * 3.156599e-03 + up->bpf[2] * 7.567487e-03 + up->bpf[3] * 4.344580e-03 + up->bpf[4] * 1.190128e-02 + up->bpf[5] * 4.344580e-03 + up->bpf[6] * 7.567487e-03 + up->bpf[7] * 3.156599e-03 + up->bpf[8] * 6.176213e-03; up->monitor = signal / 4.; /* note monitor after filter */ /* * Soft limiter/discriminator. The 11-sample discriminator lag * interval corresponds to three cycles of 2125 Hz, which * requires the sample frequency to be 2125 * 11 / 3 = 7791.7 * Hz. The discriminator output varies +-0.5 interval for input * frequency 2025-2225 Hz. However, we don't get to sample at * this frequency, so the discriminator output is biased. Life * at 8000 Hz sucks. */ limit = signal; if (limit > LIMIT) limit = LIMIT; else if (limit < -LIMIT) limit = -LIMIT; disc = up->disc[up->discptr] * -limit; up->disc[up->discptr] = limit; up->discptr = (up->discptr + 1 ) % LAG; if (disc >= 0) disc = SQRT(disc); else disc = -SQRT(-disc); /* * Lowpass filter. Raised cosine, Ts = 1 / 300, beta = 0.1. */ lpf = (up->lpf[26] = up->lpf[25]) * 2.538771e-02; lpf += (up->lpf[25] = up->lpf[24]) * 1.084671e-01; lpf += (up->lpf[24] = up->lpf[23]) * 2.003159e-01; lpf += (up->lpf[23] = up->lpf[22]) * 2.985303e-01; lpf += (up->lpf[22] = up->lpf[21]) * 4.003697e-01; lpf += (up->lpf[21] = up->lpf[20]) * 5.028552e-01; lpf += (up->lpf[20] = up->lpf[19]) * 6.028795e-01; lpf += (up->lpf[19] = up->lpf[18]) * 6.973249e-01; lpf += (up->lpf[18] = up->lpf[17]) * 7.831828e-01; lpf += (up->lpf[17] = up->lpf[16]) * 8.576717e-01; lpf += (up->lpf[16] = up->lpf[15]) * 9.183463e-01; lpf += (up->lpf[15] = up->lpf[14]) * 9.631951e-01; lpf += (up->lpf[14] = up->lpf[13]) * 9.907208e-01; lpf += (up->lpf[13] = up->lpf[12]) * 1.000000e+00; lpf += (up->lpf[12] = up->lpf[11]) * 9.907208e-01; lpf += (up->lpf[11] = up->lpf[10]) * 9.631951e-01; lpf += (up->lpf[10] = up->lpf[9]) * 9.183463e-01; lpf += (up->lpf[9] = up->lpf[8]) * 8.576717e-01; lpf += (up->lpf[8] = up->lpf[7]) * 7.831828e-01; lpf += (up->lpf[7] = up->lpf[6]) * 6.973249e-01; lpf += (up->lpf[6] = up->lpf[5]) * 6.028795e-01; lpf += (up->lpf[5] = up->lpf[4]) * 5.028552e-01; lpf += (up->lpf[4] = up->lpf[3]) * 4.003697e-01; lpf += (up->lpf[3] = up->lpf[2]) * 2.985303e-01; lpf += (up->lpf[2] = up->lpf[1]) * 2.003159e-01; lpf += (up->lpf[1] = up->lpf[0]) * 1.084671e-01; lpf += up->lpf[0] = disc * 2.538771e-02; /* * Maximum likelihood decoder. The UART updates each of the * eight survivors and determines the span, slice level and * tentative decoded character. Valid 11-bit characters are * framed so that bit 1 and bit 11 (stop bits) are mark and bit * 2 (start bit) is space. When a valid character is found, the * survivor with maximum distance determines the final decoded * character. */ up->baud += 1. / SECOND; if (up->baud > 1. / (BAUD * 8.)) { up->baud -= 1. / (BAUD * 8.); sp = &up->surv[up->decptr]; span = sp->es_max - sp->es_min; up->maxsignal += (span - up->maxsignal) / 80.; if (up->dbrk > 0) { up->dbrk--; } else if ((sp->uart & 0x403) == 0x401 && span > 1000.) { dist = 0; j = 0; for (i = 0; i < 8; i++) { if (up->surv[i].dist > dist) { dist = up->surv[i].dist; j = i; } } chu_decode(peer, (up->surv[j].uart >> 2) & 0xff); up->dbrk = 80; } up->decptr = (up->decptr + 1) % 8; chu_uart(sp, -lpf * AGAIN); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -