Themabewertung:
  • 1 Bewertung(en) - 5 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
iRadioAndroid - mehrere playlisten
#1
Moinsen,
das hatte ich mir doch einfacher vorgestellt Confused bin bisher mit meinen ersten Java Programmierversuchen gescheitert.

Was will ich erreichen:
Über 4 Tasten 4 verschieden Playlisten laden. Tasten könnten dann später LW, MW, KW und  UKW sein.

1) Erst einmal playlist0.m3u bis playlist3.m3u auf die SD-Karte übertragen.

2) iRadioPlayer.java die Funktion onStartCommand  den Aufruf von readPlaylistFromFile um den Parameter 0 erweitert.
Code:
public int onStartCommand(Intent intent, int flags, int startId) {
        // Log.i(TAG, "try to read playlist.m3u from folder Download ...");
        readPlaylistFromFile(0);

3) iRadioPlayer.java die Funktion readPlaylistFromFile erweitert: (int nr) und  "/playlist" + nr + ".m3u"
Code:
    void readPlaylistFromFile(int nr) {
        Log.i(TAG, "try to read playlist" + nr +".m3u from folder Download ...");
        playlist.clear();
        if ((playlist != null) && (playlist.isEmpty())) {
            FileInputStream is;
            BufferedReader reader;
            final File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/playlist" + nr + ".m3u");

4) iRadioPlayer.java eine neue Funktion eingefügt:
Code:
public void newPlaylistFromFile(int nr) {
        playlist.clear();
        readPlaylistFromFile(nr);
        gotoProg(0);
    }

5) gpiodSerialOTG um 4 Kommandos erweitert:
Code:
           if (iRadioPlayerService != null) {
                if (dataUTF8.contains("0FB")) {
                    Log.i(TAG, "command 0FB -> Band 0");
                    iRadioPlayerService.newPlaylistFromFile(0);
                }
            }
            if (iRadioPlayerService != null) {
                if (dataUTF8.contains("1FB")) {
                    Log.i(TAG, "command 1FB -> Band 1");
                    iRadioPlayerService.newPlaylistFromFile(1);
                }
            }
            if (iRadioPlayerService != null) {
                if (dataUTF8.contains("2FB")) {
                    Log.i(TAG, "command 2FB -> Band 2");
                    iRadioPlayerService.newPlaylistFromFile(2);
                }
            }
            if (iRadioPlayerService != null) {
                if (dataUTF8.contains("3FB")) {
                    Log.i(TAG, "command 3FB -> Band 3");
                    iRadioPlayerService.newPlaylistFromFile(3);
                }
            }

6) dir firmware erteitert:
Code:
// switches for next & prev channel
#define PIN_TASTER_PROGRAM_NEXT  3  
#define PIN_TASTER_PROGRAM_PREV  2

// rotary encoder for volume setting
#define PIN_ENCODER_VOL_CLK    5
#define PIN_ENCODER_VOL_DT     4

// switches for frequency band
#define PIN_TASTER_BAND_0  8  
#define PIN_TASTER_BAND_1  9
#define PIN_TASTER_BAND_2  10  
#define PIN_TASTER_BAND_3  11

unsigned char flag;
unsigned char Last_RoB_Status;
unsigned char Current_RoB_Status;

static unsigned long last_interrupt_time = 0;


void setup() {
  // put your setup code here, to run once:
  // switches with interrupt support, rotary in polling mode
  pinMode(PIN_TASTER_PROGRAM_NEXT, INPUT_PULLUP);
  pinMode(PIN_TASTER_PROGRAM_PREV, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(PIN_TASTER_PROGRAM_NEXT), Interrupt, FALLING);
  attachInterrupt(digitalPinToInterrupt(PIN_TASTER_PROGRAM_PREV), Interrupt, FALLING);

  pinMode(PIN_ENCODER_VOL_CLK, INPUT_PULLUP);
  pinMode(PIN_ENCODER_VOL_DT, INPUT_PULLUP);

  pinMode(PIN_TASTER_BAND_0, INPUT_PULLUP);
  pinMode(PIN_TASTER_BAND_1, INPUT_PULLUP);
  pinMode(PIN_TASTER_BAND_2, INPUT_PULLUP);
  pinMode(PIN_TASTER_BAND_3, INPUT_PULLUP);

  // Enable PCIE2 Bit1 = 1 (Port B)
  PCICR |= B00000001;
  // Enable PCINT8 bis PCINT11 (Pins D8, D9, D10, D11)
  PCMSK0 |= B00001111;

  // Send commands via serial to Smartphone
  Serial.begin(115200);
}

void rotaryProcessing(void)
{
    Last_RoB_Status = digitalRead(PIN_ENCODER_VOL_CLK);

    while(!digitalRead(PIN_ENCODER_VOL_DT)){
        Current_RoB_Status = digitalRead(PIN_ENCODER_VOL_CLK);
        flag = 1;
    }

    if(flag == 1){
        flag = 0;
        if((Last_RoB_Status == 0)&&(Current_RoB_Status == 1)){
             Serial.println("VUP"); // send iRadioAndroid command for volume up
        }
        if((Last_RoB_Status == 1)&&(Current_RoB_Status == 0)){
             Serial.println("VDW"); // send iRadioAndroid command for volume down
        }

    }
}

ISR (PCINT0_vect)
{
  // Port B Interrupt occured
 
  // Check if this was D8
  if (digitalRead(PIN_TASTER_BAND_0) == LOW) {
      Serial.println("0FB");
  }
  if (digitalRead(PIN_TASTER_BAND_1) == LOW) {
      Serial.println("1FB");
  }
  if (digitalRead(PIN_TASTER_BAND_2) == LOW) {
      Serial.println("2FB");
  }
  if (digitalRead(PIN_TASTER_BAND_3) == LOW) {
      Serial.println("3FB");
  }
}

void Interrupt() {
  unsigned long interrupt_time = millis();
  // If interrupts come faster than 500ms, assume it's a bounce and ignore
  if (interrupt_time - last_interrupt_time > 500)
  {
    if (digitalRead(PIN_TASTER_PROGRAM_NEXT) == 0)
      Serial.println("PNX"); // send iRadioAndroid command for next program

    if (digitalRead(PIN_TASTER_PROGRAM_PREV) == 0)
      Serial.println("PPR"); // send iRadioAndroid command for prev program
  }

  last_interrupt_time = interrupt_time;
}


void loop() {
  // put your main code here, to run repeatedly:
  rotaryProcessing();
  delay(10);
   
}

Die firmware funktioniert zumindest (mit Serial Monitor getestet)
Die playlist0.m3u wird auch geladen.
Nur bei den "Bereichstasten" passiert nichts Huh  

Sollte hier jemand eine Lösung haben, dann immer her damit.
Noch lieber wäre mir jemand erklärt mir meine Fehler in den Programmänderungen.

-Joe
Zitieren
#2
Nachtrag:

Habe mir 4 Buttons an den oberen Rand der Skala gelegt und damit die Umschaltung zu steuern. Das funktioniert super!

Jetzt muss ich mal sehen warum es nicht über die externen Taster funktioniert.

-Joe
Zitieren
#3
Hallo Joe,

den Code zum Einlesen und Verarbeiten habe bis jetzt noch nicht gründlich angeschaut, aber wenn du schreibst das es mit virtuellen Buttons auf dem Touch funktioniert, dann wird das gut sein. Wenn es sich um ein Skalensimulationscode handelt, bei dem zur Verteilung und Berechnung die Anzahl der Sender in der Liste herangezogen werden, wirst du dort in der run-Methode eventuell noch Arbeit reinstecken müssen. Vielleicht sogar eine Art "Lock/Sperre" implementieren, das es da zu keiner Fehlberechung bei der Bandumschaltung (Senderabstand wird negativ oder div/0) kommt oder die App bei Bandumschaltung vielleicht abstürzen kann!

Was passiert zum Beispiel wenn irgendeine Stelle in der run() der Skalensimulation den aktuellen eingestellten Kanal holt?
Beispiel: aktueller Kanal = 10 aus einer Liste von 25 Sendern.
Senderliste wird gelöscht (neue ist aber noch nicht nachgeladen)-> Anzahl Sender ist 0, aber aktueller Kanal ist immer noch 10
Senderliste neu nachgeladen, hat aber nur 5 Sender , gotoProg(0) noch nicht ausgeführt
run() ist Timergeteuert und hat immer noch aktueller Kanal = 10
jetzt ist gotoProg(0) durch -> run() bekommt beim nächsten Aufruf den aktuellen Kanal ! beides wieder in Synchronisation!

Was passiert aber wenn zwischendurch bis zum Sync ein Umschaltbefehl (über gpiod oder touch) eintrifft? Aktueller Kanal wird auf 11 oder 9 gesetzt und versucht in der Liste diese URL zu holen. Out-of-bound !

Wenn nur eine Liste im iRadio existiert ist das kein Drama, da wird die Syncronität bei Service-Start hergestellt und niemals verändert. Wenn jetzt zwischen mehreren Playlists umgeschaltet wird, müssen die unterschiedlichen Services und Threads aber synchronisiert werden wenn plötzlich eine andere Playlist eingelesen wird.

Das ist im einfachsten Fall nicht ganz so schwer -> Berechne/Verändere Skalenzeigersachen wie Abstände oder Sachen die von der aktuellen Programmnummer abhängig sind, nur neu, wenn Playlist nicht leer ist oder eine andere noch einzuarbeitende Sperre inaktiv ist, ansonsten überspringe alle Displayaktualisierungen für einen run()- Aufruf und lasse auch keine Umschaltungen zu bis wir wieder alle Daten zur neuen Liste haben und alle Listenvariablen in den Grenzen 0 bis Anzahl der Sender in Liste -1 sind!
Musst du überprüfen ob das bei deiner Simulation (displayd,gpiod) nötig ist, ob sie sich immer richtig verhält, denn bisher war ja nur eine Auslegung für genau eine Liste im iRadioAndroid drin.

Was Probleme macht ist also uC <=> OTG-Kabel <=> gpiod  wenn ich das richtig verstanden habe?

Nachdem die USB Buchse ja belegt ist, kannst du Logcat-Meldungen nur über WiFi-Debug erhalten (einschaltbar im Entwicklernmenu, wenn es das Telefon kann). Ansonsten kannst du dir die empfangenen Befehle auch wieder an den Microcontroller zurücksenden lassen und dort auswerten (LED an oder aus wenn Befehl erkannt oder nicht erkannt). 

Funktioniert grundsätzlich schon mal ein Umschalt oder Lauter/Leiser Befehl? Wenn nicht, hast du der App wahrscheinlich noch keine Zugriffsrechte für USB erteilt?

[aus Post https://radio-bastler.de/forum/showthrea...#pid264740]

Kurzform: Passenden Mikrocontroller nehmen -> Verkabeln -> Arduino IDE installieren -> die Demofirmware damit compilieren und auf den uC flashen -> uC per OTG-USB-Kabel an das Androidsystem anschließen -> Android Systemmeldung bestätigen, damit dauerhaft die Zugriffsrechte am iRadioAndroid zugewiesen werden -> iRadioAndroid Neustart -> spielen


Vielleicht wird dein eigenes USB gpio gar nicht erkannt? Siehe Projektseite Hinweis: USB Geräte besitzen eine Kennung bestehend aus Hersteller-ID (Vendor-ID) und Product-ID mit denen sie sich am System anmelden. Für einige GPIO-Interfaces sind sollte Kennungen bereits im iRadioAndroid in der Datei https://github.com/BM45/iRadioAndroid/bl...filter.xml eingepflegt.    Wenn das nicht stimmt wird der Dialog mit der Rechteerteilung nicht erscheinen.

Ein wertvolles Hilfsmittel kann hier die App Serial USB Terminal sein!

https://play.google.com/store/apps/detai...l=de&gl=US

Die App verfügt über so etwas wie einen "Scanner", dort sieht man die Vendor/Product-ID des eingesteckten USB Interfaces. Das sind die Daten für deine device_filter.xml

Auch hier muss für die Kommunikation dann OTG-Recht eingeräumt werden und man sieht (wenn die Verbindungsparameter richtig eingestellt sind) die Kommunikation vom uC zu Handy. iRadioAndroid darf dann nicht laufen weil es nur eine App gibt die Zugriff auf den Port hat. Die App ist ein wertvolles Hilfsmittel wenn man kein Live-Logcat über Wifi im AndroidStudio hat.

Otto (mobil)
Zitieren
#4
Nochmal zurück zum Code


PHP-Code:
public void newPlaylistFromFile(int nr) {
        playlist.clear();
        readPlaylistFromFile(nr);
        gotoProg(0);
    

in newPlaylistFromFile würde ich playlist.clear() entfernen, denn das wird in der eigentlichen privaten Methode readPlaylistFromFile schon gemacht

PHP-Code:
  void readPlaylistFromFile(int nr) {
        Log.i(TAG"try to read playlist" nr +".m3u from folder Download ...");
        playlist.clear();
        if ((playlist != null) && (playlist.isEmpty())) {
            FileInputStream is;
            BufferedReader reader


um alle Threads/Services synchron zu halten müsste in readPlaylistFromFile vor dem playlist.clear() dann ein Lock, eine Sperre gesetzt werden. Das kann eine einfache globale statische Boolean Variable sein die überall erreichbar ist und in anderen Services/Threads gelesen werden kann. Alternativ hat auch Java eine Klasse Lock https://docs.oracle.com/javase/8/docs/ap.../Lock.html  Weitere Anwendungsbeispiele der Klasse dazu gibt es im Netz.

Am Ende von readPlaylistFromFile muss diese Sperre wieder aufgehoben werden!

In allen anderen Codeteilen iRadioPlayer, displayd, gpiod, ... muss vor Codeteilen die mit der Playlist arbeiten, geprüft werden, ob der Lock gesetzt ist oder nicht.
 
- gpiod darf (muss) Befehle empfangen, darf sie aber nur durchlassen (über iRadioPlayerService) wenn Sperre inanktiv ist
- displayd darf in seiner Zeichen/Aktualisierungsmethode nur Daten der Playlist (Anzahl Elemente) verwenden wenn die Playlist vollständig geladen ist
- iRadioPlayer darf nur umschalten oder starten wenn die Sperre inaktiv ist, hier kann dann auch die Sperrfunktion für gpiods mit übernommen werden, da alles was über iRadioPlayerService läuft hier ankommt

Wenn das konsequent über alle Module durchgezogen wird, würde ein plötzlicher Wechsel der Playlists im laufendem Betrieb unter keinen Umständen (so selten sie vielleicht auftreten) ein Fehlverhalten der App nach sich ziehen.
 
Nebensache: In gpiodSerialOTG kann allgemein noch eine Codeaufhübschung/Refactoring erfolgen, indem man   if (iRadioPlayerService != null) { .... } um alle Befehlerkennungen zieht, aber das ändert in der Funktion nichts, kann auch so bleiben, wurde so auch im Democode gemacht.

Otto
Zitieren
#5
Kommst du klar damit Joe?
Zitieren
#6
Moin Otto,

sagen wir mal so: Mühsam ernährt sich das Eichhörnchen.

Ich muss viel googeln um eine Zeile Java zu schreiben Confused 

Eigentlich läuft es so und ich habe keine Abstürze bemerkt!? Verstehe aber das Problem ...

Bin hier also immer noch am testen.

-Joe
Zitieren
#7
Thumbs_up 

Wenn ich deine interessanten Experimente und Codemodifikationen sehen, habe ich keinen Zweifel, daß das Java-Eichhörnchen kugelrund wird!

Otto
Zitieren


Möglicherweise verwandte Themen…
Thema Verfasser Antworten Ansichten Letzter Beitrag
  iRadioAndroid - iRadio Portierung für Android Geräte OttoBerger 154 10.443 23.03.2024, 13:45
Letzter Beitrag: Uli
  iRadioAndroid - playlistScale JoeXXL 5 350 15.02.2024, 07:59
Letzter Beitrag: OttoBerger
  iRadioAndroid - Station Info JoeXXL 0 147 08.02.2024, 14:05
Letzter Beitrag: JoeXXL
  TV-Box mit iRadioAndroid saarfranzose 6 485 06.01.2024, 21:39
Letzter Beitrag: saarfranzose

Gehe zu: