int main(int argc, char **argv) { int i, p, act; struct hardware hw; if (set_mode(0, NULL, NULL)) { cleanup(); return 0; } (void)read_hardware_parameters("hardware.txt", &hw); /* get our own copy, error handling in set_mode() */ printf("%i\n", (int)(hw.freq * hw.min_len / 100)); for (i = act = 0;; i++) { p = get_pulse(); if (p & GETBIT_IO) { printf("IO error!\n"); break; } act += p; printf("%c", p == 1 ? '+' : ' '); if (i == (int)(hw.freq * hw.min_len / 100)) { printf(" %lu\n", act*hw.freq/hw.min_len); i = act = 0; } (void)usleep(1000000.0 / hw.freq); } cleanup(); return 0; }
int main(int argc, char **argv) { struct tap tapin, tapout; FILE *infile; long pulse; getopts(argc, argv); if (optind == argc) { infile = stdin; } else if (optind == argc - 1) { if (!strcmp(argv[optind], "-")) { infile = stdin; } else { infile = fopen(argv[optind], "rb"); if (!infile) { perror(argv[optind]); return 1; } } } else { fprintf(stderr, "%s: too many arguments\n", argv0); usage(); return 1; } if (tap_read_header(&tapin, infile)) { fprintf(stderr, "%s: error reading TAP file\n", argv0); return 1; } if (outversion < 0) tapout.version = tapin.version; else tapout.version = outversion; if (tap_write_header(&tapout, stdout)) { fprintf(stderr, "%s: error writing TAP file\n", argv0); return 1; } while ((pulse = get_pulse(&tapin)) >= 0) { if (tapin.version == 0 && pulse == V0_LONG_PULSE) { pulse = LONG_PULSE; } pulse /= speed; put_pulse(pulse, &tapout); } tap_close(&tapout); return 0; }
/* * The bits are decoded from the signal using an exponential low-pass filter in * conjunction with a Schmitt trigger. The idea and the initial implementation * for this come from Udo Klein, with permission. * http://blog.blinkenlight.net/experiments/dcf77/binary-clock/#comment-5916 */ struct GB_result get_bit_live(void) { char outch; bool newminute = false; unsigned stv = 1; int p; struct timespec slp; #if !defined(MACOS) struct timespec tp0, tp1; #endif unsigned sec2; long long a, y = 1000000000; long long twait; static int init_bit = 2; bool is_eom = gb_res.marker == emark_minute || gb_res.marker == emark_late; bit.freq_reset = false; bit.bitlen_reset = false; set_new_state(); /* * One period is either 1000 ms or 2000 ms long (normal or padding for * last). The active part is either 100 ms ('0') or 200 ms ('1') long. * The maximum allowed values as percentage of the second length are * specified as half the value and the whole value of the lengths of * bit 0 and bit 20 respectively. * * ~A > 3/2 * realfreq: end-of-minute * ~A > 5/2 * realfreq: timeout */ if (init_bit == 2) { bit.realfreq = hw.freq * 1000000; bit.bit0 = bit.realfreq / 10; bit.bit20 = bit.realfreq / 5; } sec2 = 1000000000 / (hw.freq * hw.freq); /* * Set up filter, reach 50% after realfreq/20 samples (i.e. 50 ms) */ a = 1000000000 - (long long)(1000000000 * exp2(-2e7 / bit.realfreq)); bit.tlow = -1; bit.tlast0 = -1; for (bit.t = 0; bit.t != 0xFFFFFFFF; bit.t++) { #if !defined(MACOS) (void)clock_gettime(CLOCK_MONOTONIC, &tp0); #endif p = get_pulse(); if (p == 2) { gb_res.bad_io = true; outch = '*'; goto report; } if (bit.signal != NULL) { if ((bit.t & 7) == 0) bit.signal[bit.t / 8] = 0; /* clear data from previous second */ bit.signal[bit.t / 8] |= p << (unsigned char)(bit.t & 7); } if (y >= 0 && y < a / 2) bit.tlast0 = (int)bit.t; y += a * (p * 1000000000 - y) / 1000000000; /* * Prevent algorithm collapse during thunderstorms * or scheduler abuse */ if (bit.realfreq <= hw.freq * 500000 || bit.realfreq >= hw.freq * 1500000) reset_frequency(); if (bit.t > bit.realfreq * 2500000) { bit.realfreq += ((long long) (bit.t * 2500000 - bit.realfreq) / 20); a = 1000000000 - (long long)(1000000000 * exp2(-2e7 / bit.realfreq)); if (bit.tlow * 100 / bit.t < 1) { gb_res.hwstat = ehw_receive; outch = 'r'; } else if (bit.tlow * 100 / bit.t >= 99) { gb_res.hwstat = ehw_transmit; outch = 'x'; } else { gb_res.hwstat = ehw_random; outch = '#'; } goto report; /* timeout */ } /* * Schmitt trigger, maximize value to introduce * hysteresis and to avoid infinite memory. */ if (y < 500000000 && stv == 1) { /* end of high part of second */ y = 0; stv = 0; bit.tlow = (int)bit.t; } if (y > 500000000 && stv == 0) { /* end of low part of second */ y = 1000000000; stv = 1; newminute = bit.t * 2000000 > bit.realfreq * 3; if (init_bit == 2) init_bit--; else { if (newminute) bit.realfreq += ((long long)(bit.t * 500000 - bit.realfreq) / 20); else bit.realfreq += ((long long)(bit.t * 1000000 - bit.realfreq) / 20); a = 1000000000 - (long long)(1000000000 * exp2(-2e7 / bit.realfreq)); } if (newminute) { /* * Reset the frequency and the EOM flag if two * consecutive EOM markers come in, which means * something is wrong. */ if (is_eom) { if (gb_res.marker == emark_minute) gb_res.marker = emark_none; else if (gb_res.marker == emark_late) gb_res.marker = emark_toolong; reset_frequency(); } else { if (gb_res.marker == emark_none) gb_res.marker = emark_minute; else if (gb_res.marker == emark_toolong) gb_res.marker = emark_late; } } break; /* start of new second */ } twait = (long long)(sec2 * bit.realfreq / 1000000); #if !defined(MACOS) (void)clock_gettime(CLOCK_MONOTONIC, &tp1); twait = twait - (tp1.tv_sec - tp0.tv_sec) * 1000000000 - (tp1.tv_nsec - tp0.tv_nsec); #endif slp.tv_sec = twait / 1000000000; slp.tv_nsec = twait % 1000000000; while (twait > 0 && nanosleep(&slp, &slp)) ; } if (2 * bit.realfreq * bit.tlow * (1 + (newminute ? 1 : 0)) < (bit.bit0 + bit.bit20) * bit.t) { /* zero bit, ~100 ms active signal */ gb_res.bitval = ebv_0; outch = '0'; buffer[bitpos] = 0; } else if (bit.realfreq * bit.tlow * (1 + (newminute ? 1 : 0)) < (bit.bit0 + bit.bit20) * bit.t) { /* one bit, ~200 ms active signal */ gb_res.bitval = ebv_1; outch = '1'; buffer[bitpos] = 1; } else { /* bad radio signal, retain old value */ gb_res.bitval = ebv_none; outch = '_'; /* force bit 20 to be 1 to recover from too low b20 value */ if (bitpos == 20) { gb_res.bitval = ebv_1; outch = '1'; buffer[20] = 1; } } if (init_bit == 1) init_bit--; else if (gb_res.hwstat == ehw_ok && gb_res.marker == emark_none) { if (bitpos == 0 && gb_res.bitval == ebv_0) bit.bit0 += ((long long) (bit.tlow * 1000000 - bit.bit0) / 2); if (bitpos == 20 && gb_res.bitval == ebv_1) bit.bit20 += ((long long) (bit.tlow * 1000000 - bit.bit20) / 2); /* During a thunderstorm the value of bit20 might underflow */ if (bit.bit20 < bit.bit0) reset_bitlen(); } report: acc_minlen += 1000000 * bit.t / (bit.realfreq / 1000); if (logfile != NULL) { fprintf(logfile, "%c", outch); if (gb_res.marker == emark_minute || gb_res.marker == emark_late) fprintf(logfile, "a%uc%6.4f\n", acc_minlen, (double)((bit.t * 1e6) / bit.realfreq)); } if (gb_res.marker == emark_minute || gb_res.marker == emark_late) cutoff = bit.t * 1000000 / (bit.realfreq / 10000); return gb_res; }
int main(int argc, char *argv[]) { struct sigaction sigact; struct hardware hw; int ch, min, res; bool raw = false, verbose = true; while ((ch = getopt(argc, argv, "qr")) != -1) { switch (ch) { case 'q' : verbose = false; break; case 'r' : raw = true; break; default: printf("usage: %s [-qr]\n", argv[0]); return EX_USAGE; } } res = read_config_file(ETCDIR"/config.txt"); if (res != 0) { cleanup(); return res; } res = set_mode_live(); if (res != 0) { cleanup(); return res; } hw = get_hardware_parameters(); sigact.sa_handler = do_cleanup; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(SIGINT, &sigact, (struct sigaction *)NULL); min = -1; for (;;) { struct bitinfo bi; struct GB_result bit; if (raw) { struct timespec slp; slp.tv_sec = 1.0 / hw.freq; slp.tv_nsec = 1e9 / hw.freq; printf("%i", get_pulse()); fflush(stdout); while (nanosleep(&slp, &slp)) ; continue; } bit = get_bit_live(); bi = get_bitinfo(); if (verbose) { if (bi.freq_reset) printf("!"); /* display first bi->t pulses */ for (unsigned long long i = 0; i < bi.t / 8; i++) for (unsigned j = 0; j < 8; j++) printf("%c", (bi.signal[i] & (1 << j)) > 0 ? '+' : '-'); /* * display pulses in the last partially filled item * bi.t is 0-based, hence the <= comparison */ for (unsigned j = 0; j <= (bi.t & 7); j++) printf("%c", (bi.signal[bi.t / 8] & (1 << j)) > 0 ? '+' : '-'); printf("\n"); } if (bit.marker == emark_toolong || bit.marker == emark_late) min++; printf("%i %i %u %llu %llu %llu %i:%i\n", bi.tlow, bi.tlast0, bi.t, bi.bit0, bi.bit20, bi.realfreq, min, get_bitpos()); if (bit.marker == emark_minute) min++; bit = next_bit(); } /* NOTREACHED */ }