Skip to content

Commit a018c41

Browse files
committed
Added Read Event Dispatching
Implemented read events for incoming data. Javascript function registerReadCallback() will register a callback that will be called when data is read from the serial device.
1 parent 646d6ac commit a018c41

File tree

2 files changed

+239
-9
lines changed

2 files changed

+239
-9
lines changed

src/android/org/stereolux/cordova/serial/Serial.java

Lines changed: 229 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.stereolux.cordova.serial;
22

33
import java.io.IOException;
4+
import java.util.concurrent.ExecutorService;
5+
import java.util.concurrent.Executors;
46
import java.nio.ByteBuffer;
57
import java.util.List;
68

@@ -19,11 +21,16 @@
1921
import android.hardware.usb.UsbDeviceConnection;
2022
import android.hardware.usb.UsbManager;
2123
import android.util.Log;
24+
import android.util.Base64;
2225

2326
import com.hoho.android.usbserial.driver.UsbSerialDriver;
2427
import com.hoho.android.usbserial.driver.UsbSerialPort;
2528
import com.hoho.android.usbserial.driver.UsbSerialProber;
2629

30+
import com.hoho.android.usbserial.util.SerialInputOutputManager;
31+
import com.hoho.android.usbserial.util.HexDump;
32+
33+
2734
/**
2835
* Cordova plugin to communicate with the android serial port
2936
* @author Xavier Seignard <[email protected]>
@@ -37,6 +44,8 @@ public class Serial extends CordovaPlugin {
3744
private static final String ACTION_READ = "readSerial";
3845
private static final String ACTION_WRITE = "writeSerial";
3946
private static final String ACTION_CLOSE = "closeSerial";
47+
private static final String ACTION_READ_CALLBACK = "registerReadCallback";
48+
4049
// UsbManager instance to deal with permission and opening
4150
private UsbManager manager;
4251
// The current driver that handle the serial port
@@ -49,6 +58,37 @@ public class Serial extends CordovaPlugin {
4958

5059
private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
5160

61+
// Connection info
62+
int baudRate;
63+
int dataBits;
64+
int stopBits;
65+
int parity;
66+
boolean setDTR;
67+
68+
boolean portPaused;
69+
70+
private CallbackContext readCallback;
71+
72+
73+
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
74+
private SerialInputOutputManager mSerialIoManager;
75+
76+
private final SerialInputOutputManager.Listener mListener =
77+
new SerialInputOutputManager.Listener() {
78+
79+
@Override
80+
public void onRunError(Exception e) {
81+
Log.d(TAG, "Runner stopped.");
82+
}
83+
84+
@Override
85+
public void onNewData(final byte[] data) {
86+
Serial.this.updateReceivedData(data);
87+
}
88+
};
89+
90+
91+
5292
/**
5393
* Overridden execute method
5494
* @param action the string representation of the action to execute
@@ -88,6 +128,11 @@ else if (ACTION_CLOSE.equals(action)) {
88128
closeSerial(callbackContext);
89129
return true;
90130
}
131+
// Register read callback
132+
else if (ACTION_READ_CALLBACK.equals(action)) {
133+
registerReadCallback(callbackContext);
134+
return true;
135+
}
91136
// the action doesn't exist
92137
return false;
93138
}
@@ -127,29 +172,35 @@ public void run() {
127172
});
128173
}
129174

175+
130176
/**
131-
* Open the serial port
177+
* Open the serial port from Cordova
132178
* @param opts a {@link JSONObject} containing the connection paramters
133179
* @param callbackContext the cordova {@link CallbackContext}
134180
*/
135181
private void openSerial(final JSONObject opts, final CallbackContext callbackContext) {
182+
136183
cordova.getThreadPool().execute(new Runnable() {
137184
public void run() {
185+
138186
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
187+
139188
if (connection != null) {
140189
// get first port and open it
141190
port = driver.getPorts().get(0);
191+
142192
try {
143-
port.open(connection);
193+
144194
// get connection params or the default values
145-
int baudRate = opts.has("baudRate") ? opts.getInt("baudRate") : 9600;
146-
int dataBits = opts.has("dataBits") ? opts.getInt("dataBits") : UsbSerialPort.DATABITS_8;
147-
int stopBits = opts.has("stopBits") ? opts.getInt("stopBits") : UsbSerialPort.STOPBITS_1;
148-
int parity = opts.has("parity") ? opts.getInt("parity") : UsbSerialPort.PARITY_NONE;
195+
baudRate = opts.has("baudRate") ? opts.getInt("baudRate") : 9600;
196+
dataBits = opts.has("dataBits") ? opts.getInt("dataBits") : UsbSerialPort.DATABITS_8;
197+
stopBits = opts.has("stopBits") ? opts.getInt("stopBits") : UsbSerialPort.STOPBITS_1;
198+
parity = opts.has("parity") ? opts.getInt("parity") : UsbSerialPort.PARITY_NONE;
199+
setDTR = opts.has("dtr") && opts.getBoolean("dtr");
200+
201+
port.open(connection);
149202
port.setParameters(baudRate, dataBits, stopBits, parity);
150-
if (opts.has("dtr") && opts.getBoolean("dtr")) {
151-
port.setDTR(true);
152-
}
203+
if (setDTR) port.setDTR(true);
153204
}
154205
catch (IOException e) {
155206
// deal with error
@@ -161,13 +212,15 @@ public void run() {
161212
Log.d(TAG, e.getMessage());
162213
callbackContext.error(e.getMessage());
163214
}
215+
164216
Log.d(TAG, "Serial port opened!");
165217
callbackContext.success("Serial port opened!");
166218
}
167219
else {
168220
Log.d(TAG, "Cannot connect to the device!");
169221
callbackContext.error("Cannot connect to the device!");
170222
}
223+
onDeviceStateChange();
171224
}
172225
});
173226
}
@@ -254,7 +307,174 @@ public void run() {
254307
Log.d(TAG, e.getMessage());
255308
callbackContext.error(e.getMessage());
256309
}
310+
onDeviceStateChange();
257311
}
258312
});
259313
}
314+
315+
316+
private void stopIoManager() {
317+
if (mSerialIoManager != null) {
318+
Log.i(TAG, "Stopping io manager ..");
319+
mSerialIoManager.stop();
320+
mSerialIoManager = null;
321+
}
322+
}
323+
324+
private void startIoManager() {
325+
if (driver != null) {
326+
Log.i(TAG, "Starting io manager ..");
327+
mSerialIoManager = new SerialInputOutputManager(port, mListener);
328+
mExecutor.submit(mSerialIoManager);
329+
}
330+
}
331+
332+
private void onDeviceStateChange() {
333+
stopIoManager();
334+
startIoManager();
335+
}
336+
337+
/**
338+
* Dispatch read data to javascript
339+
* @param data
340+
*/
341+
private void updateReceivedData(byte[] data) {
342+
343+
if( readCallback != null ) {
344+
345+
// final String message = "Read " + data.length + " bytes: \n" + HexDump.dumpHexString(data) + "\n\n";
346+
// Log.d(TAG, message);
347+
348+
JSONObject returnObj = new JSONObject();
349+
addProperty(returnObj, "length", data.length);
350+
addPropertyBytes(returnObj, "data", data);
351+
352+
PluginResult result = new PluginResult(PluginResult.Status.OK, returnObj);
353+
result.setKeepCallback(true);
354+
readCallback.sendPluginResult(result);
355+
}
356+
357+
}
358+
359+
360+
/**
361+
* Register callback for read data
362+
* @param callbackContext the cordova {@link CallbackContext}
363+
*/
364+
private void registerReadCallback(final CallbackContext callbackContext) {
365+
366+
Log.d(TAG, "Registering Callback");
367+
368+
369+
cordova.getThreadPool().execute(new Runnable() {
370+
public void run() {
371+
372+
Log.d(TAG, "Registering Read Callback");
373+
readCallback = callbackContext;
374+
375+
JSONObject returnObj = new JSONObject();
376+
addProperty(returnObj, "registerReadCallback", "true");
377+
378+
//Keep the callback
379+
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, returnObj);
380+
pluginResult.setKeepCallback(true);
381+
callbackContext.sendPluginResult(pluginResult);
382+
383+
}
384+
});
385+
386+
}
387+
388+
389+
390+
@Override
391+
public void onPause(boolean multitasking) {
392+
393+
stopIoManager();
394+
if (port != null) {
395+
try {
396+
port.close();
397+
} catch (IOException e) {
398+
// Ignore.
399+
}
400+
portPaused = true;
401+
port = null;
402+
}
403+
404+
}
405+
406+
@Override
407+
public void onResume(boolean multitasking) {
408+
409+
Log.d(TAG, "Resumed, driver=" + driver);
410+
if (driver == null && portPaused) {
411+
Log.d(TAG, "No serial device to resume.");
412+
} else {
413+
414+
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
415+
416+
if (connection != null) {
417+
// get first port and open it
418+
port = driver.getPorts().get(0);
419+
420+
try {
421+
422+
port.open(connection);
423+
port.setParameters(baudRate, dataBits, stopBits, parity);
424+
if (setDTR) port.setDTR(true);
425+
}
426+
catch (IOException e) {
427+
// deal with error
428+
Log.d(TAG, e.getMessage());
429+
}
430+
Log.d(TAG, "Serial port opened!");
431+
}
432+
else {
433+
Log.d(TAG, "Cannot connect to the device!");
434+
}
435+
436+
Log.d(TAG, "Serial device: " + driver.getClass().getSimpleName());
437+
}
438+
onDeviceStateChange();
439+
}
440+
441+
442+
443+
/**
444+
* The final call you receive before your activity is destroyed.
445+
*/
446+
@Override
447+
public void onDestroy() {
448+
449+
Log.d(TAG, "Destroy, port=" + port);
450+
451+
if(port != null)
452+
try {
453+
port.close();
454+
}
455+
catch (IOException e) {
456+
Log.d(TAG, e.getMessage());
457+
}
458+
459+
onDeviceStateChange();
460+
461+
}
462+
463+
464+
private void addProperty(JSONObject obj, String key, Object value)
465+
{
466+
try
467+
{
468+
obj.put(key, value);
469+
}
470+
catch (JSONException e){}
471+
}
472+
473+
private void addPropertyBytes(JSONObject obj, String key, byte[] bytes)
474+
{
475+
String string = Base64.encodeToString(bytes, Base64.NO_WRAP);
476+
addProperty(obj, key, string);
477+
}
478+
479+
260480
}

www/serial.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ var serial = {
4343
'closeSerial',
4444
[]
4545
);
46+
},
47+
registerReadCallback: function(successCallback, errorCallback) {
48+
cordova.exec(
49+
successCallback,
50+
errorCallback,
51+
'Serial',
52+
'registerReadCallback',
53+
[]
54+
);
4655
}
56+
4757
};
4858
module.exports = serial;

0 commit comments

Comments
 (0)