我在外围设备上使用两个 ATT 特性实现了双工 BLE 通信(本质上,类似于串行 TX/RX 电缆)——一个是可写的,另一个是可读的,带有通知。除了报告的写入速度外,一切都按预期工作。
当我调用下面的代码时:
txCharacteristic.setValue(data);
boolean queuedOk =
connectedPeripheralGatt.writeCharacteristic(txCharacteristic);
onCharacteristicWrite 回调几乎立即被触发,然后我重复上面的代码 fragment 以在特性上应用下一个数据 fragment 。当接收方报告正确的速度(大约 10 KB/s)时,根据 onCharacteristicWriteRequest 中收集的时间戳测量,发送方报告令人难以置信的速度(如 50 - 300 KB/s)并且它报告它已完成将所有数据推送到 writeCharacteristic,尽管接收方仍在接收传入数据。
因此,显然 onCharacteristicWriteRequest 正在被调用,而大部分数据仍在发送到目标设备的途中。
当我将数据从外围设备发送到中央设备时,同样的事情发生了,只是这次 onNotificationSent 在外围设备上是关于它的速度和 onCharacteristicChanged 在中央正在报告正确的速度。
是否有任何或多或少可靠的方法来近似测量来自发送方的传出数据速率而不打开 ACK(出于性能原因我不想这样做)?
数据本身完好无损,我正在使用 0.5 - 5 兆字节大小的图像文件对其进行测试,并且图像始终在接收端正确解码。
为了最大化吞吐量,可写特性被设置为不可靠的,如下所示:
BluetoothGattCharacteristic rxCharacteristic = new BluetoothGattCharacteristic(UUID.fromString(RX_CHARACTERISTIC_UUID),
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,
BluetoothGattCharacteristic.PERMISSION_WRITE);
rxCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
我不确定我对 PROPERTY_WRITE_NO_RESPONSE 和 WRITE_TYPE_NO_RESPONSE 的使用,但从某些网站上的一些文章来看,模糊地似乎同时指定两者是一个好习惯;如果我错了,请纠正我。
我明白,通过这样的设置,我不能指望接收方对数据进行真正的确认,但我仍然希望 onCharacteristicWrite 和 onNotificationSent 本身至少会提供真实的数据定时检测数据何时实际从源设备发送出去。相反,似乎有一个相当大的缓存消耗我的数据并报告它几乎立即发送。
最佳答案
你是对的。
如果您使用“write with response”,则在远程发回写响应后将调用 onCharacteristicWrite 回调。但是,如果您使用“write without response”,Android 有一个流量控制机制可以缓冲您写入的数据。它是这样工作的:
应用写入数据包。蓝牙堆栈将此数据包放入其内部缓冲区。如果将此数据包入队后缓冲区中仍有更多空间,则会调用 onCharacteristicWrite 回调,因此您可以立即写入另一个数据包。当缓冲区已满时,它会等待调用 onCharacteristicWrite 回调,直到缓冲区中现在有 50% 的可用空间(如果我没记错的话)。
只要内部缓冲区中有数据包,它就会尝试将它们写入蓝牙 Controller ,蓝牙 Controller 也可以缓冲有限数量的数据包。蓝牙 Controller 通过 HCI 将“完成的数据包数”事件发送回 Android 的蓝牙堆栈,这表明远程设备的链路层已确认数据包。 (这并不表示远程应用程序没有收到它;只是远程蓝牙 Controller 收到了它。)如果蓝牙 Controller 中没有可用空间,它将等待直到有空间。
这比它在 iOS 上的工作方式要聪明得多。在那里,如果您发送大量“write with response”数据包,如果内部缓冲区已满,它们甚至会在发送之前被丢弃。 (这可以通过每 10 个数据包左右发送“write with response”来解决)。
不幸的是(对于您的情况),当数据包已被远程链路层确认时,Android 的蓝牙堆栈不会向应用程序发送回调,因此您必须根据 onCharacteristicWrite 回调来确定速度。但是,您可以每隔 10 个数据包左右向另一个方向发送一次状态通知,我认为这会给您带来良好的效果。如果 Android 的蓝牙堆栈在收到链路层确认时转而发送 onCharacteristicWrite 回调,这会将速度降低到每个连接事件仅一个数据包。
如果链接有时由于监督超时而断开连接,您应该知道我前段时间发布的错误报告:https://issuetracker.google.com/issues/37121017 .
关于您的属性/权限问题,这可能是同一件事,但蓝牙团队决定将它们分开。权限与 ATT 协议(protocol)有关,告诉蓝牙堆栈允许客户端做什么。属性只是对方可以读取的一些属性,以便知道它是什么类型的特征。
关于android - onCharacteristicWrite 和 onNotificationSent 被调用得太快 - 如何获取实际传出数据速率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43741849/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为