Android Question Bluetooth in service

George Anifantakis

Member
Licensed User
Longtime User
Hi
I've tried to create a service to print in a bluetooth printer using the bluetooth example with the below results.

First problem is that it prints only the first time the service is called. If i try to run the service again without restarting the application serial fails to connect with error Service discovery failed. If i restart the appl first time works properly. This happens in rapid mode, in other modes legacy or release it doesn't print anything.

Below the code

B4X:
#Region  Service Attributes
    #StartAtBoot: False
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim admin As BluetoothAdmin
    Dim serial1 As Serial
    Dim foundDevices As List
    Type NameAndMac1 (Name As String, Mac As String)
    Dim connectedDevice As NameAndMac1
    Dim nm As NameAndMac1
    Dim cMac As String = "00:02:5B:B3:22:09"
    Dim cStatus As Int = 0
    Dim AStream As AsyncStreams
End Sub
Sub Service_Create
  '  If admin.IsInitialized = False Then    admin.Initialize("admin")
  ' If serial1.IsEnabled = False Then    serial1.Initialize("serial1")
  admin.Initialize("admin")
  serial1.Initialize("serial1")
End Sub

Sub Service_Start (StartingIntent As Intent)
      If admin.IsEnabled = False Then
        If admin.Enable = False Then
            ToastMessageShow("Error enabling Bluetooth adapter.", True)
        Else
            ToastMessageShow("Enabling Bluetooth adapter...", False)
            'the StateChanged event will be soon raised
        End If
  End If
 
  bConnect
End Sub


Public Sub bConnect
    cStatus = 0
    'ToastMessageShow(admin.IsInitialized , True)
    If cMac <> "" Then
    '    ProgressDialogShow("Connecting printer, please wait..")   
        cStatus = 2
        serial1.Disconnect
        serial1.Connect(cMac)
    '    serial1.Listen
    Else
        SearchDevice
    End If
End Sub


Sub Serial1_Connected (Success As Boolean)
    'ProgressDialogHide
'    Log("connected: " & Success)
    ToastMessageShow(Success , True)
    If Success = False Then
        If cStatus = 1 Then
          SearchDevice
        Else
          serial1.Disconnect
          Log(LastException.Message)
          ToastMessageShow("Error connecting: " & LastException.Message, True)
          CallSub(Main, "StopSrv")
        End If
    Else
        cMac = serial1.Address
        cStatus = 9
        PrintReceipt("werwer")
        'StartActivity(ChatActivity)
    End If
End Sub

Sub SearchDevice
    cStatus = 2
    foundDevices.Initialize
    nm.Initialize
      If admin.StartDiscovery    = False Then
        ToastMessageShow("Error starting discovery process.", True)
    Else
        'ProgressDialogShow("Searching for devices...")
    End If
End Sub

Sub Admin_DeviceFound (Name As String, MacAddress As String)
    nm.Name = ""
    nm.Mac = ""
    If Name = "MPT-II" Then
        nm.Name = Name
        nm.Mac = MacAddress
        admin.CancelDiscovery
    End If
    'ProgressDialogShow("Searching for devices (~ device found)...".Replace("~", foundDevices.Size))
End Sub

Sub Admin_DiscoveryFinished
    ProgressDialogHide
    If nm.Name = "MPT-II" Then
        'ProgressDialogShow("Connecting " & nm.Name )
        serial1.Connect(connectedDevice.Mac)
    End If
End Sub


Public Sub Disconnect
    serial1.Disconnect
End Sub



Public Sub PrintReceipt(instr As String)
Try
    If AStream.IsInitialized = False Then
        'AStream.InitializePrefix(serial1.InputStream, True, serial1.OutputStream, "AStream")
        AStream.Initialize(serial1.InputStream, serial1.OutputStream, "AStream")
    End If
    Dim buf(2) As Byte
    buf(0) = 0x1B
    buf(1) = 0x40
    Log(AStream.Write(buf))
    Log(AStream.Write(instr.GetBytes("UTF8")))
    'AStream.Write(Chr(27)&Chr(64).GET )
    Dim buf(1) As Byte
    buf(0) = 0x0A
    AStream.Write(buf)
  'writeLine(Chr(27) & Chr(116) & Chr(33))
  Catch
    ToastMessageShow("Error.." , False)
  End Try
  serial1.Disconnect
  CallSub(Main, "StopSrv")
End Sub

Sub Service_Destroy
  serial1.Disconnect
End Sub
 

George Anifantakis

Member
Licensed User
Longtime User
I tried using service. The service operation sometimes works and other don't. Sometimes the connection is established but the printer does,t print anything. As i mentioned above this happens in legacy or release modes in rapid mode things are better. I think that the problem is that the service close the connection before data have been transmitted to the printer. If this is the problem how can check if the transition has been completed.

I changed the code to be simple as i need to check only for paired devices and connect if available.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim admin As BluetoothAdmin
    Dim serial1 As Serial
    Type NameAndMac1 (Name As String, Mac As String)
    Dim connectedDevice As NameAndMac1
    Dim nm As NameAndMac1
    Dim PairedDevices As Map
    Dim cMac As String = "00:02:5B:B3:22:09"
    Dim cStatus As Int = 0
    Dim AStream As AsyncStreams
    Dim cnt As Int
    Dim ProcActive As Boolean
End Sub
Sub Service_Create
  admin.Initialize("admin")
  serial1.Initialize("serial1")
End Sub

Sub Service_Start (StartingIntent As Intent)
    PairedDevices = serial1.GetPairedDevices
    ProcActive = True
    cnt = 0
    If admin.IsEnabled = False Then
        If admin.Enable = False Then
            ToastMessageShow("Error enabling Bluetooth adapter.", True)
            ProcEnd
    Else
            ToastMessageShow("Enabling Bluetooth adapter...", False)
            'the StateChanged event will be soon raised
            End If
    End If
    bConnect
End Sub

Public Sub bConnect
    cStatus = 0
    'ToastMessageShow(admin.IsInitialized , True)
    Dim wmac As String = ""
    Dim i As Int
    wmac = ""
    For i = cnt  To PairedDevices.Size - 1
        If PairedDevices.GetKeyAt(i) = "MPT-II" Then
            wmac = PairedDevices.Get(PairedDevices.GetKeyAt(i))   
            cnt = i + 1
            Exit
        End If
    Next
    If wmac <> "" Then serial1.Connect(wmac)
    If wmac = "" AND i = PairedDevices.Size  Then
        ToastMessageShow("Cannot find any printer.." , False)   
        ProcEnd
    End If
End Sub

Sub Serial1_Connected (Success As Boolean)
    ToastMessageShow(Success , True)
    If Success = False Then
        bConnect
    Else
'        cMac = serial1.Address
'        cStatus = 9
        PrintReceipt1("werwer")
    End If
End Sub

Public Sub PrintReceipt1(instr As String)
Dim os1 As OutputStream
os1=serial1.OutputStream
Dim buf(2) As Byte
buf(0) = 0x1B
buf(1) = 0x40
os1.WriteBytes(buf , 0, buf.Length)
os1.Flush
os1.WriteBytes(instr.GetBytes("UTF8") , 0, instr.GetBytes("UTF8").Length)
os1.Flush
Dim buf(1) As Byte
buf(0) = 0x0A
os1.WriteBytes(buf , 0, buf.Length)
os1.Flush
  ProcEnd   
End Sub

Sub ProcEnd
serial1.Disconnect
ProcActive = False
CallSub("Main" , "StopSrv")
End Sub


Sub Service_Destroy
'  serial1.Disconnect
End Sub
 
Upvote 0

George Anifantakis

Member
Licensed User
Longtime User
1. Keeping the connection open. If you mean to delete the statement serial1.Disconnect I tried that but major problem encountered after that as first time is running but the next time cannot connect properly. tablet must be restarted to release the connection.

2. Regarding the AsyncStreams i 've tried as well replacing the below send to printer block

B4X:
Public Sub PrintReceipt1(instr As String)
Dim os1 As OutputStream
os1=serial1.OutputStream
Dim buf(2) As Byte
buf(0) = 0x1B
buf(1) = 0x40
os1.WriteBytes(buf , 0, buf.Length)
os1.Flush
os1.WriteBytes(instr.GetBytes("UTF8") , 0, instr.GetBytes("UTF8").Length)
os1.Flush
Dim buf(1) As Byte
buf(0) = 0x0A
os1.WriteBytes(buf , 0, buf.Length)
os1.Flush

  ProcEnd 
End Sub


With this one using asyncstream

B4X:
Public Sub PrintReceipt(instr As String)

Try
    If AStream.IsInitialized = False Then
        'AStream.InitializePrefix(serial1.InputStream, True, serial1.OutputStream, "AStream")
        AStream.Initialize(serial1.InputStream, serial1.OutputStream, "AStream")
    End If
    Dim buf(2) As Byte
    buf(0) = 0x1B
    buf(1) = 0x40
    Log(AStream.Write(buf))
    Log(AStream.Write(instr.GetBytes("UTF8")))
    Dim buf(1) As Byte
    buf(0) = 0x0A
    AStream.Write(buf)
  Catch
    ToastMessageShow("Error.." , False)
  End Try
  ProcEnd
End Sub

Nothing same behavior. Any other suggestion?
 
Upvote 0

George Anifantakis

Member
Licensed User
Longtime User
I think now is working properly. Also the async transmission process needed to be inside try catch statements in order to fire the events. Blow the code. Thanks a lot for your support.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim admin As BluetoothAdmin
    Dim serial1 As Serial
    Dim PairedDevices As Map
    Dim cStatus As Int = 0
    Dim AStream As AsyncStreams
    Dim cnt As Int
    Dim ProcActive As Boolean
End Sub
Sub Service_Create
  admin.Initialize("admin")
  serial1.Initialize("serial1")
  PairedDevices = serial1.GetPairedDevices
    ProcActive = True
    cnt = 0
    If admin.IsEnabled = False Then
        If admin.Enable = False Then
            ToastMessageShow("Error enabling Bluetooth adapter.", True)
            ProcEnd
    Else
            ToastMessageShow("Enabling Bluetooth adapter...", False)
            'the StateChanged event will be soon raised
            End If
  End If
  bConnect
End Sub

Sub Service_Start (StartingIntent As Intent)
    PrintReceipt("werwer")
End Sub

Sub AStream_Error
    bConnect
End Sub

Sub AStream_Terminated
    bConnect
End Sub

Public Sub bConnect
    cStatus = 0
    Dim wmac As String = ""
    Dim i As Int
    wmac = ""
    For i = cnt  To PairedDevices.Size - 1
        If PairedDevices.GetKeyAt(i) = "MPT-II" Then
            wmac = PairedDevices.Get(PairedDevices.GetKeyAt(i))   
            cnt = i + 1
            Exit
        End If
    Next
    If wmac <> "" Then serial1.Connect(wmac)
    If wmac = "" AND i = PairedDevices.Size  Then
        ToastMessageShow("Cannot find any printer.." , False)   
        cStatus = 9
        ProcEnd
    End If
End Sub

Sub Serial1_Connected (Success As Boolean)
    ToastMessageShow(Success , True)
    If Success = False Then
        bConnect
    Else
        PrintReceipt("werwer")
    End If
End Sub

Public Sub PrintReceipt(instr As String)
  Try
    If AStream.IsInitialized = False Then
        'AStream.InitializePrefix(serial1.InputStream, True, serial1.OutputStream, "AStream")
        AStream.Initialize(serial1.InputStream, serial1.OutputStream, "AStream")
    End If
    Dim buf(2) As Byte
    buf(0) = 0x1B
    buf(1) = 0x40
    Log(AStream.Write(buf))
    Log(AStream.Write(instr.GetBytes("UTF8")))
    Dim buf(1) As Byte
    buf(0) = 0x0A
    AStream.Write(buf)
    ProcEnd
  Catch   
  End Try
End Sub

Sub ProcEnd
ProcActive = False
CallSub("Main" , "StopSrv")
End Sub
 
Upvote 0

George Anifantakis

Member
Licensed User
Longtime User
I noticed that if the printer will close after 1st print the system sent the data without any error message. I can manage that using a confirmation dialog after the printing. The problem starts when printer is restarted. Then the connection fails. Only with tablet restart the process starts working again. I tried with the below code to initialize the process with no luck.

B4X:
    If PRTSrv.serial1.IsInitialized = True Then  PRTSrv.serial1.Disconnect
    If PRTSrv.admin.IsInitialized = True Then
      PRTSrv.admin.Disable
      PRTSrv.admin.Enable
    End If
    PRTSrv.admin.Initialize("admin")
    PRTSrv.serial1.Initialize("serial1")

So can you please tell me which is the proper way to initialize the connection like during system restart.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
This code is not good:
B4X:
Catch 

EndTry

You should at least log the error message.

You should also not try to reconnect immediately when there is an error. I think that it is better not to connect at all.

Instead let the user reconnect (with a button).


You should not access serial1 from the activity. Instead you should call a sub in the service that will initialize it. You can use CallSubDelayed for that.
 
Upvote 0

George Anifantakis

Member
Licensed User
Longtime User
The process is based on the above comments "Only reconnect after AStream_Terminated was fired (or AStream_Error)" keeping that in mind, first send to printer command is executed and if there is an error the service is trying to connect. I may have understood something wrong. So can you please clarify the below.
1. The connect statement must be in the service_create sub?
2. The connect statement must be in a different sub that will be called using CallSubDelayed ?
3. When AStream_Terminated was fired (or AStream_Error) i should try to reconnect calling the above created sub to connect using CallSubDelayed? or the user from the activity should call this sub using CallSubDelayed using a button ?
4. The connect sub should also initilize admin and serial or trying only to connect?

Also another problem i found is that if you close the app using exitapplication and try to restart the application again print fails. if you stop the application using the home key this problem does not occur. The behavior is very strange and i do not know how to initilize the process from the start at least to use it every time it prints to be sure that everything will work.
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
You should handle the Serial object in your service. You can connect the serial in any sub you want. You just need to make sure that you understand in which cases the sub is called and not reconnect an already active connection.

I'm also not sure that it is a good idea to try to connect immediately after the connection was broken. I think that it is better to let the user choose when to reconnect.

See this example: FileTransfer - Send and receive files with AsyncStreams
 
Upvote 0
Top