static int write_header(avro_file_writer_t w) { int rval; uint8_t version = 1; /* TODO: remove this static buffer */ avro_writer_t schema_writer; char schema_buf[64 * 1024]; const avro_encoding_t *enc = &avro_binary_encoding; /* Generate random sync */ generate_sync(w); check(rval, avro_write(w->writer, "Obj", 3)); check(rval, avro_write(w->writer, &version, 1)); check(rval, enc->write_long(w->writer, 3)); check(rval, enc->write_string(w->writer, "avro.sync")); check(rval, enc->write_bytes(w->writer, w->sync, sizeof(w->sync))); check(rval, enc->write_string(w->writer, "avro.codec")); check(rval, enc->write_bytes(w->writer, "null", 4)); check(rval, enc->write_string(w->writer, "avro.schema")); schema_writer = avro_writer_memory(schema_buf, sizeof(schema_buf)); rval = avro_schema_to_json(w->writers_schema, schema_writer); if (rval) { avro_writer_free(schema_writer); return rval; } check(rval, enc->write_bytes(w->writer, schema_buf, avro_writer_tell(schema_writer))); check(rval, enc->write_long(w->writer, 0)); return write_sync(w); }
int main(int argc,char *argv[]){ unsigned char data[FRAMEBITS/8]; // One minor frame unsigned char symbols[2*FRAMEBITS]; unsigned char nsymbols[2*FRAMEBITS]; int i,fd; char *filename; struct stat statbuf; off_t length; short *samples; int nsamples; int start; int startsync = SYNC_FAIL,endsync = SYNC_FAIL; void *vd; // Viterbi decoder handle int symerrors; int firstsample; int frame; int begin; int maxmetric,minmetric; int ind; char *locale; double clock_tolerance = 5; // Maximum allowable clock offset, samples/frame if((locale = getenv("LANG")) != NULL) setlocale(LC_ALL,locale); else setlocale(LC_ALL,"en_US.utf8"); begin = 0; while((i = getopt(argc,argv,"c:o:r:t:")) != EOF){ switch(i){ case 't': clock_tolerance = atof(optarg); break; case 'c': Symrate = atof(optarg); break; case 'r': Samprate = atof(optarg); break; case 'o': begin = atoi(optarg); // Starting sample, default 0 break; } } Symbolsamples = Samprate/Symrate; Framesamples = Symbolsamples * 2*FRAMEBITS; // Read baseband samples, downsampled to Samprate (important!) and look for sync vector filename = argv[optind]; if(lstat(filename,&statbuf) == -1){ fprintf(stderr,"lstat(%s) failed: %s\n",filename,strerror(errno)); exit(1); } if(!S_ISREG(statbuf.st_mode)){ fprintf(stderr,"%s is not an ordinary file\n",filename); exit(1); } length = statbuf.st_size; if((fd = open(filename,O_RDONLY)) == -1){ fprintf(stderr,"open(%s,readonly) failed; %s\n",filename,strerror(errno)); exit(1); } if((samples = mmap(NULL,length,PROT_READ,MAP_SHARED,fd,0)) == MAP_FAILED){ fprintf(stderr,"mmap(%s,%lld) failed: %s\n",filename, (long long)length,strerror(errno)); close(fd); exit(1); } nsamples = length / sizeof(*samples); printf("%s: %'d samples, %'.3lf seconds @ %.1lf Hz\n",filename, nsamples,nsamples/Samprate,Samprate); generate_sync(Symrate); vd = create_viterbi224(FRAMEBITS); if(vd == NULL){ fprintf(stderr,"Can't create viterbi decoder\n"); exit(2); } for(frame=1;begin + Framesamples < nsamples;frame++){ int low,high; // Look for starting frame sync if(startsync == SYNC_FAIL){ // No endsync from previous frame, find initial sync while(1){ startsync = fft_sync_search(&samples[begin],0,(int)Framesamples,begin); if(startsync != SYNC_FAIL){ startsync += begin; break; } begin += Framesamples; // Skip a frame time and try again printf("Start sync search failure, skip to %'d\n",begin); } } assert(startsync != SYNC_FAIL); // Look for ending frame sync // Start halfway through the frame, but actually search the middle // of the result, which straddles the next sync. Only search in the // allowable range to keep the clock from being driven into the weeds by noise while(1){ start = startsync + Framesamples/2; low = 0.5 * Framesamples - clock_tolerance; // very tight tolerance, +/- 5 samples high = 0.5 * Framesamples + clock_tolerance; endsync = fft_sync_search(&samples[start],low,high,-1); if(endsync != SYNC_FAIL){ endsync += start; break; } // Go back to look for another start sync begin = startsync + Framesamples; printf("End sync search failure, skip to %'d\n",begin); startsync = SYNC_FAIL; goto again; } // Got both start and end sync, proceed i = startsync/Samprate; printf("Frame %'d @ sample %'d (%'d:%02d)\n",frame,startsync,i/60,i % 60); // Update estimate of sample clock rate et al #if 0 // Hack - not let it change Framesamples = endsync - startsync; // Actual samples in current frame (int) Symbolsamples = Framesamples/(2*FRAMEBITS); // Actual samples in symbol (float) Symrate = Samprate / Symbolsamples; #endif printf("Symbol rate: %'.3lf Hz; samples/sym: %'.3lf; samples/frame: %'.1lf\n", Symrate,Symbolsamples,Framesamples); #if 0 // If clock estimate has changed a lot, regenerate the sync vector with the new clock if(abs(SYNCBITS*Samprate/Symrate - Synclen) > Symbolsamples/10.){ printf("Clock changed; regenerate sync\n"); generate_sync(Symrate); } #endif // startsync points to the first symbol in the 34-bit sync sequence, // so we want to skip past it to the first symbol in the new frame firstsample = SYNCBITS*Symbolsamples + startsync; for(i=0; i < 2*FRAMEBITS; i++){ double sum; int midpoint,last; ind = firstsample + i * Symbolsamples; midpoint = firstsample + (i+0.5)*Symbolsamples; last = firstsample + (i+1.0)*Symbolsamples; // Integrate bit, remove manchester sum = 0; for(;ind < midpoint;ind++) // first half of symbol sum -= samples[ind]; for(; ind < last;ind++) sum += samples[ind]; sum += 128; // Offset-128 for Viterbi decoder symbols[i] = (sum > 255) ? 255 : ((sum < 0) ? 0 : sum); // Clip to range 0-255 } // We start with the encoder having just transmitted these five fixed bytes, // 3 bytes of coder dump and 2 bytes of sync: // 12 fc 81 9f be init_viterbi224(vd,0x819fbe); update_viterbi224_blk(vd,symbols,FRAMEBITS); chainback_viterbi224(vd,data,FRAMEBITS,0x819fbe); maxmetric = max_metric_viterbi224(vd); minmetric = min_metric_viterbi224(vd); for(i=0; i<128; i++){ printf("%02x",data[i]); if((i % 16) == 15) putchar('\n'); else putchar(' '); } // Re-encode and compare to received symbols to count channel errors encode(nsymbols,data,FRAMEBITS/8,0x819fbe); symerrors = 0; for(i=0;i<2*FRAMEBITS;i++){ if(nsymbols[i] != (symbols[i] > 128)){ symerrors++; #if 0 printf("sym error %d: %d != %d\n",i,nsymbols[i],symbols[i]); #endif } } printf("Viterbi path metric range %'d - %'d, diff %'d\n",minmetric,maxmetric,maxmetric-minmetric); if(symerrors){ double esn0; esn0 = erfc1(2.*symerrors/(2*FRAMEBITS)); // Amplitude ratio esn0 *= esn0; // square to get power ratio // ebn0 = 2 * esn0 for rate 1/2 code printf("re-encode symbol errors: %'d/%'d; estimated Eb/No = %.2lf dB\n", symerrors,2*FRAMEBITS,10*log10(2*esn0)); } else { printf("No re-encode symbol errors; estimated Eb/No > %.2lf dB\n",10.5); // hack; 7.5 dB has a BER < 1/2048 } putchar('\n'); fflush(stdout); startsync = endsync; again:; } delete_viterbi224(vd); exit(0); }