@leonardojc/capacitor-ioboard 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,14 +4,17 @@ import android.util.Log;
|
|
|
4
4
|
import android.util.Base64;
|
|
5
5
|
import android.os.Handler;
|
|
6
6
|
import android.os.Looper;
|
|
7
|
+
import com.getcapacitor.JSObject;
|
|
8
|
+
import com.getcapacitor.PluginCall;
|
|
9
|
+
import com.frankandroid.capacitor.serialport.SerialPortPlugin;
|
|
7
10
|
import java.util.Arrays;
|
|
8
11
|
import java.util.ArrayList;
|
|
9
12
|
import java.util.List;
|
|
10
13
|
import java.util.concurrent.TimeUnit;
|
|
11
14
|
import java.util.concurrent.CountDownLatch;
|
|
12
|
-
import java.
|
|
13
|
-
import java.
|
|
14
|
-
import java.
|
|
15
|
+
import java.util.concurrent.CompletableFuture;
|
|
16
|
+
import java.util.concurrent.ScheduledExecutorService;
|
|
17
|
+
import java.util.concurrent.Executors;
|
|
15
18
|
import java.io.IOException;
|
|
16
19
|
|
|
17
20
|
/**
|
|
@@ -23,15 +26,13 @@ public class IOBoardManager {
|
|
|
23
26
|
|
|
24
27
|
private static final String TAG = "IOBoardManager";
|
|
25
28
|
|
|
26
|
-
//
|
|
27
|
-
private FileInputStream serialInputStream;
|
|
28
|
-
private FileOutputStream serialOutputStream;
|
|
29
|
-
private String currentPortPath;
|
|
29
|
+
// SerialPort plugin integration
|
|
30
30
|
private boolean isConnected = false;
|
|
31
|
-
private
|
|
31
|
+
private String currentPortId = null;
|
|
32
32
|
private Handler mainHandler;
|
|
33
33
|
private String responseBuffer = "";
|
|
34
34
|
private CountDownLatch responseLatch;
|
|
35
|
+
private com.frankandroid.capacitor.serialport.SerialPortPlugin serialPortPlugin;
|
|
35
36
|
|
|
36
37
|
// Response classes
|
|
37
38
|
public static class IOBoardResponse {
|
|
@@ -140,11 +141,12 @@ public class IOBoardManager {
|
|
|
140
141
|
*/
|
|
141
142
|
public IOBoardManager() {
|
|
142
143
|
mainHandler = new Handler(Looper.getMainLooper());
|
|
143
|
-
|
|
144
|
+
serialPortPlugin = new com.frankandroid.capacitor.serialport.SerialPortPlugin();
|
|
145
|
+
Log.d(TAG, "IOBoardManager initialized with SerialPort plugin");
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
/**
|
|
147
|
-
* Open serial port
|
|
149
|
+
* Open serial port using SerialPort plugin
|
|
148
150
|
*/
|
|
149
151
|
public boolean openSerialPort(String portPath, int baudRate) {
|
|
150
152
|
if (isConnected) {
|
|
@@ -153,160 +155,236 @@ public class IOBoardManager {
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
try {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
158
|
+
Log.d(TAG, "Opening serial port via SerialPort plugin: " + portPath + " at " + baudRate + " baud");
|
|
159
|
+
|
|
160
|
+
// Create a mock PluginCall for the SerialPort plugin
|
|
161
|
+
JSObject openParams = new JSObject();
|
|
162
|
+
openParams.put("path", portPath);
|
|
163
|
+
openParams.put("baudRate", baudRate);
|
|
164
|
+
|
|
165
|
+
// Use CompletableFuture to handle async call
|
|
166
|
+
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
|
167
|
+
|
|
168
|
+
PluginCall mockCall = new PluginCall() {
|
|
169
|
+
@Override
|
|
170
|
+
public void resolve(JSObject result) {
|
|
171
|
+
boolean success = result.optBoolean("success", false);
|
|
172
|
+
if (success) {
|
|
173
|
+
isConnected = true;
|
|
174
|
+
currentPortId = portPath; // Store port path as ID
|
|
175
|
+
Log.d(TAG, "SerialPort opened successfully");
|
|
176
|
+
setupSerialDataListener();
|
|
177
|
+
}
|
|
178
|
+
future.complete(success);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@Override
|
|
182
|
+
public void reject(String message) {
|
|
183
|
+
Log.e(TAG, "Failed to open SerialPort: " + message);
|
|
184
|
+
future.complete(false);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@Override
|
|
188
|
+
public String getString(String key) {
|
|
189
|
+
return openParams.optString(key);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@Override
|
|
193
|
+
public int getInt(String key, int defaultValue) {
|
|
194
|
+
return openParams.optInt(key, defaultValue);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Call SerialPort plugin
|
|
199
|
+
serialPortPlugin.openPort(mockCall);
|
|
200
|
+
|
|
201
|
+
// Wait for result (with timeout)
|
|
202
|
+
return future.get(5, TimeUnit.SECONDS);
|
|
203
|
+
|
|
204
|
+
} catch (Exception e) {
|
|
205
|
+
Log.e(TAG, "Error opening port via SerialPort plugin: " + e.getMessage());
|
|
178
206
|
isConnected = false;
|
|
179
207
|
return false;
|
|
180
208
|
}
|
|
181
209
|
}
|
|
182
210
|
|
|
183
211
|
/**
|
|
184
|
-
*
|
|
212
|
+
* Setup data listener for SerialPort plugin
|
|
213
|
+
*/
|
|
214
|
+
private void setupSerialDataListener() {
|
|
215
|
+
// The SerialPort plugin will emit data events that we can capture
|
|
216
|
+
// For now, we'll rely on the existing data flow mechanism
|
|
217
|
+
Log.d(TAG, "Serial data listener setup completed");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Close serial port using SerialPort plugin
|
|
185
222
|
*/
|
|
186
223
|
public void closeSerialPort() {
|
|
187
224
|
if (!isConnected) return;
|
|
188
225
|
|
|
189
226
|
try {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
227
|
+
Log.d(TAG, "Closing serial port via SerialPort plugin");
|
|
228
|
+
|
|
229
|
+
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
|
230
|
+
|
|
231
|
+
PluginCall mockCall = new PluginCall() {
|
|
232
|
+
@Override
|
|
233
|
+
public void resolve(JSObject result) {
|
|
234
|
+
isConnected = false;
|
|
235
|
+
currentPortId = null;
|
|
236
|
+
Log.d(TAG, "SerialPort closed successfully");
|
|
237
|
+
future.complete(true);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@Override
|
|
241
|
+
public void reject(String message) {
|
|
242
|
+
Log.e(TAG, "Failed to close SerialPort: " + message);
|
|
243
|
+
future.complete(false);
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
serialPortPlugin.closePort(mockCall);
|
|
248
|
+
future.get(2, TimeUnit.SECONDS);
|
|
249
|
+
|
|
250
|
+
} catch (Exception e) {
|
|
251
|
+
Log.e(TAG, "Error closing port via SerialPort plugin: " + e.getMessage());
|
|
209
252
|
}
|
|
210
253
|
}
|
|
211
254
|
|
|
212
255
|
/**
|
|
213
|
-
*
|
|
256
|
+
* Send command and wait for response using SerialPort plugin
|
|
214
257
|
*/
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
258
|
+
public CompletableFuture<byte[]> sendCommandAndWaitResponse(byte[] command, int timeoutMs) {
|
|
259
|
+
CompletableFuture<byte[]> future = new CompletableFuture<>();
|
|
260
|
+
|
|
261
|
+
if (!isConnected) {
|
|
262
|
+
future.completeExceptionally(new IOException("Port is not connected"));
|
|
263
|
+
return future;
|
|
218
264
|
}
|
|
219
265
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
Thread.sleep(10); // Small delay to prevent excessive CPU usage
|
|
239
|
-
} catch (IOException | InterruptedException e) {
|
|
240
|
-
if (isConnected) {
|
|
241
|
-
Log.e(TAG, "Error in reader thread: " + e.getMessage());
|
|
266
|
+
try {
|
|
267
|
+
Log.d(TAG, "Sending command: " + IOBoardProtocolUtils.bytesToHex(command));
|
|
268
|
+
|
|
269
|
+
// Send command using SerialPort plugin
|
|
270
|
+
JSObject writeParams = new JSObject();
|
|
271
|
+
String hexData = IOBoardProtocolUtils.bytesToHex(command);
|
|
272
|
+
writeParams.put("data", hexData);
|
|
273
|
+
|
|
274
|
+
PluginCall writeCall = new PluginCall() {
|
|
275
|
+
@Override
|
|
276
|
+
public void resolve(JSObject result) {
|
|
277
|
+
boolean success = result.optBoolean("success", false);
|
|
278
|
+
if (success) {
|
|
279
|
+
Log.d(TAG, "Command sent successfully via SerialPort");
|
|
280
|
+
// Start waiting for response
|
|
281
|
+
waitForResponse(future, timeoutMs);
|
|
282
|
+
} else {
|
|
283
|
+
future.completeExceptionally(new IOException("Failed to send command"));
|
|
242
284
|
}
|
|
243
|
-
break;
|
|
244
285
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
286
|
+
|
|
287
|
+
@Override
|
|
288
|
+
public void reject(String message) {
|
|
289
|
+
Log.e(TAG, "Failed to send data: " + message);
|
|
290
|
+
future.completeExceptionally(new IOException("Send failed: " + message));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
@Override
|
|
294
|
+
public String getString(String key) {
|
|
295
|
+
return writeParams.optString(key);
|
|
296
|
+
}
|
|
297
|
+
};
|
|
250
298
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
readerThread.interrupt();
|
|
257
|
-
try {
|
|
258
|
-
readerThread.join(1000); // Wait up to 1 second
|
|
259
|
-
} catch (InterruptedException e) {
|
|
260
|
-
Thread.currentThread().interrupt();
|
|
261
|
-
}
|
|
299
|
+
serialPortPlugin.writeData(writeCall);
|
|
300
|
+
|
|
301
|
+
} catch (Exception e) {
|
|
302
|
+
Log.e(TAG, "Error sending command: " + e.getMessage());
|
|
303
|
+
future.completeExceptionally(e);
|
|
262
304
|
}
|
|
305
|
+
|
|
306
|
+
return future;
|
|
263
307
|
}
|
|
264
308
|
|
|
265
309
|
/**
|
|
266
|
-
*
|
|
310
|
+
* Helper method for backward compatibility - returns String response
|
|
267
311
|
*/
|
|
268
312
|
private String sendCommandAndWaitResponse(byte[] command, int timeoutMs) throws Exception {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
313
|
+
CompletableFuture<byte[]> future = sendCommandAndWaitResponse(command, timeoutMs);
|
|
314
|
+
byte[] responseData = future.get(timeoutMs + 1000, TimeUnit.MILLISECONDS);
|
|
315
|
+
return new String(responseData, "ISO-8859-1");
|
|
316
|
+
}
|
|
272
317
|
|
|
273
|
-
|
|
274
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Wait for response from SerialPort
|
|
320
|
+
*/
|
|
321
|
+
private void waitForResponse(CompletableFuture<byte[]> future, int timeoutMs) {
|
|
322
|
+
// Schedule timeout
|
|
323
|
+
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
|
324
|
+
scheduler.schedule(() -> {
|
|
325
|
+
if (!future.isDone()) {
|
|
326
|
+
future.completeExceptionally(new IOException("Response timeout after " + timeoutMs + "ms"));
|
|
327
|
+
}
|
|
328
|
+
}, timeoutMs, TimeUnit.MILLISECONDS);
|
|
275
329
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
330
|
+
// Set up listener for incoming data
|
|
331
|
+
// Note: This would typically be set up through the SerialPort plugin's data events
|
|
332
|
+
// For now, we'll use a simplified approach
|
|
333
|
+
setupResponseListener(future, scheduler);
|
|
334
|
+
}
|
|
281
335
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
336
|
+
/**
|
|
337
|
+
* Setup response listener (simplified for SerialPort integration)
|
|
338
|
+
*/
|
|
339
|
+
private void setupResponseListener(CompletableFuture<byte[]> future, ScheduledExecutorService scheduler) {
|
|
340
|
+
// This would be implemented to listen for data events from SerialPort plugin
|
|
341
|
+
// For now, we'll implement a polling mechanism
|
|
342
|
+
new Thread(() -> {
|
|
343
|
+
try {
|
|
344
|
+
Thread.sleep(100); // Wait for potential response
|
|
345
|
+
|
|
346
|
+
// Try to read response using SerialPort plugin
|
|
347
|
+
JSObject readParams = new JSObject();
|
|
348
|
+
readParams.put("timeout", 1000);
|
|
349
|
+
|
|
350
|
+
PluginCall readCall = new PluginCall() {
|
|
351
|
+
@Override
|
|
352
|
+
public void resolve(JSObject result) {
|
|
353
|
+
try {
|
|
354
|
+
String dataHex = result.optString("data", "");
|
|
355
|
+
if (!dataHex.isEmpty()) {
|
|
356
|
+
byte[] responseData = IOBoardProtocolUtils.hexToBytes(dataHex);
|
|
357
|
+
Log.d(TAG, "Received response: " + IOBoardProtocolUtils.bytesToHex(responseData));
|
|
358
|
+
future.complete(responseData);
|
|
359
|
+
} else {
|
|
360
|
+
future.completeExceptionally(new IOException("No response data received"));
|
|
361
|
+
}
|
|
362
|
+
} catch (Exception e) {
|
|
363
|
+
future.completeExceptionally(e);
|
|
364
|
+
} finally {
|
|
365
|
+
scheduler.shutdown();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
@Override
|
|
370
|
+
public void reject(String message) {
|
|
371
|
+
future.completeExceptionally(new IOException("Read failed: " + message));
|
|
372
|
+
scheduler.shutdown();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@Override
|
|
376
|
+
public int getInt(String key, int defaultValue) {
|
|
377
|
+
return readParams.optInt(key, defaultValue);
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
serialPortPlugin.readData(readCall);
|
|
382
|
+
|
|
383
|
+
} catch (Exception e) {
|
|
384
|
+
future.completeExceptionally(e);
|
|
385
|
+
scheduler.shutdown();
|
|
302
386
|
}
|
|
303
|
-
|
|
304
|
-
} catch (IOException e) {
|
|
305
|
-
throw new Exception("Error sending command: " + e.getMessage());
|
|
306
|
-
} catch (InterruptedException e) {
|
|
307
|
-
Thread.currentThread().interrupt();
|
|
308
|
-
throw new Exception("Command interrupted");
|
|
309
|
-
}
|
|
387
|
+
}).start();
|
|
310
388
|
}
|
|
311
389
|
|
|
312
390
|
// New simplified API methods
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leonardojc/capacitor-ioboard",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "A Capacitor plugin for controlling custom IOBOARD devices via RS485 serial communication with full native protocol implementation",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|