diff options
Diffstat (limited to 'src/rds_mod.c')
-rw-r--r-- | src/rds_mod.c | 302 |
1 files changed, 0 insertions, 302 deletions
diff --git a/src/rds_mod.c b/src/rds_mod.c deleted file mode 100644 index 687aa65..0000000 --- a/src/rds_mod.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * RDS Modulator from: - * PiFmRds - FM/RDS transmitter for the Raspberry Pi - * https://github.com/ChristopheJacquet/PiFmRds - * - * Copyright (C) 2014 by Christophe Jacquet, F8FTK - * - * adapted for use with fl2k_fm: - * Copyright (C) 2018 by Steve Markgraf <steve@steve-m.de> - * - * SPDX-License-Identifier: GPL-3.0+ - * - * 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 <time.h> -#include <stdlib.h> - -#define RT_LENGTH 64 -#define PS_LENGTH 8 -#define GROUP_LENGTH 4 - -extern double waveform_biphase[576]; - -struct { - uint16_t pi; - int ta; - char ps[PS_LENGTH+1]; - char rt[RT_LENGTH+1]; -} rds_params = { 0 }; - -/* 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 (1 << 15) -#define BLOCK_SIZE 16 - -#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE+POLY_DEG)) -#define SAMPLES_PER_BIT 192 -#define FILTER_SIZE (sizeof(waveform_biphase)/sizeof(double)) -#define SAMPLE_BUFFER_SIZE (SAMPLES_PER_BIT + FILTER_SIZE) - - -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; - int i, bit, msb; - - for (i = 0; i < BLOCK_SIZE; i++) { - bit = (block & MSB_BIT) != 0; - block <<= 1; - - msb = (crc >> (POLY_DEG-1)) & 1; - crc <<= 1; - - if ((msb ^ bit) != 0) - crc = crc ^ POLY; - } - - return crc; -} - -/* Possibly generates a CT (clock time) group if the minute has just changed - Returns 1 if the CT group was generated, 0 otherwise -*/ -int get_rds_ct_group(uint16_t *blocks) -{ - static int latest_minutes = -1; - int l, mjd, offset; - - // Check time - time_t now; - struct tm *utc; - - now = time(NULL); - utc = gmtime(&now); - - if(utc->tm_min != latest_minutes) { - // Generate CT group - latest_minutes = utc->tm_min; - - l = utc->tm_mon <= 1 ? 1 : 0; - mjd = 14956 + utc->tm_mday + - (int)((utc->tm_year - l) * 365.25) + - (int)((utc->tm_mon + 2 + l*12) * 30.6001); - - blocks[1] = 0x4400 | (mjd>>15); - blocks[2] = (mjd<<1) | (utc->tm_hour>>4); - blocks[3] = (utc->tm_hour & 0xF)<<12 | utc->tm_min<<6; - - utc = localtime(&now); - - //'struct tm' has no member named 'tm_gmtoff' on Windows+MinGW - #if defined(__APPLE__) || defined(__FreeBSD__) - offset = utc->tm_gmtoff / (30 * 60); - #else - offset = time(NULL) / (30 * 60); - #endif - - blocks[3] |= abs(offset); - if (offset < 0) - blocks[3] |= 0x20; - - return 1; - } else { - return 0; - } -} - -/* Creates an RDS group. This generates sequences of the form 0A, 0A, 0A, 0A, 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 (0A) 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 }; - uint16_t block, check; - int i, j; - - // Generate block content - if (!get_rds_ct_group(blocks)) { // CT (clock time) has priority on other group types - if (state < 4) { - blocks[1] = 0x0400 | ps_state; - - if (rds_params.ta) - blocks[1] |= 0x0010; - - blocks[2] = 0xCDCD; // no AF - blocks[3] = rds_params.ps[ps_state*2] << 8 | rds_params.ps[ps_state*2+1]; - ps_state++; - - if (ps_state >= 4) - ps_state = 0; - } else { // state == 5 - blocks[1] = 0x2400 | rt_state; - blocks[2] = rds_params.rt[rt_state*4+0] << 8 | rds_params.rt[rt_state*4+1]; - blocks[3] = rds_params.rt[rt_state*4+2] << 8 | rds_params.rt[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 (i = 0; i < GROUP_LENGTH; i++) { - block = blocks[i]; - check = crc(block) ^ offset_words[i]; - for (j = 0; j < BLOCK_SIZE; j++) { - *buffer++ = ((block & (1 << (BLOCK_SIZE-1))) != 0); - block <<= 1; - } - for (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(double *buffer, uint32_t count) -{ - static int bit_buffer[BITS_PER_GROUP]; - static int bit_pos = BITS_PER_GROUP; - static double sample_buffer[SAMPLE_BUFFER_SIZE] = {0}; - - static int prev_output = 0; - static int cur_output = 0; - static int cur_bit = 0; - static int sample_count = SAMPLES_PER_BIT; - static int inverting = 0; - static int phase = 0; - - static unsigned int in_sample_index = 0; - static unsigned int out_sample_index = SAMPLE_BUFFER_SIZE-1; - - unsigned int i, j, idx; - double val, sample; - double *src; - - for (i = 0; i < count; i++) { - if (sample_count >= SAMPLES_PER_BIT) { - if (bit_pos >= BITS_PER_GROUP) { - get_rds_group(bit_buffer); - bit_pos = 0; - } - - // do differential encoding - cur_bit = bit_buffer[bit_pos]; - prev_output = cur_output; - cur_output = prev_output ^ cur_bit; - - inverting = (cur_output == 1); - - src = waveform_biphase; - idx = in_sample_index; - - for (j = 0; j < FILTER_SIZE; j++) { - val = *src++; - if (inverting) - val = -val; - - sample_buffer[idx++] += val; - - if (idx >= SAMPLE_BUFFER_SIZE) - idx = 0; - } - - in_sample_index += SAMPLES_PER_BIT; - if (in_sample_index >= SAMPLE_BUFFER_SIZE) - in_sample_index -= SAMPLE_BUFFER_SIZE; - - bit_pos++; - sample_count = 0; - } - - sample = sample_buffer[out_sample_index]; - sample_buffer[out_sample_index] = 0; - out_sample_index++; - if (out_sample_index >= SAMPLE_BUFFER_SIZE) - out_sample_index = 0; - - // 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_count++; - } -} - -void set_rds_pi(uint16_t pi_code) -{ - rds_params.pi = pi_code; -} - -void set_rds_rt(char *rt) -{ - int i; - - strncpy(rds_params.rt, rt, 64); - - for (i = 0; i < 64; i++) { - if (rds_params.rt[i] == 0) - rds_params.rt[i] = 32; - } -} - -void set_rds_ps(char *ps) -{ - int i; - - strncpy(rds_params.ps, ps, 8); - - for (i = 0; i < 8; i++) { - if (rds_params.ps[i] == 0) - rds_params.ps[i] = 32; - } -} - -void set_rds_ta(int ta) -{ - rds_params.ta = ta; -} |