Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qgroundcontrol
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Valentin Platzgummer
qgroundcontrol
Commits
6243dbac
Commit
6243dbac
authored
Jan 22, 2019
by
Don Gagne
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
parent
6580a544
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
271 additions
and
318 deletions
+271
-318
CdcAcmSerialDriver.java
...com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
+2
-2
CommonUsbSerialDriver.java
.../hoho/android/usbserial/driver/CommonUsbSerialDriver.java
+22
-6
Cp2102SerialDriver.java
...com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
+2
-2
FtdiSerialDriver.java
...c/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
+2
-2
ProlificSerialDriver.java
...m/hoho/android/usbserial/driver/ProlificSerialDriver.java
+2
-2
UsbSerialDriver.java
...rc/com/hoho/android/usbserial/driver/UsbSerialDriver.java
+10
-0
UsbSerialProber.java
...rc/com/hoho/android/usbserial/driver/UsbSerialProber.java
+4
-20
QGCActivity.java
android/src/org/mavlink/qgroundcontrol/QGCActivity.java
+226
-283
qserialport_android.cpp
libs/qtandroidserialport/src/qserialport_android.cpp
+1
-1
No files found.
android/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java
View file @
6243dbac
...
@@ -41,8 +41,8 @@ public class CdcAcmSerialDriver extends CommonUsbSerialDriver {
...
@@ -41,8 +41,8 @@ public class CdcAcmSerialDriver extends CommonUsbSerialDriver {
private
static
final
int
SET_CONTROL_LINE_STATE
=
0x22
;
private
static
final
int
SET_CONTROL_LINE_STATE
=
0x22
;
private
static
final
int
SEND_BREAK
=
0x23
;
private
static
final
int
SEND_BREAK
=
0x23
;
public
CdcAcmSerialDriver
(
UsbDevice
device
,
UsbDeviceConnection
connection
)
{
public
CdcAcmSerialDriver
(
UsbDevice
device
)
{
super
(
device
,
connection
);
super
(
device
);
}
}
@Override
@Override
...
...
android/src/com/hoho/android/usbserial/driver/CommonUsbSerialDriver.java
View file @
6243dbac
...
@@ -35,11 +35,13 @@ abstract class CommonUsbSerialDriver implements UsbSerialDriver {
...
@@ -35,11 +35,13 @@ abstract class CommonUsbSerialDriver implements UsbSerialDriver {
public
static
final
int
DEFAULT_READ_BUFFER_SIZE
=
16
*
1024
;
public
static
final
int
DEFAULT_READ_BUFFER_SIZE
=
16
*
1024
;
public
static
final
int
DEFAULT_WRITE_BUFFER_SIZE
=
16
*
1024
;
public
static
final
int
DEFAULT_WRITE_BUFFER_SIZE
=
16
*
1024
;
protected
final
UsbDevice
mDevice
;
protected
final
UsbDevice
mDevice
;
protected
final
UsbDeviceConnection
mConnection
;
protected
final
Object
mReadBufferLock
=
new
Object
();
protected
final
Object
mWriteBufferLock
=
new
Object
();
protected
final
Object
mReadBufferLock
=
new
Object
();
protected
UsbDeviceConnection
mConnection
=
null
;
protected
final
Object
mWriteBufferLock
=
new
Object
();
private
int
_permissionStatus
=
permissionStatusRequestRequired
;
/** Internal read buffer. Guarded by {@link #mReadBufferLock}. */
/** Internal read buffer. Guarded by {@link #mReadBufferLock}. */
protected
byte
[]
mReadBuffer
;
protected
byte
[]
mReadBuffer
;
...
@@ -47,14 +49,28 @@ abstract class CommonUsbSerialDriver implements UsbSerialDriver {
...
@@ -47,14 +49,28 @@ abstract class CommonUsbSerialDriver implements UsbSerialDriver {
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
protected
byte
[]
mWriteBuffer
;
protected
byte
[]
mWriteBuffer
;
public
CommonUsbSerialDriver
(
UsbDevice
device
,
UsbDeviceConnection
connection
)
{
public
CommonUsbSerialDriver
(
UsbDevice
device
)
{
mDevice
=
device
;
mDevice
=
device
;
mConnection
=
connection
;
mReadBuffer
=
new
byte
[
DEFAULT_READ_BUFFER_SIZE
];
mReadBuffer
=
new
byte
[
DEFAULT_READ_BUFFER_SIZE
];
mWriteBuffer
=
new
byte
[
DEFAULT_WRITE_BUFFER_SIZE
];
mWriteBuffer
=
new
byte
[
DEFAULT_WRITE_BUFFER_SIZE
];
}
}
@Override
public
void
setConnection
(
UsbDeviceConnection
connection
)
{
mConnection
=
connection
;
}
@Override
public
int
permissionStatus
()
{
return
_permissionStatus
;
}
@Override
public
void
setPermissionStatus
(
int
permissionStatus
)
{
_permissionStatus
=
permissionStatus
;
}
/**
/**
* Returns the currently-bound USB device.
* Returns the currently-bound USB device.
*
*
...
...
android/src/com/hoho/android/usbserial/driver/Cp2102SerialDriver.java
View file @
6243dbac
...
@@ -61,8 +61,8 @@ public class Cp2102SerialDriver extends CommonUsbSerialDriver {
...
@@ -61,8 +61,8 @@ public class Cp2102SerialDriver extends CommonUsbSerialDriver {
private
UsbEndpoint
mReadEndpoint
;
private
UsbEndpoint
mReadEndpoint
;
private
UsbEndpoint
mWriteEndpoint
;
private
UsbEndpoint
mWriteEndpoint
;
public
Cp2102SerialDriver
(
UsbDevice
device
,
UsbDeviceConnection
connection
)
{
public
Cp2102SerialDriver
(
UsbDevice
device
)
{
super
(
device
,
connection
);
super
(
device
);
}
}
private
int
setConfigSingle
(
int
request
,
int
value
)
{
private
int
setConfigSingle
(
int
request
,
int
value
)
{
...
...
android/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java
View file @
6243dbac
...
@@ -211,8 +211,8 @@ public class FtdiSerialDriver extends CommonUsbSerialDriver {
...
@@ -211,8 +211,8 @@ public class FtdiSerialDriver extends CommonUsbSerialDriver {
* @throws UsbSerialRuntimeException if the given device is incompatible
* @throws UsbSerialRuntimeException if the given device is incompatible
* with this driver
* with this driver
*/
*/
public
FtdiSerialDriver
(
UsbDevice
usbDevice
,
UsbDeviceConnection
usbConnection
)
{
public
FtdiSerialDriver
(
UsbDevice
usbDevice
)
{
super
(
usbDevice
,
usbConnection
);
super
(
usbDevice
);
mType
=
null
;
mType
=
null
;
}
}
...
...
android/src/com/hoho/android/usbserial/driver/ProlificSerialDriver.java
View file @
6243dbac
...
@@ -231,8 +231,8 @@ public class ProlificSerialDriver extends CommonUsbSerialDriver {
...
@@ -231,8 +231,8 @@ public class ProlificSerialDriver extends CommonUsbSerialDriver {
return
((
getStatus
()
&
flag
)
==
flag
);
return
((
getStatus
()
&
flag
)
==
flag
);
}
}
public
ProlificSerialDriver
(
UsbDevice
device
,
UsbDeviceConnection
connection
)
{
public
ProlificSerialDriver
(
UsbDevice
device
)
{
super
(
device
,
connection
);
super
(
device
);
}
}
@Override
@Override
...
...
android/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
View file @
6243dbac
...
@@ -83,6 +83,16 @@ public interface UsbSerialDriver {
...
@@ -83,6 +83,16 @@ public interface UsbSerialDriver {
/** 2 stop bits. */
/** 2 stop bits. */
public
static
final
int
STOPBITS_2
=
2
;
public
static
final
int
STOPBITS_2
=
2
;
public
static
final
int
permissionStatusSuccess
=
0
;
public
static
final
int
permissionStatusDenied
=
1
;
public
static
final
int
permissionStatusRequested
=
2
;
public
static
final
int
permissionStatusRequestRequired
=
3
;
public
static
final
int
permissionStatusOpen
=
4
;
public
int
permissionStatus
();
public
void
setPermissionStatus
(
int
permissionStatus
);
public
void
setConnection
(
UsbDeviceConnection
connection
);
/**
/**
* Returns the currently-bound USB device.
* Returns the currently-bound USB device.
*
*
...
...
android/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
View file @
6243dbac
...
@@ -65,11 +65,7 @@ public enum UsbSerialProber {
...
@@ -65,11 +65,7 @@ public enum UsbSerialProber {
if
(!
testIfSupported
(
usbDevice
,
FtdiSerialDriver
.
getSupportedDevices
()))
{
if
(!
testIfSupported
(
usbDevice
,
FtdiSerialDriver
.
getSupportedDevices
()))
{
return
Collections
.
emptyList
();
return
Collections
.
emptyList
();
}
}
final
UsbDeviceConnection
connection
=
manager
.
openDevice
(
usbDevice
);
final
UsbSerialDriver
driver
=
new
FtdiSerialDriver
(
usbDevice
);
if
(
connection
==
null
)
{
return
Collections
.
emptyList
();
}
final
UsbSerialDriver
driver
=
new
FtdiSerialDriver
(
usbDevice
,
connection
);
return
Collections
.
singletonList
(
driver
);
return
Collections
.
singletonList
(
driver
);
}
}
},
},
...
@@ -80,11 +76,7 @@ public enum UsbSerialProber {
...
@@ -80,11 +76,7 @@ public enum UsbSerialProber {
if
(!
testIfSupported
(
usbDevice
,
CdcAcmSerialDriver
.
getSupportedDevices
()))
{
if
(!
testIfSupported
(
usbDevice
,
CdcAcmSerialDriver
.
getSupportedDevices
()))
{
return
Collections
.
emptyList
();
return
Collections
.
emptyList
();
}
}
final
UsbDeviceConnection
connection
=
manager
.
openDevice
(
usbDevice
);
final
UsbSerialDriver
driver
=
new
CdcAcmSerialDriver
(
usbDevice
);
if
(
connection
==
null
)
{
return
Collections
.
emptyList
();
}
final
UsbSerialDriver
driver
=
new
CdcAcmSerialDriver
(
usbDevice
,
connection
);
return
Collections
.
singletonList
(
driver
);
return
Collections
.
singletonList
(
driver
);
}
}
},
},
...
@@ -95,11 +87,7 @@ public enum UsbSerialProber {
...
@@ -95,11 +87,7 @@ public enum UsbSerialProber {
if
(!
testIfSupported
(
usbDevice
,
Cp2102SerialDriver
.
getSupportedDevices
()))
{
if
(!
testIfSupported
(
usbDevice
,
Cp2102SerialDriver
.
getSupportedDevices
()))
{
return
Collections
.
emptyList
();
return
Collections
.
emptyList
();
}
}
final
UsbDeviceConnection
connection
=
manager
.
openDevice
(
usbDevice
);
final
UsbSerialDriver
driver
=
new
Cp2102SerialDriver
(
usbDevice
);
if
(
connection
==
null
)
{
return
Collections
.
emptyList
();
}
final
UsbSerialDriver
driver
=
new
Cp2102SerialDriver
(
usbDevice
,
connection
);
return
Collections
.
singletonList
(
driver
);
return
Collections
.
singletonList
(
driver
);
}
}
},
},
...
@@ -110,11 +98,7 @@ public enum UsbSerialProber {
...
@@ -110,11 +98,7 @@ public enum UsbSerialProber {
if
(!
testIfSupported
(
usbDevice
,
ProlificSerialDriver
.
getSupportedDevices
()))
{
if
(!
testIfSupported
(
usbDevice
,
ProlificSerialDriver
.
getSupportedDevices
()))
{
return
Collections
.
emptyList
();
return
Collections
.
emptyList
();
}
}
final
UsbDeviceConnection
connection
=
manager
.
openDevice
(
usbDevice
);
final
UsbSerialDriver
driver
=
new
ProlificSerialDriver
(
usbDevice
);
if
(
connection
==
null
)
{
return
Collections
.
emptyList
();
}
final
UsbSerialDriver
driver
=
new
ProlificSerialDriver
(
usbDevice
,
connection
);
return
Collections
.
singletonList
(
driver
);
return
Collections
.
singletonList
(
driver
);
}
}
};
};
...
...
android/src/org/mavlink/qgroundcontrol/QGCActivity.java
View file @
6243dbac
...
@@ -31,11 +31,13 @@ package org.mavlink.qgroundcontrol;
...
@@ -31,11 +31,13 @@ package org.mavlink.qgroundcontrol;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.ArrayList
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.Executors
;
import
java.io.IOException
;
import
java.io.IOException
;
import
android.app.Activity
;
import
android.app.Activity
;
import
android.app.PendingIntent
;
import
android.content.BroadcastReceiver
;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.Intent
;
...
@@ -53,81 +55,136 @@ import org.qtproject.qt5.android.bindings.QtApplication;
...
@@ -53,81 +55,136 @@ import org.qtproject.qt5.android.bindings.QtApplication;
public
class
QGCActivity
extends
QtActivity
public
class
QGCActivity
extends
QtActivity
{
{
public
static
int
BAD_PORT
=
0
;
public
static
int
BAD_DEVICE_ID
=
0
;
private
static
QGCActivity
m_instance
;
private
static
QGCActivity
_instance
=
null
;
private
static
UsbManager
m_manager
;
// ANDROID USB HOST CLASS
private
static
UsbManager
_usbManager
=
null
;
private
static
List
<
UsbSerialDriver
>
m_devices
;
// LIST OF CURRENT DEVICES
private
static
List
<
UsbSerialDriver
>
_drivers
;
private
static
HashMap
<
Integer
,
UsbSerialDriver
>
m_openedDevices
;
// LIST OF OPENED DEVICES
private
static
HashMap
<
Integer
,
UsbIoManager
>
m_ioManager
;
private
static
HashMap
<
Integer
,
UsbIoManager
>
m_ioManager
;
// THREADS FOR LISTENING FOR INCOMING DATA
private
static
HashMap
<
Integer
,
Integer
>
_userDataHashByDeviceId
;
private
static
HashMap
<
Integer
,
Integer
>
m_userData
;
// CORRESPONDING USER DATA FOR OPENED DEVICES. USED IN DISCONNECT CALLBACK
private
static
final
String
TAG
=
"QGC_QGCActivity"
;
// USED TO DETECT WHEN A DEVICE HAS BEEN UNPLUGGED
private
static
PowerManager
.
WakeLock
_wakeLock
;
private
BroadcastReceiver
m_UsbReceiver
=
null
;
private
static
final
String
ACTION_USB_PERMISSION
=
"com.android.example.USB_PERMISSION"
;
private
final
static
ExecutorService
m_Executor
=
Executors
.
newSingleThreadExecutor
();
private
static
PendingIntent
_usbPermissionIntent
=
null
;
private
static
final
String
TAG
=
"QGC_QGCActivity"
;
private
static
PowerManager
.
WakeLock
m_wl
;
public
static
Context
m_context
;
public
static
Context
m_context
;
private
final
static
ExecutorService
m_Executor
=
Executors
.
newSingleThreadExecutor
();
private
final
static
UsbIoManager
.
Listener
m_Listener
=
private
final
static
UsbIoManager
.
Listener
m_Listener
=
new
UsbIoManager
.
Listener
()
new
UsbIoManager
.
Listener
()
{
{
@Override
@Override
public
void
onRunError
(
Exception
eA
,
int
userData
A
)
public
void
onRunError
(
Exception
eA
,
int
userData
)
{
{
Log
.
e
(
TAG
,
"onRunError Exception"
);
Log
.
e
(
TAG
,
"onRunError Exception"
);
nativeDeviceException
(
userData
A
,
eA
.
getMessage
());
nativeDeviceException
(
userData
,
eA
.
getMessage
());
}
}
@Override
@Override
public
void
onNewData
(
final
byte
[]
dataA
,
int
userData
A
)
public
void
onNewData
(
final
byte
[]
dataA
,
int
userData
)
{
{
nativeDeviceNewData
(
userData
A
,
dataA
);
nativeDeviceNewData
(
userData
,
dataA
);
}
}
};
};
// NATIVE C++ FUNCTION THAT WILL BE CALLED IF THE DEVICE IS UNPLUGGED
private
static
UsbSerialDriver
_findDriverByDeviceId
(
int
deviceId
)
{
private
static
native
void
nativeDeviceHasDisconnected
(
int
userDataA
);
for
(
UsbSerialDriver
driver:
_drivers
)
{
private
static
native
void
nativeDeviceException
(
int
userDataA
,
String
messageA
);
if
(
driver
.
getDevice
().
getDeviceId
()
==
deviceId
)
{
private
static
native
void
nativeDeviceNewData
(
int
userDataA
,
byte
[]
dataA
);
return
driver
;
}
}
return
null
;
}
private
static
UsbSerialDriver
_findDriverByDeviceName
(
String
deviceName
)
{
for
(
UsbSerialDriver
driver:
_drivers
)
{
if
(
driver
.
getDevice
().
getDeviceName
().
equals
(
deviceName
))
{
return
driver
;
}
}
return
null
;
}
private
final
static
BroadcastReceiver
_usbReceiver
=
new
BroadcastReceiver
()
{
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
String
action
=
intent
.
getAction
();
Log
.
i
(
TAG
,
"BroadcastReceiver USB action "
+
action
);
if
(
ACTION_USB_PERMISSION
.
equals
(
action
))
{
synchronized
(
_instance
)
{
UsbDevice
device
=
(
UsbDevice
)
intent
.
getParcelableExtra
(
UsbManager
.
EXTRA_DEVICE
);
if
(
device
!=
null
)
{
UsbSerialDriver
driver
=
_findDriverByDeviceId
(
device
.
getDeviceId
());
if
(
intent
.
getBooleanExtra
(
UsbManager
.
EXTRA_PERMISSION_GRANTED
,
false
))
{
qgcLogDebug
(
"Permission granted to "
+
device
.
getDeviceName
());
driver
.
setPermissionStatus
(
UsbSerialDriver
.
permissionStatusSuccess
);
}
else
{
qgcLogDebug
(
"Permission denied for "
+
device
.
getDeviceName
());
driver
.
setPermissionStatus
(
UsbSerialDriver
.
permissionStatusDenied
);
}
}
}
}
else
if
(
UsbManager
.
ACTION_USB_DEVICE_DETACHED
.
equals
(
action
))
{
UsbDevice
device
=
(
UsbDevice
)
intent
.
getParcelableExtra
(
UsbManager
.
EXTRA_DEVICE
);
if
(
device
!=
null
)
{
if
(
_userDataHashByDeviceId
.
containsKey
(
device
.
getDeviceId
()))
{
nativeDeviceHasDisconnected
(
_userDataHashByDeviceId
.
get
(
device
.
getDeviceId
()));
}
}
}
}
};
// Native C++ functions which connect back to QSerialPort code
private
static
native
void
nativeDeviceHasDisconnected
(
int
userData
);
private
static
native
void
nativeDeviceException
(
int
userData
,
String
messageA
);
private
static
native
void
nativeDeviceNewData
(
int
userData
,
byte
[]
dataA
);
// Native C++ functions called to log output
// Native C++ functions called to log output
public
static
native
void
qgcLogDebug
(
String
message
);
public
static
native
void
qgcLogDebug
(
String
message
);
public
static
native
void
qgcLogWarning
(
String
message
);
public
static
native
void
qgcLogWarning
(
String
message
);
////////////////////////////////////////////////////////////////////////////////////////////////
// QGCActivity singleton
//
// Constructor. Only used once to create the initial instance for the static functions.
//
////////////////////////////////////////////////////////////////////////////////////////////////
public
QGCActivity
()
public
QGCActivity
()
{
{
m_instance
=
this
;
_instance
=
this
;
m_openedDevices
=
new
HashMap
<
Integer
,
UsbSerialDriver
>();
_drivers
=
new
ArrayList
<
UsbSerialDriver
>();
m_userData
=
new
HashMap
<
Integer
,
Integer
>();
_userDataHashByDeviceId
=
new
HashMap
<
Integer
,
Integer
>();
m_ioManager
=
new
HashMap
<
Integer
,
UsbIoManager
>();
m_ioManager
=
new
HashMap
<
Integer
,
UsbIoManager
>();
Log
.
i
(
TAG
,
"Instance created"
);
}
}
@Override
@Override
public
void
onCreate
(
Bundle
savedInstanceState
)
{
public
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
super
.
onCreate
(
savedInstanceState
);
PowerManager
pm
=
(
PowerManager
)
m_instance
.
getSystemService
(
Context
.
POWER_SERVICE
);
PowerManager
pm
=
(
PowerManager
)
_instance
.
getSystemService
(
Context
.
POWER_SERVICE
);
m_wl
=
pm
.
newWakeLock
(
PowerManager
.
SCREEN_BRIGHT_WAKE_LOCK
,
"QGroundControl"
);
_wakeLock
=
pm
.
newWakeLock
(
PowerManager
.
SCREEN_BRIGHT_WAKE_LOCK
,
"QGroundControl"
);
if
(
m_wl
!=
null
)
{
if
(
_wakeLock
!=
null
)
{
m_wl
.
acquire
();
_wakeLock
.
acquire
();
Log
.
i
(
TAG
,
"SCREEN_BRIGHT_WAKE_LOCK acquired."
);
}
else
{
}
else
{
Log
.
i
(
TAG
,
"SCREEN_BRIGHT_WAKE_LOCK not acquired!!!"
);
Log
.
i
(
TAG
,
"SCREEN_BRIGHT_WAKE_LOCK not acquired!!!"
);
}
}
m_instance
.
getWindow
().
addFlags
(
WindowManager
.
LayoutParams
.
FLAG_KEEP_SCREEN_ON
);
_instance
.
getWindow
().
addFlags
(
WindowManager
.
LayoutParams
.
FLAG_KEEP_SCREEN_ON
);
_usbManager
=
(
UsbManager
)
_instance
.
getSystemService
(
Context
.
USB_SERVICE
);
// Register for USB Detach and USB Permission intent
IntentFilter
filter
=
new
IntentFilter
();
filter
.
addAction
(
UsbManager
.
ACTION_USB_DEVICE_DETACHED
);
filter
.
addAction
(
ACTION_USB_PERMISSION
);
_instance
.
registerReceiver
(
_instance
.
_usbReceiver
,
filter
);
// Create intent for usb permission request
_usbPermissionIntent
=
PendingIntent
.
getBroadcast
(
_instance
,
0
,
new
Intent
(
ACTION_USB_PERMISSION
),
0
);
}
}
@Override
@Override
protected
void
onDestroy
()
{
protected
void
onDestroy
()
{
try
{
try
{
if
(
m_wl
!=
null
)
{
if
(
_wakeLock
!=
null
)
{
m_wl
.
release
();
_wakeLock
.
release
();
Log
.
i
(
TAG
,
"SCREEN_BRIGHT_WAKE_LOCK released."
);
}
}
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
Log
.
e
(
TAG
,
"Exception onDestroy()"
);
Log
.
e
(
TAG
,
"Exception onDestroy()"
);
...
@@ -138,225 +195,156 @@ public class QGCActivity extends QtActivity
...
@@ -138,225 +195,156 @@ public class QGCActivity extends QtActivity
public
void
onInit
(
int
status
)
{
public
void
onInit
(
int
status
)
{
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Incrementally updates the list of drivers connected to the device
//
private
static
void
updateCurrentDrivers
()
// Find all current devices that match the device filter described in the androidmanifest.xml and the
// device_filter.xml
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
private
static
boolean
getCurrentDevices
()
{
{
if
(
m_instance
==
null
)
List
<
UsbSerialDriver
>
currentDrivers
=
UsbSerialProber
.
findAllDevices
(
_usbManager
);
return
false
;
// Remove stale drivers
if
(
m_manager
==
null
)
for
(
int
i
=
_drivers
.
size
()-
1
;
i
>=
0
;
i
--)
{
m_manager
=
(
UsbManager
)
m_instance
.
getSystemService
(
Context
.
USB_SERVICE
);
boolean
found
=
false
;
for
(
UsbSerialDriver
currentDriver:
currentDrivers
)
{
if
(
_drivers
.
get
(
i
).
getDevice
().
getDeviceId
()
==
currentDriver
.
getDevice
().
getDeviceId
())
{
found
=
true
;
break
;
}
}
if
(
m_devices
!=
null
)
if
(!
found
)
{
m_devices
.
clear
();
qgcLogDebug
(
"Remove stale driver "
+
_drivers
.
get
(
i
).
getDevice
().
getDeviceName
());
_drivers
.
remove
(
i
);
}
}
m_devices
=
UsbSerialProber
.
findAllDevices
(
m_manager
);
// Add new drivers
for
(
int
i
=
0
;
i
<
currentDrivers
.
size
();
i
++)
{
boolean
found
=
false
;
for
(
int
j
=
0
;
j
<
_drivers
.
size
();
j
++)
{
if
(
currentDrivers
.
get
(
i
).
getDevice
().
getDeviceId
()
==
_drivers
.
get
(
j
).
getDevice
().
getDeviceId
())
{
found
=
true
;
break
;
}
}
return
true
;
if
(!
found
)
{
UsbSerialDriver
newDriver
=
currentDrivers
.
get
(
i
);
UsbDevice
device
=
newDriver
.
getDevice
();
String
deviceName
=
device
.
getDeviceName
();
_drivers
.
add
(
newDriver
);
qgcLogDebug
(
"Adding new driver "
+
deviceName
);
// Request permission if needed
if
(
_usbManager
.
hasPermission
(
device
))
{
qgcLogDebug
(
"Already have permission to use device "
+
deviceName
);
newDriver
.
setPermissionStatus
(
UsbSerialDriver
.
permissionStatusSuccess
);
}
else
{
qgcLogDebug
(
"Requesting permission to use device "
+
deviceName
);
newDriver
.
setPermissionStatus
(
UsbSerialDriver
.
permissionStatusRequested
);
_usbManager
.
requestPermission
(
device
,
_usbPermissionIntent
);
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Returns array of device info for each unopened device.
//
/// @return Device info format DeviceName:Company:ProductId:VendorId
// List all available devices that are not already open. It returns the serial port info
// in a : separated string array. Each string entry consists of the following:
//
// DeviceName:Company:ProductId:VendorId
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
public
static
String
[]
availableDevicesInfo
()
public
static
String
[]
availableDevicesInfo
()
{
{
// GET THE LIST OF CURRENT DEVICES
updateCurrentDrivers
();
if
(!
getCurrentDevices
())
{
Log
.
e
(
TAG
,
"QGCActivity instance not present"
);
return
null
;
}
// MAKE SURE WE HAVE ENTRIES
if
(
_drivers
.
size
()
<=
0
)
{
if
(
m_devices
.
size
()
<=
0
)
{
//Log.e(TAG, "No USB devices found");
return
null
;
return
null
;
}
}
if
(
m_openedDevices
==
null
)
List
<
String
>
deviceInfoList
=
new
ArrayList
<
String
>();
{
Log
.
e
(
TAG
,
"m_openedDevices is null"
);
return
null
;
}
int
countL
=
0
;
for
(
int
i
=
0
;
i
<
_drivers
.
size
();
i
++)
{
int
iL
;
String
deviceInfo
;
UsbSerialDriver
driver
=
_drivers
.
get
(
i
);
// CHECK FOR ALREADY OPENED DEVICES AND DON"T INCLUDE THEM IN THE COUNT
if
(
driver
.
permissionStatus
()
!=
UsbSerialDriver
.
permissionStatusSuccess
)
{
for
(
iL
=
0
;
iL
<
m_devices
.
size
();
iL
++)
continue
;
{
if
(
m_openedDevices
.
get
(
m_devices
.
get
(
iL
).
getDevice
().
getDeviceId
())
!=
null
)
{
countL
++;
break
;
}
}
}
if
(
m_devices
.
size
()
-
countL
<=
0
)
UsbDevice
device
=
driver
.
getDevice
();
{
//Log.e(TAG, "No open USB devices found");
return
null
;
}
String
[]
listL
=
new
String
[
m_devices
.
size
()
-
countL
];
deviceInfo
=
device
.
getDeviceName
()
+
":"
;
UsbSerialDriver
driverL
;
String
tempL
;
// GET THE DATA ON THE INDIVIDUAL DEVICES SKIPPING THE ONES THAT ARE ALREADY OPEN
if
(
driver
instanceof
FtdiSerialDriver
)
{
countL
=
0
;
deviceInfo
=
deviceInfo
+
"FTDI:"
;
for
(
iL
=
0
;
iL
<
m_devices
.
size
();
iL
++)
}
else
if
(
driver
instanceof
CdcAcmSerialDriver
)
{
{
deviceInfo
=
deviceInfo
+
"Cdc Acm:"
;
driverL
=
m_devices
.
get
(
iL
);
}
else
if
(
driver
instanceof
Cp2102SerialDriver
)
{
if
(
m_openedDevices
.
get
(
driverL
.
getDevice
().
getDeviceId
())
==
null
)
deviceInfo
=
deviceInfo
+
"Cp2102:"
;
{
}
else
if
(
driver
instanceof
ProlificSerialDriver
)
{
UsbDevice
deviceL
=
driverL
.
getDevice
();
deviceInfo
=
deviceInfo
+
"Prolific:"
;
tempL
=
deviceL
.
getDeviceName
()
+
":"
;
}
else
{
deviceInfo
=
deviceInfo
+
"Unknown:"
;
if
(
driverL
instanceof
FtdiSerialDriver
)
tempL
=
tempL
+
"FTDI:"
;
else
if
(
driverL
instanceof
CdcAcmSerialDriver
)
tempL
=
tempL
+
"Cdc Acm:"
;
else
if
(
driverL
instanceof
Cp2102SerialDriver
)
tempL
=
tempL
+
"Cp2102:"
;
else
if
(
driverL
instanceof
ProlificSerialDriver
)
tempL
=
tempL
+
"Prolific:"
;
else
tempL
=
tempL
+
"Unknown:"
;
tempL
=
tempL
+
Integer
.
toString
(
deviceL
.
getProductId
())
+
":"
;
tempL
=
tempL
+
Integer
.
toString
(
deviceL
.
getVendorId
())
+
":"
;
listL
[
countL
]
=
tempL
;
countL
++;
qgcLogDebug
(
"Found "
+
tempL
);
}
}
}
return
listL
;
deviceInfo
=
deviceInfo
+
Integer
.
toString
(
device
.
getProductId
())
+
":"
;
}
deviceInfo
=
deviceInfo
+
Integer
.
toString
(
device
.
getVendorId
())
+
":"
;
deviceInfoList
.
add
(
deviceInfo
);
}
String
[]
rgDeviceInfo
=
new
String
[
deviceInfoList
.
size
()];
for
(
int
i
=
0
;
i
<
deviceInfoList
.
size
();
i
++)
{
rgDeviceInfo
[
i
]
=
deviceInfoList
.
get
(
i
);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
return
rgDeviceInfo
;
//
}
// Open a device based on the name.
//
/// Open the specified device
// Args: nameA - name of the device to open
/// @param userData Data to associate with device and pass back through to native calls.
// userDataA - C++ pointer to the QSerialPort that is trying to open the device. This is
/// @return Device id
// used by the detector to inform the C++ side if it is unplugged
public
static
int
open
(
Context
parentContext
,
String
deviceName
,
int
userData
)
//
// Returns: ID number of opened port. This number is used to reference the correct port in subsequent
// calls like close(), read(), and write().
//
/////////////////////////////////////////////////////////////////////////////////////////////////
public
static
int
open
(
Context
parentContext
,
String
nameA
,
int
userDataA
)
{
{
int
idL
=
BAD_PORT
;
int
deviceId
=
BAD_DEVICE_ID
;
m_context
=
parentContext
;
m_context
=
parentContext
;
//qgcLogDebug("Getting device list");
UsbSerialDriver
driver
=
_findDriverByDeviceName
(
deviceName
);
if
(!
getCurrentDevices
())
if
(
driver
==
null
)
{
return
BAD_PORT
;
qgcLogWarning
(
"Attempt to open unknown device "
+
deviceName
);
return
BAD_DEVICE_ID
;
// CHECK THAT PORT IS NOT ALREADY OPENED
if
(
m_openedDevices
!=
null
)
{
for
(
UsbSerialDriver
driverL:
m_openedDevices
.
values
())
{
if
(
nameA
.
equals
(
driverL
.
getDevice
().
getDeviceName
()))
{
Log
.
e
(
TAG
,
"Device already opened"
);
return
BAD_PORT
;
}
}
}
}
else
return
BAD_PORT
;
if
(
m_devices
==
null
)
if
(
driver
.
permissionStatus
()
!=
UsbSerialDriver
.
permissionStatusSuccess
)
{
return
BAD_PORT
;
qgcLogWarning
(
"Attempt to open device with incorrect permission status "
+
deviceName
+
" "
+
driver
.
permissionStatus
());
return
BAD_DEVICE_ID
;
}
// OPEN THE DEVICE
UsbDevice
device
=
driver
.
getDevice
();
try
deviceId
=
device
.
getDeviceId
();
{
for
(
int
iL
=
0
;
iL
<
m_devices
.
size
();
iL
++)
{
Log
.
i
(
TAG
,
"Checking device "
+
m_devices
.
get
(
iL
).
getDevice
().
getDeviceName
()
+
" id: "
+
m_devices
.
get
(
iL
).
getDevice
().
getDeviceId
());
if
(
nameA
.
equals
(
m_devices
.
get
(
iL
).
getDevice
().
getDeviceName
()))
{
idL
=
m_devices
.
get
(
iL
).
getDevice
().
getDeviceId
();
m_openedDevices
.
put
(
idL
,
m_devices
.
get
(
iL
));
m_userData
.
put
(
idL
,
userDataA
);
if
(
m_instance
.
m_UsbReceiver
==
null
)
{
Log
.
i
(
TAG
,
"Creating new broadcast receiver"
);
m_instance
.
m_UsbReceiver
=
new
BroadcastReceiver
()
{
public
void
onReceive
(
Context
contextA
,
Intent
intentA
)
{
String
actionL
=
intentA
.
getAction
();
if
(
UsbManager
.
ACTION_USB_DEVICE_DETACHED
.
equals
(
actionL
))
{
UsbDevice
deviceL
=
(
UsbDevice
)
intentA
.
getParcelableExtra
(
UsbManager
.
EXTRA_DEVICE
);
if
(
deviceL
!=
null
)
{
if
(
m_userData
.
containsKey
(
deviceL
.
getDeviceId
()))
{
nativeDeviceHasDisconnected
(
m_userData
.
get
(
deviceL
.
getDeviceId
()));
}
}
}
}
};
// TURN ON THE INTENT FILTER SO IT WILL DETECT AN UNPLUG SIGNAL
IntentFilter
filterL
=
new
IntentFilter
();
filterL
.
addAction
(
UsbManager
.
ACTION_USB_DEVICE_DETACHED
);
m_instance
.
registerReceiver
(
m_instance
.
m_UsbReceiver
,
filterL
);
}
m_openedDevices
.
get
(
idL
).
open
();
try
{
driver
.
setConnection
(
_usbManager
.
openDevice
(
device
));
driver
.
open
();
driver
.
setPermissionStatus
(
UsbSerialDriver
.
permissionStatusOpen
);
// START UP THE IO MANAGER TO READ/WRITE DATA TO THE DEVICE
_userDataHashByDeviceId
.
put
(
deviceId
,
userData
);
UsbIoManager
managerL
=
new
UsbIoManager
(
m_openedDevices
.
get
(
idL
),
m_Listener
,
userDataA
);
if
(
managerL
==
null
)
Log
.
e
(
TAG
,
"UsbIoManager instance is null"
);
m_ioManager
.
put
(
idL
,
managerL
);
m_Executor
.
submit
(
managerL
);
Log
.
i
(
TAG
,
"Port open successful"
);
return
idL
;
}
}
return
BAD_PORT
;
UsbIoManager
ioManager
=
new
UsbIoManager
(
driver
,
m_Listener
,
userData
);
}
m_ioManager
.
put
(
deviceId
,
ioManager
);
catch
(
IOException
exA
)
m_Executor
.
submit
(
ioManager
);
{
if
(
idL
!=
BAD_PORT
)
{
m_openedDevices
.
remove
(
idL
);
m_userData
.
remove
(
idL
);
if
(
m_ioManager
.
get
(
idL
)
!=
null
)
qgcLogDebug
(
"Port open successful"
);
m_ioManager
.
get
(
idL
).
stop
();
}
catch
(
IOException
exA
)
{
driver
.
setPermissionStatus
(
UsbSerialDriver
.
permissionStatusRequestRequired
);
_userDataHashByDeviceId
.
remove
(
deviceId
);
m_ioManager
.
remove
(
idL
);
if
(
m_ioManager
.
get
(
deviceId
)
!=
null
)
{
m_ioManager
.
get
(
deviceId
).
stop
();
m_ioManager
.
remove
(
deviceId
);
}
}
qgcLogWarning
(
"Port open exception: "
+
exA
.
getMessage
());
qgcLogWarning
(
"Port open exception: "
+
exA
.
getMessage
());
return
BAD_
PORT
;
return
BAD_
DEVICE_ID
;
}
}
return
deviceId
;
}
}
public
static
void
startIoManager
(
int
idA
)
public
static
void
startIoManager
(
int
idA
)
...
@@ -364,12 +352,12 @@ public class QGCActivity extends QtActivity
...
@@ -364,12 +352,12 @@ public class QGCActivity extends QtActivity
if
(
m_ioManager
.
get
(
idA
)
!=
null
)
if
(
m_ioManager
.
get
(
idA
)
!=
null
)
return
;
return
;
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
;
return
;
UsbIoManager
managerL
=
new
UsbIoManager
(
driverL
,
m_Listener
,
m_userData
.
get
(
idA
));
UsbIoManager
managerL
=
new
UsbIoManager
(
driverL
,
m_Listener
,
_userDataHashByDeviceId
.
get
(
idA
));
m_ioManager
.
put
(
idA
,
managerL
);
m_ioManager
.
put
(
idA
,
managerL
);
m_Executor
.
submit
(
managerL
);
m_Executor
.
submit
(
managerL
);
}
}
...
@@ -398,7 +386,7 @@ public class QGCActivity extends QtActivity
...
@@ -398,7 +386,7 @@ public class QGCActivity extends QtActivity
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////
public
static
boolean
setParameters
(
int
idA
,
int
baudRateA
,
int
dataBitsA
,
int
stopBitsA
,
int
parityA
)
public
static
boolean
setParameters
(
int
idA
,
int
baudRateA
,
int
dataBitsA
,
int
stopBitsA
,
int
parityA
)
{
{
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
false
;
return
false
;
...
@@ -427,7 +415,7 @@ public class QGCActivity extends QtActivity
...
@@ -427,7 +415,7 @@ public class QGCActivity extends QtActivity
////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////
public
static
boolean
close
(
int
idA
)
public
static
boolean
close
(
int
idA
)
{
{
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
false
;
return
false
;
...
@@ -435,8 +423,8 @@ public class QGCActivity extends QtActivity
...
@@ -435,8 +423,8 @@ public class QGCActivity extends QtActivity
try
try
{
{
stopIoManager
(
idA
);
stopIoManager
(
idA
);
m_userData
.
remove
(
idA
);
_userDataHashByDeviceId
.
remove
(
idA
);
m_openedDevices
.
remove
(
idA
);
driverL
.
setPermissionStatus
(
UsbSerialDriver
.
permissionStatusRequestRequired
);
driverL
.
close
();
driverL
.
close
();
return
true
;
return
true
;
...
@@ -462,7 +450,7 @@ public class QGCActivity extends QtActivity
...
@@ -462,7 +450,7 @@ public class QGCActivity extends QtActivity
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
public
static
int
write
(
int
idA
,
byte
[]
sourceA
,
int
timeoutMSecA
)
public
static
int
write
(
int
idA
,
byte
[]
sourceA
,
int
timeoutMSecA
)
{
{
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
0
;
return
0
;
...
@@ -488,51 +476,22 @@ public class QGCActivity extends QtActivity
...
@@ -488,51 +476,22 @@ public class QGCActivity extends QtActivity
*/
*/
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Determine if a device name if valid. Note, it does not look for devices that are already open
//
// Args: nameA - name of device to look for
//
// Returns: T/F
//
////////////////////////////////////////////////////////////////////////////////////////////////////
public
static
boolean
isDeviceNameValid
(
String
nameA
)
public
static
boolean
isDeviceNameValid
(
String
nameA
)
{
{
if
(
m_devices
.
size
()
<=
0
)
for
(
UsbSerialDriver
driver:
_drivers
)
{
return
false
;
if
(
driver
.
getDevice
().
getDeviceName
()
==
nameA
)
for
(
int
iL
=
0
;
iL
<
m_devices
.
size
();
iL
++)
{
if
(
m_devices
.
get
(
iL
).
getDevice
().
getDeviceName
()
==
nameA
)
return
true
;
return
true
;
}
}
return
false
;
return
false
;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Check if the device is open
//
// Args: nameA - name of device
//
// Returns: T/F
//
//////////////////////////////////////////////////////////////////////////////////////////////////////
public
static
boolean
isDeviceNameOpen
(
String
nameA
)
public
static
boolean
isDeviceNameOpen
(
String
nameA
)
{
{
if
(
m_openedDevices
==
null
)
for
(
UsbSerialDriver
driverL:
_drivers
)
{
return
false
;
if
(
nameA
.
equals
(
driverL
.
getDevice
().
getDeviceName
())
&&
driverL
.
permissionStatus
()
==
UsbSerialDriver
.
permissionStatusOpen
)
{
for
(
UsbSerialDriver
driverL:
m_openedDevices
.
values
())
{
if
(
nameA
.
equals
(
driverL
.
getDevice
().
getDeviceName
()))
return
true
;
return
true
;
}
}
}
return
false
;
return
false
;
...
@@ -554,7 +513,7 @@ public class QGCActivity extends QtActivity
...
@@ -554,7 +513,7 @@ public class QGCActivity extends QtActivity
{
{
try
try
{
{
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
false
;
return
false
;
...
@@ -584,7 +543,7 @@ public class QGCActivity extends QtActivity
...
@@ -584,7 +543,7 @@ public class QGCActivity extends QtActivity
{
{
try
try
{
{
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
false
;
return
false
;
...
@@ -615,7 +574,7 @@ public class QGCActivity extends QtActivity
...
@@ -615,7 +574,7 @@ public class QGCActivity extends QtActivity
{
{
try
try
{
{
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
false
;
return
false
;
...
@@ -641,7 +600,7 @@ public class QGCActivity extends QtActivity
...
@@ -641,7 +600,7 @@ public class QGCActivity extends QtActivity
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
public
static
int
getDeviceHandle
(
int
idA
)
public
static
int
getDeviceHandle
(
int
idA
)
{
{
UsbSerialDriver
driverL
=
m_openedDevices
.
get
(
idA
);
UsbSerialDriver
driverL
=
_findDriverByDeviceId
(
idA
);
if
(
driverL
==
null
)
if
(
driverL
==
null
)
return
-
1
;
return
-
1
;
...
@@ -652,21 +611,5 @@ public class QGCActivity extends QtActivity
...
@@ -652,21 +611,5 @@ public class QGCActivity extends QtActivity
else
else
return
connectL
.
getFileDescriptor
();
return
connectL
.
getFileDescriptor
();
}
}
//////////////////////////////////////////////////////////////////////////////////////////////
//
// Get the open usb serial driver for the given id
//
// Args: idA - ID number from the open command
//
// Returns: usb device driver
//
/////////////////////////////////////////////////////////////////////////////////////////////
public
static
UsbSerialDriver
getUsbSerialDriver
(
int
idA
)
{
return
m_openedDevices
.
get
(
idA
);
}
}
}
libs/qtandroidserialport/src/qserialport_android.cpp
View file @
6243dbac
...
@@ -197,7 +197,7 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
...
@@ -197,7 +197,7 @@ bool QSerialPortPrivate::open(QIODevice::OpenMode mode)
if
(
deviceId
==
BAD_PORT
)
if
(
deviceId
==
BAD_PORT
)
{
{
qWarning
()
<<
"Error opening
%s
"
<<
systemLocation
.
toLatin1
().
data
();
qWarning
()
<<
"Error opening"
<<
systemLocation
.
toLatin1
().
data
();
q_ptr
->
setError
(
QSerialPort
::
DeviceNotFoundError
);
q_ptr
->
setError
(
QSerialPort
::
DeviceNotFoundError
);
return
false
;
return
false
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment