Themabewertung:
  • 1 Bewertung(en) - 5 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Loewe Kobold Zeigersimulation (iRadio)
#1
ja ihr habt richtig gelesen. Es ist diesmal keine Skalensimulation, sondern eine Skalenzeigersimulation. Wobei die Technik genau gleich zu einer Skalensimulation ist. Lediglich gibt es keine künstliche, sondern eine echte Skala, und die Zeigergrafik bewegt sich auf einem neutralen Hintergrundbild.
Genau die gleiche Installation als Skalensimulation hatte ich auch schon auf dem Metz Baby, dessen Bibliothek sogar Bestandteil des iRadio-Installationspaketes ist. Es waren nur die Grafiken auszutauschen.
Natürlich lief nicht alles reibungslos, und alle Probleme sind noch nicht gelöst. Darauf werde ich noch eingehen. Es betrifft Anpassungen an der sdlskale.cxx sowie das leidige Thema NF-Störungen. Aber jetzt will ich erst mal Bild und Video zu dem Umbau zeigen.

   

die Grundplatte ist recht asymmetrisch. Es war nicht leicht die Maße abzunehmen.

   

   

   

   

hier läuft noch der Metz-Zeiger. Ich hab ihn später rot eingefärbt:

   

   

   

   

Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#2
Hallo Jupp,

... grandios, endlich mal ein gutes Projekt für den Raspi!! Smiley32


Gruß Horst
Zitieren
#3
danke Horst!

Du bist noch nicht so lange hier. Wenn es dich interessiert kannst du dir die Entwicklungsgeschichte von iRadio hier durchlesen:

Ein minimales Internetradio für alte und neue Raspberrys

oder die Zusammenfassung in meinem blog:

https://radiobasteleien.blogspot.com/sea...bel/iRadio
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#4
ich hab mich jetzt wirklich wieder tagelang mit Störgeräuschen und verzerrtem Ton an dem Kobold geärgert. Raspberry und NF aus dem gleichen Netzteil zu speisen taugt einfach nicht. Ich nahm den Ton testweise über HDMI ab, ich schaltete einen Tonübertrager dazwischen, ich experimentierte mit den Pegeln. Alles ohne Erfolg. Jetzt habe ich einen interessanten Lösungsansatz. Ich speise zwar weiterhin den kleinen Endstufenbaustein über das Raspberry Steckernetzteil, gehe die Versorgungsspannung des Verstärkers aber mit einer 18650-Zelle puffern. Dazu versorgt das Steckernetzteil eine kleine Ladeelektronik, welche ihre Ausgangsspannung an den Verstärker weitergibt. Beim Abschalten der Spannungsversorgung fällt ein Relais ab und nimmt die Last an der Ladeelektronik weg, so das es keine Entladung des Akku gibt. Die Lösung ist recht unkonventionell, aber funktioniert. Eine Weiterentwicklung dieser Idee wäre es das Relais über einen GPIO zu schalten, so das nur bei aktivem Empfang die Endstufe zugeschaltet wird. Das hätte den Zusatzeffekt daß die Prasselgeräusche beim Hochfahren des Radio und beim Abstimmen auch unterdrückt wären. Das würde aber Änderungen am Quellcode verlangen und wir würden uns vom Standard entfernen. Mit der aktuellen Lösung kann man auch leben.

Hier die Experimentierphase:

   

als sich ein Erfolg einstellte baute ich eine neue Grundplatte:

   

   

   

es sieht noch etwas wüst aus, aber es ist ja auch eine Baustelle:

   
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#5
(24.04.2020, 22:50)saarfranzose schrieb: Eine Weiterentwicklung dieser Idee wäre es das Relais über einen GPIO zu schalten, so das nur bei aktivem Empfang die Endstufe zugeschaltet wird. Das hätte den Zusatzeffekt daß die Prasselgeräusche beim Hochfahren des Radio und beim Abstimmen auch unterdrückt wären. Das würde aber Änderungen am Quellcode verlangen und wir würden uns vom Standard entfernen. Mit der aktuellen Lösung kann man auch leben.
Hallo Jupp, 
hier könnte man den Beispielcode vom Servo-displayd als Vorlage nehmen, er liegt in .../iRadio/display/servo/servo.c
Dort wird ja ein GPIO zur Stromfreigabe für das Servo genutzt, damit man das Jitter der PWM bei eingestelltem Sender nicht mehr hat. Die Logik müsste natürlich 
in Zeile 144     digitalWrite (TRIGGER_SERVO_PIN, LOW);  
in Zeile 164    digitalWrite (TRIGGER_SERVO_PIN, HIGH);
in Zeile 169       digitalWrite (TRIGGER_SERVO_PIN, LOW);

genau invertiert werden. Dann bleibt das Relais beim Radioempfang angezogen, beim Senderwechsel (Abstimmen) fällt es ab. 
Die GPIOs liegen beim Hochfahren des Rechners ja auf LOW, damit wäre den Endstufe automatisch abgeschaltet. Sobald der Prozess für die Skalensimulation (hier Zeigersimulation) gestartet wird, geht damit automatisch auch die Endstufe in den Betrieb.
Wenn Du den Code aus der servo.c nicht in deine Zeigersimulation einbauen kannst, sage hier bescheid. Dann baue ich deinen Quellcode für so einen GPIO-Endstufenpin um.

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
#6
Hallo Bernhard,
schön das du dich einklinkst!
wäre es denn von allgemeinem Interesse einen Freigabepin (evtl. über einen Schalter) in den gpiod einzubauen, wie du vorgeschlagen hast? Ich brauche für den Kobold keine Speziallösung, so bedeutend finde ich das Projekt nicht. Aber wäre es eine Anregung für das nächste iRadio release?
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#7
Hallo Jupp,

das ist schon eine Sache für den displayd und nicht den gpiod. Gpiod hat keine Ahnung wann der Sender spielt und wann nicht, er arbeitet nach dem Fire&Forget-Prinzip und bekommt keine Rückmeldung von vlc. Der displayd hingegen, siehe auch die Skalensimualtion des Lorenz C2_V2 hat die Info, dort haben wir das mit dem an und abschalten der Endstufe übrigens schon umgesetzt (Weckfunktion, Standby usw.). In der Skalensimulation gibt es ja auch das Flag

#define PAUSE_BEIM_SENDERWECHSEL true // true oder false

. Dort wird VLC solange stumm geschaltet bis der Skalenzeiger die richtige Position erreicht hat. An genau diesen Stellen wo die Auswertung des Flags erfolgt, könnte man mit den Befehlen aus #5 einen beliebigen Pin high/low setzen (sofern überhaupt noch einer frei ist und das Display nicht alle belegt).

Also wenn, dann würde ich erstmal nur - wenn Du es nicht allein schaffst - deinen Code für dieses Radio hier anpassen, damit Du die nicht 100%-ige Trennung deiner Endstufe oder deine Einstrahlungsproblematik in den Griff bekommst. Allerdings ist das "klicken" eines Relais zwischen der Programmumschaltung sicher auch nicht das wahre und nervt schnell, ich würde da wahrscheinlich eher nochmal an das Design des Radios rangehen und eine richtige Trennung der Endstufe wenigstens mit einem isolierenden DC-DC Wandler anstreben. Dann reicht ein Netzteil aus. Die billigen Wandler lösen das Problem leider nicht.

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
#8
danke für das Angebot, Bernhard. Ich überlasse es lieber dir den code zu erweitern.

Ich hab etwas seltsame Tonübertrager eingekauft, vermutlich taugen die wirklich nichts. Obwohl mit 1:1 angegeben gibt es eine niederohmige und eine hochohmige Seite. Egal wie man sie anklemmt verschlechtern sie das Klangbild, ändern die Pegel, und beseitigen die Störungen nur teilweise. Da suche ich mir mal eine andere Bezugsquelle.

Für das Relais hab ich Alternativen, das soll nicht das Problem sein.

GPIO's sind noch mind. 5 Stück frei, obwohl ich schon einen volume-daemon dazugesetzt habe.

PS: soeben zwei Newport Übertrager geordert
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#9
das ist vielleicht eine gute Gelegenheit einen originalen Kobold aus meiner Sammlung im Vergleich zu zeigen. Das Flohmarktgehäuse hatte nur den Lautsprecher. Keine Rückwand, kein Chassis,keine Knöpfe.

   

   

   
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#10
Hallo Jupp, 

ich mache das jetzt mal als Trockenübung:

Die Metz-Babyskale sah ja so aus:

PHP-Code:
#include <stdlib.h>
#include <string.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

#define PLAYLIST "/home/pi/.config/vlc/playlist.m3u"
//#define PLAYLIST "playlist.m3u"

#define ZEIGERANSCHLAG_LINKS 120
#define ZEIGERANSCHLAG_RECHTS 440

#define SKALE_HOEHE 290
#define SKALE_BREITE 480

#define BILDER_PRO_SEKUNDE 20

#define PAUSE_BEIM_SENDERWECHSEL true // true oder false

#define ANZAHL_SENDER (Senderliste.size()-1)

#define SENDERABSTAND (ZEIGERANSCHLAG_RECHTS-ZEIGERANSCHLAG_LINKS)/ANZAHL_SENDER

bool flag_neue_metadaten false;

char buf[64];
char now[64];
char genre[64];
char bitrate[64];
char streamURL[255];

char channel[64];

void rmSubstr(char *str, const char *toRemove)
{
 
   size_t length strlen(toRemove);
 
   while((str strstr(strtoRemove)))
 
   {
 
       memmove(strstr lengthstrlen(str length));
 
   }
}

Uint32 vlc_Callback(Uint32 intervalvoid *param)
{

 
   //FILE *text =  popen("ls *", "r");
 
   FILE *text popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep title:""r");
 
   FILE *text_now_playing popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep now_playing:""r");
 
   FILE *text_genre popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep genre:""r");
 
   FILE *text_bitrate popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep Bitrate:""r");
 
   FILE *text_streamURL popen("echo \"status\" | nc 127.0.0.1 9294 -N | grep \"new input:\" ""r");

 
   fgets(buf64text);
 
   fgets(now64text_now_playing);
 
   fgets(genre64text_genre);
 
   fgets(bitrate64text_bitrate);
 
   fgets(streamURL255text_streamURL);

 
   rmSubstr(buf,"| title:");
 
   rmSubstr(buf,"\r");
 
strcpy(channel,buf);

 
   rmSubstr(now,"| now_playing:");
 
   rmSubstr(now,"\r");

 
   rmSubstr(genre,"| genre:");
 
   rmSubstr(genre,"\r");

 
   rmSubstr(bitrate,"| Bitrate:");
 
   rmSubstr(bitrate,"\r");

 
   rmSubstr(streamURL,"> ( new input: ");
 
   rmSubstr(streamURL," )");

 
   pclose(text);
 
   pclose(text_now_playing);
 
   pclose(text_genre);
 
   pclose(text_bitrate);
 
   pclose(text_streamURL);

 
   flag_neue_metadaten true;
 
   return(interval);
}


int aktueller_Sender(vector<stringListestring URL) {
 
  //cout << "URL ist:" <<  URL << " size: "  << URL.size() << "\n";
 
  for (int i=0i<Liste.size(); i++) {
 if (
URL.rfind(Liste.at(i)) != -1)
 
    return i;
 
  }

 
 return -1;
}

int main(void) {

 
   char SenderURL[255];
 
   vector<stringSenderliste;
 
   int i_alti;

 
ifstream in(PLAYLIST);

 if(!
in) {
 
cout << "Senderliste nicht gefunden/kann nicht geoeffnet werden.\n";
 
   return 1
 
  }

 while(
in) {
 
    in.getline(SenderURL255);  // delim defaults to '\n'
 
    if(in) {
 
            string str SenderURL;
 
      Senderliste.push_back(str);
 
    }
 
  }

 
in.close();

 
   cout << "Senderliste enthaelt " << Senderliste.size() << " Sender.\n";


 
   // SDL - Teil
 
   SDL_Event event;
 
   SDL_Renderer *renderer NULL;
 
   SDL_Texture *textur_skale NULL;
 
   SDL_Texture *textur_zeiger NULL;
 
   SDL_Window *window NULL;

 
   TTF_Font font NULL;
 
   SDL_Surface surface_prgtitel NULL;
 
   SDL_Texture textur_prgtitel NULL;

 
   if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) {
 
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Konnte SDL nicht initialisieren: %s"SDL_GetError());
 
       return 3;
 
   }

 
   if (SDL_CreateWindowAndRenderer(SKALE_BREITESKALE_HOEHE 0, &window, &renderer)) {
 
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Window und Renderer konnten nicht erzeugt werden: %s"SDL_GetError());
 
       return 3;
 
   }


 
   // load support for the PNG image formats
 
   int flags=IMG_INIT_PNG;
 
   if(IMG_Init(flags)&flags != flags) {
 
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"PNG Unterstuetzung konnte nicht initialisiert werden: %s"IMG_GetError());
 return 
3;
 
   }

 
   textur_skale IMG_LoadTexture(renderer"skale.png");
 
   textur_zeiger IMG_LoadTexture(renderer"zeiger.png");

 
   if ((textur_skale == NULL) || (textur_zeiger == NULL) ) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler beim Laden der Skalen und Zeiger Texturen: %s"IMG_GetError());
 return 
3;
 
   }

 
  if(TTF_Init()==-1) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in TTF_Init: %s"TTF_GetError());
 
    return 3;
 
  }

 
  font TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf"16);
 
  if(!font) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in TTF_OpenFont: %s"TTF_GetError());
 return 
3;
 
  }

 
  SDL_Color color_yellow = { 2550};
 
  //  printf("%s","Test\n");
 
  // common_fps_init();

 
  // Position und Dimension des Skalenzeigers
 
  SDL_Rect ZeigerRect;
 
  ZeigerRect.150ZeigerRect.0;
 
  ZeigerRect.10ZeigerRect.377;

 
  // Timer fuer cvlc Socketverbindung
 
  SDL_AddTimer(1000vlc_CallbackNULL);

 
  // Event-Schleife & Daemonbetrieb
 
  while (1) {
 
  // welcher Sender wird von vlc gerade wiedergeben ?
 
    string str streamURL;

 
i_alt i;
 
    i aktueller_Sender(Senderliste,str);

 
// URL wegen URL Redirection nicht in Senderliste? Dann belasse Zeiger an Stelle.
 
if (== -1)
 
i_alt;

 
    // Zeichen Skalenhintergrund ... oder Texture fuer Hintergrundbeleuchtung
 
    SDL_SetRenderDrawColor(renderer,255,255,255,255);
 
    SDL_RenderClear(renderer);

 
    // Verschiebe Skalenzeigerposition zum eingestellten Sender
 
    if (ZeigerRect.> (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS ) {
 if (
PAUSE_BEIM_SENDERWECHSEL)
 
  system("echo \"stop\" | nc 127.0.0.1 9294 -N");

 
        ZeigerRect.x--;
 
 if (
PAUSE_BEIM_SENDERWECHSEL
 
  if (ZeigerRect.== (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS
 
  system("echo \"play\" | nc 127.0.0.1 9294 -N"); 
 
    }

 
    if (ZeigerRect.< (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS ) {
 if (
PAUSE_BEIM_SENDERWECHSEL)
 
  system("echo \"stop\" | nc 127.0.0.1 9294 -N");

 
      ZeigerRect.x++;

 if (
PAUSE_BEIM_SENDERWECHSEL
 
  if (ZeigerRect.== (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS
 
  system("echo \"play\" | nc 127.0.0.1 9294 -N"); 
 
    }

 
    // Zeichne Skalenglase
 
    SDL_RenderCopy(renderertextur_skaleNULLNULL);

 
    // Zeichne Zeiger
 
    SDL_RenderCopy(renderertextur_zeigerNULL, &ZeigerRect);

 
// Zeichen Programmnamen auf Skalenglas
 // vermeiden von Nulllaengenfehler
 
if (flag_neue_metadaten) {
 
flag_neue_metadaten false;
 
channel[strlen(channel)-1]='\0';
 
       }

 if (
strlen(channel)!=0) {
 
surface_prgtitel TTF_RenderText_Solid(fontchannelcolor_yellow);
 if(!
surface_prgtitel) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in TTF_RenderText_Solid: %s"TTF_GetError());
 return 
3;
 }

 
    textur_prgtitel SDL_CreateTextureFromSurface(renderer,surface_prgtitel);
 if (
textur_prgtitel == NULL) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in CreateTextureFromSurface: %s"SDL_GetError());
 return 
3;
 
    }
 }

 
    int texW 0int texH 0;
 
  SDL_QueryTexture(textur_prgtitelNULLNULL, &texW, &texH);
 
    SDL_Rect dstrect = { 20270texWtexH };

 
    SDL_RenderCopy(renderertextur_prgtitelNULL, &dstrect);

 
    // Aktualisiere Fenster
 
    SDL_RenderPresent(renderer);
 
    //  common_fps_update_and_print();

 
    // Eventbehandlung
 
    if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
 break;

 
SDL_Delay(1000/BILDER_PRO_SEKUNDE); // Limit max. xxx fps

 // Aufraeumarbeiten pro Frame
 
if (surface_prgtitel)
 
SDL_FreeSurface(surface_prgtitel);

 if (
textur_prgtitel)
 
SDL_DestroyTexture(textur_prgtitel);

 
   // while(1)

 
   // Aufraeumen und Ressourcen freigeben
 
   if (textur_skale)
 
    SDL_DestroyTexture(textur_skale);

 
   if (textur_zeiger)
 
SDL_DestroyTexture(textur_zeiger);

 
   if (textur_prgtitel)
 
SDL_DestroyTexture(textur_prgtitel);

 
   if (surface_prgtitel)
 
SDL_FreeSurface(surface_prgtitel);

 
   if (font)
 
TTF_CloseFont(font);

 
   IMG_Quit();

 
   if (renderer)
 
SDL_DestroyRenderer(renderer);

 
   if (window)
 
SDL_DestroyWindow(window);

 
   TTF_Quit();
 
   SDL_Quit();
 
   return EXIT_SUCCESS;


Wir hängen uns einfach in die Pause beim Senderwechsel mit ein, denn da soll die Endstufe ja schweigen,
also hinter #define PAUSE_BEIM_SENDERWECHSEL true // true oder false
legen wir gleich unseren GPIO fest der das Relais,.... ansteuert.


PHP-Code:
#define PAUSE_BEIM_SENDERWECHSEL true   // true oder false

#define TRIGGER_PIN 24 // GPIO24 - Freigabe der Versorgungsspannung 

Dort wo PAUSE_BEIM_SENDERWECHSEL ausgewertet wird, machen wir Blöcke hinter den if-Bedingungen und schalten dort entsprechend den GPIO an und aus.



PHP-Code:
       // Verschiebe Skalenzeigerposition zum eingestellten Sender
 
       if (ZeigerRect.> (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS ) {
 
                       if (PAUSE_BEIM_SENDERWECHSEL) {
 
                               system("echo \"stop\" | nc 127.0.0.1 9294 -N");
 
                               digitalWrite (TRIGGER_PINLOW);
 
                       }

 
                       ZeigerRect.x--;

 
                       if (PAUSE_BEIM_SENDERWECHSEL)
 
                        if (ZeigerRect.== (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS) {
 
                                       system("echo \"play\" | nc 127.0.0.1 9294 -N");
 
                                       digitalWrite (TRIGGER_PINHIGH);
 
                       }
 
       }

 
       if (ZeigerRect.< (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS ) {
 
                       if (PAUSE_BEIM_SENDERWECHSEL) {
 
                               system("echo \"stop\" | nc 127.0.0.1 9294 -N");
 
                               digitalWrite (TRIGGER_PINLOW);
 
                       }

 
               ZeigerRect.x++;

 
                       if (PAUSE_BEIM_SENDERWECHSEL)
 
                        if (ZeigerRect.== (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS) {
 
                               system("echo \"play\" | nc 127.0.0.1 9294 -N");
 
                               digitalWrite (TRIGGER_PINHIGH);
 
                       }
 
       


Damit die Endstufe direkt nach dem Start der Skalensimulation eingeschaltet wird, können wir optional auch nochmal einen Anschaltbefehl for die never-ending while-Schleife setzen:

PHP-Code:
  // Timer fuer cvlc Socketverbindung
 
  SDL_AddTimer(1000vlc_CallbackNULL);

 
  // Endstufe freigeben
 
  digitalWrite (TRIGGER_PINHIGH);

 
// Event-Schleife & Daemonbetrieb 
 
while(1) { 


Da wir nun zusätzlich zu SDL2 auch noch WiringPi benutzen, müssen wir die Bibliothek auch noch inkludieren:

PHP-Code:
#include <wiringPi.h> 

Der gesamte umgebaute Code der Skalensimulation (war ja kein Aufwand) hier:

PHP-Code:
#include <stdlib.h>
#include <string.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>

#include <wiringPi.h>


using namespace std;

#define PLAYLIST "/home/pi/.config/vlc/playlist.m3u"
//#define PLAYLIST "playlist.m3u"

#define ZEIGERANSCHLAG_LINKS 120
#define ZEIGERANSCHLAG_RECHTS 440

#define SKALE_HOEHE 290
#define SKALE_BREITE 480

#define BILDER_PRO_SEKUNDE 20

#define PAUSE_BEIM_SENDERWECHSEL true // true oder false

#define TRIGGER_PIN 24 // GPIO24 - Freigabe der Versorgungsspannung

#define ANZAHL_SENDER (Senderliste.size()-1)

#define SENDERABSTAND (ZEIGERANSCHLAG_RECHTS-ZEIGERANSCHLAG_LINKS)/ANZAHL_SENDER

bool flag_neue_metadaten false;

char buf[64];
char now[64];
char genre[64];
char bitrate[64];
char streamURL[255];

char channel[64];

void rmSubstr(char *str, const char *toRemove)
{
 
   size_t length strlen(toRemove);
 
   while((str strstr(strtoRemove)))
 
   {
 
       memmove(strstr lengthstrlen(str length));
 
   }
}

Uint32 vlc_Callback(Uint32 intervalvoid *param)
{

 
   //FILE *text =  popen("ls *", "r");
 
   FILE *text popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep title:""r");
 
   FILE *text_now_playing popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep now_playing:""r");
 
   FILE *text_genre popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep genre:""r");
 
   FILE *text_bitrate popen("echo \"info\" | nc 127.0.0.1 9294 -N | grep Bitrate:""r");
 
   FILE *text_streamURL popen("echo \"status\" | nc 127.0.0.1 9294 -N | grep \"new input:\" ""r");

 
   fgets(buf64text);
 
   fgets(now64text_now_playing);
 
   fgets(genre64text_genre);
 
   fgets(bitrate64text_bitrate);
 
   fgets(streamURL255text_streamURL);

 
   rmSubstr(buf,"| title:");
 
   rmSubstr(buf,"\r");
 
strcpy(channel,buf);

 
   rmSubstr(now,"| now_playing:");
 
   rmSubstr(now,"\r");

 
   rmSubstr(genre,"| genre:");
 
   rmSubstr(genre,"\r");

 
   rmSubstr(bitrate,"| Bitrate:");
 
   rmSubstr(bitrate,"\r");

 
   rmSubstr(streamURL,"> ( new input: ");
 
   rmSubstr(streamURL," )");

 
   pclose(text);
 
   pclose(text_now_playing);
 
   pclose(text_genre);
 
   pclose(text_bitrate);
 
   pclose(text_streamURL);

 
   flag_neue_metadaten true;
 
   return(interval);
}


int aktueller_Sender(vector<stringListestring URL) {
 
  //cout << "URL ist:" <<  URL << " size: "  << URL.size() << "\n";
 
  for (int i=0i<Liste.size(); i++) {
 if (
URL.rfind(Liste.at(i)) != -1)
 
    return i;
 
  }

 
 return -1;
}

int main(void) {

 
   wiringPiSetup();
    pinMode(TRIGGER_PIN,OUTPUT);

 
   char SenderURL[255];
 
   vector<stringSenderliste;
 
   int i_alti;

 
ifstream in(PLAYLIST);

 if(!
in) {
 
cout << "Senderliste nicht gefunden/kann nicht geoeffnet werden.\n";
 
   return 1;
 
  }

 while(
in) {
 
    in.getline(SenderURL255);  // delim defaults to '\n'
 
    if(in) {
 
            string str SenderURL;
 
      Senderliste.push_back(str);
 
    }
 
  }

 
in.close();

 
   cout << "Senderliste enthaelt " << Senderliste.size() << " Sender.\n";


 
   // SDL - Teil
 
   SDL_Event event;
 
   SDL_Renderer *renderer NULL;
 
   SDL_Texture *textur_skale NULL;
 
   SDL_Texture *textur_zeiger NULL;
 
   SDL_Window *window NULL;

 
   TTF_Font font NULL;
 
   SDL_Surface surface_prgtitel NULL;
 
   SDL_Texture textur_prgtitel NULL;

 
   if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) {
 
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Konnte SDL nicht initialisieren: %s"SDL_GetError());
 
       return 3;
 
   }

 
   if (SDL_CreateWindowAndRenderer(SKALE_BREITESKALE_HOEHE 0, &window, &renderer)) {
 
       SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Window und Renderer konnten nicht erzeugt werden: %s"SDL_GetError());
 
       return 3;
 
   }


 
   // load support for the PNG image formats
 
   int flags=IMG_INIT_PNG;
 
   if(IMG_Init(flags)&flags != flags) {
 
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"PNG Unterstuetzung konnte nicht initialisiert werden: %s"IMG_GetError());
 return 
3;
 
   }

 
   textur_skale IMG_LoadTexture(renderer"skale.png");
 
   textur_zeiger IMG_LoadTexture(renderer"zeiger.png");

 
   if ((textur_skale == NULL) || (textur_zeiger == NULL) ) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler beim Laden der Skalen und Zeiger Texturen: %s"IMG_GetError());
 return 
3;
 
   }

 
  if(TTF_Init()==-1) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in TTF_Init: %s"TTF_GetError());
 
    return 3;
 
  }

 
  font TTF_OpenFont("/usr/share/fonts/truetype/freefont/FreeSans.ttf"16);
 
  if(!font) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in TTF_OpenFont: %s"TTF_GetError());
 return 
3;
 
  }

 
  SDL_Color color_yellow = { 2550};
 
  //  printf("%s","Test\n");
 
  // common_fps_init();

 
  // Position und Dimension des Skalenzeigers
 
  SDL_Rect ZeigerRect;
 
  ZeigerRect.150ZeigerRect.0;
 
  ZeigerRect.10ZeigerRect.377;

 
  // Timer fuer cvlc Socketverbindung
 
  SDL_AddTimer(1000vlc_CallbackNULL);

 
  // Endstufe freigeben
 
  digitalWrite (TRIGGER_PINHIGH);

 
  // Event-Schleife & Daemonbetrieb
 
  while (1) {
 
  // welcher Sender wird von vlc gerade wiedergeben ?
 
    string str streamURL;

 
i_alt i;
 
    i aktueller_Sender(Senderliste,str);

 
// URL wegen URL Redirection nicht in Senderliste? Dann belasse Zeiger an Stelle.
 
if (== -1)
 
  i i_alt;

 
    // Zeichen Skalenhintergrund ... oder Texture fuer Hintergrundbeleuchtung
 
    SDL_SetRenderDrawColor(renderer,255,255,255,255);
 
    SDL_RenderClear(renderer);

 
    // Verschiebe Skalenzeigerposition zum eingestellten Sender
 
    if (ZeigerRect.> (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS ) {
 if (
PAUSE_BEIM_SENDERWECHSEL) {
 
  system("echo \"stop\" | nc 127.0.0.1 9294 -N");
 
digitalWrite (TRIGGER_PINLOW);
 }

 
        ZeigerRect.x--;

 if (
PAUSE_BEIM_SENDERWECHSEL)
 
  if (ZeigerRect.== (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS) {
 
  system("echo \"play\" | nc 127.0.0.1 9294 -N");
 
digitalWrite (TRIGGER_PINHIGH);
 }
 
    }

 
    if (ZeigerRect.< (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS ) {
 if (
PAUSE_BEIM_SENDERWECHSEL) {
 
  system("echo \"stop\" | nc 127.0.0.1 9294 -N");
 
digitalWrite (TRIGGER_PINLOW);
 }

 
      ZeigerRect.x++;

 if (
PAUSE_BEIM_SENDERWECHSEL)
 
  if (ZeigerRect.== (SENDERABSTAND*i) + ZEIGERANSCHLAG_LINKS) {
 
  system("echo \"play\" | nc 127.0.0.1 9294 -N");
 
digitalWrite (TRIGGER_PINHIGH);
 }
 
    }

 
    // Zeichne Skalenglase
 
    SDL_RenderCopy(renderertextur_skaleNULLNULL);

 
    // Zeichne Zeiger
 
    SDL_RenderCopy(renderertextur_zeigerNULL, &ZeigerRect);

 
// Zeichen Programmnamen auf Skalenglas
 // vermeiden von Nulllaengenfehler
 
if (flag_neue_metadaten) {
 
flag_neue_metadaten false;
 
channel[strlen(channel)-1]='\0';
 
       }

 if (
strlen(channel)!=0) {
 
surface_prgtitel TTF_RenderText_Solid(fontchannelcolor_yellow);
 if(!
surface_prgtitel) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in TTF_RenderText_Solid: %s"TTF_GetError());
 return 
3;
 }

 
    textur_prgtitel SDL_CreateTextureFromSurface(renderer,surface_prgtitel);
 if (
textur_prgtitel == NULL) {
 
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION"Fehler in CreateTextureFromSurface: %s"SDL_GetError());
 return 
3;
 
    }
 }

 
    int texW 0int texH 0;
 
  SDL_QueryTexture(textur_prgtitelNULLNULL, &texW, &texH);
 
    SDL_Rect dstrect = { 20270texWtexH };

 
    SDL_RenderCopy(renderertextur_prgtitelNULL, &dstrect);

 
    // Aktualisiere Fenster
 
    SDL_RenderPresent(renderer);
 
    //  common_fps_update_and_print();

 
    // Eventbehandlung
 
    if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
 break;

 
SDL_Delay(1000/BILDER_PRO_SEKUNDE); // Limit max. xxx fps

 // Aufraeumarbeiten pro Frame
 
if (surface_prgtitel)
 
SDL_FreeSurface(surface_prgtitel);

 if (
textur_prgtitel)
 
SDL_DestroyTexture(textur_prgtitel);

 
   // while(1)

 
   // Aufraeumen und Ressourcen freigeben
 
   if (textur_skale)
 
    SDL_DestroyTexture(textur_skale);

 
   if (textur_zeiger)
 
SDL_DestroyTexture(textur_zeiger);

 
   if (textur_prgtitel)
 
SDL_DestroyTexture(textur_prgtitel);

 
   if (surface_prgtitel)
 
SDL_FreeSurface(surface_prgtitel);

 
   if (font)
 
TTF_CloseFont(font);

 
   IMG_Quit();

 
   if (renderer)
 
SDL_DestroyRenderer(renderer);

 
   if (window)
 
SDL_DestroyWindow(window);

 
   TTF_Quit();
 
   SDL_Quit();
 
   return EXIT_SUCCESS;


beziehungsweise als fertige Datei zum Download: 
.txt   sdlskale.cxx.txt (Größe: 8,41 KB / Downloads: 14)

Damit das ganze übersetzt wird, sagen wir dem Compiler noch das er die WiringPi Bibliothek dazu linken soll:
Im Build-script fügen wir hinten also noch -lwiringPi an, das der ganze Aufruf so aussieht:

PHP-Code:
g++ sdlskale.cxx -o sdlskale -lSDL2 -lSDL2_image -lSDL2_ttf -lwiringPi 


fertig. Die Binärversion der Skalensimulation ist damit gebaut und kann per GPIO die Endstufe an und abschalten.

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
#11
die im vorherigen post gezeigten Änderungen sind nun mit Unterstützung von Bernhard und Otto umgesetzt und experimentell verdrahtet. In der Startphase und zwischen den Sendern ist der Ton nun gemutet. Dies ist hardwareseitig realisiert durch einen Mosfet-Schalter, welcher den Lautsprecher wegschaltet. Der kleinen Endstufe schadet es nicht wenn sie mal ohne Last läuft. Den Weg hab ich vorläufig gewählt weil der Mosfet-Schalter in der Minus-Leitung unterbricht und ich Minus bzw. Masse am Verstärker erst wegschalten kann wenn ich die Basisplatte umbaue.
Das Video zeigt aber auch noch den Effekt der Akkupufferung. Am Anfang ist der Ton noch leicht verzerrt und voll Störungen. Wenn der Akku vollgeladen ist, was durch die blaue LED an der Ladeschaltung angezeigt wird, übernimmt er die Pufferung und die Verzerrungen und Störungen reduzieren sich massiv.



PS: nicht von dem Preis bei aliexpress irritieren lassen, den Mosfet Schalter gibt es auch bedeutend günstiger.
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#12
die Platine hab ich jetzt abgeändert. Die Schaltung ist etwas trickreich. Das Mosfet-Modul schaltet dem NF-Verstärker die Masse von Versorgungsspannung und Signal weg. In dem Zustand wird dann auch kein Strom mehr aus dem Akku entnommen. Geladen wird er trotzdem über die Ladeelektronik. Einen Verdrahtungsplan will ich noch zeichnen. Das Formteil für den Raspi will ich noch mal neu drucken. Das Display sitzt nicht gerade. Das will ich noch korrigieren.

   

   

   
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#13
ich hab das Schaltbild etwas in Szene gesetzt. Man sieht daß die + Speisung des Verstärkers von der Ladeschaltung kommt, und die - Speisung vom Mosfet-Schalter. Eine Spannungsverteilung ist immer wichtig, da auch noch andere Verbraucher angeklemmt sind. In dem Fall die beiden Drehencoder.

   
Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren
#14
Es gibt noch einmal ein Video. Ich habe eine neue Grundplatte gedruckt mit genauerer Ausrichtung des Displays und die Einblendung der Senderinformationen in der software neu positioniert. Und endlich die Schutzfolie am Display abgezogen. Beim Schalten des Mosfet-Schalters hört man noch ein Knackgeräusch, da muss wohl noch irgendwo eine Kapazität hin. Das schau ich mir noch mal an. Aber sonst bin ich mit dem Ergebnis jetzt sehr zufrieden.

Gruß,
Jupp
-----------------------------

was du baust ist immer mit dir verbunden
(Lego)

Einsamkeit ist nur ein Mangel an Technologie
(@beetlebum)
Zitieren


Möglicherweise verwandte Themen…
Thema Verfasser Antworten Ansichten Letzter Beitrag
  iRadioAndroid - iRadio Portierung für Android Geräte OttoBerger 154 9.103 23.03.2024, 13:45
Letzter Beitrag: Uli
  Saba TV-Journey mit iRadio saarfranzose 6 2.093 20.07.2023, 20:22
Letzter Beitrag: saarfranzose
  Raspberry iRadio, heavy duty Emmpunkt 5 1.039 27.03.2023, 17:58
Letzter Beitrag: saarfranzose
  russisches 6N-1 mit iRadio und RGB-Panel saarfranzose 10 1.758 11.03.2023, 15:00
Letzter Beitrag: saarfranzose
  FAQ zum iRadio saarfranzose 602 36.258 03.03.2023, 11:59
Letzter Beitrag: saarfranzose

Gehe zu: