Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Internetradio, meine Programmierversuche
#1
Hallo zusammen,

irgendwie hat mich auch der Bazillus zum Internetradiobasteln infiziert.
Warum ist das ganze nur so extrem ansteckend Huh 

Zum testen der grundsätzlichen Funktion der Softwareinstallation habe ich mir, auch als erste Programmierübung in C, ein Textbasiertes Frontend gebastelt:

.png   Bildschirmfoto vom 2018-11-25 20-37-00.png (Größe: 10,22 KB / Downloads: 510)

Das Progrämmchen hat noch einige Schwächen, z.B. ist das zyklische einlesen der Informationen nicht möglich, da das Ding immer auf die Tasteneingabe wartet.
Ich habe allerdings nicht vor, daran weiter zu arbeiten.
Das ganze war einfach mal um zu testen, ob das Radio auch läuft.
In der Praxis wäre es etwas ungut, wenn ich zur Bedienung des Radios jedesmal den PC anwerfen muss.

Meine nächsten Vorhaben:

- Ein grafisches Frontend für ein Stand-alone-Gerät unter Verwendung der von Bernhard empfohlenen Software.

- Ein Modul zum nach- bzw. aufrüsten von beliebigen Geräten.
Hier habe ich eine ganz spartanische Lösung geplant, mit Poti und A/D-Wandler zur Senderwahl sowie optional ein I²C-Display.

Da meine vorhandenen Teile (z.B. Displayansteuerung) für 5V-Logik ausgelegt sind, missbrauche ich einen Schnittstellenisolator ADuM 1250 als Pegelwandler.
Damit kann ich dann bei Bedarf auch eine vollständige galvanische Trennung vom Raspberry-Pi realisieren.
A/D-Wandler für I²C (12 bit) habe ich auch noch rumliegen.

Basis soll in beiden Fällen das von Bernhard geschnürte Softwarepaket sein.


Grüße

Martin
Zitieren
#2
Das wird spannend, ich freue mich!
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#3
So, weiter geht's.

Hier zunächst die Schaltung, wie ich die Skalenposition zum Raspberry Pi übertragen will:

   

Den Schnittstellenisolator ADuM1250 missbrauche ich hier als Pegelwandler.
Der MCP3426 ist ein 12-bit Analog-Digitalwandler.
Mit einem Poti habe ich den Vorteil, dass ich immer ziemlich genau weiß, wo der Skalenzeiger momentan steht.
Das ist also gewissermaßen ein Absolutwegmesssystem.

Mit der Software klappt es leider noch nicht so, wie ich mir das vorgestellt habe.
Ich wollte ursprünglich nach dem Schema 'system(Variable);' das ganze an das remote-control übergeben, allerdings passieren da Dinge, auf welche ich mir momentan noch keinen Reim machen kann:

   

Während der Variableninhalt (2. Zeile von oben) einem vollständigen Befehl entspricht, fehlen in der Ausgabe (vorletzte Zeile) einige Zeichen Huh .

Die Auswertung der Potiposition stelle ich mir so vor, dass ich die theoretischen 4096 Digits, welche der AD-Wandler liefert in eine ungerade Anzahl von Blöcken aufteile.
Nur bei geradzahligen Blöcken wird eine Station aufgerufen, die ungeradzahligen sind die Lücken zwischen den Sendern.
Bei den Lücken soll dann auch die LED angesteuert werden, die mir an unauffälliger Stelle eine 'Senderlücke' signalisiert.

Ich werde mir nun die nächsten Tage die oben gezeigte Schaltung auf einem Steckbrett aufbauen und mit einem Arduino testen, ob sie grundsätzlich funktioniert.
Dann werde ich mich mit I²C am Raspberry Pi beschäftigen.
Laut meinen Internetrecherchen soll da 'wiringpi' ganz hilfreich sein.


Grüße

Martin
Zitieren
#4
Die Pullup Wiederstände sind überflüssig denn der Pi hat am I2C Bus welche eingebaut die man per Software auch nicht abstellen kann. Bei den Problemen mit deiner Software kann ich ohne Quellcode nicht helfen. Für die Programmierung der GPIO hat Bernhard bereits die BCM2835 Bibliothek in das iRadio mit aufgenommen. Ein Beispielsprogramm ist auch dabei. gpiod.c
Die Bibliothek wird dort bei der Installation vom iRadio direkt übersetzt.
Ich weiß nicht ob es zu Problemen kommt wenn man dann auch noch WiringPi hinzunimmt. Eigentlich sollte BCM2835 aber ausreichen. Bernhard hat auch im BCM Ordner unter Examples die Demos stehenlassen die die Bibliothek mitbringt. U.a. auch etwas zu I2C.

Otto.
Zitieren
#5
Hallo zusammen,

heute bin ich weiter gekommen als gedacht!
Die weiter oben gezeigte Schaltung habe ich mit einigen Modifikationen aufgebaut und an einem Arduino getestet.

Im Internet habe ich dann ein Codebeispiel zur Abfrage eines MCP3426 gefunden, hier musste nur noch aus dem Hauptprogramm eine Funktion gemacht werden, und schon kann ich die Potiabfrage zyklisch aufrufen.
Den Teiler habe ich hier mal für eine Senderliste mit 31 Sendern festgelegt:


.png   Bildschirmfoto vom 2018-11-27 23-54-19.png (Größe: 10,55 KB / Downloads: 318)

Da ich die ungeradzahligen 'Sendernummern' auslassen möchte (als Lücke zwischen den Sendern) brauche ich 31 * 2 = 62 + 1 = 63 Positionen.
Die Ansteuerung der LED als Signalisierung der 'Senderlücken' funktioniert auch schon.

Sobald ich mit dem Code fertig bin, werde ich ihn hier einstellen.

Noch ein Hinweis zum MCP3426:
Da dieses Bauteil Massesymmetrische Spannungen (+- 2,048V) messen kann, bekomme ich hier nur 2047 digits zurück.
Gleichzeitig muss dann vor das Poti (zwischen +5V und Poti) ein Teilerwiderstand, damit die über dem Poti liegende Spannung nur 2,048V beträgt.
Natürlich könnte man auch eine passende Referenzdiode verwenden.


Grüße

Martin
Zitieren
#6
Hallo zusammen,

das ist das Resultat des heutigen Tages:


.png   Bildschirmfoto vom 2018-11-28 21-18-01.png (Größe: 8,33 KB / Downloads: 291)

Leider funktioniert der 'goto'-Befehl des remote-control nicht so, wie ich es eigentlich erwartet habe!
Jedenfalls wird auffallend oft anstelle des eigentlich gewünschten Senders der erste Sender der Tabelle aufgerufen.

Hier der Code:

Code:
/* iradio_V2
Dient als Nachrüstlösung ohne Displayausgabe z.B. für Radios ohne UKW-Teil.
Die Senderwahl wird mittels eines Dreh- oder Linearpoti vorgenommen, zum einlesen dient ein A/D-Wandler vom Typ MCP3426.
Das zugehörige Programmteil habe ich im Internet gefunden und für meine Bedürfnisse angepasst.
Betriebart ist 12-bit, Kanal 1                                                                                            */

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <bcm2835.h>
#include <stdint.h>
#include <string.h>

#define PIN_1 RPI_GPIO_P1_11
#define teiler 32

/* Definition der Textfarben */
#define ANSI_BLACK            "\x1b[30m"
#define ANSI_RED            "\x1b[31m"
#define ANSI_GREEN            "\x1b[32m"
#define ANSI_BROWN            "\x1b[33m"
#define ANSI_BLUE            "\x1b[34m"
#define ANSI_MAGENTA        "\x1b[35m"
#define ANSI_CYAN            "\x1b[36m"
#define ANSI_LIGHTGRAY        "\x1b[37m"
#define ANSI_DARKGRAY        "\x1b[1;30m"
#define ANSI_LIGHTRED        "\x1b[1;31m"
#define ANSI_LIGHTGREEN        "\x1b[1;32m"
#define ANSI_YELLOW            "\x1b[1;33m"
#define ANSI_LIGHTBLUE        "\x1b[1;34m"
#define ANSI_LIGHTMAGENTA    "\x1b[1;35m"
#define ANSI_LIGHTCYAN        "\x1b[1;36m"
#define ANSI_WHITE            "\x1b[1;37m"

/* Definition der Hintergrundfarben */
#define ANSI_GRND_BLACK        "\x1b[40m"
#define ANSI_GRND_RED        "\x1b[41m"
#define ANSI_GRND_GREEN        "\x1b[42m"
#define ANSI_GRND_BROWN        "\x1b[43m"
#define ANSI_GRND_BLUE        "\x1b[44m"
#define ANSI_GRND_MAGENTA    "\x1b[45m"
#define ANSI_GRND_CYAN        "\x1b[46m"
#define ANSI_GRND_GRAY        "\x1b[47m"

/* Setzt Farben wieder auf den Ursprungszustand */
#define ANSI_DEFAULTCOLORS    "\x1b[0m"


/* Weitere Funktionen */
#define ANSI_CLS()            printf("\x1b[2J\x1b[1;1H")
#define ANSI_LOCATE( x, y )    printf("\x1b[%i;%iH", y, x)
#define ANSI_CLREOL()       printf("\x1b[K")
#define ANSI_COLOR( c )        printf(c) /* Hierbei ist 'c' eine der obigen Farbkonstanten */



int lesen()

// Distributed with a free-will license.
// Use it any way you want, profit or free, provided it fits in the licenses of its associated works.
// MCP3426
// This code is designed to work with the MCP3426_I2CADC I2C Mini Module available from ControlEverything.com.
// https://www.controleverything.com/content/Analog-Digital-Converters?sku=MCP3426_I2CADC#tabs-0-product_tabset-2

{
    // Create I2C bus
    int file;
    int raw_adc;                //neu deklariert, war usprünglich weiter unten in einer else-Klausel deklariert
   char *bus = "/dev/i2c-1";
    if((file = open(bus, O_RDWR)) < 0)
    {
        printf("Failed to open the bus. \n");
        exit(1);
    }
    // Get I2C device, MCP3426 I2C address is 0x68(104)
    ioctl(file, I2C_SLAVE, 0x68);

    // Select configuration command(0x10)
    // Continuous conversion mode, channel-1, 12-bit resolution
    char config[1] = {0};
    config[0] = 0x10;
    write(file, config, 1);
    //sleep(1);
   delay(100);

    // Read 2 bytes of data from register(0x00)
    // raw_adc msb, raw_adc lsb
    char reg[1] = {0x00};
    write(file, reg, 1);
    char data[2] = {0};
    if(read(file, data, 2) != 2)
    {
        printf("Error : Input/output Error \n");
    }
    else
    {
        // Convert the data to 12-bits
        raw_adc = ((data[0] & 0x0F) * 256 + data[1]);
        if(raw_adc > 2047)
        {
            raw_adc -= 4095;
        }

        // Output data to screen
        //printf("Digital value of Analog Input : %d \n", raw_adc);
    }
   close(file);              //Nachtrag 28.11.18 MR
   return raw_adc;
}


void info_lesen(int sender)

{
    char station[70];
    char titel[70];
    char station_neu[70];
    char titel_neu[70];
    int schleife;
    FILE *text1 = popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep now_playing:", "r");
    fgets(titel,70,text1);
    pclose(text1);
    FILE *text2 = popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep title:", "r");
    fgets(station,70,text2);
    pclose(text2);
    for (schleife = 15; schleife < 71; schleife++)
       titel_neu[schleife-15] = titel[schleife];
    for (schleife = 9; schleife < 71; schleife++)
       station_neu[schleife-9] = station[schleife];
    ANSI_COLOR(ANSI_GRND_BLUE);
    ANSI_CLS();
    ANSI_COLOR(ANSI_LIGHTGREEN);
    ANSI_LOCATE(10,5);
    printf("Info für Sender %d",sender);
    ANSI_COLOR(ANSI_LIGHTGRAY);
    ANSI_LOCATE(10,10);
    printf("Station:    %s",station_neu);
    ANSI_LOCATE(10,16);
    printf("Titel:      %s",titel_neu);
}



void entscheid (int sender)

{
    switch(sender)
   {
   case 0:
           system("echo \"goto 1\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 2:
           system("echo \"goto 2\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 4:
           system("echo \"goto 3\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 6:
           system("echo \"goto 4\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 8:
           system("echo \"goto 5\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 10:
           system("echo \"goto 6\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 12:
            system("echo \"goto 7\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 14:
            system("echo \"goto 8\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 16:
            system("echo \"goto 9\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 18:
            system("echo \"goto 10\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 20:
            system("echo \"goto 11\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 22:
            system("echo \"goto 12\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 24:
            system("echo \"goto 13\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 26:
            system("echo \"goto 14\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 28:
            system("echo \"goto 15\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 30:
            system("echo \"goto 16\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 32:
            system("echo \"goto 17\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 34:
            system("echo \"goto 18\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 36:
            system("echo \"goto 19\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 38:
            system("echo \"goto 20\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 40:
            system("echo \"goto 21\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 42:
            system("echo \"goto 22\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 44:
            system("echo \"goto 23\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 46:
            system("echo \"goto 24\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 48:
            system("echo \"goto 25\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   case 50:
            system("echo \"goto 26\" | nc 127.0.0.1 9294 -N");
            bcm2835_gpio_write(PIN_1, LOW);
            //system("echo \"play\" | nc 127.0.0.1 9294 -N");
           break;
   default:
            bcm2835_gpio_write(PIN_1, HIGH);
            //system("echo \"stop\" | nc 127.0.0.1 9294 -N");
           break;
   } //Ende der Case-Verzweigung
}


int main()
    {
    int wert;
    int sender;
   int sender_alt = 999;

   if (!bcm2835_init())
    return 1;
    bcm2835_gpio_fsel(PIN_1, BCM2835_GPIO_FSEL_OUTP);

    while (1)
          {
          wert = lesen();
          if (wert == 0) wert = 1;
          sender = wert / teiler;
               if (sender != sender_alt)
                  {
                    system("echo \"stop\" | nc 127.0.0.1 9294 -N");
                   //printf("rufe switch mit %d /n",sender);
                    entscheid(sender);
                    sender_alt = sender;
                    system("echo \"play\" | nc 127.0.0.1 9294 -N");
                       }
          info_lesen((sender/2)+1);
          }
    ANSI_COLOR(ANSI_DEFAULTCOLORS);
    ANSI_CLS();
    return 0;
    }


Grundsätzlich funktioniert alles so, wie es soll.
In den 'Senderlücken' leuchtet eine LED als zur Signalisierung auf.

Hier noch die geänderte Ansteuerschaltung sowie die Version 2 mit zusätzlicher einstellbarer Referenzdiode:

   

   

Noch ein Tipp am Rande zu den Potis: Beim großen C gibt es Schieberegler mit allen möglichen Betätigungswegen.
Manchmal wird es einfacher sein, so ein Teil zu adaptieren als ein Drehpoti.

Als 'Opfergerät' habe ich einen Siemens Klangmeister RG71 ausgewählt.
Dieser bedarf allerdings noch einiger Zuwendung, da beide Drehkondensatoren fest sind.

Das scheint aber ein typisches Leiden dieser Geräteserie zu sein.
Meine insgesamt 4 RG51 haben das gleiche Problem.

Auch will vorher noch mein Grundig 4055 fertiggestellt werden, der blockiert momentan die Werkbank.


Viele Grüße

Martin
Zitieren
#7
Hallo Martin. Bei weiteren Experimenten wirst du vielleicht feststellen das er erste Sender in der VLC programmliste nicht immer bei 1 oder 0 beginnt. Eventuell erst ab 5 oder 6 und die vorgerhegenden Einträge haben andere Funktionen. Du solltest also eine Offset variable definieren die den Verschub ausgleicht. Deine Switchvariante ist auch alles andere als günstig. Die Umschaltung mit eine Leerposition kann man über eine Rechenregel viel eleganter machen. 2*n ist immer gerade 2*n+1 immer ungerade. Und mit dem Modulooperator % hast du sowieso alle Freiheit deinen Switchkode auf 3-4 Zeilen zu verkürzen. Du solltest deinen Code generell so auslegen das er auch kürzere und längere Programmlisten fehlerfrei verarbeit. Das tut er im Moment nicht. Ich lese dazu bei Programmstart erstmal die Senderliste ein und bestimme die Anzahl der Zeilen und damit Anzahl der Sender. Erst dann verteile ich die Sender rechnerisch über die Senderskala. Man kann auch überlegen in der Zwischenposition eine Datei mit Wellenrauschen wiederzugeben.

Otto.
Zitieren
#8
Auch von mir ein Hallo,

da steckt einiges wahres drin was Otto erwähnt hat. In diesem Codeteil:

if (sender != sender_alt)
{
system("echo \"stop\" | nc 127.0.0.1 9294 -N");
/printf("rufe switch mit %d /n",sender);
entscheid(sender);
sender_alt = sender;
system("echo \"play\" | nc 127.0.0.1 9294 -N");
}

kannst Du Dir das Stoppen und Wiederanlaufen sparen. Es ist eigentlich nicht vorgesehen, VLC beim Wechsel eines Streams anzuhalten. Es reicht wenn über next/prev oder goto ein neuer Playlisteintrag ausgewählt wird. Die Freigabe von Ressourcen und die Allokierung erfolgt innerhalb von VLC automatisch! Wenn Du unbedingt eine Pause zwischen den Sendern benötigst, solltest Du das über das Muten von VLC realisieren und dabei bereits den Zeiger auf den nächsten Eintrag der Playlist setzen. So kann in diesem "stillen" Zwischenraum bereits der Stream geholt werden. Das kann je nach Sender durchaus mal eine, zwei oder drei Sekunden dauern was dann zur Folge hat, dass es scheint, das sich die Applikation nicht so flüssig bedienen lässt wie sie sollte.

Gruß Bernhard
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#9
Hallo Otto, hallo Bernhard,

zunächst vielen Dank für die Rückmeldungen!

@Otto:
Dass die switch-case-Variante alles andere als optimal ist ist mir auch bewusst!
Nur ist es mir bis dato noch nicht gelungen, ein vlc-Kommando per Programm zusammenzusetzen.
Bei meinem ersten Versuch ist das passiert:


.png   Bildschirmfoto vom 2018-11-29 16-39-26.png (Größe: 8,87 KB / Downloads: 253)

Hier ist der Code dazu:


Code:
/* stringcat.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(void) {
  char ziel_1[60] = {34,'e','c','h','o',' ',92,34};
  char ziel[30] = "| nc 127.0.0.1 9294 -N ";
  char name[20] = "volup 2";
  char sender[5];
  int station = 10;
 
  //sender = itoa(station,10);
  strcat(ziel_1, name);
  //strcat(ziel_1,sender);
  ziel_1[strlen(ziel_1)] = 92;
  ziel_1[strlen(ziel_1)] = 34;
  ziel_1[strlen(ziel_1)] = 32;
  strcat(ziel_1, ziel);
  ziel_1[strlen(ziel_1)] = 34;
  printf("%s",ziel_1);
  puts("\n");
  system(ziel_1);
  return 0;
}


//system("echo \"goto xxx\" | nc 127.0.0.1 9294 -N");
während bei der Textausgabe (2. Zeile im Screenshot) der Befehl noch vollständig ist, fehlen bei der Befehlsausgabe (vorletzte Zeile) etliche Zeichen Huh .
Das war der Grund dafür, dass ich mir zunächst mit switch-case geholfen habe.
An den modulo-Operator habe ich nämlich auch schon gedacht.

@all:
Aus dem Verhalten des goto-Kommandos werde ich noch nicht ganz schlau.
Es ist ja nicht nur so, dass am Anfang am vier Positionen die selbe Station gespielt wird.
Er schaltet auch nicht alle in der Liste enthaltenen Stationen durch, es kommt auffallend oft die erste gelistete Station!


Viele Grüße

Martin
Zitieren
#10
Na Martin, ist doch klar warum das nicht geht.
Zu erzeugst ja auch ein falsches Kommando. Du erzeugst genau den Kommandostring den dein Programm direkt nach dem Aufrufen ausgibt, also
"echo \"volup 2\" | nc 127.0.0.1 9294 -N" aber schon das ist falsch!

Der system-Aufruf aber sieht so aus: int system(const char *command)
Das command muss also lauten: echo \"volup 2\" | nc 127.0.0.1 9294 -N und nicht "echo \"volup 2\" | nc 127.0.0.1 9294 -N"

Was sollen die zusätzlichen Anführungszeichen am Kommandoanfang und -ende? Die haben in command nichts zu suchen, lediglich wenn man das commando direkt im system-Aufruf zuweist, also dem char* command direkt im system-call einen Wert zuweist, dann schreibt man system("echo \"volup 2\" | nc 127.0.0.1 9294 -N");
Das was Du in deinem Programm ausführst entspricht praktisch system(""echo \"volup 2\" | nc 127.0.0.1 9294 -N""); und das ist falsch.

Der Compiler wird nicht meckern, denn für Ihn ist beides ein char*, für die Konsole aber ist es ein Unterschied.

Was mich auch verwirrt ist dein Mischmasch an unterschiedlichen Initialisierungen und Wertzuweisungen.

 char ziel_1[60] = {34,'e','c','h','o',' ',92,34};
 char ziel[30] = "| nc 127.0.0.1 9294 -N ";

??? Warum mal so (char-weise) und dann als kompletten String? Letzteres ist doch viel übersichtlicher.
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#11
Hallo Bernhard,

sorry, aber das funktioniert auch nicht:


.png   Bildschirmfoto vom 2018-11-29 20-19-58.png (Größe: 9,86 KB / Downloads: 215)

Irgendwas geht da schief, ich komme nur nicht dahinter, was.
Ich glaub' ich bin zu blöd für C oder noch zu sehr dem gewohnten Turbo-Pascal resp. Delphi verhaftet.


Noch eine andere Sache!

Mit der Senderliste passieren Abenteuerliche Dinge!

Während nach einem Neustart des Raspberry-Pi die Liste schön mit aufeinanderfolgenden Nummern beginnt, werden im laufe des Betriebs Einträge umnummeriert und teilweise auch vervielfältigt.

Ab Nummer 8 wird umnummeriert, und zwar dann zunächst jeweils  um +27.
Die Nummern 12 bis 17 bleiben dann unberührt, ab 18 beginnt das Spiel wieder.
22 bleibt wieder unberührt.
Aus der ursprünglichen Nummer 23 werden dann die Nummern 43 bis 47
24 wird 48
25 bleibt
26 wird 49 bis 53
27 bleibt
28 wird 54
29 wird 55 bis 59
30 wird 60
31 wird 61 bis 65
32 bleibt
33 wird 66
34 wird 67

Also daraus werde ich gar nicht schlau!


Grüße

Martin
Zitieren
#12
Doch Martin das funktioniert, aber du hast schon wieder ein Fehler im Zusammenbau des Kommandostings gemacht, das zeigt deine Programmausgabe! Ich glaube Du hast gar keine Ahnung was das Kommando überhaupt auf der Konsole macht und wie es dort auszusehen hat? Was bedeutet denn der Echo Befehl in der Kommandozeile und was bedeutet dieses Zeichen |  ?

In der Konsole sieht das gesamte Kommando so aus: echo "volup 2" | nc 127.0.0.1 9294 -N    und genauso muss es dein Programm auch ausgeben! Das tut es aber nach deinem Screenshot nicht. Warum? Weil Du immer noch die Sache mit den \" nicht gefixed hast! \" ist ein Zeichen und nicht zwei, der Backslash ist ein Maskierungszeichen für das Anführungszeichen, weil das Anführungszeichen innerhalb eines Strings in C/C++ niemals ohne Backslash stehen kann! Normalerweise beendet ein Anführungszeichen innerhalb eines Strings diesen ja wenn es ohne Backslash im Programmcode steht.

Der String ist in C also: echo \"volup 2\" | nc 127.0.0.1 9294 -N  (wie oben geschrieben), in der Konsole aber echo "volup 2" | nc 127.0.0.1 9294 -N

So schwer ist die Sache doch nicht? Informiere Dich dringend zu Maskierungszeichen oder Escape sequence in C / C++, sonst wirst Du nie verstehen wie sich Zeichenketten (Strings) in C oder C++ verhalten oder zusammensetzen.


.png   Bildschirmfoto vom 2018-11-29 20-19-58.png (Größe: 14,08 KB / Downloads: 195)
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#13
Hallo Bernhard,

danke, jetzt ist der Groschen gefallen!
Aber das mit den Escape-Sequenzen und Fluchtsymbolen ist insbesondere für Pascal-Umsteiger schon eine kleine Herausforderung!

Ich war bisher der Ansicht, dass die Backshlashes zum Konsolenkommando gehören!
Leider habe ich noch keine Kommandobeschreibung zum VLC bzw. zum zugehörigen remote-control gefunden.


Jetzt muss ich mir nur noch die bei Linux fehlende 'itoa' basteln, dann werde ich die lange switch-case-Schleife los.

Wie ich mit der 'Verstümmelung' der Senderliste (s. oben) umgehen soll, dazu muss ich mir auch noch Gedanken machen.
Ideen habe ich leider noch keine.


Viele Grüße

Martin
Zitieren
#14
Wenn der Compiler die itoa (also Integer to String Umwandlung) nicht mitbringt, dann geht es sicher auch so:

sprintf(char* Zielstring, "%ld",int Quelle); siehe: http://openbook.rheinwerk-verlag.de/c_vo...e59f80a1af

Der Formatstring in der Mitte kann natürlich eigenen Bedürfnissen angepasst werden, somit könntest Du mit einem einzigen Befehl das ganze Kommando für die Senderumschaltung zusammensetzen.

_____

Das mit der Senderliste muss näher, aber vorallem systematisch untersucht werden. Wenn dann kann ja nur VLC eine Umsortierung machen, wir selbst ändern mit den iRadio ja nichts an der Senderliste sondern verschieben diese nur mittels mv-Befehl.

Fürs Erste vielleicht mal folgendes.

1. VLC- interne Senderliste in vlc über das remote control interface löschen.

-Kontrolle ob alles gelöscht wurde -> komplette Senderliste über das remote control interface ausgeben lassen
-Ist die Senderliste über das Webinterface ebenfalls leer?

2. VLC killen und danach über sudo /usr/bin/vlcd neu starten. Durch den Neustart wird die Senderliste vom Dateisystem neu eingeladen.

-Vergleich Senderliste auf Dateisystem, Senderliste im Webbrowser, Senderliste über remote control interface

Gibt es Unterschiede? Wenn ja, vielleicht immer bei bestimmten Sendern oder Streamformaten? Durch Umstellen der Senderliste auf Dateibasis reproduzieren bzw. bestätigen? 

Wenn man Anhaltpunkte hat, wann es zu Umstellungen kommt, kann man den Sourcecode von cvlc dahingehen untersuchen und schauen ob es einen Bug gibt der dafür verantwortlich ist.
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#15
Hallo Martin, hallo zusammen, 

ich habe mal meine Playlisten auf verschiedenen Geräten nach obigen Muster hin untersucht, mit dem Ergebnis das hier bei mir nichts durcheinandergewürfelt wird. 

Item 1, also Sender 1 läuft auf allen meinen Instanzen wie gehabt immer intern mit einem Offset von 4, sprich also auf internen Programmplatz 5 los. Die vorherigen Plätze sind, sofern sie nicht wie Feststationsspeicher selbst angelegt werden, immer mit der ersten URL in der Playlist belegt. [Änderungen in zukünftigen Versionen sind möglich!]

Programmtechnisch habe ich das immer so umgesetzt,  den ersten Eintrag über den search-Befehl und der URL gesucht und dann ab dem gefundenen Offset geschaltet. Da ich mir nicht sicher sein kann das der Offset immer 4 ist (er kann bei neuen Versionen auch komplett entfallen oder größer/kleiner werden), kann man das natürlich nicht hart in den Programmcode kodieren, man muss also immer über die Suchfunktion gehen.

Hier ein Vergleich der Listenausgaben, alle Sender bleiben an Ihrer Stelle.

   

   

   

Was aber passieren kann, zum Beispiel in neuen Versionen automatisch oder man stößt es über den sort-Befehl im remote control interface an, ist das die Liste sortiert wird. Nach was man sortiert, kann man ja im "key" selbst festlegen. 
Eventuell alphabetisch oder nach der Rangfolge wie oft ein Stream abgespielt wurde! Man muss auch beachten das sich Einträge dynamisch in der Liste ändern können sobald ein Stream einmal angespielt wird! 
So wird die kryptische URL in der Regel nach wenigen Sekunden durch den Sendernamen ersetzt (siehe oben) und ist ab diesem Zeitpunkt auch nur noch unter dem Sendernamen in der vlc-internen Senderdatenbank auffindbar. Wenn man sich also den Offset per URL holen will, dann geht das nur am Anfang direkt nach dem Programmstart! 

Glaskugelmodus an:
Wird von irgendeinem anderen Prozess die Playlist erneut sortiert bzw. aktualisiert, kann es zu deinem Phänomen kommen Martin. Möglicherweise händisch oder automatisch ausgelöst, musst Du mal nachschauen wie das bei Dir gemacht wird und wer das macht.
Glaskugelmodus aus:

Man selbst kann die Playlist ja auch über netcat editieren, verschieben oder gar neu "line by line" einspielen, siehe Liste aller Befehle die man mit "help" erhält. Hier ist man Programmiertechnisch frei und kann sich austoben. Man könnte sogar, will man auf die interne Playlist/Datenbank von VLC verzichten, die Playlist extern mit einem Programm in eine eigenen Datenstruktur (Array z.B.) einlesen und jeweils einen Stream per add-Befehl zu VLC schicken. Der Stream wird dann automatisch abgespielt und die Playlist dient nur als eine Art History. Dann wird man so ein Phänomen wie Martin es beschreibt nie haben können, man verliert dadurch aber halt die Datenbankfunktionen von VLC und muss diese Funktionen, wenn man sie benötigt, extern selbst implementieren.

Gruß Bernhard
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#16
ACHTUNG: vermutlich ein Bug in älteren (und neueren?) VLC Versionen!

Bingo Martin, ich habe etwas gefunden!  Da ich die Version 2.2.6 Umbrella von VLC eingesetzt habe und damit kein Fehlverhalten feststellen konnte, habe ich mir von der VLC-Projektseite aus dem FTP eine alte Version ( genau die 2.0.3 Twoflower ) direkt als Sourcecode gezogen und übersetzt. 


 BINGO ! Die 2.0.3 hat eine interessante Mathematik bei längeren Senderlisten, schaut selbst!

   

Kanal 52 fehlt zum Beispiel komplett, wird dieser aber von einem externen Programm angewählt, dann passiert folgendes:

   

Jetzt ist nicht nur die Nummerierung am Listenende völlig im A****.

Wähle ich händisch den jetzt plötzlich nicht mehr existierenden Kanal 51, so ist dieser intern gar nicht vergeben und VLC schaltet defaultmäßig und richtigerweise auf den ersten Stream in der Liste der funktioniert und das ist Kanal 5, das Schwarzwaldradio. Bestätigt wird das in dem ich mir über den Status-Befehl den aktuell spielenden Stream ausgeben lasse!

!!!Hier ist also von einem Fehler in VLC auszugehen!!! Passt also auf wenn Ihr ein bestehendes Internetradio habt, in dem die Firmware zur Umschaltung auf den "goto" oder "gotoitem" Befehl angewiesen ist! Üblicherweise wird das der Fall sein, wenn Ihr Stationstasten verbaut habt oder mittels Poti und ADC oder per Stufenschalter das Progamm umschaltet.

Ein Update oder Downgrade der VLC-Software kann hier zu Fehlern führen!

Wird die Umschaltung über die Befehle next und prev gemacht, üblicherweise also bei Geräten mit Encoderbedienung, tritt der Fehler bisher nicht auf! Wahrscheinlich weil VLC intern die nächste Station richtig anspringen kann und nicht auf einen leeren (nicht vorhanden) Programmplatz zugreift.

Als Workaround sehe ich im Moment nur folgende Lösung.
Programmliste im eigenen Programm öffnen und in einer eigenen Liste (Array, List,...) vorhalten.
Befehle goto oder gotoitem durch add [URL aus eigener Liste] ersetzen. 
Displayroutinen brauchen in der Regel kein Update, den VLC holt die Senderinfo der eingestellten 
Station richtig ab. Diese Metadaten können weiter ganz normal per info oder status-Befehl abgerufen werden.
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#17
Achtung auch die aktuellste über das Raspbian-Paketsystem verteile VLC Version "3.0.3 Vetinari" ist von dem Fehler betroffen!

Hier klappt zwar das Einlesen der Programmliste im Gegensatz zur Version 2.0.3  fehlerfrei. Greift man jedoch per goto oder gotoitem auf das (n-1) - te Element der internen Programmliste zu, wird das Listenende ebenfalls zerstört.

Offensichtlich hat man als Basis für die 3er Version einen nur teilkorrigierten 2er-Zweig genommen. 
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren
#18
Ich kann die Experimente von Bernhard und die Probleme mit VLC bestätigen. 

Nach Bernhards Vorschlag hier mein Patch für meine Radios die mit Python laufen.

Zuerst wird eine neue Funktion definiert die die Programmliste von der SD-Karte liest.

Zitat:def getPlaylistChannels():
             playlist = "/home/bananapi/.config/vlc/playlist.m3u"
             mode = "r"

             file = open(playlist,mode)
             lines = file.readlines()

             file.close()
             return lines

Der Rückgabewert ist eine Stringliste und damit genau das was Bernhard vorgeschlagen hat.
Im weiteren Programm wende ich die Funktion so an.
Zitat:wifi_radio_channels = getPlaylistChannels()
num_wifi_radio_channels = len(wifi_radio_channels)

wifi_radio_channels = eigene Senderliste innerhalb meines Programmcodes
num_wifi_radio_channels = Anzahl der Programme in der Senderliste
Anstelle mit goto [index] schalte ich die Programm jetzt mit add [URL] um.
Zitat:if vlc.connect():
           vlc.communicate("add " + wifi_radio_channels[cur_wifi_radio_channel])

Der Patch funktioniert für alle VLC-Versionen und somit automatisch auch für das iRadio und Pimoroni-Paket.
Lediglich die Programmliste im Webbrowser wächst mit jedem Umschalten an. Die Liste ist jetzt so eine Art
Verbindungsverlauf und zeigt alle besuchten Stationen an.
MfG
Otto.
Zitieren
#19
Ja so klappt das, in C / C++ sind es praktisch die gleichen Schritte. Also kein großer Umbau.
Ansprechpartner für Umbau oder Modernisierung von Röhrenradios mittels SDR,DAB+,Internetradio,Firmwareentwicklung. 
Unser Open-Source Softwarebaukasten für Internetradios gibt es auf der Github-Seite! Projekt: BM45/iRadio (Google "github BM45/iRadio")
Zitieren


Möglicherweise verwandte Themen…
Thema Verfasser Antworten Ansichten Letzter Beitrag
  Huth E72 Internetradio mit ESP32 saarfranzose 10 1.783 12.05.2023, 14:49
Letzter Beitrag: saarfranzose
  Ein Internetradio Bausatz von PIMORONI Bernhard45 200 81.544 06.06.2022, 19:17
Letzter Beitrag: Reparateur
  Ein minimales Internetradio für alte und neue Raspberrys Bernhard45 189 105.593 12.04.2022, 16:00
Letzter Beitrag: navi
  Meine Vorschaltlampe Holly-Z 41 6.969 21.03.2022, 10:40
Letzter Beitrag: Hanskanns
  Dementia III ESP32 Internetradio mit Simulation saarfranzose 9 2.805 21.01.2022, 23:14
Letzter Beitrag: saarfranzose

Gehe zu: