@leonardojc/capacitor-ioboard 1.2.7 → 2.0.0
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.
- package/README.md +257 -209
- package/android/build.gradle +0 -1
- package/android/src/main/java/com/leonardojc/capacitor/ioboard/CapacitorIoboardPlugin.java +926 -381
- package/android/src/main/java/com/leonardojc/capacitor/ioboard/CapacitorIoboardPlugin.java.backup +777 -0
- package/android/src/main/java/com/leonardojc/capacitor/ioboard/SerialConnectionManager.java +446 -0
- package/dist/esm/definitions-v2.d.ts +228 -0
- package/dist/esm/definitions-v2.js +11 -0
- package/dist/esm/definitions.d.ts +28 -0
- package/dist/esm/index-v2.d.ts +266 -0
- package/dist/esm/index-v2.js +295 -0
- package/dist/esm/web.d.ts +13 -16
- package/dist/esm/web.js +51 -135
- package/dist/plugin.cjs.js +50 -134
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +50 -134
- package/dist/plugin.js.map +1 -1
- package/package.json +3 -4
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
package com.leonardojc.capacitor.ioboard;
|
|
2
|
+
|
|
3
|
+
import android.os.Handler;
|
|
4
|
+
import android.os.Looper;
|
|
5
|
+
import android.util.Log;
|
|
6
|
+
import java.io.File;
|
|
7
|
+
import java.io.FileInputStream;
|
|
8
|
+
import java.io.FileOutputStream;
|
|
9
|
+
import java.io.IOException;
|
|
10
|
+
import java.util.ArrayList;
|
|
11
|
+
import java.util.List;
|
|
12
|
+
import java.util.concurrent.ExecutorService;
|
|
13
|
+
import java.util.concurrent.Executors;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Serial communication manager for IOBoard plugin
|
|
17
|
+
* Handles low-level serial port operations
|
|
18
|
+
*/
|
|
19
|
+
public class SerialConnectionManager {
|
|
20
|
+
private static final String TAG = "SerialConnectionManager";
|
|
21
|
+
|
|
22
|
+
public interface SerialDataListener {
|
|
23
|
+
void onDataReceived(byte[] data);
|
|
24
|
+
void onConnectionStateChanged(boolean connected);
|
|
25
|
+
void onError(String error);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private FileInputStream serialInputStream;
|
|
29
|
+
private FileOutputStream serialOutputStream;
|
|
30
|
+
private String currentPortPath;
|
|
31
|
+
private boolean isConnected = false;
|
|
32
|
+
private Thread readerThread;
|
|
33
|
+
private Handler mainHandler;
|
|
34
|
+
private SerialDataListener listener;
|
|
35
|
+
private ExecutorService executorService;
|
|
36
|
+
|
|
37
|
+
public SerialConnectionManager() {
|
|
38
|
+
mainHandler = new Handler(Looper.getMainLooper());
|
|
39
|
+
executorService = Executors.newSingleThreadExecutor();
|
|
40
|
+
Log.d(TAG, "SerialConnectionManager initialized");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public void setDataListener(SerialDataListener listener) {
|
|
44
|
+
this.listener = listener;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Opens a serial port connection
|
|
49
|
+
*/
|
|
50
|
+
public synchronized boolean openPort(String portPath, int baudRate, int dataBits, int stopBits, String parity) {
|
|
51
|
+
try {
|
|
52
|
+
Log.d(TAG, "Opening serial port: " + portPath + " at " + baudRate + " baud");
|
|
53
|
+
|
|
54
|
+
if (isConnected) {
|
|
55
|
+
Log.w(TAG, "Port already connected, closing existing connection");
|
|
56
|
+
closePort();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Verificar que el puerto existe
|
|
60
|
+
File portFile = new File(portPath);
|
|
61
|
+
if (!portFile.exists()) {
|
|
62
|
+
throw new IOException("Serial port does not exist: " + portPath);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Configurar parámetros del puerto serial usando stty
|
|
66
|
+
String sttyCommand = String.format(
|
|
67
|
+
"stty -F %s %d cs%d %s %s raw -echo -echoe -echok -echoctl -echoke",
|
|
68
|
+
portPath,
|
|
69
|
+
baudRate,
|
|
70
|
+
dataBits,
|
|
71
|
+
stopBits == 1 ? "-cstopb" : "cstopb",
|
|
72
|
+
getParityFlag(parity)
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
Log.d(TAG, "Configuring port with: " + sttyCommand);
|
|
76
|
+
Process sttyProcess = Runtime.getRuntime().exec(new String[]{"su", "-c", sttyCommand});
|
|
77
|
+
int sttyResult = sttyProcess.waitFor();
|
|
78
|
+
|
|
79
|
+
Log.d(TAG, "stty configuration result: " + sttyResult);
|
|
80
|
+
if (sttyResult != 0) {
|
|
81
|
+
Log.w(TAG, "stty configuration failed, trying alternative method");
|
|
82
|
+
|
|
83
|
+
// Try alternative configuration without su
|
|
84
|
+
String altCommand = String.format("stty -F %s %d raw -echo", portPath, baudRate);
|
|
85
|
+
Log.d(TAG, "Trying alternative: " + altCommand);
|
|
86
|
+
Process altProcess = Runtime.getRuntime().exec(altCommand);
|
|
87
|
+
int altResult = altProcess.waitFor();
|
|
88
|
+
Log.d(TAG, "Alternative stty result: " + altResult);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Abrir streams de entrada y salida
|
|
92
|
+
serialInputStream = new FileInputStream(portFile);
|
|
93
|
+
serialOutputStream = new FileOutputStream(portFile);
|
|
94
|
+
|
|
95
|
+
currentPortPath = portPath;
|
|
96
|
+
isConnected = true;
|
|
97
|
+
|
|
98
|
+
// Iniciar hilo de lectura
|
|
99
|
+
startReaderThread();
|
|
100
|
+
|
|
101
|
+
// Verificar que el hilo se inició correctamente
|
|
102
|
+
Thread.sleep(100); // Dar tiempo al hilo de iniciarse
|
|
103
|
+
Log.d(TAG, "Reader thread status: " + (readerThread != null ? "Created" : "NULL"));
|
|
104
|
+
Log.d(TAG, "Reader thread alive: " + (readerThread != null ? readerThread.isAlive() : "N/A"));
|
|
105
|
+
|
|
106
|
+
Log.d(TAG, "Serial port opened successfully");
|
|
107
|
+
notifyConnectionStateChanged(true);
|
|
108
|
+
|
|
109
|
+
return true;
|
|
110
|
+
|
|
111
|
+
} catch (Exception e) {
|
|
112
|
+
Log.e(TAG, "Error opening serial port: " + e.getMessage(), e);
|
|
113
|
+
isConnected = false;
|
|
114
|
+
notifyError("Failed to open port: " + e.getMessage());
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Closes the serial port connection
|
|
121
|
+
*/
|
|
122
|
+
public synchronized void closePort() {
|
|
123
|
+
try {
|
|
124
|
+
Log.d(TAG, "Closing serial port");
|
|
125
|
+
|
|
126
|
+
isConnected = false;
|
|
127
|
+
|
|
128
|
+
// Detener hilo de lectura
|
|
129
|
+
if (readerThread != null && readerThread.isAlive()) {
|
|
130
|
+
readerThread.interrupt();
|
|
131
|
+
try {
|
|
132
|
+
readerThread.join(1000);
|
|
133
|
+
} catch (InterruptedException e) {
|
|
134
|
+
Log.w(TAG, "Reader thread join interrupted");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Cerrar streams
|
|
139
|
+
if (serialInputStream != null) {
|
|
140
|
+
serialInputStream.close();
|
|
141
|
+
serialInputStream = null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (serialOutputStream != null) {
|
|
145
|
+
serialOutputStream.close();
|
|
146
|
+
serialOutputStream = null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
currentPortPath = null;
|
|
150
|
+
|
|
151
|
+
Log.d(TAG, "Serial port closed");
|
|
152
|
+
notifyConnectionStateChanged(false);
|
|
153
|
+
|
|
154
|
+
} catch (Exception e) {
|
|
155
|
+
Log.e(TAG, "Error closing serial port: " + e.getMessage(), e);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Writes data to the serial port with enhanced debugging
|
|
161
|
+
*/
|
|
162
|
+
public boolean writeData(byte[] data) {
|
|
163
|
+
if (!isConnected || serialOutputStream == null) {
|
|
164
|
+
Log.e(TAG, "Cannot write: port not connected");
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
// Enhanced logging with hex dump
|
|
170
|
+
Log.d(TAG, "=== WRITING TO SERIAL PORT ===");
|
|
171
|
+
Log.d(TAG, "Port: " + currentPortPath);
|
|
172
|
+
Log.d(TAG, "Data length: " + data.length + " bytes");
|
|
173
|
+
Log.d(TAG, "HEX data: " + bytesToHex(data));
|
|
174
|
+
Log.d(TAG, "Raw bytes: " + java.util.Arrays.toString(data));
|
|
175
|
+
|
|
176
|
+
// Clear any pending input first
|
|
177
|
+
if (serialInputStream != null && serialInputStream.available() > 0) {
|
|
178
|
+
int available = serialInputStream.available();
|
|
179
|
+
byte[] discarded = new byte[available];
|
|
180
|
+
serialInputStream.read(discarded);
|
|
181
|
+
Log.d(TAG, "Discarded " + available + " pending bytes before write");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
long startTime = System.currentTimeMillis();
|
|
185
|
+
|
|
186
|
+
// Write entire frame at once (IOBoard expects complete frame)
|
|
187
|
+
Log.d(TAG, "Sending complete frame as single write operation...");
|
|
188
|
+
serialOutputStream.write(data);
|
|
189
|
+
serialOutputStream.flush();
|
|
190
|
+
|
|
191
|
+
long endTime = System.currentTimeMillis();
|
|
192
|
+
|
|
193
|
+
Log.i(TAG, "✅ Successfully wrote " + data.length + " bytes in " + (endTime - startTime) + "ms");
|
|
194
|
+
Log.i(TAG, "HEX written: " + bytesToHex(data));
|
|
195
|
+
|
|
196
|
+
// Wait longer for IOBoard response (some devices need more processing time)
|
|
197
|
+
Thread.sleep(200); // Increased from 50ms to 200ms
|
|
198
|
+
|
|
199
|
+
// Check immediately if there's a response available
|
|
200
|
+
if (serialInputStream != null) {
|
|
201
|
+
int available = serialInputStream.available();
|
|
202
|
+
Log.d(TAG, "Checking for response after " + (endTime - startTime) + "ms write + 200ms wait: " + available + " bytes available");
|
|
203
|
+
|
|
204
|
+
if (available > 0) {
|
|
205
|
+
Log.w(TAG, "⚠️ DATA AVAILABLE AFTER WRITE! " + available + " bytes - reader thread should pick this up");
|
|
206
|
+
} else {
|
|
207
|
+
Log.d(TAG, "🔍 No immediate response detected - this is normal for some IOBoard operations");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return true;
|
|
212
|
+
} catch (Exception e) {
|
|
213
|
+
Log.e(TAG, "❌ Error writing to serial port: " + e.getMessage(), e);
|
|
214
|
+
Log.e(TAG, "Failed to write HEX: " + bytesToHex(data));
|
|
215
|
+
notifyError("Write error: " + e.getMessage());
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Helper method to convert bytes to hex string for debugging
|
|
221
|
+
private String bytesToHex(byte[] bytes) {
|
|
222
|
+
StringBuilder hexString = new StringBuilder();
|
|
223
|
+
for (byte b : bytes) {
|
|
224
|
+
String hex = Integer.toHexString(0xFF & b);
|
|
225
|
+
if (hex.length() == 1) {
|
|
226
|
+
hexString.append('0');
|
|
227
|
+
}
|
|
228
|
+
hexString.append(hex.toUpperCase()).append(" ");
|
|
229
|
+
}
|
|
230
|
+
return hexString.toString().trim();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Helper method to interpret door status codes
|
|
234
|
+
private String interpretDoorStatus(int doorStatus) {
|
|
235
|
+
switch (doorStatus) {
|
|
236
|
+
case 0xFE:
|
|
237
|
+
return "Door Closed/Locked (0xFE)";
|
|
238
|
+
case 0xFF:
|
|
239
|
+
return "Door Open/Unlocked (0xFF)";
|
|
240
|
+
case 0x00:
|
|
241
|
+
return "Door Unknown/Error (0x00)";
|
|
242
|
+
case 0x01:
|
|
243
|
+
return "Door Moving/Processing (0x01)";
|
|
244
|
+
default:
|
|
245
|
+
return String.format("Door Custom Status (0x%02X)", doorStatus);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Checks if the port is connected
|
|
251
|
+
*/
|
|
252
|
+
public boolean isConnected() {
|
|
253
|
+
return isConnected;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Gets the current port path
|
|
258
|
+
*/
|
|
259
|
+
public String getCurrentPortPath() {
|
|
260
|
+
return currentPortPath;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Lists available serial ports
|
|
265
|
+
*/
|
|
266
|
+
public List<String> listAvailablePorts() {
|
|
267
|
+
List<String> ports = new ArrayList<>();
|
|
268
|
+
|
|
269
|
+
// Paths comunes para puertos seriales en Android
|
|
270
|
+
String[] commonPaths = {
|
|
271
|
+
"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3", "/dev/ttyS4",
|
|
272
|
+
"/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2", "/dev/ttyUSB3",
|
|
273
|
+
"/dev/ttyACM0", "/dev/ttyACM1", "/dev/ttyACM2", "/dev/ttyACM3",
|
|
274
|
+
"/dev/ttymxc0", "/dev/ttymxc1", "/dev/ttymxc2", "/dev/ttymxc3"
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
for (String path : commonPaths) {
|
|
278
|
+
File portFile = new File(path);
|
|
279
|
+
if (portFile.exists()) {
|
|
280
|
+
Log.d(TAG, "Found serial port: " + path);
|
|
281
|
+
ports.add(path);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
Log.d(TAG, "Found " + ports.size() + " available serial ports");
|
|
286
|
+
return ports;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private void startReaderThread() {
|
|
290
|
+
Log.d(TAG, "🚀 STARTING READER THREAD...");
|
|
291
|
+
|
|
292
|
+
// Stop any existing reader thread first
|
|
293
|
+
if (readerThread != null && readerThread.isAlive()) {
|
|
294
|
+
Log.d(TAG, "Stopping existing reader thread");
|
|
295
|
+
readerThread.interrupt();
|
|
296
|
+
try {
|
|
297
|
+
readerThread.join(1000);
|
|
298
|
+
} catch (InterruptedException e) {
|
|
299
|
+
Log.w(TAG, "Interrupted while stopping reader thread");
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
readerThread = new Thread(() -> {
|
|
304
|
+
Log.d(TAG, "📡 Serial reader thread started for port: " + currentPortPath);
|
|
305
|
+
Log.d(TAG, "Reader thread ID: " + Thread.currentThread().getId());
|
|
306
|
+
Log.d(TAG, "Input stream available: " + (serialInputStream != null));
|
|
307
|
+
|
|
308
|
+
byte[] buffer = new byte[1024];
|
|
309
|
+
|
|
310
|
+
while (isConnected && !Thread.currentThread().isInterrupted()) {
|
|
311
|
+
try {
|
|
312
|
+
if (serialInputStream != null) {
|
|
313
|
+
// Check if data is available
|
|
314
|
+
int available = serialInputStream.available();
|
|
315
|
+
if (available > 0) {
|
|
316
|
+
Log.d(TAG, "📨 Data available: " + available + " bytes");
|
|
317
|
+
|
|
318
|
+
int bytesRead = serialInputStream.read(buffer, 0, Math.min(available, buffer.length));
|
|
319
|
+
if (bytesRead > 0) {
|
|
320
|
+
byte[] data = new byte[bytesRead];
|
|
321
|
+
System.arraycopy(buffer, 0, data, 0, bytesRead);
|
|
322
|
+
|
|
323
|
+
// Enhanced logging for received data
|
|
324
|
+
Log.d(TAG, "=== 📥 RECEIVED FROM IOBOARD ===");
|
|
325
|
+
Log.d(TAG, "Port: " + currentPortPath);
|
|
326
|
+
Log.d(TAG, "Received " + bytesRead + " bytes");
|
|
327
|
+
Log.d(TAG, "HEX received: " + bytesToHex(data));
|
|
328
|
+
Log.d(TAG, "Raw bytes: " + java.util.Arrays.toString(data));
|
|
329
|
+
|
|
330
|
+
// Parser automático de respuesta del IOBoard
|
|
331
|
+
try {
|
|
332
|
+
CapacitorIoboardPlugin.IOBoardResponse response = CapacitorIoboardPlugin.parseIOBoardResponse(data);
|
|
333
|
+
if (response.isValid) {
|
|
334
|
+
Log.i(TAG, String.format("🎯 IOBoard Response Parsed Successfully: %s", response.toString()));
|
|
335
|
+
|
|
336
|
+
// Logging específico según tipo de respuesta
|
|
337
|
+
if (response.type == 0x00) { // Status Response
|
|
338
|
+
Log.i(TAG, String.format("📊 IOBoard Status - Firmware: %s, Door Status: 0x%02X",
|
|
339
|
+
response.firmware, response.doorStatus));
|
|
340
|
+
|
|
341
|
+
// Interpretar door status
|
|
342
|
+
String doorStatusDesc = interpretDoorStatus(response.doorStatus);
|
|
343
|
+
Log.i(TAG, String.format("🚪 Door Status: %s", doorStatusDesc));
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
Log.w(TAG, "⚠️ Received invalid IOBoard response - trying ASCII interpretation");
|
|
347
|
+
|
|
348
|
+
// Try to interpret as ASCII if printable
|
|
349
|
+
String ascii = new String(data);
|
|
350
|
+
boolean isPrintable = ascii.chars().allMatch(c -> c >= 32 && c <= 126);
|
|
351
|
+
if (isPrintable) {
|
|
352
|
+
Log.d(TAG, "ASCII: '" + ascii + "'");
|
|
353
|
+
} else {
|
|
354
|
+
Log.d(TAG, "Binary data (non-ASCII)");
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} catch (Exception e) {
|
|
358
|
+
Log.e(TAG, "❌ Error parsing IOBoard response: " + e.getMessage(), e);
|
|
359
|
+
|
|
360
|
+
// Fallback: Try to interpret as ASCII if printable
|
|
361
|
+
String ascii = new String(data);
|
|
362
|
+
boolean isPrintable = ascii.chars().allMatch(c -> c >= 32 && c <= 126);
|
|
363
|
+
if (isPrintable) {
|
|
364
|
+
Log.d(TAG, "ASCII fallback: '" + ascii + "'");
|
|
365
|
+
} else {
|
|
366
|
+
Log.d(TAG, "Binary data fallback (non-ASCII)");
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
Log.d(TAG, "=== END RECEIVED DATA ===");
|
|
371
|
+
|
|
372
|
+
notifyDataReceived(data);
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
// No data available, small sleep to prevent busy waiting
|
|
376
|
+
Thread.sleep(50); // Increased from 10ms to 50ms
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
Log.w(TAG, "Serial input stream is null");
|
|
380
|
+
Thread.sleep(100);
|
|
381
|
+
}
|
|
382
|
+
} catch (InterruptedException e) {
|
|
383
|
+
Log.d(TAG, "📡 Reader thread interrupted");
|
|
384
|
+
break;
|
|
385
|
+
} catch (Exception e) {
|
|
386
|
+
Log.e(TAG, "❌ Error reading from serial port: " + e.getMessage(), e);
|
|
387
|
+
notifyError("Read error: " + e.getMessage());
|
|
388
|
+
|
|
389
|
+
// Small delay before retrying
|
|
390
|
+
try {
|
|
391
|
+
Thread.sleep(1000);
|
|
392
|
+
} catch (InterruptedException ie) {
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
Log.d(TAG, "📡 Serial reader thread stopped");
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
readerThread.setName("SerialReader-" + currentPortPath);
|
|
402
|
+
Log.d(TAG, "🎬 Starting reader thread...");
|
|
403
|
+
readerThread.start();
|
|
404
|
+
Log.d(TAG, "✅ Reader thread started successfully");
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
private String getParityFlag(String parity) {
|
|
408
|
+
switch (parity.toLowerCase()) {
|
|
409
|
+
case "even":
|
|
410
|
+
return "parenb -parodd";
|
|
411
|
+
case "odd":
|
|
412
|
+
return "parenb parodd";
|
|
413
|
+
case "none":
|
|
414
|
+
default:
|
|
415
|
+
return "-parenb";
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
private void notifyDataReceived(byte[] data) {
|
|
420
|
+
if (listener != null) {
|
|
421
|
+
Log.d(TAG, "Notifying listener of received data: " + bytesToHex(data));
|
|
422
|
+
mainHandler.post(() -> listener.onDataReceived(data));
|
|
423
|
+
} else {
|
|
424
|
+
Log.w(TAG, "No listener set for received data: " + bytesToHex(data));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private void notifyConnectionStateChanged(boolean connected) {
|
|
429
|
+
if (listener != null) {
|
|
430
|
+
mainHandler.post(() -> listener.onConnectionStateChanged(connected));
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private void notifyError(String error) {
|
|
435
|
+
if (listener != null) {
|
|
436
|
+
mainHandler.post(() -> listener.onError(error));
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
public void cleanup() {
|
|
441
|
+
closePort();
|
|
442
|
+
if (executorService != null) {
|
|
443
|
+
executorService.shutdown();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
export interface CapacitorIoboardPlugin {
|
|
2
|
+
/**
|
|
3
|
+
* Connect to IOBoard device via serial port
|
|
4
|
+
* @param options Serial connection parameters
|
|
5
|
+
*/
|
|
6
|
+
connect(options: SerialConnectionOptions): Promise<ConnectionResponse>;
|
|
7
|
+
/**
|
|
8
|
+
* Disconnect from IOBoard device
|
|
9
|
+
*/
|
|
10
|
+
disconnect(): Promise<BasicResponse>;
|
|
11
|
+
/**
|
|
12
|
+
* Check if connected to IOBoard device
|
|
13
|
+
*/
|
|
14
|
+
isConnected(): Promise<ConnectionStatusResponse>;
|
|
15
|
+
/**
|
|
16
|
+
* List available serial ports
|
|
17
|
+
*/
|
|
18
|
+
listPorts(): Promise<PortListResponse>;
|
|
19
|
+
/**
|
|
20
|
+
* Get status from IOBoard device
|
|
21
|
+
* @param options Device address
|
|
22
|
+
*/
|
|
23
|
+
getStatus(options: DeviceAddressOptions): Promise<StatusResponse>;
|
|
24
|
+
/**
|
|
25
|
+
* Unlock a specific pallet with RGB LED control
|
|
26
|
+
* @param options Pallet unlock parameters with RGB settings
|
|
27
|
+
*/
|
|
28
|
+
unlockPallet(options: UnlockPalletOptions): Promise<BasicResponse>;
|
|
29
|
+
/**
|
|
30
|
+
* Control multiple LEDs simultaneously
|
|
31
|
+
* @param options Multiple LED control parameters
|
|
32
|
+
*/
|
|
33
|
+
controlMultiple(options: MultipleControlOptions): Promise<BasicResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Start OTA firmware update
|
|
36
|
+
* @param options OTA initialization parameters
|
|
37
|
+
*/
|
|
38
|
+
startOTAUpdate(options: OTAStartOptions): Promise<BasicResponse>;
|
|
39
|
+
/**
|
|
40
|
+
* Send OTA data packet
|
|
41
|
+
* @param options OTA data packet parameters
|
|
42
|
+
*/
|
|
43
|
+
sendOTAData(options: OTADataOptions): Promise<BasicResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* Add listener for data received events
|
|
46
|
+
*/
|
|
47
|
+
addListener(eventName: 'dataReceived', listenerFunc: (event: DataReceivedEvent) => void): Promise<PluginListenerHandle>;
|
|
48
|
+
/**
|
|
49
|
+
* Add listener for connection state changes
|
|
50
|
+
*/
|
|
51
|
+
addListener(eventName: 'connectionStateChanged', listenerFunc: (event: ConnectionStateEvent) => void): Promise<PluginListenerHandle>;
|
|
52
|
+
/**
|
|
53
|
+
* Add listener for serial errors
|
|
54
|
+
*/
|
|
55
|
+
addListener(eventName: 'serialError', listenerFunc: (event: ErrorEvent) => void): Promise<PluginListenerHandle>;
|
|
56
|
+
/**
|
|
57
|
+
* Remove all listeners for this plugin
|
|
58
|
+
*/
|
|
59
|
+
removeAllListeners(): Promise<void>;
|
|
60
|
+
}
|
|
61
|
+
export interface SerialConnectionOptions {
|
|
62
|
+
/** Serial port path (e.g., '/dev/ttyS2') */
|
|
63
|
+
portPath: string;
|
|
64
|
+
/** Baud rate (default: 115200) */
|
|
65
|
+
baudRate?: number;
|
|
66
|
+
/** Data bits (default: 8) */
|
|
67
|
+
dataBits?: number;
|
|
68
|
+
/** Stop bits (default: 1) */
|
|
69
|
+
stopBits?: number;
|
|
70
|
+
/** Parity (default: 'none') */
|
|
71
|
+
parity?: 'none' | 'even' | 'odd';
|
|
72
|
+
}
|
|
73
|
+
export interface DeviceAddressOptions {
|
|
74
|
+
/** IOBoard device address (1-255) */
|
|
75
|
+
address: number;
|
|
76
|
+
}
|
|
77
|
+
export interface UnlockPalletOptions {
|
|
78
|
+
/** IOBoard device address */
|
|
79
|
+
address: number;
|
|
80
|
+
/** Pallet number (0-7) */
|
|
81
|
+
palletNumber: number;
|
|
82
|
+
/** RGB Red value (0-255) */
|
|
83
|
+
red?: number;
|
|
84
|
+
/** RGB Green value (0-255) */
|
|
85
|
+
green?: number;
|
|
86
|
+
/** RGB Blue value (0-255) */
|
|
87
|
+
blue?: number;
|
|
88
|
+
/** LED intensity (0-100) */
|
|
89
|
+
intensity?: number;
|
|
90
|
+
/** Number of blinks (0-255) */
|
|
91
|
+
blinkTimes?: number;
|
|
92
|
+
/** Blink speed (1-30) */
|
|
93
|
+
blinkSpeed?: number;
|
|
94
|
+
}
|
|
95
|
+
export interface LEDConfiguration {
|
|
96
|
+
/** RGB Red value (0-255) */
|
|
97
|
+
red: number;
|
|
98
|
+
/** RGB Green value (0-255) */
|
|
99
|
+
green: number;
|
|
100
|
+
/** RGB Blue value (0-255) */
|
|
101
|
+
blue: number;
|
|
102
|
+
/** LED intensity (0-100) */
|
|
103
|
+
intensity: number;
|
|
104
|
+
/** Number of blinks (0-255) */
|
|
105
|
+
blinkTimes: number;
|
|
106
|
+
/** Blink speed (1-30) */
|
|
107
|
+
blinkSpeed: number;
|
|
108
|
+
}
|
|
109
|
+
export interface MultipleControlOptions {
|
|
110
|
+
/** IOBoard device address */
|
|
111
|
+
address: number;
|
|
112
|
+
/** Array of LED configurations for 8 pallets */
|
|
113
|
+
leds: LEDConfiguration[];
|
|
114
|
+
}
|
|
115
|
+
export interface OTAStartOptions {
|
|
116
|
+
/** IOBoard device address */
|
|
117
|
+
address: number;
|
|
118
|
+
/** Firmware file name */
|
|
119
|
+
fileName: string;
|
|
120
|
+
/** File size in bytes */
|
|
121
|
+
fileSize: number;
|
|
122
|
+
/** Total number of packets */
|
|
123
|
+
totalPackets: number;
|
|
124
|
+
}
|
|
125
|
+
export interface OTADataOptions {
|
|
126
|
+
/** IOBoard device address */
|
|
127
|
+
address: number;
|
|
128
|
+
/** Packet number */
|
|
129
|
+
packetNumber: number;
|
|
130
|
+
/** Data payload (128 bytes) */
|
|
131
|
+
data: number[];
|
|
132
|
+
}
|
|
133
|
+
export interface BasicResponse {
|
|
134
|
+
/** Operation success flag */
|
|
135
|
+
success: boolean;
|
|
136
|
+
/** Error message if failed */
|
|
137
|
+
error?: string;
|
|
138
|
+
/** Additional message */
|
|
139
|
+
message?: string;
|
|
140
|
+
}
|
|
141
|
+
export interface ConnectionResponse extends BasicResponse {
|
|
142
|
+
/** Connected port path */
|
|
143
|
+
portPath?: string;
|
|
144
|
+
/** Baud rate used */
|
|
145
|
+
baudRate?: number;
|
|
146
|
+
}
|
|
147
|
+
export interface ConnectionStatusResponse {
|
|
148
|
+
/** Connection status */
|
|
149
|
+
connected: boolean;
|
|
150
|
+
/** Current port path if connected */
|
|
151
|
+
portPath?: string;
|
|
152
|
+
}
|
|
153
|
+
export interface PortListResponse {
|
|
154
|
+
/** Available serial ports */
|
|
155
|
+
ports: string[];
|
|
156
|
+
/** Number of ports found */
|
|
157
|
+
count: number;
|
|
158
|
+
}
|
|
159
|
+
export interface StatusResponse extends BasicResponse {
|
|
160
|
+
/** Device address */
|
|
161
|
+
address?: number;
|
|
162
|
+
/** Device status information */
|
|
163
|
+
status?: DeviceStatus;
|
|
164
|
+
/** Frame type received */
|
|
165
|
+
frameType?: number;
|
|
166
|
+
/** Raw response data */
|
|
167
|
+
rawData?: number[];
|
|
168
|
+
}
|
|
169
|
+
export interface DeviceStatus {
|
|
170
|
+
/** Device online status */
|
|
171
|
+
online: boolean;
|
|
172
|
+
/** Firmware version */
|
|
173
|
+
firmwareVersion?: string;
|
|
174
|
+
/** Pallet states */
|
|
175
|
+
pallets?: PalletStatus[];
|
|
176
|
+
/** Device temperature */
|
|
177
|
+
temperature?: number;
|
|
178
|
+
/** Power status */
|
|
179
|
+
powerStatus?: string;
|
|
180
|
+
}
|
|
181
|
+
export interface PalletStatus {
|
|
182
|
+
/** Pallet number */
|
|
183
|
+
number: number;
|
|
184
|
+
/** Pallet locked/unlocked state */
|
|
185
|
+
locked: boolean;
|
|
186
|
+
/** Current LED RGB values */
|
|
187
|
+
led?: {
|
|
188
|
+
red: number;
|
|
189
|
+
green: number;
|
|
190
|
+
blue: number;
|
|
191
|
+
intensity: number;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
export interface DataReceivedEvent {
|
|
195
|
+
/** Parsed response data */
|
|
196
|
+
data: any;
|
|
197
|
+
/** Raw bytes as string */
|
|
198
|
+
rawBytes: string;
|
|
199
|
+
}
|
|
200
|
+
export interface ConnectionStateEvent {
|
|
201
|
+
/** Connection status */
|
|
202
|
+
connected: boolean;
|
|
203
|
+
/** Port path */
|
|
204
|
+
portPath?: string;
|
|
205
|
+
}
|
|
206
|
+
export interface ErrorEvent {
|
|
207
|
+
/** Error message */
|
|
208
|
+
error: string;
|
|
209
|
+
}
|
|
210
|
+
export interface PluginListenerHandle {
|
|
211
|
+
remove(): Promise<void>;
|
|
212
|
+
}
|
|
213
|
+
export interface RGBColor {
|
|
214
|
+
red: number;
|
|
215
|
+
green: number;
|
|
216
|
+
blue: number;
|
|
217
|
+
}
|
|
218
|
+
export interface ColorPresets {
|
|
219
|
+
RED: RGBColor;
|
|
220
|
+
GREEN: RGBColor;
|
|
221
|
+
BLUE: RGBColor;
|
|
222
|
+
WHITE: RGBColor;
|
|
223
|
+
YELLOW: RGBColor;
|
|
224
|
+
PURPLE: RGBColor;
|
|
225
|
+
CYAN: RGBColor;
|
|
226
|
+
OFF: RGBColor;
|
|
227
|
+
}
|
|
228
|
+
export declare const COLOR_PRESETS: ColorPresets;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Predefined color constants
|
|
2
|
+
export const COLOR_PRESETS = {
|
|
3
|
+
RED: { red: 255, green: 0, blue: 0 },
|
|
4
|
+
GREEN: { red: 0, green: 255, blue: 0 },
|
|
5
|
+
BLUE: { red: 0, green: 0, blue: 255 },
|
|
6
|
+
WHITE: { red: 255, green: 255, blue: 255 },
|
|
7
|
+
YELLOW: { red: 255, green: 255, blue: 0 },
|
|
8
|
+
PURPLE: { red: 255, green: 0, blue: 255 },
|
|
9
|
+
CYAN: { red: 0, green: 255, blue: 255 },
|
|
10
|
+
OFF: { red: 0, green: 0, blue: 0 }
|
|
11
|
+
};
|