socket receive and send are very slow over TCP - android

kernel_recvmsg with option MSG_WAITALL is taking long time to receive data. even tried default option with flag 0. Overall throughput is affected with kernel_recvmsg. TCP_NODELAY socket option also set. tried to change all kinds of recv and send buffer options, between client and server but overall throughput is not getting changed.
server: windows 10 PC
client: Android 7.1 linux version 4.4.63
testing in 5 ghz network...
Is there any options left over to try.
timers below added shows that more time is consumed in kernel_recvmsg. even perf tool calls shows more time is consumed in kenrel_recvmsg.
t_usb.rx_rcv_start = ktime_get();
while (total_rcvd < length && total_rcvd >= 0 &&
!kthread_should_stop()) {
kvec.iov_base = tcp_recv_buf+data_rcvd;
kvec.iov_len = length-data_rcvd;
data_rcvd = kernel_recvmsg(tcp_socket->socket, msg, &kvec,
1, length - total_rcvd, MSG_WAITALL);
if (data_rcvd > 0) {
total_rcvd += data_rcvd;
} else {
vfree(tcp_recv_buf);
return data_rcvd;
}
}
t_usb.rx_start = t_usb.rx_rcv_end=ktime_get();

Related

How to transfer images via Bluetooth (LE) to a desktop application

We are currently trying to implement the transmission of images from a mobile device (in this case an IPhone) to a desktop application. We tried already the Bluetooth Serial plugin which works fine for Android but does not list any devices when scanning for our desktop application.
To cover iOS support (AFAIK iOS only supports BluetoothLE), we reimplemented our desktop application to use BluetoothLE and behave like a peripheral. Also we altered our Ionic application to use BLE plugin.
Now BluetoothLE only supports the transmission of packages with the size of 20 Byte whilst our image is about 500kb big. So we could obviously split our image into chunks and transmit it with the following function (taken from this gist):
function writeLargeData(buffer) {
console.log('writeLargeData', buffer.byteLength, 'bytes in',MAX_DATA_SEND_SIZE, 'byte chunks.');
var chunkCount = Math.ceil(buffer.byteLength / MAX_DATA_SEND_SIZE);
var chunkTotal = chunkCount;
var index = 0;
var startTime = new Date();
var transferComplete = function () {
console.log("Transfer Complete");
}
var sendChunk = function () {
if (!chunkCount) {
transferComplete();
return; // so we don't send an empty buffer
}
console.log('Sending data chunk', chunkCount + '.');
var chunk = buffer.slice(index, index + MAX_DATA_SEND_SIZE);
index += MAX_DATA_SEND_SIZE;
chunkCount--;
ble.write(
device_id,
service_uuid,
characteristic_uuid,
chunk,
sendChunk, // success callback - call sendChunk() (recursive)
function(reason) { // error callback
console.log('Write failed ' + reason);
}
)
}
// send the first chunk
sendChunk();
}
Still this would mean for us that we would have to launch about 25k transmissions which I assume will take a long time to complete. Now I wonder why is that the data transmission via Bluetooth is that handicapped.
If you want to try out L2CAP your could modify your Central desktop app somehow like this:
private let characteristicUUID = CBUUID(string: CBUUIDL2CAPPSMCharacteristicString)
...
Then advertize and publish a L2CAP channel:
let service = CBMutableService(type: peripheralUUID, primary: true)
let properties: CBCharacteristicProperties = [.read, .indicate]
let permissions: CBAttributePermissions = [.readable]
let characteristic = CBMutableCharacteristic(type: characteristicUUID, properties: properties, value: nil, permissions: permissions)
self.characteristic = characteristic
service.characteristics = [characteristic]
self.manager.add(service)
self.manager.publishL2CAPChannel(withEncryption: false)
let data = [CBAdvertisementDataLocalNameKey : "Peripherial-42", CBAdvertisementDataServiceUUIDsKey: [peripheralUUID]] as [String : Any]
self.manager.startAdvertising(data)
In your
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
respective your
func peripheralManager(_ peripheral: CBPeripheralManager, didPublishL2CAPChannel PSM: CBL2CAPPSM, error: Error?) {
offer the PSM value (= kind of socket handle (UInt16), for Bluetooth stream connections):
let data = withUnsafeBytes(of: PSM) { Data($0) }
if let characteristic = self.characteristic {
characteristic.value = data
self.manager.updateValue(data, for: characteristic, onSubscribedCentrals: self.subscribedCentrals)
}
finally in
func peripheralManager(_ peripheral: CBPeripheralManager, didOpen channel: CBL2CAPChannel?, error: Error?)
open an input stream:
channel.inputStream.delegate = self
channel.inputStream.schedule(in: RunLoop.current, forMode: .default)
channel.inputStream.open()
where the delegate could look something like this:
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.hasBytesAvailable:
if let stream = aStream as? InputStream {
...
//buffer is some UnsafeMutablePointer<UInt8>
let read = stream.read(buffer, maxLength: capacity)
print("\(read) bytes read")
}
case ...
}
iOS app with Central Role
Assuming you have something like that in your iOS code:
func sendImage(imageData: Data) {
self.manager = CBCentralManager(delegate: self, queue: nil)
self.imageData = imageData
self.bytesToWrite = imageData.count
NSLog("start")
}
then you can modify your peripheral on your iOS client to work with the L2Cap channel like this:
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
...
if let characteristicValue = characteristic.value {
let psm = characteristicValue.withUnsafeBytes {
$0.load(as: UInt16.self)
}
print("using psm \(psm) for l2cap channel!")
peripheral.openL2CAPChannel(psm)
}
}
and as soon as you are notified of the opened channel, open the output stream on it:
func peripheral(_ peripheral: CBPeripheral, didOpen channel: CBL2CAPChannel?, error: Error?)
...
channel.outputStream.delegate = self.streamDelegate
channel.outputStream.schedule(in: RunLoop.current, forMode: .default)
channel.outputStream.open()
Your supplied stream delegate might look like this:
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
switch eventCode {
case Stream.Event.hasSpaceAvailable:
if let stream = aStream as? OutputStream, let imageData = self.imageData {
if self.bytesToWrite > 0 {
let bytesWritten = imageData.withUnsafeBytes {
stream.write(
$0.advanced(by: totalBytes),
maxLength: self.bytesToWrite
)
}
self.bytesToWrite -= bytesWritten
self.totalBytes += bytesWritten
print("\(bytesWritten) bytes written, \(bytesToWrite) remain")
} else {
NSLog("finished")
}
}
case ...
There is a cool WWDC video from 2017, What's New in Core Bluetooth, see here https://developer.apple.com/videos/play/wwdc2017/712/
At around 14:45 it starts to discuss how L2Cap channels are working.
At 28:47, the Get the Most out of Core Bluetooth topic starts, in which performance-related things are discussed in detail. That's probably exactly what you're interested in.
Finally, at 37:59 you will see various possible throughputs in kbps.
Based on the data shown on the slide, the maximum possible speed with L2CAP + EDL (Extended Data Length) + 15ms interval is 394 kbps.
Please have a look at this comment
The following snippet is taken from there
ble.requestMtu(yourDeviceId, 512, () => {
console.log('MTU Size ok.');
}, error => {
console.log('MTU Size failed.');
});
It is suggesting that you need to request the Mtu after connection and then I think you can break your message into chunks of 512 bytes rather than 20 bytes.
They have done this for android specific issue
First I should say that there are already tons of blog posts and Q&As on the exact same topic, so please read them first.
If you run iPhone 7, you have the LE Data Length Extension. The default MTU is also 185 bytes, which means you can send notifications or write without response commands with 182 bytes of payload. And please make sure you absolutely not use Write With Response or Indications since that will almost stall the transfer. When you run iOS in central mode you are restricted to 30 ms connection interval. Using a shorter connection interval can have benefits, so I would suggest you to run iOS in peripheral mode instead so you from the central side can set a connection interval of something short, say 12 ms. Since iPhone X and iPhone 8, you can also switch to the 2MBit/s PHY to get increased transfer speed. So to answer your actual question why BLE data transfer is handicapped: it's not, at least if you follow best practice.
You also haven't told anything about the system that runs your desktop application. If it supports 2 MBit/s PHY, LE Data Length Extension and a MTU of at least 185, then you should be happy and make sure your connections use all those features. If not, you should still get higher performance if you enable at least one of them.

RXBleConnection keep dropping after connection established (Status 19)

I'm developing an application to pair with two kind of sensors with the app and also these sensors are pairing with each other, we developed our custom bluetooth communication protocol. The connection is working great usually, but there are still some errors that I'm having hard time to fix it.
Sensor 1 paring alone is working great, but every time I'm pairing both of them, then i close the app, pair it again with first sensor, I got disconnected with status 19 just after the connection is established, after I try again one or two times the connection will be established properly. I was thinking that was a problem with Gatt refresh, but I already tried one solution found here and I keep reproducing this error every time.
fun connectToDevice(device: BraincareDevice, pairColor: Int) {
BleLogHelper.writeLog("Connecting to ${device.name}")
isConnecting = true
val deviceType = if (device is Sensor) DeviceType.SENSOR else DeviceType.DONGLE
if (deviceType == DeviceType.SENSOR) {
sensorConnectionSubscription?.dispose()
} else {
dongleConnectionSubscription?.dispose()
}
val connectionSubscription = device.device.establishConnection(false)
.flatMapSingle { connection ->
if (device is Sensor) {
sensorConnection = connection
connectedSensor = device
} else if (device is Dongle) {
dongleConnection = connection
connectedDongle = device
}
connection.queue(CustomRefresh())
?.observeOn(Schedulers.io())
?.doOnComplete{
BleLogHelper.writeLog("GATT REFRESHED")
}
?.subscribe ({
BleLogHelper.writeLog("GATT REFRESHED")
},{
BleLogHelper.writeLog("FAIL REFRESHING GATT")
})
BleLogHelper.writeLog("Send Request Connection Command $deviceType")
val command = BraincareBluetoothCommandProtocol.createRequestConnectionCommandFrame(deviceType)
connection.writeCharacteristic(BraincareBluetoothProtocol.rxCharacteristicUUID, command)
}
.delay(300, TimeUnit.MILLISECONDS)
.subscribe({
BleLogHelper.writeLog("Connection Established ${device.type}")
val iscon= this.isConnecting
startBlinkingDeviceLed(deviceType, pairColor)
connectionFlowListeners.forEach { it.onConnectionEstablished(device) }
}, {
BleLogHelper.writeError("Connection Lost ${device.type}", it)
BleLogHelper.writeError("Retrying...", it)
val iscon= this.isConnecting
if (isMonitoring || isConnecting || deviceType == DeviceType.DONGLE){
connectionStateListeners.forEach {
if (deviceType == DeviceType.SENSOR) {
sensorNotificationSubscription?.dispose()
sensorRssiSubscription?.dispose()
blinkingDeviceLedsSubscription?.dispose()
disconnectFromDevice(DeviceType.SENSOR)
} else {
dongleRssiSubscription?.dispose()
disconnectFromDevice(DeviceType.DONGLE)
}
isConnecting = false
it.onConnectionLost(device)
}
}else{
reconnectToDevice(device, pairColor)
}
})
if (deviceType == DeviceType.SENSOR) {
sensorConnectionSubscription = connectionSubscription
} else {
dongleConnectionSubscription = connectionSubscription
}
}
The exception is firing just after connection.writeCharacteristic(BraincareBluetoothProtocol.rxCharacteristicUUID, command)
Log error:
2019-05-21 10:54:11.816 11797-11889/io.b4c.brain4care.debug E/BLEBC: 21/05/2019 10:54:11.810 - Connection Lost SENSOR
com.polidea.rxandroidble2.exceptions.BleDisconnectedException: Disconnected from D4:57:4F:53:44:E7 with status 19 (UNKNOWN)
at com.polidea.rxandroidble2.internal.connection.RxBleGattCallback$2.onConnectionStateChange(RxBleGattCallback.java:77)
at android.bluetooth.BluetoothGatt$1$4.run(BluetoothGatt.java:268)
at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:789)
at android.bluetooth.BluetoothGatt.-wrap0(Unknown Source:0)
at android.bluetooth.BluetoothGatt$1.onClientConnectionState(BluetoothGatt.java:264)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:70)
at android.os.Binder.execTransact(Binder.java:682)
status=19 is GATT_CONN_TERMINATE_PEER_USER. This library since version 1.8.1 lists the reason properly. It is always advised to use the newest available version of basically any library as they bring improvements over time.
There is no clear question in the post. With the provided information it is not possible to tell more than the above — the peripheral you use disconnects from the app. Why this happens is up to your peripheral and you can possibly find an answer in the documentation.
Bear in mind that newer Android versions do not allow concurrent pairing procedures to more than one BLE device at a time. Pairing of two devices should be performed sequentially i.e.
Peripheral A starts pairing
Peripheral A finishes pairing
Peripheral B starts pairing
Peripheral B finishes pairing
Peripherals may be connected at the same time but only a single pairing procedure may be held at a time.

Receive data from arduino to android

i'm working for a project using arduino and android studio, I would like to control my arduino from my mobile application by sending 0 t of 1, then I would like to receive arduino data on my android application,it is an obstacle detector that sends warning when there is an obstacle, here is the code of the arduino, it works because I tested with an application that I downloaded from google play, now I do not know how to display the message sent by arduino on my mobile application, and also how control the arduino from my app.
int echo = 3;
int trig = 2;
int greenled=4;
int redled=5;
float timelapse;
float distance;
char state=' ';
void setup() {
pinMode(greenled, OUTPUT);
pinMode(redled, OUTPUT);
pinMode(trig,OUTPUT);
pinMode(echo,INPUT);
digitalWrite(trig,LOW);
digitalWrite(greenled,LOW);
digitalWrite(redled,LOW);
Serial.begin(9600);
}
void loop() {
if (Serial.available()>0){
digitalWrite(trig,HIGH);
delayMicroseconds(10);
digitalWrite(trig,LOW);
timelapse=pulseIn(echo,HIGH);
distance = timelapse/58 ;
// if (distance > 200 || distance< 0 ) { Serial.println ( "Out of range"); }
if ( distance < 100 ) {
digitalWrite(redled, HIGH);
digitalWrite(greenled,LOW);
Serial.println("Attention");
delay(150);
}
else {
digitalWrite(redled,LOW);
digitalWrite(greenled,HIGH);
Serial.println("Libre");
}
delay(50);
}
else {
digitalWrite(redled,LOW);
digitalWrite(greenled,LOW);
digitalWrite(trig,LOW);
}
}
You didn't specify anything about how you're connecting your Arduino with your mobile phone. There are multiple ways to connect them together.
My wild guess here is that you're using a wired connection, as I see no code related to Bluetooth or any other communication.
If you're using OTG wired connection then, this would help.
Incase you want to do it wirelessly, you can read and write using serial port to a PC/Pi and then use a python script to upload the data to a cloud like firebase, and then read and data in your Android app from firebase. This is just one suggestion, there are many.

AT Commands doesn't work :: WinSock Bluetooth Connection

I'm creating windows application in C++, which connect's PC with mobile via bluetooth and winsock. Allow's you to call and send messages from mobile via computer.
I'm using AT command's to tell mobile what i want to do. Pair with mobile device and force a call with At command
ATD+420******;
works perfect, but all commands for handling SMS like
AT+CMGL, AT+CMGF, AT+CMGS etc.
phone probably doesnt recognize them and returns ERROR.
Here is code which connects PC with mobile via bluetooth and socket:
SOCKADDR_BTH RemoteEndPoint;
RemoteEndPoint.port = 0;
RemoteEndPoint.addressFamily = AF_BTH;
RemoteEndPoint.btAddr = m_foundDevices[m_deviceIndex].Address.ullLong;
RemoteEndPoint.serviceClassId = HandsfreeServiceClass_UUID;
int BTHAddrLength = sizeof(RemoteEndPoint);
// Create the socket.
if ((m_localSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM)) == INVALID_SOCKET)
{
// handle error.
}
// Connect the socket.
if ((iResult = connect(m_localSocket, (SOCKADDR *)&RemoteEndPoint, sizeof(RemoteEndPoint))) == INVALID_SOCKET)
{
// handle error.
}
Notice line
RemoteEndPoint.serviceClassId = HandsfreeServiceClass_UUID
I think the problem is here, becouse u cant send sms from Handsfree, but when i use another UUID, it doesnt even pair with mobile.
=== Here is just for info, how am i sending and receiving data from mobile ===
char recvbuf[DEFAULT_BUFLEN] = "";
const char *sendbuf = "AT+CMGL\r";
int len = (int)strlen(sendbuf);
if ((iResult = send(m_localSocket, sendbuf, len, MSG_OOB)) == SOCKET_ERROR)
{
// handle error. return ~0
}
if ((iResult = recv(m_localSocket, recvbuf, recvbuflen, 0)) == SOCKET_ERROR)
{
// handle error. return ~0
}
// Here recvbuf == "\r\nERROR\r\n"
-- I would like to find out the problem, why AT command's for SMS doesnt work.
Thank you for any advices!
If you have any question's about problem, i'll kindly explain.
Regards,
Filip.
EDIT
I found out answer "If you want to send SMS Messages, a Server Socket will be needed on the GSM Device", but after hours of googling i have no clue how to do that. Any suggestion's? Thank you.

How should GATT_CMD_STARTED (status=134) be interpreted?

I'm working on an android app where I need to communicate with a bluetooth LE device and in the middle of the communication I receive a callback:
onCharacteristicWrite()
...which is expected. But the status of the operation is 134 instead of 0 (=success).
This GATT status constant is not defined in the official API but here is a translation in one of many unofficial lists:
public static final int GATT_CMD_STARTED = 134;
See: https://code.google.com/r/naranjomanuel-opensource-broadcom-ble/source/browse/framework/java/src/com/broadcom/bt/service/gatt/GattConstants.java?r=983950f9b35407446bf082633d70c7655c206d22
The consequence, that I can see, in my app is that I do not get an expected callback to:
onCharacteristicChanged()
Does anybody know what GATT_CMD_STARTED means? Is it an error?
The description of the following function taken from the bludroid sources hint that something is not working correctly in your GATT server.
Commands seem to "queue up" there, as there must be pending requests or value confirmations as hinted in the comment before the if(...) clause.
It might be worth checking what exactly is going on before you do the writeCharacteristic(...) as it seems to not finish correctly or create hiccups in your server.
/*******************************************************************************
**
** Function attp_cl_send_cmd
**
** Description Send a ATT command or enqueue it.
**
** Returns GATT_SUCCESS if command sent
** GATT_CONGESTED if command sent but channel congested
** GATT_CMD_STARTED if command queue up in GATT
** GATT_ERROR if command sending failure
**
*******************************************************************************/
tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
{
tGATT_STATUS att_ret = GATT_SUCCESS;
if (p_tcb != NULL)
{
cmd_code &= ~GATT_AUTH_SIGN_MASK;
/* no pending request or value confirmation */
if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
cmd_code == GATT_HANDLE_VALUE_CONF)
{
att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
{
/* do not enq cmd if handle value confirmation or set request */
if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
{
gatt_start_rsp_timer (clcb_idx);
gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
}
}
else
att_ret = GATT_INTERNAL_ERROR;
}
else
{
att_ret = GATT_CMD_STARTED;
gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
}
}
else
att_ret = GATT_ERROR;
return att_ret;
}
Starts at line 469 in android sources.
The native GATT error and statuscodes can be found here.

Categories

Resources