1
0
mirror of https://github.com/mik3y/usb-serial-for-android synced 2025-06-28 10:16:45 +00:00

Compare commits

..

289 Commits

Author SHA1 Message Date
Kai Morich
c608aadc59 target sdk 35 2025-04-18 08:37:24 +02:00
Kai Morich
06faad5622 CDC device tests with MCP2221 2025-04-18 08:18:33 +02:00
Kai Morich
52042f8c3e fix off-by-one error in example app (#623) 2025-04-13 07:33:46 +02:00
kai-morich
068fe80c07
Update README.md 2025-03-10 18:30:37 +01:00
Kai Morich
e1018ab31c gradle update 2025-03-09 09:32:14 +01:00
Kai Morich
026355f61e terminate SerialInputOutputManager write thread if read thread terminates (e.g. port closed) 2025-02-15 18:02:15 +01:00
Kai Morich
150174573c gradle + library update 2025-01-29 08:39:26 +01:00
Dmitry Kaukov
9911e141a7
01. Refactored SerialInputOutputManager (#615)
Used separate threads for reading and writing, enhancing concurrency and performance.

Note: before was possible to start `SerialInputOutputManager` with `Executors.newSingleThreadExecutor().submit(ioManager)`. Now you have to use `ioManager.start()`
2025-01-28 21:26:09 +01:00
Holden
2673407f1d
UsbSerialPort Documentation Fixes (#608) 2024-11-09 10:42:55 +01:00
Holden
8584fe4cb8
Allow Unlimited Read Size for Android 9+ (#609) 2024-11-09 09:56:13 +01:00
kai-morich
0b5950c991
catch all Throwables from SerialInputOutputManager.Listener methods (#601) (#606)
to avoid breaking Interface changes, Error from onNewData() is wrapped into Exception when calling onRunError()
2024-10-28 21:12:22 +01:00
kai-morich
9f93e192ca
v3.8.1 2024-10-18 10:25:35 +02:00
Kai Morich
f5380975ce values supported by default setFlowControl() consistent with getSupportedFlowControl() 2024-07-12 09:29:08 +02:00
kai-morich
0a32c3f9e3
v3.8.0 2024-07-05 22:07:44 +02:00
Kai Morich
88ca3f57c4 flowcontrol for ftdi, pl2303, cp210x 2024-07-05 21:18:37 +02:00
Kai Morich
843792001f replace catch+throw with finally !ok, to get rid of UnhandledException shown as error
method declared as throwing only IOException, but unchecked exceptions can always happen
2024-07-05 18:59:54 +02:00
kai-morich
275590027b
Update README.md 2024-06-02 15:09:07 +02:00
Kai Morich
b6e1833270 test coverage 2024-06-02 14:52:39 +02:00
Kai Morich
b794092c81 improved error handling for read() with concurrent close() (#569)
reworked previous solution from change 8b9ad7ef / v3.7.1 because closeInt() was not working any more
2024-06-02 10:16:56 +02:00
Kai Morich
b1362416f0 gradle + library update 2024-06-01 14:46:38 +02:00
Kai Morich
0c0275675f SerialInputOutputManager.writeAsync(): handle SerialTimeoutException 2024-06-01 14:46:38 +02:00
Kai Morich
cab862599d write(): throw SerialTimeoutException if connection still valid 2024-06-01 14:46:38 +02:00
Holden
2fbceb6cc7
Fix ControlLine enum spacing (#577) 2024-06-01 10:07:38 +02:00
kai-morich
a4ee5c2158
Update README.md 2024-05-13 22:19:37 +02:00
Kai Morich
9bc3834eff handle uncaught NPE causing App termination in prolific driver controlline background thread 2024-05-13 22:07:27 +02:00
Kai Morich
28506a9bf9 assert warning cleanup 2024-05-03 08:47:22 +02:00
Kai Morich
8b9ad7efdf improved error handling for read() with concurrent close() (#569)
- isOpen() returns false during concurrent close()
- less tracing in SerialInputOutputManager
2024-04-25 18:24:28 +02:00
Kai Morich
1245293888 harmonize controlTransfer() result comparison 2024-02-18 13:34:08 +01:00
Kai Morich
26a2f9363e target sdk 34
Pending intent and broadcast receiver changed according to sdk 34 release notes.
Permisssion dialog now shown while fragment is paused.
2024-02-18 13:30:50 +01:00
Kai Morich
83646d6955 gradle 8.2 2024-02-18 12:19:46 +01:00
Self Not Found
573c7e41ca
Add read() and write() with length argument (#544)
To reduce array copy
2023-11-08 21:12:30 +01:00
kai-morich
880c0070cb
3.7.0 in README 2023-10-15 17:07:10 +02:00
kai-morich
a1709c3911
mention gradle kotlin DSL (#537) 2023-10-15 17:06:14 +02:00
kai-morich
9c30dc5ffa
update build workflow versions 2023-10-02 19:12:33 +02:00
kai-morich
b06118b156 consolidate get[Supported]ControlLines 2023-10-02 19:05:55 +02:00
kai-morich
de6d5aa384 replace tab with spaces 2023-10-02 15:52:25 +02:00
kai-morich
11ccb5b949 add missing ChromeCcd setParameters 2023-10-02 08:36:50 +02:00
kai-morich
d585ca8be7
add ChromeCcd to readme 2023-10-02 08:29:22 +02:00
Vladimir Serbinenko
2a2463cd12
Add support for Cr50 (Chromebook CCD) (#540) 2023-10-02 08:19:57 +02:00
kai-morich
80a555a189
v3.6.0 in readme 2023-09-06 07:54:30 +02:00
kai-morich
34e6d989fd
fix codacy badge in README.md 2023-08-25 08:51:25 +02:00
kai-morich
35fdeb1e13 improved exception type also for read with timeout 2023-08-24 19:51:47 +02:00
ExPl0siF
399d3c9c2f
Added error management inside read function to get more appropriate exception (#529) 2023-08-24 18:49:29 +02:00
kai-morich
54ff9bfa44 composite CDC devices: get correct ACM data interface from IAD (#499) 2023-08-23 07:55:31 +02:00
kai-morich
7aecce7943 util/HexDump with space separated hex strings 2023-07-31 08:23:35 +02:00
kai-morich
d15f4d52bb move util/HexDump class from example to library 2023-07-31 08:23:35 +02:00
kai-morich
fd8c155ca5
Merge pull request #521 from elicec/master
add gsm modem usb driver
2023-07-31 08:19:24 +02:00
elicec
88b74d716c add GSM Modem usb device driver 2023-07-31 08:57:34 +08:00
kai-morich
e9a38ca891 skip non ACM subclasses for CDC composite devices 2023-07-24 19:12:18 +02:00
kai-morich
a9c835bcb0 gradle 8.0 2023-07-04 20:52:08 +02:00
kai-morich
9bd1f25773 version update in README 2023-03-15 07:47:48 +01:00
kai-morich
083b9ae7fe use correct control index for composite CDC devices with non-consecutive interface IDs (#477) 2023-03-15 07:47:27 +01:00
kai-morich
fd551970be no code changes, just use normal line breaks 2023-03-15 07:47:08 +01:00
kai-morich
5db45548ba probe CDC devices by USB interface types instead of fixed VID+PID
- no more custom prober required for standard CDC devices
- legacy (singleInterface) CDC devices still have to be added by VID+PID
- for autostart VID+PID still have to be added to device_filter.xml
2023-03-11 19:12:42 +01:00
kai-morich
85f64aff96 skip RNDIS related data interfaces in composite CDC devices (#469) 2023-03-11 17:42:13 +01:00
kai-morich
6c648e9f56 have to use MUTABLE to get GRANTED flag at intent extras 2023-03-11 17:42:12 +01:00
kai-morich
dd1b95b852 target sdk 33 2023-03-11 17:42:12 +01:00
kai-morich
7ea76f8899 cdcacm unit test 2023-03-11 17:42:12 +01:00
kai-morich
fbe64fe4be gradle update, coverage working again 2023-03-11 17:42:12 +01:00
kai-morich
8d3326ed66 remove redundant parameter 2023-03-11 17:42:12 +01:00
kai-morich
6ffb666b33
Merge pull request #464 from chobitsfan/patch-2
update adding repository
2023-01-12 17:25:01 +01:00
kai-morich
e3085eacce
clarified condition for alternative repo setting 2023-01-12 17:21:32 +01:00
Chobits Tai
589b8a0fbf
update adding repository 2023-01-04 14:10:54 +08:00
kai-morich
5bb8db02d5
Update README.md
mention Qinheng CH9102
2022-07-22 08:12:37 +02:00
kai-morich
963ae1d243
version update 2022-07-22 08:03:51 +02:00
kai-morich
ab27c19dc3 sdk 31 fixes: pending intent mutability 2022-07-21 21:59:36 +02:00
kai-morich
1091b4d88b improve PL2303 device type detection (#439) 2022-07-21 12:56:59 +02:00
kai-morich
b0e956c5b3
Merge pull request #440 from majbthrd/addCH9102F
added VID/PID for Qinheng CH9102F
2022-07-21 07:58:56 +02:00
Peter Lawrence
82aeccbf1c added VID/PID for Qinheng CH9102F 2022-07-20 17:21:00 -05:00
kai-morich
f8e76c9b3b
updated version in dependency example 2022-07-17 16:05:02 +02:00
kai-morich
1d4e0128c0 added VID/PID for Raspberry Pi Pico SDK 2022-07-05 07:29:25 +02:00
kai-morich
f997a8b68a log prolific device type 2022-05-18 08:27:27 +02:00
kai-morich
cf9bada887 use optimal write buffer size by default + revert gradle update
write buffer: SerialTimeoutException from write() has valid ex.bytesTransferred
gradle 7.1.x creates empty coverage results
2022-04-26 21:40:49 +02:00
kai-morich
b853ac773c test concurrent access on multi-port devices 2022-04-19 22:17:23 +02:00
kai-morich
1f35587739 target-sdk + dependency update 2022-04-19 20:55:34 +02:00
kai-morich
dea836d8ce
Merge pull request #411 from Glass-Imaging/rp2_support
Add support for Raspberry Pi Pico
2022-02-13 13:09:45 +01:00
Doug MacEwen
a2fa5f010a Specify Support is only for Micropython 2022-02-11 11:32:51 -08:00
Doug MacEwen
49ee2d3c8e Add support for Raspberry Pi Pico 2022-02-08 16:08:49 -08:00
kai-morich
896b242be0
switch openjdk distribution for build action 2021-10-06 08:29:15 +02:00
kai-morich
bdfb7d5f6c reordered public members 2021-09-26 08:09:39 +02:00
kai-morich
76f9198c02 more configurable debug log, disabled by default (#389) 2021-09-26 08:02:20 +02:00
kai-morich
d319879386 jitpack with gradle 7 2021-09-21 20:38:32 +02:00
kai-morich
70d4f41268
Create jitpack.yml 2021-09-20 21:23:00 +02:00
kai-morich
a7e88827f0
Update README.md 2021-09-20 21:10:53 +02:00
kai-morich
12095f6b94 coverage for PL2303 variants 2021-08-17 22:51:26 +02:00
kai-morich
1661535d6b
Update build.yml 2021-08-17 17:56:52 +02:00
kai-morich
21cf775281 fix PL2303G product IDs (#383) 2021-08-17 17:29:49 +02:00
kai-morich
cd83951bd1
version update 2021-08-05 17:09:05 +02:00
kai-morich
18e300efa3 add dedicated handling for Ch34x baud rate 921600 2021-07-28 17:49:35 +02:00
kai-morich
76f0260a55
Update version 2021-07-01 18:33:07 +02:00
kai-morich
4e0a6d6d2d
Merge pull request #374 from mik3y/ft2232c
restore FT2232C support
2021-07-01 11:15:34 +02:00
kai-morich
7ffbc73919 restore FT2232C support 2021-07-01 07:45:24 +02:00
kai-morich
c73c38ca82
Merge pull request #366 from ti777777/main
update readme
2021-05-23 15:49:07 +02:00
ti777777
25b5f28a8d update readme 2021-05-23 17:41:33 +08:00
kai-morich
c82cd284ae support PL2303GC/GB/GT/GL/GE/GS
see https://lore.kernel.org/linux-usb/20190213123000.4656-1-charlesyeh522@gmail.com/
2021-05-13 20:55:15 +02:00
kai-morich
2f23bdfb6d custom baud rates for PL2303TA/TB
see https://lore.kernel.org/r/3aee5708-7961-f464-8c5f-6685d96920d6@IEEE.org
2021-05-11 17:30:09 +02:00
kai-morich
22a685e738 target-sdk-version update from 29 to 30 2021-05-09 08:50:29 +02:00
kai-morich
38527730cd
Merge pull request #289 from rusefi/st_cdc
ST CDC
2021-05-08 19:22:38 +02:00
kai-morich
73ef6c5b53
renamed Troubleshooting wiki page to FAQ 2021-04-26 08:04:00 +02:00
kai-morich
5f94a47b63 read w/o timeout now only throws exception on connection lost
partly revert f4166f34, as there might be unkown reasons for empty response
2021-04-20 22:53:53 +02:00
kai-morich
128d1a00b1 new SerialInputOutputManager.start() method
Previously recommended start action `Executors.newSingleThreadExecutor().submit(ioManager)` did not shutdown the Executor, which caused a thread leak. It's still possible to use old style start, as SerialInputOutputManager continues to implement Runnable interface.
2021-04-16 21:55:22 +02:00
kai-morich
848d4e7713 SerialInputOutputManager: use optimal read buffer size to reduce latency for FTDI and CH34x 2021-04-04 20:55:41 +02:00
kai-morich
c917ac5c83 fixed example app crash 2021-04-02 20:36:12 +02:00
kai-morich
f1d73c04dc fixed some warnings 2021-04-02 20:28:41 +02:00
kai-morich
b6e9dbe40f generate unit test coverage xml for codecov upload 2021-03-26 20:25:59 +01:00
kai-morich
f4166f34a0 read w/o timeout now throws exception on connection lost or buffer to small
SerialInputOutputManager already returned connection lost exception, as the next read failed
2021-03-26 18:11:23 +01:00
kai-morich
2d4d2f78a5
Merge pull request #351 from lambdapioneer/master
Use monotonic clock for timeouts
2021-03-18 08:11:26 +01:00
Daniel Hugenroth
b8c3057967 Use monotonic clock for timeouts 2021-03-16 22:39:00 +00:00
kai-morich
c06ccf70bc really set thread priority in SerialInputOutputManager (#349) 2021-02-27 13:59:30 +01:00
kai-morich
cbed086279 fix write timeout calculation 2021-02-14 14:16:25 +01:00
kai-morich
4ffcc8d0fb simplify write timeout handling 2021-02-13 21:07:21 +01:00
kai-morich
f60414f8ec improve write timeout handling
Return type of write() method changed to void. The return value was redundant before, as it always was the request length or an exception was thrown.

If timeout is reached, write() now throws a SerialTimeoutException with ex.bytesTransferred filled with known transferred bytes.

Added CommonUsbSerialPort.getReadEndpoint() and .getWriteEndpoint() to assist in setting the optimal write buffer size with port.setWriteBufferSize(port.getWriteEndpoint().getMaxPacketSize()).

By default the write buffer size is > MaxPacketSize and the Linux kernel splits writes in chunks. When the timeout occurs, it's unknown how many chunks have already been transferred and the exception typically stores 0. With optimal write buffer size, this value is known and stored in SerialTimeoutException, but due to more kernel round trips write() might take slightly longer().
2021-02-07 16:37:01 +01:00
kai-morich
85d0348844 improve error quality + test for PR #339 2021-01-31 19:58:59 +01:00
kai-morich
fc610a9764 IntDef Parity for better warnings
but no @Intdef for databits, stopbits as these are frequently used with numbers instead of constants
remove redundant modifiers
2021-01-16 23:21:10 +01:00
kai-morich
5519182256
Merge pull request #339 from ybs-github/master
catch exception thrown by `close()` inside `open()`
2021-01-10 10:04:27 +01:00
kai-morich
a807ea91f0
Merge pull request #333 from IljaK/patch-1
Debug mode disable
2020-12-16 20:01:48 +01:00
Ilja
911cf96ba0
Debug mode disable
Ability to disable DEBUG Logging for in/out bytes.
2020-12-16 14:24:43 +02:00
Yehezkiel Syamsuhadi
ebc8d791fc catch exception thrown by close() 2020-12-14 10:23:29 +11:00
kai-morich
6b7d358f1f
move codacy project 2020-12-12 11:40:16 +01:00
kai-morich
2d3f5e73ab
Merge pull request #330 from Sharabaddin/master
dependencies example with current version instead of `Tag` that has to be replaced by each user
2020-12-10 20:45:35 +01:00
Sharabaddin
6ff679d989
ez for start
and fix potential problems
2020-12-10 14:03:45 +02:00
kai-morich
69330e9168
link feature matrix 2020-10-17 12:31:10 +02:00
kai-morich
115fb407b4 coverage fix, gradle update 2020-10-14 20:36:49 +02:00
kai-morich
768f716600 new setBreak() method 2020-10-14 20:36:49 +02:00
kai-morich
1e75f91467 slightly more coverage, local coverage report, dependency update 2020-10-12 21:28:50 +02:00
kai-morich
08a93ec530 PL2303 fix initial input control line values 2020-10-07 21:40:07 +02:00
kai-morich
732e138630 PL2303(HX) support non-standard baud rates 2020-09-28 21:12:50 +02:00
kai-morich
1adf2a9b98 PL2303 throw error on unsupported baud rates
instead of silently falling back to 9600 baud
2020-09-27 09:03:37 +02:00
kai-morich
d63a24762d mention other CP210x devices, remove CP2110 which is a HID device 2020-09-22 07:52:18 +02:00
kai-morich
26999e3626 read with timeout now throws error on connection lost, e.g. device disconnected
and similar connection lost detection for prolific input control lines
2020-09-12 21:17:52 +02:00
kai-morich
c53c3ed0ae check read buffer size 2020-09-06 09:48:10 +02:00
kai-morich
6f4cd0313c FTDI read() now waits until timeout
previously returned after periodic FTDI status response (default 16 msec)
2020-09-05 12:00:37 +02:00
kai-morich
80e8eb8a60 iomanager with configurable threadpriority and higher default to prevent data loss 2020-08-31 22:40:28 +02:00
kai-morich
f443d1f012 iomanager with configurable buffer size 2020-08-31 22:40:28 +02:00
kai-morich
4f2d6c73a4
list all supported FTDI devices 2020-08-24 17:32:03 +02:00
kai-morich
698f590d58 restored UsbId.FTDI_FT231X
same ID for FT230X, FT231X, FT234XD
tested with FT230X
2020-08-23 20:44:34 +02:00
kai-morich
f36756dc86
Update CHANGELOG.txt 2020-08-20 07:49:50 +02:00
kai-morich
73d669c4dc remove FT231X also from device_filter.xml 2020-08-01 12:24:54 +02:00
kai-morich
57d10a08dd
Merge pull request #297 from mik3y/v3
ftdi rewrite, MIT license, ...
2020-08-01 10:21:54 +02:00
kai-morich
a664082f23 throw UnsupportedOperationException instead of returning false 2020-08-01 10:06:51 +02:00
kai-morich
954295456c rebase new FTDI baudrate test 2020-07-30 17:52:18 +02:00
kai-morich
2d13b90f59 move from LGPL to MIT license (#244)
moving away from LGPL possible, as the FTDI driver is rewritten and not based any more on LGPL code from libftdi.
2020-07-29 11:03:26 +02:00
kai-morich
e496195bd9 rewrite ftdi driver without LGPL code from libftdi 2020-07-27 17:39:01 +02:00
kai-morich
e0ed25b85f CH341A readme update 2020-07-27 17:38:16 +02:00
kai-morich
963729924b mention close of UsbDeviceConnection in javadoc comment 2020-07-21 08:20:22 +02:00
kai-morich
ce73857825 slightly more tests 2020-07-19 19:47:13 +02:00
kai-morich
a2f0097092 improve control line example 2020-07-19 19:16:05 +02:00
kai-morich
8eaf3f5c5f tests UsbDeviceConnection close behavior
and extract test utilities
2020-07-18 20:48:27 +02:00
kai-morich
a1e58b9843 implement CP21xx input control lines
open() CP21xx without RTS, DTR set
2020-07-04 15:31:58 +02:00
kai-morich
7423fd9d79 new getControlLines() and getSupportedControLines() methods
getControlLines() requires less USB calls than calling getRTS() + ... + getRI() individually.
getSupportedControlLines() tells you, which control lines are supported by a driver. Previously you had to check the driver implementation.
2020-06-30 18:10:02 +02:00
kai-morich
13df128226 implement CH34x input control lines 2020-06-27 11:53:12 +02:00
kai-morich
06d1041738 added CH341A support 2020-06-27 08:46:23 +02:00
rusefi
aee7fc1b9d ST CDC
See https://www.the-sz.com/products/usbid/index.php?v=0483&p=&n=
2020-06-24 20:38:52 -04:00
kai-morich
3e7fd9a748 add vectorDrawables.useSupportLibrary=true to sample app 2020-06-11 13:15:00 +02:00
kai-morich
735fa3d70f make all SerialPort classes public
and test FtdiSerialPort methods
2020-06-10 19:09:34 +02:00
kai-morich
33149b66fd
Merge pull request #281 from bensadiku/master
Expose a isOpen method to check on the current state of the connection
2020-05-19 21:10:08 +02:00
Behxhet Sadiku
37324c6b0f Expose isOpen on CommonUsbSerialPort 2020-05-19 20:50:42 +02:00
kai-morich
ca78840144 example app with event-based or direct read 2020-04-08 22:21:26 +02:00
kai-morich
2354f93354 modernize example app 2020-03-29 16:56:26 +02:00
kai-morich
cffe54e15c test control lines 2020-03-21 18:01:05 +01:00
Kai Morich
5096d6940c relax CH340 initialization
controlIn(0x95, 0x0706) result includes control line values
2020-03-08 16:06:44 +01:00
kai-morich
2cad1fd5a2 fix CP2102N initialization
do not send SET_BAUDDIV command. It fails on CP2102N and CP2102/5 work without
2020-03-01 13:54:35 +01:00
kai-morich
17c3d40605 align device_filter.xml with devices recognized by DefaultProber 2020-02-29 19:15:14 +01:00
kai-morich
2a77ebf8b9 fix ch340 initialization 2020-02-03 20:36:56 +01:00
kai-morich
bbed92eafb support multi-port CDC devices 2020-01-10 08:02:56 +01:00
kai-morich
ce97a3408b reuse UsbRequest
less LogCat output
2019-12-13 21:13:48 +01:00
kai-morich
7b578918b0 support FTDI control lines for multi-port devices 2019-11-23 13:24:28 +01:00
uholeschak
6b32e25e9c Fixed modem status
Signed-off-by: kai-morich <mail@kai-morich.de>
2019-11-23 13:23:10 +01:00
uholeschak
21e96594d2 Added missing functions: - latency timer - modem lines
Signed-off-by: kai-morich <mail@kai-morich.de>
2019-11-23 13:22:42 +01:00
kai-morich
a954db1b94 readme with sync + async read 2019-11-16 00:09:41 +01:00
kai-morich
6d3ed12ca8
Create build.yml 2019-11-15 23:57:39 +01:00
kai-morich
e2e9df8463 reimplement read timeout 2019-11-15 21:45:22 +01:00
kai-morich
669ab48e0f resolve merge issue 2019-11-15 07:51:03 +01:00
kai-morich
8c559ef892
Merge pull request #240 from tva-TIS/master
DTR and RTS support for CP21xx drivers
2019-11-14 19:40:45 +01:00
Tim Vahlbrock
89ad5be9c3 Improved DTR and RTS support. DTR and RTS can now be queried after transmission. Added usage of existing methods and new constants. 2019-11-14 14:44:39 +01:00
Tim Vahlbrock
92b16a8c24 Merge branch 'master' of https://github.com/mik3y/usb-serial-for-android 2019-11-14 14:15:39 +01:00
kai-morich
fd2055791a added proguard rules
now they are part of the .aar library, before you had to add them to each release app
2019-11-13 18:49:27 +01:00
kai-morich
24187b3af6 refactor duplicated code in close method 2019-11-09 22:48:00 +01:00
kai-morich
5767298636 refactor duplicated read/write methods 2019-11-09 20:26:50 +01:00
kai-morich
e1b62cf675 write + purge tests, remove unused read buffer code 2019-11-03 19:34:14 +01:00
kai-morich
5c6748e1b8 improve setParameter() error handling
harmonize exception messages, more UI friendly messages
distinguish IllegalArgumentException and UnsupportedOperationException
2019-11-02 13:49:08 +01:00
kai-morich
18b5b6e648 unify open() error handling, more tests, minor cleanup 2019-11-02 13:09:15 +01:00
kai-morich
6869eff88a revert previous usbRequest.cancel() removal
Combine usbRequest.cancel() and releaseInterface to interrupt read() and terminate SerialInputOutputManager.
UsbRequest.cancel() immediately interrupts read() on newer Android versions.
With releaseInterface() only, some hickup are observed on fast reconnect.
Keep releaseInterface() as only this interrupts read() on older Androids.
2019-11-02 12:46:45 +01:00
Tim Vahlbrock
7eaea45068 Added DTR and RTS support for cp21xx driver 2019-10-28 13:20:34 +01:00
TVa[TIS]
e20b3cc913
Merge pull request #1 from mik3y/master
Update from upstream
2019-10-28 13:16:12 +01:00
kai-morich
9ea936b14a improve close handling
Use releaseInterface to interrupt read() and terminate SerialInputOutputManager. Previously some drivers used usbRequest.cancel() but this does not interrupt read() on older Android.

Added connection check to read(). Before Android 8.0 request.initialize() did not check usbConnection, which can lead to native crash if NULL
2019-10-27 21:32:38 +01:00
Kai Morich
b3631dff58 README with SerialInputOutputManager for read() and port for write()
test the usually not used read/write variants
2019-10-26 21:32:28 +02:00
Kai Morich
800381e370 CdcAcm driver: cancel read() on close() 2019-10-26 20:37:06 +02:00
Kai Morich
fac8c9f340 test nonstandard baud rates 2019-10-26 15:40:40 +02:00
Kai Morich
f7399c2aad more coverage tests
purgeHwBuffers: adjust parameter names to match read/write methods and actual behavior
2019-10-25 22:23:00 +02:00
Kai Morich
37059b1a27 reduce non covered code
move HexDump class from library to example
remove unused UsbSerialRuntimeException
2019-10-21 21:04:58 +02:00
Kai Morich
ac1fe40793 manage USB permission intent 2019-10-21 20:56:13 +02:00
kai-morich
6a50595274
Merge pull request #231 from mik3y/coverage
show code coverage
2019-10-20 22:52:58 +02:00
Kai Morich
54a3db115f show code coverage 2019-10-20 22:41:55 +02:00
Kai Morich
9755a4cb87 release preparations 2019-10-12 11:37:35 +02:00
Kai Morich
2bee5b930b build with jitpack 2019-10-06 17:52:17 +02:00
Kai Morich
508c39e66a README cleanup 2019-10-06 10:27:41 +02:00
kai-morich
6e58180f91
Merge pull request #230 from kai-morich/async
Async
2019-10-05 14:12:27 +02:00
Kai Morich
0d48ed04e7 Always use async read, as bulkTransfer can cause data loss. Increase API version to 17 because async read only works reliably since Android 4.2 (http://b.android.com/28023) 2019-10-05 10:35:15 +02:00
Kai Morich
e527afdf35 compile+target sdk 28, gradle 4.6 2019-10-05 10:35:15 +02:00
kai-morich
f54dd65624
Merge pull request #212 from kai-morich/multiport
support ft_232h, cp210_ multiport devices
2019-10-05 10:32:27 +02:00
Kai Morich
61b272b8b6 support ft_232h, cp210_ multiport devices
harmonize claimInterface() error handling
cancel read() on close()
2019-10-05 10:27:11 +02:00
Kai Morich
0ea5b282b7 implement async read for all devices 2019-10-05 10:27:11 +02:00
Kai Morich
adb22f718e build tools update; instrumented device test 2019-10-05 10:27:11 +02:00
kai-morich
c89ca2c96a
Merge pull request #195 from kai-morich/ch340-parameter
CH34x: data bits, parity, stop bits
2019-10-04 16:50:16 +02:00
kai-morich
d7147201de
Merge pull request #188 from kai-morich/ch340-async
enable async read for CH340 as in CDC driver to prevent data loss at high baud rates
2019-10-04 16:49:50 +02:00
kai-morich
eb2de17af8
Merge pull request #170 from kai-morich/ftdi-async
enable async read for FTDI + prevent loss of last packet if full
2019-10-04 16:49:03 +02:00
kai-morich
deabc510c1
Merge pull request #189 from kai-morich/cdc-endpoints
support USB devices with other non CDC related endpoints, e.g. when u…
2019-10-04 16:48:03 +02:00
kai-morich
f1c147125f
Merge pull request #156 from grevaillot/master
ch34xSerialDriver: support more baudrates.
2019-10-04 16:45:34 +02:00
Kai Morich
9c1ca288ae CH34x: data bits, parity, stop bits
CP21xx: mark+space
all devices: return error on unsupported parameters
2018-01-20 13:09:29 +01:00
Kai Morich
df4e9174cb enable async read for CH340 as in CDC driver to prevent data loss at high baud rates 2017-11-03 22:52:32 +01:00
Kai Morich
fcd8596bdd enable async read for FTDI as in CDC driver. this prevents -1 error from bulkTransfer() when receiving data in multiple packets, e.g. if consumed to slow at high baud rates.
prevent loss of last packet if full
2017-04-01 23:15:55 +02:00
Kai Morich
608c67499a support USB devices with other non CDC related endpoints, e.g. when using ARM mbed DAPLink firmware 2017-02-17 22:03:32 +01:00
Guillaume Revaillot
73b8b73133 ch34xSerialDriver: support more baudrates.
allow to use 57600bps with ch34x based adapter by using dynamic computation of baudrate configuration, based on linux kernel's driver.
2016-11-16 13:58:01 +01:00
mike w
b96f9ca7a2 Merge pull request #108 from Scypho/master
adding support for USB devices with only one channel
2016-09-11 16:32:00 -04:00
mike w
6d8c40a71c Merge pull request #137 from shanet/readme_fixes
Readme fixes
2016-09-11 16:30:05 -04:00
mike w
3d6c092e07 Merge pull request #147 from jmiguelrc/add_support_arduino_micro
Add support for Arduino Micro (Issue #146)
2016-09-11 16:29:18 -04:00
João Costa
458ed446fb Add support for Arduino Micro 2016-07-08 16:29:55 +01:00
shane tully
1ef426920f fix example code in README 2016-05-01 18:43:30 -07:00
shane tully
3479892809 fix link to device_filter.xml and remove trailing whitespace in README 2016-05-01 18:31:40 -07:00
mike w
ccc8e8d3f0 Merge pull request #96 from marcosdiez/dtr_and_rts
User can now set DTR and RTS on the fly
2016-03-23 19:31:56 -04:00
mike w
f53c5e548a Merge pull request #103 from xeonfusion/patch-1
Update ProlificSerialDriver.java
2016-03-23 19:31:24 -04:00
mike w
b9b9c7268f Merge pull request #121 from xseignard/master
Added CH34x driver
2016-03-23 19:27:55 -04:00
xseignard
e0d9c3c091 Added CH34x driver 2015-12-09 02:29:30 +01:00
mike w
a213f06ad0 Merge pull request #111 from sureshjoshi/master
Updating Gradle project to > 1.0.0
2015-06-23 10:05:45 -04:00
SJ
9d48757285 - Updating Gradle project to > 1.0.0
- Updated .gitignore with Github ignore settings
- Updated build tools and SDK versions to 22
- Migrated .gradle files from pre-1.0.0 to post-1.0.0
2015-06-23 00:24:43 -04:00
Jens Peter Schroer
45b8364103 adding support for USB devices with only one channel 2015-05-12 12:23:40 +02:00
xeonfusion
50dda78a63 Update ProlificSerialDriver.java
Missing Parity case in switch statement causes the Prolific driver code to crash when Parity is set to Even.
2015-03-13 15:50:14 +04:00
Marcos Diez
e04c5f8877 User can now set DTR and RTS on the fly 2015-01-17 14:34:31 +02:00
mike w
228c7936eb Merge pull request #85 from treymarc/patch-1
remove uncessary call to mWriteBuffer.position()
2014-11-10 23:10:04 -05:00
Trey Marc
b251430e02 remove uncessary call to mWriteBuffer.position()
assigne len with mWriteBuffer.position() before testing
2014-11-10 23:35:03 +01:00
mike w
ef13784f4f Fix off-by-one error in filterStatusBytes.
Closes #74.
2014-11-10 10:24:53 -05:00
mike w
f6f7e2600a Merge pull request #82 from treymarc/patch-1
Correct USART init for stm32 autobauding
2014-11-10 09:38:27 -05:00
mike w
37bfca8908 Merge pull request #84 from diegoherranz/master
Fix typo on link to usbSerialExamples
2014-11-04 10:43:03 -05:00
Diego Herranz
49af3725d0 Fix typo on link to usbSerialExamples 2014-11-04 16:31:58 +01:00
treymarc
4ccaff47b1 source formating :replaced tab 2014-10-27 22:03:58 +01:00
Trey Marc
8f439384a7 Correct USART init for stm32 autobauding
Hello,

I had some headache trying to figure out the issue when flashing some stm32 mcu over uart [1] 

With the above changes i can now flash stm32 devices correctly.

regards,

1 : http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf
2014-10-27 21:26:37 +01:00
bens-unit01
09c84a4a3c added support to retrieve the device serial number 2014-09-16 11:50:50 -07:00
mike wakerly
dbdf95525e maven: Update group name and artifact id. 2014-09-08 11:22:17 -07:00
mike wakerly
06582e68ad Add Maven Central uploadArchives target.
Issue #70.
2014-09-08 11:02:45 -07:00
mike wakerly
c842a1d5f6 Fix LICENSE file.
Source and docs have always listed LGPL v2.1; v3 version was
originally added in error.
2014-09-08 11:02:45 -07:00
mike wakerly
0b65b42f84 Update build tools. 2014-09-08 11:02:45 -07:00
mike w
64652c1971 Merge pull request #77 from chiragnagpal/master
Update README.md
2014-09-01 09:52:47 -07:00
Chirag Nagpal
942adc18a2 modified: README.md 2014-09-01 21:40:26 +05:30
mike wakerly
4a226864b0 Merge branch 'develop' 2014-06-24 13:47:22 -07:00
mike wakerly
a9c42b96e1 Update build tools. 2014-06-24 13:45:45 -07:00
mike wakerly
6ef85d04c1 cdc: Special case read timout == Integer.MAX_VALUE.
Some systems return 0 from read() when the device has been disconnected.
The only way to detect this is to 'never' expect a timeout.
2014-06-14 12:55:28 -07:00
mike wakerly
8e8ded4a9c cdc: Add async read capability. 2014-06-14 12:55:28 -07:00
mike wakerly
95592f984a Convert to gradle. 2014-06-14 12:55:24 -07:00
mike wakerly
9c577949b0 Add ProbeDevice. 2014-06-14 12:55:24 -07:00
mike wakerly
66eec6c870 open(): Set mConnection eagerly, and clear on failure.
Similar to CdcAcmSerialDriver. Issue #53.
2014-06-14 12:55:24 -07:00
mike wakerly
61714523fc Fix open().
Issue #53.
2014-06-14 12:55:24 -07:00
mike wakerly
a331afaa1a UsbSerialProber: Expose getDefaultProbeTable(). 2014-06-14 12:55:24 -07:00
mike wakerly
e4b3ed610c UsbSerialPort: Add port number to interface. 2014-06-14 12:55:24 -07:00
mike wakerly
8a152071b4 Update README.md 2014-06-14 12:55:21 -07:00
Felix Hädicke
e62e95be2e Rename Cp2102SerialDriver to Cp21xxSerialDriver and add Usb IDs for more Silabs devices
Conflicts:
	UsbSerialLibrary/src/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java
	UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbId.java
	UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialProber.java
2014-06-14 12:53:34 -07:00
mike wakerly
8abc3be1f1 API refactor, adding UsbSerialPort interface.
- UsbSerialDriver is now a discrete interface.
- UsbSerialDriver provides getPorts() method, returning one or
  more usable UsbSerialPort.
- Use of UsbDeviceConnection is deferred until open(),
  making it possible to probe for ports without
  permission from Android.

(Thanks to Felix for inspiring some of these changes).
2014-06-14 12:53:34 -07:00
mike w
d9db4e3607 Merge pull request #63 from venkateshshukla/patch-1
Corrected USB Control Request Type definitions
2014-05-18 11:47:47 -07:00
Venkatesh Shukla
6ef7e80f81 Corrected USB Control Request Type definitions
Even though they are not being used, might as well set them right. The other option would be to delete these four lines. For reference, http://www.beyondlogic.org/usbnutshell/usb6.shtml

SIgned-off-by Venkatesh Shukla <venkatesh.shukla.eee11@iitbhu.ac.in>
2014-05-18 22:47:17 +05:30
mike w
5c8a6556a9 Update README.md 2014-03-03 23:44:06 -08:00
mike w
c212114340 Merge pull request #39 from vocaro/master
Throw exception on bad parameters to Prolific
2013-11-06 18:34:16 -08:00
Trevor Harmon
275589eeb6 Throw exception on bad parameters to Prolific 2013-11-06 16:02:05 -08:00
mike wakerly
7e9589d582 Add wiki links. 2013-10-28 18:44:33 -07:00
mike wakerly
d207612d4d Fix for botched merge 730ed711. 2013-10-28 17:20:47 -07:00
Arthur Benemann
d272021034 Adding support for the new FT231X IC from FTDI
To use it as a serial-USB bridge it's the same thing as a FT232 IC
2013-10-28 17:06:51 -07:00
mike wakerly
f878d5db80 Classpath update from ADT. 2013-10-28 17:06:51 -07:00
Felix Hädicke
730ed711e1 UsbSerialPort: add purgeHwBuffers method.
Consolidates following changes from Felix (newest first):
  1123807 Rename flushHwBuffers to purgeHwBuffers
  3eb145d Use UsbSerialPort instead of UsbSerialDriver in SerialInputOutputManager
  f91a974 Return true in flushHwBuffers default implementation if there is nothing to flush
  69c0b59 Implement flushHwBuffers for Cp2102 driver
  4a41bd9 Rename UsbSerialPort.flush function to flushHwBuffers
  c908da4 Refactoring: Make ProlificSerialDriver a subclass of CdcAcmSerialDriver
  39cb480 Refactoring: New UsbSerialPort interface
  d542f64 Refactoring: Do not require permission to USB device when probing
  9a13571 Support flushing non-written / non-read data
2013-10-28 17:05:22 -07:00
Felix Hädicke
2bdcbfd16e Device support: PL2303.
This change consolidates changes made by Felix Hädicke:
  https://code.google.com/r/felixhaedicke-usb-serial-for-android/

Upstream changes merged (newest first):
  3b6fb7f Rename parameter variables
  74d858f Remove unused constant
  bab0691 Make consts private
  381f28c Remove test code
  bdd9a64 Suppport for reading CTS / DSR / CD / RI status
  ccf807a Remove "Untested" TODO comment (no longer true)
  1b1ccce Remove unneeded commented out function ctrlIn
  5f853db Make parameter fields private
  d8c6758 Fix for wrong constant being used when turning off DTR
  05ff566 Fix for NullPointerException
  9d2c9af Reenabled device type detection
  307ce72 Device support: PL2303.

Original commit message:
  New driver for Prolific PL2303

  A new driver for Prolific PL2303 devices, which is more or less a port
  of the "pyprolific" driver from https://github.com/eblot/pyftdi
2013-10-28 16:41:57 -07:00
mike w
4b4499f369 Update README.md 2013-09-13 09:34:09 -07:00
mike w
d7ba0be9d4 Update README.md 2013-09-13 09:33:53 -07:00
mike w
e2c042fc89 Update README.md 2013-09-13 09:29:42 -07:00
Felix Hädicke
eca40d6b11 FTDI driver: Filter status bytes
Filter status bytes at the beginning of every USB package received from
FTDI serial adapters
2013-05-22 13:08:05 -07:00
mike wakerly
b709823906 Update demo activity.
Demo now consists of two activities:
  - DeviceListActivity shows all usb devices (including unsupported ones)
    in a ListView.
  - SerialConsoleActivity dumps the data stream for a device selected in
    DeviceListActivity.
2013-05-22 13:04:05 -07:00
mike wakerly
b07bbcf292 Eclipse settings: adjust import order to match Android style. 2013-05-22 12:58:24 -07:00
mike wakerly
386b98ac46 UsbSerialProber: API cleanup; support multi-port devices.
acquire() is renamed and deprecated in favor of findFirstDevice().

findAllDevices() is added as new functionality.

Internally, probe() now returns a list, allow a (future) multi-port
device to return multiple drivers, one for each port (googlecode
issue #14).
2013-05-22 11:45:20 -07:00
mike wakerly
3991b2c7c7 Fix typo. 2013-05-22 10:47:45 -07:00
mike wakerly
22c4c9b280 CDC: fix incorrect stop bits (thanks vovkab). 2013-04-07 23:06:30 -07:00
mike wakerly
beccfbb409 Add Leaflabs Maple to CDC probe table. 2013-04-07 22:53:21 -07:00
mike wakerly
f73b485418 Remove setBaudRate(); do not touch line config in open().
Callers should call setParameters() after open() (and now have the option of
skipping this step where feasible.)
2013-04-07 22:42:40 -07:00
mike wakerly
fe2eb8278b UsbSerialDriver is an interface once again.
Code shared among the existing drivers is moved into CommonUsbSerialDriver.
2013-02-19 13:28:26 -08:00
ducky-hong
2b3528b425 added support for cp2102 device 2013-02-07 15:05:13 -08:00
mike wakerly
c3ac464ab3 Rename LUFA ids (which use Ateml's vendor code) to match Linux usb.ids 2013-01-16 09:49:21 -08:00
Elliot Smith
890e543e0c Added support for LUFA Virtual Serial Example
Closes issue #8.

Signed-off-by: mike wakerly <opensource@hoho.com>
2013-01-15 17:59:23 -08:00
mike wakerly
dfea06412f Remove stray 'R' import. 2012-12-10 10:41:51 -08:00
mike wakerly
f35468e0f8 Rewind output buffer before copying. 2012-12-07 17:47:17 -08:00
mike wakerly
3f271aab81 Add setParameters() method and deprecate setBaudRate().
Interface is similar to javax.comm.
2012-12-07 14:08:03 -08:00
mike wakerly
0424133e58 Update changelog; add BuildInfo. 2012-11-28 10:35:56 -08:00
mike wakerly
111707c92f Driver interface: add methods for CD, CTS, DSR, DTR, RI, and RTS. 2012-11-28 10:24:47 -08:00
mike wakerly
a3b9c27f84 Update Eclipse prefs. 2012-11-13 10:54:35 -08:00
123 changed files with 12396 additions and 2493 deletions

17
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Build with Gradle
run: ./gradlew assembleDebug

50
.gitignore vendored
View File

@ -1,9 +1,43 @@
UsbSerialLibrary/bin
UsbSerialLibrary/gen
# Built application files
*.apk
*.ap_
UsbSerialExamples/bin
UsbSerialExamples/gen
UsbSerialLibrary/dictionary.txt
UsbSerialLibrary/local.properties
UsbSerialLibrary/proguard-project.txt
UsbSerialLibrary/build.xml
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
# Studio/Gradle
*.iml
.gradle/
build/
# User-specific stuff:
.idea/workspace.xml
.idea/tasks.xml
.idea/dictionaries
.idea/markdown-navigator*.xml
# Sensitive or high-churn files:
.idea/dataSources.ids
.idea/dataSources.xml
.idea/sqlDataSources.xml
.idea/dynamic.xml
.idea/uiDesigner.xml
# Gradle:
.idea/gradle.xml
.idea/libraries
.idea/jarRepositories.xml
# Eclipse/Android/Misc
.metadata/
local.properties
*.DS_Store
proguard/
jacoco.exec

9
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,9 @@
caches
codeStyles
libraries
workspace.xml
androidTestResultsUserPreferences.xml
appInsightsSettings.xml
deploymentTargetDropDown.xml
deploymentTargetSelector.xml
other.xml

6
.idea/AndroidProjectSystem.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

6
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

61
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="androidx.annotation.Nullable" />
<option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="18">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="android.annotation.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
<item index="12" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
<item index="13" class="java.lang.String" itemvalue="io.reactivex.annotations.Nullable" />
<item index="14" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.Nullable" />
<item index="15" class="java.lang.String" itemvalue="org.jspecify.nullness.Nullable" />
<item index="16" class="java.lang.String" itemvalue="jakarta.annotation.Nullable" />
<item index="17" class="java.lang.String" itemvalue="org.jspecify.annotations.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="17">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="android.annotation.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
<item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
<item index="12" class="java.lang.String" itemvalue="io.reactivex.annotations.NonNull" />
<item index="13" class="java.lang.String" itemvalue="io.reactivex.rxjava3.annotations.NonNull" />
<item index="14" class="java.lang.String" itemvalue="jakarta.annotation.Nonnull" />
<item index="15" class="java.lang.String" itemvalue="org.jspecify.nullness.NonNull" />
<item index="16" class="java.lang.String" itemvalue="org.jspecify.annotations.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

17
.idea/runConfigurations.xml generated Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,3 +1,20 @@
2011-12-28 mike wakerly <opensource@hoho.com>
For recent changelog look here:
* https://github.com/mik3y/usb-serial-for-android/releases
* Initial release.
v0.2.0 (unreleased)
* Gradle, Android Studio support.
* New driver: CP2102 (thanks Ducky).
* New prober support: LUFA Virtual Serial, Leaflabs Maple, Teensyduino.
* New driver methods: getCD, getCTS, getDSR, getDTR, setDTR, getRI, getRTS,
setRTS.
* API change: setBaudrate() has been removed; use setParameters().
* API change: open() no longer implicitly sets the baud rate. Clients should
call setParameters() immediately after open(), when necessary.
* Library version is available in `com.hoho.android.usbserial.BuildInfo`.
v0.1.0 (2012-10-12)
* New driver: CdcAcmSerialDriver.
* Better tuned read and write buffer sizes.
v0.0.1 (2011-12-28)
* Initial release.

View File

@ -1,165 +1,22 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
MIT License
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Copyright (c) 2011-2013 Google Inc.
Copyright (c) 2013 Mike Wakerly
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

260
README.md
View File

@ -1,81 +1,179 @@
# usb-serial-for-android
Library for talking to Arduinos and other USB serial devices on Android, using
USB Host mode and Android 3.1+
Homepage: http://code.google.com/p/usb-serial-for-android
## About
This project provides an Android userspace driver for USB serial devices. You
can use it to talk to your Arduino, or any other supported serial devices.
## Usage
Download the sources. Inside you will find two Eclipse projects:
* UsbSerialLibrary - the main library code, an "Android Library" project.
* UsbSerialExamples - a demo Android application
In Eclipse, open "File", "Import", and then select "General, "Existing Projects
into Workspace".
Navigate to the directory you just checked out and import both projects. Then
run the demo application.
## Compatible Serial Devices
Supported and tested:
* FT232R
Possibly supported (untested):
* FT232H
* FT2232D
* FT2432H
Unsupported (send patches!):
* Arduino Uno (CDC)
## Compatible Android Devices
Supported and tested:
* Motorola Xoom, Android 3.1/3.2
Possibly supported (untested):
* Samsung Galaxy Tab 10.1
## License and Copyright
This library is licensed under LGPL Version 2.1. Please see LICENSE.txt for the
complete license.
Copyright 2011, Google Inc. All Rights Reserved.
Portions of this library are based on libftdi
(http://www.intra2net.com/en/developer/libftdi). Please see
FtdiSerialDriver.java for more information.
## Contributing
Patches are welcome. We're especially interested in supporting more devices.
Please open a bug report.
## Credits
Author/maintainer: mike wakerly <opensource@hoho.com>
Contributors:
* Robert Tsai <rob@tsaiberspace.com> (code review)
[![Actions Status](https://github.com/mik3y/usb-serial-for-android/workflows/build/badge.svg)](https://github.com/mik3y/usb-serial-for-android/actions)
[![Jitpack](https://jitpack.io/v/mik3y/usb-serial-for-android.svg)](https://jitpack.io/#mik3y/usb-serial-for-android)
[![Codacy](https://app.codacy.com/project/badge/Grade/ef799bba8a7343818af0a90eba3ecb46)](https://app.codacy.com/gh/kai-morich/usb-serial-for-android-mik3y/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![codecov](https://codecov.io/gh/mik3y/usb-serial-for-android/branch/master/graph/badge.svg)](https://codecov.io/gh/mik3y/usb-serial-for-android)
# usb-serial-for-android
This is a driver library for communication with Arduinos and other USB serial hardware on
Android, using the
[Android USB Host Mode (OTG)](http://developer.android.com/guide/topics/connectivity/usb/host.html)
available since Android 3.1 and working reliably since Android 4.2.
No root access, ADK, or special kernel drivers are required; all drivers are implemented in
Java. You get a raw serial port with `read()`, `write()`, and [other functions](https://github.com/mik3y/usb-serial-for-android/wiki/FAQ#Feature_Matrix) for use with your own protocols.
## Quick Start
**1.** Add library to your project:
Add jitpack.io repository to your root build.gradle:
```gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
```
Starting with gradle 6.8 you can alternatively add jitpack.io repository to your settings.gradle:
```gradle
dependencyResolutionManagement {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
```
If using gradle kotlin use line
```gradle.kts
maven(url = "https://jitpack.io")
```
Add library to dependencies
```gradle
dependencies {
implementation 'com.github.mik3y:usb-serial-for-android:3.9.0'
}
```
**2.** If the app should be notified when a device is attached, add
[device_filter.xml](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples/src/main/res/xml/device_filter.xml)
to your project's `res/xml/` directory and configure in your `AndroidManifest.xml`.
```xml
<activity
android:name="..."
...>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
```
**3.** Use it! Example code snippet:
open device:
```java
// Find all available drivers from attached devices.
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
if (availableDrivers.isEmpty()) {
return;
}
// Open a connection to the first available driver.
UsbSerialDriver driver = availableDrivers.get(0);
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
if (connection == null) {
// add UsbManager.requestPermission(driver.getDevice(), ..) handling here
return;
}
UsbSerialPort port = driver.getPorts().get(0); // Most devices have just one port (port 0)
port.open(connection);
port.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
```
then use direct read/write
```java
port.write(request, WRITE_WAIT_MILLIS);
len = port.read(response, READ_WAIT_MILLIS);
```
or direct write + event driven read:
```java
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
usbIoManager.start();
...
port.write("hello".getBytes(), WRITE_WAIT_MILLIS);
@Override
public void onNewData(byte[] data) {
runOnUiThread(() -> { textView.append(new String(data)); });
}
```
and finally:
```java
port.close();
```
For a simple example, see
[UsbSerialExamples](https://github.com/mik3y/usb-serial-for-android/blob/master/usbSerialExamples)
folder in this project.
See separate github project [SimpleUsbTerminal](https://github.com/kai-morich/SimpleUsbTerminal)
for a more complete example with:
* Background service to stay connected while the app is not visible or rotating
* Flow control
## Probing for Unrecognized Devices
Sometimes you may need to do a little extra work to support devices which
usb-serial-for-android doesn't (yet) know about -- but which you know to be
compatible with one of the built-in drivers. This may be the case for a brand
new device or for one using a custom VID/PID pair.
UsbSerialProber is a class to help you find and instantiate compatible
UsbSerialDrivers from the tree of connected UsbDevices. Normally, you will use
the default prober returned by ``UsbSerialProber.getDefaultProber()``, which
uses USB interface types and the built-in list of well-known VIDs and PIDs that
are supported by our drivers.
To use your own set of rules, create and use a custom prober:
```java
// Probe for our custom FTDI device, which use VID 0x1234 and PID 0x0001 and 0x0002.
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x1234, 0x0001, FtdiSerialDriver.class);
customTable.addProduct(0x1234, 0x0002, FtdiSerialDriver.class);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> drivers = prober.findAllDrivers(usbManager);
// ...
```
*Note*: as of v3.5.0 this library detects CDC/ACM devices by USB interface types instead of fixed VID+PID,
so custom probers are typically not required any more for CDC/ACM devices.
Of course, nothing requires you to use UsbSerialProber at all: you can
instantiate driver classes directly if you know what you're doing; just supply
a compatible UsbDevice.
## Compatible Devices
This library supports USB to serial converter chips with specific drivers
* FTDI FT232R, FT232H, FT2232H, FT4232H, FT230X, FT231X, FT234XD
* Prolific PL2303
* Silabs CP2102, CP210*
* Qinheng CH340, CH341A
some other device specific drivers
* GsmModem devices, e.g. for Unisoc based Fibocom GSM modems
* Chrome OS CCD (Closed Case Debugging)
and devices implementing the generic CDC/ACM protocol like
* Qinheng CH9102
* Microchip MCP2221
* Arduino using ATmega32U4
* Digispark using V-USB software USB
* ...
## Help & Discussion
For common problems, see the [FAQ](https://github.com/mik3y/usb-serial-for-android/wiki/FAQ) wiki page.
Are you using the library? Add your project to
[ProjectsUsingUsbSerialForAndroid](https://github.com/mik3y/usb-serial-for-android/wiki/Projects-Using-usb-serial-for-android).

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry combineaccessrules="false" kind="src" path="/UsbSerialLibrary"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>UsbSerialExamples</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,280 +0,0 @@
#Thu Jun 02 12:32:09 PDT 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=1
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=false
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=100
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true

View File

@ -1,4 +0,0 @@
#Thu Apr 21 23:18:48 PDT 2011
eclipse.preferences.version=1
formatter_profile=_Android
formatter_settings_version=11

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hoho.android.usbserial.examples"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="12" />
<uses-feature android:name="android.hardware.usb.host" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name="com.hoho.android.usbserial.examples.DemoActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>

View File

@ -1,40 +0,0 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

View File

@ -1,12 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-12
android.library.reference.1=../UsbSerialLibrary

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/demoTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<ScrollView
android:id="@+id/demoScroller"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/demoText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:typeface="monospace" />
</ScrollView>
</LinearLayout>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, DemoActivity!</string>
<string name="app_name">UsbSerialExamples</string>
</resources>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
<usb-device vendor-id="1027" product-id="24577" />
<!-- 0x2341 / Arduino -->
<usb-device vendor-id="9025" />
<!-- 0x16C0 / 0x0483: Teensyduino -->
<usb-device vendor-id="5824" product-id="1155" />
</resources>

View File

@ -1,165 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.examples;
import android.app.Activity;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.ScrollView;
import android.widget.TextView;
import com.hoho.android.usbserial.R;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.HexDump;
import com.hoho.android.usbserial.util.SerialInputOutputManager;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* A sample Activity demonstrating USB-Serial support.
*
* @author mike wakerly (opensource@hoho.com)
*/
public class DemoActivity extends Activity {
private final String TAG = DemoActivity.class.getSimpleName();
/**
* The device currently in use, or {@code null}.
*/
private UsbSerialDriver mSerialDevice;
/**
* The system's USB service.
*/
private UsbManager mUsbManager;
private TextView mTitleTextView;
private TextView mDumpTextView;
private ScrollView mScrollView;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private SerialInputOutputManager mSerialIoManager;
private final SerialInputOutputManager.Listener mListener =
new SerialInputOutputManager.Listener() {
@Override
public void onRunError(Exception e) {
Log.d(TAG, "Runner stopped.");
}
@Override
public void onNewData(final byte[] data) {
DemoActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
DemoActivity.this.updateReceivedData(data);
}
});
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
mTitleTextView = (TextView) findViewById(R.id.demoTitle);
mDumpTextView = (TextView) findViewById(R.id.demoText);
mScrollView = (ScrollView) findViewById(R.id.demoScroller);
}
@Override
protected void onPause() {
super.onPause();
stopIoManager();
if (mSerialDevice != null) {
try {
mSerialDevice.close();
} catch (IOException e) {
// Ignore.
}
mSerialDevice = null;
}
}
@Override
protected void onResume() {
super.onResume();
mSerialDevice = UsbSerialProber.acquire(mUsbManager);
Log.d(TAG, "Resumed, mSerialDevice=" + mSerialDevice);
if (mSerialDevice == null) {
mTitleTextView.setText("No serial device.");
} else {
try {
mSerialDevice.open();
} catch (IOException e) {
Log.e(TAG, "Error setting up device: " + e.getMessage(), e);
mTitleTextView.setText("Error opening device: " + e.getMessage());
try {
mSerialDevice.close();
} catch (IOException e2) {
// Ignore.
}
mSerialDevice = null;
return;
}
mTitleTextView.setText("Serial device: " + mSerialDevice);
}
onDeviceStateChange();
}
private void stopIoManager() {
if (mSerialIoManager != null) {
Log.i(TAG, "Stopping io manager ..");
mSerialIoManager.stop();
mSerialIoManager = null;
}
}
private void startIoManager() {
if (mSerialDevice != null) {
Log.i(TAG, "Starting io manager ..");
mSerialIoManager = new SerialInputOutputManager(mSerialDevice, mListener);
mExecutor.submit(mSerialIoManager);
}
}
private void onDeviceStateChange() {
stopIoManager();
startIoManager();
}
private void updateReceivedData(byte[] data) {
final String message = "Read " + data.length + " bytes: \n"
+ HexDump.dumpHexString(data) + "\n\n";
mDumpTextView.append(message);
mScrollView.smoothScrollTo(0, mDumpTextView.getBottom());
}
}

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>UsbSerialLibrary</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,280 +0,0 @@
#Thu Jun 02 12:32:09 PDT 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=1
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=false
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=100
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true

View File

@ -1,4 +0,0 @@
#Thu Apr 21 23:18:48 PDT 2011
eclipse.preferences.version=1
formatter_profile=_Android
formatter_settings_version=11

View File

@ -1,36 +0,0 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

View File

@ -1,12 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-12
android.library=true

View File

@ -1,175 +0,0 @@
package com.hoho.android.usbserial.driver;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
/**
* USB CDC/ACM serial driver implementation.
*
* @author mike wakerly (opensource@hoho.com)
*/
public class CdcAcmSerialDriver extends UsbSerialDriver {
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
private UsbInterface mControlInterface;
private UsbInterface mDataInterface;
private UsbEndpoint mControlEndpoint;
private UsbEndpoint mReadEndpoint;
private UsbEndpoint mWriteEndpoint;
public CdcAcmSerialDriver(UsbDevice device, UsbDeviceConnection connection) {
super(device, connection);
}
@Override
public void open() throws IOException {
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
Log.d(TAG, "Claiming control interface.");
mControlInterface = mDevice.getInterface(0);
Log.d(TAG, "Control iface=" + mControlInterface);
// class should be USB_CLASS_COMM
if (!mConnection.claimInterface(mControlInterface, true)) {
throw new IOException("Could not claim control interface.");
}
mControlEndpoint = mControlInterface.getEndpoint(0);
Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection());
Log.d(TAG, "Claiming data interface.");
mDataInterface = mDevice.getInterface(1);
Log.d(TAG, "data iface=" + mDataInterface);
// class should be USB_CLASS_CDC_DATA
if (!mConnection.claimInterface(mDataInterface, true)) {
throw new IOException("Could not claim data interface.");
}
mReadEndpoint = mDataInterface.getEndpoint(1);
Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
mWriteEndpoint = mDataInterface.getEndpoint(0);
Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
Log.d(TAG, "Setting line coding");
setBaudRate(115200);
}
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
private int sendAcmControlMessage(int request, int value, byte[] buf) {
return mConnection.controlTransfer(USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
}
private int setAcmLineCoding(int bitRate, int stopBits, int parity, int dataBits) {
byte[] msg = {
(byte) ( bitRate & 0xff),
(byte) ((bitRate >> 8 ) & 0xff),
(byte) ((bitRate >> 16) & 0xff),
(byte) ((bitRate >> 24) & 0xff),
(byte) stopBits,
(byte) parity,
(byte) dataBits};
return sendAcmControlMessage(SET_LINE_CODING, 0, msg);
}
@Override
public void close() throws IOException {
mConnection.close();
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
final int numBytesRead;
synchronized (mReadBufferLock) {
int readAmt = Math.min(dest.length, mReadBuffer.length);
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
timeoutMillis);
if (numBytesRead < 0) {
// This sucks: we get -1 on timeout, not 0 as preferred.
// We *should* use UsbRequest, except it has a bug/api oversight
// where there is no way to determine the number of bytes read
// in response :\ -- http://b.android.com/28023
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
}
return numBytesRead;
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
// TODO(mikey): Nearly identical to FtdiSerial write. Refactor.
int offset = 0;
while (offset < src.length) {
final int writeLength;
final int amtWritten;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
timeoutMillis);
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length);
}
Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
}
return offset;
}
@Override
public int setBaudRate(int baudRate) throws IOException {
setAcmLineCoding(baudRate, 0, 0, 8);
return baudRate;
}
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_ARDUINO),
new int[] {
UsbId.ARDUINO_UNO,
UsbId.ARDUINO_UNO_R3,
UsbId.ARDUINO_MEGA_2560,
UsbId.ARDUINO_MEGA_2560_R3,
UsbId.ARDUINO_SERIAL_ADAPTER,
UsbId.ARDUINO_SERIAL_ADAPTER_R3,
UsbId.ARDUINO_MEGA_ADK,
UsbId.ARDUINO_MEGA_ADK_R3,
UsbId.ARDUINO_LEONARDO,
});
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_VAN_OOIJEN_TECH),
new int[] {
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
});
return supportedDevices;
}
}

View File

@ -1,421 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.LinkedHashMap;
import java.util.Map;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import com.hoho.android.usbserial.util.HexDump;
/**
* A {@link UsbSerialDriver} implementation for a variety of FTDI devices
* <p>
* This driver is based on
* <a href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>, and is
* copyright and subject to the following terms:
*
* <pre>
* Copyright (C) 2003 by Intra2net AG
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation;
*
* opensource@intra2net.com
* http://www.intra2net.com/en/developer/libftdi
* </pre>
*
* </p>
* <p>
* Some FTDI devices have not been tested; see later listing of supported and
* unsupported devices. Devices listed as "supported" support the following
* features:
* <ul>
* <li>Read and write of serial data (see {@link #read(byte[], int)} and
* {@link #write(byte[], int)}.
* <li>Setting baud rate (see {@link #setBaudRate(int)}).
* </ul>
* </p>
* <p>
* Supported and tested devices:
* <ul>
* <li>{@value DeviceType#TYPE_R}</li>
* </ul>
* </p>
* <p>
* Unsupported but possibly working devices (please contact the author with
* feedback or patches):
* <ul>
* <li>{@value DeviceType#TYPE_2232C}</li>
* <li>{@value DeviceType#TYPE_2232H}</li>
* <li>{@value DeviceType#TYPE_4232H}</li>
* <li>{@value DeviceType#TYPE_AM}</li>
* <li>{@value DeviceType#TYPE_BM}</li>
* </ul>
* </p>
*
* @author mike wakerly (opensource@hoho.com)
* @see <a href="http://code.google.com/p/usb-serial-for-android/">USB Serial
* for Android project page</a>
* @see <a href="http://www.ftdichip.com/">FTDI Homepage</a>
* @see <a href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>
*/
public class FtdiSerialDriver extends UsbSerialDriver {
private static final int DEFAULT_BAUD_RATE = 115200;
public static final int USB_TYPE_STANDARD = 0x00 << 5;
public static final int USB_TYPE_CLASS = 0x00 << 5;
public static final int USB_TYPE_VENDOR = 0x00 << 5;
public static final int USB_TYPE_RESERVED = 0x00 << 5;
public static final int USB_RECIP_DEVICE = 0x00;
public static final int USB_RECIP_INTERFACE = 0x01;
public static final int USB_RECIP_ENDPOINT = 0x02;
public static final int USB_RECIP_OTHER = 0x03;
public static final int USB_ENDPOINT_IN = 0x80;
public static final int USB_ENDPOINT_OUT = 0x00;
public static final int USB_WRITE_TIMEOUT_MILLIS = 5000;
public static final int USB_READ_TIMEOUT_MILLIS = 5000;
// From ftdi.h
/**
* Reset the port.
*/
private static final int SIO_RESET_REQUEST = 0;
/**
* Set the modem control register.
*/
private static final int SIO_MODEM_CTRL_REQUEST = 1;
/**
* Set flow control register.
*/
private static final int SIO_SET_FLOW_CTRL_REQUEST = 2;
/**
* Set baud rate.
*/
private static final int SIO_SET_BAUD_RATE_REQUEST = 3;
/**
* Set the data characteristics of the port.
*/
private static final int SIO_SET_DATA_REQUEST = 4;
private static final int SIO_RESET_SIO = 0;
public static final int FTDI_DEVICE_OUT_REQTYPE =
UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT;
public static final int FTDI_DEVICE_IN_REQTYPE =
UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN;
/**
* Length of the modem status header, transmitted with every read.
*/
private static final int MODEM_STATUS_HEADER_LENGTH = 2;
private final String TAG = FtdiSerialDriver.class.getSimpleName();
private DeviceType mType;
/**
* FTDI chip types.
*/
private static enum DeviceType {
TYPE_BM, TYPE_AM, TYPE_2232C, TYPE_R, TYPE_2232H, TYPE_4232H;
}
private int mInterface = 0; /* INTERFACE_ANY */
private int mMaxPacketSize = 64; // TODO(mikey): detect
/**
* Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
* since it gives no indication of number of bytes read. Set this to
* {@code true} on platforms where it is fixed.
*/
private static final boolean ENABLE_ASYNC_READS = false;
/**
* Constructor.
*
* @param usbDevice the {@link UsbDevice} to use
* @param usbConnection the {@link UsbDeviceConnection} to use
* @throws UsbSerialRuntimeException if the given device is incompatible
* with this driver
*/
public FtdiSerialDriver(UsbDevice usbDevice, UsbDeviceConnection usbConnection) {
super(usbDevice, usbConnection);
mType = null;
}
public void reset() throws IOException {
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, SIO_RESET_REQUEST,
SIO_RESET_SIO, 0 /* index */, null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Reset failed: result=" + result);
}
// TODO(mikey): autodetect.
mType = DeviceType.TYPE_R;
}
@Override
public void open() throws IOException {
boolean opened = false;
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
if (mConnection.claimInterface(mDevice.getInterface(i), true)) {
Log.d(TAG, "claimInterface " + i + " SUCCESS");
} else {
Log.d(TAG, "claimInterface " + i + " FAIL");
}
}
reset();
setBaudRate(DEFAULT_BAUD_RATE);
opened = true;
} finally {
if (!opened) {
close();
}
}
}
@Override
public void close() {
mConnection.close();
}
@Override
public int read(byte[] dest, int timeoutMillis) throws IOException {
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);
if (ENABLE_ASYNC_READS) {
final int readAmt;
synchronized (mReadBufferLock) {
// mReadBuffer is only used for maximum read size.
readAmt = Math.min(dest.length, mReadBuffer.length);
}
final UsbRequest request = new UsbRequest();
request.initialize(mConnection, endpoint);
final ByteBuffer buf = ByteBuffer.wrap(dest);
if (!request.queue(buf, readAmt)) {
throw new IOException("Error queueing request.");
}
final UsbRequest response = mConnection.requestWait();
if (response == null) {
throw new IOException("Null response");
}
final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
if (payloadBytesRead > 0) {
Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return payloadBytesRead;
} else {
return 0;
}
} else {
final int totalBytesRead;
synchronized (mReadBufferLock) {
final int readAmt = Math.min(dest.length, mReadBuffer.length);
totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,
readAmt, timeoutMillis);
}
if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
}
final int payloadBytesRead = totalBytesRead - MODEM_STATUS_HEADER_LENGTH;
if (payloadBytesRead > 0) {
System.arraycopy(mReadBuffer, MODEM_STATUS_HEADER_LENGTH, dest, 0, payloadBytesRead);
}
return payloadBytesRead;
}
}
@Override
public int write(byte[] src, int timeoutMillis) throws IOException {
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(1);
int offset = 0;
while (offset < src.length) {
final int writeLength;
final int amtWritten;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength,
timeoutMillis);
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length);
}
Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
}
return offset;
}
@Override
public int setBaudRate(int baudRate) throws IOException {
long[] vals = convertBaudrate(baudRate);
long actualBaudrate = vals[0];
long index = vals[1];
long value = vals[2];
Log.i(TAG, "Requested baudrate=" + baudRate + ", actual=" + actualBaudrate);
int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE,
SIO_SET_BAUD_RATE_REQUEST, (int) value, (int) index,
null, 0, USB_WRITE_TIMEOUT_MILLIS);
if (result != 0) {
throw new IOException("Setting baudrate failed: result=" + result);
}
return (int) actualBaudrate;
}
private long[] convertBaudrate(int baudrate) {
// TODO(mikey): Braindead transcription of libfti method. Clean up,
// using more idiomatic Java where possible.
int divisor = 24000000 / baudrate;
int bestDivisor = 0;
int bestBaud = 0;
int bestBaudDiff = 0;
int fracCode[] = {
0, 3, 2, 4, 1, 5, 6, 7
};
for (int i = 0; i < 2; i++) {
int tryDivisor = divisor + i;
int baudEstimate;
int baudDiff;
if (tryDivisor <= 8) {
// Round up to minimum supported divisor
tryDivisor = 8;
} else if (mType != DeviceType.TYPE_AM && tryDivisor < 12) {
// BM doesn't support divisors 9 through 11 inclusive
tryDivisor = 12;
} else if (divisor < 16) {
// AM doesn't support divisors 9 through 15 inclusive
tryDivisor = 16;
} else {
if (mType == DeviceType.TYPE_AM) {
// TODO
} else {
if (tryDivisor > 0x1FFFF) {
// Round down to maximum supported divisor value (for
// BM)
tryDivisor = 0x1FFFF;
}
}
}
// Get estimated baud rate (to nearest integer)
baudEstimate = (24000000 + (tryDivisor / 2)) / tryDivisor;
// Get absolute difference from requested baud rate
if (baudEstimate < baudrate) {
baudDiff = baudrate - baudEstimate;
} else {
baudDiff = baudEstimate - baudrate;
}
if (i == 0 || baudDiff < bestBaudDiff) {
// Closest to requested baud rate so far
bestDivisor = tryDivisor;
bestBaud = baudEstimate;
bestBaudDiff = baudDiff;
if (baudDiff == 0) {
// Spot on! No point trying
break;
}
}
}
// Encode the best divisor value
long encodedDivisor = (bestDivisor >> 3) | (fracCode[bestDivisor & 7] << 14);
// Deal with special cases for encoded value
if (encodedDivisor == 1) {
encodedDivisor = 0; // 3000000 baud
} else if (encodedDivisor == 0x4001) {
encodedDivisor = 1; // 2000000 baud (BM only)
}
// Split into "value" and "index" values
long value = encodedDivisor & 0xFFFF;
long index;
if (mType == DeviceType.TYPE_2232C || mType == DeviceType.TYPE_2232H
|| mType == DeviceType.TYPE_4232H) {
index = (encodedDivisor >> 8) & 0xffff;
index &= 0xFF00;
index |= 0 /* TODO mIndex */;
} else {
index = (encodedDivisor >> 16) & 0xffff;
}
// Return the nearest baud rate
return new long[] {
bestBaud, index, value
};
}
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<Integer, int[]>();
supportedDevices.put(Integer.valueOf(UsbId.VENDOR_FTDI),
new int[] {
UsbId.FTDI_FT232R,
});
return supportedDevices;
}
}

View File

@ -1,53 +0,0 @@
/* Copyright 2012 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
/**
* Registry of USB vendor/product ID constants.
*
* Culled from various sources; see
* <a href="http://www.linux-usb.org/usb.ids">usb.ids</a> for one listing.
*
* @author mike wakerly (opensource@hoho.com)
*/
public final class UsbId {
public static final int VENDOR_FTDI = 0x0403;
public static final int FTDI_FT232R = 0x6001;
public static final int VENDOR_ARDUINO = 0x2341;
public static final int ARDUINO_UNO = 0x0001;
public static final int ARDUINO_MEGA_2560 = 0x0010;
public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;
public static final int ARDUINO_MEGA_ADK = 0x003f;
public static final int ARDUINO_MEGA_2560_R3 = 0x0042;
public static final int ARDUINO_UNO_R3 = 0x0043;
public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;
public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
public static final int ARDUINO_LEONARDO = 0x8036;
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
private UsbId() {
throw new IllegalAccessError("Non-instantiable class.");
}
}

View File

@ -1,141 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
import java.io.IOException;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
/**
* Driver interface for a supported USB serial device.
*
* @author mike wakerly (opensource@hoho.com)
*/
public abstract class UsbSerialDriver {
public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024;
public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
protected final UsbDevice mDevice;
protected final UsbDeviceConnection mConnection;
protected final Object mReadBufferLock = new Object();
protected final Object mWriteBufferLock = new Object();
/** Internal read buffer. Guarded by {@link #mReadBufferLock}. */
protected byte[] mReadBuffer;
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
protected byte[] mWriteBuffer;
public UsbSerialDriver(UsbDevice device, UsbDeviceConnection connection) {
mDevice = device;
mConnection = connection;
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
}
/**
* Opens and initializes the device as a USB serial device. Upon success,
* caller must ensure that {@link #close()} is eventually called.
*
* @throws IOException on error opening or initializing the device.
*/
public abstract void open() throws IOException;
/**
* Closes the serial device.
*
* @throws IOException on error closing the device.
*/
public abstract void close() throws IOException;
/**
* Reads as many bytes as possible into the destination buffer.
*
* @param dest the destination byte buffer
* @param timeoutMillis the timeout for reading
* @return the actual number of bytes read
* @throws IOException if an error occurred during reading
*/
public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException;
/**
* Writes as many bytes as possible from the source buffer.
*
* @param src the source byte buffer
* @param timeoutMillis the timeout for writing
* @return the actual number of bytes written
* @throws IOException if an error occurred during writing
*/
public abstract int write(final byte[] src, final int timeoutMillis) throws IOException;
/**
* Sets the baud rate of the serial device.
*
* @param baudRate the desired baud rate, in bits per second
* @return the actual rate set
* @throws IOException on error setting the baud rate
*/
public abstract int setBaudRate(final int baudRate) throws IOException;
/**
* Returns the currently-bound USB device.
*
* @return the device
*/
public final UsbDevice getDevice() {
return mDevice;
}
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for read operations. Most users should not need to change this.
*
* @param bufferSize the size in bytes
*/
public final void setReadBufferSize(int bufferSize) {
synchronized (mReadBufferLock) {
if (bufferSize == mReadBuffer.length) {
return;
}
mReadBuffer = new byte[bufferSize];
}
}
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for write operations. Most users should not need to change this.
*
* @param bufferSize the size in bytes
*/
public final void setWriteBufferSize(int bufferSize) {
synchronized (mWriteBufferLock) {
if (bufferSize == mWriteBuffer.length) {
return;
}
mWriteBuffer = new byte[bufferSize];
}
}
}

View File

@ -1,147 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.driver;
import java.util.Map;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
/**
* Helper class to assist in detecting and building {@link UsbSerialDriver}
* instances from available hardware.
*
* @author mike wakerly (opensource@hoho.com)
*/
public enum UsbSerialProber {
// TODO(mikey): Too much boilerplate.
/**
* Prober for {@link FtdiSerialDriver}.
*
* @see FtdiSerialDriver
*/
FTDI_SERIAL {
@Override
public UsbSerialDriver getDevice(final UsbManager manager, final UsbDevice usbDevice) {
if (!testIfSupported(usbDevice, FtdiSerialDriver.getSupportedDevices())) {
return null;
}
final UsbDeviceConnection connection = manager.openDevice(usbDevice);
if (connection == null) {
return null;
}
return new FtdiSerialDriver(usbDevice, connection);
}
},
CDC_ACM_SERIAL {
@Override
public UsbSerialDriver getDevice(UsbManager manager, UsbDevice usbDevice) {
if (!testIfSupported(usbDevice, CdcAcmSerialDriver.getSupportedDevices())) {
return null;
}
final UsbDeviceConnection connection = manager.openDevice(usbDevice);
if (connection == null) {
return null;
}
return new CdcAcmSerialDriver(usbDevice, connection);
}
};
/**
* Builds a new {@link UsbSerialDriver} instance from the raw device, or
* returns <code>null</code> if it could not be built (for example, if the
* probe failed).
*
* @param manager the {@link UsbManager} to use
* @param usbDevice the raw {@link UsbDevice} to use
* @return the first available {@link UsbSerialDriver}, or {@code null} if
* no devices could be acquired
*/
public abstract UsbSerialDriver getDevice(final UsbManager manager, final UsbDevice usbDevice);
/**
* Acquires and returns the first available serial device among all
* available {@link UsbDevice}s, or returns {@code null} if no device could
* be acquired.
*
* @param usbManager the {@link UsbManager} to use
* @return the first available {@link UsbSerialDriver}, or {@code null} if
* no devices could be acquired
*/
public static UsbSerialDriver acquire(final UsbManager usbManager) {
for (final UsbDevice usbDevice : usbManager.getDeviceList().values()) {
final UsbSerialDriver probedDevice = acquire(usbManager, usbDevice);
if (probedDevice != null) {
return probedDevice;
}
}
return null;
}
/**
* Builds and returns a new {@link UsbSerialDriver} from the given
* {@link UsbDevice}, or returns {@code null} if no drivers supported this
* device.
*
* @param usbManager the {@link UsbManager} to use
* @param usbDevice the {@link UsbDevice} to use
* @return a new {@link UsbSerialDriver}, or {@code null} if no devices
* could be acquired
*/
public static UsbSerialDriver acquire(final UsbManager usbManager, final UsbDevice usbDevice) {
for (final UsbSerialProber prober : values()) {
final UsbSerialDriver probedDevice = prober.getDevice(usbManager, usbDevice);
if (probedDevice != null) {
return probedDevice;
}
}
return null;
}
/**
* Returns {@code true} if the given device is found in the vendor/product map.
*
* @param usbDevice the device to test
* @param supportedDevices map of vendor ids to product id(s)
* @return {@code true} if supported
*/
private static boolean testIfSupported(final UsbDevice usbDevice,
final Map<Integer, int[]> supportedDevices) {
final int[] supportedProducts = supportedDevices.get(
Integer.valueOf(usbDevice.getVendorId()));
if (supportedProducts == null) {
return false;
}
final int productId = usbDevice.getProductId();
for (int supportedProductId : supportedProducts) {
if (productId == supportedProductId) {
return true;
}
}
return false;
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package com.hoho.android.usbserial.driver;
/**
* Generic unchecked exception for the usbserial package.
*
* @author mike wakerly (opensource@hoho.com)
*/
@SuppressWarnings("serial")
public class UsbSerialRuntimeException extends RuntimeException {
public UsbSerialRuntimeException() {
super();
}
public UsbSerialRuntimeException(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
}
public UsbSerialRuntimeException(String detailMessage) {
super(detailMessage);
}
public UsbSerialRuntimeException(Throwable throwable) {
super(throwable);
}
}

View File

@ -1,188 +0,0 @@
/* Copyright 2011 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
package com.hoho.android.usbserial.util;
import java.io.IOException;
import java.nio.ByteBuffer;
import android.hardware.usb.UsbRequest;
import android.util.Log;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
/**
* Utility class which services a {@link UsbSerialDriver} in its {@link #run()}
* method.
*
* @author mike wakerly (opensource@hoho.com)
*/
public class SerialInputOutputManager implements Runnable {
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
private static final boolean DEBUG = true;
private static final int READ_WAIT_MILLIS = 200;
private static final int BUFSIZ = 4096;
private final UsbSerialDriver mDriver;
private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
// Synchronized by 'mWriteBuffer'
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
private enum State {
STOPPED,
RUNNING,
STOPPING
}
// Synchronized by 'this'
private State mState = State.STOPPED;
// Synchronized by 'this'
private Listener mListener;
public interface Listener {
/**
* Called when new incoming data is available.
*/
public void onNewData(byte[] data);
/**
* Called when {@link SerialInputOutputManager#run()} aborts due to an
* error.
*/
public void onRunError(Exception e);
}
/**
* Creates a new instance with no listener.
*/
public SerialInputOutputManager(UsbSerialDriver driver) {
this(driver, null);
}
/**
* Creates a new instance with the provided listener.
*/
public SerialInputOutputManager(UsbSerialDriver driver, Listener listener) {
mDriver = driver;
mListener = listener;
}
public synchronized void setListener(Listener listener) {
mListener = listener;
}
public synchronized Listener getListener() {
return mListener;
}
public void writeAsync(byte[] data) {
synchronized (mWriteBuffer) {
mWriteBuffer.put(data);
}
}
public synchronized void stop() {
if (getState() == State.RUNNING) {
Log.i(TAG, "Stop requested");
mState = State.STOPPING;
}
}
private synchronized State getState() {
return mState;
}
/**
* Continuously services the read and write buffers until {@link #stop()} is
* called, or until a driver exception is raised.
*
* NOTE(mikey): Uses inefficient read/write-with-timeout.
* TODO(mikey): Read asynchronously with {@link UsbRequest#queue(ByteBuffer, int)}
*/
@Override
public void run() {
synchronized (this) {
if (getState() != State.STOPPED) {
throw new IllegalStateException("Already running.");
}
mState = State.RUNNING;
}
Log.i(TAG, "Running ..");
try {
while (true) {
if (getState() != State.RUNNING) {
Log.i(TAG, "Stopping mState=" + getState());
break;
}
step();
}
} catch (Exception e) {
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
final Listener listener = getListener();
if (listener != null) {
listener.onRunError(e);
}
} finally {
synchronized (this) {
mState = State.STOPPED;
Log.i(TAG, "Stopped.");
}
}
}
private void step() throws IOException {
// Handle incoming data.
int len = mDriver.read(mReadBuffer.array(), READ_WAIT_MILLIS);
if (len > 0) {
if (DEBUG) Log.d(TAG, "Read data len=" + len);
final Listener listener = getListener();
if (listener != null) {
final byte[] data = new byte[len];
mReadBuffer.get(data, 0, len);
listener.onNewData(data);
}
mReadBuffer.clear();
}
// Handle outgoing data.
byte[] outBuff = null;
synchronized (mWriteBuffer) {
if (mWriteBuffer.position() > 0) {
len = mWriteBuffer.position();
outBuff = new byte[len];
mWriteBuffer.get(outBuff, 0, len);
mWriteBuffer.clear();
}
}
if (outBuff != null) {
if (DEBUG) {
Log.d(TAG, "Writing data len=" + len);
}
mDriver.write(outBuff, READ_WAIT_MILLIS);
}
}
}

View File

@ -1,43 +0,0 @@
/* Copyright 2012 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* Project home page: http://code.google.com/p/usb-serial-for-android/
*/
// Sample Arduino sketch for use with usb-serial-for-android.
// Prints an ever-increasing counter, and writes back anything
// it receives.
static int counter = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.print("Tick #");
Serial.print(counter++, DEC);
Serial.print("\n");
if (Serial.peek() != -1) {
Serial.print("Read: ");
do {
Serial.print((char) Serial.read());
} while (Serial.peek() != -1);
Serial.print("\n");
}
delay(1000);
}

18
build.gradle Normal file
View File

@ -0,0 +1,18 @@
// Top-level gradle script.
buildscript {
repositories {
mavenCentral()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.9.1'
}
}
allprojects {
repositories {
mavenCentral()
google()
}
}

5
codecov.yml Normal file
View File

@ -0,0 +1,5 @@
codecov:
max_report_age: off
require_ci_to_pass: no
notify:
wait_for_ci: no

3
gradle.properties Normal file
View File

@ -0,0 +1,3 @@
android.enableJetifier=true
android.useAndroidX=true
android.defaults.buildfeatures.buildconfig=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Tue Oct 13 21:20:09 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip

188
gradlew vendored Executable file
View File

@ -0,0 +1,188 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

100
gradlew.bat vendored Normal file
View File

@ -0,0 +1,100 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem http://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

4
jitpack.yml Normal file
View File

@ -0,0 +1,4 @@
jdk:
- openjdk17
install:
- ./gradlew :usbSerialForAndroid:publishToMavenLocal

1
settings.gradle Normal file
View File

@ -0,0 +1 @@
include 'usbSerialForAndroid', 'usbSerialExamples'

View File

@ -0,0 +1,64 @@
/*
bridge USB-serial to hardware-serial
for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro)
hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB
see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino
-> CDC.cpp|HardwareSerial.cpp for serial implementation details
this sketch is mainly for demonstration / test of CDC communication
performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet
*/
uint32_t baud = 9600;
uint8_t databits = 8;
uint8_t stopbits = 1;
uint8_t parity = 0;
void setup() {
Serial.begin(baud); // USB
Serial1.begin(baud, SERIAL_8N1);
}
void loop() {
// show USB connected state
if (Serial) TXLED1;
else TXLED0;
// configure hardware serial
if (Serial.baud() != baud ||
Serial.numbits() != databits ||
Serial.stopbits() != stopbits ||
Serial.paritytype() != parity) {
baud = Serial.baud();
databits = Serial.numbits();
stopbits = Serial.stopbits();
parity = Serial.paritytype();
uint8_t config = 0; // ucsrc register
switch (databits) {
case 5: break;
case 6: config |= 2; break;
case 7: config |= 4; break;
case 8: config |= 6; break;
default: config |= 6;
}
switch (stopbits) {
case 2: config |= 8;
// 1.5 stopbits not supported
}
switch (parity) {
case 1: config |= 0x30; break; // odd
case 2: config |= 0x20; break; // even
// mark, space not supported
}
Serial1.end();
Serial1.begin(baud, config);
}
// bridge
if (Serial.available() > 0)
Serial1.write(Serial.read());
if (Serial1.available() > 0)
Serial.write(Serial1.read());
}

View File

@ -0,0 +1,303 @@
/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/
#include "USBCore.h" // kai:added
#include "USBAPI.h"
#include <avr/wdt.h>
#include <util/atomic.h>
#if defined(USBCON)
typedef struct
{
u32 dwDTERate;
u8 bCharFormat;
u8 bParityType;
u8 bDataBits;
u8 lineState;
} LineInfo;
static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
static volatile int32_t breakValue = -1;
static u8 wdtcsr_save;
#define WEAK __attribute__ ((weak))
extern const CDCDescriptor _cdcInterface PROGMEM;
const CDCDescriptor _cdcInterface =
{
D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
// CDC communication interface
D_INTERFACE(CDC_ACM_INTERFACE,3,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0), // kai
D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd)
D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not)
D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE), // Communication interface is master, data interface is slave 0
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),
// CDC data interface
//D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0), // kai:removed
D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0),
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0)
};
bool isLUFAbootloader()
{
return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE;
}
int CDC_GetInterface(u8* interfaceNum)
{
interfaceNum[0] += 1; // kai
return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface));
}
bool CDC_Setup(USBSetup& setup)
{
u8 r = setup.bRequest;
u8 requestType = setup.bmRequestType;
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
{
if (CDC_GET_LINE_CODING == r)
{
USB_SendControl(0,(void*)&_usbLineInfo,7);
return true;
}
}
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
{
if (CDC_SEND_BREAK == r)
{
breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
}
if (CDC_SET_LINE_CODING == r)
{
USB_RecvControl((void*)&_usbLineInfo,7);
}
if (CDC_SET_CONTROL_LINE_STATE == r)
{
_usbLineInfo.lineState = setup.wValueL;
// auto-reset into the bootloader is triggered when the port, already
// open at 1200 bps, is closed. this is the signal to start the watchdog
// with a relatively long period so it can finish housekeeping tasks
// like servicing endpoints before the sketch ends
uint16_t magic_key_pos = MAGIC_KEY_POS;
// If we don't use the new RAMEND directly, check manually if we have a newer bootloader.
// This is used to keep compatible with the old leonardo bootloaders.
// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check.
#if MAGIC_KEY_POS != (RAMEND-1)
// For future boards save the key in the inproblematic RAMEND
// Which is reserved for the main() return value (which will never return)
if (isLUFAbootloader()) {
// horray, we got a new bootloader!
magic_key_pos = (RAMEND-1);
}
#endif
// We check DTR state to determine if host port is open (bit 0 of lineState).
if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0)
{
#if MAGIC_KEY_POS != (RAMEND-1)
// Backup ram value if its not a newer bootloader and it hasn't already been saved.
// This should avoid memory corruption at least a bit, not fully
if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) {
*(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos;
}
#endif
// Store boot key
*(uint16_t *)magic_key_pos = MAGIC_KEY;
// Save the watchdog state in case the reset is aborted.
wdtcsr_save = WDTCSR;
wdt_enable(WDTO_120MS);
}
else if (*(uint16_t *)magic_key_pos == MAGIC_KEY)
{
// Most OSs do some intermediate steps when configuring ports and DTR can
// twiggle more than once before stabilizing.
// To avoid spurious resets we set the watchdog to 120ms and eventually
// cancel if DTR goes back high.
// Cancellation is only done if an auto-reset was started, which is
// indicated by the magic key having been set.
wdt_reset();
// Restore the watchdog state in case the sketch was using it.
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = wdtcsr_save;
#if MAGIC_KEY_POS != (RAMEND-1)
// Restore backed up (old bootloader) magic key data
if (magic_key_pos != (RAMEND-1)) {
*(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1);
} else
#endif
{
// Clean up RAMEND key
*(uint16_t *)magic_key_pos = 0x0000;
}
}
}
return true;
}
return false;
}
void Serial_::begin(unsigned long /* baud_count */)
{
peek_buffer = -1;
}
void Serial_::begin(unsigned long /* baud_count */, byte /* config */)
{
peek_buffer = -1;
}
void Serial_::end(void)
{
}
int Serial_::available(void)
{
if (peek_buffer >= 0) {
return 1 + USB_Available(CDC_RX);
}
return USB_Available(CDC_RX);
}
int Serial_::peek(void)
{
if (peek_buffer < 0)
peek_buffer = USB_Recv(CDC_RX);
return peek_buffer;
}
int Serial_::read(void)
{
if (peek_buffer >= 0) {
int c = peek_buffer;
peek_buffer = -1;
return c;
}
return USB_Recv(CDC_RX);
}
int Serial_::availableForWrite(void)
{
return USB_SendSpace(CDC_TX);
}
void Serial_::flush(void)
{
USB_Flush(CDC_TX);
}
size_t Serial_::write(uint8_t c)
{
return write(&c, 1);
}
size_t Serial_::write(const uint8_t *buffer, size_t size)
{
/* only try to send bytes if the high-level CDC connection itself
is open (not just the pipe) - the OS should set lineState when the port
is opened and clear lineState when the port is closed.
bytes sent before the user opens the connection or after
the connection is closed are lost - just like with a UART. */
// TODO - ZE - check behavior on different OSes and test what happens if an
// open connection isn't broken cleanly (cable is yanked out, host dies
// or locks up, or host virtual serial port hangs)
if (_usbLineInfo.lineState > 0) {
int r = USB_Send(CDC_TX,buffer,size);
if (r > 0) {
return r;
} else {
setWriteError();
return 0;
}
}
setWriteError();
return 0;
}
// This operator is a convenient way for a sketch to check whether the
// port has actually been configured and opened by the host (as opposed
// to just being connected to the host). It can be used, for example, in
// setup() before printing to ensure that an application on the host is
// actually ready to receive and display the data.
// We add a short delay before returning to fix a bug observed by Federico
// where the port is configured (lineState != 0) but not quite opened.
Serial_::operator bool() {
bool result = false;
if (_usbLineInfo.lineState > 0)
result = true;
delay(10);
return result;
}
unsigned long Serial_::baud() {
// Disable interrupts while reading a multi-byte value
uint32_t baudrate;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
baudrate = _usbLineInfo.dwDTERate;
}
return baudrate;
}
uint8_t Serial_::stopbits() {
return _usbLineInfo.bCharFormat;
}
uint8_t Serial_::paritytype() {
return _usbLineInfo.bParityType;
}
uint8_t Serial_::numbits() {
return _usbLineInfo.bDataBits;
}
bool Serial_::dtr() {
return _usbLineInfo.lineState & 0x1;
}
bool Serial_::rts() {
return _usbLineInfo.lineState & 0x2;
}
int32_t Serial_::readBreak() {
int32_t ret;
// Disable IRQs while reading and clearing breakValue to make
// sure we don't overwrite a value just set by the ISR.
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
ret = breakValue;
breakValue = -1;
}
return ret;
}
Serial_ Serial;
#endif /* if defined(USBCON) */

View File

@ -0,0 +1,8 @@
## castrated CDC test (single interface with 3 endpoints)
As mentioned [here](https://arduino.stackexchange.com/a/31695/62145), Arduino functions can be _overwritten_ by copying complete files into the own project.
This is used to create a castrated CDC device with a single interface containing 3 endpoints.
The modifications have been done against Arduino 1.8.10, for changes see comments containing `kai`.

View File

@ -0,0 +1,301 @@
// Copyright (c) 2010, Peter Barrett
/*
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/
#ifndef __USBCORE_H__
#define __USBCORE_H__
#include "USBAPI.h"
// Standard requests
#define GET_STATUS 0
#define CLEAR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADDRESS 5
#define GET_DESCRIPTOR 6
#define SET_DESCRIPTOR 7
#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9
#define GET_INTERFACE 10
#define SET_INTERFACE 11
// bmRequestType
#define REQUEST_HOSTTODEVICE 0x00
#define REQUEST_DEVICETOHOST 0x80
#define REQUEST_DIRECTION 0x80
#define REQUEST_STANDARD 0x00
#define REQUEST_CLASS 0x20
#define REQUEST_VENDOR 0x40
#define REQUEST_TYPE 0x60
#define REQUEST_DEVICE 0x00
#define REQUEST_INTERFACE 0x01
#define REQUEST_ENDPOINT 0x02
#define REQUEST_OTHER 0x03
#define REQUEST_RECIPIENT 0x03
#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE)
#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE)
#define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE)
// Class requests
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define MSC_RESET 0xFF
#define MSC_GET_MAX_LUN 0xFE
// Descriptors
#define USB_DEVICE_DESC_SIZE 18
#define USB_CONFIGUARTION_DESC_SIZE 9
#define USB_INTERFACE_DESC_SIZE 9
#define USB_ENDPOINT_DESC_SIZE 7
#define USB_DEVICE_DESCRIPTOR_TYPE 1
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2
#define USB_STRING_DESCRIPTOR_TYPE 3
#define USB_INTERFACE_DESCRIPTOR_TYPE 4
#define USB_ENDPOINT_DESCRIPTOR_TYPE 5
// usb_20.pdf Table 9.6 Standard Feature Selectors
#define DEVICE_REMOTE_WAKEUP 1
#define ENDPOINT_HALT 2
#define TEST_MODE 3
// usb_20.pdf Figure 9-4. Information Returned by a GetStatus() Request to a Device
#define FEATURE_SELFPOWERED_ENABLED (1 << 0)
#define FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1)
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
#define USB_DEVICE_CLASS_STORAGE 0x08
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
#define USB_CONFIG_POWERED_MASK 0x40
#define USB_CONFIG_BUS_POWERED 0x80
#define USB_CONFIG_SELF_POWERED 0xC0
#define USB_CONFIG_REMOTE_WAKEUP 0x20
// bMaxPower in Configuration Descriptor
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
// bEndpointAddress in Endpoint Descriptor
#define USB_ENDPOINT_DIRECTION_MASK 0x80
#define USB_ENDPOINT_OUT(addr) (lowByte((addr) | 0x00))
#define USB_ENDPOINT_IN(addr) (lowByte((addr) | 0x80))
#define USB_ENDPOINT_TYPE_MASK 0x03
#define USB_ENDPOINT_TYPE_CONTROL 0x00
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
#define USB_ENDPOINT_TYPE_BULK 0x02
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
#define CDC_V1_10 0x0110
#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02
#define CDC_CALL_MANAGEMENT 0x01
#define CDC_ABSTRACT_CONTROL_MODEL 0x02
#define CDC_HEADER 0x00
#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02
#define CDC_UNION 0x06
#define CDC_CS_INTERFACE 0x24
#define CDC_CS_ENDPOINT 0x25
#define CDC_DATA_INTERFACE_CLASS 0x0A
#define MSC_SUBCLASS_SCSI 0x06
#define MSC_PROTOCOL_BULK_ONLY 0x50
#ifndef USB_VERSION
#define USB_VERSION 0x200
#endif
// Device
typedef struct {
u8 len; // 18
u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE
u16 usbVersion; // 0x200 or 0x210
u8 deviceClass;
u8 deviceSubClass;
u8 deviceProtocol;
u8 packetSize0; // Packet 0
u16 idVendor;
u16 idProduct;
u16 deviceVersion; // 0x100
u8 iManufacturer;
u8 iProduct;
u8 iSerialNumber;
u8 bNumConfigurations;
} DeviceDescriptor;
// Config
typedef struct {
u8 len; // 9
u8 dtype; // 2
u16 clen; // total length
u8 numInterfaces;
u8 config;
u8 iconfig;
u8 attributes;
u8 maxPower;
} ConfigDescriptor;
// String
// Interface
typedef struct
{
u8 len; // 9
u8 dtype; // 4
u8 number;
u8 alternate;
u8 numEndpoints;
u8 interfaceClass;
u8 interfaceSubClass;
u8 protocol;
u8 iInterface;
} InterfaceDescriptor;
// Endpoint
typedef struct
{
u8 len; // 7
u8 dtype; // 5
u8 addr;
u8 attr;
u16 packetSize;
u8 interval;
} EndpointDescriptor;
// Interface Association Descriptor
// Used to bind 2 interfaces together in CDC compostite device
typedef struct
{
u8 len; // 8
u8 dtype; // 11
u8 firstInterface;
u8 interfaceCount;
u8 functionClass;
u8 funtionSubClass;
u8 functionProtocol;
u8 iInterface;
} IADDescriptor;
// CDC CS interface descriptor
typedef struct
{
u8 len; // 5
u8 dtype; // 0x24
u8 subtype;
u8 d0;
u8 d1;
} CDCCSInterfaceDescriptor;
typedef struct
{
u8 len; // 4
u8 dtype; // 0x24
u8 subtype;
u8 d0;
} CDCCSInterfaceDescriptor4;
typedef struct
{
u8 len;
u8 dtype; // 0x24
u8 subtype; // 1
u8 bmCapabilities;
u8 bDataInterface;
} CMFunctionalDescriptor;
typedef struct
{
u8 len;
u8 dtype; // 0x24
u8 subtype; // 1
u8 bmCapabilities;
} ACMFunctionalDescriptor;
typedef struct
{
// IAD
IADDescriptor iad; // Only needed on compound device
// Control
InterfaceDescriptor cif; //
CDCCSInterfaceDescriptor header;
CMFunctionalDescriptor callManagement; // Call Management
ACMFunctionalDescriptor controlManagement; // ACM
CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION
EndpointDescriptor cifin;
// Data
//InterfaceDescriptor dif; // kai:removed
EndpointDescriptor in;
EndpointDescriptor out;
} CDCDescriptor;
typedef struct
{
InterfaceDescriptor msc;
EndpointDescriptor in;
EndpointDescriptor out;
} MSCDescriptor;
#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \
{ 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
#define D_CONFIG(_totalLength,_interfaces) \
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) }
#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \
{ 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 }
#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \
{ 7, 5, _addr,_attr,_packetSize, _interval }
#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \
{ 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 }
#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
// Bootloader related fields
// Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten
// by the running sketch before to actual reboot).
// Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both
// the usafe and the safe location.
#ifndef MAGIC_KEY
#define MAGIC_KEY 0x7777
#endif
#ifndef MAGIC_KEY_POS
#define MAGIC_KEY_POS 0x0800
#endif
#ifndef NEW_LUFA_SIGNATURE
#define NEW_LUFA_SIGNATURE 0xDCFB
#endif
#endif

View File

@ -0,0 +1,64 @@
/*
bridge USB-serial to hardware-serial
for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro)
hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB
see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino
-> CDC.cpp|HardwareSerial.cpp for serial implementation details
this sketch is mainly for demonstration / test of CDC communication
performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet
*/
uint32_t baud = 9600;
uint8_t databits = 8;
uint8_t stopbits = 1;
uint8_t parity = 0;
void setup() {
Serial.begin(baud); // USB
Serial1.begin(baud, SERIAL_8N1);
}
void loop() {
// show USB connected state
if (Serial) TXLED1;
else TXLED0;
// configure hardware serial
if (Serial.baud() != baud ||
Serial.numbits() != databits ||
Serial.stopbits() != stopbits ||
Serial.paritytype() != parity) {
baud = Serial.baud();
databits = Serial.numbits();
stopbits = Serial.stopbits();
parity = Serial.paritytype();
uint8_t config = 0; // ucsrc register
switch (databits) {
case 5: break;
case 6: config |= 2; break;
case 7: config |= 4; break;
case 8: config |= 6; break;
default: config |= 6;
}
switch (stopbits) {
case 2: config |= 8;
// 1.5 stopbits not supported
}
switch (parity) {
case 1: config |= 0x30; break; // odd
case 2: config |= 0x20; break; // even
// mark, space not supported
}
Serial1.end();
Serial1.begin(baud, config);
}
// bridge
if (Serial.available() > 0)
Serial1.write(Serial.read());
if (Serial1.available() > 0)
Serial.write(Serial1.read());
}

View File

@ -0,0 +1,320 @@
/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/
#include "USBCore.h" // kai:added
#include "USBAPI.h"
#include "USBDesc.h" // kai:added
#include <avr/wdt.h>
#include <util/atomic.h>
#if defined(USBCON)
typedef struct
{
u32 dwDTERate;
u8 bCharFormat;
u8 bParityType;
u8 bDataBits;
u8 lineState;
} LineInfo;
static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };
static volatile int32_t breakValue = -1;
static u8 wdtcsr_save;
#define WEAK __attribute__ ((weak))
extern const CDCDescriptor _cdcInterface PROGMEM;
const CDCDescriptor _cdcInterface =
{
D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
// CDC communication interface
D_INTERFACE(CDC_ACM_INTERFACE1,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd)
D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not)
D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE1,CDC_DATA_INTERFACE1), // Communication interface is master, data interface is slave 0
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM1),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),
// CDC data interface
D_INTERFACE(CDC_DATA_INTERFACE1,2,CDC_DATA_INTERFACE_CLASS,0,0),
D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT1),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0),
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN1 ),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0)
, // kai: added
D_IAD(2,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),
// CDC communication interface
D_INTERFACE(CDC_ACM_INTERFACE2,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
D_CDCCS(CDC_HEADER,0x10,0x01), // Header (1.10 bcd)
D_CDCCS(CDC_CALL_MANAGEMENT,1,1), // Device handles call management (not)
D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6), // SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE2,CDC_DATA_INTERFACE2), // Communication interface is master, data interface is slave 0
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM2),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),
// CDC data interface
D_INTERFACE(CDC_DATA_INTERFACE2,2,CDC_DATA_INTERFACE_CLASS,0,0),
D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT2),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0),
D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN2),USB_ENDPOINT_TYPE_BULK,USB_EP_SIZE,0)
};
bool isLUFAbootloader()
{
return pgm_read_word(FLASHEND - 1) == NEW_LUFA_SIGNATURE;
}
int CDC_GetInterface(u8* interfaceNum)
{
interfaceNum[0] += 4; // kai
return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface));
}
bool CDC_Setup(USBSetup& setup)
{
u8 r = setup.bRequest;
u8 requestType = setup.bmRequestType;
if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
{
if (CDC_GET_LINE_CODING == r)
{
USB_SendControl(0,(void*)&_usbLineInfo,7);
return true;
}
}
if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
{
if (CDC_SEND_BREAK == r)
{
breakValue = ((uint16_t)setup.wValueH << 8) | setup.wValueL;
}
if (CDC_SET_LINE_CODING == r)
{
USB_RecvControl((void*)&_usbLineInfo,7);
}
if (CDC_SET_CONTROL_LINE_STATE == r)
{
_usbLineInfo.lineState = setup.wValueL;
// auto-reset into the bootloader is triggered when the port, already
// open at 1200 bps, is closed. this is the signal to start the watchdog
// with a relatively long period so it can finish housekeeping tasks
// like servicing endpoints before the sketch ends
uint16_t magic_key_pos = MAGIC_KEY_POS;
// If we don't use the new RAMEND directly, check manually if we have a newer bootloader.
// This is used to keep compatible with the old leonardo bootloaders.
// You are still able to set the magic key position manually to RAMEND-1 to save a few bytes for this check.
#if MAGIC_KEY_POS != (RAMEND-1)
// For future boards save the key in the inproblematic RAMEND
// Which is reserved for the main() return value (which will never return)
if (isLUFAbootloader()) {
// horray, we got a new bootloader!
magic_key_pos = (RAMEND-1);
}
#endif
// We check DTR state to determine if host port is open (bit 0 of lineState).
if (1200 == _usbLineInfo.dwDTERate && (_usbLineInfo.lineState & 0x01) == 0)
{
#if MAGIC_KEY_POS != (RAMEND-1)
// Backup ram value if its not a newer bootloader and it hasn't already been saved.
// This should avoid memory corruption at least a bit, not fully
if (magic_key_pos != (RAMEND-1) && *(uint16_t *)magic_key_pos != MAGIC_KEY) {
*(uint16_t *)(RAMEND-1) = *(uint16_t *)magic_key_pos;
}
#endif
// Store boot key
*(uint16_t *)magic_key_pos = MAGIC_KEY;
// Save the watchdog state in case the reset is aborted.
wdtcsr_save = WDTCSR;
wdt_enable(WDTO_120MS);
}
else if (*(uint16_t *)magic_key_pos == MAGIC_KEY)
{
// Most OSs do some intermediate steps when configuring ports and DTR can
// twiggle more than once before stabilizing.
// To avoid spurious resets we set the watchdog to 120ms and eventually
// cancel if DTR goes back high.
// Cancellation is only done if an auto-reset was started, which is
// indicated by the magic key having been set.
wdt_reset();
// Restore the watchdog state in case the sketch was using it.
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = wdtcsr_save;
#if MAGIC_KEY_POS != (RAMEND-1)
// Restore backed up (old bootloader) magic key data
if (magic_key_pos != (RAMEND-1)) {
*(uint16_t *)magic_key_pos = *(uint16_t *)(RAMEND-1);
} else
#endif
{
// Clean up RAMEND key
*(uint16_t *)magic_key_pos = 0x0000;
}
}
}
return true;
}
return false;
}
void Serial_::begin(unsigned long /* baud_count */)
{
peek_buffer = -1;
}
void Serial_::begin(unsigned long /* baud_count */, byte /* config */)
{
peek_buffer = -1;
}
void Serial_::end(void)
{
}
int Serial_::available(void)
{
if (peek_buffer >= 0) {
return 1 + USB_Available(CDC_RX);
}
return USB_Available(CDC_RX);
}
int Serial_::peek(void)
{
if (peek_buffer < 0)
peek_buffer = USB_Recv(CDC_RX);
return peek_buffer;
}
int Serial_::read(void)
{
if (peek_buffer >= 0) {
int c = peek_buffer;
peek_buffer = -1;
return c;
}
return USB_Recv(CDC_RX);
}
int Serial_::availableForWrite(void)
{
return USB_SendSpace(CDC_TX);
}
void Serial_::flush(void)
{
USB_Flush(CDC_TX);
}
size_t Serial_::write(uint8_t c)
{
return write(&c, 1);
}
size_t Serial_::write(const uint8_t *buffer, size_t size)
{
/* only try to send bytes if the high-level CDC connection itself
is open (not just the pipe) - the OS should set lineState when the port
is opened and clear lineState when the port is closed.
bytes sent before the user opens the connection or after
the connection is closed are lost - just like with a UART. */
// TODO - ZE - check behavior on different OSes and test what happens if an
// open connection isn't broken cleanly (cable is yanked out, host dies
// or locks up, or host virtual serial port hangs)
if (_usbLineInfo.lineState > 0) {
int r = USB_Send(CDC_TX,buffer,size);
if (r > 0) {
return r;
} else {
setWriteError();
return 0;
}
}
setWriteError();
return 0;
}
// This operator is a convenient way for a sketch to check whether the
// port has actually been configured and opened by the host (as opposed
// to just being connected to the host). It can be used, for example, in
// setup() before printing to ensure that an application on the host is
// actually ready to receive and display the data.
// We add a short delay before returning to fix a bug observed by Federico
// where the port is configured (lineState != 0) but not quite opened.
Serial_::operator bool() {
bool result = false;
if (_usbLineInfo.lineState > 0)
result = true;
delay(10);
return result;
}
unsigned long Serial_::baud() {
// Disable interrupts while reading a multi-byte value
uint32_t baudrate;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
baudrate = _usbLineInfo.dwDTERate;
}
return baudrate;
}
uint8_t Serial_::stopbits() {
return _usbLineInfo.bCharFormat;
}
uint8_t Serial_::paritytype() {
return _usbLineInfo.bParityType;
}
uint8_t Serial_::numbits() {
return _usbLineInfo.bDataBits;
}
bool Serial_::dtr() {
return _usbLineInfo.lineState & 0x1;
}
bool Serial_::rts() {
return _usbLineInfo.lineState & 0x2;
}
int32_t Serial_::readBreak() {
int32_t ret;
// Disable IRQs while reading and clearing breakValue to make
// sure we don't overwrite a value just set by the ISR.
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
ret = breakValue;
breakValue = -1;
}
return ret;
}
Serial_ Serial;
#endif /* if defined(USBCON) */

View File

@ -0,0 +1,8 @@
## multiple CDC interface test
As mentioned [here](https://arduino.stackexchange.com/a/31695/62145), Arduino functions can be _overwritten_ by copying complete files into the own project.
This is used to create a device with 2 CDC interfaces. For simplicity only one of both is functional (configurable in USBDesc.h)
The modifications have been done against Arduino 1.8.10, for changes see comments containing `kai`.

View File

@ -0,0 +1,870 @@
/* Copyright (c) 2010, Peter Barrett
** Sleep/Wakeup support added by Michael Dreher
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/
#include "USBAPI.h"
#include "USBDesc.h" // kai:added
#include "PluggableUSB.h"
#include <stdlib.h>
#if defined(USBCON)
/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
#define TX_RX_LED_PULSE_MS 100
volatile u8 TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */
volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */
//==================================================================
//==================================================================
extern const u16 STRING_LANGUAGE[] PROGMEM;
extern const u8 STRING_PRODUCT[] PROGMEM;
extern const u8 STRING_MANUFACTURER[] PROGMEM;
extern const DeviceDescriptor USB_DeviceDescriptorIAD PROGMEM;
const u16 STRING_LANGUAGE[2] = {
(3<<8) | (2+2),
0x0409 // English
};
#ifndef USB_PRODUCT
// If no product is provided, use USB IO Board
#define USB_PRODUCT "USB IO Board"
#endif
const u8 STRING_PRODUCT[] PROGMEM = USB_PRODUCT;
#if USB_VID == 0x2341
# if defined(USB_MANUFACTURER)
# undef USB_MANUFACTURER
# endif
# define USB_MANUFACTURER "Arduino LLC"
#elif USB_VID == 0x1b4f
# if defined(USB_MANUFACTURER)
# undef USB_MANUFACTURER
# endif
# define USB_MANUFACTURER "SparkFun"
#elif !defined(USB_MANUFACTURER)
// Fall through to unknown if no manufacturer name was provided in a macro
# define USB_MANUFACTURER "Unknown"
#endif
const u8 STRING_MANUFACTURER[] PROGMEM = USB_MANUFACTURER;
#define DEVICE_CLASS 0x02
// DEVICE DESCRIPTOR
const DeviceDescriptor USB_DeviceDescriptorIAD =
D_DEVICE(0xEF,0x02,0x01,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,ISERIAL,1);
//==================================================================
//==================================================================
volatile u8 _usbConfiguration = 0;
volatile u8 _usbCurrentStatus = 0; // meaning of bits see usb_20.pdf, Figure 9-4. Information Returned by a GetStatus() Request to a Device
volatile u8 _usbSuspendState = 0; // copy of UDINT to check SUSPI and WAKEUPI bits
static inline void WaitIN(void)
{
while (!(UEINTX & (1<<TXINI)))
;
}
static inline void ClearIN(void)
{
UEINTX = ~(1<<TXINI);
}
static inline void WaitOUT(void)
{
while (!(UEINTX & (1<<RXOUTI)))
;
}
static inline u8 WaitForINOrOUT()
{
while (!(UEINTX & ((1<<TXINI)|(1<<RXOUTI))))
;
return (UEINTX & (1<<RXOUTI)) == 0;
}
static inline void ClearOUT(void)
{
UEINTX = ~(1<<RXOUTI);
}
static inline void Recv(volatile u8* data, u8 count)
{
while (count--)
*data++ = UEDATX;
RXLED1; // light the RX LED
RxLEDPulse = TX_RX_LED_PULSE_MS;
}
static inline u8 Recv8()
{
RXLED1; // light the RX LED
RxLEDPulse = TX_RX_LED_PULSE_MS;
return UEDATX;
}
static inline void Send8(u8 d)
{
UEDATX = d;
}
static inline void SetEP(u8 ep)
{
UENUM = ep;
}
static inline u8 FifoByteCount()
{
return UEBCLX;
}
static inline u8 ReceivedSetupInt()
{
return UEINTX & (1<<RXSTPI);
}
static inline void ClearSetupInt()
{
UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
}
static inline void Stall()
{
UECONX = (1<<STALLRQ) | (1<<EPEN);
}
static inline u8 ReadWriteAllowed()
{
return UEINTX & (1<<RWAL);
}
static inline u8 Stalled()
{
return UEINTX & (1<<STALLEDI);
}
static inline u8 FifoFree()
{
return UEINTX & (1<<FIFOCON);
}
static inline void ReleaseRX()
{
UEINTX = 0x6B; // FIFOCON=0 NAKINI=1 RWAL=1 NAKOUTI=0 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=1
}
static inline void ReleaseTX()
{
UEINTX = 0x3A; // FIFOCON=0 NAKINI=0 RWAL=1 NAKOUTI=1 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=0
}
static inline u8 FrameNumber()
{
return UDFNUML;
}
//==================================================================
//==================================================================
u8 USBGetConfiguration(void)
{
return _usbConfiguration;
}
#define USB_RECV_TIMEOUT
class LockEP
{
u8 _sreg;
public:
LockEP(u8 ep) : _sreg(SREG)
{
cli();
SetEP(ep & 7);
}
~LockEP()
{
SREG = _sreg;
}
};
// Number of bytes, assumes a rx endpoint
u8 USB_Available(u8 ep)
{
LockEP lock(ep);
return FifoByteCount();
}
// Non Blocking receive
// Return number of bytes read
int USB_Recv(u8 ep, void* d, int len)
{
if (!_usbConfiguration || len < 0)
return -1;
LockEP lock(ep);
u8 n = FifoByteCount();
len = min(n,len);
n = len;
u8* dst = (u8*)d;
while (n--)
*dst++ = Recv8();
if (len && !FifoByteCount()) // release empty buffer
ReleaseRX();
return len;
}
// Recv 1 byte if ready
int USB_Recv(u8 ep)
{
u8 c;
if (USB_Recv(ep,&c,1) != 1)
return -1;
return c;
}
// Space in send EP
u8 USB_SendSpace(u8 ep)
{
LockEP lock(ep);
if (!ReadWriteAllowed())
return 0;
return USB_EP_SIZE - FifoByteCount();
}
// Blocking Send of data to an endpoint
int USB_Send(u8 ep, const void* d, int len)
{
if (!_usbConfiguration)
return -1;
if (_usbSuspendState & (1<<SUSPI)) {
//send a remote wakeup
UDCON |= (1 << RMWKUP);
}
int r = len;
const u8* data = (const u8*)d;
u8 timeout = 250; // 250ms timeout on send? TODO
bool sendZlp = false;
while (len || sendZlp)
{
u8 n = USB_SendSpace(ep);
if (n == 0)
{
if (!(--timeout))
return -1;
delay(1);
continue;
}
if (n > len) {
n = len;
}
{
LockEP lock(ep);
// Frame may have been released by the SOF interrupt handler
if (!ReadWriteAllowed())
continue;
len -= n;
if (ep & TRANSFER_ZERO)
{
while (n--)
Send8(0);
}
else if (ep & TRANSFER_PGM)
{
while (n--)
Send8(pgm_read_byte(data++));
}
else
{
while (n--)
Send8(*data++);
}
if (sendZlp) {
ReleaseTX();
sendZlp = false;
} else if (!ReadWriteAllowed()) { // ...release if buffer is full...
ReleaseTX();
if (len == 0) sendZlp = true;
} else if ((len == 0) && (ep & TRANSFER_RELEASE)) { // ...or if forced with TRANSFER_RELEASE
// XXX: TRANSFER_RELEASE is never used can be removed?
ReleaseTX();
}
}
}
TXLED1; // light the TX LED
TxLEDPulse = TX_RX_LED_PULSE_MS;
return r;
}
u8 _initEndpoints[USB_ENDPOINTS] =
{
0, // Control Endpoint
EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM
EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT
EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN
// kai:added
EP_TYPE_INTERRUPT_IN, // CDC_ENDPOINT_ACM
EP_TYPE_BULK_OUT, // CDC_ENDPOINT_OUT
EP_TYPE_BULK_IN, // CDC_ENDPOINT_IN
// Following endpoints are automatically initialized to 0
};
#define EP_SINGLE_64 0x32 // EP0
#define EP_DOUBLE_64 0x36 // Other endpoints
#define EP_SINGLE_16 0x12
static
void InitEP(u8 index, u8 type, u8 size)
{
UENUM = index;
UECONX = (1<<EPEN);
UECFG0X = type;
UECFG1X = size;
}
static
void InitEndpoints()
{
for (u8 i = 1; i < sizeof(_initEndpoints) && _initEndpoints[i] != 0; i++)
{
UENUM = i;
UECONX = (1<<EPEN);
UECFG0X = _initEndpoints[i];
#if USB_EP_SIZE == 16
UECFG1X = EP_SINGLE_16;
#elif USB_EP_SIZE == 64
UECFG1X = EP_DOUBLE_64;
#else
#error Unsupported value for USB_EP_SIZE
#endif
}
UERST = 0x7E; // And reset them
UERST = 0;
}
// Handle CLASS_INTERFACE requests
static
bool ClassInterfaceRequest(USBSetup& setup)
{
u8 i = setup.wIndex;
if (CDC_CLASS_INTERFACE == i) // kai
return CDC_Setup(setup);
#ifdef PLUGGABLE_USB_ENABLED
return PluggableUSB().setup(setup);
#endif
return false;
}
static int _cmark;
static int _cend;
void InitControl(int end)
{
SetEP(0);
_cmark = 0;
_cend = end;
}
static
bool SendControl(u8 d)
{
if (_cmark < _cend)
{
if (!WaitForINOrOUT())
return false;
Send8(d);
if (!((_cmark + 1) & 0x3F))
ClearIN(); // Fifo is full, release this packet
}
_cmark++;
return true;
}
// Clipped by _cmark/_cend
int USB_SendControl(u8 flags, const void* d, int len)
{
int sent = len;
const u8* data = (const u8*)d;
bool pgm = flags & TRANSFER_PGM;
while (len--)
{
u8 c = pgm ? pgm_read_byte(data++) : *data++;
if (!SendControl(c))
return -1;
}
return sent;
}
// Send a USB descriptor string. The string is stored in PROGMEM as a
// plain ASCII string but is sent out as UTF-16 with the correct 2-byte
// prefix
static bool USB_SendStringDescriptor(const u8*string_P, u8 string_len, uint8_t flags) {
SendControl(2 + string_len * 2);
SendControl(3);
bool pgm = flags & TRANSFER_PGM;
for(u8 i = 0; i < string_len; i++) {
bool r = SendControl(pgm ? pgm_read_byte(&string_P[i]) : string_P[i]);
r &= SendControl(0); // high byte
if(!r) {
return false;
}
}
return true;
}
// Does not timeout or cross fifo boundaries
int USB_RecvControl(void* d, int len)
{
auto length = len;
while(length)
{
// Dont receive more than the USB Control EP has to offer
// Use fixed 64 because control EP always have 64 bytes even on 16u2.
auto recvLength = length;
if(recvLength > 64){
recvLength = 64;
}
// Write data to fit to the end (not the beginning) of the array
WaitOUT();
Recv((u8*)d + len - length, recvLength);
ClearOUT();
length -= recvLength;
}
return len;
}
static u8 SendInterfaces()
{
u8 interfaces = 0;
CDC_GetInterface(&interfaces);
#ifdef PLUGGABLE_USB_ENABLED
PluggableUSB().getInterface(&interfaces);
#endif
return interfaces;
}
// Construct a dynamic configuration descriptor
// This really needs dynamic endpoint allocation etc
// TODO
static
bool SendConfiguration(int maxlen)
{
// Count and measure interfaces
InitControl(0);
u8 interfaces = SendInterfaces();
ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces);
// Now send them
InitControl(maxlen);
USB_SendControl(0,&config,sizeof(ConfigDescriptor));
SendInterfaces();
return true;
}
static
bool SendDescriptor(USBSetup& setup)
{
int ret;
u8 t = setup.wValueH;
if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t)
return SendConfiguration(setup.wLength);
InitControl(setup.wLength);
#ifdef PLUGGABLE_USB_ENABLED
ret = PluggableUSB().getDescriptor(setup);
if (ret != 0) {
return (ret > 0 ? true : false);
}
#endif
const u8* desc_addr = 0;
if (USB_DEVICE_DESCRIPTOR_TYPE == t)
{
desc_addr = (const u8*)&USB_DeviceDescriptorIAD;
}
else if (USB_STRING_DESCRIPTOR_TYPE == t)
{
if (setup.wValueL == 0) {
desc_addr = (const u8*)&STRING_LANGUAGE;
}
else if (setup.wValueL == IPRODUCT) {
return USB_SendStringDescriptor(STRING_PRODUCT, strlen(USB_PRODUCT), TRANSFER_PGM);
}
else if (setup.wValueL == IMANUFACTURER) {
return USB_SendStringDescriptor(STRING_MANUFACTURER, strlen(USB_MANUFACTURER), TRANSFER_PGM);
}
else if (setup.wValueL == ISERIAL) {
#ifdef PLUGGABLE_USB_ENABLED
char name[ISERIAL_MAX_LEN];
PluggableUSB().getShortName(name);
return USB_SendStringDescriptor((uint8_t*)name, strlen(name), 0);
#endif
}
else
return false;
}
if (desc_addr == 0)
return false;
u8 desc_length = pgm_read_byte(desc_addr);
USB_SendControl(TRANSFER_PGM,desc_addr,desc_length);
return true;
}
// Endpoint 0 interrupt
ISR(USB_COM_vect)
{
SetEP(0);
if (!ReceivedSetupInt())
return;
USBSetup setup;
Recv((u8*)&setup,8);
ClearSetupInt();
u8 requestType = setup.bmRequestType;
if (requestType & REQUEST_DEVICETOHOST)
WaitIN();
else
ClearIN();
bool ok = true;
if (REQUEST_STANDARD == (requestType & REQUEST_TYPE))
{
// Standard Requests
u8 r = setup.bRequest;
u16 wValue = setup.wValueL | (setup.wValueH << 8);
if (GET_STATUS == r)
{
if (requestType == (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_DEVICE))
{
Send8(_usbCurrentStatus);
Send8(0);
}
else
{
// TODO: handle the HALT state of an endpoint here
// see "Figure 9-6. Information Returned by a GetStatus() Request to an Endpoint" in usb_20.pdf for more information
Send8(0);
Send8(0);
}
}
else if (CLEAR_FEATURE == r)
{
if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE))
&& (wValue == DEVICE_REMOTE_WAKEUP))
{
_usbCurrentStatus &= ~FEATURE_REMOTE_WAKEUP_ENABLED;
}
}
else if (SET_FEATURE == r)
{
if((requestType == (REQUEST_HOSTTODEVICE | REQUEST_STANDARD | REQUEST_DEVICE))
&& (wValue == DEVICE_REMOTE_WAKEUP))
{
_usbCurrentStatus |= FEATURE_REMOTE_WAKEUP_ENABLED;
}
}
else if (SET_ADDRESS == r)
{
WaitIN();
UDADDR = setup.wValueL | (1<<ADDEN);
}
else if (GET_DESCRIPTOR == r)
{
ok = SendDescriptor(setup);
}
else if (SET_DESCRIPTOR == r)
{
ok = false;
}
else if (GET_CONFIGURATION == r)
{
Send8(1);
}
else if (SET_CONFIGURATION == r)
{
if (REQUEST_DEVICE == (requestType & REQUEST_RECIPIENT))
{
InitEndpoints();
_usbConfiguration = setup.wValueL;
} else
ok = false;
}
else if (GET_INTERFACE == r)
{
}
else if (SET_INTERFACE == r)
{
}
}
else
{
InitControl(setup.wLength); // Max length of transfer
ok = ClassInterfaceRequest(setup);
}
if (ok)
ClearIN();
else
{
Stall();
}
}
void USB_Flush(u8 ep)
{
SetEP(ep);
if (FifoByteCount())
ReleaseTX();
}
static inline void USB_ClockDisable()
{
#if defined(OTGPADE)
USBCON = (USBCON & ~(1<<OTGPADE)) | (1<<FRZCLK); // freeze clock and disable VBUS Pad
#else // u2 Series
USBCON = (1 << FRZCLK); // freeze clock
#endif
PLLCSR &= ~(1<<PLLE); // stop PLL
}
static inline void USB_ClockEnable()
{
#if defined(UHWCON)
UHWCON |= (1<<UVREGE); // power internal reg
#endif
USBCON = (1<<USBE) | (1<<FRZCLK); // clock frozen, usb enabled
// ATmega32U4
#if defined(PINDIV)
#if F_CPU == 16000000UL
PLLCSR |= (1<<PINDIV); // Need 16 MHz xtal
#elif F_CPU == 8000000UL
PLLCSR &= ~(1<<PINDIV); // Need 8 MHz xtal
#else
#error "Clock rate of F_CPU not supported"
#endif
#elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
// for the u2 Series the datasheet is confusing. On page 40 its called PINDIV and on page 290 its called PLLP0
#if F_CPU == 16000000UL
// Need 16 MHz xtal
PLLCSR |= (1 << PLLP0);
#elif F_CPU == 8000000UL
// Need 8 MHz xtal
PLLCSR &= ~(1 << PLLP0);
#endif
// AT90USB646, AT90USB647, AT90USB1286, AT90USB1287
#elif defined(PLLP2)
#if F_CPU == 16000000UL
#if defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
// For Atmel AT90USB128x only. Do not use with Atmel AT90USB64x.
PLLCSR = (PLLCSR & ~(1<<PLLP1)) | ((1<<PLLP2) | (1<<PLLP0)); // Need 16 MHz xtal
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)
// For AT90USB64x only. Do not use with AT90USB128x.
PLLCSR = (PLLCSR & ~(1<<PLLP0)) | ((1<<PLLP2) | (1<<PLLP1)); // Need 16 MHz xtal
#else
#error "USB Chip not supported, please defined method of USB PLL initialization"
#endif
#elif F_CPU == 8000000UL
// for Atmel AT90USB128x and AT90USB64x
PLLCSR = (PLLCSR & ~(1<<PLLP2)) | ((1<<PLLP1) | (1<<PLLP0)); // Need 8 MHz xtal
#else
#error "Clock rate of F_CPU not supported"
#endif
#else
#error "USB Chip not supported, please defined method of USB PLL initialization"
#endif
PLLCSR |= (1<<PLLE);
while (!(PLLCSR & (1<<PLOCK))) // wait for lock pll
{
}
// Some tests on specific versions of macosx (10.7.3), reported some
// strange behaviors when the board is reset using the serial
// port touch at 1200 bps. This delay fixes this behavior.
delay(1);
#if defined(OTGPADE)
USBCON = (USBCON & ~(1<<FRZCLK)) | (1<<OTGPADE); // start USB clock, enable VBUS Pad
#else
USBCON &= ~(1 << FRZCLK); // start USB clock
#endif
#if defined(RSTCPU)
#if defined(LSM)
UDCON &= ~((1<<RSTCPU) | (1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode
#else // u2 Series
UDCON &= ~((1 << RSTCPU) | (1 << RMWKUP) | (1 << DETACH)); // enable attach resistor, set full speed mode
#endif
#else
// AT90USB64x and AT90USB128x don't have RSTCPU
UDCON &= ~((1<<LSM) | (1<<RMWKUP) | (1<<DETACH)); // enable attach resistor, set full speed mode
#endif
}
// General interrupt
ISR(USB_GEN_vect)
{
u8 udint = UDINT;
UDINT &= ~((1<<EORSTI) | (1<<SOFI)); // clear the IRQ flags for the IRQs which are handled here, except WAKEUPI and SUSPI (see below)
// End of Reset
if (udint & (1<<EORSTI))
{
InitEP(0,EP_TYPE_CONTROL,EP_SINGLE_64); // init ep0
_usbConfiguration = 0; // not configured yet
UEIENX = 1 << RXSTPE; // Enable interrupts for ep0
}
// Start of Frame - happens every millisecond so we use it for TX and RX LED one-shot timing, too
if (udint & (1<<SOFI))
{
USB_Flush(CDC_TX); // Send a tx frame if found
// check whether the one-shot period has elapsed. if so, turn off the LED
if (TxLEDPulse && !(--TxLEDPulse))
TXLED0;
if (RxLEDPulse && !(--RxLEDPulse))
RXLED0;
}
// the WAKEUPI interrupt is triggered as soon as there are non-idle patterns on the data
// lines. Thus, the WAKEUPI interrupt can occur even if the controller is not in the "suspend" mode.
// Therefore the we enable it only when USB is suspended
if (udint & (1<<WAKEUPI))
{
UDIEN = (UDIEN & ~(1<<WAKEUPE)) | (1<<SUSPE); // Disable interrupts for WAKEUP and enable interrupts for SUSPEND
//TODO
// WAKEUPI shall be cleared by software (USB clock inputs must be enabled before).
//USB_ClockEnable();
UDINT &= ~(1<<WAKEUPI);
_usbSuspendState = (_usbSuspendState & ~(1<<SUSPI)) | (1<<WAKEUPI);
}
else if (udint & (1<<SUSPI)) // only one of the WAKEUPI / SUSPI bits can be active at time
{
UDIEN = (UDIEN & ~(1<<SUSPE)) | (1<<WAKEUPE); // Disable interrupts for SUSPEND and enable interrupts for WAKEUP
//TODO
//USB_ClockDisable();
UDINT &= ~((1<<WAKEUPI) | (1<<SUSPI)); // clear any already pending WAKEUP IRQs and the SUSPI request
_usbSuspendState = (_usbSuspendState & ~(1<<WAKEUPI)) | (1<<SUSPI);
}
}
// VBUS or counting frames
// Any frame counting?
u8 USBConnected()
{
u8 f = UDFNUML;
delay(3);
return f != UDFNUML;
}
//=======================================================================
//=======================================================================
USBDevice_ USBDevice;
USBDevice_::USBDevice_()
{
}
void USBDevice_::attach()
{
_usbConfiguration = 0;
_usbCurrentStatus = 0;
_usbSuspendState = 0;
USB_ClockEnable();
UDINT &= ~((1<<WAKEUPI) | (1<<SUSPI)); // clear already pending WAKEUP / SUSPEND requests
UDIEN = (1<<EORSTE) | (1<<SOFE) | (1<<SUSPE); // Enable interrupts for EOR (End of Reset), SOF (start of frame) and SUSPEND
TX_RX_LED_INIT;
}
void USBDevice_::detach()
{
}
// Check for interrupts
// TODO: VBUS detection
bool USBDevice_::configured()
{
return _usbConfiguration;
}
void USBDevice_::poll()
{
}
bool USBDevice_::wakeupHost()
{
// clear any previous wakeup request which might have been set but could be processed at that time
// e.g. because the host was not suspended at that time
UDCON &= ~(1 << RMWKUP);
if(!(UDCON & (1 << RMWKUP))
&& (_usbSuspendState & (1<<SUSPI))
&& (_usbCurrentStatus & FEATURE_REMOTE_WAKEUP_ENABLED))
{
// This short version will only work, when the device has not been suspended. Currently the
// Arduino core doesn't handle SUSPEND at all, so this is ok.
USB_ClockEnable();
UDCON |= (1 << RMWKUP); // send the wakeup request
return true;
}
return false;
}
bool USBDevice_::isSuspended()
{
return (_usbSuspendState & (1 << SUSPI));
}
#endif /* if defined(USBCON) */

View File

@ -0,0 +1,317 @@
// Copyright (c) 2010, Peter Barrett
/*
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/
#ifndef __USBCORE_H__
#define __USBCORE_H__
#include "USBAPI.h"
// Standard requests
#define GET_STATUS 0
#define CLEAR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADDRESS 5
#define GET_DESCRIPTOR 6
#define SET_DESCRIPTOR 7
#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9
#define GET_INTERFACE 10
#define SET_INTERFACE 11
// bmRequestType
#define REQUEST_HOSTTODEVICE 0x00
#define REQUEST_DEVICETOHOST 0x80
#define REQUEST_DIRECTION 0x80
#define REQUEST_STANDARD 0x00
#define REQUEST_CLASS 0x20
#define REQUEST_VENDOR 0x40
#define REQUEST_TYPE 0x60
#define REQUEST_DEVICE 0x00
#define REQUEST_INTERFACE 0x01
#define REQUEST_ENDPOINT 0x02
#define REQUEST_OTHER 0x03
#define REQUEST_RECIPIENT 0x03
#define REQUEST_DEVICETOHOST_CLASS_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_CLASS | REQUEST_INTERFACE)
#define REQUEST_HOSTTODEVICE_CLASS_INTERFACE (REQUEST_HOSTTODEVICE | REQUEST_CLASS | REQUEST_INTERFACE)
#define REQUEST_DEVICETOHOST_STANDARD_INTERFACE (REQUEST_DEVICETOHOST | REQUEST_STANDARD | REQUEST_INTERFACE)
// Class requests
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define MSC_RESET 0xFF
#define MSC_GET_MAX_LUN 0xFE
// Descriptors
#define USB_DEVICE_DESC_SIZE 18
#define USB_CONFIGUARTION_DESC_SIZE 9
#define USB_INTERFACE_DESC_SIZE 9
#define USB_ENDPOINT_DESC_SIZE 7
#define USB_DEVICE_DESCRIPTOR_TYPE 1
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 2
#define USB_STRING_DESCRIPTOR_TYPE 3
#define USB_INTERFACE_DESCRIPTOR_TYPE 4
#define USB_ENDPOINT_DESCRIPTOR_TYPE 5
// usb_20.pdf Table 9.6 Standard Feature Selectors
#define DEVICE_REMOTE_WAKEUP 1
#define ENDPOINT_HALT 2
#define TEST_MODE 3
// usb_20.pdf Figure 9-4. Information Returned by a GetStatus() Request to a Device
#define FEATURE_SELFPOWERED_ENABLED (1 << 0)
#define FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1)
#define USB_DEVICE_CLASS_COMMUNICATIONS 0x02
#define USB_DEVICE_CLASS_HUMAN_INTERFACE 0x03
#define USB_DEVICE_CLASS_STORAGE 0x08
#define USB_DEVICE_CLASS_VENDOR_SPECIFIC 0xFF
#define USB_CONFIG_POWERED_MASK 0x40
#define USB_CONFIG_BUS_POWERED 0x80
#define USB_CONFIG_SELF_POWERED 0xC0
#define USB_CONFIG_REMOTE_WAKEUP 0x20
// bMaxPower in Configuration Descriptor
#define USB_CONFIG_POWER_MA(mA) ((mA)/2)
// bEndpointAddress in Endpoint Descriptor
#define USB_ENDPOINT_DIRECTION_MASK 0x80
#define USB_ENDPOINT_OUT(addr) (lowByte((addr) | 0x00))
#define USB_ENDPOINT_IN(addr) (lowByte((addr) | 0x80))
#define USB_ENDPOINT_TYPE_MASK 0x03
#define USB_ENDPOINT_TYPE_CONTROL 0x00
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
#define USB_ENDPOINT_TYPE_BULK 0x02
#define USB_ENDPOINT_TYPE_INTERRUPT 0x03
#define TOBYTES(x) ((x) & 0xFF),(((x) >> 8) & 0xFF)
#define CDC_V1_10 0x0110
#define CDC_COMMUNICATION_INTERFACE_CLASS 0x02
#define CDC_CALL_MANAGEMENT 0x01
#define CDC_ABSTRACT_CONTROL_MODEL 0x02
#define CDC_HEADER 0x00
#define CDC_ABSTRACT_CONTROL_MANAGEMENT 0x02
#define CDC_UNION 0x06
#define CDC_CS_INTERFACE 0x24
#define CDC_CS_ENDPOINT 0x25
#define CDC_DATA_INTERFACE_CLASS 0x0A
#define MSC_SUBCLASS_SCSI 0x06
#define MSC_PROTOCOL_BULK_ONLY 0x50
#ifndef USB_VERSION
#define USB_VERSION 0x200
#endif
// Device
typedef struct {
u8 len; // 18
u8 dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE
u16 usbVersion; // 0x200 or 0x210
u8 deviceClass;
u8 deviceSubClass;
u8 deviceProtocol;
u8 packetSize0; // Packet 0
u16 idVendor;
u16 idProduct;
u16 deviceVersion; // 0x100
u8 iManufacturer;
u8 iProduct;
u8 iSerialNumber;
u8 bNumConfigurations;
} DeviceDescriptor;
// Config
typedef struct {
u8 len; // 9
u8 dtype; // 2
u16 clen; // total length
u8 numInterfaces;
u8 config;
u8 iconfig;
u8 attributes;
u8 maxPower;
} ConfigDescriptor;
// String
// Interface
typedef struct
{
u8 len; // 9
u8 dtype; // 4
u8 number;
u8 alternate;
u8 numEndpoints;
u8 interfaceClass;
u8 interfaceSubClass;
u8 protocol;
u8 iInterface;
} InterfaceDescriptor;
// Endpoint
typedef struct
{
u8 len; // 7
u8 dtype; // 5
u8 addr;
u8 attr;
u16 packetSize;
u8 interval;
} EndpointDescriptor;
// Interface Association Descriptor
// Used to bind 2 interfaces together in CDC compostite device
typedef struct
{
u8 len; // 8
u8 dtype; // 11
u8 firstInterface;
u8 interfaceCount;
u8 functionClass;
u8 funtionSubClass;
u8 functionProtocol;
u8 iInterface;
} IADDescriptor;
// CDC CS interface descriptor
typedef struct
{
u8 len; // 5
u8 dtype; // 0x24
u8 subtype;
u8 d0;
u8 d1;
} CDCCSInterfaceDescriptor;
typedef struct
{
u8 len; // 4
u8 dtype; // 0x24
u8 subtype;
u8 d0;
} CDCCSInterfaceDescriptor4;
typedef struct
{
u8 len;
u8 dtype; // 0x24
u8 subtype; // 1
u8 bmCapabilities;
u8 bDataInterface;
} CMFunctionalDescriptor;
typedef struct
{
u8 len;
u8 dtype; // 0x24
u8 subtype; // 1
u8 bmCapabilities;
} ACMFunctionalDescriptor;
typedef struct
{
// IAD
IADDescriptor iad; // Only needed on compound device
// Control
InterfaceDescriptor cif; //
CDCCSInterfaceDescriptor header;
CMFunctionalDescriptor callManagement; // Call Management
ACMFunctionalDescriptor controlManagement; // ACM
CDCCSInterfaceDescriptor functionalDescriptor; // CDC_UNION
EndpointDescriptor cifin;
// Data
InterfaceDescriptor dif;
EndpointDescriptor in;
EndpointDescriptor out;
// kai:added
IADDescriptor iad2; // Only needed on compound device
// Control
InterfaceDescriptor cif2; //
CDCCSInterfaceDescriptor header2;
CMFunctionalDescriptor callManagement2; // Call Management
ACMFunctionalDescriptor controlManagement2; // ACM
CDCCSInterfaceDescriptor functionalDescriptor2; // CDC_UNION
EndpointDescriptor cifin2;
// Data
InterfaceDescriptor dif2;
EndpointDescriptor in2;
EndpointDescriptor out2;
} CDCDescriptor;
typedef struct
{
InterfaceDescriptor msc;
EndpointDescriptor in;
EndpointDescriptor out;
} MSCDescriptor;
#define D_DEVICE(_class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs) \
{ 18, 1, USB_VERSION, _class,_subClass,_proto,_packetSize0,_vid,_pid,_version,_im,_ip,_is,_configs }
#define D_CONFIG(_totalLength,_interfaces) \
{ 9, 2, _totalLength,_interfaces, 1, 0, USB_CONFIG_BUS_POWERED | USB_CONFIG_REMOTE_WAKEUP, USB_CONFIG_POWER_MA(500) }
#define D_INTERFACE(_n,_numEndpoints,_class,_subClass,_protocol) \
{ 9, 4, _n, 0, _numEndpoints, _class,_subClass, _protocol, 0 }
#define D_ENDPOINT(_addr,_attr,_packetSize, _interval) \
{ 7, 5, _addr,_attr,_packetSize, _interval }
#define D_IAD(_firstInterface, _count, _class, _subClass, _protocol) \
{ 8, 11, _firstInterface, _count, _class, _subClass, _protocol, 0 }
#define D_CDCCS(_subtype,_d0,_d1) { 5, 0x24, _subtype, _d0, _d1 }
#define D_CDCCS4(_subtype,_d0) { 4, 0x24, _subtype, _d0 }
// Bootloader related fields
// Old Caterina bootloader places the MAGIC key into unsafe RAM locations (it can be rewritten
// by the running sketch before to actual reboot).
// Newer bootloaders, recognizable by the LUFA "signature" at the end of the flash, can handle both
// the usafe and the safe location.
#ifndef MAGIC_KEY
#define MAGIC_KEY 0x7777
#endif
#ifndef MAGIC_KEY_POS
#define MAGIC_KEY_POS 0x0800
#endif
#ifndef NEW_LUFA_SIGNATURE
#define NEW_LUFA_SIGNATURE 0xDCFB
#endif
#endif

View File

@ -0,0 +1,77 @@
/*
Copyright (c) 2011, Peter Barrett
Copyright (c) 2015, Arduino LLC
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
*/
#define PLUGGABLE_USB_ENABLED
#if defined(EPRST6)
#define USB_ENDPOINTS 7 // AtMegaxxU4
#else
#define USB_ENDPOINTS 5 // AtMegaxxU2
#endif
#define ISERIAL_MAX_LEN 20
#define CDC_INTERFACE_COUNT 2
#define CDC_ENPOINT_COUNT 3
// kai:begin
#undef CDC_ACM_INTERFACE
#undef CDC_DATA_INTERFACE
#undef CDC_FIRST_ENDPOINT
#undef CDC_ENDPOINT_ACM
#undef CDC_ENDPOINT_OUT
#undef CDC_ENDPOINT_IN
#undef CDC_RX
#undef CDC_TX
#define CDC_ACM_INTERFACE1 0 // CDC ACM
#define CDC_DATA_INTERFACE1 1 // CDC Data
#define CDC_FIRST_ENDPOINT1 1
#define CDC_ENDPOINT_ACM1 (CDC_FIRST_ENDPOINT1) // CDC First
#define CDC_ENDPOINT_OUT1 (CDC_FIRST_ENDPOINT1+1)
#define CDC_ENDPOINT_IN1 (CDC_FIRST_ENDPOINT1+2)
#define CDC_ACM_INTERFACE2 2 // CDC ACM
#define CDC_DATA_INTERFACE2 3 // CDC Data
#define CDC_FIRST_ENDPOINT2 4
#define CDC_ENDPOINT_ACM2 (CDC_FIRST_ENDPOINT2) // CDC First
#define CDC_ENDPOINT_OUT2 (CDC_FIRST_ENDPOINT2+1)
#define CDC_ENDPOINT_IN2 (CDC_FIRST_ENDPOINT2+2)
// only one of both interfaces is functional:
#define ACTIVE_INTERFACE 1
#if ACTIVE_INTERFACE == 1
# define CDC_CLASS_INTERFACE CDC_ACM_INTERFACE1
# define CDC_RX CDC_ENDPOINT_OUT1
# define CDC_TX CDC_ENDPOINT_IN1
#else
# define CDC_CLASS_INTERFACE CDC_ACM_INTERFACE2
# define CDC_RX CDC_ENDPOINT_OUT2
# define CDC_TX CDC_ENDPOINT_IN2
#endif
#undef USB_VID
#define USB_VID 0x2342
// kai:end
#define INTERFACE_COUNT (MSC_INTERFACE + MSC_INTERFACE_COUNT)
#define IMANUFACTURER 1
#define IPRODUCT 2
#define ISERIAL 3

View File

@ -0,0 +1,64 @@
/*
bridge USB-serial to hardware-serial
for Arduinos based on ATmega32u4 (Leonardo and compatible Pro Micro, Micro)
hardware serial is configured with baud-rate, databits, stopbits, parity as send over USB
see https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/cores/arduino
-> CDC.cpp|HardwareSerial.cpp for serial implementation details
this sketch is mainly for demonstration / test of CDC communication
performance as real usb-serial bridge would be inacceptable as each byte is send in separate USB packet
*/
uint32_t baud = 9600;
uint8_t databits = 8;
uint8_t stopbits = 1;
uint8_t parity = 0;
void setup() {
Serial.begin(baud); // USB
Serial1.begin(baud, SERIAL_8N1);
}
void loop() {
// show USB connected state
if (Serial) TXLED1;
else TXLED0;
// configure hardware serial
if (Serial.baud() != baud ||
Serial.numbits() != databits ||
Serial.stopbits() != stopbits ||
Serial.paritytype() != parity) {
baud = Serial.baud();
databits = Serial.numbits();
stopbits = Serial.stopbits();
parity = Serial.paritytype();
uint8_t config = 0; // ucsrc register
switch (databits) {
case 5: break;
case 6: config |= 2; break;
case 7: config |= 4; break;
case 8: config |= 6; break;
default: config |= 6;
}
switch (stopbits) {
case 2: config |= 8;
// 1.5 stopbits not supported
}
switch (parity) {
case 1: config |= 0x30; break; // odd
case 2: config |= 0x20; break; // even
// mark, space not supported
}
Serial1.end();
Serial1.begin(baud, config);
}
// bridge
if (Serial.available() > 0)
Serial1.write(Serial.read());
if (Serial1.available() > 0)
Serial.write(Serial1.read());
}

6
test/pi_pico/README.md Normal file
View File

@ -0,0 +1,6 @@
# `tinyusb_dev_cdc_dual_ports.uf2`
compiled from `C:/Program Files/Raspberry Pi/Pico SDK v1.5.1/pico-sdk/lib/tinyusb/examples/device/cdc_dual_ports`
to `C:/Users/` _user_`/Documents/Pico-v1.5.1/pico-examples/build/usb/device/tinyusb_device_examples/cdc_dual_ports/tinyusb_dev_cdc_dual_ports.uf2`

Binary file not shown.

42
test/rfc2217_server.diff Normal file
View File

@ -0,0 +1,42 @@
*** /n/archiv/python/rfc2217_server.py 2018-03-10 09:02:07.613771600 +0100
--- rfc2217_server.py 2018-03-09 20:57:44.933717100 +0100
***************
*** 26,31 ****
--- 26,32 ----
self,
logger=logging.getLogger('rfc2217.server') if debug else None)
self.log = logging.getLogger('redirector')
+ self.dlog = logging.getLogger('data')
def statusline_poller(self):
self.log.debug('status line poll thread started')
***************
*** 55,60 ****
--- 56,62 ----
try:
data = self.serial.read(self.serial.in_waiting or 1)
if data:
+ self.dlog.debug("serial read: "+data.encode('hex'))
# escape outgoing data when needed (Telnet IAC (0xff) character)
self.write(b''.join(self.rfc2217.escape(data)))
except socket.error as msg:
***************
*** 76,81 ****
--- 78,84 ----
data = self.socket.recv(1024)
if not data:
break
+ self.dlog.debug("socket read: "+data.encode('hex'))
self.serial.write(b''.join(self.rfc2217.filter(data)))
except socket.error as msg:
self.log.error('{}'.format(msg))
***************
*** 132,137 ****
--- 135,141 ----
logging.basicConfig(level=logging.INFO)
#~ logging.getLogger('root').setLevel(logging.INFO)
logging.getLogger('rfc2217').setLevel(level)
+ logging.getLogger('data').setLevel(level)
# connect to serial port
ser = serial.serial_for_url(args.SERIALPORT, do_not_open=True)

View File

@ -0,0 +1,33 @@
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 35
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 35
vectorDrawables.useSupportLibrary = true
missingDimensionStrategy 'device', 'anyDevice'
}
buildTypes {
release {
minifyEnabled true
}
}
namespace 'com.hoho.android.usbserial.examples'
}
dependencies {
implementation project(':usbSerialForAndroid')
implementation 'androidx.appcompat:appcompat:1.6.1' // later versions have minsdk 21
implementation 'com.google.android.material:material:1.11.0' // later versions have minsdk 19
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- mipmap/ic_launcher created with Android Studio -> New -> Image Asset using @color/colorPrimary and USB clip art -->
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<!-- for this simple app launchMode=singleTask and singleTop have same effect.
If you would start another activity in the app, e.g. Android Settings
then you should use singleTask, else a new MainActivity would be started
when the settings activity is currently shown -->
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:windowSoftInputMode="stateHidden|adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
</application>
</manifest>

View File

@ -0,0 +1,22 @@
package com.hoho.android.usbserial.examples;
import com.hoho.android.usbserial.driver.FtdiSerialDriver;
import com.hoho.android.usbserial.driver.ProbeTable;
import com.hoho.android.usbserial.driver.UsbSerialProber;
/**
* add devices here, that are not known to DefaultProber
*
* if the App should auto start for these devices, also
* add IDs to app/src/main/res/xml/device_filter.xml
*/
class CustomProber {
static UsbSerialProber getCustomProber() {
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x1234, 0x0001, FtdiSerialDriver.class); // e.g. device with custom VID+PID
customTable.addProduct(0x1234, 0x0002, FtdiSerialDriver.class); // e.g. device with custom VID+PID
return new UsbSerialProber(customTable);
}
}

View File

@ -0,0 +1,164 @@
package com.hoho.android.usbserial.examples;
import android.app.AlertDialog;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.ListFragment;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import java.util.ArrayList;
import java.util.Locale;
public class DevicesFragment extends ListFragment {
static class ListItem {
UsbDevice device;
int port;
UsbSerialDriver driver;
ListItem(UsbDevice device, int port, UsbSerialDriver driver) {
this.device = device;
this.port = port;
this.driver = driver;
}
}
private final ArrayList<ListItem> listItems = new ArrayList<>();
private ArrayAdapter<ListItem> listAdapter;
private int baudRate = 19200;
private boolean withIoManager = true;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
listAdapter = new ArrayAdapter<ListItem>(getActivity(), 0, listItems) {
@NonNull
@Override
public View getView(int position, View view, @NonNull ViewGroup parent) {
ListItem item = listItems.get(position);
if (view == null)
view = getActivity().getLayoutInflater().inflate(R.layout.device_list_item, parent, false);
TextView text1 = view.findViewById(R.id.text1);
TextView text2 = view.findViewById(R.id.text2);
if(item.driver == null)
text1.setText("<no driver>");
else if(item.driver.getPorts().size() == 1)
text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver",""));
else
text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver","")+", Port "+item.port);
text2.setText(String.format(Locale.US, "Vendor %04X, Product %04X", item.device.getVendorId(), item.device.getProductId()));
return view;
}
};
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(null);
View header = getActivity().getLayoutInflater().inflate(R.layout.device_list_header, null, false);
getListView().addHeaderView(header, null, false);
setEmptyText("<no USB devices found>");
((TextView) getListView().getEmptyView()).setTextSize(18);
setListAdapter(listAdapter);
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_devices, menu);
}
@Override
public void onResume() {
super.onResume();
refresh();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == R.id.refresh) {
refresh();
return true;
} else if (id ==R.id.baud_rate) {
final String[] values = getResources().getStringArray(R.array.baud_rates);
int pos = java.util.Arrays.asList(values).indexOf(String.valueOf(baudRate));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Baud rate");
builder.setSingleChoiceItems(values, pos, (dialog, which) -> {
baudRate = Integer.parseInt(values[which]);
dialog.dismiss();
});
builder.create().show();
return true;
} else if (id ==R.id.read_mode) {
final String[] values = getResources().getStringArray(R.array.read_modes);
int pos = withIoManager ? 0 : 1; // read_modes[0]=event/io-manager, read_modes[1]=direct
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Read mode");
builder.setSingleChoiceItems(values, pos, (dialog, which) -> {
withIoManager = (which == 0);
dialog.dismiss();
});
builder.create().show();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
void refresh() {
UsbManager usbManager = (UsbManager) getActivity().getSystemService(Context.USB_SERVICE);
UsbSerialProber usbDefaultProber = UsbSerialProber.getDefaultProber();
UsbSerialProber usbCustomProber = CustomProber.getCustomProber();
listItems.clear();
for(UsbDevice device : usbManager.getDeviceList().values()) {
UsbSerialDriver driver = usbDefaultProber.probeDevice(device);
if(driver == null) {
driver = usbCustomProber.probeDevice(device);
}
if(driver != null) {
for(int port = 0; port < driver.getPorts().size(); port++)
listItems.add(new ListItem(device, port, driver));
} else {
listItems.add(new ListItem(device, 0, null));
}
}
listAdapter.notifyDataSetChanged();
}
@Override
public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) {
ListItem item = listItems.get(position-1);
if(item.driver == null) {
Toast.makeText(getActivity(), "no driver", Toast.LENGTH_SHORT).show();
} else {
Bundle args = new Bundle();
args.putInt("device", item.device.getDeviceId());
args.putInt("port", item.port);
args.putInt("baud", baudRate);
args.putBoolean("withIoManager", withIoManager);
Fragment fragment = new TerminalFragment();
fragment.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.fragment, fragment, "terminal").addToBackStack(null).commit();
}
}
}

View File

@ -0,0 +1,45 @@
package com.hoho.android.usbserial.examples;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.FragmentManager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportFragmentManager().addOnBackStackChangedListener(this);
if (savedInstanceState == null)
getSupportFragmentManager().beginTransaction().add(R.id.fragment, new DevicesFragment(), "devices").commit();
else
onBackStackChanged();
}
@Override
public void onBackStackChanged() {
getSupportActionBar().setDisplayHomeAsUpEnabled(getSupportFragmentManager().getBackStackEntryCount()>0);
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
@Override
protected void onNewIntent(Intent intent) {
if("android.hardware.usb.action.USB_DEVICE_ATTACHED".equals(intent.getAction())) {
TerminalFragment terminal = (TerminalFragment)getSupportFragmentManager().findFragmentByTag("terminal");
if (terminal != null)
terminal.status("USB device detected");
}
super.onNewIntent(intent);
}
}

View File

@ -0,0 +1,409 @@
package com.hoho.android.usbserial.examples;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.method.ScrollingMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.HexDump;
import com.hoho.android.usbserial.util.SerialInputOutputManager;
import java.io.IOException;
import java.util.Arrays;
import java.util.EnumSet;
public class TerminalFragment extends Fragment implements SerialInputOutputManager.Listener {
private enum UsbPermission { Unknown, Requested, Granted, Denied }
private static final String INTENT_ACTION_GRANT_USB = BuildConfig.APPLICATION_ID + ".GRANT_USB";
private static final int WRITE_WAIT_MILLIS = 2000;
private static final int READ_WAIT_MILLIS = 2000;
private int deviceId, portNum, baudRate;
private boolean withIoManager;
private final BroadcastReceiver broadcastReceiver;
private final Handler mainLooper;
private TextView receiveText;
private ControlLines controlLines;
private SerialInputOutputManager usbIoManager;
private UsbSerialPort usbSerialPort;
private UsbPermission usbPermission = UsbPermission.Unknown;
private boolean connected = false;
public TerminalFragment() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(INTENT_ACTION_GRANT_USB.equals(intent.getAction())) {
usbPermission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
? UsbPermission.Granted : UsbPermission.Denied;
connect();
}
}
};
mainLooper = new Handler(Looper.getMainLooper());
}
/*
* Lifecycle
*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
setRetainInstance(true);
deviceId = getArguments().getInt("device");
portNum = getArguments().getInt("port");
baudRate = getArguments().getInt("baud");
withIoManager = getArguments().getBoolean("withIoManager");
}
@Override
public void onStart() {
super.onStart();
ContextCompat.registerReceiver(getActivity(), broadcastReceiver, new IntentFilter(INTENT_ACTION_GRANT_USB), ContextCompat.RECEIVER_NOT_EXPORTED);
}
@Override
public void onStop() {
getActivity().unregisterReceiver(broadcastReceiver);
super.onStop();
}
@Override
public void onResume() {
super.onResume();
if(!connected && (usbPermission == UsbPermission.Unknown || usbPermission == UsbPermission.Granted))
mainLooper.post(this::connect);
}
@Override
public void onPause() {
if(connected) {
status("disconnected");
disconnect();
}
super.onPause();
}
/*
* UI
*/
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_terminal, container, false);
receiveText = view.findViewById(R.id.receive_text); // TextView performance decreases with number of spans
receiveText.setTextColor(getResources().getColor(R.color.colorRecieveText)); // set as default color to reduce number of spans
receiveText.setMovementMethod(ScrollingMovementMethod.getInstance());
TextView sendText = view.findViewById(R.id.send_text);
View sendBtn = view.findViewById(R.id.send_btn);
sendBtn.setOnClickListener(v -> send(sendText.getText().toString()));
View receiveBtn = view.findViewById(R.id.receive_btn);
controlLines = new ControlLines(view);
if(withIoManager) {
receiveBtn.setVisibility(View.GONE);
} else {
receiveBtn.setOnClickListener(v -> read());
}
return view;
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_terminal, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.clear) {
receiveText.setText("");
return true;
} else if( id == R.id.send_break) {
if(!connected) {
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
} else {
try {
usbSerialPort.setBreak(true);
Thread.sleep(100); // should show progress bar instead of blocking UI thread
usbSerialPort.setBreak(false);
SpannableStringBuilder spn = new SpannableStringBuilder();
spn.append("send <break>\n");
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
receiveText.append(spn);
} catch(UnsupportedOperationException ignored) {
Toast.makeText(getActivity(), "BREAK not supported", Toast.LENGTH_SHORT).show();
} catch(Exception e) {
Toast.makeText(getActivity(), "BREAK failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
/*
* Serial
*/
@Override
public void onNewData(byte[] data) {
mainLooper.post(() -> {
receive(data);
});
}
@Override
public void onRunError(Exception e) {
mainLooper.post(() -> {
status("connection lost: " + e.getMessage());
disconnect();
});
}
/*
* Serial + UI
*/
private void connect() {
UsbDevice device = null;
UsbManager usbManager = (UsbManager) getActivity().getSystemService(Context.USB_SERVICE);
for(UsbDevice v : usbManager.getDeviceList().values())
if(v.getDeviceId() == deviceId)
device = v;
if(device == null) {
status("connection failed: device not found");
return;
}
UsbSerialDriver driver = UsbSerialProber.getDefaultProber().probeDevice(device);
if(driver == null) {
driver = CustomProber.getCustomProber().probeDevice(device);
}
if(driver == null) {
status("connection failed: no driver for device");
return;
}
if(portNum >= driver.getPorts().size()) {
status("connection failed: not enough ports at device");
return;
}
usbSerialPort = driver.getPorts().get(portNum);
UsbDeviceConnection usbConnection = usbManager.openDevice(driver.getDevice());
if(usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
usbPermission = UsbPermission.Requested;
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
Intent intent = new Intent(INTENT_ACTION_GRANT_USB);
intent.setPackage(getActivity().getPackageName());
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(getActivity(), 0, intent, flags);
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
return;
}
if(usbConnection == null) {
if (!usbManager.hasPermission(driver.getDevice()))
status("connection failed: permission denied");
else
status("connection failed: open failed");
return;
}
try {
usbSerialPort.open(usbConnection);
try{
usbSerialPort.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
}catch (UnsupportedOperationException e){
status("unsupport setparameters");
}
if(withIoManager) {
usbIoManager = new SerialInputOutputManager(usbSerialPort, this);
usbIoManager.start();
}
status("connected");
connected = true;
controlLines.start();
} catch (Exception e) {
status("connection failed: " + e.getMessage());
disconnect();
}
}
private void disconnect() {
connected = false;
controlLines.stop();
if(usbIoManager != null) {
usbIoManager.setListener(null);
usbIoManager.stop();
}
usbIoManager = null;
try {
usbSerialPort.close();
} catch (IOException ignored) {}
usbSerialPort = null;
}
private void send(String str) {
if(!connected) {
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
return;
}
try {
byte[] data = (str + '\n').getBytes();
SpannableStringBuilder spn = new SpannableStringBuilder();
spn.append("send " + data.length + " bytes\n");
spn.append(HexDump.dumpHexString(data)).append("\n");
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
receiveText.append(spn);
usbSerialPort.write(data, WRITE_WAIT_MILLIS);
} catch (Exception e) {
onRunError(e);
}
}
private void read() {
if(!connected) {
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
return;
}
try {
byte[] buffer = new byte[8192];
int len = usbSerialPort.read(buffer, READ_WAIT_MILLIS);
receive(Arrays.copyOf(buffer, len));
} catch (IOException e) {
// when using read with timeout, USB bulkTransfer returns -1 on timeout _and_ errors
// like connection loss, so there is typically no exception thrown here on error
status("connection lost: " + e.getMessage());
disconnect();
}
}
private void receive(byte[] data) {
SpannableStringBuilder spn = new SpannableStringBuilder();
spn.append("receive " + data.length + " bytes\n");
if(data.length > 0)
spn.append(HexDump.dumpHexString(data)).append("\n");
receiveText.append(spn);
}
void status(String str) {
SpannableStringBuilder spn = new SpannableStringBuilder(str+'\n');
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorStatusText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
receiveText.append(spn);
}
class ControlLines {
private static final int refreshInterval = 200; // msec
private final Runnable runnable;
private final ToggleButton rtsBtn, ctsBtn, dtrBtn, dsrBtn, cdBtn, riBtn;
ControlLines(View view) {
runnable = this::run; // w/o explicit Runnable, a new lambda would be created on each postDelayed, which would not be found again by removeCallbacks
rtsBtn = view.findViewById(R.id.controlLineRts);
ctsBtn = view.findViewById(R.id.controlLineCts);
dtrBtn = view.findViewById(R.id.controlLineDtr);
dsrBtn = view.findViewById(R.id.controlLineDsr);
cdBtn = view.findViewById(R.id.controlLineCd);
riBtn = view.findViewById(R.id.controlLineRi);
rtsBtn.setOnClickListener(this::toggle);
dtrBtn.setOnClickListener(this::toggle);
}
private void toggle(View v) {
ToggleButton btn = (ToggleButton) v;
if (!connected) {
btn.setChecked(!btn.isChecked());
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
return;
}
String ctrl = "";
try {
if (btn.equals(rtsBtn)) { ctrl = "RTS"; usbSerialPort.setRTS(btn.isChecked()); }
if (btn.equals(dtrBtn)) { ctrl = "DTR"; usbSerialPort.setDTR(btn.isChecked()); }
} catch (IOException e) {
status("set" + ctrl + "() failed: " + e.getMessage());
}
}
private void run() {
if (!connected)
return;
try {
EnumSet<UsbSerialPort.ControlLine> controlLines = usbSerialPort.getControlLines();
rtsBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.RTS));
ctsBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.CTS));
dtrBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.DTR));
dsrBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.DSR));
cdBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.CD));
riBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.RI));
mainLooper.postDelayed(runnable, refreshInterval);
} catch (Exception e) {
status("getControlLines() failed: " + e.getMessage() + " -> stopped control line refresh");
}
}
void start() {
if (!connected)
return;
try {
EnumSet<UsbSerialPort.ControlLine> controlLines = usbSerialPort.getSupportedControlLines();
if (!controlLines.contains(UsbSerialPort.ControlLine.RTS)) rtsBtn.setVisibility(View.INVISIBLE);
if (!controlLines.contains(UsbSerialPort.ControlLine.CTS)) ctsBtn.setVisibility(View.INVISIBLE);
if (!controlLines.contains(UsbSerialPort.ControlLine.DTR)) dtrBtn.setVisibility(View.INVISIBLE);
if (!controlLines.contains(UsbSerialPort.ControlLine.DSR)) dsrBtn.setVisibility(View.INVISIBLE);
if (!controlLines.contains(UsbSerialPort.ControlLine.CD)) cdBtn.setVisibility(View.INVISIBLE);
if (!controlLines.contains(UsbSerialPort.ControlLine.RI)) riBtn.setVisibility(View.INVISIBLE);
run();
} catch (Exception e) {
Toast.makeText(getActivity(), "getSupportedControlLines() failed: " + e.getMessage(), Toast.LENGTH_SHORT).show();
rtsBtn.setVisibility(View.INVISIBLE);
ctsBtn.setVisibility(View.INVISIBLE);
dtrBtn.setVisibility(View.INVISIBLE);
dsrBtn.setVisibility(View.INVISIBLE);
cdBtn.setVisibility(View.INVISIBLE);
cdBtn.setVisibility(View.INVISIBLE);
riBtn.setVisibility(View.INVISIBLE);
}
}
void stop() {
mainLooper.removeCallbacks(runnable);
rtsBtn.setChecked(false);
ctsBtn.setChecked(false);
dtrBtn.setChecked(false);
dsrBtn.setChecked(false);
cdBtn.setChecked(false);
riBtn.setChecked(false);
}
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>
<RelativeLayout
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/listDivider"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:gravity="center"
android:text="@string/devices"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
</LinearLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text1"
android:layout_marginTop="12dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="@+id/text2"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>

View File

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ToggleButton
android:id="@+id/controlLineRts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48sp"
android:textOff="RTS"
android:textOn="RTS" />
<ToggleButton
android:id="@+id/controlLineCts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48sp"
android:clickable="false"
android:textColor="@android:color/secondary_text_dark"
android:textOff="CTS"
android:textOn="CTS" />
<View
android:layout_height="match_parent"
android:layout_width="6dp" />
<ToggleButton
android:id="@+id/controlLineDtr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48sp"
android:textOff="DTR"
android:textOn="DTR" />
<ToggleButton
android:id="@+id/controlLineDsr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:minWidth="48sp"
android:textColor="@android:color/secondary_text_dark"
android:textOff="DSR"
android:textOn="DSR" />
<View
android:layout_height="match_parent"
android:layout_width="6dp" />
<ToggleButton
android:id="@+id/controlLineCd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:minWidth="48sp"
android:textColor="@android:color/secondary_text_dark"
android:textOff="CD"
android:textOn="CD" />
<ToggleButton
android:id="@+id/controlLineRi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="48sp"
android:clickable="false"
android:textColor="@android:color/secondary_text_dark"
android:textOff="RI"
android:textOn="RI" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:background="?android:attr/listDivider"
android:layout_height="2dp" />
<TextView
android:id="@+id/receive_text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:freezesText="true"
android:gravity="bottom"
android:scrollbars="vertical"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:typeface="monospace" />
<Button
android:id="@+id/receive_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Read" />
<View
android:layout_width="match_parent"
android:background="?android:attr/listDivider"
android:layout_height="2dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/send_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:inputType="text|textNoSuggestions"
android:singleLine="true" />
<ImageButton
android:id="@+id/send_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_send_white_24dp" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/refresh"
android:title="Refresh devices" />
<item
android:id="@+id/baud_rate"
android:title="Baud rate" />
<item
android:id="@+id/read_mode"
android:title="Read mode" />
</menu>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/clear"
android:icon="@drawable/ic_delete_white_24dp"
android:title="Clear"
app:showAsAction="always" />
<item
android:id="@+id/send_break"
android:title="Send BREAK"
app:showAsAction="never" />
</menu>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="baud_rates">
<item>2400</item>
<item>9600</item>
<item>19200</item>
<item>57600</item>
<item>115200</item>
</string-array>
<string-array name="read_modes">
<item>event: SerialInputOutputManager.onNewData()</item>
<item>direct: UsbSerialPort.read()</item>
</string-array>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#949C29</color>
<color name="colorPrimaryDark">#61671B</color>
<color name="colorAccent">#D8E33B</color>
<color name="colorRecieveText">#00FF00</color>
<color name="colorSendText">#82CAFF</color>
<color name="colorStatusText">#FFDB58</color>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_title">USB Serial For Android Example</string>
<string name="app_name">USB Serial Example</string>
<string name="devices">USB Devices</string>
</resources>

View File

@ -0,0 +1,7 @@
<resources>
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 0x0403 / 0x60??: FTDI -->
<usb-device vendor-id="1027" product-id="24577" /> <!-- 0x6001: FT232R -->
<usb-device vendor-id="1027" product-id="24592" /> <!-- 0x6010: FT2232H -->
<usb-device vendor-id="1027" product-id="24593" /> <!-- 0x6011: FT4232H -->
<usb-device vendor-id="1027" product-id="24596" /> <!-- 0x6014: FT232H -->
<usb-device vendor-id="1027" product-id="24597" /> <!-- 0x6015: FT230X, FT231X, FT234XD -->
<!-- 0x10C4 / 0xEA??: Silabs CP210x -->
<usb-device vendor-id="4292" product-id="60000" /> <!-- 0xea60: CP2102 and other CP210x single port devices -->
<usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 -->
<usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 -->
<!-- 0x067B / 0x23?3: Prolific PL2303x -->
<usb-device vendor-id="1659" product-id="8963" /> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
<usb-device vendor-id="1659" product-id="9123" /> <!-- 0x23a3: PL2303GC -->
<usb-device vendor-id="1659" product-id="9139" /> <!-- 0x23b3: PL2303GB -->
<usb-device vendor-id="1659" product-id="9155" /> <!-- 0x23c3: PL2303GT -->
<usb-device vendor-id="1659" product-id="9171" /> <!-- 0x23d3: PL2303GL -->
<usb-device vendor-id="1659" product-id="9187" /> <!-- 0x23e3: PL2303GE -->
<usb-device vendor-id="1659" product-id="9203" /> <!-- 0x23f3: PL2303GS -->
<!-- 0x1a86 / 0x?523: Qinheng CH34x -->
<usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A -->
<usb-device vendor-id="6790" product-id="29987" /> <!-- 0x7523: CH340 -->
<!-- CDC driver -->
<usb-device vendor-id="9025" /> <!-- 0x2341 / ......: Arduino -->
<usb-device vendor-id="5824" product-id="1155" /> <!-- 0x16C0 / 0x0483: Teensyduino -->
<usb-device vendor-id="1003" product-id="8260" /> <!-- 0x03EB / 0x2044: Atmel Lufa -->
<usb-device vendor-id="7855" product-id="4" /> <!-- 0x1eaf / 0x0004: Leaflabs Maple -->
<usb-device vendor-id="3368" product-id="516" /> <!-- 0x0d28 / 0x0204: ARM mbed -->
<usb-device vendor-id="1155" product-id="22336" /><!-- 0x0483 / 0x5740: ST CDC -->
<usb-device vendor-id="11914" product-id="5" /> <!-- 0x2E8A / 0x0005: Raspberry Pi Pico Micropython -->
<usb-device vendor-id="11914" product-id="10" /> <!-- 0x2E8A / 0x000A: Raspberry Pi Pico SDK -->
<usb-device vendor-id="6790" product-id="21972" /><!-- 0x1A86 / 0x55D4: Qinheng CH9102F -->
</resources>

View File

@ -0,0 +1,60 @@
plugins {
id 'com.android.library'
id 'maven-publish'
}
android {
compileSdkVersion 35
defaultConfig {
minSdkVersion 17
targetSdkVersion 35
consumerProguardFiles 'proguard-rules.pro'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ...
'rfc2217_server_host': '192.168.0.78',
'rfc2217_server_nonstandard_baudrates': 'true', // true false false
]
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
namespace 'com.hoho.android.usbserial'
publishing {
// if coverage is enabled, change 'release' to 'anyDeviceRelease' or comment out publishing rule
singleVariant('release') {
withSourcesJar()
}
}
}
dependencies {
implementation "androidx.annotation:annotation:1.9.1"
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:5.15.2'
androidTestImplementation 'androidx.appcompat:appcompat:1.6.1' // later versions have minsdk 21
androidTestImplementation 'androidx.test:core:1.5.0' // later versions have minsdk 19
androidTestImplementation 'androidx.test:runner:1.5.2' // later versions have minsdk 19
androidTestImplementation 'commons-net:commons-net:3.9.0' // later versions fail on old Android devices with missing java.time.Duration class
androidTestImplementation 'org.apache.commons:commons-lang3:3.14.0'
}
// gradle task: publishToMavenLocal
project.afterEvaluate {
publishing {
publications {
release(MavenPublication) {
from components.release
// values used for local maven repo, jitpack uses github release:
groupId 'com.github.mik3y'
artifactId 'usb-serial-for-android'
version '3.8.0beta'
}
}
}
}
//apply from: 'coverage.gradle'

View File

@ -0,0 +1,78 @@
// see https://github.com/mik3y/usb-serial-for-android/wiki/Device-Tests-&-Coverage-Report for instructions
apply plugin: 'jacoco'
android {
flavorDimensions += 'device'
productFlavors {
anyDevice {
// Used as fallback in usbSerialExample/build.gradle -> missingDimensionStrategy, but not for coverage report
dimension 'device'
}
mcp2221 {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'CdcAcm']
}
ch340 {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Ch34x']
}
cp2102 { // and cp2105 first port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Cp21xx', 'test_device_port': '0']
}
cp2105 { // second port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Cp21xx', 'test_device_port': '1']
}
ft232 { // and ft2232 first port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Ftdi', 'test_device_port': '0']
}
ft2232 { // second port
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Ftdi', 'test_device_port': '1']
}
pl2303 {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Prolific']
}
pl2303t {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Prolific']
}
pl2303g {
dimension 'device'
testInstrumentationRunnerArguments = ['test_device_driver': 'Prolific']
}
}
buildTypes {
debug {
enableUnitTestCoverage true
enableAndroidTestCoverage true
}
}
}
// create report even if tests fail
project.gradle.taskGraph.whenReady {
-> project.tasks.findAll { it.name =~ /connected.+AndroidTest/ }.each {
it.ignoreFailures = true
}
}
task jacocoTestReport(type: JacocoReport, dependsOn: ['compileAnyDeviceDebugSources'
/*, 'testAnyDeviceDebugUnitTest' */
/*, 'create<device>DebugCoverageReport' */]) {
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
def debugTree = fileTree(dir: "$project.buildDir/intermediates/javac/anyDeviceDebug", excludes: fileFilter)
def mainSrc = "$project.projectDir/src/main/java"
reports.xml.required = true
sourceDirectories.from files([mainSrc])
classDirectories.from files([debugTree])
executionData.from fileTree(dir: project.buildDir, includes: [
'outputs/unit_test_code_coverage/anyDeviceDebugUnitTest/testAnyDeviceDebugUnitTest.exec',
'outputs/code_coverage/*DebugAndroidTest/connected/*/coverage.ec'
])
}

View File

@ -0,0 +1 @@
-keep class com.hoho.android.usbserial.driver.* { *; }

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hoho.android.usbserial"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="12" />
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,216 @@
/*
* test multiple devices or multiple ports on same device
*
* TxD and RxD have to be cross connected
*/
package com.hoho.android.usbserial;
import android.content.Context;
import android.hardware.usb.UsbManager;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import android.util.Log;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import com.hoho.android.usbserial.driver.UsbSerialProber;
import com.hoho.android.usbserial.util.TestBuffer;
import com.hoho.android.usbserial.util.UsbWrapper;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
@RunWith(AndroidJUnit4.class)
public class CrossoverTest {
private final static String TAG = CrossoverTest.class.getSimpleName();
private Context context;
private UsbManager usbManager;
private UsbWrapper usb1, usb2;
@Rule
public TestRule watcher = new TestWatcher() {
protected void starting(Description description) {
Log.i(TAG, "===== starting test: " + description.getMethodName()+ " =====");
}
};
@Before
public void setUp() throws Exception {
assumeTrue("ignore test for device specific coverage report",
InstrumentationRegistry.getArguments().getString("test_device_driver") == null);
context = ApplicationProvider.getApplicationContext();
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);
assertNotEquals("no USB device found", 0, availableDrivers.size());
if (availableDrivers.size() == 0) {
fail("no USB device found");
} else if (availableDrivers.size() == 1) {
assertEquals("expected device with 2 ports.", 2, availableDrivers.get(0).getPorts().size());
usb1 = new UsbWrapper(context, availableDrivers.get(0), 0);
usb2 = new UsbWrapper(context, availableDrivers.get(0), 1);
} else {
assertEquals("expected 2 devices with 1 port.", 1, availableDrivers.get(0).getPorts().size());
assertEquals("expected 2 devices with 1 port.", 1, availableDrivers.get(1).getPorts().size());
usb1 = new UsbWrapper(context, availableDrivers.get(0), 0);
usb2 = new UsbWrapper(context, availableDrivers.get(1), 0);
}
usb1.setUp();
usb2.setUp();
}
@Test
public void reopen() throws Exception {
byte[] buf;
usb1.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD));
usb2.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD));
usb1.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
usb2.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
usb1.write("x".getBytes());
buf = usb2.read(1);
assertThat(buf, equalTo("x".getBytes()));
usb2.write("y".getBytes());
buf = usb1.read(1);
assertThat(buf, equalTo("y".getBytes()));
usb2.close(); // does not affect usb1 with individual UsbDeviceConnection on same device
usb2.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD));
usb2.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
usb1.write("x".getBytes());
buf = usb2.read(1);
assertThat(buf, equalTo("x".getBytes()));
usb2.write("y".getBytes());
buf = usb1.read(1);
assertThat(buf, equalTo("y".getBytes()));
usb1.close();
usb2.close();
}
@Test
public void ioManager() throws Exception {
byte[] buf;
// each SerialInputOutputManager thread runs in it's own SingleThreadExecutor
usb1.open();
usb2.open();
usb1.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
usb2.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
usb1.write("x".getBytes());
buf = usb2.read(1);
assertThat(buf, equalTo("x".getBytes()));
usb2.write("y".getBytes());
buf = usb1.read(1);
assertThat(buf, equalTo("y".getBytes()));
usb1.close();
usb2.close();
}
@Test
public void baudRate() throws Exception {
byte[] buf;
usb1.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD));
usb2.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD));
usb1.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
usb2.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE);
// a - start bit (0)
// o - stop bit (1)
// 0/1 - data bit
// out 19k2: a00011001o
// in 9k6: a 0 1 0 1 1 1 1 1 o
usb1.write(new byte[]{(byte)0x98});
buf = usb2.read(1);
assertThat(buf, equalTo(new byte[]{(byte)0xfa}));
// out 9k6: a 1 0 1 1 1 1 1 1 o
// in 19k2: a01100111o
usb2.write(new byte[]{(byte)0xfd});
buf = usb1.read(1);
assertThat(buf, equalTo(new byte[]{(byte)0xe6}));
usb1.close();
usb2.close();
}
@Test
public void concurrent() throws Exception {
// 115200 baud ~= 11kB/sec => ~1.5 second test duration with 16kB tbuf
// concurrent (+ blocking) write calls as tbuf larger than any buffer size returned by UsbWrapper.getWriteSizes()
// concurrent read calls in IoManager threads
TestBuffer tbuf1 = new TestBuffer(16*1024);
TestBuffer tbuf2 = new TestBuffer(16*1024);
class WriteRunnable implements Runnable {
public WriteRunnable(int port) { this.port = port; }
private final int port;
Exception exc;
@Override
public void run() {
byte[] buf = new byte[1024];
try {
for(int i=0; i<tbuf1.buf.length / 1024; i++) {
System.arraycopy(tbuf1.buf, i*1024, buf, 0, 1024);
if (port == 1)
usb1.write(buf);
else
usb2.write(buf);
}
} catch (IOException exc) {
this.exc = exc;
}
}
}
usb1.open();
usb2.open();
usb1.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
usb2.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
WriteRunnable wr1 = new WriteRunnable(1), wr2 = new WriteRunnable(2);
Thread wt1 = new Thread(wr1), wt2 = new Thread(wr2);
boolean done1 = false, done2 = false;
wt1.start();
Thread.sleep(50);
wt2.start();
while(!done1 && !done2) {
if(!done1)
done1 = tbuf1.testRead(usb1.read(-1));
if(!done2)
done2 = tbuf2.testRead(usb2.read(-1));
}
wt1.join(); wt2.join();
assertNull(wr1.exc);
assertNull(wr2.exc);
}
}

View File

@ -0,0 +1,8 @@
package com.hoho.android.usbserial.driver;
public class CommonUsbSerialPortWrapper {
public static byte[] getWriteBuffer(UsbSerialPort serialPort) {
CommonUsbSerialPort commonSerialPort = (CommonUsbSerialPort) serialPort;
return commonSerialPort.mWriteBuffer;
}
}

View File

@ -0,0 +1,13 @@
package com.hoho.android.usbserial.driver;
public class ProlificSerialPortWrapper {
public static boolean isDeviceTypeT(UsbSerialPort serialPort) {
ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort;
return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_T;
}
public static boolean isDeviceTypeHxn(UsbSerialPort serialPort) {
ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort;
return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_HXN;
}
}

View File

@ -0,0 +1,152 @@
package com.hoho.android.usbserial.util;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import org.apache.commons.net.telnet.InvalidTelnetOptionException;
import org.apache.commons.net.telnet.TelnetClient;
import org.apache.commons.net.telnet.TelnetCommand;
import org.apache.commons.net.telnet.TelnetOptionHandler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
public class TelnetWrapper {
private final static String TAG = TelnetWrapper.class.getSimpleName();
private final static int TELNET_READ_WAIT = 500;
private final static int TELNET_COMMAND_WAIT = 2000;
private final static byte RFC2217_COM_PORT_OPTION = 0x2c;
private final static byte RFC2217_SET_BAUDRATE = 1;
private final static byte RFC2217_SET_DATASIZE = 2;
private final static byte RFC2217_SET_PARITY = 3;
private final static byte RFC2217_SET_STOPSIZE = 4;
private final static byte RFC2217_PURGE_DATA = 12;
private final String host;
private final int port;
private TelnetClient telnetClient;
private InputStream readStream;
private OutputStream writeStream;
private ArrayList<int[]> commandResponse = new ArrayList<>();
public int writeDelay = 0;
public TelnetWrapper(String host, int port) {
this.host = host;
this.port = port;
telnetClient = null;
}
private void setUpFixtureInt() throws Exception {
if(telnetClient != null)
return;
telnetClient = new TelnetClient();
telnetClient.addOptionHandler(new TelnetOptionHandler(RFC2217_COM_PORT_OPTION, false, false, false, false) {
@Override
public int[] answerSubnegotiation(int[] suboptionData, int suboptionLength) {
int[] data = new int[suboptionLength];
System.arraycopy(suboptionData, 0, data, 0, suboptionLength);
commandResponse.add(data);
return super.answerSubnegotiation(suboptionData, suboptionLength);
}
});
telnetClient.setConnectTimeout(2000);
telnetClient.connect(host, port);
telnetClient.setTcpNoDelay(true);
writeStream = telnetClient.getOutputStream();
readStream = telnetClient.getInputStream();
}
private int[] doCommand(String name, byte[] command) throws IOException, InterruptedException {
commandResponse.clear();
telnetClient.sendCommand((byte) TelnetCommand.SB);
writeStream.write(command);
telnetClient.sendCommand((byte)TelnetCommand.SE);
for(int i=0; i<TELNET_COMMAND_WAIT; i++) {
if(commandResponse.size() > 0) break;
Thread.sleep(1);
}
assertEquals("RFC2217 " + name+ " w/o response.", 1, commandResponse.size());
//Log.d(TAG, name + " -> " + Arrays.toString(commandResponse.get(0)));
return commandResponse.get(0);
}
public void setUp() throws Exception {
setUpFixtureInt();
telnetClient.sendAYT(1000); // not correctly handled by rfc2217_server.py, but WARNING output "ignoring Telnet command: '\xf6'" is a nice separator between tests
doCommand("purge-data", new byte[] {RFC2217_COM_PORT_OPTION, RFC2217_PURGE_DATA, 3});
writeDelay = 0;
}
public void tearDown() {
try {
read(0);
} catch (Exception ignored) {
}
}
public void tearDownFixture() throws Exception {
try {
telnetClient.disconnect();
} catch (Exception ignored) {}
readStream = null;
writeStream = null;
telnetClient = null;
}
// wait full time
public byte[] read() throws Exception {
return read(-1, -1);
}
public byte[] read(int expectedLength) throws Exception {
return read(expectedLength, -1);
}
public byte[] read(int expectedLength, int readWait) throws Exception {
if(readWait == -1)
readWait = TELNET_READ_WAIT;
long end = System.currentTimeMillis() + readWait;
ByteBuffer buf = ByteBuffer.allocate(65536);
while(System.currentTimeMillis() < end) {
if(readStream.available() > 0) {
buf.put((byte) readStream.read());
} else {
if (expectedLength >= 0 && buf.position() >= expectedLength)
break;
Thread.sleep(1);
}
}
byte[] data = new byte[buf.position()];
buf.flip();
buf.get(data);
return data;
}
public void write(byte[] data) throws Exception{
if(writeDelay != 0) {
for(byte b : data) {
writeStream.write(b);
writeStream.flush();
Thread.sleep(writeDelay);
}
} else {
writeStream.write(data);
writeStream.flush();
}
}
public void setParameters(int baudRate, int dataBits, int stopBits, @UsbSerialPort.Parity int parity) throws IOException, InterruptedException, InvalidTelnetOptionException {
doCommand("set-baudrate", new byte[] {RFC2217_COM_PORT_OPTION, RFC2217_SET_BAUDRATE, (byte)(baudRate>>24), (byte)(baudRate>>16), (byte)(baudRate>>8), (byte)baudRate});
doCommand("set-datasize", new byte[] {RFC2217_COM_PORT_OPTION, RFC2217_SET_DATASIZE, (byte)dataBits});
doCommand("set-stopsize", new byte[] {RFC2217_COM_PORT_OPTION, RFC2217_SET_STOPSIZE, (byte)stopBits});
doCommand("set-parity", new byte[] {RFC2217_COM_PORT_OPTION, RFC2217_SET_PARITY, (byte)(parity+1)});
}
}

View File

@ -0,0 +1,32 @@
package com.hoho.android.usbserial.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
public class TestBuffer {
public final byte[] buf;
public int len;
public TestBuffer(int length) {
len = 0;
buf = new byte[length];
int i = 0;
int j = 0;
for (j = 0; j < length / 16; j++)
for (int k = 0; k < 16; k++)
buf[i++] = (byte) j;
while (i < length)
buf[i++] = (byte) j;
}
public boolean testRead(byte[] data) {
assertNotEquals(0, data.length);
assertTrue("got " + (len + data.length) + " bytes", (len + data.length) <= buf.length);
for (int j = 0; j < data.length; j++)
assertEquals("at pos " + (len + j), (byte) ((len + j) / 16), data[j]);
len += data.length;
//Log.d(TAG, "read " + len);
return len == buf.length;
}
}

View File

@ -0,0 +1,390 @@
package com.hoho.android.usbserial.util;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import com.hoho.android.usbserial.driver.CdcAcmSerialDriver;
import com.hoho.android.usbserial.driver.Ch34xSerialDriver;
import com.hoho.android.usbserial.driver.CommonUsbSerialPort;
import com.hoho.android.usbserial.driver.Cp21xxSerialDriver;
import com.hoho.android.usbserial.driver.FtdiSerialDriver;
import com.hoho.android.usbserial.driver.ProlificSerialDriver;
import com.hoho.android.usbserial.driver.ProlificSerialPortWrapper;
import com.hoho.android.usbserial.driver.UsbId;
import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialPort;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.concurrent.Callable;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import androidx.core.content.ContextCompat;
public class UsbWrapper implements SerialInputOutputManager.Listener {
public final static int USB_READ_WAIT = 500;
public final static int USB_WRITE_WAIT = 500;
private static final String TAG = UsbWrapper.class.getSimpleName();
public enum OpenCloseFlags { NO_IOMANAGER_THREAD, NO_IOMANAGER_START, NO_CONTROL_LINE_INIT, NO_DEVICE_CONNECTION };
// constructor
final Context context;
public final UsbSerialDriver serialDriver;
public final int devicePort;
public final UsbSerialPort serialPort;
// open
public UsbDeviceConnection deviceConnection;
public SerialInputOutputManager ioManager;
// read
final Deque<byte[]> readBuffer = new LinkedList<>();
Exception readError;
public boolean readBlock = false;
long readTime = 0;
// device properties
public boolean isCp21xxRestrictedPort; // second port of Cp2105 has limited dataBits, stopBits, parity
public boolean outputLinesSupported;
public boolean inputLinesSupported;
public boolean inputLinesConnected;
public boolean inputLinesOnlyRtsCts;
public int writePacketSize = -1;
public int writeBufferSize = -1;
public int readBufferSize = -1;
public UsbWrapper(Context context, UsbSerialDriver serialDriver, int devicePort) {
this.context = context;
this.serialDriver = serialDriver;
this.devicePort = devicePort;
serialPort = serialDriver.getPorts().get(devicePort);
CommonUsbSerialPort.DEBUG = true;
}
public void setUp() throws Exception {
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
if (!usbManager.hasPermission(serialDriver.getDevice())) {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
RingtoneManager.getRingtone(context, notification).play();
Log.d(TAG,"USB permission ...");
final Boolean[] granted = {null};
BroadcastReceiver usbReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
granted[0] = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
}
};
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
Intent intent = new Intent("com.android.example.USB_PERMISSION");
intent.setPackage(context.getPackageName());
PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, intent, flags);
IntentFilter filter = new IntentFilter("com.android.example.USB_PERMISSION");
ContextCompat.registerReceiver(context, usbReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
usbManager.requestPermission(serialDriver.getDevice(), permissionIntent);
for(int i=0; i<5000; i++) {
if(granted[0] != null) break;
Thread.sleep(1);
}
Log.d(TAG,"USB permission "+granted[0]);
assertTrue("USB permission dialog not confirmed", granted[0] != null && granted[0]);
}
// extract some device properties:
isCp21xxRestrictedPort = serialDriver instanceof Cp21xxSerialDriver && serialDriver.getPorts().size()==2 && serialPort.getPortNumber() == 1;
// output lines are supported by all common drivers
// input lines are supported by all common drivers except CDC
if (serialDriver instanceof FtdiSerialDriver) {
outputLinesSupported = true;
inputLinesSupported = true;
if(serialDriver.getDevice().getProductId() == UsbId.FTDI_FT2232H)
inputLinesConnected = true; // I only have 74LS138 connected at FT2232, not at FT232
if(serialDriver.getDevice().getProductId() == UsbId.FTDI_FT231X) {
inputLinesConnected = true;
inputLinesOnlyRtsCts = true; // I only test with FT230X that has only these 2 control lines. DTR is silently ignored
}
} else if (serialDriver instanceof Cp21xxSerialDriver) {
outputLinesSupported = true;
inputLinesSupported = true;
if(serialDriver.getPorts().size() == 1)
inputLinesConnected = true; // I only have 74LS138 connected at CP2102, not at CP2105
} else if (serialDriver instanceof ProlificSerialDriver) {
outputLinesSupported = true;
inputLinesSupported = true;
inputLinesConnected = true;
} else if (serialDriver instanceof Ch34xSerialDriver) {
outputLinesSupported = true;
inputLinesSupported = true;
if(serialDriver.getDevice().getProductId() == UsbId.QINHENG_CH340)
inputLinesConnected = true; // I only have 74LS138 connected at CH340, not connected at CH341A
} else if (serialDriver instanceof CdcAcmSerialDriver) {
outputLinesSupported = true;
}
if (serialDriver instanceof Cp21xxSerialDriver) {
if (serialDriver.getPorts().size() == 1) { writePacketSize = 64; writeBufferSize = 576; }
else if (serialPort.getPortNumber() == 0) { writePacketSize = 64; writeBufferSize = 320; }
else { writePacketSize = 32; writeBufferSize = 128; }; //, 160}; // write buffer size detection is unreliable
} else if (serialDriver instanceof Ch34xSerialDriver) {
writePacketSize = 32; writeBufferSize = 64;
} else if (serialDriver instanceof ProlificSerialDriver) {
writePacketSize = 64; writeBufferSize = 256;
} else if (serialDriver instanceof FtdiSerialDriver) {
switch (serialDriver.getPorts().size()) {
case 1: writePacketSize = 64; writeBufferSize = 128; break;
case 2: writePacketSize = 512; writeBufferSize = 4096; break;
case 4: writePacketSize = 512; writeBufferSize = 2048; break;
}
if(serialDriver.getDevice().getProductId() == UsbId.FTDI_FT231X)
writeBufferSize = 512;
} else if (serialDriver instanceof CdcAcmSerialDriver) {
writePacketSize = 16; writeBufferSize = 32; // MCP2221 values, other devices might be different
}
readBufferSize = writeBufferSize;
if (serialDriver instanceof Cp21xxSerialDriver && serialDriver.getPorts().size() == 2) {
readBufferSize = 256;
} else if (serialDriver instanceof FtdiSerialDriver && serialDriver.getPorts().size() == 1 && serialDriver.getDevice().getProductId() != UsbId.FTDI_FT231X) {
readBufferSize = 256;
} // PL2303 HXN checked in open()
}
public void tearDown() {
try {
if (ioManager != null)
read(0);
else
serialPort.purgeHwBuffers(true, true);
} catch (Exception ignored) {
}
close();
//usb.serialDriver = null;
}
public void close() {
close(EnumSet.noneOf(OpenCloseFlags.class));
}
public void close(EnumSet<OpenCloseFlags> flags) {
if (ioManager != null) {
ioManager.setListener(null);
ioManager.stop();
}
if (serialPort != null) {
try {
if(!flags.contains(OpenCloseFlags.NO_CONTROL_LINE_INIT)) {
serialPort.setDTR(false);
serialPort.setRTS(false);
if (serialPort.getFlowControl() != UsbSerialPort.FlowControl.NONE)
serialPort.setFlowControl(UsbSerialPort.FlowControl.NONE);
}
} catch (Exception ignored) {
}
try {
serialPort.close();
} catch (Exception ignored) {
}
//usbSerialPort = null;
}
if(!flags.contains(OpenCloseFlags.NO_DEVICE_CONNECTION)) {
deviceConnection = null; // closed in usbSerialPort.close()
}
if(ioManager != null) {
for (int i = 0; i < 2000; i++) {
if (SerialInputOutputManager.State.STOPPED == ioManager.getState()) break;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
assertEquals(SerialInputOutputManager.State.STOPPED, ioManager.getState());
ioManager = null;
}
}
public void open() throws Exception {
open(EnumSet.noneOf(OpenCloseFlags.class));
}
public void open(EnumSet<OpenCloseFlags> flags) throws Exception {
if(!flags.contains(OpenCloseFlags.NO_DEVICE_CONNECTION)) {
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
deviceConnection = usbManager.openDevice(serialDriver.getDevice());
}
serialPort.open(deviceConnection);
if(!flags.contains(OpenCloseFlags.NO_CONTROL_LINE_INIT)) {
serialPort.setDTR(true);
serialPort.setRTS(true);
}
if(!flags.contains(OpenCloseFlags.NO_IOMANAGER_THREAD)) {
ioManager = new SerialInputOutputManager(serialPort, this);
if(!flags.contains(OpenCloseFlags.NO_IOMANAGER_START))
ioManager.start();
}
synchronized (readBuffer) {
readBuffer.clear();
}
readError = null;
if (serialDriver instanceof ProlificSerialDriver && ProlificSerialPortWrapper.isDeviceTypeHxn(serialPort)) {
readBufferSize = 768;
}
}
public void waitForIoManagerStarted() throws IOException {
for (int i = 0; i < 100; i++) {
if (SerialInputOutputManager.State.STOPPED != ioManager.getState()) return;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
throw new IOException("IoManager not started");
}
public boolean hasIoManagerThreads() {
int c = 0;
for (Thread thread : Thread.getAllStackTraces().keySet()) {
if (thread.getName().equals(SerialInputOutputManager.class.getSimpleName() + "_read"))
c += 1;
if (thread.getName().equals(SerialInputOutputManager.class.getSimpleName() + "_write"))
c += 1;
}
return c == 2;
}
// wait full time
public byte[] read() throws Exception {
return read(-1, -1, -1);
}
public byte[] read(int expectedLength) throws Exception {
return read(expectedLength, -1, -1);
}
public byte[] read(int expectedLength, int readBufferSize) throws Exception {
return read(expectedLength, readBufferSize, -1);
}
public byte[] read(int expectedLength, int readBufferSize, int readWait) throws Exception {
if(readWait == -1)
readWait = USB_READ_WAIT;
long end = System.currentTimeMillis() + readWait;
ByteBuffer buf = ByteBuffer.allocate(16*1024);
if(ioManager != null) {
while (System.currentTimeMillis() < end) {
if(readError != null)
throw new IOException(readError);
synchronized (readBuffer) {
while(readBuffer.peek() != null)
buf.put(readBuffer.remove());
}
if (expectedLength >= 0 && buf.position() >= expectedLength)
break;
Thread.sleep(1);
}
} else {
byte[] b1 = new byte[readBufferSize > 0 ? readBufferSize : 256];
while (System.currentTimeMillis() < end) {
int len = serialPort.read(b1, USB_READ_WAIT);
if (len > 0)
buf.put(b1, 0, len);
if (expectedLength >= 0 && buf.position() >= expectedLength)
break;
}
}
byte[] data = new byte[buf.position()];
buf.flip();
buf.get(data);
return data;
}
public void write(byte[] data) throws IOException {
serialPort.write(data, USB_WRITE_WAIT);
}
public void setParameters(int baudRate, int dataBits, int stopBits, @UsbSerialPort.Parity int parity) throws IOException, InterruptedException {
serialPort.setParameters(baudRate, dataBits, stopBits, parity);
if(serialDriver instanceof CdcAcmSerialDriver)
Thread.sleep(10); // arduino_leonardeo_bridge.ini needs some time
else
Thread.sleep(1);
}
/* return TRUE/FALSE/null instead of true/false/<throw UnsupportedOperationException> */
public Boolean getControlLine(Callable<?> callable) throws Exception {
try {
return (Boolean)callable.call();
} catch (UnsupportedOperationException t) {
return null;
}
}
// return [write packet size, write buffer size(s)]
public int[] getWriteSizes() {
if (serialDriver instanceof Cp21xxSerialDriver) {
if (serialDriver.getPorts().size() == 1) return new int[]{64, 576};
else if (serialPort.getPortNumber() == 0) return new int[]{64, 320};
else return new int[]{32, 128, 160}; // write buffer size detection is unreliable
} else if (serialDriver instanceof Ch34xSerialDriver) {
return new int[]{32, 64};
} else if (serialDriver instanceof ProlificSerialDriver) {
return new int[]{64, 256};
} else if (serialDriver instanceof FtdiSerialDriver) {
switch (serialDriver.getPorts().size()) {
case 1: return new int[]{64, 128};
case 2: return new int[]{512, 4096};
case 4: return new int[]{512, 2048};
default: return null;
}
} else if (serialDriver instanceof CdcAcmSerialDriver) {
return new int[]{64, 128};
} else {
return null;
}
}
@Override
public void onNewData(byte[] data) {
long now = System.currentTimeMillis();
if(readTime == 0)
readTime = now;
if(data.length > 64) {
Log.d(TAG, "usb " + devicePort + " read: time+=" + String.format("%-3d",now- readTime) + " len=" + String.format("%-4d",data.length) + " data=" + new String(data, 0, 32) + "..." + new String(data, data.length-32, 32));
} else {
Log.d(TAG, "usb " + devicePort + " read: time+=" + String.format("%-3d",now- readTime) + " len=" + String.format("%-4d",data.length) + " data=" + new String(data));
}
readTime = now;
while(readBlock)
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (readBuffer) {
readBuffer.add(data);
}
}
@Override
public void onRunError(Exception e) {
readError = e;
}
}

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -0,0 +1,359 @@
/* Copyright 2011-2013 Google Inc.
* Copyright 2013 mike wakerly <opensource@hoho.com>
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import com.hoho.android.usbserial.util.HexDump;
import com.hoho.android.usbserial.util.UsbUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* USB CDC/ACM serial driver implementation.
*
* @author mike wakerly (opensource@hoho.com)
* @see <a
* href="http://www.usb.org/developers/devclass_docs/usbcdc11.pdf">Universal
* Serial Bus Class Definitions for Communication Devices, v1.1</a>
*/
public class CdcAcmSerialDriver implements UsbSerialDriver {
public static final int USB_SUBCLASS_ACM = 2;
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
private final UsbDevice mDevice;
private final List<UsbSerialPort> mPorts;
public CdcAcmSerialDriver(UsbDevice device) {
mDevice = device;
mPorts = new ArrayList<>();
int ports = countPorts(device);
for (int port = 0; port < ports; port++) {
mPorts.add(new CdcAcmSerialPort(mDevice, port));
}
if (mPorts.size() == 0) {
mPorts.add(new CdcAcmSerialPort(mDevice, -1));
}
}
@SuppressWarnings({"unused"})
public static boolean probe(UsbDevice device) {
return countPorts(device) > 0;
}
private static int countPorts(UsbDevice device) {
int controlInterfaceCount = 0;
int dataInterfaceCount = 0;
for (int i = 0; i < device.getInterfaceCount(); i++) {
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_COMM &&
device.getInterface(i).getInterfaceSubclass() == USB_SUBCLASS_ACM)
controlInterfaceCount++;
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
dataInterfaceCount++;
}
return Math.min(controlInterfaceCount, dataInterfaceCount);
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
@Override
public List<UsbSerialPort> getPorts() {
return mPorts;
}
public class CdcAcmSerialPort extends CommonUsbSerialPort {
private UsbInterface mControlInterface;
private UsbInterface mDataInterface;
private UsbEndpoint mControlEndpoint;
private int mControlIndex;
private boolean mRts = false;
private boolean mDtr = false;
private static final int USB_RECIP_INTERFACE = 0x01;
private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
private static final int GET_LINE_CODING = 0x21;
private static final int SET_CONTROL_LINE_STATE = 0x22;
private static final int SEND_BREAK = 0x23;
public CdcAcmSerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
}
@Override
public UsbSerialDriver getDriver() {
return CdcAcmSerialDriver.this;
}
@Override
protected void openInt() throws IOException {
Log.d(TAG, "interfaces:");
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
Log.d(TAG, mDevice.getInterface(i).toString());
}
if (mPortNumber == -1) {
Log.d(TAG,"device might be castrated ACM device, trying single interface logic");
openSingleInterface();
} else {
Log.d(TAG,"trying default interface logic");
openInterface();
}
}
private void openSingleInterface() throws IOException {
// the following code is inspired by the cdc-acm driver in the linux kernel
mControlIndex = 0;
mControlInterface = mDevice.getInterface(0);
mDataInterface = mDevice.getInterface(0);
if (!mConnection.claimInterface(mControlInterface, true)) {
throw new IOException("Could not claim shared control/data interface");
}
for (int i = 0; i < mControlInterface.getEndpointCount(); ++i) {
UsbEndpoint ep = mControlInterface.getEndpoint(i);
if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)) {
mControlEndpoint = ep;
} else if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) {
mReadEndpoint = ep;
} else if ((ep.getDirection() == UsbConstants.USB_DIR_OUT) && (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) {
mWriteEndpoint = ep;
}
}
if (mControlEndpoint == null) {
throw new IOException("No control endpoint");
}
}
private void openInterface() throws IOException {
mControlInterface = null;
mDataInterface = null;
int j = getInterfaceIdFromDescriptors();
Log.d(TAG, "interface count=" + mDevice.getInterfaceCount() + ", IAD=" + j);
if (j >= 0) {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface usbInterface = mDevice.getInterface(i);
if (usbInterface.getId() == j || usbInterface.getId() == j+1) {
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM &&
usbInterface.getInterfaceSubclass() == USB_SUBCLASS_ACM) {
mControlIndex = usbInterface.getId();
mControlInterface = usbInterface;
}
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
mDataInterface = usbInterface;
}
}
}
}
if (mControlInterface == null || mDataInterface == null) {
Log.d(TAG, "no IAD fallback");
int controlInterfaceCount = 0;
int dataInterfaceCount = 0;
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface usbInterface = mDevice.getInterface(i);
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM &&
usbInterface.getInterfaceSubclass() == USB_SUBCLASS_ACM) {
if (controlInterfaceCount == mPortNumber) {
mControlIndex = usbInterface.getId();
mControlInterface = usbInterface;
}
controlInterfaceCount++;
}
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
if (dataInterfaceCount == mPortNumber) {
mDataInterface = usbInterface;
}
dataInterfaceCount++;
}
}
}
if(mControlInterface == null) {
throw new IOException("No control interface");
}
Log.d(TAG, "Control interface id " + mControlInterface.getId());
if (!mConnection.claimInterface(mControlInterface, true)) {
throw new IOException("Could not claim control interface");
}
mControlEndpoint = mControlInterface.getEndpoint(0);
if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) {
throw new IOException("Invalid control endpoint");
}
if(mDataInterface == null) {
throw new IOException("No data interface");
}
Log.d(TAG, "data interface id " + mDataInterface.getId());
if (!mConnection.claimInterface(mDataInterface, true)) {
throw new IOException("Could not claim data interface");
}
for (int i = 0; i < mDataInterface.getEndpointCount(); i++) {
UsbEndpoint ep = mDataInterface.getEndpoint(i);
if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
mReadEndpoint = ep;
if (ep.getDirection() == UsbConstants.USB_DIR_OUT && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
mWriteEndpoint = ep;
}
}
private int getInterfaceIdFromDescriptors() {
ArrayList<byte[]> descriptors = UsbUtils.getDescriptors(mConnection);
Log.d(TAG, "USB descriptor:");
for(byte[] descriptor : descriptors)
Log.d(TAG, HexDump.toHexString(descriptor));
if (descriptors.size() > 0 &&
descriptors.get(0).length == 18 &&
descriptors.get(0)[1] == 1 && // bDescriptorType
descriptors.get(0)[4] == (byte)(UsbConstants.USB_CLASS_MISC) && //bDeviceClass
descriptors.get(0)[5] == 2 && // bDeviceSubClass
descriptors.get(0)[6] == 1) { // bDeviceProtocol
// is IAD device, see https://www.usb.org/sites/default/files/iadclasscode_r10.pdf
int port = -1;
for (int d = 1; d < descriptors.size(); d++) {
if (descriptors.get(d).length == 8 &&
descriptors.get(d)[1] == 0x0b && // bDescriptorType == IAD
descriptors.get(d)[4] == UsbConstants.USB_CLASS_COMM && // bFunctionClass == CDC
descriptors.get(d)[5] == USB_SUBCLASS_ACM) { // bFunctionSubClass == ACM
port++;
if (port == mPortNumber &&
descriptors.get(d)[3] == 2) { // bInterfaceCount
return descriptors.get(d)[2]; // bFirstInterface
}
}
}
}
return -1;
}
private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException {
int len = mConnection.controlTransfer(
USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000);
if(len < 0) {
throw new IOException("controlTransfer failed");
}
return len;
}
@Override
protected void closeInt() {
try {
mConnection.releaseInterface(mControlInterface);
mConnection.releaseInterface(mDataInterface);
} catch(Exception ignored) {}
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
if(baudRate <= 0) {
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
}
if(dataBits < DATABITS_5 || dataBits > DATABITS_8) {
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
}
byte stopBitsByte;
switch (stopBits) {
case STOPBITS_1: stopBitsByte = 0; break;
case STOPBITS_1_5: stopBitsByte = 1; break;
case STOPBITS_2: stopBitsByte = 2; break;
default: throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
}
byte parityBitesByte;
switch (parity) {
case PARITY_NONE: parityBitesByte = 0; break;
case PARITY_ODD: parityBitesByte = 1; break;
case PARITY_EVEN: parityBitesByte = 2; break;
case PARITY_MARK: parityBitesByte = 3; break;
case PARITY_SPACE: parityBitesByte = 4; break;
default: throw new IllegalArgumentException("Invalid parity: " + parity);
}
byte[] msg = {
(byte) ( baudRate & 0xff),
(byte) ((baudRate >> 8 ) & 0xff),
(byte) ((baudRate >> 16) & 0xff),
(byte) ((baudRate >> 24) & 0xff),
stopBitsByte,
parityBitesByte,
(byte) dataBits};
sendAcmControlMessage(SET_LINE_CODING, 0, msg);
}
@Override
public boolean getDTR() throws IOException {
return mDtr;
}
@Override
public void setDTR(boolean value) throws IOException {
mDtr = value;
setDtrRts();
}
@Override
public boolean getRTS() throws IOException {
return mRts;
}
@Override
public void setRTS(boolean value) throws IOException {
mRts = value;
setDtrRts();
}
private void setDtrRts() throws IOException {
int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
}
@Override
public EnumSet<ControlLine> getControlLines() throws IOException {
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
if(mRts) set.add(ControlLine.RTS);
if(mDtr) set.add(ControlLine.DTR);
return set;
}
@Override
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
return EnumSet.of(ControlLine.RTS, ControlLine.DTR);
}
@Override
public void setBreak(boolean value) throws IOException {
sendAcmControlMessage(SEND_BREAK, value ? 0xffff : 0, null);
}
}
@SuppressWarnings({"unused"})
public static Map<Integer, int[]> getSupportedDevices() {
return new LinkedHashMap<>();
}
}

View File

@ -0,0 +1,387 @@
/* Copyright 2014 Andreas Butti
*
* Project home page: https://github.com/mik3y/usb-serial-for-android
*/
package com.hoho.android.usbserial.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.util.Log;
import com.hoho.android.usbserial.BuildConfig;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class Ch34xSerialDriver implements UsbSerialDriver {
private static final String TAG = Ch34xSerialDriver.class.getSimpleName();
private final UsbDevice mDevice;
private final UsbSerialPort mPort;
private static final int LCR_ENABLE_RX = 0x80;
private static final int LCR_ENABLE_TX = 0x40;
private static final int LCR_MARK_SPACE = 0x20;
private static final int LCR_PAR_EVEN = 0x10;
private static final int LCR_ENABLE_PAR = 0x08;
private static final int LCR_STOP_BITS_2 = 0x04;
private static final int LCR_CS8 = 0x03;
private static final int LCR_CS7 = 0x02;
private static final int LCR_CS6 = 0x01;
private static final int LCR_CS5 = 0x00;
private static final int GCL_CTS = 0x01;
private static final int GCL_DSR = 0x02;
private static final int GCL_RI = 0x04;
private static final int GCL_CD = 0x08;
private static final int SCL_DTR = 0x20;
private static final int SCL_RTS = 0x40;
public Ch34xSerialDriver(UsbDevice device) {
mDevice = device;
mPort = new Ch340SerialPort(mDevice, 0);
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
@Override
public List<UsbSerialPort> getPorts() {
return Collections.singletonList(mPort);
}
public class Ch340SerialPort extends CommonUsbSerialPort {
private static final int USB_TIMEOUT_MILLIS = 5000;
private final int DEFAULT_BAUD_RATE = 9600;
private boolean dtr = false;
private boolean rts = false;
public Ch340SerialPort(UsbDevice device, int portNumber) {
super(device, portNumber);
}
@Override
public UsbSerialDriver getDriver() {
return Ch34xSerialDriver.this;
}
@Override
protected void openInt() throws IOException {
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
UsbInterface usbIface = mDevice.getInterface(i);
if (!mConnection.claimInterface(usbIface, true)) {
throw new IOException("Could not claim data interface");
}
}
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
UsbEndpoint ep = dataIface.getEndpoint(i);
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
mReadEndpoint = ep;
} else {
mWriteEndpoint = ep;
}
}
}
initialize();
setBaudRate(DEFAULT_BAUD_RATE);
}
@Override
protected void closeInt() {
try {
for (int i = 0; i < mDevice.getInterfaceCount(); i++)
mConnection.releaseInterface(mDevice.getInterface(i));
} catch(Exception ignored) {}
}
private int controlOut(int request, int value, int index) {
final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request,
value, index, null, 0, USB_TIMEOUT_MILLIS);
}
private int controlIn(int request, int value, int index, byte[] buffer) {
final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
return mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, request,
value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS);
}
private void checkState(String msg, int request, int value, int[] expected) throws IOException {
byte[] buffer = new byte[expected.length];
int ret = controlIn(request, value, 0, buffer);
if (ret < 0) {
throw new IOException("Failed send cmd [" + msg + "]");
}
if (ret != expected.length) {
throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]");
}
for (int i = 0; i < expected.length; i++) {
if (expected[i] == -1) {
continue;
}
int current = buffer[i] & 0xff;
if (expected[i] != current) {
throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " byte, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
}
}
}
private void setControlLines() throws IOException {
if (controlOut(0xa4, ~((dtr ? SCL_DTR : 0) | (rts ? SCL_RTS : 0)), 0) < 0) {
throw new IOException("Failed to set control lines");
}
}
private byte getStatus() throws IOException {
byte[] buffer = new byte[2];
int ret = controlIn(0x95, 0x0706, 0, buffer);
if (ret < 0)
throw new IOException("Error getting control lines");
return buffer[0];
}
private void initialize() throws IOException {
checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00});
if (controlOut(0xa1, 0, 0) < 0) {
throw new IOException("Init failed: #2");
}
setBaudRate(DEFAULT_BAUD_RATE);
checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00});
if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) {
throw new IOException("Init failed: #5");
}
checkState("init #6", 0x95, 0x0706, new int[]{-1/*0xf?*/, -1/*0xec,0xee*/});
if (controlOut(0xa1, 0x501f, 0xd90a) < 0) {
throw new IOException("Init failed: #7");
}
setBaudRate(DEFAULT_BAUD_RATE);
setControlLines();
checkState("init #10", 0x95, 0x0706, new int[]{-1/* 0x9f, 0xff*/, -1/*0xec,0xee*/});
}
private void setBaudRate(int baudRate) throws IOException {
long factor;
long divisor;
if (baudRate == 921600) {
divisor = 7;
factor = 0xf300;
} else {
final long BAUDBASE_FACTOR = 1532620800;
final int BAUDBASE_DIVMAX = 3;
if(BuildConfig.DEBUG && (baudRate & (3<<29)) == (1<<29))
baudRate &= ~(1<<29); // for testing purpose bypass dedicated baud rate handling
factor = BAUDBASE_FACTOR / baudRate;
divisor = BAUDBASE_DIVMAX;
while ((factor > 0xfff0) && divisor > 0) {
factor >>= 3;
divisor--;
}
if (factor > 0xfff0) {
throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate);
}
factor = 0x10000 - factor;
}
divisor |= 0x0080; // else ch341a waits until buffer full
int val1 = (int) ((factor & 0xff00) | divisor);
int val2 = (int) (factor & 0xff);
Log.d(TAG, String.format("baud rate=%d, 0x1312=0x%04x, 0x0f2c=0x%04x", baudRate, val1, val2));
int ret = controlOut(0x9a, 0x1312, val1);
if (ret < 0) {
throw new IOException("Error setting baud rate: #1)");
}
ret = controlOut(0x9a, 0x0f2c, val2);
if (ret < 0) {
throw new IOException("Error setting baud rate: #2");
}
}
@Override
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
if(baudRate <= 0) {
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
}
setBaudRate(baudRate);
int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX;
switch (dataBits) {
case DATABITS_5:
lcr |= LCR_CS5;
break;
case DATABITS_6:
lcr |= LCR_CS6;
break;
case DATABITS_7:
lcr |= LCR_CS7;
break;
case DATABITS_8:
lcr |= LCR_CS8;
break;
default:
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
}
switch (parity) {
case PARITY_NONE:
break;
case PARITY_ODD:
lcr |= LCR_ENABLE_PAR;
break;
case PARITY_EVEN:
lcr |= LCR_ENABLE_PAR | LCR_PAR_EVEN;
break;
case PARITY_MARK:
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE;
break;
case PARITY_SPACE:
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN;
break;
default:
throw new IllegalArgumentException("Invalid parity: " + parity);
}
switch (stopBits) {
case STOPBITS_1:
break;
case STOPBITS_1_5:
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
case STOPBITS_2:
lcr |= LCR_STOP_BITS_2;
break;
default:
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
}
int ret = controlOut(0x9a, 0x2518, lcr);
if (ret < 0) {
throw new IOException("Error setting control byte");
}
}
@Override
public boolean getCD() throws IOException {
return (getStatus() & GCL_CD) == 0;
}
@Override
public boolean getCTS() throws IOException {
return (getStatus() & GCL_CTS) == 0;
}
@Override
public boolean getDSR() throws IOException {
return (getStatus() & GCL_DSR) == 0;
}
@Override
public boolean getDTR() throws IOException {
return dtr;
}
@Override
public void setDTR(boolean value) throws IOException {
dtr = value;
setControlLines();
}
@Override
public boolean getRI() throws IOException {
return (getStatus() & GCL_RI) == 0;
}
@Override
public boolean getRTS() throws IOException {
return rts;
}
@Override
public void setRTS(boolean value) throws IOException {
rts = value;
setControlLines();
}
@Override
public EnumSet<ControlLine> getControlLines() throws IOException {
int status = getStatus();
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
if(rts) set.add(ControlLine.RTS);
if((status & GCL_CTS) == 0) set.add(ControlLine.CTS);
if(dtr) set.add(ControlLine.DTR);
if((status & GCL_DSR) == 0) set.add(ControlLine.DSR);
if((status & GCL_CD) == 0) set.add(ControlLine.CD);
if((status & GCL_RI) == 0) set.add(ControlLine.RI);
return set;
}
@Override
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
return EnumSet.allOf(ControlLine.class);
}
@Override
public void setBreak(boolean value) throws IOException {
byte[] req = new byte[2];
if(controlIn(0x95, 0x1805, 0, req) < 0) {
throw new IOException("Error getting BREAK condition");
}
if(value) {
req[0] &= ~1;
req[1] &= ~0x40;
} else {
req[0] |= 1;
req[1] |= 0x40;
}
int val = (req[1] & 0xff) << 8 | (req[0] & 0xff);
if(controlOut(0x9a, 0x1805, val) < 0) {
throw new IOException("Error setting BREAK condition");
}
}
}
@SuppressWarnings({"unused"})
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
supportedDevices.put(UsbId.VENDOR_QINHENG, new int[]{
UsbId.QINHENG_CH340,
UsbId.QINHENG_CH341A,
});
return supportedDevices;
}
}

Some files were not shown because too many files have changed in this diff Show More