Compare commits
17 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
2add0cc3e6 | |
|
|
8f17867b05 | |
|
|
86bc722a76 | |
|
|
4a6a617af0 | |
|
|
9256df8b01 | |
|
|
b01b31154e | |
|
|
8961801595 | |
|
|
ad67d6d63c | |
|
|
2add7e7b62 | |
|
|
d80daf406e | |
|
|
fe473525f7 | |
|
|
51d1c5a3fe | |
|
|
0b72c6adb6 | |
|
|
da4a9803e8 | |
|
|
1106473eec | |
|
|
a5f6556489 | |
|
|
23a3dd8e50 |
12
README.md
12
README.md
|
|
@ -1,3 +1,4 @@
|
|||
**THIS IS THE DEVELOPMENT BRANCH!**
|
||||
if you wanna use pifmrds, then scroll down to pifmrds usage ([here](#usage))
|
||||

|
||||
# About rpitx2
|
||||
|
|
@ -23,7 +24,7 @@ sudo apt-get install git
|
|||
You can now clone the repository. A script (install.sh) is there for easy installation. You could inspect it and make steps manually in case of any doubt. You can note that /boot/config.txt should be prompt to be modified during the installation. If it is not accepted, **rpitx2** will be unstable.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/KubaPro010/rpitx2
|
||||
git clone https://github.com/KubaPro010/rpitx2 -b dev
|
||||
cd rpitx2
|
||||
./install.sh
|
||||
```
|
||||
|
|
@ -163,7 +164,10 @@ if you have a arg with no argume... wait what args with args? anyways like the i
|
|||
`-af` - same as pifmadv<br>
|
||||
`-rdsvolume` - rds volume, so how many times is the rds "louder"<br>
|
||||
`-pilotvolume` - pilot volume<br>
|
||||
`-limiterthreshold` - limiter threshold, limits to 10, i think that its in linear ratio, so the algorithm to convert from db is gonna be 10 ** (db/20)<br><br>
|
||||
`-limiterthreshold` - limiter threshold, limits to 10, i think that its in linear ratio, so the algorithm to convert from db is gonna be 10 ** (db/20)<br>
|
||||
`-di` - sets the di, usually just set this to 1 so you have stereo<br>
|
||||
`-ecc` - you wanna really want them to know you country for some reason? use this to set the ecc, so when i use a 0x3000 pi code i won't get 10 countries i'll just get the worst one, for example i can set it to E2 which is poland! - **DEV**<br>
|
||||
<br>
|
||||
|
||||
now you know what you can pass as the args to the program, but theres a pipe still, it wont include the ones in pifmadv or pifmrds:<br>
|
||||
`PI` - you can change pi code while runtime, useful when you forgot to set a pi code, but you probably won't care about it<br>
|
||||
|
|
@ -183,8 +187,10 @@ now you know what you can pass as the args to the program, but theres a pipe sti
|
|||
`COM` - toggle, like rds but it doesnt toggle the rds, it does toggle the COMPRESSOR<br>
|
||||
`CMG` - change compressor max gain recip<br>
|
||||
`LIM` - same as that arg<br>
|
||||
`ECC` - same as arg<br>
|
||||
`DI` - sam as arg - **DEV**<br>
|
||||
<br>
|
||||
and thats all, and remember kids dont pirate
|
||||
thats all, and remember kids dont pirate
|
||||
|
||||
## Features
|
||||
what makes this better you may ask, you might have seen some features in usage already, as of 22.03.24 (DD.MM.YY) a limiter was implemented alongside the compressor, this can be used if the compressor is set too low/high or it is disabled altogether, from around 500 khz of bandwidht to about 200 khz of bandwidht, this was tested with a wav file amplified 2000 times, still the sound was distorted but the band wasn't atleast
|
||||
|
|
|
|||
|
|
@ -69,14 +69,12 @@ ResultAndArg poll_control_pipe(int log) {
|
|||
set_rds_rt(arg);
|
||||
if(log==1) printf("RT A set to: \"%s\"\n", arg);
|
||||
resarg.res = CONTROL_PIPE_RT_SET;
|
||||
}
|
||||
else if(fifo[0] == 'P' && fifo[1] == 'I') {
|
||||
} else if(fifo[0] == 'P' && fifo[1] == 'I') {
|
||||
arg[4] = 0;
|
||||
set_rds_pi((uint16_t) strtol(arg, NULL, 16));
|
||||
if(log==1) printf("PI set to: \"%s\"\n", arg);
|
||||
resarg.res = CONTROL_PIPE_PI_SET;
|
||||
}
|
||||
else if(fifo[0] == 'T' && fifo[1] == 'A') {
|
||||
} else if(fifo[0] == 'T' && fifo[1] == 'A') {
|
||||
int ta = ( strcmp(arg, "ON") == 0 );
|
||||
set_rds_ta(ta);
|
||||
if(log==1) {
|
||||
|
|
@ -84,8 +82,7 @@ ResultAndArg poll_control_pipe(int log) {
|
|||
if(ta) printf("ON\n"); else printf("OFF\n");
|
||||
}
|
||||
resarg.res = CONTROL_PIPE_TA_SET;
|
||||
}
|
||||
else if(fifo[0] == 'T' && fifo[1] == 'P') {
|
||||
} else if(fifo[0] == 'T' && fifo[1] == 'P') {
|
||||
int tp = ( strcmp(arg, "ON") == 0 );
|
||||
set_rds_tp(tp);
|
||||
if(log==1) {
|
||||
|
|
@ -93,8 +90,7 @@ ResultAndArg poll_control_pipe(int log) {
|
|||
if(tp) printf("ON\n"); else printf("OFF\n");
|
||||
}
|
||||
resarg.res = CONTROL_PIPE_TP_SET;
|
||||
}
|
||||
else if(fifo[0] == 'M' && fifo[1] == 'S') {
|
||||
} else if(fifo[0] == 'M' && fifo[1] == 'S') {
|
||||
int ms = ( strcmp(arg, "ON") == 0 );
|
||||
set_rds_ms(ms);
|
||||
if(log==1) {
|
||||
|
|
@ -102,8 +98,7 @@ ResultAndArg poll_control_pipe(int log) {
|
|||
if(ms) printf("ON\n"); else printf("OFF\n");
|
||||
}
|
||||
resarg.res = CONTROL_PIPE_MS_SET;
|
||||
}
|
||||
else if(fifo[0] == 'A' && fifo[1] == 'B') {
|
||||
} else if(fifo[0] == 'A' && fifo[1] == 'B') {
|
||||
int ab = ( strcmp(arg, "ON") == 0 );
|
||||
set_rds_ab(ab);
|
||||
if(log==1) {
|
||||
|
|
@ -111,6 +106,15 @@ ResultAndArg poll_control_pipe(int log) {
|
|||
if(ab) printf("ON\n"); else printf("OFF\n");
|
||||
}
|
||||
resarg.res = CONTROL_PIPE_AB_SET;
|
||||
} else if(fifo[0] == 'D' && fifo[1] == 'I') {
|
||||
int di = atoi(arg);
|
||||
set_rds_di(di);
|
||||
if(log==1) {
|
||||
printf("Set DI to ");
|
||||
printf(di); //yes i am that lazy
|
||||
printf("\n");
|
||||
}
|
||||
resarg.res = 25;
|
||||
} else if(fifo[0] == 'C' && fifo[1] == 'T') {
|
||||
int ct = ( strcmp(arg, "ON") == 0 );
|
||||
if(log==1) {
|
||||
|
|
@ -261,6 +265,11 @@ ResultAndArg poll_control_pipe(int log) {
|
|||
printf("Limiter threshold was not set, thresholds larger than 4 are not allowed\n");
|
||||
}
|
||||
}
|
||||
} else if(fifo[0] == 'E' && fifo[1] == 'C' && fifo[2] == 'C') {
|
||||
arg[2] = 0;
|
||||
set_rds_ecc((uint16_t)strtol(arg, NULL, 16));
|
||||
if(log==1) printf("ECC set to: \"%s\"\n", arg);
|
||||
resarg.res = 26;
|
||||
}
|
||||
}
|
||||
return resarg;
|
||||
|
|
|
|||
|
|
@ -191,17 +191,6 @@ int fm_mpx_open(char *filename, size_t len, int raw, double preemphasis, int raw
|
|||
|
||||
printf("Created low-pass FIR filter for audio channels, with cutoff at %.1f Hz\n", cutoff_freq);
|
||||
|
||||
if( 0 )
|
||||
{
|
||||
printf("f = [ ");
|
||||
for(int i=0; i<FIR_TAPS; i++) {
|
||||
for(int j=0; j<FIR_PHASES; j++) {
|
||||
printf("%.5f ", low_pass_fir[j][i]);
|
||||
}
|
||||
}
|
||||
printf("]; \n");
|
||||
}
|
||||
|
||||
audio_pos = downsample_factor;
|
||||
audio_buffer = alloc_empty_buffer(length * channels);
|
||||
if(audio_buffer == NULL) return -1;
|
||||
|
|
@ -220,8 +209,7 @@ int fm_mpx_open(char *filename, size_t len, int raw, double preemphasis, int raw
|
|||
// 10 after.
|
||||
int fm_mpx_get_samples(float *mpx_buffer, int drds, float compressor_decay, float compressor_attack, float compressor_max_gain_recip, int disablestereo, float gain, int enablecompressor, int rds_ct_enabled, float rds_volume, int paused, float pilot_volume, int generate_multiplex, float limiter_threshold) {
|
||||
*audio_buffer = 0.0;
|
||||
int stereo_capable = (channels > 1) && (!disablestereo); //chatgpt
|
||||
if(!drds && generate_multiplex) get_rds_samples(mpx_buffer, length, stereo_capable, rds_ct_enabled, rds_volume);
|
||||
if(!drds && generate_multiplex) get_rds_samples(mpx_buffer, length, rds_ct_enabled, rds_volume);
|
||||
|
||||
if(inf == NULL) return 0; // if there is no audio, stop here
|
||||
|
||||
|
|
@ -352,7 +340,6 @@ int fm_mpx_get_samples(float *mpx_buffer, int drds, float compressor_decay, floa
|
|||
if( channels > 1 ) {
|
||||
if(!disablestereo) {
|
||||
if(generate_multiplex) {
|
||||
if(1) {
|
||||
mpx_buffer[i] += 4.05*(out_left+out_right) + // Stereo sum signal
|
||||
4.05 * carrier_38[phase_38] * (out_left-out_right) + // Stereo difference signal
|
||||
pilot_volume*carrier_19[phase_19]; // Stereo pilot tone
|
||||
|
|
@ -360,11 +347,6 @@ int fm_mpx_get_samples(float *mpx_buffer, int drds, float compressor_decay, floa
|
|||
phase_38++;
|
||||
if(phase_19 >= 12) phase_19 = 0;
|
||||
if(phase_38 >= 6) phase_38 = 0;
|
||||
} else { // polar stereo (https://forums.stereotool.com/viewtopic.php?t=6233, https://personal.utdallas.edu/~dlm/3350%20comm%20sys/ITU%20std%20on%20FM%20--%20R-REC-BS.450-3-200111-I!!PDF-E.pdf)
|
||||
mpx_buffer[i] += 4.05*(out_left+out_right) + // Stereo sum signal (L+R)
|
||||
4.05 * (out_left-out_right); // Stereo difference signal
|
||||
//NO PIOT TONE!!!!!!!!!!!!!!!!!!!!!!!!!!!! (its missplelled correctly probably just like misspelled)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(generate_multiplex) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ static void fatal(char *fmt, ...)
|
|||
terminate(0);
|
||||
}
|
||||
|
||||
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, char *control_pipe, int pty, int *af_array, int raw, int drds, double preemp, int power, int rawSampleRate, int rawChannels, int deviation, int ta, int tp, float cutoff_freq, float gaim, float compressor_decay, float compressor_attack, float compressor_max_gain_recip, int enablecompressor, int rds_ct_enabled, float rds_volume, float pilot_volume, int disablestereo, int log, float limiter_threshold) {
|
||||
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, char *control_pipe, int pty, int *af_array, int raw, int drds, double preemp, int power, int rawSampleRate, int rawChannels, int deviation, int ta, int tp, float cutoff_freq, float gaim, float compressor_decay, float compressor_attack, float compressor_max_gain_recip, int enablecompressor, int rds_ct_enabled, float rds_volume, float pilot_volume, int disablestereo, int log, float limiter_threshold, int di, uint16_t ecc) { //man this is so fucking long
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = terminate;
|
||||
|
|
@ -47,7 +47,6 @@ int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt,
|
|||
sigaction(SIGINT, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
sigaction(SIGKILL, &sa, NULL);
|
||||
sigaction(SIGHUP, &sa, NULL); //https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
|
||||
sigaction(SIGPWR, &sa, NULL);
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
sigaction(SIGSEGV, &sa, NULL); //seg fault
|
||||
|
|
@ -78,6 +77,8 @@ int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt,
|
|||
set_rds_ms(1);
|
||||
set_rds_tp(tp);
|
||||
set_rds_ta(ta);
|
||||
set_rds_di(di);
|
||||
set_rds_ecc(ecc);
|
||||
uint16_t count = 0;
|
||||
uint16_t count2 = 0;
|
||||
if(log) {
|
||||
|
|
@ -199,6 +200,8 @@ int main(int argc, char **argv) {
|
|||
int bypassfreqrange = 0;
|
||||
int ct = 1;
|
||||
float cutofffreq = 16200;
|
||||
uint16_t ecc = 0;
|
||||
int di = DI_STEREO;
|
||||
// Parse command-line arguments
|
||||
for(int i=1; i<argc; i++) {
|
||||
char *arg = argv[i];
|
||||
|
|
@ -210,10 +213,13 @@ int main(int argc, char **argv) {
|
|||
} else if(strcmp("-freq", arg)==0 && param != NULL) {
|
||||
i++;
|
||||
carrier_freq = 1e6 * atof(param);
|
||||
if((carrier_freq < 64e6 || carrier_freq > 108e6) && !bypassfreqrange) fatal("Incorrect frequency specification. Must be in megahertz, of the form 107.9, between 64 and 108. (going that low for UKF radios, such as the UNITRA Jowita or other old band FM Radios)\n");
|
||||
if((carrier_freq < 64e6 || carrier_freq > 108e6) && !bypassfreqrange) fatal("Incorrect frequency specification. Must be in megahertz, of the form 107.9, between 64 and 108. (going that low for old communist radios, such as the UNITRA Jowita or other old band FM Radios)\n");
|
||||
} else if(strcmp("-pi", arg)==0 && param != NULL) {
|
||||
i++;
|
||||
pi = (uint16_t) strtol(param, NULL, 16);
|
||||
pi = (uint16_t)strtol(param, NULL, 16);
|
||||
} else if(strcmp("-ecc", arg)==0 && param != NULL) {
|
||||
i++;
|
||||
ecc = (uint16_t)strtol(param, NULL, 16);
|
||||
} else if(strcmp("-ps", arg)==0 && param != NULL) {
|
||||
i++;
|
||||
ps = param;
|
||||
|
|
@ -248,6 +254,9 @@ int main(int argc, char **argv) {
|
|||
} else if(strcmp("-pty", arg)==0 && param != NULL) {
|
||||
i++;
|
||||
pty = atoi(param);
|
||||
} else if(strcmp("-di", arg)==0 && param != NULL) {
|
||||
i++;
|
||||
di = atoi(param);
|
||||
} else if(strcmp("-gpiopin", arg)==0 && param != NULL) {
|
||||
i++;
|
||||
printf("GPIO pin setting disabled, mod librpitx and pifmsa (pifm simply advanced) for this\n");
|
||||
|
|
@ -356,6 +365,6 @@ int main(int argc, char **argv) {
|
|||
int FifoSize=DATA_SIZE*2;
|
||||
//fmmod=new ngfmdmasync(carrier_freq,228000,14,FifoSize, false, gpiopin); //you can mod
|
||||
fmmod=new ngfmdmasync(carrier_freq,228000,14,FifoSize, false);
|
||||
int errcode = tx(carrier_freq, audio_file, pi, ps, rt, control_pipe, pty, alternative_freq, raw, drds, preemp, power, rawSampleRate, rawChannels, deviation, ta, tp, cutofffreq, gain, compressor_decay, compressor_attack, compressor_max_gain_recip, enable_compressor, ct, rds_volume, pilot_volume, dstereo, log, limiter_threshold);
|
||||
int errcode = tx(carrier_freq, audio_file, pi, ps, rt, control_pipe, pty, alternative_freq, raw, drds, preemp, power, rawSampleRate, rawChannels, deviation, ta, tp, cutofffreq, gain, compressor_decay, compressor_attack, compressor_max_gain_recip, enable_compressor, ct, rds_volume, pilot_volume, dstereo, log, limiter_threshold, di, ecc);
|
||||
terminate(errcode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,14 +31,16 @@
|
|||
|
||||
struct {
|
||||
uint16_t pi;
|
||||
int ta;
|
||||
int pty;
|
||||
int tp;
|
||||
int ms;
|
||||
int ab;
|
||||
uint8_t ta;
|
||||
uint8_t pty;
|
||||
uint8_t tp;
|
||||
uint8_t ms;
|
||||
uint8_t ab;
|
||||
uint8_t di;
|
||||
char ps[PS_LENGTH];
|
||||
char rt[RT_LENGTH];
|
||||
int af[100];
|
||||
uint16_t ecc;
|
||||
} rds_params = { 0 };
|
||||
/* Here, the first member of the struct must be a scalar to avoid a
|
||||
warning on -Wmissing-braces with GCC < 4.8.3
|
||||
|
|
@ -89,8 +91,8 @@ int get_rds_ct_group(uint16_t *blocks, int enabled) {
|
|||
time_t now;
|
||||
struct tm *utc;
|
||||
|
||||
now = time (NULL);
|
||||
utc = gmtime (&now);
|
||||
now = time(NULL);
|
||||
utc = gmtime(&now);
|
||||
|
||||
if(!enabled) {
|
||||
latest_minutes = utc->tm_min; //oh wait it won't anyway
|
||||
|
|
@ -105,7 +107,7 @@ int get_rds_ct_group(uint16_t *blocks, int enabled) {
|
|||
(int)((utc->tm_year - l) * 365.25) +
|
||||
(int)((utc->tm_mon + 2 + l*12) * 30.6001);
|
||||
|
||||
blocks[1] = 0x4400 | (mjd>>15);
|
||||
blocks[1] = rds_params.tp << 10 | rds_params.pty << 5 | 4 << 12 | (mjd>>15); //they forgot the tp and pty, does pifmadv have this? yes
|
||||
blocks[2] = (mjd<<1) | (utc->tm_hour>>4);
|
||||
blocks[3] = (utc->tm_hour & 0xF)<<12 | utc->tm_min<<6;
|
||||
|
||||
|
|
@ -114,8 +116,6 @@ int get_rds_ct_group(uint16_t *blocks, int enabled) {
|
|||
int offset = utc->tm_gmtoff / (30 * 60);
|
||||
blocks[3] |= abs(offset);
|
||||
if(offset < 0) blocks[3] |= 0x20;
|
||||
|
||||
//printf("Generated CT: %04X %04X %04X\n", blocks[1], blocks[2], blocks[3]);
|
||||
return 1;
|
||||
} else return 0;
|
||||
}
|
||||
|
|
@ -125,7 +125,7 @@ int get_rds_ct_group(uint16_t *blocks, int enabled) {
|
|||
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, int stereo, int ct_clock_enabled) { //no idea how to do ptyn and decoder id
|
||||
void get_rds_group(int *buffer, int stereo, int ct_clock_enabled) {
|
||||
static int state = 0;
|
||||
static int ps_state = 0;
|
||||
static int rt_state = 0;
|
||||
|
|
@ -135,34 +135,43 @@ void get_rds_group(int *buffer, int stereo, int ct_clock_enabled) { //no idea ho
|
|||
// Generate block content
|
||||
if(!get_rds_ct_group(blocks, ct_clock_enabled)) { // CT (clock time) has priority on other group types (when its on)
|
||||
if(state < 4) {
|
||||
blocks[1] = 0x0000 | rds_params.tp << 10 | rds_params.pty << 5 | rds_params.ta << 4 | rds_params.ms << 3 | ps_state;
|
||||
if((ps_state == 3) && stereo) blocks[1] |= 0x0004; // DI Stereo, someone explain from where the 0004 comes from and what does "bit d0" mean?
|
||||
blocks[1] = rds_params.tp << 10 | rds_params.pty << 5 | rds_params.ta << 4 | rds_params.ms << 3 | ps_state;
|
||||
blocks[1] |= ((rds_params.di & 0x01) << 2); //also yes i did see the bitshift 2 in micro rds, code for stereo is in binary 0001, bit shift 2 is 0100 which is equal to 0x0004
|
||||
if(rds_params.af[0]) { // AF
|
||||
if(af_state == 0) {
|
||||
blocks[2] = (rds_params.af[0] + 224) << 8 | rds_params.af[1];
|
||||
blocks[2] = (rds_params.af[0] + AF_CODE_NUM_AFS_BASE) << 8 | rds_params.af[1];
|
||||
} else {
|
||||
if(rds_params.af[af_state+1]) {
|
||||
blocks[2] = rds_params.af[af_state] << 8 | rds_params.af[af_state+1];
|
||||
} else {
|
||||
blocks[2] = rds_params.af[af_state] << 8 | 0xCD;
|
||||
blocks[2] = rds_params.af[af_state] << 8 | AF_CODE_FILLER;
|
||||
}
|
||||
}
|
||||
af_state = af_state + 2;
|
||||
if(af_state > rds_params.af[0]) af_state = 0;
|
||||
} else {
|
||||
blocks[2] = AF_CODE_NO_AF << 8 | AF_CODE_FILLER; //handle no af, if we didnt do this, block 2 would be empty
|
||||
}
|
||||
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 { // Type 2A groups
|
||||
blocks[1] = 0x2000 | rds_params.tp << 10 | rds_params.pty << 5 | rds_params.ab << 4 | rt_state;
|
||||
if(ps_state >= 4) ps_state = 0; //max segments
|
||||
} else if(state < 6) { // Type 2A groups
|
||||
//ill explain text in rds, rds does not have the full string, you have segments, which are 4 character parts, the 64 character rt is split into 16 of those (rt_state), the rt is really lets say AAAABBBBCCCC, a rds group has the 2nd segment with the string "hell", so its now AAAAhellCCCC, we get a next group, 3rd with "o! " "so AAAAhello! ", we get a 1st as "hi: ", so "hi: |hell|o! |",i am unsure if this is actually it for 100% but that how i understand it
|
||||
//micro rds does also have a problem with stray charcters, as it will try to set the number of segments to actually use instead of some text followed spaces, like a dot followed by 63 spaces, why send 15 segment full of spaces when you can have 1 segment with data? so it would use a single segment with a dot, it will speed up the speed of loading of the rt text, but there will be stray characters, because of generaly how does the transmission work, here spaces would replace the stray characters, but micrords fixes it with toggling the A/B every set, clever huh?
|
||||
//ps also works like that but it has 2 characters per segment instead, so AABBCCDD because if it had 4 then it would take 2 segments as ps is small
|
||||
blocks[1] = (2 << 12) | rds_params.tp << 10 | rds_params.pty << 5 | rds_params.ab << 4 | 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;
|
||||
if(rt_state >= 16) rt_state = 0; //max segments
|
||||
} else if(state == 6 && rds_params.ecc != 0) { //ECC
|
||||
blocks[1] = (1 << 12) | rds_params.tp << 10 | rds_params.pty << 5;
|
||||
blocks[2] = rds_params.ecc;
|
||||
}
|
||||
//expected sequence: (0A 0A 0A 0A 2A 2A 1A) this sequence should supply us the whole ps, 8 characters of rt and ecc
|
||||
|
||||
state++;
|
||||
if(state >= 6) state = 0;
|
||||
if(state >= 7) state = 0;
|
||||
}
|
||||
|
||||
// Calculate the checkword for each block and emit the bits
|
||||
|
|
@ -185,7 +194,7 @@ void get_rds_group(int *buffer, int stereo, int ct_clock_enabled) { //no idea ho
|
|||
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, int stereo, int ct_clock_enabled, float sample_volume) {
|
||||
void get_rds_samples(float *buffer, int count, int ct_clock_enabled, float sample_volume) {
|
||||
static int bit_buffer[BITS_PER_GROUP];
|
||||
static int bit_pos = BITS_PER_GROUP;
|
||||
static float sample_buffer[SAMPLE_BUFFER_SIZE] = {0};
|
||||
|
|
@ -203,7 +212,7 @@ void get_rds_samples(float *buffer, int count, int stereo, int ct_clock_enabled,
|
|||
for(int i=0; i<count; i++) {
|
||||
if(sample_count >= SAMPLES_PER_BIT) {
|
||||
if(bit_pos >= BITS_PER_GROUP) {
|
||||
get_rds_group(bit_buffer, stereo, ct_clock_enabled);
|
||||
get_rds_group(bit_buffer, ct_clock_enabled);
|
||||
bit_pos = 0;
|
||||
}
|
||||
|
||||
|
|
@ -298,3 +307,11 @@ void set_rds_ms(int ms) {
|
|||
void set_rds_ab(int ab) {
|
||||
rds_params.ab = ab;
|
||||
}
|
||||
|
||||
void set_rds_di(int di) {
|
||||
rds_params.di = di;
|
||||
}
|
||||
|
||||
void set_rds_ecc(int ecc) {
|
||||
rds_params.ecc = ecc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,20 @@
|
|||
#ifndef RDS_H
|
||||
#define RDS_H
|
||||
|
||||
//taken from bartek's MicroRDS https://github.com/barteqcz/MicroRDS/blob/main/src/rds.h
|
||||
#define DI_STEREO (1 << 0) /* 1 - Stereo */
|
||||
#define DI_AH (1 << 1) /* 2 - Artificial Head */
|
||||
#define DI_COMPRESSED (1 << 2) /* 4 - Compressed */
|
||||
#define DI_DPTY (1 << 3) /* 8 - Dynamic PTY */
|
||||
|
||||
#define AF_CODE_FILLER 205
|
||||
#define AF_CODE_NO_AF 224
|
||||
#define AF_CODE_NUM_AFS_BASE AF_CODE_NO_AF
|
||||
#define AF_CODE_LFMF_FOLLOWS 250
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern void get_rds_samples(float *buffer, int count, int stereo, int ct_clock_enabled, float sample_volume);
|
||||
extern void get_rds_samples(float *buffer, int count, int ct_clock_enabled, float sample_volume);
|
||||
extern void set_rds_pi(uint16_t pi_code);
|
||||
extern void set_rds_rt(char *rt);
|
||||
extern void set_rds_ps(char *ps);
|
||||
|
|
@ -34,6 +44,8 @@ extern void set_rds_af(int *af_array);
|
|||
extern void set_rds_tp(int tp);
|
||||
extern void set_rds_ms(int ms);
|
||||
extern void set_rds_ab(int ab);
|
||||
extern void set_rds_di(int di);
|
||||
extern void set_rds_ecc(int ecc);
|
||||
|
||||
|
||||
#endif /* RDS_H */
|
||||
Loading…
Reference in New Issue