German Paket Daten sammeln

MarkusR

Well-Known Member
Licensed User
Irgendwie habe ich hier ein Denkfehler drin.

Ich sammle Daten die aufeinanderfolgend rein kommen. (Serielle Schnittstelle)
Eine Datenzeile besteht aus start tab wert new line
Dieses Reihen möchte ich in eine Liste außer dieses New Line Zeichen sammeln.
Beim verarbeiten gehe ich dann die Reihen durch und zerlege die nach Tab Zeichen
und übertrage die Werte in eine Struktur.

Manchmal kommt es vor das ich kein gültigen Wert habe wenn ich die Liste verarbeite, das verstehe ich nicht.

Die andere Seite auf dem Arduino macht das hier:
B4X:
String row = "start\t" + String(valuea);
bt.println(row);
Meine Klasse die die Daten sammeln soll und als Zeilen in die Liste fügt.
B4X:
Sub Class_Globals

    Dim InputBuffer As String
    Public List As List
  
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
  
    InputBuffer = ""
  
    List.Initialize
    List.Clear
  
End Sub

Public Sub Collect(Data As String)
  
    'Log("Collect: '" & Data & "'")
  
    InputBuffer = InputBuffer & Data

    Dim x,x1,x2 As Int
    x = InputBuffer.IndexOf("start")
    If x > 0 Then InputBuffer = InputBuffer.SubString(x) 'mit start fängt die reihe an
  
    If InputBuffer.StartsWith("start") = False Then InputBuffer="" 'ungültiger anfang

    x1 = InputBuffer.IndexOf("start")
    x2 = InputBuffer.IndexOf(CRLF)

    If x1>=0 And x2 > x1 Then 'mindestens eine reihe mit start und chr(10)
  
     Dim Row As String = InputBuffer.SubString2(0,x2) 'bis ohne Zeilenumbruch merken
     List.Add(Row)
  
     InputBuffer = InputBuffer.SubString(x2+1) 'kürzen vorne was ausgelesen wurde weg
  
     Collect("") 'das soll den Rest zerlegen 
    End If

End Sub

Public Sub Test
  
    Collect("234234")
    Collect("start" & TAB)
    Collect("123")
    Collect(CRLF)
    Collect("start" & TAB)
    Collect("456" & CRLF)
    Collect("start" & TAB)
  
    For Each Row As String In List
        Log(Row)
    Next

    InputBuffer = ""
    List.Clear
      
End Sub
 
Last edited:

DonManfred

Expert
Licensed User
Was ist bei deinem Test das "erwartete" Ergebnis? log

B4X:
Logger connected to: 988ad036525346515630
--------- beginning of main
--------- beginning of system
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
start    123
start    456
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **
Ich habe zu collect hinzugefügt

B4X:
Public Sub Collect(Data As String)
 
    'Log("Collect: '" & Data & "'")
 
    InputBuffer = InputBuffer & Data
    InputBuffer = InputBuffer.Replace(Chr(13)&Chr(10),CRLF) ' Neu
    Dim x,x1,x2 As Int
    x = InputBuffer.IndexOf("start")
    If x > 0 Then InputBuffer = InputBuffer.SubString(x) 'mit start fängt die reihe an
 
    If InputBuffer.StartsWith("start") = False Then InputBuffer="" 'ungültiger anfang

    x1 = InputBuffer.IndexOf("start")
    x2 = InputBuffer.IndexOf(CRLF)

    If x1>=0 And x2 > x1 Then 'mindestens eine reihe mit start und chr(10)
 
        Dim Row As String = InputBuffer.SubString2(0,x2) 'bis ohne Zeilenumbruch merken
        List.Add(Row)
 
        InputBuffer = InputBuffer.SubString(x2+1) 'kürzen vorne was ausgelesen wurde weg
 
        Collect("") 'das soll den Rest zerlegen
    End If

End Sub
 

pucki

Active Member
Licensed User
Kleine Frage zum Arduino. Das BT lässt vermuten das du ein Bluetooth-Modul benutzt. Welches ist das, und wie steuerst du es an.
Und ich würde auch gerne wissen wie du es auf der Android-Seite ansteuerst.

@manfred. Ist es mit B4a möglich, irgendwie die Daten des Songs der gerade von einer ANDEREN APP gespielt wird auszulesen und an ein Bluetooth-Modul zu senden.
Ich frage deshalb, weil ich gerne wissen will, welcher Song von wem gerade läuft OHNE auf mein Handy zu schauen.

Gruß

Pucki
 

OliverA

Expert
Licensed User
B4X:
'Based on @DonManfred's update:
Public Sub Collect(Data As String)
   'Log("Collect: '" & Data & "'")
   InputBuffer = InputBuffer & Data
   InputBuffer = InputBuffer.Replace(Chr(13)&Chr(10),CRLF) ' Neu
   'Brauchen kein x
   Dim x1,x2 As Int
   'Add & TAB to all the IndexOf("start") methods
   x1 = InputBuffer.IndexOf("start" & TAB)
   If x1 <> -1  Then ' Wir haben einen start gefunded
       x2 = InputBuffer.IndexOf2(CRLF, x1)
       If x2 <> -1 Then ' Wir haben ein ende gefunden
           Dim row As String = InputBuffer.SubString2(x1,x2) 'bis ohne Zeilenumbruch merken
           'Leeren start ausschliessen (start\t ohne CRLF)
           x1 = row.LastIndexOf("start" & TAB)
           If x1 > 0 Then
               row = row.SubString(x1)
           End If
           List.Add(row)
           InputBuffer = InputBuffer.SubString(x2+1) 'kürzen vorne was ausgelesen wurde weg
           Collect("") 'das soll den Rest zerlegen
       End If
   End If
End Sub
B4X:
    InputBuffer = ""
 
   List.Initialize
   List.Clear
   Collect("234234")
   Collect("start" & TAB)
   Collect("123")
   Collect(CRLF)
   Collect("start" & TAB)
   Collect("456" & CRLF)
   'Start w/o data
   Collect("start" & TAB)
   'Split start
   Collect("sta")
   Collect("rt" & TAB)
   Collect("split start" & CRLF)
   'Junk
   Collect("st")
   Collect(TAB & "123")
   Collect("456" & CRLF)
   'Good
   Collect("start" & TAB)
   Collect("good start" & CRLF)
   'Trick
   Collect("start" & TAB & "start" & TAB & "trick" & CRLF & "start" & TAB & "treat" & CRLF)
 
   For Each Row As String In List
       Log(Row)
   Next

   InputBuffer = ""
   List.Clear
B4X:
start   123
start   456
start   split start
start   good start
start   trick
start   treat
 

MarkusR

Well-Known Member
Licensed User
Kleine Frage zum Arduino. Das BT lässt vermuten das du ein Bluetooth-Modul benutzt. Welches ist das, und wie steuerst du es an.
Und ich würde auch gerne wissen wie du es auf der Android-Seite ansteuerst.
Android BLE2 Version 1.37 hab ein Beispiel hier im Forum dazu gefunden.

Arduino IDE
https://www.arduino.cc/en/Main/Software

Nutze aber besser Serial1, auf dem Uno Serial aber ohne das es am PC angeschlossen ist weil das der USB Port ist

Modul: DSD TECH HM-10 Bluetooth 4.0 BLE
Kostet ~ 9€ bei Amazon.

Das Modul braucht einen Spannungsteiler den man leicht selber machen kann mit zwei Wiederstände.
B4X:
Sub Spannungsteiler()

    Dim vin,vout,r1,r2 As Float
    
    r1 = 1000.0
    r2 = 1950.0
    
    vin = 5.0
    vout = vin * (r2/ (r1+r2))
    
    Log(vout)
    
End Sub

B4X:
// Lautstärke
// * RX is digital pin 10 (connect to TX of other device)
// * TX is digital pin 11 (connect to RX of other device) (voltage divider 5V to 3.3V)

int readPinA = A0;
int readPinD = 7;
int ledPin = 2;

int count=0;
bool alarmflag=false;
unsigned long alarmtime;

#include <SoftwareSerial.h>
SoftwareSerial bt(10, 11); // RX Empfang, TX Senden

void setup() {
  // put your setup code here, to run once:

  Serial.begin(38400);
  //Serial.begin(115200);

  //pinMode(readPinA,INPUT);
  pinMode(readPinD,INPUT);
 pinMode(ledPin,OUTPUT);

//38400

//115200 ist wohl für softwre serial zu viel

  bt.begin(38400);
  //bt.begin(115200);
  //Serial.begin(115200); //BT Modul hat default 9600

 // AT+BAUD4 stellt 115200 Baud ein
  // AT muss OK sagen
  // "AT+BAUD?" Anwort "OK+Get:4"
  //0 – 9600
 //2 – 38400
 //4 – 115200

}

void loop() {

  if (1==1) {

    if (bt.available()) {
      Serial.write(bt.read());
    }
    if (Serial.available()) {
      bt.write(Serial.read());
    }
 
  }
 
 
  // put your main code here, to run repeatedly:

 int valuea = analogRead(readPinA);
 int valued=digitalRead(readPinD);

if (abs(512-valuea)>10)  {
  alarmflag=true;
  alarmtime=millis();
  }

if (millis() - alarmtime >3000) {alarmflag=false;}

 Alarm(alarmflag);

String row = "start\t" + String(valuea);

bt.println(row);

//delay(20); //irgendwie stört das die Serielle (Software) Übertragung ...

}

void Alarm(bool flag)
 {
   if (flag==true)
   {
      digitalWrite(ledPin, HIGH);
   } else {
     digitalWrite(ledPin, LOW);
   }
}
 

MarkusR

Well-Known Member
Licensed User

MarkusR

Well-Known Member
Licensed User
Das sieht so aus als ob Bytes in der Übertragung verschwinden und dann habe ich zwischen zwei Zahlen einen Zeilenumbruch. Das Log schreibt die Daten wie sie rein kommen.
Snap_2019.04.11_23h04m18s_002_.png


Habe nun den Ardunio Mega mit Hardware Serial 1 genutzt. Läuft besser :)
 
Last edited:

pucki

Active Member
Licensed User
Ich an deiner Stelle würde ein Back-Protokoll installieren.

Das heißt z.b. du sendest eine Zahl am Ende der Zelle. Wenn die Zeile analysiert ist, wird diese Zahl zurück geschickt und verglichen. Machen übrigens fast alle Datenübertragungsprotokolle so oder so ähnlich. Oder was meinst du warum du beim Download immer Upload hast. Ohne so was kannst du NIE sicher sein, ob was verschluckt wurde.


Gruß

Pucki
 

MarkusR

Well-Known Member
Licensed User
Ich an deiner Stelle würde ein Back-Protokoll installieren.

Das heißt z.b. du sendest eine Zahl am Ende der Zelle. Wenn die Zeile analysiert ist, wird diese Zahl zurück geschickt und verglichen. Machen übrigens fast alle Datenübertragungsprotokolle so oder so ähnlich. Oder was meinst du warum du beim Download immer Upload hast. Ohne so was kannst du NIE sicher sein, ob was verschluckt wurde.


Gruß

Pucki
jo, tcp braucht sowas nicht, aber eine prüfsumme wäre gut.
hatte gestern den fall im debug modus das ich den mikro controller aus geschaltet hatte und dann liefen noch minuten daten rein in die b4a app. :D
Glücklich bin ich mit der übertragung noch nicht.
Das Projekt was ich grad mache misst Lärmbelästigung per Mikro und Schwellwert.
 

Filippo

Expert
Licensed User
String row = "start\t" + String(valuea);
bt.println(row);
Du solltest immer vorher prüfen ob die ganze Zeile in B4a angekommen ist, erst dann kannst du die Zeile teilen.
Am besten verwendest du die classe von Erel.
 

MarkusR

Well-Known Member
Licensed User
Du solltest immer vorher prüfen ob die ganze Zeile in B4a angekommen ist, erst dann kannst du die Zeile teilen.
Am besten verwendest du die classe von Erel.
Ja, optimal wäre wenn die Zeile wirklich und richtig angekommen ist.
Auf der Arduino Seite nutze ich noch kein B4R.
Vielleicht mache ich son Ping Pong Spiel wie Pucki das mit dem Back-Protokoll erwähnt hat.
Aber dann bekomme ich bestimmt nicht die Wellenform so gut angezeigt die ich vom Mikro aufnehme.
 

Filippo

Expert
Licensed User
Ja, optimal wäre wenn die Zeile wirklich und richtig angekommen ist.
Wenn du die classe von Erel verwendest, dann funnktioniert es auch richtig.

Auf der Arduino Seite nutze ich noch kein B4R.
Ich verwende es auch nicht, bin schon seit langem mit Ardiuno gewöhnt.
 

MarkusR

Well-Known Member
Licensed User
Wenn du die classe von Erel verwendest, dann funnktioniert es auch richtig.
Ich verwende es auch nicht, bin schon seit langem mit Ardiuno gewöhnt.
Meinst du speziell diesen "prefix" mode?



Zwei wichtige Befehle die auf dem Ardunio nützlich sind:
Serial.availableForWrite() Get the number of bytes (characters) available for writing in the serial buffer without blocking the write operation.
Serial.flush() Waits for the transmission of outgoing serial data to complete.
 
Last edited:

thetahsk

Active Member
Licensed User
Android BLE2 Version 1.37 hab ein Beispiel hier im Forum dazu gefunden.

Das Modul braucht einen Spannungsteiler den man leicht selber machen kann mit zwei Wiederstände.
B4X:
Sub Spannungsteiler()

    Dim vin,vout,r1,r2 As Float
 
    r1 = 1000.0
    r2 = 1950.0
 
    vin = 5.0
    vout = vin * (r2/ (r1+r2))
 
    Log(vout)
 
End Sub
Überprüfe bitte mal ob dein "sportlicher Spannungsteiler" stabil das BT Modul versorgt. Mit R1=1000 u. R2=1950 fliesen da gerade mal 1.69 mA.
Das BT Modul wird wahrscheinlich einen deutlich höheren Verbrauch haben. ( 5-30 mA).
Hast du auch Pegelwandler für die serielle Verbindung eingebaut ?
 
Last edited:

Filippo

Expert
Licensed User
Meinst du speziell diesen "prefix" mode?
Nein, einfach nur "bt.println(row);".
Die classe B4a wartet bis ein CRLF kommt und gibt es weiter für weitere prüfungen.
 

MarkusR

Well-Known Member
Licensed User
Nein, einfach nur "bt.println(row);".
Die classe B4a wartet bis ein CRLF kommt und gibt es weiter für weitere prüfungen.
Hatte ich ja so gemacht. Ich glaube das sich der Ausgangspuffer zu schnell gefüllt hatte und dann können die Bytes nicht raus geschickt werden
und alles kommt dann zerstückelt an sobald im Puffer wieder Platz ist.

Edit:
The buffer size is 64 bytes.
 
Last edited:

MarkusR

Well-Known Member
Licensed User
Spannungsteiler
Das Modul läuft mit 5V nur die Übertragung vom Arduino TX nach RX hat den Spannungsteiler über 1k & 2k Widerstand.
 

Filippo

Expert
Licensed User
Hatte ich ja so gemacht. Ich glaube das sich der Ausgangspuffer zu schnell gefüllt hatte und dann können die Bytes nicht raus geschickt werden
und alles kommt dann zerstückelt an sobald im Puffer wieder Platz ist.
Probiere meine modifizierte classe, damit habe ich keine Probleme mehr.
Ich verwende diese classe in B4a und B4i.

B4X:
Sub Class_Globals
    Private mTarget As Object
    Private mEventName As String
    Private sb As StringBuilder
    Private charset As String = "iso-8859-1"
    'Private bc As ByteConverter
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(TargetModule As Object, EventName As String)
    mTarget = TargetModule
    mEventName = EventName
    sb.Initialize
End Sub

Public Sub NewData (Buffer() As Byte)
    'Log("bc.HexFromBytes=" & bc.HexFromBytes(Buffer))
    Dim newDataStart As Int = sb.Length
    sb.Append(BytesToString(Buffer, 0, Buffer.Length, charset))
    Dim s As String = sb.ToString
    Dim start As Int = 0
    For i = newDataStart To s.Length - 1
        Dim c As Char = s.CharAt(i)
        If i = 0 And c = Chr(10) Then '\n...
            start = 1 'might be a broken end of line character
            Continue
        End If
        If c = Chr(10) Then '\n
            CallSubDelayed2(mTarget, mEventName & "_NewText", s.SubString2(start, i))
            start = i + 1
        Else If c = Chr(13) Then '\r
            CallSubDelayed2(mTarget, mEventName & "_NewText", s.SubString2(start, i))
            If i < s.Length - 1 And s.CharAt(i + 1) = Chr(10) Then '\r\n
                i = i + 1
            End If
            start = i + 1
        End If
    Next
    If start > 0 Then sb.Remove(0, start)
End Sub
 
Top