#include #include #include #include #include void showstats(); uint8_t getbit(); void checkbit(uint8_t bit); void printhelp(); void corrupt_stream(); void corrupt_stream2(); void corrupt_bit(uint8_t bit); uint16_t scrambleLFSR=0; //Shorter is better: The shorter the LSFR, the quicker it can recover from errors. uint32_t errcount=0,bitcount=0; uint32_t recbytes=0; float corrupt_prob=0.01; //Used in test2 mode. uint8_t msbfirst=0; int main(int argc, char *argv[]){ uint8_t transmit=0; //If false, assume receive mode. uint32_t n=0,showevery=256; for(n=0;n>7); checkbit((in&0x40)>>6); checkbit((in&0x20)>>5); checkbit((in&0x10)>>4); checkbit((in&0x08)>>3); checkbit((in&0x04)>>2); checkbit((in&0x02)>>1); checkbit((in&0x01) ); recbytes++; if(recbytes==showevery) showstats(); }while(1); else do{ uint8_t in=getchar(); if(feof(stdin)) break; checkbit((in&0x01) ); checkbit((in&0x02)>>1); checkbit((in&0x04)>>2); checkbit((in&0x08)>>3); checkbit((in&0x10)>>4); checkbit((in&0x20)>>5); checkbit((in&0x40)>>6); checkbit((in&0x80)>>7); recbytes++; if(recbytes==showevery) showstats(); }while(1); } void corrupt_stream(){ if(msbfirst){ fprintf(stderr,"Berty: Error, -msb specified but test mode does not support -msb.\n"); return; } uint16_t counter=0; do{ uint8_t abyte=getchar(); if(feof(stdin)) break; if(!(counter++%512)) abyte=abyte^0x01; putchar(abyte); }while(1); } void corrupt_stream2(){ if(msbfirst){ fprintf(stderr,"Berty: Error, -msb specified but test mode does not support -msb.\n"); return; } do{ uint8_t in=getchar(); if(feof(stdin)) break; corrupt_bit((in&0x01)<<7); corrupt_bit((in&0x02)<<6); corrupt_bit((in&0x04)<<5); corrupt_bit((in&0x08)<<4); corrupt_bit((in&0x10)<<3); corrupt_bit((in&0x20)<<2); corrupt_bit((in&0x40)<<1); corrupt_bit((in&0x80) ); }while(1); } uint8_t output_bit_counter=0; uint8_t shiftregister; void corrupt_bit(uint8_t bit){ float p=((float)rand())/RAND_MAX; //0 to 1 if(corrupt_prob>p){ p=((float)rand())/RAND_MAX; if(p<0.90) bit=!bit; //Corrupt this bit. if(p<0.95) return; //Drop this bit. else corrupt_bit(bit); //Duplicate this bit. } shiftregister=(shiftregister>>1)|bit; output_bit_counter++; if(output_bit_counter==8){ output_bit_counter=0; putchar(shiftregister); } } void showstats(){ printf("Got %u bits, %u errs. BER %f\n", bitcount, errcount, errcount/(float)bitcount); recbytes=0;errcount=0;bitcount=0; fflush(stdout); } uint8_t getbit(){ /* Relic of testing using the V34 scrambler. Turned out a much shorter one is better. uint32_t bits=scrambleLFSR&0x00420000; scrambleLFSR=scrambleLFSR<<1; uint8_t newbit=1; if(bits==0x00400000 || bits==0x00020000) newbit=0; else scrambleLFSR=scrambleLFSR|1; */ uint16_t bits=scrambleLFSR&0x0042; scrambleLFSR=scrambleLFSR<<1; uint8_t newbit=1; if(bits==0x0040 || bits==0x0002) newbit=0; else scrambleLFSR=scrambleLFSR|1; return(newbit); } uint8_t skip=0; void checkbit(uint8_t bit){ uint16_t bits=scrambleLFSR&0x0042; scrambleLFSR=(scrambleLFSR<<1)|bit; if(bits==0x0040 || bits==0x0002) bit=!bit; if(skip){ skip--; }else{ bitcount++; if(!bit){ errcount++; skip=7; //Prevents error-multiplication effect of the scrambler and propagation of bit dup/skip errors. } } } void printhelp(){ printf("Berty is a very simple utility for conducting Bit Error Ratio tests. It does this by using a linear feedback shift register to form a self-syncronising scrambler fed using an all-ones sequence. The resulting pseudorandom sequence can then be sent over a communication channel under test. At the receiving end another instance of berty then receives the stream, carries out the other half of the self-syncronising scrambler, and counts the 'zero' symbols - each of which indicates a single bit error. The BER is then calculated from these. It's not perfectly accurate - it has to ignore 24 bits following any error to allow for resyncronisation - but it's probably the best you'll get without out-of-channel syncronisation.\n In addition to measuring bit error rate, it can act as a simulated noisy channel in order to test error detection and correction protocols. This function will operate only in LSB-first mode.\n"); printf("Berty was designed as testing tool for use in the design and optimisation of audio-frequency modems for use in amateur radio, but may be applied to any bit-orientated communications channel.\n\n"); printf(" -t Transmit mode - default is receive.\n -msb Send/receive bytes msb-first - default is lsb-first)\n -n Show statistics every 8*n received bits. Default is 256, or 2Kib.\n -test1 Test mode - input to output, but corrupting every 300th bit.\n -test2

Another test mode, a bit more aggressive - it'll randomly flip, drop or duplicate bits, with flips being ten times more common than duplications and drops combined - a simplistic but reasonable model of a noisy channel. The p parameter, 0-1, sets the probability of an error - 0.1 is a very poor channel.\n\nTo test berty, simply pipe one instance into another via the data-corrupting test mode: \"berty -t|berty -test1|berty\" - the simulated channel should read a single error in every other block.\n\nBerty is a bit error ratio tester, not a byte tester - if you are using byte-orientated communication channel, you will receive more accurate results if you disable byte-boundry syncronisation features when possible. On minimodem, this is done with \"--startbits 0 --stopbits 0.0\"\n"); exit(1); }