summaryrefslogtreecommitdiff
path: root/rdsreceiver.c
diff options
context:
space:
mode:
authorUlrich Eckhardt <uli@uli-eckhardt.de>2018-05-27 12:33:26 (GMT)
committerUlrich Eckhardt <uli@uli-eckhardt.de>2018-05-27 12:33:26 (GMT)
commit73144cec5a92ab7cee0f1de729b1e38ec11d9605 (patch)
treed8c09eb4aeb4ea409e6a2c192ec5238c83f008b8 /rdsreceiver.c
parent71725a25bc2656040784a3dd301cdcb77c5b92e0 (diff)
downloadvdr-plugin-radio-73144cec5a92ab7cee0f1de729b1e38ec11d9605.tar.gz
vdr-plugin-radio-73144cec5a92ab7cee0f1de729b1e38ec11d9605.tar.bz2
Split radioaudio.c
Move classes in file radioaudio.c into own files.
Diffstat (limited to 'rdsreceiver.c')
-rw-r--r--rdsreceiver.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/rdsreceiver.c b/rdsreceiver.c
new file mode 100644
index 0000000..8c95474
--- /dev/null
+++ b/rdsreceiver.c
@@ -0,0 +1,219 @@
+#include <vdr/remote.h>
+#include <vdr/status.h>
+#include <vdr/plugin.h>
+#include "radioaudio.h"
+#include "radioskin.h"
+#include "radiotools.h"
+#include "service.h"
+#include <math.h>
+
+extern bool RdsLogo;
+extern cRadioAudio *RadioAudio;
+
+// --- cRDSReceiver ------------------------------------------------------------
+
+cRDSReceiver::cRDSReceiver(int Pid) {
+ dsyslog("radio: additional RDS-Receiver starts on Pid=%d", Pid);
+
+ pid = Pid;
+ rt_start = rt_bstuff = false;
+}
+
+cRDSReceiver::~cRDSReceiver() {
+ dsyslog("radio: additional RDS-Receiver stopped");
+}
+
+#if VDRVERSNUM >= 20300
+void cRDSReceiver::Receive(const uchar *Data, int Length)
+#else
+ void cRDSReceiver::Receive(uchar *Data, int Length)
+#endif
+ {
+ const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data
+ static unsigned char mtext[mframel + 1];
+ static int index;
+ static int mec = 0;
+
+ // check TS-Size, -Sync, PID, Payload
+ if (Length != TS_SIZE || Data[0] != 0x47
+ || pid != ((Data[1] & 0x1f) << 8) + Data[2] || !(Data[3] & 0x10)) {
+ return;
+ }
+
+ int offset;
+ if (Data[1] & 0x40) { // 1.TS-Frame, payload-unit-start
+ offset = (Data[3] & 0x20) ? Data[4] + 11 : 10; // Header + ADFL + 6 byte: PES-Startcode, -StreamID, -PacketLength
+ if (Data[offset - 3] == 0xbd) { // StreamID = Private stream 1 (for rds)
+ offset += 3; // 3 byte: Extension + Headerlength
+ offset += Data[offset - 1];
+ } else {
+ return;
+ }
+ } else {
+ offset = (Data[3] & 0x20) ? Data[4] + 5 : 4; // Header + ADFL
+ }
+
+ if ((TS_SIZE - offset) <= 0) {
+ return;
+ }
+ // print TS-RawData with RDS
+ if ((S_Verbose & 0x02) == 0x02) {
+ printf("\n\nTS-Data(%d):\n", Length);
+ int cnt = 0;
+ for (int a = 0; a < Length; a++) {
+ printf("%02x ", Data[a]);
+ cnt++;
+ if (cnt > 15) {
+ cnt = 0;
+ printf("\n");
+ }
+ }
+ printf("(End)\n");
+ }
+
+ for (int i = 0, val = 0; i < (TS_SIZE - offset); i++) {
+ val = Data[offset + i];
+
+ if (val == 0xfe) { // Start
+ index = -1;
+ rt_start = true;
+ rt_bstuff = false;
+ mec = 0;
+ if ((S_Verbose & 0x0f) >= 2) {
+ printf("\nRDS-Start: ");
+ }
+ }
+
+ if (rt_start) {
+ if ((S_Verbose & 0x0f) >= 2) {
+ printf("%02x ", val);
+ }
+ // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff
+ if (rt_bstuff) {
+ switch (val) {
+ case 0x00:
+ mtext[index] = 0xfd;
+ break;
+ case 0x01:
+ mtext[index] = 0xfe;
+ break;
+ case 0x02:
+ mtext[index] = 0xff;
+ break;
+ default:
+ mtext[++index] = val; // should never be
+ }
+ rt_bstuff = false;
+ if ((S_Verbose & 0x0f) >= 2) {
+ printf("(Bytestuffing -> %02x) ", mtext[index]);
+ }
+ } else {
+ mtext[++index] = val;
+ }
+ if (val == 0xfd && index > 0) { // stuffing found
+ rt_bstuff = true;
+ }
+ // early check for used MEC
+ if (index == 5) {
+ //mec = val;
+ switch (val) {
+ case 0x0a: // RT
+ case 0x46: // ODA-Data
+ case 0x07: // PTY
+ case 0x3e: // PTYN
+ case 0x30: // TMC
+ case 0x02:
+ mec = val; // PS
+ RdsLogo = true;
+ break;
+ default:
+ rt_start = false;
+ if ((S_Verbose & 0x0f) >= 2) {
+ printf("[RDS-MEC '%02x' not used -> End]\n", val);
+ }
+ }
+ }
+ if (index >= mframel) { // max. rdslength, garbage ?
+ rt_start = false;
+ if ((S_Verbose & 0x0f) >= 2) {
+ printf("(RDS-Error: too long, garbage ?)\n");
+ }
+ }
+ }
+
+ if (rt_start && val == 0xff) { // End
+ rt_start = false;
+ if ((S_Verbose & 0x0f) >= 2) {
+ printf("(RDS-End)\n");
+ }
+ if (index < 9) { // min. rdslength, garbage ?
+ if ((S_Verbose & 0x0f) >= 1) {
+ printf("RDS-Error: too short -> garbage ?\n");
+ }
+ } else {
+ // crc16-check
+ unsigned short crc16 = crc16_ccitt(mtext, index - 3, true);
+ if (crc16 != (mtext[index - 2] << 8) + mtext[index - 1]) {
+ if ((S_Verbose & 0x0f) >= 1) {
+ printf(
+ "RDS-Error: wrong CRC # calc = %04x <> transmit = %02x%02x\n",
+ crc16, mtext[index - 2], mtext[index - 1]);
+ }
+ } else {
+ switch (mec) {
+ case 0x0a:
+ RadioAudio->RadiotextDecode(mtext, index); // Radiotext
+ break;
+ case 0x46:
+ switch ((mtext[7] << 8) + mtext[8]) { // ODA-ID
+ case 0x4bd7:
+ RadioAudio->RadiotextDecode(mtext, index); // RT+
+ break;
+ case 0x0d45:
+ case 0xcd46:
+ if ((S_Verbose & 0x20) > 0) {
+ unsigned char tmc[6]; // TMC Alert-C
+ int i;
+ for (i = 9; i <= (index - 3); i++) {
+ tmc[i - 9] = mtext[i];
+ }
+ tmc_parser(tmc, i - 8);
+ }
+ break;
+ default:
+ if ((S_Verbose & 0x0f) >= 2) {
+ printf(
+ "[RDS-ODA AID '%02x%02x' not used -> End]\n",
+ mtext[7], mtext[8]);
+ }
+ }
+ break;
+ case 0x07:
+ RT_PTY = mtext[8]; // PTY
+ if ((S_Verbose & 0x0f) >= 1) {
+ printf("RDS-PTY set to '%s'\n",
+ ptynr2string(RT_PTY));
+ }
+ break;
+ case 0x3e:
+ RadioAudio->RDS_PsPtynDecode(true, mtext, index); // PTYN
+ break;
+ case 0x02:
+ RadioAudio->RDS_PsPtynDecode(false, mtext, index); // PS
+ break;
+ case 0x30:
+ if ((S_Verbose & 0x20) > 0) { // TMC Alert-C
+ unsigned char tmc[6];
+ int i;
+ for (i = 7; i <= (index - 3); i++) {
+ tmc[i - 7] = mtext[i];
+ }
+ tmc_parser(tmc, i - 6);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+}