French [RESOLU]Dialogue Android/Arduino sous B4A

Bricopin

Member
Licensed User
Bonjour,
Un projet simple qui me permet de dialoguer avec un Arduino.
Tout fonctionne parfaitement (je transmet et reçoit mes données)
Le seul problème est que les données reçues ne sont pas toujours complètes.
Je dois recevoir une trame de 24 caractères (en fait 24 chiffres).
Des fois je reçois les 24 chiffres, des fois une dizaine, des fois 5, des fois 1, etc...
Je n'ai aucune erreur de fonctionnement.
Ou est mon erreur ?
Cordialement

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("accueil")
    MyDeviceName = "linvor"
    ToastMessageShow("Trying to connect to " & MyDeviceName, True)
    Timer1.Initialize("timer1",50000)
    Timer1.Enabled = False
    
    Try
        BT.Initialize("BT")
        Serial1.Initialize("Serial1")
    Catch
        ToastMessageShow("No BlueTooth Device visible...", True)
    End Try
    
End Sub

Sub Activity_Resume
    Try
        If BT.IsEnabled = False Then
            BT.Enable
        Else
            'connect to SK
            BTConnectToDevice
        End If
    Catch
    End Try
End Sub

Sub BT_StateChanged(NewState As Int,OldState As Int)
    If NewState = BT.STATE_ON Then
        BTConnectToDevice
        Log("BT Connect")
    Else
        Serial1.Disconnect
        Timer1.Enabled = False
        Log("BT Disconnect")
    End If
End Sub

Sub BTConnectToDevice
    Dim PairedDevices As Map
    PairedDevices = Serial1.GetPairedDevices
    Try
        Serial1.Connect3(PairedDevices.Get(MyDeviceName),1)
    Catch
        ToastMessageShow("Device not available",True)
    End Try
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

'Sub mnuConnect_Click
'    Dim PairedDevices As Map
'    PairedDevices = Serial1.GetPairedDevices
'    Dim l As List
'    l.Initialize
'    For i = 0 To PairedDevices.Size - 1
'        l.Add(PairedDevices.GetKeyAt(i))
'    Next
'    Dim res As Int
'    res = InputList(l, "Choose device", -1)             
'    If res <> DialogResponse.CANCEL Then
'        Serial1.Connect(PairedDevices.Get(l.Get(res)))
'    End If
'End Sub

Sub Serial1_Connected (Success As Boolean)
    If Success = True Then
        ToastMessageShow("Bluetooth connected to " & Serial1.Address, False)
        AStreams.Initialize(Serial1.InputStream,Serial1.OutputStream,"AStreams")
        Timer1.Enabled = True
    Else    'disconnected
        ToastMessageShow("Connection to " & Serial1.Address & _
                        " broken!", True)
        Timer1.Enabled = False
        connected = False
    End If
End Sub

Sub AStreams_NewData (Buffer () As Byte)
    msg = BytesToString (Buffer, 0 , Buffer.Length, "UTF8" )
    ToastMessageShow (msg, False )
End Sub
 

klaus

Expert
Licensed User
Longtime User
Est-tu sûr que les données sont parties?
Dans la routine AStreams_NewData essaies de remplacer ToastMessageShow (msg, False ) par Log(msg) pour voir si les données arrivent en plusieurs fois ou si elles sont incomplètes.
J'avais vu une fois, mais je ne me rappelle plus exactement où, une solution qui regroupe plusieurs arrivées de données pour être sûr qu'elles soient complètes.
 

Bricopin

Member
Licensed User
Bonjour Klaus,
Le problème est identique avec Log(msg) mais me permet de mieux voir ce qui se passe.
La trame (en fait il y a 25 chiffres) arrive une fois complète (25) , puis ensuite en 2 fois (Exemple 9+16, puis 4+21, puis 1+24) et ça boucle.
Oui les données sont bien envoyées en totalité (je le vérifie avec le moniteur série de l'Arduino).
Qui plus, j'avais déjà développé cette appli avec WinDev mobile et elle fonctionnait parfaitement.
JPR
 

klaus

Expert
Licensed User
Longtime User
Le problème est identique avec Log(msg) mais me permet de mieux voir ce qui se passe.
C'était le but.
Regardes cette Class: AsyncStreamText.
Dans cette Class, il y a une routine qui réassemble des messages partiels.
Si l'Arduino envoie un caractère spécifique à la fin du message, la Class ci-dessus devrait résoudre le problème.
Si non, tu pourrais modifier la routine pour attendre que le message soit complet et le reconstituer.

J'ai utilisé cette Class dans le projet exemple HC05DataLogger qui figure dans le B4R Example Projects Booklet.
 
Last edited:

Bricopin

Member
Licensed User
Bonjour à tous,
Je n'ai pas utilisé cette classe et j'ai préféré ajouter une routine qui vérifie que le message soit complet.
La routine éffectue bien son travail mais dans la mesure ou les messages tronqués sont très nombreux, le déroulement du programme s'en trouve fortement ralenti.
J'ai donc changé de programme et le nouveau fonctionne parfaitement.
J'ai juste un petit soucis, bien que ce ne soit ni dramatique ni bloquant.
Le programme démarre le mode BT sur le smartphone, mais ne le supprime pas lorsque je quitte le programme.
Y a t'il une commande spécifique .
JPR
C
B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("accueil")
    MyDeviceName = "linvor"
    ToastMessageShow("Trying to connect to " & MyDeviceName, True)
    
    If FirstTime Then
        Serial1.Initialize("Serial1")           
        Timer1.Initialize("Timer1", 500)       
        'Timer2.Initialize("Timer2", 100)       
    End If
    Try
        BT.Initialize("BT")
        Serial1.Initialize("Serial1")
    Catch
        ToastMessageShow("No BlueTooth Device visible...", True)
    End Try
End Sub

Sub Activity_Resume
    pw.KeepAlive(True)        'pour eviter mise en veille : avec bibliotheque "phone"
    Try
        If BT.IsEnabled = False Then
            BT.Enable
        Else
            BTConnectToDevice
        End If
    Catch
    End Try
End Sub

Sub BTConnectToDevice
    Dim PairedDevices As Map   
    PairedDevices = Serial1.GetPairedDevices
    Try
        Serial1.Connect3(PairedDevices.Get(MyDeviceName),1)
    Catch
        ToastMessageShow("Device not available",True)
    End Try
End Sub

Sub Serial1_Connected (Success As Boolean)
    If Success Then
        ToastMessageShow("Bluetooth connected to " & Serial1.Address, False)   
        TextReader1.Initialize(Serial1.InputStream)
        TextWriter1.Initialize(Serial1.OutputStream)
        Timer1.Enabled = True
        'Timer2.Enabled = True
        connected = True
    Else
        ToastMessageShow("Connection to " & Serial1.Address & _
                        " broken!", True)
        connected = False
        Timer1.Enabled = False
        'Timer2.Enabled = False
        Msgbox(LastException.Message, "Error connecting.")
    End If
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    
End Sub

Sub BT_StateChanged(NewState As Int,OldState As Int)
    If NewState = BT.STATE_ON Then
        BTConnectToDevice
        Log("BT Connect")
    Else
        Serial1.Disconnect
        Timer1.Enabled = False
        Log("BT Disconnect")
    End If
End Sub


Sub Timer1_Tick
    If connected Then
        If TextReader1.Ready Then   
            msg = TextReader1.ReadLine   
            trames = (msg)
        End If
    End If
End Sub
i-joint listing nouveau programme
 

klaus

Expert
Licensed User
Longtime User
J'ai donc changé de programme et le nouveau fonctionne parfaitement.
Qu'est-ce que tu as changé? Ça pourrait être intéressant pour d'autres utilisateurs.
Quelle Library utilises-tu pour Bluetooth?
As-tu essayé BT.Disconnect ?
 

Bricopin

Member
Licensed User
Bonjour à tous,
La librairie Serial Ver 1.26 .
Dans le premier programme j'utiliise AsyncStream.
Dans le second j'utilise TextReader.
Je me suis servi de plusieurs programmes disponibles sur le forum.
J'ai fait un mix avec les différents éléments pour obtenir ce que je voulais à savoir :
- Connexion automatique du Bluetooth du smartphone.
- Connexion a un module Bluetooth unique (avec son nom en dur dans le programme).
- Récupération au fil de l'eau de la trame transmise par l'Arduino.
- Émission de commande en direction de l'Arduino.
- Déconnexion automatique du Bluetooth à la fermeture du programme.
JPR
 

Bricopin

Member
Licensed User
Bonjour à tous,
Voici le programme
JPR

B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("accueil")
    myvar = (msg)
    MyDeviceName = "linvor"
    ToastMessageShow("Trying to connect to " & MyDeviceName, True)
    If FirstTime Then
        Serial1.Initialize("Serial1")           
        Timer1.Initialize("Timer1", 500)
        Timer1.Enabled = False       
        Timer2.Initialize("Timer2", 500)
        Timer2.Enabled = False
    End If
    Try
        BT.Initialize("BT")
        Serial1.Initialize("Serial1")
    Catch
        ToastMessageShow("No BlueTooth Device visible...", True)
    End Try
End Sub

Sub Activity_Resume
    pw.KeepAlive(True)        'pour eviter mise en veille : avec bibliotheque "phone"
    Try
        If BT.IsEnabled = False Then
            BT.Enable
        Else
            BTConnectToDevice
        End If
    Catch
    End Try
End Sub

Sub BT_StateChanged(NewState As Int,OldState As Int)
    If NewState = BT.STATE_ON Then
        BTConnectToDevice
        Log("BT Connect")
    Else
        Serial1.Disconnect
        Timer1.Enabled = False
        Timer2.Enabled = False
        Log("BT Disconnect")
    End If
End Sub

Sub BTConnectToDevice
    Dim PairedDevices As Map   
    PairedDevices = Serial1.GetPairedDevices
    Try
        Serial1.Connect3(PairedDevices.Get(MyDeviceName),1)
    Catch
        ToastMessageShow("Device not available",True)
    End Try
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed  Then
        pw.ReleaseKeepAlive        'pour eviter mise en veille : avec bibliotheque "phone"
    End If
End Sub

Sub Serial1_Connected (Success As Boolean)
    If Success = True Then
        ToastMessageShow("Bluetooth connected to " & Serial1.Address, False)   
        TextReader1.Initialize(Serial1.InputStream)
        TextWriter1.Initialize(Serial1.OutputStream)
        Timer1.Enabled = True
        Timer2.Enabled = True
        connected = True
    Else
        ToastMessageShow("Connection to " & Serial1.Address & _
                        " broken!", True)
        Timer1.Enabled = False
        connected = False
        Timer2.Enabled = False
        Msgbox(LastException.Message, "Error connecting.")
    End If
End Sub

Sub Timer1_Tick
    If connected Then
        If TextReader1.Ready Then   
            msg = TextReader1.ReadLine
            Trames = (msg)
            msg = ("")
        End If
    End If
End Sub

Sub Timer2_Tick
    'Log (Trames)
    EditText1.text = (Trames)
    Trames = ("")
End Sub

Sub btEntrer_Click
    Activity.LoadLayout("nivstab")

Sub BtStopNivStab_Click        ' Choix "z" = Arret de la fonction en cours
    TextWriter1.WriteLine("z")
    TextWriter1.Flush
End Sub
 

Bricopin

Member
Licensed User
Bonjour à tous,
Mon projet est constitué de plusieurs activity.
Je récupère en permanence les données provenant de l'Arduino dans une variable (trames).
Ces données me servent à effectuer différentes actions.
Quels est la bonne manière de transferer cette variable dans les autres activity.
J'ai fais des essais (statsub, callsub, callsubdelayed, etc) grâces aux messages récupérés sur le forum mais ça ne fonctionne pas.
JPR
 
Last edited:

Serge Bertet

Active Member
Licensed User
Je fais la même chose que toi mais en wifi, les infos viennent d'autres téléphones.
J'ai mis tout le code wifi dans le service starter avec timers, buffers, etc.
Quand il y a des données je propage les infos à l'activité qui est ouverte.
B4X:
    ' Propager l'info à toutes les activités (sauf "play vidéo" et "play image").
    If SubExists(PrefTools, "FileReceived") Then CallSub(PrefTools, "FileReceived")
    If SubExists(Main, "FileReceived") Then CallSub(Main, "FileReceived")
    If SubExists(preferences, "FileReceived") Then CallSub(preferences, "FileReceived")
 

Bricopin

Member
Licensed User
Bonjour à tous,
J'ai fais un essai avec la proposition d'Electrizay (merci à lui) mais en définitive j'ai opté pour une autre solution.
En fait je charge dans "Activity_Create" toutes mes Layout avec LoadLayout("xxxxx") et je n'ai plus qu'à les rendre visibles ou pas suivant le besoin.
De ce fait, ma variable "trames" est en permanence disponible.
Comme mes différentes Layout possédaient des éléments similaires, cela me simplifie le travail dans la mesure ou je définie tous mes éléments identiques seulement dans la 1er Layout et je "colle " ensuite les autres Layout par dessus, c'est bien plus pratique.
Ayant trouvé une solution satisfaisante je passe ce post en résolu .
J'ai d'autres questions, j'ouvrirais donc de nouveaux posts au fur et à mesure.
JPR
 
Last edited:

klaus

Expert
Licensed User
Longtime User
Juste une précision:
Le fait de charger un Layout ne signifie pas charger une nouvelle Activity!
Les Layouts sont indépendants des Activities!
Dans ton cas, tu n'as qu'une Activity, mais to jongles avec différents Layouts.

Pour voir la différence, tu peux regarder ce thread: Different examples with two layouts.
 

Bricopin

Member
Licensed User
Bonjour,
Oui, je n'ai pas employé les bons termes.
J'ai modifié mon post précédents afin qu'il soit compréhensible.
JPR
 
Top