@leonardojc/capacitor-ioboard 1.1.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/CapacitorIoboard.podspec +13 -0
- package/LICENSE +21 -0
- package/README.md +292 -0
- package/android/build.gradle +39 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/java/com/leonardojc/capacitor/ioboard/CapacitorIoboardPlugin.java +336 -0
- package/android/src/main/java/com/leonardojc/capacitor/ioboard/IOBoardManager.java +657 -0
- package/dist/esm/definitions.d.ts +154 -0
- package/dist/esm/definitions.js +43 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/protocol.d.ts +62 -0
- package/dist/esm/protocol.js +191 -0
- package/dist/esm/web.d.ts +17 -0
- package/dist/esm/web.js +167 -0
- package/dist/plugin.cjs.js +422 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +425 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/CapacitorIoboard.swift +8 -0
- package/ios/Plugin/CapacitorIoboardPlugin.m +15 -0
- package/ios/Plugin/CapacitorIoboardPlugin.swift +142 -0
- package/package.json +97 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
export interface CapacitorIoboardPlugin {
|
|
2
|
+
/**
|
|
3
|
+
* Open serial connection to IOBOARD device
|
|
4
|
+
* @param options Serial connection parameters
|
|
5
|
+
*/
|
|
6
|
+
connect(options: SerialConnectionOptions): Promise<IOBoardResponse>;
|
|
7
|
+
/**
|
|
8
|
+
* Close serial connection
|
|
9
|
+
*/
|
|
10
|
+
disconnect(): Promise<IOBoardResponse>;
|
|
11
|
+
/**
|
|
12
|
+
* Check if serial connection is active
|
|
13
|
+
*/
|
|
14
|
+
isConnected(): Promise<{
|
|
15
|
+
connected: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Query the status of an IOBOARD device
|
|
19
|
+
* @param options Device address and timeout
|
|
20
|
+
*/
|
|
21
|
+
getStatus(options: DeviceOptions): Promise<IOBoardStatusResponse>;
|
|
22
|
+
/**
|
|
23
|
+
* Unlock a specific pallet with LED feedback
|
|
24
|
+
* @param options Pallet control parameters
|
|
25
|
+
*/
|
|
26
|
+
unlockPallet(options: UnlockPalletOptions): Promise<IOBoardResponse>;
|
|
27
|
+
/**
|
|
28
|
+
* Control multiple pallets simultaneously
|
|
29
|
+
* @param options Full pallet control parameters
|
|
30
|
+
*/
|
|
31
|
+
controlMultiplePallets(options: MultiplePalletOptions): Promise<IOBoardResponse>;
|
|
32
|
+
/**
|
|
33
|
+
* Scan for IOBOARD devices on the network
|
|
34
|
+
* @param options Scan parameters
|
|
35
|
+
*/
|
|
36
|
+
scanDevices(options: ScanOptions): Promise<ScanResponse>;
|
|
37
|
+
/**
|
|
38
|
+
* Send OTA update notification to IOBOARD
|
|
39
|
+
* @param options OTA notification parameters
|
|
40
|
+
*/
|
|
41
|
+
sendOTANotification(options: OTANotificationOptions): Promise<IOBoardResponse>;
|
|
42
|
+
/**
|
|
43
|
+
* Send OTA data packet to IOBOARD
|
|
44
|
+
* @param options OTA data parameters
|
|
45
|
+
*/
|
|
46
|
+
sendOTAData(options: OTADataOptions): Promise<IOBoardResponse>;
|
|
47
|
+
}
|
|
48
|
+
export interface IOBoardResponse {
|
|
49
|
+
success: boolean;
|
|
50
|
+
message?: string;
|
|
51
|
+
data?: any;
|
|
52
|
+
}
|
|
53
|
+
export interface IOBoardStatusResponse extends IOBoardResponse {
|
|
54
|
+
data?: {
|
|
55
|
+
doorLockStatus: number;
|
|
56
|
+
softwareVersion: {
|
|
57
|
+
major: number;
|
|
58
|
+
minor: number;
|
|
59
|
+
patch: number;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export interface SerialConnectionOptions {
|
|
64
|
+
portPath?: string;
|
|
65
|
+
baudRate?: number;
|
|
66
|
+
dataBits?: number;
|
|
67
|
+
stopBits?: number;
|
|
68
|
+
parity?: 'none' | 'even' | 'odd';
|
|
69
|
+
flowControl?: 'none' | 'hardware' | 'software';
|
|
70
|
+
timeout?: number;
|
|
71
|
+
}
|
|
72
|
+
export interface DeviceOptions {
|
|
73
|
+
address: number;
|
|
74
|
+
timeout?: number;
|
|
75
|
+
}
|
|
76
|
+
export interface UnlockPalletOptions extends DeviceOptions {
|
|
77
|
+
palletNumber: number;
|
|
78
|
+
ledColor?: 'red' | 'green' | 'blue' | 'yellow' | 'white' | 'off';
|
|
79
|
+
blinkTimes?: number;
|
|
80
|
+
blinkSpeed?: number;
|
|
81
|
+
}
|
|
82
|
+
export interface MultiplePalletOptions extends DeviceOptions {
|
|
83
|
+
doorLockMask: number;
|
|
84
|
+
ledControls?: LEDControlOptions[];
|
|
85
|
+
}
|
|
86
|
+
export interface ScanOptions {
|
|
87
|
+
startAddress?: number;
|
|
88
|
+
endAddress?: number;
|
|
89
|
+
timeout?: number;
|
|
90
|
+
}
|
|
91
|
+
export interface ScanResponse extends IOBoardResponse {
|
|
92
|
+
devices?: Array<{
|
|
93
|
+
address: number;
|
|
94
|
+
responding: boolean;
|
|
95
|
+
status?: any;
|
|
96
|
+
}>;
|
|
97
|
+
}
|
|
98
|
+
export interface LEDControlOptions {
|
|
99
|
+
red: number;
|
|
100
|
+
green: number;
|
|
101
|
+
blue: number;
|
|
102
|
+
intensity: number;
|
|
103
|
+
blinkTimes: number;
|
|
104
|
+
blinkSpeed: number;
|
|
105
|
+
}
|
|
106
|
+
export interface OTANotificationOptions {
|
|
107
|
+
address: number;
|
|
108
|
+
majorVersion: number;
|
|
109
|
+
minorVersion: number;
|
|
110
|
+
patchVersion: number;
|
|
111
|
+
firmwareSize: number;
|
|
112
|
+
}
|
|
113
|
+
export interface OTADataOptions {
|
|
114
|
+
address: number;
|
|
115
|
+
packetNumber: number;
|
|
116
|
+
data: string;
|
|
117
|
+
}
|
|
118
|
+
export declare const IOBOARD_PROTOCOL: {
|
|
119
|
+
SOI: number;
|
|
120
|
+
EOI: number;
|
|
121
|
+
FRAME_TYPES: {
|
|
122
|
+
STATUS_QUERY: number;
|
|
123
|
+
SINGLE_PALLET: number;
|
|
124
|
+
FULL_PALLET: number;
|
|
125
|
+
OTA_REQUEST: number;
|
|
126
|
+
OTA_DATA: number;
|
|
127
|
+
OTA_RESPONSE: number;
|
|
128
|
+
};
|
|
129
|
+
DEFAULT_BAUD_RATE: number;
|
|
130
|
+
DEFAULT_DATA_BITS: number;
|
|
131
|
+
DEFAULT_STOP_BITS: number;
|
|
132
|
+
DEFAULT_PARITY: "none";
|
|
133
|
+
DEFAULT_TIMEOUT: number;
|
|
134
|
+
MIN_ADDRESS: number;
|
|
135
|
+
MAX_ADDRESS: number;
|
|
136
|
+
MIN_PALLET: number;
|
|
137
|
+
MAX_PALLET: number;
|
|
138
|
+
OTA_PACKET_SIZE: number;
|
|
139
|
+
OTA_RESPONSES: {
|
|
140
|
+
AREA_REQUEST: number;
|
|
141
|
+
REQUEST_A_ZONE: number;
|
|
142
|
+
REQUEST_B_ZONE: number;
|
|
143
|
+
DATA_REQUEST: number;
|
|
144
|
+
COMPLETION: number;
|
|
145
|
+
ERROR: number;
|
|
146
|
+
};
|
|
147
|
+
OTA_ERROR_CODES: {
|
|
148
|
+
ILLEGAL_VERSION: number;
|
|
149
|
+
NON_OTA_STATUS: number;
|
|
150
|
+
WRITE_FAILED: number;
|
|
151
|
+
VERIFICATION_FAILED: number;
|
|
152
|
+
TRANSFER_FAILED: number;
|
|
153
|
+
};
|
|
154
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Protocol Constants
|
|
2
|
+
export const IOBOARD_PROTOCOL = {
|
|
3
|
+
SOI: 0x0D,
|
|
4
|
+
EOI: 0x0A,
|
|
5
|
+
FRAME_TYPES: {
|
|
6
|
+
STATUS_QUERY: 0x00,
|
|
7
|
+
SINGLE_PALLET: 0x01,
|
|
8
|
+
FULL_PALLET: 0x02,
|
|
9
|
+
OTA_REQUEST: 0xF1,
|
|
10
|
+
OTA_DATA: 0xF2,
|
|
11
|
+
OTA_RESPONSE: 0xF3
|
|
12
|
+
},
|
|
13
|
+
DEFAULT_BAUD_RATE: 115200,
|
|
14
|
+
DEFAULT_DATA_BITS: 8,
|
|
15
|
+
DEFAULT_STOP_BITS: 1,
|
|
16
|
+
DEFAULT_PARITY: 'none',
|
|
17
|
+
DEFAULT_TIMEOUT: 5000,
|
|
18
|
+
// Address range
|
|
19
|
+
MIN_ADDRESS: 1,
|
|
20
|
+
MAX_ADDRESS: 63,
|
|
21
|
+
// Pallet range
|
|
22
|
+
MIN_PALLET: 0,
|
|
23
|
+
MAX_PALLET: 7,
|
|
24
|
+
// OTA Constants
|
|
25
|
+
OTA_PACKET_SIZE: 128,
|
|
26
|
+
// Response codes
|
|
27
|
+
OTA_RESPONSES: {
|
|
28
|
+
AREA_REQUEST: 0x26,
|
|
29
|
+
REQUEST_A_ZONE: 0x41,
|
|
30
|
+
REQUEST_B_ZONE: 0x42,
|
|
31
|
+
DATA_REQUEST: 0x23,
|
|
32
|
+
COMPLETION: 0x4F,
|
|
33
|
+
ERROR: 0x45, // 'E'
|
|
34
|
+
},
|
|
35
|
+
// Error codes
|
|
36
|
+
OTA_ERROR_CODES: {
|
|
37
|
+
ILLEGAL_VERSION: 9,
|
|
38
|
+
NON_OTA_STATUS: 8,
|
|
39
|
+
WRITE_FAILED: 7,
|
|
40
|
+
VERIFICATION_FAILED: 6,
|
|
41
|
+
TRANSFER_FAILED: 5
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { registerPlugin } from '@capacitor/core';
|
|
2
|
+
const CapacitorIoboard = registerPlugin('CapacitorIoboard', {
|
|
3
|
+
web: () => import('./web').then(m => new m.CapacitorIoboardWeb()),
|
|
4
|
+
});
|
|
5
|
+
export * from './definitions';
|
|
6
|
+
export * from './protocol';
|
|
7
|
+
export { CapacitorIoboard };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IOBOARD Protocol utilities for frame construction and parsing
|
|
3
|
+
*/
|
|
4
|
+
export declare class IOBoardProtocol {
|
|
5
|
+
/**
|
|
6
|
+
* Calculate CRC-16 CCITT checksum
|
|
7
|
+
*/
|
|
8
|
+
static calculateCRC16(data: number[]): number;
|
|
9
|
+
/**
|
|
10
|
+
* Build a command frame for IOBOARD
|
|
11
|
+
*/
|
|
12
|
+
static buildFrame(address: number, frameType: number, data: number[]): number[];
|
|
13
|
+
/**
|
|
14
|
+
* Parse a response frame from IOBOARD
|
|
15
|
+
*/
|
|
16
|
+
static parseFrame(frame: number[]): {
|
|
17
|
+
success: boolean;
|
|
18
|
+
address?: number;
|
|
19
|
+
frameType?: number;
|
|
20
|
+
data?: number[];
|
|
21
|
+
error?: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Build status query frame
|
|
25
|
+
*/
|
|
26
|
+
static buildStatusQuery(address: number): number[];
|
|
27
|
+
/**
|
|
28
|
+
* Build single pallet control frame
|
|
29
|
+
*/
|
|
30
|
+
static buildSinglePalletControl(address: number, palletNumber: number, doorLock: boolean, ledControl: any): number[];
|
|
31
|
+
/**
|
|
32
|
+
* Build full pallet control frame
|
|
33
|
+
*/
|
|
34
|
+
static buildFullPalletControl(address: number, doorLockControl: number, extendedControl: number, ledControls: any[]): number[];
|
|
35
|
+
/**
|
|
36
|
+
* Build OTA notification frame
|
|
37
|
+
*/
|
|
38
|
+
static buildOTANotification(address: number, majorVersion: number, minorVersion: number, patchVersion: number, firmwareSize: number): number[];
|
|
39
|
+
/**
|
|
40
|
+
* Build OTA data frame
|
|
41
|
+
*/
|
|
42
|
+
static buildOTAData(address: number, packetNumber: number, data: Uint8Array): number[];
|
|
43
|
+
/**
|
|
44
|
+
* Parse status response
|
|
45
|
+
*/
|
|
46
|
+
static parseStatusResponse(data: number[]): {
|
|
47
|
+
doorLockStatus: number;
|
|
48
|
+
softwareVersion: {
|
|
49
|
+
major: number;
|
|
50
|
+
minor: number;
|
|
51
|
+
patch: number;
|
|
52
|
+
};
|
|
53
|
+
} | null;
|
|
54
|
+
/**
|
|
55
|
+
* Convert frame to hex string for debugging
|
|
56
|
+
*/
|
|
57
|
+
static frameToHex(frame: number[]): string;
|
|
58
|
+
/**
|
|
59
|
+
* Convert hex string to frame
|
|
60
|
+
*/
|
|
61
|
+
static hexToFrame(hex: string): number[];
|
|
62
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IOBOARD Protocol utilities for frame construction and parsing
|
|
3
|
+
*/
|
|
4
|
+
export class IOBoardProtocol {
|
|
5
|
+
/**
|
|
6
|
+
* Calculate CRC-16 CCITT checksum
|
|
7
|
+
*/
|
|
8
|
+
static calculateCRC16(data) {
|
|
9
|
+
let crc = 0xFFFF;
|
|
10
|
+
for (const byte of data) {
|
|
11
|
+
crc ^= (byte << 8);
|
|
12
|
+
for (let bit = 0; bit < 8; bit++) {
|
|
13
|
+
if (crc & 0x8000) {
|
|
14
|
+
crc = (crc << 1) ^ 0x1021;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
crc = crc << 1;
|
|
18
|
+
}
|
|
19
|
+
crc &= 0xFFFF;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return crc;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build a command frame for IOBOARD
|
|
26
|
+
*/
|
|
27
|
+
static buildFrame(address, frameType, data) {
|
|
28
|
+
const frame = [];
|
|
29
|
+
// SOI
|
|
30
|
+
frame.push(0x0D);
|
|
31
|
+
// Address
|
|
32
|
+
frame.push(address);
|
|
33
|
+
// Frame Type
|
|
34
|
+
frame.push(frameType);
|
|
35
|
+
// Data
|
|
36
|
+
frame.push(...data);
|
|
37
|
+
// Calculate CRC for address + frameType + data
|
|
38
|
+
const crcData = [address, frameType, ...data];
|
|
39
|
+
const crc = this.calculateCRC16(crcData);
|
|
40
|
+
// CRC (high byte first)
|
|
41
|
+
frame.push((crc >> 8) & 0xFF);
|
|
42
|
+
frame.push(crc & 0xFF);
|
|
43
|
+
// EOI
|
|
44
|
+
frame.push(0x0A);
|
|
45
|
+
return frame;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse a response frame from IOBOARD
|
|
49
|
+
*/
|
|
50
|
+
static parseFrame(frame) {
|
|
51
|
+
if (frame.length < 6) {
|
|
52
|
+
return { success: false, error: 'Frame too short' };
|
|
53
|
+
}
|
|
54
|
+
// Check SOI and EOI
|
|
55
|
+
if (frame[0] !== 0x0D || frame[frame.length - 1] !== 0x0A) {
|
|
56
|
+
return { success: false, error: 'Invalid frame markers' };
|
|
57
|
+
}
|
|
58
|
+
const address = frame[1];
|
|
59
|
+
const frameType = frame[2];
|
|
60
|
+
const dataLength = frame.length - 6; // SOI + Address + FrameType + CRC(2) + EOI
|
|
61
|
+
const data = frame.slice(3, 3 + dataLength);
|
|
62
|
+
// Extract CRC from frame
|
|
63
|
+
const receivedCRC = (frame[frame.length - 3] << 8) | frame[frame.length - 2];
|
|
64
|
+
// Calculate expected CRC
|
|
65
|
+
const crcData = [address, frameType, ...data];
|
|
66
|
+
const expectedCRC = this.calculateCRC16(crcData);
|
|
67
|
+
if (receivedCRC !== expectedCRC) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
error: `CRC mismatch: expected ${expectedCRC.toString(16)}, got ${receivedCRC.toString(16)}`
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
success: true,
|
|
75
|
+
address,
|
|
76
|
+
frameType,
|
|
77
|
+
data
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build status query frame
|
|
82
|
+
*/
|
|
83
|
+
static buildStatusQuery(address) {
|
|
84
|
+
return this.buildFrame(address, 0x00, []);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Build single pallet control frame
|
|
88
|
+
*/
|
|
89
|
+
static buildSinglePalletControl(address, palletNumber, doorLock, ledControl) {
|
|
90
|
+
const data = [];
|
|
91
|
+
// Pallet number
|
|
92
|
+
data.push(palletNumber);
|
|
93
|
+
// Door lock control (1 = unlock, 0 = no action)
|
|
94
|
+
data.push(doorLock ? 1 : 0);
|
|
95
|
+
// LED control (6 bytes)
|
|
96
|
+
data.push(ledControl.red);
|
|
97
|
+
data.push(ledControl.green);
|
|
98
|
+
data.push(ledControl.blue);
|
|
99
|
+
data.push(ledControl.intensity);
|
|
100
|
+
data.push(ledControl.blinkTimes);
|
|
101
|
+
data.push(ledControl.blinkSpeed);
|
|
102
|
+
return this.buildFrame(address, 0x01, data);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Build full pallet control frame
|
|
106
|
+
*/
|
|
107
|
+
static buildFullPalletControl(address, doorLockControl, extendedControl, ledControls) {
|
|
108
|
+
const data = [];
|
|
109
|
+
// Door lock control (8-bit mask)
|
|
110
|
+
data.push(doorLockControl);
|
|
111
|
+
// Extended control
|
|
112
|
+
data.push(extendedControl);
|
|
113
|
+
// LED controls for 8 pallets (48 bytes total)
|
|
114
|
+
for (let i = 0; i < 8; i++) {
|
|
115
|
+
const led = ledControls[i] || {
|
|
116
|
+
red: 0, green: 0, blue: 0,
|
|
117
|
+
intensity: 0, blinkTimes: 0, blinkSpeed: 0
|
|
118
|
+
};
|
|
119
|
+
data.push(led.red);
|
|
120
|
+
data.push(led.green);
|
|
121
|
+
data.push(led.blue);
|
|
122
|
+
data.push(led.intensity);
|
|
123
|
+
data.push(led.blinkTimes);
|
|
124
|
+
data.push(led.blinkSpeed);
|
|
125
|
+
}
|
|
126
|
+
return this.buildFrame(address, 0x02, data);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Build OTA notification frame
|
|
130
|
+
*/
|
|
131
|
+
static buildOTANotification(address, majorVersion, minorVersion, patchVersion, firmwareSize) {
|
|
132
|
+
const data = [];
|
|
133
|
+
// Version (3 bytes)
|
|
134
|
+
data.push(majorVersion);
|
|
135
|
+
data.push(minorVersion);
|
|
136
|
+
data.push(patchVersion);
|
|
137
|
+
// Firmware size (4 bytes, little-endian)
|
|
138
|
+
data.push(firmwareSize & 0xFF);
|
|
139
|
+
data.push((firmwareSize >> 8) & 0xFF);
|
|
140
|
+
data.push((firmwareSize >> 16) & 0xFF);
|
|
141
|
+
data.push((firmwareSize >> 24) & 0xFF);
|
|
142
|
+
return this.buildFrame(address, 0xF1, data);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build OTA data frame
|
|
146
|
+
*/
|
|
147
|
+
static buildOTAData(address, packetNumber, data) {
|
|
148
|
+
const frameData = [];
|
|
149
|
+
// Packet number (4 bytes, little-endian)
|
|
150
|
+
frameData.push(packetNumber & 0xFF);
|
|
151
|
+
frameData.push((packetNumber >> 8) & 0xFF);
|
|
152
|
+
frameData.push((packetNumber >> 16) & 0xFF);
|
|
153
|
+
frameData.push((packetNumber >> 24) & 0xFF);
|
|
154
|
+
// Data bytes (up to 128 bytes)
|
|
155
|
+
for (let i = 0; i < data.length; i++) {
|
|
156
|
+
frameData.push(data[i]);
|
|
157
|
+
}
|
|
158
|
+
return this.buildFrame(address, 0xF2, frameData);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Parse status response
|
|
162
|
+
*/
|
|
163
|
+
static parseStatusResponse(data) {
|
|
164
|
+
if (data.length < 4) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
doorLockStatus: data[0],
|
|
169
|
+
softwareVersion: {
|
|
170
|
+
major: data[1],
|
|
171
|
+
minor: data[2],
|
|
172
|
+
patch: data[3]
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Convert frame to hex string for debugging
|
|
178
|
+
*/
|
|
179
|
+
static frameToHex(frame) {
|
|
180
|
+
return frame.map(b => b.toString(16).padStart(2, '0')).join(' ').toUpperCase();
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Convert hex string to frame
|
|
184
|
+
*/
|
|
185
|
+
static hexToFrame(hex) {
|
|
186
|
+
return hex.split(' ')
|
|
187
|
+
.map(h => h.trim())
|
|
188
|
+
.filter(h => h.length > 0)
|
|
189
|
+
.map(h => parseInt(h, 16));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { CapacitorIoboardPlugin, IOBoardResponse, IOBoardStatusResponse, DeviceOptions, UnlockPalletOptions, MultiplePalletOptions, ScanOptions, ScanResponse, OTANotificationOptions, OTADataOptions, SerialConnectionOptions } from './definitions';
|
|
3
|
+
export declare class CapacitorIoboardWeb extends WebPlugin implements CapacitorIoboardPlugin {
|
|
4
|
+
private isConnectedState;
|
|
5
|
+
connect(options: SerialConnectionOptions): Promise<IOBoardResponse>;
|
|
6
|
+
disconnect(): Promise<IOBoardResponse>;
|
|
7
|
+
isConnected(): Promise<{
|
|
8
|
+
connected: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
getStatus(options: DeviceOptions): Promise<IOBoardStatusResponse>;
|
|
11
|
+
unlockPallet(options: UnlockPalletOptions): Promise<IOBoardResponse>;
|
|
12
|
+
controlMultiplePallets(options: MultiplePalletOptions): Promise<IOBoardResponse>;
|
|
13
|
+
scanDevices(options: ScanOptions): Promise<ScanResponse>;
|
|
14
|
+
sendOTANotification(options: OTANotificationOptions): Promise<IOBoardResponse>;
|
|
15
|
+
sendOTAData(options: OTADataOptions): Promise<IOBoardResponse>;
|
|
16
|
+
private getMaskBits;
|
|
17
|
+
}
|
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
export class CapacitorIoboardWeb extends WebPlugin {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.isConnectedState = false;
|
|
6
|
+
}
|
|
7
|
+
async connect(options) {
|
|
8
|
+
console.log('IOBOARD Web: Connect', options);
|
|
9
|
+
// Simulate connection delay
|
|
10
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
11
|
+
this.isConnectedState = true;
|
|
12
|
+
return {
|
|
13
|
+
success: true,
|
|
14
|
+
message: `Connected to ${options.portPath || '/dev/ttyS2'} (web mock)`
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async disconnect() {
|
|
18
|
+
console.log('IOBOARD Web: Disconnect');
|
|
19
|
+
this.isConnectedState = false;
|
|
20
|
+
return {
|
|
21
|
+
success: true,
|
|
22
|
+
message: 'Disconnected successfully (web mock)'
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async isConnected() {
|
|
26
|
+
return { connected: this.isConnectedState };
|
|
27
|
+
}
|
|
28
|
+
async getStatus(options) {
|
|
29
|
+
console.log('IOBOARD Web: Get Status', options);
|
|
30
|
+
if (!this.isConnectedState) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
message: 'No serial connection established'
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Mock response
|
|
37
|
+
return {
|
|
38
|
+
success: true,
|
|
39
|
+
message: 'Status retrieved successfully (web mock)',
|
|
40
|
+
data: {
|
|
41
|
+
doorLockStatus: 0b11010001,
|
|
42
|
+
softwareVersion: {
|
|
43
|
+
major: 1,
|
|
44
|
+
minor: 2,
|
|
45
|
+
patch: 3
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async unlockPallet(options) {
|
|
51
|
+
console.log('IOBOARD Web: Unlock Pallet', options);
|
|
52
|
+
if (!this.isConnectedState) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
message: 'No serial connection established'
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// Validate pallet number
|
|
59
|
+
if (options.palletNumber < 0 || options.palletNumber > 7) {
|
|
60
|
+
return {
|
|
61
|
+
success: false,
|
|
62
|
+
message: 'Invalid pallet number. Must be 0-7'
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Mock response
|
|
66
|
+
return {
|
|
67
|
+
success: true,
|
|
68
|
+
message: `Pallet ${options.palletNumber} unlocked successfully (web mock)`,
|
|
69
|
+
data: {
|
|
70
|
+
address: options.address,
|
|
71
|
+
palletNumber: options.palletNumber,
|
|
72
|
+
ledColor: options.ledColor || 'green'
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async controlMultiplePallets(options) {
|
|
77
|
+
console.log('IOBOARD Web: Control Multiple Pallets', options);
|
|
78
|
+
if (!this.isConnectedState) {
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
message: 'No serial connection established'
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Mock response
|
|
85
|
+
return {
|
|
86
|
+
success: true,
|
|
87
|
+
message: 'Multiple pallets controlled successfully (web mock)',
|
|
88
|
+
data: {
|
|
89
|
+
address: options.address,
|
|
90
|
+
doorLockMask: options.doorLockMask,
|
|
91
|
+
affectedPallets: this.getMaskBits(options.doorLockMask)
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
async scanDevices(options) {
|
|
96
|
+
console.log('IOBOARD Web: Scan Devices', options);
|
|
97
|
+
if (!this.isConnectedState) {
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
message: 'No serial connection established'
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// Mock scan results
|
|
104
|
+
const devices = [];
|
|
105
|
+
const start = options.startAddress || 1;
|
|
106
|
+
const end = Math.min(options.endAddress || 63, start + 5); // Mock max 5 devices
|
|
107
|
+
for (let addr = start; addr <= end; addr++) {
|
|
108
|
+
devices.push({
|
|
109
|
+
address: addr,
|
|
110
|
+
responding: Math.random() > 0.7,
|
|
111
|
+
status: Math.random() > 0.7 ? { doorLockStatus: Math.floor(Math.random() * 256) } : undefined
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
message: `Scanned addresses ${start}-${end} (web mock)`,
|
|
117
|
+
devices
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async sendOTANotification(options) {
|
|
121
|
+
console.log('IOBOARD Web: Send OTA Notification', options);
|
|
122
|
+
if (!this.isConnectedState) {
|
|
123
|
+
return {
|
|
124
|
+
success: false,
|
|
125
|
+
message: 'No serial connection established'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Mock response
|
|
129
|
+
return {
|
|
130
|
+
success: true,
|
|
131
|
+
message: 'OTA notification sent successfully (web mock)',
|
|
132
|
+
data: {
|
|
133
|
+
address: options.address,
|
|
134
|
+
version: `${options.majorVersion}.${options.minorVersion}.${options.patchVersion}`,
|
|
135
|
+
firmwareSize: options.firmwareSize
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async sendOTAData(options) {
|
|
140
|
+
console.log('IOBOARD Web: Send OTA Data', options);
|
|
141
|
+
if (!this.isConnectedState) {
|
|
142
|
+
return {
|
|
143
|
+
success: false,
|
|
144
|
+
message: 'No serial connection established'
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// Mock response
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
message: `OTA data packet ${options.packetNumber} sent successfully (web mock)`,
|
|
151
|
+
data: {
|
|
152
|
+
address: options.address,
|
|
153
|
+
packetNumber: options.packetNumber,
|
|
154
|
+
dataLength: options.data.length
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
getMaskBits(mask) {
|
|
159
|
+
const bits = [];
|
|
160
|
+
for (let i = 0; i < 8; i++) {
|
|
161
|
+
if (mask & (1 << i)) {
|
|
162
|
+
bits.push(i);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return bits;
|
|
166
|
+
}
|
|
167
|
+
}
|