int main(int argc, char*argv[])
{
    srand(time(NULL));
    
    // data options
    struct wlan_txvector_s txvector;
    txvector.LENGTH      = 100;
    txvector.DATARATE    = WLANFRAME_RATE_36;
    txvector.SERVICE     = 0;
    txvector.TXPWR_LEVEL = 0;

    // debug options
    int debug_enabled = 0;
    
    // channel options
    float noise_floor = -20.0f;        // noise floor [dB]
    float SNRdB = 20.0f;                // signal-to-noise ratio [dB]
    float phi   = 0.0f;                 // carrier phase offset
    float dphi  = 0.0f;                 // carrier frequency offset

    // get options
    int dopt;
    while((dopt = getopt(argc,argv,"hds:F:n:r:")) != EOF){
        switch (dopt) {
        case 'h': usage();                          return 0;
        case 'd': debug_enabled = 1;                break;
        case 's': SNRdB = atof(optarg);             break;
        case 'F': dphi  = atof(optarg);             break;
        case 'n': txvector.LENGTH = atoi(optarg);   break;
        case 'r':
            switch ( atoi(optarg) ) {
            case 6:  txvector.DATARATE = WLANFRAME_RATE_6;  break;
            case 9:  txvector.DATARATE = WLANFRAME_RATE_9;  break;
            case 12: txvector.DATARATE = WLANFRAME_RATE_12; break;
            case 18: txvector.DATARATE = WLANFRAME_RATE_18; break;
            case 24: txvector.DATARATE = WLANFRAME_RATE_24; break;
            case 36: txvector.DATARATE = WLANFRAME_RATE_36; break;
            case 48: txvector.DATARATE = WLANFRAME_RATE_48; break;
            case 54: txvector.DATARATE = WLANFRAME_RATE_54; break;
            default:
                fprintf(stderr,"error: %s, invalid rate '%s'\n", argv[0], optarg);
                exit(1);
            }
            break;
        default:
            exit(1);
        }
    }

    // validate input
    if (txvector.LENGTH == 0 || txvector.LENGTH > 4095) {
        fprintf(stderr,"error: %s, input vector length must be in [0,4095]\n", argv[0]);
        exit(1);
    }
    
    unsigned int i;

    // initialize original data message
    unsigned char msg_org[txvector.LENGTH];
    for (i=0; i<txvector.LENGTH; i++)
        msg_org[i] = rand() & 0xff;

    float nstd  = powf(10.0f, noise_floor/20.0f);
    float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f);

    // arrays
    float complex buffer[80];   // data buffer

    // create frame generator
    wlanframegen fg = wlanframegen_create();

    // create frame synchronizer
    wlanframesync fs = wlanframesync_create(callback, (void*)msg_org);
    if (debug_enabled)
        wlanframesync_debug_enable(fs);
    //wlanframesync_print(fs);

    // assemble frame and print
    wlanframegen_assemble(fg, msg_org, txvector);
    wlanframegen_print(fg);

    // open output file
    FILE * fid = fopen(OUTPUT_FILENAME,"w");
    if (!fid) {
        fprintf(stderr,"error: %s, could not open '%s' for writing\n", argv[0], OUTPUT_FILENAME);
        exit(1);
    }
    fprintf(fid,"%% %s : auto-generated file\n\n", OUTPUT_FILENAME);
    fprintf(fid,"clear all;\n");
    fprintf(fid,"close all;\n\n");
    fprintf(fid,"x = [];\n");
    unsigned int n = 0;

    // push noise through synchronizer
    unsigned int d = 32*64 + 2;
    for (i=0; i<d; i++) {
        buffer[0] = nstd*( randnf() + _Complex_I*randnf() )*M_SQRT1_2;
        wlanframesync_execute(fs, buffer, 1);
    }

    // generate/synchronize frame
    int last_frame = 0;
    while (!last_frame) {
        // write symbol
        last_frame = wlanframegen_writesymbol(fg, buffer);

        // push through channel (add noise, carrier offset)
        for (i=0; i<80; i++) {
            buffer[i] *= cexpf(_Complex_I*(phi + dphi*n));
            buffer[i] *= gamma;
            buffer[i] += nstd*( randnf() + _Complex_I*randnf() )*M_SQRT1_2;

            // write buffer to file
            fprintf(fid,"x(%4u) = %12.4e + j*%12.4e;\n", n+1, crealf(buffer[i]), cimagf(buffer[i]));

            n++;
        }

        // run through synchronize
        wlanframesync_execute(fs, buffer, 80);
    }

    // plot results
    fprintf(fid,"\n");
    fprintf(fid,"figure;\n");
    fprintf(fid,"t = 0:(length(x)-1);\n");
    fprintf(fid,"plot(t,real(x), t,imag(x));\n");

    fclose(fid);
    printf("results written to '%s'\n", OUTPUT_FILENAME);

    // write debug output if enabled
    if (debug_enabled)
        wlanframesync_debug_print(fs, "wlanframesync_debug.m");

    // destroy objects
    wlanframegen_destroy(fg);
    wlanframesync_destroy(fs);

    printf("done.\n");
    return 0;
}
int wlanframesync_runtest(unsigned int _rate)
{
    srand(time(NULL));
    
    // data options
    unsigned char * msg_org = annexg_G1;
    struct wlan_txvector_s txvector;
    txvector.LENGTH      = 100;
    txvector.DATARATE    = _rate;
    txvector.SERVICE     = 0;
    txvector.TXPWR_LEVEL = 0;
    
#if 0
    // channel options
    float noise_floor = -120.0f;        // noise floor [dB]
    float SNRdB = 20.0f;                // signal-to-noise ratio [dB]
    float phi   = 0.0f;                 // carrier phase offset
    float dphi  = 0.0f;                 // carrier frequency offset
    
    float nstd  = powf(10.0f, noise_floor/20.0f);
    float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f);
#endif

    // arrays
    float complex buffer[80];   // data buffer

    // create frame generator
    wlanframegen fg = wlanframegen_create();

    // initialize test data object
    struct wlanframesync_autotest_s testdata;
    testdata.msg_org    = msg_org;
    testdata.length     = txvector.LENGTH;
    testdata.datarate   = txvector.DATARATE;
    testdata.num_frames = 0;
    testdata.valid      = 1;

    // create frame synchronizer
    wlanframesync fs = wlanframesync_create(callback, (void*)&testdata);
    //wlanframesync_print(fs);

    // assemble frame and print
    wlanframegen_assemble(fg, msg_org, txvector);
    wlanframegen_print(fg);

#if 0
    // push noise through synchronizer
    unsigned int d = 32*64 + 2;
    for (i=0; i<d; i++) {
        buffer[0] = nstd*( randnf() + _Complex_I*randnf() )*M_SQRT1_2;
        wlanframesync_execute(fs, buffer, 1);
    }
#endif

    // generate/synchronize frame
    int last_frame = 0;
    while (!last_frame) {
        // write symbol
        last_frame = wlanframegen_writesymbol(fg, buffer);

#if 0
        // push through channel (add noise, carrier offset)
        for (i=0; i<80; i++) {
            buffer[i] *= cexpf(_Complex_I*(phi + dphi*n));
            buffer[i] *= gamma;
            buffer[i] += nstd*( randnf() + _Complex_I*randnf() )*M_SQRT1_2;
            n++;
        }
#endif

        // run through synchronize
        wlanframesync_execute(fs, buffer, 80);
    }

    // destroy objects
    wlanframegen_destroy(fg);
    wlanframesync_destroy(fs);

    // check results
    if (testdata.num_frames == 0) {
        fprintf(stderr,"wlanframesync_autotest: no frames detected!\n");
        testdata.valid = 0;
    }

    if (!testdata.valid) {
        fprintf(stderr,"fail: %s, synchronization failure (rate = %u)\n", __FILE__, _rate);
        exit(1);
    }
    
    return 0;
}