F5OEO-PiFmRds/src/rds.c

184 wiersze
5.5 KiB
C

/*
PiFmRds - FM/RDS transmitter for the Raspberry Pi
Copyright (C) 2014 Christophe Jacquet, F8FTK
See https://github.com/ChristopheJacquet/PiFmRds
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "waveforms.h"
#define MAX_TEXT_LENGTH 64
#define GROUP_LENGTH 4
struct {
char text[MAX_TEXT_LENGTH];
uint16_t pi;
} rds_params;
/* The RDS error-detection code generator polynomial is
x^10 + x^8 + x^7 + x^5 + x^4 + x^3 + x^0
*/
#define POLY 0x1B9
#define POLY_DEG 10
#define MSB_BIT 0x8000
#define BLOCK_SIZE 16
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE+POLY_DEG))
#define SAMPLES_PER_BIT 192
uint16_t offset_words[] = {0x0FC, 0x198, 0x168, 0x1B4};
// We don't handle offset word C' here for the sake of simplicity
/* Classical CRC computation */
uint16_t crc(uint16_t block) {
uint16_t crc = 0;
for(int j=0; j<BLOCK_SIZE; j++) {
int bit = (block & MSB_BIT) != 0;
block <<= 1;
int msb = (crc >> (POLY_DEG-1)) & 1;
crc <<= 1;
if((msb ^ bit) != 0) {
crc = crc ^ POLY;
}
}
return crc;
}
/* Creates an RDS group. This generates sequences of the form 0B, 0B, 0B, 0B, 2A, etc.
The pattern is of length 5, the variable 'state' keeps track of where we are in the
pattern. 'ps_state' and 'rt_state' keep track of where we are in the PS (0B) sequence
or RT (2A) sequence, respectively.
*/
void get_rds_group(int *buffer) {
static int state = 0;
static int ps_state = 0;
static int rt_state = 0;
uint16_t blocks[GROUP_LENGTH] = {rds_params.pi, 0, 0, 0};
// Generate block content
if(state < 4) {
blocks[1] = 0x0000 | ps_state;
blocks[2] = 0xCDCD; // no AF
blocks[3] = rds_params.text[ps_state*2]<<8 | rds_params.text[ps_state*2+1];
ps_state++;
if(ps_state >= 4) ps_state = 0;
} else { // state == 5
blocks[1] = 0x2000 | rt_state;
blocks[2] = rds_params.text[rt_state*4+0]<<8 | rds_params.text[rt_state*4+1];
blocks[3] = rds_params.text[rt_state*4+2]<<8 | rds_params.text[rt_state*4+3];
rt_state++;
if(rt_state >= 16) rt_state = 0;
}
state++;
if(state >= 5) state = 0;
// Calculate the checkword for each block and emit the bits
for(int i=0; i<GROUP_LENGTH; i++) {
uint16_t block = blocks[i];
uint16_t check = crc(block) ^ offset_words[i];
for(int j=0; j<BLOCK_SIZE; j++) {
*buffer++ = ((block & (1<<(BLOCK_SIZE-1))) != 0);
block <<= 1;
}
for(int j=0; j<POLY_DEG; j++) {
*buffer++= ((check & (1<<(POLY_DEG-1))) != 0);
check <<= 1;
}
}
}
/* Get a number of RDS samples. This generates the envelope of the waveform using
pre-generated elementary waveform samples, and then it amplitude-modulates the
envelope with a 57 kHz carrier, which is very efficient as 57 kHz is 4 times the
sample frequency we are working at (228 kHz).
*/
void get_rds_samples(float *buffer, int count) {
static int bit_buffer[BITS_PER_GROUP];
static int bit_pos = BITS_PER_GROUP;
static int prev_output = 0;
static int cur_output = 0;
static int prev_bit = 0;
static int cur_bit = 0;
static int sample_pos = SAMPLES_PER_BIT;
static float *current_waveform = NULL;
static int inverting = 0;
static int phase = 0;
for(int i=0; i<count; i++) {
if(sample_pos >= SAMPLES_PER_BIT) {
if(bit_pos >= BITS_PER_GROUP) {
get_rds_group(bit_buffer);
bit_pos = 0;
}
// do differential encoding
prev_bit = cur_bit;
cur_bit = bit_buffer[bit_pos];
prev_output = cur_output;
cur_output = prev_output ^ cur_bit;
// select appropriate waveform
current_waveform = (prev_output == cur_output) ?
waveform_identical : waveform_different;
inverting = (prev_output == 0) ? 1 : -1;
bit_pos++;
sample_pos = 0;
//printf("%d", cur_bit); fflush(stdout);
}
float sample = current_waveform[sample_pos] * inverting;
// modulate at 57 kHz
// use phase for this
switch(phase) {
case 0:
case 2: sample = 0; break;
case 1: break;
case 3: sample = -sample; break;
}
phase++;
if(phase >= 4) phase = 0;
*buffer++ = sample;
sample_pos++;
}
}
/* Simple test program */
int main(int argc, char **argv) {
rds_params.pi = 0x1234;
strncpy(rds_params.text, "Hello", 64);
float buffer[300000];
get_rds_samples(buffer, 300000);
for(int i=0; i<300000; i++) {
printf("%c", (((int)(buffer[i]*50))));
}
}