简体   繁体   English

蓝牙getInputStream和getOutputStream如何使用pyjnius读写arguments?

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

I have been fumbling with getting data from a bluetooth RS232 converter using the python for android jnius library.我一直在摸索使用 android jnius 库的 python 从蓝牙 RS232 转换器获取数据。 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.我原以为它会像 PySerial 库一样简单,但由于我还是 java 的新手,因此实现完全不同。
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' .我很容易地创建了蓝牙连接,但是当我尝试读取或写入数据时,我得到一个jnius.jnius.JavaException No methods matching your arguments,并且可供read的方法是: '()I', '([B)I', '([BII)I'write'(I)V', '([B)V', '([BII)V' I tried finding this in the developer android docs as well as DuckDuckGoing it but with no clarity.我尝试在开发人员 android 文档以及 DuckDuckGoing 中找到它,但不清楚。
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 . 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?有人可以将我指向文档以了解上述读写 arguments 吗?
Also, please help me to understand why the read, readLine() and write objects does not return any data?另外,请帮助我理解为什么read, readLine() and write对象不返回任何数据?

Java libraries I call:我调用的 Java 库:

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):连接代码(从 Github 及以上链接获得):

    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.所以我终于使用readLine()方法得到了输入,不返回错误,也返回字符串。 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.主要的事情是我检查了device != Noneif rfsocket.connected:在我的事件循环中创建 getInputStream 之前,以免重新创建套接字 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.还是不知道write read The readLine() method returns the string intermitantly or not at all and my eventloop seems to not work with the readLine() method. readLine()方法间歇地返回字符串或根本不返回字符串,我的事件循环似乎不适用于readLine()方法。

Update on update:更新更新:

The event loop works again.事件循环再次工作。 My bad, I did not call the trigger object correctly.我的错,我没有正确调用触发器 object。 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. 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 预期字符串或空字符串的片段。 I had similar string bits and pieces returned when I received the data via a hardline using PySerial.当我使用 PySerial 通过硬线接收数据时,我返回了类似的字符串位和片段。 The solution was resetting the input buffer.解决方案是重置输入缓冲区。 Is there something similar in the above java libraries?上面的 java 库中是否有类似的东西?

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.我尝试了BufferedInputStream库并得到了相同的结果,没有更多的间歇性读取。 Why?为什么? So I re-Apk'd the main file of last night and boom intermittant Input read once again.所以我重新 Apk'd 昨晚的main文件并再次读取间歇输入。
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 .原因是如果我在rfsocket蓝牙 object 未连接到指定端口时创建 java 对象, Null对象未在其他端口上初始化,并且由于某些原因未if self.recv_stream is not None上初始化对象self.recv_stream != None Probably because they are not Null objects but Null for the subsequent port 1 socket connection I specified.可能是因为它们不是Null对象,而是我指定的后续端口 1 套接字连接的Null
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 . readline()与我的示例一样工作, read()需要三个 arguments bytes(), int offset, int len(bytes()jnius.jnius.exception hieroglyphics 的消息中不清楚。仍在弄清楚write方法。您可以在BufferedReader方法中指定的一件事是您要读取的块大小的第二个参数,或者在 java 中使用defaultCharBufferSize

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 .要连接到蓝牙,我按照android 开发人员网站上的建议,在GitHub 示例上构建。 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.在创建getOutputStreamgetInputStream java 对象之前,我必须明确设置自己的套接字,否则连接和对象的端口将不同。 You only need to call the GetBSerial() to connect您只需要调用GetBSerial()即可连接

    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.我使用了readLine()方法,但是要使用read()方法,有两种方法可以构建字符串。 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.关于write()方法的第一件事是它需要一个字节 object。 So you build a bytearray() and use it as an argument.因此,您构建了一个bytearray()并将其用作参数。 Example using ESC/POS printer initialise command and a string:使用 ESC/POS 打印机初始化命令和字符串的示例:

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.无法弄清楚如何在一个 go 中创建一个字节数组 integer 和字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM