How to use the pyjnius read and write arguments for Bluetooth getInputStream and getOutputStream?

自闭症网瘾萝莉.ら 提交于 2020-01-25 03:59:05

问题


I have been fumbling with getting data from a bluetooth RS232 converter using the python for android jnius library. I had thought that it would be as simple as the PySerial library, but as I am still new to java the implementation is quite different.
I created the bluetooth connection quite easily, but as soon as I try to read or write data I get a jnius.jnius.JavaException that No methods matching your arguments, and that the methods available for read are: '()I', '([B)I', '([BII)I' and for write are '(I)V', '([B)V', '([BII)V'. I tried finding this in the developer android docs as well as DuckDuckGoing it but with no clarity.
I also tried the BufferedReader example (Here) using the readLine() method, but I am constantly getting an error: JavaException: JVM exception occurred: Attempt to invoke virtual method 'int java.io.InputStream.read(byte[], int, int)' on a null object reference.

Can someone please point me to the documentation to understand the above read and write arguments?
Also, please help me to understand why the read, readLine() and write objects does not return any data?

Java libraries I call:

BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
BluetoothDevice = autoclass('android.bluetooth.BluetoothDevice')
BluetoothSocket = autoclass('android.bluetooth.BluetoothSocket')
InputStreamReader = autoclass('java.io.InputStreamReader')
BufferedReader = autoclass('java.io.BufferedReader')
UUID = autoclass('java.util.UUID')
System = autoclass('java.lang.System')

Connecting code (got this from Github and above link):

    def get_socket_stream(self, name):
        paired_devices = BluetoothAdapter.getDefaultAdapter().getBondedDevices().toArray()
        self.rfsocket == None
        for device in paired_devices:
            if device.getName() == name:
                if device.bluetoothEnabled:
                    if not device.connected:
                        self.rfsocket = device.createInsecureRfcommSocketToServiceRecord(
                            UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"))
                        self.reader = InputStreamReader(self.rfsocket.getInputStream(), 'LATIN-1')
                        recv_stream = BufferedReader(self.reader)
                        send_stream = self.rfsocket.getOutputStream()
                        break
        print(self.rfsocket.getRemoteDevice().getName())
        if self.rfsocket.port <= 0:
            self.rfsocket = device.createRfcommSocket(1)
            if not self.rfsocket.connected:
                print('port two: ',self.rfsocket.port)
                self.rfsocket.connect()

Read and write code (source: same as above link):

    def GetBSerial(self):
        self.messager('Trying Serial')
        self.recv_stream, self.send_stream = self.get_socket_stream(devicename)
        if  not self.rfsocket.connected and self.recv_stream == None:
            print("Get paired device failed")
        else:
            print('Initiating trigger')
            self.weight_ticker()
    def GetInput(self):
        self.send_stream.write("Hallo\r\n")
        self.send_stream.flush
        if self.rfsocket.connected and self.recv_stream != None:
            if self.weigh_tme > 0:
                while self.recv_stream.ready != None:
                    try:
                        self.scale_output = self.recv_stream.readLine()
                    except jnius.jnius.JavaException as e:
                        print("JavaException: ", e, self.rfsocket.connected)
                    except ValueError as e:
                        print("Misc error: ", e)

                    try:
                        self.show_input(self.scale_output)
                    except ValueError:
                        pass

Update:

So I finally got the Input using the readLine() method to not return an error and also return the string. I cleaned things up a bit, but the code does not differ much. Main thing though is I checked whether the device != None and if rfsocket.connected: before creating getInputStream within my eventloop, so as not to re-create the socket object. Have to test more to see where was the main problem. Still do not no what the arguments are of the read and write method. The readLine() method returns the string intermitantly or not at all and my eventloop seems to not work with the readLine() method.

Update on update:

The event loop works again. My bad, I did not call the trigger object correctly. The readLine() method has a strange pattern in that on the first read it gives me JavaException: JVM exception occurred: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference, subsequent reads gives me pieces of the expected string or an empty string. I had similar string bits and pieces returned when I received the data via a hardline using PySerial. The solution was resetting the input buffer. Is there something similar in the above java libraries?

Finally cracked the exceptions:

Yes, this is exciting! After many hours I had noticed that I could not get the Input anymore only exceptions. I tried the BufferedInputStream library and got the same result, there was no more intermittant read. Why? So I re-Apk'd the main file of last night and boom intermittant Input read once again.
The reason was if I create the java objects when the rfsocket Bluetooth object is not connected to the specified port, Null objects was initialised on a different port which for some reason was not seen by the if blocks self.recv_stream is not None and self.recv_stream != None. Probably because they are not Null objects but Null for the subsequent port 1 socket connection I specified.
The readline() work as is in my example, the read() takes three arguments bytes(), int offset, int len(bytes() which is not clear from the jnius.jnius.exception hieroglyphics' message. Still figuring out the write method. One thing that you can specify in the BufferedReader method is a 2nd argument for the chunk size you want to read or in java speak defaultCharBufferSize.


回答1:


So I am posting my answers as I have solved them all.
To connect to bluetooth I built on the GitHub example by following the suggestions on the android developers site. I had to set my own socket explicitly before creating the getOutputStream and getInputStream java objects otherwise the ports of the connection and objects will not be the same. You only need to call the GetBSerial() to connect

    def get_socket_stream(self, name):
        defaultCharBufferSize = 8192
        try:
            blueAdapt = BluetoothAdapter.getDefaultAdapter()
            if self.rfsocket is not None:
                if self.rfsocket.connected:
                    reader = InputStreamReader(self.rfsocket.getInputStream(), getEncode)
                    recv_stream = BufferedReader(reader)
                    send_stream = self.rfsocket.getOutputStream()
                else:
                    self.rfsocket = self.device.createRfcommSocketToServiceRecord(UUID.fromString(getUuid))
                    if self.get_port_connect():
                        reader = InputStreamReader(self.rfsocket.getInputStream(), getEncode)
                        recv_stream = BufferedReader(reader, defaultCharBufferSize)
                        send_stream = self.rfsocket.getOutputStream()
            else:
                if blueAdapt is not None:
                    if blueAdapt.isEnabled():
                        paired_devices = blueAdapt.getBondedDevices().toArray()
                        self.rfsocket = None
                        for self.device in paired_devices:
                            if self.device.getName() == name:
                                if self.device.bluetoothEnabled:
                                    self.rfsocket = self.device.createRfcommSocketToServiceRecord(
                                        UUID.fromString(getUuid))
                                    if self.rfsocket is not None:
                                        if self.get_port_connect(): #connect and set the port before creating java objects
                                            reader = InputStreamReader(self.rfsocket.getInputStream(), getEncode)
                                            recv_stream = BufferedReader(reader, defaultCharBufferSize)
                                            send_stream = self.rfsocket.getOutputStream()
                                            break
                    else:
                        self.ids.bluet_info.text = '[b]Bluetooth not enabled[/b]'
            if recv_stream is not None and send_stream is not None:
                return recv_stream, send_stream
            else:
                return False, False
        except UnboundLocalError as e:
            return False, False
        except TypeError as e:
            return False, False
    def get_port_connect(self):
        try:
            if self.rfsocket.port <= 0:
                self.rfsocket = self.device.createRfcommSocket(1) #set the port explicitly
                if not self.rfsocket.connected:
                    self.rfsocket.connect()
            else:
                if not self.rfsocket.connected:
                    self.rfsocket.connect()
            if self.rfsocket.connected:
                self.ids.bluet_info.text = '[b]Connected[/b]'
            return True
        except jnius.jnius.JavaException as e:
            self.ids.bluet_info.text = '[b]Cannot connect to socket[/b]'
    def GetBSerial(self):
        try:
            getDevname = self.the.config.get('bluetoothsettings', 'stringbluetdevname')
            self.recv_stream, self.send_stream = self.get_socket_stream(getDevname)
        except jnius.jnius.JavaException as e:
            self.ids.bluet_info.text = '[b]Not Connected[/b]'

I used the readLine() method, but to use the read() method, there are two ways to build a string. Either externally (I only tried this one) or in an Array.
Import:

CharBuilder = autoclass('java.lang.Character')

Externally:

if self.recv_stream.ready() != None:
    r = self.recv_stream.read()
    theChar = CharBuilder.toChars(r) #gives a tuple of which the first element is a character
    self.read += theChar[0]

You have to play around with building your string to know where the string must start.

The first thing about the write() method is it takes a bytes object. So you build a bytearray() and use it as an argument. Example using ESC/POS printer initialise command and a string:

i = [27,64] #ASCII escape integer and at sign integer
pre = bytearray(i)
cmd = 'Hello You\n'.encode('UTF-8')
#extend bytearray
pre.extend(cmd)
self.send_stream.write(pre)
self.send_stream.flush()

Could not figure out how to create a bytearray integer and string in one go, yet.



来源:https://stackoverflow.com/questions/58477961/how-to-use-the-pyjnius-read-and-write-arguments-for-bluetooth-getinputstream-and

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!