Add the ability to receive commands on a named pipe

master
Christophe Jacquet 2014-05-04 12:41:28 +02:00
rodzic 4fdd59327b
commit 20a56c47b0
5 zmienionych plików z 190 dodań i 9 usunięć

Wyświetl plik

@ -54,6 +54,7 @@ All arguments are optional:
* `-pi` specifies the PI-code of the RDS broadcast. 4 hexadecimal digits. Example: `-pi FFFF`.
* `-ps` specifies the station name (Program Service name, PS) of the RDS broadcast. Limit: 8 characters. Example: `-ps RASP-PI`.
* `-rt` specifies the radiotext (RT) to be transmitted. Limit: 64 characters. Example: `-rt 'Hello, world!'`.
* `-ctl` specifies a named pipe (FIFO) to use as a control channel to change PS and RT at run-time (see below).
* `-ppm` specifies your Raspberry Pi's oscillator error in parts per million (ppm), see below.
By default the PS changes back and forth between `Pi-FmRds` and a sequence number, starting at `00000000`. The PS changes around one time per second.
@ -77,6 +78,29 @@ sox -t mp3 http://www.linuxvoice.com/episodes/lv_s02e01.mp3 -t wav - | sudo ./p
```
### Setting PS and RT dynamically at run-time
You can control PS and RT at run-time using a named pipe (FIFO). For this run Pi-FM-RDS with the `-ctl` argument.
Example:
```
mkfifo rds_ctl
sudo ./pi_fm_rds -ctl rds_ctl
```
Then you can send “commands” to change the PS and RT:
```
cat >rds_ctl
PS MyText
RT A text to be sent as radiotext
PS OtherTxt
...
```
## Warning and Diclaimer
Never use this program to transmit VHF-FM data through an antenna, as it is

Wyświetl plik

@ -1,17 +1,19 @@
CC = gcc
STD_CFLAGS = -Wall -std=gnu99 -c -g -O3
# Enable ARM-specific options only on ARM
# Enable ARM-specific options only on ARM, and compilation of the app only on ARM
UNAME := $(shell uname -m)
ifeq ($(UNAME), armv6l)
CFLAGS = $(STD_CFLAGS) -march=armv6 -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp -ffast-math
app: rds.o waveforms.o pi_fm_rds.o fm_mpx.o control_pipe.o
$(CC) -o pi_fm_rds rds.o waveforms.o pi_fm_rds.o fm_mpx.o control_pipe.o -lm -lsndfile
else
CFLAGS = $(STD_CFLAGS)
endif
app: rds.o waveforms.o pi_fm_rds.o fm_mpx.o
$(CC) -o pi_fm_rds rds.o waveforms.o pi_fm_rds.o fm_mpx.o -lm -lsndfile
rds_wav: rds.o waveforms.o rds_wav.o fm_mpx.o
$(CC) -o rds_wav rds_wav.o rds.o waveforms.o fm_mpx.o -lm -lsndfile
@ -19,10 +21,13 @@ rds_wav: rds.o waveforms.o rds_wav.o fm_mpx.o
rds.o: rds.c waveforms.h
$(CC) $(CFLAGS) rds.c
control_pipe.o: control_pipe.c control_pipe.h rds.h
$(CC) $(CFLAGS) control_pipe.c
waveforms.o: waveforms.c waveforms.h
$(CC) $(CFLAGS) waveforms.c
pi_fm_rds.o: pi_fm_rds.c
pi_fm_rds.o: pi_fm_rds.c control_pipe.h fm_mpx.h rds.h
$(CC) $(CFLAGS) pi_fm_rds.c
rds_wav.o: rds_wav.c

95
src/control_pipe.c 100644
Wyświetl plik

@ -0,0 +1,95 @@
/*
PiFmRds - FM/RDS transmitter for the Raspberry Pi
Copyright (C) 2014 Christophe Jacquet, F8FTK
See https://github.com/ChristopheJacquet/PiFmRds
rds_wav.c is a test program that writes a RDS baseband signal to a WAV
file. It requires libsndfile.
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/>.
control_pipe.c: handles command written to a non-blocking control pipe,
in order to change RDS PS and RT at runtime.
*/
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include "rds.h"
#include "control_pipe.h"
#define CTL_BUFFER_SIZE 100
FILE *f_ctl;
/*
* Opens a file (pipe) to be used to control the RDS coder, in non-blocking mode.
*/
int open_control_pipe(char *filename) {
int fd = open(filename, O_RDONLY | O_NONBLOCK);
if(fd == -1) return -1;
int flags;
flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
if( fcntl(fd, F_SETFL, flags) == -1 ) return -1;
f_ctl = fdopen(fd, "r");
if(f_ctl == NULL) return -1;
return 0;
}
/*
* Polls the control file (pipe), non-blockingly, and if a command is received,
* processes it and updates the RDS data.
*/
int poll_control_pipe() {
static char buf[CTL_BUFFER_SIZE];
char *res = fgets(buf, CTL_BUFFER_SIZE, f_ctl);
if(res == NULL) return -1;
if(strlen(res) > 3 && res[2] == ' ') {
char *arg = res+3;
if(arg[strlen(arg)-1] == '\n') arg[strlen(arg)-1] = 0;
if(res[0] == 'P' && res[1] == 'S') {
arg[8] = 0;
set_rds_ps(arg);
printf("PS set to: \"%s\"\n", arg);
return CONTROL_PIPE_PS_SET;
}
if(res[0] == 'R' && res[1] == 'T') {
arg[64] = 0;
set_rds_rt(arg);
printf("RT set to: \"%s\"\n", arg);
return CONTROL_PIPE_RT_SET;
}
}
return -1;
}
/*
* Closes the control pipe.
*/
int close_control_pipe() {
if(f_ctl) return fclose(f_ctl);
else return 0;
}

30
src/control_pipe.h 100644
Wyświetl plik

@ -0,0 +1,30 @@
/*
PiFmRds - FM/RDS transmitter for the Raspberry Pi
Copyright (C) 2014 Christophe Jacquet, F8FTK
See https://github.com/ChristopheJacquet/PiFmRds
rds_wav.c is a test program that writes a RDS baseband signal to a WAV
file. It requires libsndfile.
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/>.
*/
#define CONTROL_PIPE_PS_SET 1
#define CONTROL_PIPE_RT_SET 2
extern int open_control_pipe(char *filename);
extern int close_control_pipe();
extern int poll_control_pipe();

Wyświetl plik

@ -101,6 +101,7 @@
#include "rds.h"
#include "fm_mpx.h"
#include "control_pipe.h"
#define NUM_SAMPLES 50000
@ -205,6 +206,7 @@ terminate(int dummy)
}
fm_mpx_close();
close_control_pipe();
exit(1);
}
@ -262,11 +264,12 @@ map_peripheral(uint32_t base, uint32_t len)
}
#define SUBSIZE 1
#define DATA_SIZE 5000
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, int16_t ppm) {
int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt, int16_t ppm, char *control_pipe) {
int i, fd, pid;
char pagemap_fn[64];
@ -424,20 +427,33 @@ int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt,
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(!ps) {
if(varying_ps) {
if(count == 512) {
snprintf(myps, 9, "%08d", count2);
set_rds_ps(myps);
@ -448,7 +464,11 @@ int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt,
count = 0;
}
count++;
}
}
if(control_pipe && poll_control_pipe() == CONTROL_PIPE_PS_SET) {
varying_ps = 0;
}
usleep(5000);
@ -493,12 +513,15 @@ int tx(uint32_t carrier_freq, char *audio_file, uint16_t pi, char *ps, char *rt,
int main(int argc, char **argv) {
char *audio_file = NULL;
char *control_pipe = NULL;
uint32_t carrier_freq = 107900000;
char *ps = NULL;
char *rt = "PiFmRds: live FM-RDS transmission from the RaspberryPi";
uint16_t pi = 0x1234;
int16_t ppm = 0;
// Parse command-line arguments
for(int i=1; i<argc; i++) {
char *arg = argv[i];
char *param = NULL;
@ -525,11 +548,15 @@ int main(int argc, char **argv) {
} else if(strcmp("-ppm", arg)==0 && param != NULL) {
i++;
ppm = atoi(param);
} else if(strcmp("-ctl", arg)==0 && param != NULL) {
i++;
control_pipe = param;
} else {
fatal("Unrecognised argument: %s\n"
"Syntax: pi_fm_rds [-freq freq] [-audio file] [-ppm ppm_error] [-pi pi_code] [-ps ps_text] [-rt rt_text]\n", arg);
"Syntax: pi_fm_rds [-freq freq] [-audio file] [-ppm ppm_error] [-pi pi_code]\n"
" [-ps ps_text] [-rt rt_text] [-ctl control_pipe]\n", arg);
}
}
tx(carrier_freq, audio_file, pi, ps, rt, ppm);
tx(carrier_freq, audio_file, pi, ps, rt, ppm, control_pipe);
}