mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-02-26 20:33:53 +01:00
add rt timeout, clean up code, add error checking for rdsencoder save, add rds eon af and remove stale values
This commit is contained in:
2
.vscode/.server-controller-port.log
vendored
2
.vscode/.server-controller-port.log
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"port": 13452,
|
||||
"time": 1743622887495,
|
||||
"time": 1743850931238,
|
||||
"version": "0.0.3"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(rds95 VERSION 1.2)
|
||||
project(rds95 VERSION 1.3)
|
||||
|
||||
add_compile_options(-Wall -Werror -Wextra -pedantic -O2 -std=c18 -march=native -DVERSION=\"${PROJECT_VERSION}\")
|
||||
|
||||
|
||||
139
gen_wave.py
139
gen_wave.py
@@ -4,7 +4,7 @@ FFT = PLOT and True
|
||||
import math
|
||||
import io, os
|
||||
if PLOT: import matplotlib.pyplot as plt
|
||||
if FFT: import numpy as np # Import numpy for FFT
|
||||
if FFT: import numpy as np
|
||||
|
||||
DATA_RATE = 1187.5
|
||||
SIZE_RATIO = 2
|
||||
@@ -16,33 +16,33 @@ if not sample_rate.is_integer(): raise ValueError("Need a even value")
|
||||
|
||||
# this is modified from ChristopheJacquet's pydemod
|
||||
def rrcosfilter(NumSamples):
|
||||
T_delta = 1/float(sample_rate)
|
||||
sample_num = list(range(NumSamples))
|
||||
h_rrc = [0.0] * NumSamples
|
||||
SymbolPeriod = 1/(2*DATA_RATE)
|
||||
T_delta = 1/float(sample_rate)
|
||||
sample_num = list(range(NumSamples))
|
||||
h_rrc = [0.0] * NumSamples
|
||||
SymbolPeriod = 1/(2*DATA_RATE)
|
||||
|
||||
for x in sample_num:
|
||||
t = (x-NumSamples/2)*T_delta
|
||||
if t == 0.0:
|
||||
h_rrc[x] = 1.0 - 1 + (4/math.pi)
|
||||
elif t == SymbolPeriod/4:
|
||||
h_rrc[x] = (1/math.sqrt(2))*(((1+2/math.pi)* \
|
||||
(math.sin(math.pi/4))) + ((1-2/math.pi)*(math.cos(math.pi/4))))
|
||||
elif t == -SymbolPeriod/4:
|
||||
h_rrc[x] = (1/math.sqrt(2))*(((1+2/math.pi)* \
|
||||
(math.sin(math.pi/4))) + ((1-2/math.pi)*(math.cos(math.pi/4))))
|
||||
else:
|
||||
h_rrc[x] = (4*(t/SymbolPeriod)*math.cos(math.pi*t*2/SymbolPeriod))/ \
|
||||
(math.pi*t*(1-(4*t/SymbolPeriod)*(4*t/SymbolPeriod))/SymbolPeriod)
|
||||
for x in sample_num:
|
||||
t = (x-NumSamples/2)*T_delta
|
||||
if t == 0.0:
|
||||
h_rrc[x] = 1.0 - 1 + (4/math.pi)
|
||||
elif t == SymbolPeriod/4:
|
||||
h_rrc[x] = (1/math.sqrt(2))*(((1+2/math.pi)* \
|
||||
(math.sin(math.pi/4))) + ((1-2/math.pi)*(math.cos(math.pi/4))))
|
||||
elif t == -SymbolPeriod/4:
|
||||
h_rrc[x] = (1/math.sqrt(2))*(((1+2/math.pi)* \
|
||||
(math.sin(math.pi/4))) + ((1-2/math.pi)*(math.cos(math.pi/4))))
|
||||
else:
|
||||
h_rrc[x] = (4*(t/SymbolPeriod)*math.cos(math.pi*t*2/SymbolPeriod))/ \
|
||||
(math.pi*t*(1-(4*t/SymbolPeriod)*(4*t/SymbolPeriod))/SymbolPeriod)
|
||||
|
||||
return h_rrc
|
||||
return h_rrc
|
||||
|
||||
def convolve(a, b):
|
||||
out = [0] * (len(a) + len(b) - 1)
|
||||
for i in range(len(a)):
|
||||
for j in range(len(b)):
|
||||
out[i+j] += a[i] * b[j]
|
||||
return out
|
||||
out = [0] * (len(a) + len(b) - 1)
|
||||
for i in range(len(a)):
|
||||
for j in range(len(b)):
|
||||
out[i+j] += a[i] * b[j]
|
||||
return out
|
||||
|
||||
PATH = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
@@ -63,61 +63,58 @@ outc.write(header)
|
||||
outh.write(header)
|
||||
|
||||
def generate():
|
||||
l = ratio // 2
|
||||
l = ratio // 2
|
||||
|
||||
sample = [0.0] * (16*l)
|
||||
sample[l] = 1
|
||||
sample[2*l] = -1
|
||||
sample = [0.0] * (16*l)
|
||||
sample[l] = 1
|
||||
sample[2*l] = -1
|
||||
|
||||
sf = rrcosfilter(l*16)
|
||||
shapedSamples = convolve(sample, sf)
|
||||
|
||||
lowest = 0
|
||||
lowest_idx = 0
|
||||
highest = 0
|
||||
highest_idx = 0
|
||||
for i,j in enumerate(shapedSamples):
|
||||
if j < lowest:
|
||||
lowest = j
|
||||
lowest_idx = i
|
||||
if j > highest:
|
||||
highest = j
|
||||
highest_idx = i
|
||||
middle = int((lowest_idx+highest_idx)/2)
|
||||
sf = rrcosfilter(l*16)
|
||||
shapedSamples = convolve(sample, sf)
|
||||
|
||||
out = shapedSamples[middle-int(ratio*SIZE_RATIO):middle+int(ratio*SIZE_RATIO)]
|
||||
out = [2 * (i - min(out)) / (max(out) - min(out)) - 1 for i in out]
|
||||
if max(out) > 1 or min(out) < -1: raise Exception("Clipped")
|
||||
print(f"{len(out)=} {len(out)/sample_rate=} {(len(out)/sample_rate)/(1/DATA_RATE)=} {1/DATA_RATE=}")
|
||||
lowest = 0
|
||||
lowest_idx = 0
|
||||
highest = 0
|
||||
highest_idx = 0
|
||||
for i,j in enumerate(shapedSamples):
|
||||
if j < lowest:
|
||||
lowest = j
|
||||
lowest_idx = i
|
||||
if j > highest:
|
||||
highest = j
|
||||
highest_idx = i
|
||||
middle = int((lowest_idx+highest_idx)/2)
|
||||
|
||||
if PLOT:
|
||||
# Plot the waveform
|
||||
plt.plot(out, label="out")
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
out = shapedSamples[middle-int(ratio*SIZE_RATIO):middle+int(ratio*SIZE_RATIO)]
|
||||
out = [2 * (i - min(out)) / (max(out) - min(out)) - 1 for i in out]
|
||||
if max(out) > 1 or min(out) < -1: raise Exception("Clipped")
|
||||
print(f"{len(out)=} {len(out)/sample_rate=} {(len(out)/sample_rate)/(1/DATA_RATE)=} {1/DATA_RATE=}")
|
||||
|
||||
if FFT:
|
||||
# Compute the FFT of the waveform
|
||||
N = len(out)
|
||||
fft_out = np.fft.fft(out)
|
||||
fft_freqs = np.fft.fftfreq(N, d=1/sample_rate)
|
||||
if PLOT:
|
||||
plt.plot(out, label="out")
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
|
||||
# Plot the magnitude of the FFT
|
||||
plt.figure(figsize=(10, 6))
|
||||
plt.plot(fft_freqs[:N//2], np.abs(fft_out)[:N//2]) # Plot only the positive frequencies
|
||||
plt.xlim(0,DATA_RATE*3)
|
||||
plt.title("FFT of the waveform")
|
||||
plt.xlabel("Frequency (Hz)")
|
||||
plt.ylabel("Magnitude")
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
if FFT:
|
||||
N = len(out)
|
||||
fft_out = np.fft.fft(out)
|
||||
fft_freqs = np.fft.fftfreq(N, d=1/sample_rate)
|
||||
|
||||
outc.write(u"float waveform_biphase[{size}] = {{{values}}};\n\n".format(
|
||||
values = u", ".join(map(str, out)),
|
||||
size = len(out)))
|
||||
plt.figure(figsize=(10, 6))
|
||||
plt.plot(fft_freqs[:N//2], np.abs(fft_out)[:N//2])
|
||||
plt.xlim(0,DATA_RATE*3)
|
||||
plt.title("FFT of the waveform")
|
||||
plt.xlabel("Frequency (Hz)")
|
||||
plt.ylabel("Magnitude")
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
|
||||
outh.write(u"extern float waveform_biphase[{size}];\n".format(size=len(out)))
|
||||
outc.write(u"float waveform_biphase[{size}] = {{{values}}};\n\n".format(
|
||||
values = u", ".join(map(str, out)),
|
||||
size = len(out)))
|
||||
|
||||
outh.write(u"extern float waveform_biphase[{size}];\n".format(size=len(out)))
|
||||
|
||||
generate()
|
||||
|
||||
|
||||
@@ -236,6 +236,12 @@ static void handle_grpseq2(char *arg, RDSModulator* mod, char* output) {
|
||||
strcpy(output, "+\0");
|
||||
}
|
||||
|
||||
static void handle_dttmout(char *arg, RDSModulator* mod, char* output) {
|
||||
mod->enc->data[mod->enc->program].original_rt_text_timeout = atoi(arg);
|
||||
mod->enc->data[mod->enc->program].rt_text_timeout = mod->enc->data[mod->enc->program].original_rt_text_timeout;
|
||||
strcpy(output, "+\0");
|
||||
}
|
||||
|
||||
static void handle_level(char *arg, RDSModulator* mod, char* output) {
|
||||
mod->params.level = atoi(arg)/255.0f;
|
||||
strcpy(output, "+\0");
|
||||
@@ -313,7 +319,7 @@ static void handle_init(char *arg, RDSModulator* mod, char* output) {
|
||||
static void handle_ver(char *arg, RDSModulator* mod, char* output) {
|
||||
(void)arg;
|
||||
(void)mod;
|
||||
sprintf(output, "Firmware v. 1.2 - (C) 2025 radio95");
|
||||
sprintf(output, "Encoder v. %s - (C) 2025 radio95", VERSION);
|
||||
}
|
||||
|
||||
static void handle_eonen(char *arg, char *pattern, RDSModulator* mod, char* output) {
|
||||
@@ -453,6 +459,7 @@ static const command_handler_t commands_eq8[] = {
|
||||
{"PROGRAM", handle_program, 7},
|
||||
{"RDS2MOD", handle_rds2mod, 7},
|
||||
{"GRPSEQ2", handle_grpseq2, 7},
|
||||
{"DTTMOUT", handle_dttmout, 7},
|
||||
};
|
||||
static const command_handler_t commands_exact[] = {
|
||||
{"INIT", handle_init, 4},
|
||||
|
||||
@@ -10,4 +10,8 @@
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define M_2PI (M_PI * 2.0)
|
||||
#define M_2PI (M_PI * 2.0)
|
||||
|
||||
#ifndef VERSION
|
||||
#define VERSION "-.-"
|
||||
#endif
|
||||
@@ -17,7 +17,7 @@ int _strnlen(const char *s, int maxlen) {
|
||||
return len;
|
||||
}
|
||||
|
||||
// For RDS2 RFT, and UECP
|
||||
// For RDS2 RFT, file error checking, and UECP
|
||||
uint16_t crc16_ccitt(char* data, uint16_t len) {
|
||||
uint16_t i, crc=0xFFFF;
|
||||
for (i=0; i < len; i++ ) {
|
||||
|
||||
@@ -83,9 +83,7 @@ void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc) {
|
||||
}
|
||||
|
||||
float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) {
|
||||
uint16_t idx;
|
||||
float *cur_waveform;
|
||||
float sample;
|
||||
if (rdsMod->data[stream].sample_count == SAMPLES_PER_BIT) {
|
||||
if (rdsMod->data[stream].bit_pos == BITS_PER_GROUP) {
|
||||
get_rds_bits(rdsMod->enc, rdsMod->data[stream].bit_buffer, stream);
|
||||
@@ -96,7 +94,7 @@ float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) {
|
||||
rdsMod->data[stream].prev_output = rdsMod->data[stream].cur_output;
|
||||
rdsMod->data[stream].cur_output = rdsMod->data[stream].prev_output ^ rdsMod->data[stream].cur_bit;
|
||||
|
||||
idx = rdsMod->data[stream].in_sample_index;
|
||||
uint16_t idx = rdsMod->data[stream].in_sample_index;
|
||||
cur_waveform = waveform[rdsMod->data[stream].cur_output];
|
||||
|
||||
for (uint16_t i = 0; i < FILTER_SIZE; i++) {
|
||||
@@ -111,19 +109,18 @@ float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) {
|
||||
}
|
||||
rdsMod->data[stream].sample_count++;
|
||||
|
||||
if(rdsMod->data[stream].symbol_shifting.symbol_shift != 0) {
|
||||
float sample = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index];
|
||||
if(stream != 0 && rdsMod->data[stream].symbol_shifting.symbol_shift != 0) {
|
||||
rdsMod->data[stream].symbol_shifting.sample_buffer[rdsMod->data[stream].symbol_shifting.sample_buffer_idx++] = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index];
|
||||
|
||||
if (rdsMod->data[stream].symbol_shifting.sample_buffer_idx == rdsMod->data[stream].symbol_shifting.symbol_shift) rdsMod->data[stream].symbol_shifting.sample_buffer_idx = 0;
|
||||
|
||||
sample = rdsMod->data[stream].symbol_shifting.sample_buffer[rdsMod->data[stream].symbol_shifting.sample_buffer_idx];
|
||||
} else {
|
||||
sample = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index];
|
||||
}
|
||||
|
||||
rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index++] = 0;
|
||||
if (rdsMod->data[stream].out_sample_index == SAMPLE_BUFFER_SIZE)
|
||||
rdsMod->data[stream].out_sample_index = 0;
|
||||
if (rdsMod->data[stream].out_sample_index == SAMPLE_BUFFER_SIZE) rdsMod->data[stream].out_sample_index = 0;
|
||||
|
||||
uint8_t tooutput = 1;
|
||||
if (rdsMod->params.rdsgen == 0) {
|
||||
tooutput = 0;
|
||||
|
||||
73
src/rds.c
73
src/rds.c
@@ -40,7 +40,7 @@ void saveToFile(RDSEncoder *emp, const char *option) {
|
||||
} else if (strcmp(option, "PTYN") == 0) {
|
||||
memcpy(tempEncoder.data[emp->program].ptyn, emp->data[emp->program].ptyn, PTYN_LENGTH);
|
||||
tempEncoder.data[emp->program].ptyn_enabled = emp->data[emp->program].ptyn_enabled;
|
||||
} else if (strcmp(option, "AF") == 0 || strcmp(option, "AFCH") == 0) {
|
||||
} else if (strcmp(option, "AF") == 0) {
|
||||
memcpy(&(tempEncoder.data[emp->program].af), &(emp->data[emp->program].af), sizeof(emp->data[emp->program].af));
|
||||
} else if (strcmp(option, "ECC") == 0) {
|
||||
tempEncoder.data[emp->program].ecc = emp->data[emp->program].ecc;
|
||||
@@ -97,6 +97,7 @@ void saveToFile(RDSEncoder *emp, const char *option) {
|
||||
memcpy(&(rdsEncoderfile.rtpData[emp->program]), &(tempEncoder.rtpData[emp->program]), sizeof(RDSRTPlusData));
|
||||
memcpy(&(rdsEncoderfile.encoder_data), &(tempEncoder.encoder_data), sizeof(RDSEncoderData));
|
||||
rdsEncoderfile.program = tempEncoder.program;
|
||||
rdsEncoderfile.crc = crc16_ccitt((char*)&rdsEncoderfile, sizeof(RDSEncoderFile) - sizeof(uint16_t));
|
||||
|
||||
file = fopen(encoderPath, "wb");
|
||||
if (file == NULL) {
|
||||
@@ -121,10 +122,17 @@ void loadFromFile(RDSEncoder *enc) {
|
||||
fclose(file);
|
||||
|
||||
if (rdsEncoderfile.file_starter != 225 || rdsEncoderfile.file_ender != 95 || rdsEncoderfile.file_middle != 160) {
|
||||
fprintf(stderr, "Invalid file format\n");
|
||||
fprintf(stderr, "[RDSENCODER-FILE] Invalid file format\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t calculated_crc = crc16_ccitt((char*)&rdsEncoderfile, sizeof(RDSEncoderFile) - sizeof(uint16_t));
|
||||
|
||||
if (calculated_crc != rdsEncoderfile.crc) {
|
||||
fprintf(stderr, "[RDSENCODER-FILE] CRC mismatch! Data may be corrupted\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < PROGRAMS; i++) {
|
||||
memcpy(&(enc->data[i]), &(rdsEncoderfile.data[i]), sizeof(RDSData));
|
||||
memcpy(&(enc->rtpData[i]), &(rdsEncoderfile.rtpData[i]), sizeof(RDSRTPlusData));
|
||||
@@ -145,25 +153,48 @@ int rdssaved() {
|
||||
}
|
||||
|
||||
static uint16_t get_next_af(RDSEncoder* enc) {
|
||||
static uint8_t af_state;
|
||||
uint16_t out;
|
||||
|
||||
if (enc->data[enc->program].af.num_afs) {
|
||||
if (af_state == 0) {
|
||||
if (enc->state[enc->program].af_state == 0) {
|
||||
out = (AF_CODE_NUM_AFS_BASE + enc->data[enc->program].af.num_afs) << 8;
|
||||
out |= enc->data[enc->program].af.afs[0];
|
||||
af_state += 1;
|
||||
enc->state[enc->program].af_state += 1;
|
||||
} else {
|
||||
out = enc->data[enc->program].af.afs[af_state] << 8;
|
||||
if (enc->data[enc->program].af.afs[af_state + 1])
|
||||
out |= enc->data[enc->program].af.afs[af_state + 1];
|
||||
out = enc->data[enc->program].af.afs[enc->state[enc->program].af_state] << 8;
|
||||
if (enc->data[enc->program].af.afs[enc->state[enc->program].af_state + 1])
|
||||
out |= enc->data[enc->program].af.afs[enc->state[enc->program].af_state + 1];
|
||||
else
|
||||
out |= AF_CODE_FILLER;
|
||||
af_state += 2;
|
||||
enc->state[enc->program].af_state += 2;
|
||||
}
|
||||
if (af_state >= enc->data[enc->program].af.num_entries) af_state = 0;
|
||||
if (enc->state[enc->program].af_state >= enc->data[enc->program].af.num_entries) enc->state[enc->program].af_state = 0;
|
||||
} else {
|
||||
out = AF_CODE_NO_AF << 8 | AF_CODE_FILLER;
|
||||
out = AF_CODE_NUM_AFS_BASE << 8 | AF_CODE_FILLER;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static uint16_t get_next_af_eon(RDSEncoder* enc, uint8_t eon_index) {
|
||||
uint16_t out;
|
||||
|
||||
if (enc->data[enc->program].eon[eon_index].af.num_afs) {
|
||||
if (enc->state[enc->program].eon_states[eon_index].af_state == 0) {
|
||||
out = (AF_CODE_NUM_AFS_BASE + enc->data[enc->program].af.num_afs) << 8;
|
||||
out |= enc->data[enc->program].eon[eon_index].af.afs[0];
|
||||
enc->state[enc->program].eon_states[eon_index].af_state += 1;
|
||||
} else {
|
||||
out = enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state] << 8;
|
||||
if (enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state + 1])
|
||||
out |= enc->data[enc->program].eon[eon_index].af.afs[enc->state[enc->program].eon_states[eon_index].af_state + 1];
|
||||
else
|
||||
out |= AF_CODE_FILLER;
|
||||
enc->state[enc->program].eon_states[eon_index].af_state += 2;
|
||||
}
|
||||
if (enc->state[enc->program].eon_states[eon_index].af_state >= enc->data[enc->program].eon[eon_index].af.num_entries) enc->state[enc->program].eon_states[eon_index].af_state = 0;
|
||||
} else {
|
||||
out = AF_CODE_NUM_AFS_BASE << 8 | AF_CODE_FILLER;
|
||||
}
|
||||
|
||||
return out;
|
||||
@@ -355,7 +386,10 @@ get_eon:
|
||||
blocks[2] |= eon.ps[enc->state[enc->program].eon_state*2 + 1];
|
||||
blocks[1] |= enc->state[enc->program].eon_state;
|
||||
break;
|
||||
case 4: // 13
|
||||
case 4:
|
||||
blocks[2] = get_next_af_eon(enc, enc->state[enc->program].eon_index);
|
||||
break;
|
||||
case 5: // 13
|
||||
if(eon.pty == 0 && eon.tp == 0) {
|
||||
break;
|
||||
}
|
||||
@@ -363,12 +397,11 @@ get_eon:
|
||||
if(eon.tp) blocks[2] |= eon.ta;
|
||||
blocks[1] |= 13;
|
||||
break;
|
||||
// TODO: Add AF
|
||||
}
|
||||
|
||||
blocks[3] = eon.pi;
|
||||
|
||||
if(enc->state[enc->program].eon_state == 4) {
|
||||
if(enc->state[enc->program].eon_state == 5) {
|
||||
enc->state[enc->program].eon_index++;
|
||||
|
||||
uint8_t i = 0;
|
||||
@@ -556,6 +589,14 @@ static void get_rds_group(RDSEncoder* enc, uint16_t *blocks, uint8_t stream) {
|
||||
}
|
||||
}
|
||||
|
||||
if(enc->data[enc->program].rt1_enabled && enc->data[enc->program].rt_text_timeout != 0) {
|
||||
enc->data[enc->program].rt_text_timeout--;
|
||||
if(enc->data[enc->program].rt_text_timeout == 0) {
|
||||
enc->state[enc->program].rt_update = 1;
|
||||
memccpy(enc->state[enc->program].rt_text, enc->data[enc->program].default_rt, 0, RT_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
if(enc->data[enc->program].ct && stream == 0) {
|
||||
get_rds_ct_group(enc, blocks);
|
||||
goto group_coded;
|
||||
@@ -742,6 +783,8 @@ void init_rds_encoder(RDSEncoder* enc) {
|
||||
void set_rds_rt1(RDSEncoder* enc, char *rt1) {
|
||||
uint8_t i = 0, len = 0;
|
||||
|
||||
enc->data[enc->program].rt_text_timeout = enc->data[enc->program].original_rt_text_timeout;
|
||||
|
||||
enc->state[enc->program].rt_update = 1;
|
||||
|
||||
memset(enc->data[enc->program].rt1, ' ', RT_LENGTH);
|
||||
@@ -767,7 +810,7 @@ void set_rds_rt1(RDSEncoder* enc, char *rt1) {
|
||||
|
||||
void set_rds_rt2(RDSEncoder* enc, char *rt2) {
|
||||
uint8_t i = 0, len = 0;
|
||||
|
||||
|
||||
enc->state[enc->program].rt2_update = 1;
|
||||
|
||||
memset(enc->data[enc->program].rt2, ' ', RT_LENGTH);
|
||||
|
||||
13
src/rds.h
13
src/rds.h
@@ -26,8 +26,7 @@
|
||||
#define MAX_AFS 25
|
||||
|
||||
#define AF_CODE_FILLER 205
|
||||
#define AF_CODE_NO_AF 224
|
||||
#define AF_CODE_NUM_AFS_BASE AF_CODE_NO_AF
|
||||
#define AF_CODE_NUM_AFS_BASE 224
|
||||
#define AF_CODE_LFMF_FOLLOWS 250
|
||||
|
||||
#define PROGRAMS 2
|
||||
@@ -56,9 +55,6 @@ typedef struct {
|
||||
char ps[PS_LENGTH];
|
||||
char rt1[RT_LENGTH];
|
||||
|
||||
uint8_t dsn;
|
||||
uint8_t psn;
|
||||
|
||||
uint8_t ecc;
|
||||
|
||||
uint8_t ta : 1;
|
||||
@@ -103,6 +99,9 @@ typedef struct {
|
||||
|
||||
RDSEON eon[4];
|
||||
} RDSData;
|
||||
typedef struct {
|
||||
uint8_t af_state : 6;
|
||||
} RDSEONState;
|
||||
typedef struct {
|
||||
uint8_t ps_update : 1;
|
||||
uint8_t tps_update : 1;
|
||||
@@ -148,6 +147,9 @@ typedef struct {
|
||||
|
||||
uint8_t eon_index : 3;
|
||||
uint8_t eon_state : 4;
|
||||
RDSEONState eon_states[4];
|
||||
|
||||
uint8_t af_state : 6;
|
||||
|
||||
uint16_t last_stream0_group[3];
|
||||
} RDSState;
|
||||
@@ -197,6 +199,7 @@ typedef struct {
|
||||
RDSEncoderData encoder_data;
|
||||
uint8_t program : 3;
|
||||
uint8_t file_ender; // Always is 95 my freq
|
||||
uint16_t crc;
|
||||
} RDSEncoderFile;
|
||||
|
||||
#define GROUP_TYPE_0 ( 0 << 4)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#define RDS_DEVICE "RDS"
|
||||
|
||||
#define NUM_MPX_FRAMES 256
|
||||
#define NUM_MPX_FRAMES 128
|
||||
|
||||
static uint8_t stop_rds;
|
||||
|
||||
@@ -34,7 +34,7 @@ static void *control_pipe_worker(void* modulator) {
|
||||
}
|
||||
|
||||
static void show_version() {
|
||||
printf("rds95 (a RDS encoder by radio95) version 1.2\n");
|
||||
printf("rds95 (a RDS encoder by radio95) version %s\n", VERSION);
|
||||
}
|
||||
|
||||
static void show_help(char *name) {
|
||||
@@ -43,7 +43,6 @@ static void show_help(char *name) {
|
||||
"Usage: %s [options]\n"
|
||||
"\n"
|
||||
" -C,--ctl FIFO control pipe\n"
|
||||
" -h,--help Show this help text and exit\n"
|
||||
"\n",
|
||||
name
|
||||
);
|
||||
@@ -95,8 +94,8 @@ int main(int argc, char **argv) {
|
||||
format.rate = RDS_SAMPLE_RATE;
|
||||
|
||||
buffer.prebuf = 0;
|
||||
buffer.tlength = 12228;
|
||||
buffer.maxlength = 12228;
|
||||
buffer.tlength = NUM_MPX_FRAMES*4;
|
||||
buffer.maxlength = NUM_MPX_FRAMES*4;
|
||||
|
||||
rds_device = pa_simple_new(
|
||||
NULL,
|
||||
|
||||
Reference in New Issue
Block a user