@leonardojc/capacitor-ioboard 1.1.0 → 1.2.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.
|
@@ -3,26 +3,21 @@ package com.leonardojc.capacitor.ioboard;
|
|
|
3
3
|
import android.util.Log;
|
|
4
4
|
import android.util.Base64;
|
|
5
5
|
import java.util.Arrays;
|
|
6
|
+
import java.util.ArrayList;
|
|
7
|
+
import java.util.List;
|
|
6
8
|
import java.util.concurrent.TimeUnit;
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Manager class for IOBOARD communication protocol
|
|
10
12
|
* This class integrates with the @leonardojc/capacitor-serial-port plugin
|
|
13
|
+
* Uses IOBoardProtocolUtils for MTC3P08L protocol implementation
|
|
11
14
|
*/
|
|
12
15
|
public class IOBoardManager {
|
|
13
16
|
|
|
14
17
|
private static final String TAG = "IOBoardManager";
|
|
15
|
-
private static final int SOI = 0x0D; // Start of frame
|
|
16
|
-
private static final int EOI = 0x0A; // End of frame
|
|
17
|
-
|
|
18
|
-
// Frame types
|
|
19
|
-
private static final int FRAME_TYPE_STATUS_QUERY = 0x00;
|
|
20
|
-
private static final int FRAME_TYPE_SINGLE_PALLET = 0x01;
|
|
21
|
-
private static final int FRAME_TYPE_FULL_PALLET = 0x02;
|
|
22
|
-
private static final int FRAME_TYPE_OTA_REQUEST = 0xF1;
|
|
23
|
-
private static final int FRAME_TYPE_OTA_DATA = 0xF2;
|
|
24
18
|
|
|
25
19
|
private boolean isConnected = false;
|
|
20
|
+
private String currentSerialPortId = null;
|
|
26
21
|
|
|
27
22
|
// Response classes
|
|
28
23
|
public static class IOBoardResponse {
|
|
@@ -127,89 +122,18 @@ public class IOBoardManager {
|
|
|
127
122
|
}
|
|
128
123
|
|
|
129
124
|
/**
|
|
130
|
-
*
|
|
131
|
-
*/
|
|
132
|
-
private int calculateCRC16(int[] data) {
|
|
133
|
-
int crc = 0xFFFF;
|
|
134
|
-
|
|
135
|
-
for (int dataByte : data) {
|
|
136
|
-
crc ^= (dataByte << 8);
|
|
137
|
-
|
|
138
|
-
for (int bit = 0; bit < 8; bit++) {
|
|
139
|
-
if ((crc & 0x8000) != 0) {
|
|
140
|
-
crc = (crc << 1) ^ 0x1021;
|
|
141
|
-
} else {
|
|
142
|
-
crc = crc << 1;
|
|
143
|
-
}
|
|
144
|
-
crc &= 0xFFFF;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return crc;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Build a command frame for IOBOARD
|
|
153
|
-
*/
|
|
154
|
-
private int[] buildFrame(int address, int frameType, int[] data) {
|
|
155
|
-
// Calculate frame size: SOI + Address + FrameType + Data + CRC(2) + EOI
|
|
156
|
-
int frameSize = 1 + 1 + 1 + data.length + 2 + 1;
|
|
157
|
-
int[] frame = new int[frameSize];
|
|
158
|
-
int index = 0;
|
|
159
|
-
|
|
160
|
-
// SOI
|
|
161
|
-
frame[index++] = SOI;
|
|
162
|
-
|
|
163
|
-
// Address
|
|
164
|
-
frame[index++] = address;
|
|
165
|
-
|
|
166
|
-
// Frame Type
|
|
167
|
-
frame[index++] = frameType;
|
|
168
|
-
|
|
169
|
-
// Data
|
|
170
|
-
for (int dataByte : data) {
|
|
171
|
-
frame[index++] = dataByte;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Calculate CRC for address + frameType + data
|
|
175
|
-
int[] crcData = new int[1 + 1 + data.length];
|
|
176
|
-
crcData[0] = address;
|
|
177
|
-
crcData[1] = frameType;
|
|
178
|
-
System.arraycopy(data, 0, crcData, 2, data.length);
|
|
179
|
-
|
|
180
|
-
int crc = calculateCRC16(crcData);
|
|
181
|
-
|
|
182
|
-
// CRC (high byte first)
|
|
183
|
-
frame[index++] = (crc >> 8) & 0xFF;
|
|
184
|
-
frame[index++] = crc & 0xFF;
|
|
185
|
-
|
|
186
|
-
// EOI
|
|
187
|
-
frame[index] = EOI;
|
|
188
|
-
|
|
189
|
-
return frame;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Convert frame to byte array for serial transmission
|
|
194
|
-
*/
|
|
195
|
-
private byte[] frameToBytes(int[] frame) {
|
|
196
|
-
byte[] bytes = new byte[frame.length];
|
|
197
|
-
for (int i = 0; i < frame.length; i++) {
|
|
198
|
-
bytes[i] = (byte) (frame[i] & 0xFF);
|
|
199
|
-
}
|
|
200
|
-
return bytes;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Convert frame to hex string for debugging
|
|
125
|
+
* Send command via SerialPort plugin and wait for response
|
|
205
126
|
*/
|
|
206
|
-
private String
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
127
|
+
private String sendCommandAndWaitResponse(byte[] command, int timeoutMs) throws Exception {
|
|
128
|
+
// TODO: Integrate with @leonardojc/capacitor-serial-port plugin
|
|
129
|
+
// This method should:
|
|
130
|
+
// 1. Convert command to appropriate format for SerialPort plugin
|
|
131
|
+
// 2. Call SerialPort.writeData(portId, data)
|
|
132
|
+
// 3. Wait for response using SerialPort.readData() or data listeners
|
|
133
|
+
// 4. Return response string
|
|
134
|
+
|
|
135
|
+
// For now, return mock response for testing
|
|
136
|
+
throw new Exception("SerialPort integration not yet implemented");
|
|
213
137
|
}
|
|
214
138
|
|
|
215
139
|
// New simplified API methods
|
|
@@ -221,9 +145,13 @@ public class IOBoardManager {
|
|
|
221
145
|
Log.d(TAG, "Connecting to serial port: " + config.portPath + " at " + config.baudRate + " baud");
|
|
222
146
|
|
|
223
147
|
try {
|
|
224
|
-
// TODO: Initialize connection with
|
|
148
|
+
// TODO: Initialize connection with SerialPort plugin
|
|
149
|
+
// Call SerialPort.openConnection() with config parameters
|
|
150
|
+
// Store the returned port ID for future operations
|
|
151
|
+
|
|
225
152
|
// For now, just set the connected flag
|
|
226
153
|
isConnected = true;
|
|
154
|
+
currentSerialPortId = "mock_port_id";
|
|
227
155
|
|
|
228
156
|
return new IOBoardResponse(true, "Connected to " + config.portPath + " successfully");
|
|
229
157
|
|
|
@@ -240,8 +168,11 @@ public class IOBoardManager {
|
|
|
240
168
|
Log.d(TAG, "Disconnecting from serial port");
|
|
241
169
|
|
|
242
170
|
try {
|
|
243
|
-
// TODO: Close connection with
|
|
171
|
+
// TODO: Close connection with SerialPort plugin
|
|
172
|
+
// Call SerialPort.closeConnection(currentSerialPortId)
|
|
173
|
+
|
|
244
174
|
isConnected = false;
|
|
175
|
+
currentSerialPortId = null;
|
|
245
176
|
|
|
246
177
|
return new IOBoardResponse(true, "Disconnected successfully");
|
|
247
178
|
|
|
@@ -262,15 +193,33 @@ public class IOBoardManager {
|
|
|
262
193
|
}
|
|
263
194
|
|
|
264
195
|
try {
|
|
265
|
-
// Build status query frame
|
|
266
|
-
|
|
196
|
+
// Build status query frame using IOBoardProtocolUtils
|
|
197
|
+
byte[] frame = IOBoardProtocolUtils.createStatusQuery((byte) address);
|
|
198
|
+
|
|
199
|
+
Log.d(TAG, "Sending status query frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
267
200
|
|
|
268
|
-
|
|
201
|
+
// Send frame and wait for response
|
|
202
|
+
String response = sendCommandAndWaitResponse(frame, timeout);
|
|
269
203
|
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
204
|
+
// Parse response
|
|
205
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
206
|
+
|
|
207
|
+
if (!parsedResponse.success) {
|
|
208
|
+
return new StatusResponse(false, "Failed to parse response: " + parsedResponse.message, null);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Extract status data from response
|
|
212
|
+
if (parsedResponse.data.length >= 4) {
|
|
213
|
+
int doorLockStatus = parsedResponse.data[0] & 0xFF;
|
|
214
|
+
int majorVersion = parsedResponse.data[1] & 0xFF;
|
|
215
|
+
int minorVersion = parsedResponse.data[2] & 0xFF;
|
|
216
|
+
int patchVersion = parsedResponse.data[3] & 0xFF;
|
|
217
|
+
|
|
218
|
+
StatusData statusData = new StatusData(doorLockStatus, new SoftwareVersion(majorVersion, minorVersion, patchVersion));
|
|
219
|
+
return new StatusResponse(true, "Status retrieved successfully", statusData);
|
|
220
|
+
} else {
|
|
221
|
+
return new StatusResponse(false, "Invalid response data length", null);
|
|
222
|
+
}
|
|
274
223
|
|
|
275
224
|
} catch (Exception e) {
|
|
276
225
|
Log.e(TAG, "Error getting status", e);
|
|
@@ -292,22 +241,25 @@ public class IOBoardManager {
|
|
|
292
241
|
// Convert LED color to RGB values
|
|
293
242
|
LEDControl ledControl = getLEDControlFromColor(ledColor);
|
|
294
243
|
|
|
295
|
-
// Build
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
data[6] = ledControl.blinkTimes;
|
|
304
|
-
data[7] = ledControl.blinkSpeed;
|
|
244
|
+
// Build single pallet control frame using IOBoardProtocolUtils
|
|
245
|
+
byte[] frame = IOBoardProtocolUtils.createSinglePalletControl(
|
|
246
|
+
(byte) address, palletNumber, true,
|
|
247
|
+
ledControl.red, ledControl.green, ledControl.blue,
|
|
248
|
+
ledControl.intensity, ledControl.blinkTimes, ledControl.blinkSpeed
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
Log.d(TAG, "Sending unlock pallet frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
305
252
|
|
|
306
|
-
|
|
253
|
+
// Send frame and wait for response
|
|
254
|
+
String response = sendCommandAndWaitResponse(frame, timeout);
|
|
307
255
|
|
|
308
|
-
|
|
256
|
+
// Parse response
|
|
257
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
258
|
+
|
|
259
|
+
if (!parsedResponse.success) {
|
|
260
|
+
return new IOBoardResponse(false, "Failed to parse response: " + parsedResponse.message);
|
|
261
|
+
}
|
|
309
262
|
|
|
310
|
-
// TODO: Send frame via serial port plugin and receive response
|
|
311
263
|
return new IOBoardResponse(true, "Pallet " + palletNumber + " unlocked successfully");
|
|
312
264
|
|
|
313
265
|
} catch (Exception e) {
|
|
@@ -330,30 +282,35 @@ public class IOBoardManager {
|
|
|
330
282
|
// Convert LED color to RGB values
|
|
331
283
|
LEDControl ledControl = getLEDControlFromColor(ledColor);
|
|
332
284
|
|
|
333
|
-
// Build
|
|
334
|
-
int[]
|
|
335
|
-
int index = 0;
|
|
336
|
-
|
|
337
|
-
data[index++] = doorLockMask;
|
|
338
|
-
data[index++] = 0; // extendedControl
|
|
339
|
-
|
|
340
|
-
// Add LED controls for 8 pallets
|
|
285
|
+
// Build LED controls array for 8 pallets
|
|
286
|
+
int[][] ledControls = new int[8][6];
|
|
341
287
|
for (int i = 0; i < 8; i++) {
|
|
342
288
|
// If pallet is affected by mask, use specified LED color, otherwise turn off
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
data[index++] = led.blinkSpeed;
|
|
289
|
+
if ((doorLockMask & (1 << i)) != 0) {
|
|
290
|
+
ledControls[i] = new int[]{ledControl.red, ledControl.green, ledControl.blue,
|
|
291
|
+
ledControl.intensity, ledControl.blinkTimes, ledControl.blinkSpeed};
|
|
292
|
+
} else {
|
|
293
|
+
ledControls[i] = new int[]{0, 0, 0, 0, 0, 1}; // Off
|
|
294
|
+
}
|
|
350
295
|
}
|
|
351
296
|
|
|
352
|
-
|
|
297
|
+
// Build full pallet control frame using IOBoardProtocolUtils
|
|
298
|
+
byte[] frame = IOBoardProtocolUtils.createFullPalletControl(
|
|
299
|
+
(byte) address, doorLockMask, 0, ledControls
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
Log.d(TAG, "Sending multiple pallets control frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
303
|
+
|
|
304
|
+
// Send frame and wait for response
|
|
305
|
+
String response = sendCommandAndWaitResponse(frame, timeout);
|
|
353
306
|
|
|
354
|
-
|
|
307
|
+
// Parse response
|
|
308
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
309
|
+
|
|
310
|
+
if (!parsedResponse.success) {
|
|
311
|
+
return new IOBoardResponse(false, "Failed to parse response: " + parsedResponse.message);
|
|
312
|
+
}
|
|
355
313
|
|
|
356
|
-
// TODO: Send frame via serial port plugin and receive response
|
|
357
314
|
return new IOBoardResponse(true, "Multiple pallets controlled successfully");
|
|
358
315
|
|
|
359
316
|
} catch (Exception e) {
|
|
@@ -374,17 +331,52 @@ public class IOBoardManager {
|
|
|
374
331
|
|
|
375
332
|
try {
|
|
376
333
|
int deviceCount = endAddress - startAddress + 1;
|
|
377
|
-
DeviceInfo
|
|
334
|
+
List<DeviceInfo> deviceList = new ArrayList<>();
|
|
378
335
|
|
|
379
|
-
//
|
|
380
|
-
// For now, create mock responses
|
|
336
|
+
// Scan each address by sending status queries
|
|
381
337
|
for (int i = 0; i < deviceCount; i++) {
|
|
382
338
|
int address = startAddress + i;
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
339
|
+
|
|
340
|
+
try {
|
|
341
|
+
// Build status query frame using IOBoardProtocolUtils
|
|
342
|
+
byte[] frame = IOBoardProtocolUtils.createStatusQuery((byte) address);
|
|
343
|
+
|
|
344
|
+
Log.d(TAG, "Scanning address " + address + ": " + IOBoardProtocolUtils.frameToHex(frame));
|
|
345
|
+
|
|
346
|
+
// Send frame and wait for response (with shorter timeout for scanning)
|
|
347
|
+
String response = sendCommandAndWaitResponse(frame, Math.min(timeout, 1000));
|
|
348
|
+
|
|
349
|
+
// Parse response
|
|
350
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
351
|
+
|
|
352
|
+
if (parsedResponse.success) {
|
|
353
|
+
// Device responded - extract status data
|
|
354
|
+
StatusData status = null;
|
|
355
|
+
if (parsedResponse.data.length >= 4) {
|
|
356
|
+
int doorLockStatus = parsedResponse.data[0] & 0xFF;
|
|
357
|
+
int majorVersion = parsedResponse.data[1] & 0xFF;
|
|
358
|
+
int minorVersion = parsedResponse.data[2] & 0xFF;
|
|
359
|
+
int patchVersion = parsedResponse.data[3] & 0xFF;
|
|
360
|
+
|
|
361
|
+
status = new StatusData(doorLockStatus, new SoftwareVersion(majorVersion, minorVersion, patchVersion));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
deviceList.add(new DeviceInfo(address, true, status));
|
|
365
|
+
Log.d(TAG, "Device found at address " + address);
|
|
366
|
+
} else {
|
|
367
|
+
// No response or invalid response
|
|
368
|
+
deviceList.add(new DeviceInfo(address, false, null));
|
|
369
|
+
Log.d(TAG, "No response from address " + address);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
} catch (Exception e) {
|
|
373
|
+
// Device not responding
|
|
374
|
+
deviceList.add(new DeviceInfo(address, false, null));
|
|
375
|
+
Log.d(TAG, "Error scanning address " + address + ": " + e.getMessage());
|
|
376
|
+
}
|
|
386
377
|
}
|
|
387
378
|
|
|
379
|
+
DeviceInfo[] devices = deviceList.toArray(new DeviceInfo[0]);
|
|
388
380
|
return new ScanResponse(true, "Scanned addresses " + startAddress + "-" + endAddress, devices);
|
|
389
381
|
|
|
390
382
|
} catch (Exception e) {
|
|
@@ -446,15 +438,33 @@ public class IOBoardManager {
|
|
|
446
438
|
}
|
|
447
439
|
|
|
448
440
|
try {
|
|
449
|
-
// Build status query frame
|
|
450
|
-
|
|
441
|
+
// Build status query frame using IOBoardProtocolUtils
|
|
442
|
+
byte[] frame = IOBoardProtocolUtils.createStatusQuery((byte) address);
|
|
443
|
+
|
|
444
|
+
Log.d(TAG, "Sending status query frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
445
|
+
|
|
446
|
+
// Send frame and wait for response
|
|
447
|
+
String response = sendCommandAndWaitResponse(frame, 5000);
|
|
451
448
|
|
|
452
|
-
|
|
449
|
+
// Parse response
|
|
450
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
451
|
+
|
|
452
|
+
if (!parsedResponse.success) {
|
|
453
|
+
return new StatusResponse(false, "Failed to parse response: " + parsedResponse.message, null);
|
|
454
|
+
}
|
|
453
455
|
|
|
454
|
-
//
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
// Extract status data from response
|
|
457
|
+
if (parsedResponse.data.length >= 4) {
|
|
458
|
+
int doorLockStatus = parsedResponse.data[0] & 0xFF;
|
|
459
|
+
int majorVersion = parsedResponse.data[1] & 0xFF;
|
|
460
|
+
int minorVersion = parsedResponse.data[2] & 0xFF;
|
|
461
|
+
int patchVersion = parsedResponse.data[3] & 0xFF;
|
|
462
|
+
|
|
463
|
+
StatusData statusData = new StatusData(doorLockStatus, new SoftwareVersion(majorVersion, minorVersion, patchVersion));
|
|
464
|
+
return new StatusResponse(true, "Status queried successfully", statusData);
|
|
465
|
+
} else {
|
|
466
|
+
return new StatusResponse(false, "Invalid response data length", null);
|
|
467
|
+
}
|
|
458
468
|
|
|
459
469
|
} catch (Exception e) {
|
|
460
470
|
Log.e(TAG, "Error querying status", e);
|
|
@@ -473,22 +483,25 @@ public class IOBoardManager {
|
|
|
473
483
|
}
|
|
474
484
|
|
|
475
485
|
try {
|
|
476
|
-
// Build
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
486
|
+
// Build single pallet control frame using IOBoardProtocolUtils
|
|
487
|
+
byte[] frame = IOBoardProtocolUtils.createSinglePalletControl(
|
|
488
|
+
(byte) address, palletNumber, doorLock,
|
|
489
|
+
ledControl.red, ledControl.green, ledControl.blue,
|
|
490
|
+
ledControl.intensity, ledControl.blinkTimes, ledControl.blinkSpeed
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
Log.d(TAG, "Sending single pallet control frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
494
|
+
|
|
495
|
+
// Send frame and wait for response
|
|
496
|
+
String response = sendCommandAndWaitResponse(frame, 5000);
|
|
497
|
+
|
|
498
|
+
// Parse response
|
|
499
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
500
|
+
|
|
501
|
+
if (!parsedResponse.success) {
|
|
502
|
+
return new IOBoardResponse(false, "Failed to parse response: " + parsedResponse.message);
|
|
503
|
+
}
|
|
504
|
+
|
|
492
505
|
return new IOBoardResponse(true, "Single pallet controlled successfully");
|
|
493
506
|
|
|
494
507
|
} catch (Exception e) {
|
|
@@ -508,29 +521,33 @@ public class IOBoardManager {
|
|
|
508
521
|
}
|
|
509
522
|
|
|
510
523
|
try {
|
|
511
|
-
//
|
|
512
|
-
int[]
|
|
513
|
-
int index = 0;
|
|
514
|
-
|
|
515
|
-
data[index++] = doorLockControl;
|
|
516
|
-
data[index++] = extendedControl;
|
|
517
|
-
|
|
518
|
-
// Add LED controls for 8 pallets
|
|
524
|
+
// Convert LEDControl array to int[][] for IOBoardProtocolUtils
|
|
525
|
+
int[][] ledControlsArray = new int[8][6];
|
|
519
526
|
for (int i = 0; i < 8; i++) {
|
|
520
527
|
LEDControl led = (i < ledControls.length) ? ledControls[i] : new LEDControl(0, 0, 0, 0, 0, 0);
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
data[index++] = led.blinkTimes;
|
|
526
|
-
data[index++] = led.blinkSpeed;
|
|
528
|
+
ledControlsArray[i] = new int[]{
|
|
529
|
+
led.red, led.green, led.blue,
|
|
530
|
+
led.intensity, led.blinkTimes, led.blinkSpeed
|
|
531
|
+
};
|
|
527
532
|
}
|
|
528
533
|
|
|
529
|
-
|
|
534
|
+
// Build full pallet control frame using IOBoardProtocolUtils
|
|
535
|
+
byte[] frame = IOBoardProtocolUtils.createFullPalletControl(
|
|
536
|
+
(byte) address, doorLockControl, extendedControl, ledControlsArray
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
Log.d(TAG, "Sending full pallet control frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
530
540
|
|
|
531
|
-
|
|
541
|
+
// Send frame and wait for response
|
|
542
|
+
String response = sendCommandAndWaitResponse(frame, 5000);
|
|
543
|
+
|
|
544
|
+
// Parse response
|
|
545
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
546
|
+
|
|
547
|
+
if (!parsedResponse.success) {
|
|
548
|
+
return new IOBoardResponse(false, "Failed to parse response: " + parsedResponse.message);
|
|
549
|
+
}
|
|
532
550
|
|
|
533
|
-
// TODO: Send frame via serial port plugin and receive response
|
|
534
551
|
return new IOBoardResponse(true, "Full pallet controlled successfully");
|
|
535
552
|
|
|
536
553
|
} catch (Exception e) {
|
|
@@ -550,21 +567,32 @@ public class IOBoardManager {
|
|
|
550
567
|
}
|
|
551
568
|
|
|
552
569
|
try {
|
|
553
|
-
//
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
data[
|
|
557
|
-
data[
|
|
558
|
-
data[
|
|
559
|
-
data[
|
|
560
|
-
data[
|
|
561
|
-
data[
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
570
|
+
// TODO: Add OTA notification method to IOBoardProtocolUtils
|
|
571
|
+
// For now, use manual frame building based on protocol specs
|
|
572
|
+
byte[] data = new byte[8]; // '?' + version(3) + firmware size(4)
|
|
573
|
+
data[0] = 0x3F; // '?' Notification header
|
|
574
|
+
data[1] = (byte) majorVersion;
|
|
575
|
+
data[2] = (byte) minorVersion;
|
|
576
|
+
data[3] = (byte) patchVersion;
|
|
577
|
+
data[4] = (byte) (firmwareSize & 0xFF);
|
|
578
|
+
data[5] = (byte) ((firmwareSize >> 8) & 0xFF);
|
|
579
|
+
data[6] = (byte) ((firmwareSize >> 16) & 0xFF);
|
|
580
|
+
data[7] = (byte) ((firmwareSize >> 24) & 0xFF);
|
|
581
|
+
|
|
582
|
+
byte[] frame = IOBoardProtocolUtils.createFrame((byte) address, IOBoardProtocolUtils.FRAME_TYPE_OTA_REQUEST, data);
|
|
583
|
+
|
|
584
|
+
Log.d(TAG, "Sending OTA notification frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
585
|
+
|
|
586
|
+
// Send frame and wait for response
|
|
587
|
+
String response = sendCommandAndWaitResponse(frame, 5000);
|
|
588
|
+
|
|
589
|
+
// Parse response
|
|
590
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
591
|
+
|
|
592
|
+
if (!parsedResponse.success) {
|
|
593
|
+
return new IOBoardResponse(false, "Failed to parse response: " + parsedResponse.message);
|
|
594
|
+
}
|
|
566
595
|
|
|
567
|
-
// TODO: Send frame via serial port plugin and receive response
|
|
568
596
|
return new IOBoardResponse(true, "OTA notification sent successfully");
|
|
569
597
|
|
|
570
598
|
} catch (Exception e) {
|
|
@@ -587,22 +615,39 @@ public class IOBoardManager {
|
|
|
587
615
|
// Decode base64 data
|
|
588
616
|
byte[] firmwareData = Base64.decode(dataBase64, Base64.DEFAULT);
|
|
589
617
|
|
|
590
|
-
//
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
data[
|
|
594
|
-
data[
|
|
595
|
-
data[
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
618
|
+
// TODO: Add OTA data method to IOBoardProtocolUtils
|
|
619
|
+
// For now, use manual frame building based on protocol specs
|
|
620
|
+
byte[] data = new byte[4 + Math.min(firmwareData.length, 128)]; // Packet number(4) + Data content (max 128 bytes)
|
|
621
|
+
data[0] = (byte) (packetNumber & 0xFF);
|
|
622
|
+
data[1] = (byte) ((packetNumber >> 8) & 0xFF);
|
|
623
|
+
data[2] = (byte) ((packetNumber >> 16) & 0xFF);
|
|
624
|
+
data[3] = (byte) ((packetNumber >> 24) & 0xFF);
|
|
625
|
+
|
|
626
|
+
// Copy firmware data (max 128 bytes as per protocol)
|
|
627
|
+
int dataLength = Math.min(firmwareData.length, 128);
|
|
628
|
+
System.arraycopy(firmwareData, 0, data, 4, dataLength);
|
|
629
|
+
|
|
630
|
+
// Pad with zeros if needed
|
|
631
|
+
if (dataLength < 128) {
|
|
632
|
+
for (int i = 4 + dataLength; i < 4 + 128 && i < data.length; i++) {
|
|
633
|
+
data[i] = 0;
|
|
634
|
+
}
|
|
599
635
|
}
|
|
600
636
|
|
|
601
|
-
|
|
637
|
+
byte[] frame = IOBoardProtocolUtils.createFrame((byte) address, IOBoardProtocolUtils.FRAME_TYPE_OTA_DATA, data);
|
|
638
|
+
|
|
639
|
+
Log.d(TAG, "Sending OTA data frame: " + IOBoardProtocolUtils.frameToHex(frame));
|
|
640
|
+
|
|
641
|
+
// Send frame and wait for response
|
|
642
|
+
String response = sendCommandAndWaitResponse(frame, 5000);
|
|
602
643
|
|
|
603
|
-
|
|
644
|
+
// Parse response
|
|
645
|
+
IOBoardProtocolUtils.ParsedResponse parsedResponse = IOBoardProtocolUtils.parseResponse(response);
|
|
646
|
+
|
|
647
|
+
if (!parsedResponse.success) {
|
|
648
|
+
return new IOBoardResponse(false, "Failed to parse response: " + parsedResponse.message);
|
|
649
|
+
}
|
|
604
650
|
|
|
605
|
-
// TODO: Send frame via serial port plugin and receive response
|
|
606
651
|
return new IOBoardResponse(true, "OTA data sent successfully");
|
|
607
652
|
|
|
608
653
|
} catch (Exception e) {
|
|
@@ -615,12 +660,15 @@ public class IOBoardManager {
|
|
|
615
660
|
* Open serial connection
|
|
616
661
|
*/
|
|
617
662
|
public IOBoardResponse openConnection(SerialConfig config) {
|
|
618
|
-
Log.d(TAG, "Opening serial connection - BaudRate: " + config.baudRate);
|
|
663
|
+
Log.d(TAG, "Opening serial connection - Port: " + config.portPath + ", BaudRate: " + config.baudRate);
|
|
619
664
|
|
|
620
665
|
try {
|
|
621
|
-
// TODO: Initialize connection with
|
|
622
|
-
//
|
|
666
|
+
// TODO: Initialize connection with SerialPort plugin
|
|
667
|
+
// Call SerialPort.openConnection() with config parameters
|
|
668
|
+
// Store the returned port ID for future operations
|
|
669
|
+
|
|
623
670
|
isConnected = true;
|
|
671
|
+
currentSerialPortId = "mock_port_id";
|
|
624
672
|
|
|
625
673
|
return new IOBoardResponse(true, "Serial connection opened successfully");
|
|
626
674
|
|
|
@@ -637,8 +685,11 @@ public class IOBoardManager {
|
|
|
637
685
|
Log.d(TAG, "Closing serial connection");
|
|
638
686
|
|
|
639
687
|
try {
|
|
640
|
-
// TODO: Close connection with
|
|
688
|
+
// TODO: Close connection with SerialPort plugin
|
|
689
|
+
// Call SerialPort.closeConnection(currentSerialPortId)
|
|
690
|
+
|
|
641
691
|
isConnected = false;
|
|
692
|
+
currentSerialPortId = null;
|
|
642
693
|
|
|
643
694
|
return new IOBoardResponse(true, "Serial connection closed successfully");
|
|
644
695
|
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
package com.leonardojc.capacitor.ioboard;
|
|
2
|
+
|
|
3
|
+
import java.util.ArrayList;
|
|
4
|
+
import java.util.List;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* IOBOARD Protocol Helper Functions
|
|
8
|
+
* Protocolo actualizado según manual MTC3P08L
|
|
9
|
+
* Frame format: SOI | LEN | ADDR | TYPE | DATA | CRC | EOI
|
|
10
|
+
*/
|
|
11
|
+
public class IOBoardProtocolUtils {
|
|
12
|
+
|
|
13
|
+
// Frame constants
|
|
14
|
+
public static final byte SOI = 0x0D; // Start of frame
|
|
15
|
+
public static final byte EOI = 0x0A; // End of frame
|
|
16
|
+
|
|
17
|
+
// Frame types según manual actualizado
|
|
18
|
+
public static final byte FRAME_TYPE_STATUS_QUERY = 0x00; // Status query
|
|
19
|
+
public static final byte FRAME_TYPE_SINGLE_PALLET = 0x01; // Parameter settings (single pallet)
|
|
20
|
+
public static final byte FRAME_TYPE_FULL_PALLET = 0x02; // Parameter settings (full pallet)
|
|
21
|
+
public static final byte FRAME_TYPE_OTA_REQUEST = (byte) 0xF1; // OTA request
|
|
22
|
+
public static final byte FRAME_TYPE_OTA_DATA = (byte) 0xF2; // OTA data
|
|
23
|
+
public static final byte FRAME_TYPE_OTA_RESPONSE = (byte) 0xF3; // OTA response
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* CRC-16/Modbus (x16+x15+x2+1) según manual
|
|
27
|
+
*/
|
|
28
|
+
public static int calculateCRC16(byte[] data) {
|
|
29
|
+
int crc = 0xFFFF;
|
|
30
|
+
for (byte b : data) {
|
|
31
|
+
crc ^= (b & 0xFF);
|
|
32
|
+
for (int j = 0; j < 8; j++) {
|
|
33
|
+
if ((crc & 0x0001) != 0) {
|
|
34
|
+
crc = (crc >> 1) ^ 0xA001;
|
|
35
|
+
} else {
|
|
36
|
+
crc = crc >> 1;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return crc & 0xFFFF;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Formato de frame según manual: SOI | LEN | ADDR | TYPE | DATA | CRC | EOI
|
|
45
|
+
*/
|
|
46
|
+
public static byte[] createFrame(byte address, byte frameType, byte[] data) {
|
|
47
|
+
if (data == null) data = new byte[0];
|
|
48
|
+
|
|
49
|
+
int frameLength = 7 + data.length; // SOI(1) + LEN(1) + ADDR(1) + TYPE(1) + DATA(n) + CRC(2) + EOI(1)
|
|
50
|
+
byte[] frame = new byte[frameLength];
|
|
51
|
+
int index = 0;
|
|
52
|
+
|
|
53
|
+
// SOI (Frame Header)
|
|
54
|
+
frame[index++] = SOI;
|
|
55
|
+
|
|
56
|
+
// LEN (Data Length) - longitud completa del frame
|
|
57
|
+
frame[index++] = (byte) frameLength;
|
|
58
|
+
|
|
59
|
+
// ADDR (Target Address)
|
|
60
|
+
frame[index++] = address;
|
|
61
|
+
|
|
62
|
+
// TYPE (Frame Type)
|
|
63
|
+
frame[index++] = frameType;
|
|
64
|
+
|
|
65
|
+
// DATA (Data Content)
|
|
66
|
+
for (byte b : data) {
|
|
67
|
+
frame[index++] = b;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Calculate CRC para todos los datos desde SOI hasta antes del CRC
|
|
71
|
+
byte[] crcData = new byte[index];
|
|
72
|
+
System.arraycopy(frame, 0, crcData, 0, index);
|
|
73
|
+
int crc = calculateCRC16(crcData);
|
|
74
|
+
|
|
75
|
+
// CRC (Check Field) - Low byte first, High byte second según manual
|
|
76
|
+
frame[index++] = (byte) (crc & 0xFF); // Low byte
|
|
77
|
+
frame[index++] = (byte) ((crc >> 8) & 0xFF); // High byte
|
|
78
|
+
|
|
79
|
+
// EOI (Frame End)
|
|
80
|
+
frame[index] = EOI;
|
|
81
|
+
|
|
82
|
+
return frame;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Convert frame to hexadecimal string for debugging
|
|
87
|
+
*/
|
|
88
|
+
public static String frameToHex(byte[] frame) {
|
|
89
|
+
StringBuilder sb = new StringBuilder();
|
|
90
|
+
for (int i = 0; i < frame.length; i++) {
|
|
91
|
+
if (i > 0) sb.append(" ");
|
|
92
|
+
sb.append(String.format("%02X", frame[i] & 0xFF));
|
|
93
|
+
}
|
|
94
|
+
return sb.toString();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Convert frame to Latin-1 string preserving exact byte values
|
|
99
|
+
*/
|
|
100
|
+
public static String frameToLatin1String(byte[] frame) {
|
|
101
|
+
StringBuilder result = new StringBuilder();
|
|
102
|
+
for (byte b : frame) {
|
|
103
|
+
result.append((char) (b & 0xFF));
|
|
104
|
+
}
|
|
105
|
+
return result.toString();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Create status query frame
|
|
110
|
+
*/
|
|
111
|
+
public static byte[] createStatusQuery(byte address) {
|
|
112
|
+
return createFrame(address, FRAME_TYPE_STATUS_QUERY, null);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Single Pallet Control según manual: NUM | LOCK | LED (8 bytes)
|
|
117
|
+
*/
|
|
118
|
+
public static byte[] createSinglePalletControl(byte address, int palletNumber, boolean doorLock,
|
|
119
|
+
int red, int green, int blue, int intensity,
|
|
120
|
+
int blinkTimes, int blinkSpeed) {
|
|
121
|
+
byte[] data = new byte[8];
|
|
122
|
+
data[0] = (byte) palletNumber; // Pallet number (0-7)
|
|
123
|
+
data[1] = (byte) (doorLock ? 1 : 0); // Door lock control (1=unlock, 0=no action)
|
|
124
|
+
data[2] = (byte) (red & 0xFF); // RGB Red (0-255)
|
|
125
|
+
data[3] = (byte) (green & 0xFF); // RGB Green (0-255)
|
|
126
|
+
data[4] = (byte) (blue & 0xFF); // RGB Blue (0-255)
|
|
127
|
+
data[5] = (byte) (intensity & 0xFF); // Intensity (0-100 percentage, >100 = max)
|
|
128
|
+
data[6] = (byte) (blinkTimes & 0xFF); // Blink times (0=no flash, 255=forever, 1-254=times)
|
|
129
|
+
data[7] = (byte) (blinkSpeed & 0xFF); // Blink speed (1-30 seconds interval)
|
|
130
|
+
|
|
131
|
+
return createFrame(address, FRAME_TYPE_SINGLE_PALLET, data);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Full Pallet Control según manual: LOCK | EXT | LED (8 x 6 bytes = 50 bytes total)
|
|
136
|
+
*/
|
|
137
|
+
public static byte[] createFullPalletControl(byte address, int doorLockControl, int extendedControl,
|
|
138
|
+
int[][] ledControls) {
|
|
139
|
+
byte[] data = new byte[50]; // 2 + (8 * 6)
|
|
140
|
+
int index = 0;
|
|
141
|
+
|
|
142
|
+
data[index++] = (byte) (doorLockControl & 0xFF); // Door lock control (8 bits)
|
|
143
|
+
data[index++] = (byte) (extendedControl & 0xFF); // Extended control (8 bits)
|
|
144
|
+
|
|
145
|
+
// Add LED controls (8 LEDs * 6 bytes each)
|
|
146
|
+
for (int i = 0; i < 8; i++) {
|
|
147
|
+
int[] led = (ledControls != null && i < ledControls.length && ledControls[i] != null)
|
|
148
|
+
? ledControls[i]
|
|
149
|
+
: new int[]{0, 0, 0, 0, 0, 1}; // Default: off
|
|
150
|
+
|
|
151
|
+
data[index++] = (byte) (led[0] & 0xFF); // RGB Red
|
|
152
|
+
data[index++] = (byte) (led[1] & 0xFF); // RGB Green
|
|
153
|
+
data[index++] = (byte) (led[2] & 0xFF); // RGB Blue
|
|
154
|
+
data[index++] = (byte) (led[3] & 0xFF); // Intensity
|
|
155
|
+
data[index++] = (byte) (led[4] & 0xFF); // Blink times
|
|
156
|
+
data[index++] = (byte) (led[5] & 0xFF); // Blink speed
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return createFrame(address, FRAME_TYPE_FULL_PALLET, data);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Response parsing result
|
|
164
|
+
*/
|
|
165
|
+
public static class ParsedResponse {
|
|
166
|
+
public boolean success;
|
|
167
|
+
public String message;
|
|
168
|
+
public byte address;
|
|
169
|
+
public byte frameType;
|
|
170
|
+
public byte[] data;
|
|
171
|
+
|
|
172
|
+
public ParsedResponse(boolean success, String message) {
|
|
173
|
+
this.success = success;
|
|
174
|
+
this.message = message;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public ParsedResponse(boolean success, String message, byte address, byte frameType, byte[] data) {
|
|
178
|
+
this.success = success;
|
|
179
|
+
this.message = message;
|
|
180
|
+
this.address = address;
|
|
181
|
+
this.frameType = frameType;
|
|
182
|
+
this.data = data;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Parse response frame según formato: SOI | LEN | ADDR | TYPE | DATA | CRC | EOI
|
|
188
|
+
*/
|
|
189
|
+
public static ParsedResponse parseResponse(String responseString) {
|
|
190
|
+
if (responseString == null || responseString.length() < 7) {
|
|
191
|
+
return new ParsedResponse(false, "Response too short");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
byte[] allBytes = responseString.getBytes(java.nio.charset.StandardCharsets.ISO_8859_1);
|
|
195
|
+
|
|
196
|
+
byte soi = allBytes[0];
|
|
197
|
+
if (soi != SOI) {
|
|
198
|
+
return new ParsedResponse(false, "Invalid SOI");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
int len = allBytes[1] & 0xFF;
|
|
202
|
+
if (len > allBytes.length) {
|
|
203
|
+
return new ParsedResponse(false, "Invalid frame length");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Extraer solo los bytes que corresponden al frame
|
|
207
|
+
byte[] bytes = new byte[len];
|
|
208
|
+
System.arraycopy(allBytes, 0, bytes, 0, len);
|
|
209
|
+
|
|
210
|
+
byte address = bytes[2];
|
|
211
|
+
byte frameType = bytes[3];
|
|
212
|
+
byte eoi = bytes[len - 1];
|
|
213
|
+
|
|
214
|
+
if (eoi != EOI) {
|
|
215
|
+
return new ParsedResponse(false, "Invalid EOI");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Extract data (excluding SOI, LEN, ADDR, TYPE, CRC, CRC, EOI)
|
|
219
|
+
int dataLength = len - 7;
|
|
220
|
+
byte[] data = new byte[dataLength];
|
|
221
|
+
if (dataLength > 0) {
|
|
222
|
+
System.arraycopy(bytes, 4, data, 0, dataLength);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Extract CRC
|
|
226
|
+
int receivedCrcLow = bytes[4 + dataLength] & 0xFF;
|
|
227
|
+
int receivedCrcHigh = bytes[4 + dataLength + 1] & 0xFF;
|
|
228
|
+
int receivedCrc = receivedCrcLow | (receivedCrcHigh << 8);
|
|
229
|
+
|
|
230
|
+
// Verify CRC
|
|
231
|
+
byte[] crcData = new byte[4 + dataLength];
|
|
232
|
+
System.arraycopy(bytes, 0, crcData, 0, 4 + dataLength);
|
|
233
|
+
int calculatedCrc = calculateCRC16(crcData);
|
|
234
|
+
|
|
235
|
+
if (receivedCrc != calculatedCrc) {
|
|
236
|
+
return new ParsedResponse(false, "CRC verification failed");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return new ParsedResponse(true, "Response parsed successfully", address, frameType, data);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Create test frames based on manual examples
|
|
244
|
+
*/
|
|
245
|
+
public static byte[] createTestStatusQuery() {
|
|
246
|
+
return createStatusQuery((byte) 1); // Address 01
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
public static byte[] createTestSinglePallet() {
|
|
250
|
+
return createSinglePalletControl((byte) 1, 0, true, 255, 0, 0, 255, 16, 1);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Validate that our commands match manual examples
|
|
255
|
+
*/
|
|
256
|
+
public static String validateExamples() {
|
|
257
|
+
StringBuilder results = new StringBuilder();
|
|
258
|
+
|
|
259
|
+
// Test Status Query
|
|
260
|
+
byte[] statusFrame = createTestStatusQuery();
|
|
261
|
+
String statusHex = frameToHex(statusFrame);
|
|
262
|
+
String expectedStatus = "0D 07 01 00 B2 D9 0A";
|
|
263
|
+
results.append("Status Query - Expected: ").append(expectedStatus)
|
|
264
|
+
.append(", Actual: ").append(statusHex)
|
|
265
|
+
.append(", Match: ").append(statusHex.equals(expectedStatus))
|
|
266
|
+
.append("\n");
|
|
267
|
+
|
|
268
|
+
// Test Single Pallet
|
|
269
|
+
byte[] singleFrame = createTestSinglePallet();
|
|
270
|
+
String singleHex = frameToHex(singleFrame);
|
|
271
|
+
String expectedSingle = "0D 0F 01 01 00 01 FF 00 00 FF 10 01 1D 6F 0A";
|
|
272
|
+
results.append("Single Pallet - Expected: ").append(expectedSingle)
|
|
273
|
+
.append(", Actual: ").append(singleHex)
|
|
274
|
+
.append(", Match: ").append(singleHex.equals(expectedSingle));
|
|
275
|
+
|
|
276
|
+
return results.toString();
|
|
277
|
+
}
|
|
278
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leonardojc/capacitor-ioboard",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A Capacitor plugin for controlling custom IOBOARD devices via RS485 serial communication with
|
|
3
|
+
"version": "1.2.0",
|
|
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",
|
|
7
7
|
"types": "dist/esm/index.d.ts",
|