Beispiel #1
0
int Transmitter::init(float centerFrequency, int numSamples) {
	TRACE("Entered Method");
	this->numSamples = numSamples;
	this->centerFrequency = centerFrequency;


	TRACE("Initializing RDS struct");

	if (rdsCallSign.length() > 4) {
		WARN("Call Sign must be 4 characters.  Truncating " << rdsCallSign);
		rdsCallSign.resize(4);
	} else if (rdsCallSign.length() < 4) {
		WARN("Call Sign must be 4 characters.  Prepending with Ws to: " << rdsCallSign);
		while (rdsCallSign.length() < 4) {
			rdsCallSign.insert(0, "W");
		}
	}

	if (rdsShortText.length() > 8) {
		WARN("RDS Short Text cannot be longer than 8 characters.  Truncating");
		rdsShortText.resize(8);
	}

	rds_content.pi = callSignToInt(rdsCallSign);
	set_rds_ps(const_cast<char *> (rdsShortText.c_str()), &rds_content);
	set_rds_rt(const_cast<char *> (rdsFullText.c_str()), &rds_content);

	if (filePath == "") {
		ERROR("File Path to wav file has not been set!");
		return -1;
	}

	TRACE("Opening fm mpx file for " << filePath.string());
    if(fm_mpx_open(const_cast<char *> (filePath.string().c_str()), numSamples, &fm_mpx_status_struct) != 0) {
        ERROR("Could not setup FM mulitplex generator.");
        return -1;
    }

    TRACE("Clearing MPX and output vector buffer and resizing for " << numSamples << " samples");
    mpx_buffer.resize(numSamples, 0);

    basebandCmplx.resize(numSamples, std::complex<float>(0.0,0.0));
    basebandCmplx_polyPhaseout.resize(numSamples, std::complex<float>(0.0,0.0));

    basebandCmplxUpSampled.resize(numSamples*10, std::complex<float>(0.0,0.0));
    basebandCmplxUpSampledTuned.resize(numSamples*10, std::complex<float>(0.0,0.0));
    initialized = true;
	TRACE("Exited Method");
    return 0;
}
Beispiel #2
0
/* Simple test program */
int main(int argc, char **argv) {
    if(argc < 3) {
        fprintf(stderr, "Error: missing argument.\n");
        fprintf(stderr, "Syntax: rds_wav <out.wav> <text>\n");
        return EXIT_FAILURE;
    }
    
    set_rds_pi(0x1234);
    set_rds_ps(argv[2]);
    set_rds_rt(argv[2]);
    
    float buffer[LENGTH];
    
    // Set the format of the output file
    SNDFILE *outf;
    SF_INFO sfinfo;
    sfinfo.frames = LENGTH;
    sfinfo.samplerate = 228000;
    sfinfo.channels = 1;
    sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    sfinfo.sections = 1;
    sfinfo.seekable = 0;
    
    // Open the output file
    if (! (outf = sf_open(argv[1], SFM_WRITE, &sfinfo))) {
        fprintf(stderr, "Error: could not open output file %s.\n", argv[1]) ;
        return EXIT_FAILURE;
    }


    for(int j=0; j<40; j++) {
        get_rds_samples(buffer, LENGTH);

        if(sf_write_float(outf, buffer, LENGTH) != LENGTH) {
            fprintf(stderr, "Error: writing to file %s.\n", argv[1]);
            return EXIT_FAILURE;
        }
    }
    
    if(sf_close(outf) ) {
        fprintf(stderr, "Error: closing file %s.\n", argv[1]);
    }
    
    return EXIT_SUCCESS;
}
Beispiel #3
0
/* Simple test program */
int main(int argc, char **argv) {
    if(argc < 4) {
        fprintf(stderr, "Error: missing argument.\n");
        fprintf(stderr, "Syntax: rds_wav <in_audio.wav> <out_mpx.wav> <text>\n");
        return EXIT_FAILURE;
    }

// YLB Stuff is here
    struct rds_struct rds_status_struct;    
    struct fm_mpx_struct fm_mpx_status_struct;

    fm_mpx_status_struct.phase_38 = 0;
    fm_mpx_status_struct.phase_19 = 0;
    fm_mpx_status_struct.audio_index = 0;
    fm_mpx_status_struct.audio_len = 0;
    fm_mpx_status_struct.fir_index = 0;


    unsigned int i;
    for (i = 0; i < FIR_SIZE; i++) {
        fm_mpx_status_struct.fir_buffer_mono[i] = 0;
        fm_mpx_status_struct.fir_buffer_stereo[i] = 0;
    }


    rds_status_struct.pi = 0x1234;
    set_rds_ps(argv[3], &rds_status_struct);
    set_rds_rt(argv[3], &rds_status_struct);

// Done with YLB stuff

    //set_rds_ps(argv[3]);
    //set_rds_rt(argv[3]);
    
    char *in_file = argv[1];
    if(strcmp("NONE", argv[1]) == 0) in_file = NULL;



//  if(fm_mpx_open(in_file, LENGTH) != 0) {
    if(fm_mpx_open(in_file, LENGTH, &fm_mpx_status_struct) != 0) {
        printf("Could not setup FM mulitplex generator.\n");
        return EXIT_FAILURE;
    }
    

    
    // Set the format of the output file
    SNDFILE *outf;
    SF_INFO sfinfo;

    sfinfo.frames = LENGTH;
    sfinfo.samplerate = 228000;
    sfinfo.channels = 1;
    sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    sfinfo.sections = 1;
    sfinfo.seekable = 0;
    
    // Open the output file
    char *out_file = argv[2];
    if (! (outf = sf_open(out_file, SFM_WRITE, &sfinfo))) {
        fprintf(stderr, "Error: could not open output file %s.\n", out_file);
        return EXIT_FAILURE;
    }

    float mpx_buffer[LENGTH];

    for(int j=0; j<40; j++) {
        if( fm_mpx_get_samples(mpx_buffer, &rds_status_struct, &fm_mpx_status_struct) < 0 ) break;
        
        // scale samples
        for(int i=0; i<LENGTH; i++) {
            mpx_buffer[i] /= 10.;
//            printf("%f, ", mpx_buffer[i]);
        }
        exit(0);

        if(sf_write_float(outf, mpx_buffer, LENGTH) != LENGTH) {
            fprintf(stderr, "Error: writing to file %s.\n", argv[1]);
            return EXIT_FAILURE;
        }
    }
    
    if(sf_close(outf) ) {
        fprintf(stderr, "Error: closing file %s.\n", argv[1]);
    }
    
    fm_mpx_close(&fm_mpx_status_struct);

    return EXIT_SUCCESS;
}
Beispiel #4
0
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, float ppm, char *control_pipe) {
    // Catch all signals possible - it is vital we kill the DMA engine
    // on process exit!
    for (int i = 0; i < 64; i++) {
        struct sigaction sa;

        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = terminate;
        sigaction(i, &sa, NULL);
    }
        
    dma_reg = map_peripheral(DMA_VIRT_BASE, DMA_LEN);
    pwm_reg = map_peripheral(PWM_VIRT_BASE, PWM_LEN);
    clk_reg = map_peripheral(CLK_VIRT_BASE, CLK_LEN);
    gpio_reg = map_peripheral(GPIO_VIRT_BASE, GPIO_LEN);

    // Use the mailbox interface to the VC to ask for physical memory.
    mbox.handle = mbox_open();
    if (mbox.handle < 0)
        fatal("Failed to open mailbox. Check kernel support for vcio / BCM2708 mailbox.\n");
    printf("Allocating physical memory: size = %d     ", NUM_PAGES * 4096);
    if(! (mbox.mem_ref = mem_alloc(mbox.handle, NUM_PAGES * 4096, 4096, MEM_FLAG))) {
        fatal("Could not allocate memory.\n");
    }
    // TODO: How do we know that succeeded?
    printf("mem_ref = %u     ", mbox.mem_ref);
    if(! (mbox.bus_addr = mem_lock(mbox.handle, mbox.mem_ref))) {
        fatal("Could not lock memory.\n");
    }
    printf("bus_addr = %x     ", mbox.bus_addr);
    if(! (mbox.virt_addr = mapmem(BUS_TO_PHYS(mbox.bus_addr), NUM_PAGES * 4096))) {
        fatal("Could not map memory.\n");
    }
    printf("virt_addr = %p\n", mbox.virt_addr);
    

    // GPIO4 needs to be ALT FUNC 0 to output the clock
    gpio_reg[GPFSEL0] = (gpio_reg[GPFSEL0] & ~(7 << 12)) | (4 << 12);

    // Program GPCLK to use MASH setting 1, so fractional dividers work
    clk_reg[GPCLK_CNTL] = 0x5A << 24 | 6;
    udelay(100);
    clk_reg[GPCLK_CNTL] = 0x5A << 24 | 1 << 9 | 1 << 4 | 6;

    ctl = (struct control_data_s *) mbox.virt_addr;
    dma_cb_t *cbp = ctl->cb;
    uint32_t phys_sample_dst = CM_GP0DIV;
    uint32_t phys_pwm_fifo_addr = PWM_PHYS_BASE + 0x18;


    // Calculate the frequency control word
    // The fractional part is stored in the lower 12 bits
    uint32_t freq_ctl = ((float)(PLLFREQ / carrier_freq)) * ( 1 << 12 );


    for (int i = 0; i < NUM_SAMPLES; i++) {
        ctl->sample[i] = 0x5a << 24 | freq_ctl;    // Silence
        // Write a frequency sample
        cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP;
        cbp->src = mem_virt_to_phys(ctl->sample + i);
        cbp->dst = phys_sample_dst;
        cbp->length = 4;
        cbp->stride = 0;
        cbp->next = mem_virt_to_phys(cbp + 1);
        cbp++;
        // Delay
        cbp->info = BCM2708_DMA_NO_WIDE_BURSTS | BCM2708_DMA_WAIT_RESP | BCM2708_DMA_D_DREQ | BCM2708_DMA_PER_MAP(5);
        cbp->src = mem_virt_to_phys(mbox.virt_addr);
        cbp->dst = phys_pwm_fifo_addr;
        cbp->length = 4;
        cbp->stride = 0;
        cbp->next = mem_virt_to_phys(cbp + 1);
        cbp++;
    }
    cbp--;
    cbp->next = mem_virt_to_phys(mbox.virt_addr);

    // Here we define the rate at which we want to update the GPCLK control 
    // register.
    //
    // Set the range to 2 bits. PLLD is at 500 MHz, therefore to get 228 kHz
    // we need a divisor of 500000 / 2 / 228 = 1096.491228
    //
    // This is 1096 + 2012*2^-12 theoretically
    //
    // However the fractional part may have to be adjusted to take the actual
    // frequency of your Pi's oscillator into account. For example on my Pi,
    // the fractional part should be 1916 instead of 2012 to get exactly 
    // 228 kHz. However RDS decoding is still okay even at 2012.
    //
    // So we use the 'ppm' parameter to compensate for the oscillator error

    float divider = (500000./(2*228*(1.+ppm/1.e6)));
    uint32_t idivider = (uint32_t) divider;
    uint32_t fdivider = (uint32_t) ((divider - idivider)*pow(2, 12));
    
    printf("ppm corr is %.4f, divider is %.4f (%d + %d*2^-12) [nominal 1096.4912].\n", 
                ppm, divider, idivider, fdivider);

    pwm_reg[PWM_CTL] = 0;
    udelay(10);
    clk_reg[PWMCLK_CNTL] = 0x5A000006;              // Source=PLLD and disable
    udelay(100);
    // theorically : 1096 + 2012*2^-12
    clk_reg[PWMCLK_DIV] = 0x5A000000 | (idivider<<12) | fdivider;
    udelay(100);
    clk_reg[PWMCLK_CNTL] = 0x5A000216;              // Source=PLLD and enable + MASH filter 1
    udelay(100);
    pwm_reg[PWM_RNG1] = 2;
    udelay(10);
    pwm_reg[PWM_DMAC] = PWMDMAC_ENAB | PWMDMAC_THRSHLD;
    udelay(10);
    pwm_reg[PWM_CTL] = PWMCTL_CLRF;
    udelay(10);
    pwm_reg[PWM_CTL] = PWMCTL_USEF1 | PWMCTL_PWEN1;
    udelay(10);
    

    // Initialise the DMA
    dma_reg[DMA_CS] = BCM2708_DMA_RESET;
    udelay(10);
    dma_reg[DMA_CS] = BCM2708_DMA_INT | BCM2708_DMA_END;
    dma_reg[DMA_CONBLK_AD] = mem_virt_to_phys(ctl->cb);
    dma_reg[DMA_DEBUG] = 7; // clear debug error flags
    dma_reg[DMA_CS] = 0x10880001;    // go, mid priority, wait for outstanding writes

    
    uint32_t last_cb = (uint32_t)ctl->cb;

    // Data structures for baseband data
    float data[DATA_SIZE];
    int data_len = 0;
    int data_index = 0;

    // Initialize the baseband generator
    if(fm_mpx_open(audio_file, DATA_SIZE) < 0) return 1;
    
    // Initialize the RDS modulator
    char myps[9] = {0};
    set_rds_pi(pi);
    set_rds_rt(rt);
    uint16_t count = 0;
    uint16_t count2 = 0;
    int varying_ps = 0;
    
    if(ps) {
        set_rds_ps(ps);
        printf("PI: %04X, PS: \"%s\".\n", pi, ps);
    } else {
        printf("PI: %04X, PS: <Varying>.\n", pi);
        varying_ps = 1;
    }
    printf("RT: \"%s\"\n", rt);
    
    // Initialize the control pipe reader
    if(control_pipe) {
        if(open_control_pipe(control_pipe) == 0) {
            printf("Reading control commands on %s.\n", control_pipe);
        } else {
            printf("Failed to open control pipe: %s.\n", control_pipe);
            control_pipe = NULL;
        }
    }
    
    
    printf("Starting to transmit on %3.1f MHz.\n", carrier_freq/1e6);

    for (;;) {
        // Default (varying) PS
        if(varying_ps) {
            if(count == 512) {
                snprintf(myps, 9, "%08d", count2);
                set_rds_ps(myps);
                count2++;
            }
            if(count == 1024) {
                set_rds_ps("RPi-Live");
                count = 0;
            }
            count++;
        }
        
        if(control_pipe && poll_control_pipe() == CONTROL_PIPE_PS_SET) {
            varying_ps = 0;
        }
        
        usleep(5000);

        uint32_t cur_cb = mem_phys_to_virt(dma_reg[DMA_CONBLK_AD]);
        int last_sample = (last_cb - (uint32_t)mbox.virt_addr) / (sizeof(dma_cb_t) * 2);
        int this_sample = (cur_cb - (uint32_t)mbox.virt_addr) / (sizeof(dma_cb_t) * 2);
        int free_slots = this_sample - last_sample;

        if (free_slots < 0)
            free_slots += NUM_SAMPLES;

        while (free_slots >= SUBSIZE) {
            // get more baseband samples if necessary
            if(data_len == 0) {
                if( fm_mpx_get_samples(data) < 0 ) {
                    terminate(0);
                }
                data_len = DATA_SIZE;
                data_index = 0;
            }
            
            float dval = data[data_index] * (DEVIATION / 10.);
            data_index++;
            data_len--;

            int intval = (int)((floor)(dval));
            //int frac = (int)((dval - (float)intval) * SUBSIZE);


            ctl->sample[last_sample++] = (0x5A << 24 | freq_ctl) + intval; //(frac > j ? intval + 1 : intval);
            if (last_sample == NUM_SAMPLES)
                last_sample = 0;

            free_slots -= SUBSIZE;
        }
        last_cb = (uint32_t)mbox.virt_addr + last_sample * sizeof(dma_cb_t) * 2;
    }

    return 0;
}