Skip to content
Snippets Groups Projects
Commit b0a6ec2b authored by Anon's avatar Anon
Browse files

WIP

parent a68b812c
No related branches found
No related tags found
No related merge requests found
......@@ -18,6 +18,7 @@
</activity>
<activity android:name=".ScanActivity" />
<activity android:name=".SendActivity" />
</application>
<uses-permission android:name="android.permission.BLUETOOTH"/>
......
......@@ -2,15 +2,22 @@ package com.github.antweb.donkey
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.os.Environment
import android.util.Log
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.nio.ByteBuffer
import java.util.*
import java.util.zip.CRC32
private const val TAG = "FileTransfer"
class FileTransfer(
private val gatt: BluetoothGatt,
private val dataCharacteristic: BluetoothGattCharacteristic,
private val tx: BluetoothGattCharacteristic,
private val rx: BluetoothGattCharacteristic,
private val mtu: Int
) {
private val filePath = "/Download/SEND.txt"
......@@ -18,6 +25,9 @@ class FileTransfer(
private val iterator = openFile().iterator()
private var offset: Int = 0
private var lastCrc: Long = 0
private fun openFile(): ByteArray {
// TODO: Don't listen to Android Docs, use stuff that is not deprecated
val file = File(
......@@ -40,16 +50,15 @@ class FileTransfer(
}
fun sendNext() {
Log.d(TAG, "Sending next chunk: $offset")
if (!iterator.hasNext()) {
return
}
gatt?.beginReliableWrite()
val chunk = mutableListOf<Byte>()
for (i in 0 until (mtu - 5)) {
// for (i in 0 until (mtu - 5)) {
for (i in 0 until (10)) {
chunk.add(iterator.next())
}
......@@ -61,12 +70,18 @@ class FileTransfer(
val sendBuffer = ByteBuffer.allocate(chunk.size + 4)
sendBuffer.putInt(header)
sendBuffer.put(chunk.toByteArray())
val bytes = sendBuffer.array()
val crc = CRC32()
crc.update(bytes)
lastCrc = crc.value
dataCharacteristic?.value = sendBuffer.array()
gatt?.writeCharacteristic(dataCharacteristic)
// gatt?.beginReliableWrite()
tx?.value = bytes
val status = gatt?.writeCharacteristic(tx)
// This will trigger the onCharacteristicWrite callback once the other side ACKs
// In there, we can call the actual gatt?.executeReliableWrite()
if (!status) {
Log.d(TAG, "Write status: $status")
}
}
}
\ No newline at end of file
......@@ -15,22 +15,6 @@ private const val TAG = "MainActivity"
class MainActivity : AppCompatActivity() {
private val targetDeviceName = "card10"
private val mtu = 128
private val serviceUuid = "00422342-2342-2342-2342-234223422342"
private val dataCharacteristicUuid = "01422342-2342-2342-2342-234223422342"
private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
private var bluetoothGatt: BluetoothGatt? = null
private var fileService: BluetoothGattService? = null
private var dataCharacteristic: BluetoothGattCharacteristic? = null
private var mGatt: BluetoothGatt? = null
private var fileTransferService: FileTransfer? = null
private var mScanning: Boolean = false
private var connected = false
......@@ -55,102 +39,4 @@ class MainActivity : AppCompatActivity() {
startActivity(intent)
}
}
private fun scanLeDevice() {
val gattCallback = object : BluetoothGattCallback() {
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
super.onServicesDiscovered(gatt, status)
if (gatt == null) {
throw NullPointerException()
}
for (service in gatt.services) {
Log.d(TAG, "Found service: ${service.uuid}")
if (service.uuid.toString() == serviceUuid) {
fileService = service
}
for (characteristic in service.characteristics) {
Log.d(TAG, "Characteristic: ${characteristic.uuid}")
if (characteristic.uuid.toString() == dataCharacteristicUuid) {
dataCharacteristic = characteristic
}
}
}
if (fileService == null || dataCharacteristic == null) {
Log.e(TAG, "Could not find file transfer service")
return
}
gatt.requestMtu(mtu)
}
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
super.onConnectionStateChange(gatt, status, newState)
when (newState) {
BluetoothGatt.STATE_CONNECTED -> {
runOnUiThread {
tvConnection.text = "STATE_CONNECTED"
}
mGatt = gatt
gatt?.discoverServices()
}
BluetoothGatt.STATE_DISCONNECTED -> tvConnection.text = "STATE_DISCONNECTED"
BluetoothGatt.STATE_CONNECTING -> tvConnection.text = "STATE_CONNECTING"
BluetoothGatt.STATE_DISCONNECTING -> tvConnection.text = "STATE_DISCONNECTING"
}
}
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
Log.d(TAG, "MTU changed to: $mtu")
runOnUiThread {
tvValue.text = "MTU: $mtu"
}
val lData = dataCharacteristic
if (gatt != null && lData != null) {
fileTransferService = FileTransfer(gatt, lData, mtu)
fileTransferService?.sendFile()
}
}
override fun onReliableWriteCompleted(gatt: BluetoothGatt?, status: Int) {
// Last chunk sent successfully. Send next chunk
fileTransferService?.sendNext()
}
override fun onCharacteristicWrite(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?,
status: Int
) {
gatt?.executeReliableWrite()
}
}
val leScanCallback = BluetoothAdapter.LeScanCallback { device, _, _ ->
if (device.name == targetDeviceName) {
if (!connected) {
connected = true
bluetoothGatt = device.connectGatt(this, true, gattCallback, BluetoothDevice.TRANSPORT_LE)
}
}
}
// Stops scanning after a pre-defined period
Handler().postDelayed({
mScanning = false
bluetoothAdapter?.stopLeScan(leScanCallback)
}, 5000)
mScanning = true
bluetoothAdapter?.startLeScan(leScanCallback)
}
}
......@@ -14,6 +14,11 @@ private const val TAG = "ScanActivity"
class ScanActivity : AppCompatActivity() {
// HACK: Figure out how to transfer this later
companion object {
var selectedDevice: BluetoothDevice? = null
}
private lateinit var listView: ListView
private lateinit var listAdapter: DeviceListAdapter
......@@ -32,6 +37,16 @@ class ScanActivity : AppCompatActivity() {
listAdapter = DeviceListAdapter(applicationContext)
listView.adapter = listAdapter
listView.setOnItemClickListener { adapterView, view, i, l ->
val item = adapterView.adapter.getItem(i) as? BluetoothDevice
if (item != null) {
selectedDevice = item
val intent = Intent(this, SendActivity::class.java)
startActivity(intent)
}
}
checkPermissions()
scan()
}
......@@ -47,13 +62,6 @@ class ScanActivity : AppCompatActivity() {
val foundDevices = mutableSetOf<BluetoothDevice>()
val leScanCallback = BluetoothAdapter.LeScanCallback { device, _, _ ->
// if (device.name == targetDeviceName) {
// if (!connected) {
// connected = true
// bluetoothGatt = device.connectGatt(this, true, gattCallback, BluetoothDevice.TRANSPORT_LE)
// }
// }
if (!foundDevices.contains(device)) {
foundDevices.add(device)
listAdapter.add(device)
......
package com.github.antweb.donkey
import android.bluetooth.*
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import java.lang.NullPointerException
import java.util.*
private const val TAG = "SendActivity"
class SendActivity : AppCompatActivity() {
private val mtu = 128
private val serviceUuid = "00422342-2342-2342-2342-234223422342"
private val centralTxCharacteristicUuid = UUID.fromString("01422342-2342-2342-2342-234223422342")
// private var centralTxCharacteristic: BluetoothGattCharacteristic? = null
private val centralRxCharacteristicUuid = UUID.fromString("02422342-2342-2342-2342-234223422342")
// private var centralRxCharacteristic: BluetoothGattCharacteristic? = null
private val clientConfigUuid = "00002902-0000-1000-8000-00805f9b34fb"
private var bluetoothGatt: BluetoothGatt? = null
private var fileService: BluetoothGattService? = null
private var mGatt: BluetoothGatt? = null
private var fileTransferService: FileTransfer? = null
private lateinit var tvConnection: TextView
private lateinit var tvValue: TextView
private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
bluetoothManager.adapter
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_send)
tvValue = findViewById(R.id.text_value)
tvConnection = findViewById(R.id.text_connection_status)
tvConnection.text = "STATE_DISCONNECTED"
val device = ScanActivity.selectedDevice
if (device != null) {
connect(device)
} else {
Log.e(TAG, "Device is NULL!")
}
}
fun connect(device: BluetoothDevice) {
val gattCallback = object : BluetoothGattCallback() {
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
super.onServicesDiscovered(gatt, status)
if (gatt == null) {
throw NullPointerException()
}
for (service in gatt.services) {
Log.d(TAG, "Found service: ${service.uuid}")
if (service.uuid.toString() == serviceUuid) {
fileService = service
}
// for (characteristic in service.characteristics) {
// Log.d(TAG, "Characteristic: ${characteristic.uuid}")
//
// if (characteristic.uuid.toString() == centralTxCharacteristicUuid) {
// centralTxCharacteristic = characteristic
// } else if (characteristic.uuid.toString() == centralRxCharacteristicUuid) {
// centralRxCharacteristic = characteristic
// }
// }
}
if (fileService == null) {
// if (fileService == null || centralTxCharacteristic == null) {
Log.e(TAG, "Could not find file transfer service")
return
}
gatt.requestMtu(mtu)
}
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
super.onConnectionStateChange(gatt, status, newState)
when (newState) {
BluetoothGatt.STATE_CONNECTED -> {
runOnUiThread {
tvConnection.text = "STATE_CONNECTED"
}
mGatt = gatt
gatt?.discoverServices()
}
BluetoothGatt.STATE_DISCONNECTED -> tvConnection.text = "STATE_DISCONNECTED"
BluetoothGatt.STATE_CONNECTING -> tvConnection.text = "STATE_CONNECTING"
BluetoothGatt.STATE_DISCONNECTING -> tvConnection.text = "STATE_DISCONNECTING"
}
}
override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?) {
super.onCharacteristicChanged(gatt, characteristic)
}
override fun onCharacteristicRead(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?,
status: Int
) {
super.onCharacteristicRead(gatt, characteristic, status)
}
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
Log.d(TAG, "MTU changed to: $mtu")
runOnUiThread {
tvValue.text = "MTU: $mtu"
}
val tx = fileService?.getCharacteristic(centralTxCharacteristicUuid)
val rx = fileService?.getCharacteristic(centralRxCharacteristicUuid)
if (gatt != null && tx != null && rx != null) {
val descriptor = rx.getDescriptor(UUID.fromString(clientConfigUuid))
if (descriptor != null) {
gatt.setCharacteristicNotification(rx, true)
descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
val success = gatt.writeDescriptor(descriptor)
if (!success) {
Log.e(TAG, "Descriptor write failed")
}
} else {
Log.e(TAG, "Failed to write descriptor")
}
fileTransferService = FileTransfer(gatt, tx, rx, mtu)
fileTransferService?.sendFile()
}
}
override fun onReliableWriteCompleted(gatt: BluetoothGatt?, status: Int) {
// Last chunk sent successfully. Send next chunk
// fileTransferService?.sendNext()
}
override fun onCharacteristicWrite(
gatt: BluetoothGatt?,
characteristic: BluetoothGattCharacteristic?,
status: Int
) {
// gatt?.executeReliableWrite()
Thread.sleep(3000)
fileTransferService?.sendNext()
return
}
}
bluetoothGatt = device.connectGatt(this, true, gattCallback, BluetoothDevice.TRANSPORT_LE)
}
}
\ No newline at end of file
......@@ -4,4 +4,14 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text_connection_status"
/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text_value"
/>
</LinearLayout>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment