Android Question Serial Connected event not working

Yannick Proulx

Member
Licensed User
Hi Guys,
I'm working on a project that need to connect to a bluetooth barcode scanner using the SPP protocol(I was getting some scanning error using the HID protocol).
I wanna use the scanner in multiple activity.
I was able to connect to my scanner when the serial code was in an activity ( as per SPP exemple found on this web site). the problem is that I cannot use it in other activity.(at lease I dont know How to do it if it is possible to do it)

so I created a code module to execute the scanner sub from every activity.

the problem is that now the connected trigger never get hit and I don't know if the serial is connected or not .


How do you guys do to connect to a Serial Scanner and use multiple Activity?


my startup activity(Main) start my code module called Scanner(see below) this way :

B4X:
Sub Activity_Create(FirstTime As Boolean)
 
   Activity.LoadLayout("1")
     'try to connect to serial
    If Starter.kvs.ContainsKey(Starter.MAC_ADDRESS_Scanner) Then
        ToastMessageShow("Tentative de connexion au scanner...",True)
        Scanner.ConnectSerial
    Else
        Scanner.ShowPairedDevices
    End If

End Sub

and here is my Scanner Code Module :

B4X:
'Code module
'Subs in this code module will be accessible from all modules.
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim serial1 As Serial
    Dim AStream As AsyncStreams
    Dim uiSender As uiSender
   
End Sub

public Sub ConnectSerial
    serial1.Initialize("Serial1")
    serial1.Connect(Starter.kvs.Get(Starter.MAC_ADDRESS_Scanner))
      
End Sub

public Sub ShowPairedDevices

    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
    If l.Size=0 Then
        l.Add("No device(s) found...")
    End If
    Dim res As Int
    res = InputList(l, "Choose device", -1) 'show list with paired devices
    If res <> DialogResponse.CANCEL Then
        If l.Get(res)="No device(s) found..." Then
            Return 'Just
        Else
            Starter.kvs.Put(Starter.MAC_ADDRESS_Scanner,PairedDevices.Get(l.Get(res))) 'Store selection for further use
           
            serial1.Connect(Starter.kvs.Get(Starter.MAC_ADDRESS_Scanner)) 'convert the name to mac address and connect
        End If
    End If
  
End Sub
Sub AStream_NewData (Buffer() As Byte)
    Log("Received: " & BytesToString(Buffer, 0, Buffer.Length, "UTF8"))
    If uiSender <> Null Then
        Log("Writing to " & uiSender.Tag)
        uiSender.Text = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    End If

End Sub

Sub AStream_Error
    Log("Connection broken...")
  
    AStream.Close
    serial1.Disconnect
    ShowPairedDevices
   
End Sub



Sub AStream_Terminated
    Log("Connection terminated...")
    AStream_Error
End Sub

Sub Serial1_Connected (Success As Boolean)
    If Success = True Then
        ToastMessageShow("Scanner Connecté",False)
        Log("Scanner is now connected. Waiting for data...")
        AStream.Initialize(serial1.InputStream, serial1.OutputStream, "AStream")
    Else
       
        If Starter.kvs.ContainsKey(Starter.MAC_ADDRESS_Scanner) Then
            Log("Trying to connect to mac address : " & Starter.kvs.Get(Starter.MAC_ADDRESS_Scanner))
            If Starter.firsttry Then
                Starter.firsttry = False 'set to false has we have first try it once
                ToastMessageShow("Tentative de connexion au scanner...",True)
                serial1.Connect(Starter.kvs.Get(Starter.MAC_ADDRESS_Scanner)) 'convert the name to mac address and connect
               
            Else
                Dim result As Int = Msgbox2("Connection Impossible, Verifiez que le scanner est allumé. Voulez vous réessayer ?","Erreur de connexion","Oui","Annuler","Choisir un autre scanner",LoadBitmap(File.DirAssets,"new Icon.jpg"))
                Select Case result
                   
                    Case DialogResponse.POSITIVE
                        Log("Trying to reconnect Scanner once again...")
                        serial1.Connect(Starter.kvs.Get(Starter.MAC_ADDRESS_Scanner)) 'convert the name to mac address and connect
                                       
                    Case DialogResponse.NEGATIVE
                        Log("User want to change Scanner MAC Address")
                        ShowPairedDevices
                       
                    Case DialogResponse.CANCEL
                        Log("Cancel selected so return")
                        Return
                               
                End Select
            End If
           
        Else
            Log("As no scanner already connected ... ask user to choose a scanner")
            ShowPairedDevices
        End If
       
    End If
End Sub


thanks for you help once again

Yannick
 

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Yannick Proulx

Member
Licensed User
use a class or a service for this. Code Modules can not receive events.
thank you for that quick answer don.

using a class will require me to initialize as new instance of that class on every activity, no ?
can I create a process_Global in my starter service to initialize one and keep it alive as long my program is running ?

another question , How can I return the async stream that class will receive to the correct Editbox in the correct activity ?
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

Yannick Proulx

Member
Licensed User
thanks for you help, you pinpoint me to the right direction so now it works.

here is the way I get the Async Stream to the right Edittext

in my activity I added the following sub (T is my Scanner Class initialize in Starter Service ) :

B4X:
Sub EditText1_FocusChanged (HasFocus As Boolean)
    If HasFocus Then
   
        Log ("Main1 EditText has focus")
        Starter.t.et =Sender
Else
        Starter.t.et = Null
    End If
   
End Sub

in my scanner class I added an object (as edittext cannot be in Class_Globals) then in My AsyncStream new_data I declare an editText = to my Object
(The et Object has been set by the Activity sub upper)

B4X:
Dim et As Object 'in class_Globals

Sub AStream_NewData (Buffer() As Byte)
    Dim temp As EditText =et
   
    Log("Received: " & BytesToString(Buffer, 0, Buffer.Length, "UTF8"))
    If et <> Null Then
        Log("Writing to " & temp.Tag)
        temp.Text = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    End If

End Sub

Hope this can help somebody else

Yannick
 
Upvote 0

Yannick Proulx

Member
Licensed User
don , another question
I get the following error while trying to send a msgbox to the user from within my scanner class

B4X:
Error occurred on line: 101 (test)
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.ref.Reference.get()' on a null object reference
    at anywheresoftware.b4a.keywords.Common.Msgbox2Async(Common.java:475)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:755)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:345)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
    at anywheresoftware.b4a.BA$2.run(BA.java:360)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6688)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)


I tried the msgbox2async and msgbox2 but I received the same error
B4X:
                Msgbox2Async("Connection Impossible, Verifiez que le scanner est allumé. Voulez vous réessayer ?","Erreur de connexion","Oui","Annuler","Choisir un autre scanner",Null,False)
                Wait For Msgbox_Result (Result As Int)
                Select Case Result

Is it because I can't prompt the user from withing a class ...
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
I always use services for all non-ui tasks (like to connect to my scanner and receive data). Then I call a sub in the Activity with parameters via

B4X:
CallSubDelayed2(Main.ScannTarget,"NewData",BC)

Here I use "ScanTarget" (a string variable where I put the name of the Activity). So I can call the same sub in e.g. 3 different Activities. Inside the sub of the activity I fill the editext with the value or show a messagebox.

Service -> Call Sub of Activity -> Activity -> Show message(box) or use data from scanner -> Call Sub in Service to re-connect to the scanner or whatever you want to do

SERVICE
B4X:
Sub AStream_Error
    Log("Connection is broken.")
 
    AStream.Close
    serial1.Disconnect
    Main.ConnectedScanner=""
    admin.StartDiscovery
    CallSubDelayed(Main.ScannTarget,"ScannerDisConnected")
End Sub

ACTIVITY
B4X:
Sub ScannerDisConnected
    ScannerConnectedLBL.Color=Colors.yellow
    ScannerConnectedLBL.Text="Waiting for Scanner to connect..."
End Sub
 
Upvote 0

Yannick Proulx

Member
Licensed User
I always use services for all non-ui tasks (like to connect to my scanner and receive data). Then I call a sub in the Activity with parameters via

B4X:
CallSubDelayed2(Main.ScannTarget,"NewData",BC)

Here I use "ScanTarget" (a string variable where I put the name of the Activity). So I can call the same sub in e.g. 3 different Activities. Inside the sub of the activity I fill the editext with the value or show a messagebox.

Service -> Call Sub of Activity -> Activity -> Show message(box) or use data from scanner -> Call Sub in Service to re-connect to the scanner or whatever you want to do

SERVICE
B4X:
Sub AStream_Error
    Log("Connection is broken.")

    AStream.Close
    serial1.Disconnect
    Main.ConnectedScanner=""
    admin.StartDiscovery
    CallSubDelayed(Main.ScannTarget,"ScannerDisConnected")
End Sub

ACTIVITY
B4X:
Sub ScannerDisConnected
    ScannerConnectedLBL.Color=Colors.yellow
    ScannerConnectedLBL.Text="Waiting for Scanner to connect..."
End Sub


so If I understand correctly, you set main.ScanTarget value to the name of the activity when you switch activity.
You have in every activity a sub Called "ScannerDisconnected" with it specific info for this activity.
and you received you AStream data in the service then use the main.ScanTarget to return it to the right activity.

right?

btw Thanks for your help
really appreciated

Yannick
 
Upvote 0
Top