【问题标题】:How to use the pyjnius read and write arguments for Bluetooth getInputStream and getOutputStream?如何使用蓝牙 getInputStream 和 getOutputStream 的 pyjnius 读写参数?
【发布时间】:2020-02-17 01:13:29
【问题描述】:

我一直在摸索使用 python for android jnius 库从蓝牙 RS232 转换器获取数据。我原以为它会像 PySerial 库一样简单,但由于我还是 java 新手,所以实现是完全不同的。
我很容易地创建了蓝牙连接,但是当我尝试读取或写入数据时,我得到一个 jnius.jnius.JavaException 那个 No methods matching your arguments, 并且可用于 read 的方法是:'()I', '([B)I', '([BII)I' 和 @987654326 @是'(I)V', '([B)V', '([BII)V'。我尝试在开发人员 android 文档以及 DuckDuckGoing 中找到它,但不清楚。
我还使用readLine() 方法尝试了BufferedReader 示例(Here),但我不断收到错误消息:JavaException: JVM exception occurred: Attempt to invoke virtual method 'int java.io.InputStream.read(byte[], int, int)' on a null object reference

有人可以指点我的文档来理解上述读写参数吗?
另外,请帮助我理解为什么read, readLine() and write 对象不返回任何数据?

我调用的 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')

连接代码(从 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()

读写代码(来源:同上链接):

    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

更新:

所以我终于使用readLine() 方法得到了输入,既不返回错误又返回字符串。我清理了一下,但代码差别不大。主要的事情是我在我的事件循环中创建getInputStream之前检查了device != Noneif rfsocket.connected:,以免重新创建套接字对象。必须进行更多测试才能看到主要问题在哪里。仍然不知道readwrite 方法的参数是什么。 readLine() 方法间歇性地返回字符串或根本不返回字符串,我的事件循环似乎不适用于 readLine() 方法。

更新更新:

事件循环再次工作。我的错,我没有正确调用触发对象。 readLine() 方法有一个奇怪的模式,在第一次读取时它给了我JavaException: JVM exception occurred: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference,随后的读取给了我预期的字符串片段或空字符串。当我使用 PySerial 通过硬线接收数据时,我返回了类似的字符串位和片段。解决方案是重置输入缓冲区。上面的java库有没有类似的东西?

终于破解了异常:

是的,这很令人兴奋!几个小时后,我注意到我无法再获得输入,只有例外。我尝试了BufferedInputStream 库并得到了相同的结果,没有更多的间歇阅读。为什么?所以我重新 Apk'd 昨晚的main 文件并再次读取间歇输入。
原因是如果我在rfsocket 蓝牙对象未连接到指定端口时创建 java 对象,Null 对象在另一个端口上初始化,由于某种原因ifself.recv_stream is not None 看不到该对象和self.recv_stream != None。可能是因为它们不是Null 对象,而是Null 用于我指定的后续端口1 套接字连接。
readline() 与我的示例一样工作,read() 采用三个参数 bytes(), int offset, int len(bytes(),这在 jnius.jnius.exception 象形文字的消息中并不清楚。仍在研究write 方法。您可以在 BufferedReader 方法中指定的一件事是您要读取的块大小的第二个参数,或者在 java 中使用 defaultCharBufferSize

【问题讨论】:

    标签: java android python-3.x bluetooth pyjnius


    【解决方案1】:

    所以我发布了我的答案,因为我已经解决了所有问题。
    为了连接到蓝牙,我按照android developers site 上的建议在GitHub example 上构建。在创建getOutputStreamgetInputStream java 对象之前,我必须明确设置自己的套接字,否则连接和对象的端口将不一样。您只需拨打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]'
    

    我使用了readLine() 方法,但是要使用read() 方法,有两种方法可以构建字符串。在外部(我只尝试过这个)或阵列中。
    进口:

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

    对外:

    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]
    

    您必须尝试构建字符串才能知道字符串必须从哪里开始。

    write() 方法的第一件事是它需要一个字节对象。因此,您构建了一个 bytearray() 并将其用作参数。使用 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()
    

    还没有弄清楚如何一次性创建一个字节数组整数和字符串。

    【讨论】:

    • 您在上面所做的工作做得很好。我刚刚遇到了createRfcommSocket() 的问题,它给了JVM exception occurred: read failed, socket might closed or timeout, read ret: -1 你怎么能解决这个问题?需要一点见解。
    • 我创建了get_port_connect(self) 函数,如我的示例所示。它检查端口是否小于等于 0。如果 true 它将端口显式设置为 1。这是在创建 java stream 对象之前完成的。你试过了吗?
    • 感谢您的回复。我想我确实尝试过,但现在我发现因为我正在使用 BLE,并且我认为我必须使用适用于 Android 的 java GATT 接口。在点击此链接 tableauxmaths.fr/spip/spip.php?article156 后,我现在在 connectGatt() 遇到错误
    • 我还没有使用过BLE或GATT接口,只有蓝牙经典。抱歉不能给你更多信息。低能量的东西计划在 2022 赛季推出,同时转向 C(我希望)并远离 Java。
    • 好的!谢谢@Hmerman6006。希望一切顺利。
    猜你喜欢
    • 2014-04-29
    • 2011-06-22
    • 2020-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多