Skip to content

Commit ea6c0f8

Browse files
authoredMar 10, 2023
Merge pull request #372 from magnusja/develop
Release core v0.9.3 libusbcommunication v0.2.4
2 parents c25e643 + 2587e0a commit ea6c0f8

File tree

10 files changed

+110
-38
lines changed

10 files changed

+110
-38
lines changed
 

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ A library to access USB mass storage devices (pen drives, external HDDs, card re
1313
The library can be included into your project like this:
1414

1515
```ruby
16-
implementation 'me.jahnen.libaums:core:0.9.2'
16+
implementation 'me.jahnen.libaums:core:0.9.3'
1717
```
1818

1919
If you need the HTTP or the storage provider module:

‎libaums/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jacoco {
99

1010
ext {
1111
PUBLISH_GROUP_ID = 'me.jahnen.libaums'
12-
PUBLISH_VERSION = '0.9.2'
12+
PUBLISH_VERSION = '0.9.3'
1313
PUBLISH_ARTIFACT_ID = 'core'
1414
}
1515

‎libaums/src/main/java/me/jahnen/libaums/core/driver/scsi/ScsiBlockDevice.kt

+17-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import me.jahnen.libaums.core.driver.scsi.commands.sense.*
2525
import me.jahnen.libaums.core.usb.PipeException
2626
import me.jahnen.libaums.core.usb.UsbCommunication
2727
import java.io.IOException
28-
import java.lang.IllegalStateException
2928
import java.nio.ByteBuffer
3029
import java.util.*
3130

@@ -78,19 +77,25 @@ class ScsiBlockDevice(private val usbCommunication: UsbCommunication, private va
7877
*/
7978
@Throws(IOException::class)
8079
override fun init() {
80+
var lastException: Exception? = null
8181
for(i in 0..MAX_RECOVERY_ATTEMPTS) {
8282
try {
8383
initAttempt()
8484
return
85-
} catch(e: InitRequired) {
85+
} catch (e: InitRequired) {
8686
Log.i(TAG, e.message ?: "Reinitializing device")
87+
lastException = e
8788
} catch (e: NotReadyTryAgain) {
8889
Log.i(TAG, e.message ?: "Reinitializing device")
90+
lastException = e
8991
}
9092
Thread.sleep(100)
9193
}
9294

93-
throw IOException("MAX_RECOVERY_ATTEMPTS Exceeded while trying to init communication with USB device, please reattach device and try again")
95+
throw IOException(
96+
"MAX_RECOVERY_ATTEMPTS Exceeded while trying to init communication with USB device, please reattach device and try again",
97+
lastException
98+
)
9499
}
95100

96101
@Throws(IOException::class)
@@ -143,6 +148,7 @@ class ScsiBlockDevice(private val usbCommunication: UsbCommunication, private va
143148
*/
144149
@Throws(IOException::class)
145150
private fun transferCommand(command: CommandBlockWrapper, inBuffer: ByteBuffer) {
151+
var lastException: Exception? = null
146152
for(i in 0..MAX_RECOVERY_ATTEMPTS) {
147153
try {
148154
val result = transferOneCommand(command, inBuffer)
@@ -167,18 +173,24 @@ class ScsiBlockDevice(private val usbCommunication: UsbCommunication, private va
167173
is NotReadyTryAgain -> {} // try again
168174
else -> throw e
169175
}
176+
lastException = e
170177
} catch(e: PipeException) {
171178
Log.w(TAG, (e.message ?: "PipeException") + ", try bulk storage reset and retry")
172179
bulkOnlyMassStorageReset()
180+
lastException = e
173181
} catch (e: IOException) {
174182
// Retry
175183
Log.w(TAG, (e.message ?: "IOException") + ", retrying...")
184+
lastException = e
176185
}
177186

178187
Thread.sleep(100)
179188
}
180189

181-
throw IOException("MAX_RECOVERY_ATTEMPTS Exceeded while trying to transfer command to device, please reattach device and try again")
190+
throw IOException(
191+
"MAX_RECOVERY_ATTEMPTS Exceeded while trying to transfer command to device, please reattach device and try again",
192+
lastException
193+
)
182194
}
183195

184196
@Throws(IOException::class)
@@ -344,7 +356,7 @@ class ScsiBlockDevice(private val usbCommunication: UsbCommunication, private va
344356
}
345357

346358
companion object {
347-
private const val MAX_RECOVERY_ATTEMPTS = 20
359+
private const val MAX_RECOVERY_ATTEMPTS = 5
348360
private val TAG = ScsiBlockDevice::class.java.simpleName
349361
}
350362
}

‎libusbcommunication/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Refer to the following blog where someone claims that LPGL cannot be used in clo
3838
#### Inclusion in your build.gradle
3939

4040
```ruby
41-
implementation 'me.jahnen.libaums:libusbcommunication:0.2.3'
41+
implementation 'me.jahnen.libaums:libusbcommunication:0.2.4'
4242
```
4343

4444
### Activate libusb communication

‎libusbcommunication/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ String libusbDir = props['libusb.dir']
88

99
ext {
1010
PUBLISH_GROUP_ID = 'me.jahnen.libaums'
11-
PUBLISH_VERSION = '0.2.3'
11+
PUBLISH_VERSION = '0.2.4'
1212
PUBLISH_ARTIFACT_ID = 'libusbcommunication'
1313
}
1414

‎libusbcommunication/src/c/usb.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#define TAG "native_libusbcom"
88

9-
JNIEXPORT jboolean JNICALL
9+
JNIEXPORT jint JNICALL
1010
Java_me_jahnen_libaums_libusbcommunication_LibusbCommunication_nativeInit(JNIEnv *env, jobject thiz, jint fd, jlongArray handle) {
1111
LOG_D(TAG, "init native libusb");
1212
int ret;
@@ -18,33 +18,33 @@ Java_me_jahnen_libaums_libusbcommunication_LibusbCommunication_nativeInit(JNIEnv
1818
ret = libusb_set_option(NULL, LIBUSB_OPTION_WEAK_AUTHORITY);
1919
if (ret != 0) {
2020
LOG_E(TAG, "libusb_set_option returned %d, %s", ret, libusb_strerror(ret));
21-
return (jboolean) JNI_FALSE;
21+
return ret;
2222
}
2323
#endif
2424

2525
ret = libusb_init(NULL);
2626
if (ret != 0) {
2727
LOG_E(TAG, "libusb_init returned %d, %s", ret, libusb_strerror(ret));
28-
return (jboolean) JNI_FALSE;
28+
return ret;
2929
}
3030

3131
libusb_device_handle *devh = NULL;
3232
ret = libusb_wrap_sys_device(NULL, fd, &devh);
3333
if (ret != 0) {
3434
LOG_E(TAG, "libusb_wrap_sys_device returned %d, %s", ret, libusb_strerror(ret));
35-
return (jboolean) JNI_FALSE;
35+
return ret;
3636
}
3737
if (devh == NULL) {
3838
LOG_E(TAG, "libusb_wrap_sys_device device handle, %s NULL", libusb_strerror(ret));
39-
return (jboolean) JNI_FALSE;
39+
return LIBUSB_ERROR_OTHER;
4040
}
4141

4242
jlong *body = (*env)->GetLongArrayElements(env, handle, NULL);
4343
// cache heap address in java class object
4444
body[0] = (jlong)devh;
4545
(*env)->ReleaseLongArrayElements(env, handle, body, NULL);
4646

47-
return (jboolean) JNI_TRUE;
47+
return 0;
4848
}
4949

5050
JNIEXPORT void JNICALL
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package me.jahnen.libaums.libusbcommunication
2+
3+
import me.jahnen.libaums.core.ErrNo
4+
import java.io.IOException
5+
6+
/**
7+
* IOException that captures the errno and errstr of the current thread.
8+
*/
9+
open class ErrNoIOException(message: String, cause: Throwable? = null) : IOException(message, cause) {
10+
val errno = ErrNo.errno
11+
val errstr = ErrNo.errstr
12+
}

‎libusbcommunication/src/main/java/me/jahnen/libaums/libusbcommunication/LibusbCommunication.kt

+39-23
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package me.jahnen.libaums.libusbcommunication
22

3-
import android.hardware.usb.*
3+
import android.hardware.usb.UsbDevice
4+
import android.hardware.usb.UsbDeviceConnection
5+
import android.hardware.usb.UsbEndpoint
6+
import android.hardware.usb.UsbInterface
7+
import android.hardware.usb.UsbManager
48
import android.util.Log
59
import me.jahnen.libaums.core.ErrNo
610
import me.jahnen.libaums.core.usb.PipeException
@@ -12,11 +16,11 @@ import java.nio.ByteBuffer
1216

1317

1418
class LibusbCommunication(
15-
usbManager: UsbManager,
16-
usbDevice: UsbDevice,
17-
override val usbInterface: UsbInterface,
18-
override val outEndpoint: UsbEndpoint,
19-
override val inEndpoint: UsbEndpoint
19+
usbManager: UsbManager,
20+
usbDevice: UsbDevice,
21+
override val usbInterface: UsbInterface,
22+
override val outEndpoint: UsbEndpoint,
23+
override val inEndpoint: UsbEndpoint
2024
) : UsbCommunication {
2125

2226
// used to save heap address of libusb device handle
@@ -29,23 +33,24 @@ class LibusbCommunication(
2933
System.loadLibrary("libusbcom")
3034

3135
deviceConnection = usbManager.openDevice(usbDevice)
32-
?: throw IOException("deviceConnection is null!")
36+
?: throw IOException("deviceConnection is null!")
3337

34-
if(!nativeInit(deviceConnection!!.fileDescriptor, libUsbHandleArray)) {
35-
throw IOException("libusb init failed")
38+
val res = nativeInit(deviceConnection!!.fileDescriptor, libUsbHandleArray)
39+
if (res != 0) {
40+
throw LibusbException("libusb init failed", LibusbError.fromCode(res))
3641
}
3742

3843
val claim = deviceConnection!!.claimInterface(usbInterface, true)
3944
if (!claim) {
40-
throw IOException("could not claim interface!")
45+
throw ErrNoIOException("could not claim interface!")
4146
}
4247
// val ret = nativeClaimInterface(libUsbHandle, usbInterface.id)
4348
// if (ret < 0) {
4449
// throw IOException("libusb returned $ret in claim interface")
4550
// }
4651
}
4752

48-
private external fun nativeInit(fd: Int, handle: LongArray): Boolean
53+
private external fun nativeInit(fd: Int, handle: LongArray): Int
4954
private external fun nativeClaimInterface(handle: Long, interfaceNumber: Int): Int
5055
private external fun nativeClose(handle: Long, interfaceNumber: Int)
5156
private external fun nativeReset(handle: Long): Int
@@ -54,20 +59,30 @@ class LibusbCommunication(
5459
private external fun nativeControlTransfer(handle: Long, requestType: Int, request: Int, value: Int, index: Int, buffer: ByteArray, length: Int, timeout: Int): Int
5560

5661
override fun bulkOutTransfer(src: ByteBuffer): Int {
57-
val transferred = nativeBulkTransfer(libUsbHandle, outEndpoint.address, src.array(), src.position(), src.remaining(), TRANSFER_TIMEOUT)
62+
val transferred = nativeBulkTransfer(
63+
libUsbHandle, outEndpoint.address, src.array(), src.position(), src.remaining(),
64+
TRANSFER_TIMEOUT
65+
)
5866
when {
59-
transferred == LIBUSB_EPIPE -> throw PipeException()
60-
transferred < 0 -> throw IOException("libusb returned $transferred in control transfer")
67+
transferred == LibusbError.PIPE.code -> throw PipeException()
68+
transferred < 0 -> throw LibusbException(
69+
"libusb control transfer failed", LibusbError.fromCode(transferred)
70+
)
6171
}
6272
src.position(src.position() + transferred)
6373
return transferred
6474
}
6575

6676
override fun bulkInTransfer(dest: ByteBuffer): Int {
67-
val transferred = nativeBulkTransfer(libUsbHandle, inEndpoint.address, dest.array(), dest.position(), dest.remaining(), TRANSFER_TIMEOUT)
77+
val transferred = nativeBulkTransfer(
78+
libUsbHandle, inEndpoint.address, dest.array(), dest.position(), dest.remaining(),
79+
TRANSFER_TIMEOUT
80+
)
6881
when {
69-
transferred == LIBUSB_EPIPE -> throw PipeException()
70-
transferred < 0 -> throw IOException("libusb returned $transferred in control transfer")
82+
transferred == LibusbError.PIPE.code -> throw PipeException()
83+
transferred < 0 -> throw LibusbException(
84+
"libusb control transfer failed", LibusbError.fromCode(transferred)
85+
)
7186
}
7287
dest.position(dest.position() + transferred)
7388
return transferred
@@ -76,7 +91,7 @@ class LibusbCommunication(
7691
override fun controlTransfer(requestType: Int, request: Int, value: Int, index: Int, buffer: ByteArray, length: Int): Int {
7792
val ret = nativeControlTransfer(libUsbHandle, requestType, request, value, index, buffer, length, TRANSFER_TIMEOUT)
7893
if (ret < 0) {
79-
throw IOException("libusb returned $ret in control transfer")
94+
throw LibusbException("libusb control transfer failed", LibusbError.fromCode(ret))
8095
}
8196
return ret
8297
}
@@ -88,12 +103,14 @@ class LibusbCommunication(
88103

89104
val ret = nativeReset(libUsbHandle)
90105
// if LIBUSB_ERROR_NOT_FOUND might need reenumeration
91-
Log.d(TAG, "libusb reset returned $ret")
106+
Log.d(TAG, "libusb reset returned $ret: ${LibusbError.fromCode(ret).message}")
92107

93108
var counter = 3
94-
while(!deviceConnection!!.claimInterface(usbInterface, true) && counter >= 0) {
109+
while (!deviceConnection!!.claimInterface(usbInterface, true) && counter >= 0) {
95110
if (counter == 0) {
96-
throw IOException("Could not claim interface, errno: ${ErrNo.errno} ${ErrNo.errstr}")
111+
throw ErrNoIOException(
112+
"Could not claim interface, errno: ${ErrNo.errno} ${ErrNo.errstr}"
113+
)
97114
}
98115
Thread.sleep(800)
99116
counter--
@@ -102,7 +119,7 @@ class LibusbCommunication(
102119

103120
override fun clearFeatureHalt(endpoint: UsbEndpoint) {
104121
val ret = nativeClearHalt(libUsbHandle, endpoint.address)
105-
Log.d(TAG, "libusb clearFeatureHalt returned $ret")
122+
Log.d(TAG, "libusb clearFeatureHalt returned $ret: ${LibusbError.fromCode(ret).message}")
106123
}
107124

108125
override fun close() {
@@ -113,7 +130,6 @@ class LibusbCommunication(
113130

114131
companion object {
115132
private val TAG = LibusbCommunication::class.java.simpleName
116-
private val LIBUSB_EPIPE = -9
117133
}
118134
}
119135

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package me.jahnen.libaums.libusbcommunication
2+
3+
enum class LibusbError(val code: Int, val message: String) {
4+
SUCCESS(0, "Success (no error)"),
5+
IO(-1, "Input/output error"),
6+
INVALID_PARAM(-2, "Invalid parameter"),
7+
ACCESS(-3, "Access denied (insufficient permissions)"),
8+
NO_DEVICE(-4, "No such device (it may have been disconnected)"),
9+
NOT_FOUND(-5, "Entity not found"),
10+
BUSY(-6, "Resource busy"),
11+
TIMEOUT(-7, "Operation timed out"),
12+
OVERFLOW(-8, "Overflow"),
13+
PIPE(-9, "Pipe error"),
14+
INTERRUPTED(-10, "System call interrupted (perhaps due to signal)"),
15+
NO_MEM(-11, "Insufficient memory"),
16+
NOT_SUPPORTED(-12, "Operation not supported or unimplemented on this platform"),
17+
OTHER(-99, "Other error");
18+
19+
companion object {
20+
fun fromCode(code: Int): LibusbError {
21+
return values().firstOrNull { it.code == code } ?: OTHER
22+
}
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package me.jahnen.libaums.libusbcommunication
2+
3+
open class LibusbException(
4+
message: String,
5+
val libusbError: LibusbError,
6+
cause: Throwable? = null
7+
) :
8+
ErrNoIOException("$message: ${libusbError.message} [${libusbError.code}]", cause)

0 commit comments

Comments
 (0)
Please sign in to comment.