-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsx126x.js
329 lines (256 loc) · 12.8 KB
/
sx126x.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
class SX126X {
constructor(serial_num, freq, addr, power, rssi) {
this.rssi = rssi;
this.addr = addr;
this.freq = freq;
this.serial_n = serial_num;
this.power = power;
this.send_to = addr;
this.M0 = 22;
this.M1 = 27;
this.cfg_reg = [0xC2, 0x00, 0x09, 0x00, 0x00, 0x00, 0x62, 0x00, 0x17, 0x00, 0x00, 0x00];
this.get_reg = Buffer.alloc(12);
this.serialPort = null;
this.SX126X_UART_BAUDRATE_1200 = 0x00;
this.SX126X_UART_BAUDRATE_2400 = 0x20;
this.SX126X_UART_BAUDRATE_4800 = 0x40;
this.SX126X_UART_BAUDRATE_9600 = 0x60;
this.SX126X_UART_BAUDRATE_19200 = 0x80;
this.SX126X_UART_BAUDRATE_38400 = 0xA0;
this.SX126X_UART_BAUDRATE_57600 = 0xC0;
this.SX126X_UART_BAUDRATE_115200 = 0xE0;
this.SX126X_AIR_SPEED_300bps = 0x00;
this.SX126X_AIR_SPEED_1200bps = 0x01;
this.SX126X_AIR_SPEED_2400bps = 0x02;
this.SX126X_AIR_SPEED_4800bps = 0x03;
this.SX126X_AIR_SPEED_9600bps = 0x04;
this.SX126X_AIR_SPEED_19200bps = 0x05;
this.SX126X_AIR_SPEED_38400bps = 0x06;
this.SX126X_AIR_SPEED_62500bps = 0x07;
this.SX126X_PACKAGE_SIZE_240_BYTE = 0x00;
this.SX126X_PACKAGE_SIZE_128_BYTE = 0x40;
this.SX126X_PACKAGE_SIZE_64_BYTE = 0x80;
this.SX126X_PACKAGE_SIZE_32_BYTE = 0xC0;
this.SX126X_Power_22dBm = 0x00;
this.SX126X_Power_17dBm = 0x01;
this.SX126X_Power_13dBm = 0x02;
this.SX126X_Power_10dBm = 0x03;
this.initializeGPIO();
}
beginSerial(serial_num) {
const SerialPort = require('serialport').SerialPort;
this.serialPort = new SerialPort({ // e.g., '/dev/ttyS0'
path: serial_num,
baudRate: 9600,
});
this.serialPort.on('open', () => {
this.serialPort.flush(() => {
console.log('Serial port opened and input flushed');
});
});
this.serialPort.on('error', (err) => {
console.error("Serial port error:", err);
});
}
async initializeGPIO() {
const pigpio = require('pigpio').Gpio;
this.m0Pin = new pigpio(this.M0, { mode: pigpio.OUTPUT });
this.m1Pin = new pigpio(this.M1, { mode: pigpio.OUTPUT });
this.m0Pin.digitalWrite(0);
this.m1Pin.digitalWrite(1);
}
initializeSerial(serial_num) {
const SerialPort = require('serialport').SerialPort;
this.serialPort = new SerialPort({ // e.g., '/dev/ttyS0'
path: serial_num,
baudRate: 9600,
});
this.serialPort.on('open', () => {
this.serialPort.flush(() => { // Flush input buffer on open
console.log('Serial port opened and input flushed');
});
});
this.serialPort.on('error', (err) => {
console.error("Serial port error:", err);
});
}
air_speed_cal(air_speed) {
if (air_speed === 300) return this.SX126X_AIR_SPEED_300bps;
else if (air_speed === 1200) return this.SX126X_AIR_SPEED_1200bps;
else if (air_speed === 2400) return this.SX126X_AIR_SPEED_2400bps;
else if (air_speed === 4800) return this.SX126X_AIR_SPEED_4800bps;
else if (air_speed === 9600) return this.SX126X_AIR_SPEED_9600bps;
else if (air_speed === 19200) return this.SX126X_AIR_SPEED_19200bps;
else if (air_speed === 38400) return this.SX126X_AIR_SPEED_38400bps;
else if (air_speed === 62500) return this.SX126X_AIR_SPEED_62500bps;
else return this.SX126X_AIR_SPEED_2400bps; // Default to 2400 if not matched
}
buffer_size_cal(buffer_size) {
if (buffer_size === 240) return this.SX126X_PACKAGE_SIZE_240_BYTE;
else if (buffer_size === 128) return this.SX126X_PACKAGE_SIZE_128_BYTE;
else if (buffer_size === 64) return this.SX126X_PACKAGE_SIZE_64_BYTE;
else if (buffer_size === 32) return this.SX126X_PACKAGE_SIZE_32_BYTE;
else return this.SX126X_PACKAGE_SIZE_240_BYTE; // Default to 240
}
power_cal(power) {
if (power === 22) return this.SX126X_Power_22dBm;
else if (power === 17) return this.SX126X_Power_17dBm;
else if (power === 13) return this.SX126X_Power_13dBm;
else if (power === 10) return this.SX126X_Power_10dBm;
else return this.SX126X_Power_22dBm; // Default to 22dBm
}
async set(freq, addr, power, rssi, air_speed = 2400,
net_id = 0, buffer_size = 240, crypt = 0,
relay = false, lbt = false, wor = false) {
this.send_to = addr;
this.addr = addr;
this.m0Pin.digitalWrite(0); // GPIO.LOW
this.m1Pin.digitalWrite(1); // GPIO.HIGH
await new Promise(resolve => setTimeout(resolve, 100)); // time.sleep(0.1)
let low_addr = addr & 0xff;
let high_addr = (addr >> 8) & 0xff;
let net_id_temp = net_id & 0xff;
let freq_temp;
if (freq > 850) {
freq_temp = freq - 850;
} else if (freq > 410) {
freq_temp = freq - 410;
} else {
freq_temp = freq; // Or handle error/default case
}
let air_speed_temp = this.air_speed_cal(air_speed);
let buffer_size_temp = this.buffer_size_cal(buffer_size);
let power_temp = this.power_cal(power);
let rssi_temp = rssi ? 0x80 : 0x00; // Conditional for RSSI
let l_crypt = crypt & 0xff;
let h_crypt = (crypt >> 8) & 0xff;
this.cfg_reg[3] = high_addr;
this.cfg_reg[4] = low_addr;
this.cfg_reg[5] = net_id_temp;
this.cfg_reg[6] = this.SX126X_UART_BAUDRATE_9600 + air_speed_temp;
this.cfg_reg[7] = buffer_size_temp + power_temp + 0x20;
this.cfg_reg[8] = freq_temp;
this.cfg_reg[9] = 0x03 + rssi_temp;
this.cfg_reg[10] = h_crypt;
this.cfg_reg[11] = l_crypt;
const configBytes = Buffer.from(this.cfg_reg); // Convert array to Buffer
for (let i = 0; i < 2; i++) {
this.serialPort.write(configBytes, (err) => { // Send config command
if (err) {
console.log('Serial port write error:', err);
return; // Exit if write fails
}
});
await new Promise(resolve => setTimeout(resolve, 200)); // time.sleep(0.2)
if (this.serialPort.readable) { // Check if data is waiting (using 'readable' event might be better for non-blocking)
await new Promise(resolve => setTimeout(resolve, 100)); // time.sleep(0.1) - small delay before reading
const responseBuffer = this.serialPort.read(this.serialPort.bytesToRead); // Read available data
if (responseBuffer && responseBuffer.length > 0) {
if (responseBuffer[0] === 0xC1) {
// console.log("parameters setting is :", configBytes); // If you want to log config
// console.log("parameters return is :", responseBuffer); // If you want to log response
// Success - you can add more detailed logging if needed
} else {
// console.log("parameters setting fail :", responseBuffer); // If you want to log failure response
// Setting failed - you can add more detailed error handling
}
break; // Exit loop on response (success or fail)
}
} else {
console.log("trying again!");
await new Promise(resolve => {
this.serialPort.flush(() => { // Flush input buffer before retry
console.log('\x1b[1A\r'); // ANSI escape code - might need to handle this differently in Node.js if needed in console
if (i === 1) {
console.log("setting fail, press Esc to exit and run again");
setTimeout(resolve, 2000); // time.sleep(2)
console.log('\x1b[1A\r'); // ANSI escape code - might need to handle this differently in Node.js if needed in console
} else {
resolve();
}
});
});
await new Promise(resolve => setTimeout(resolve, 200)); // time.sleep(0.2)
}
}
this.m0Pin.digitalWrite(0); // GPIO.LOW
this.m1Pin.digitalWrite(0); // GPIO.LOW
await new Promise(resolve => setTimeout(resolve, 100)); // time.sleep(0.1)
}
receive() {
return new Promise((resolve, reject) => {
let accumulatedData = ''; // Buffer to accumulate data
const dataHandler = (data) => {
console.log("[SerialPort - receive()] Raw Bytes Received (Before Filter):", data); // Log raw data BEFORE filter
let filteredData = data; // Assume no prefix initially
const prefixBuffer = Buffer.from([0x00, 0x1e]);
// Robust prefix check: Does data START WITH <Buffer 00 1e>?
if (data.indexOf(prefixBuffer) === 0) {
filteredData = data.subarray(prefixBuffer.length); // Remove prefix
console.log("[SerialPort - receive()] Prefix <Buffer 00 1e> detected and removed. Filtered Data:", filteredData); // Log filtered data
} else {
console.log("[SerialPort - receive()] No prefix <Buffer 00 1e> detected. Data:", data); // Log data if no prefix
}
const receivedString = filteredData.toString('utf8');
accumulatedData += receivedString; // Append to buffer
// Attempt to parse accumulated data as JSON
try {
// const cleanData = accumulatedData.replace(/[\uFFFD\u0000-\u001F]/g, '');
const cleanData = accumulatedData.replace(/^[^{]+/, '');
accumulatedData = cleanData; // Clean up data before parsing
console.log('\n\n\n\n\n\n', accumulatedData, '\n\n\n\n\n');
const parsedJSON = JSON.parse(accumulatedData);
// JSON parsing successful!
console.log(`[SerialPort - receive()] Complete JSON Received and Parsed:`, parsedJSON);
this.serialPort.off('data', dataHandler);
this.serialPort.off('error', errorHandler);
resolve(JSON.stringify(parsedJSON));
accumulatedData = ''; // Reset buffer
} catch (parseError) {
// JSON parsing failed - Incomplete or invalid
console.log("[SerialPort - receive()] Incomplete or Invalid JSON, accumulating more data...", accumulatedData);
// console.error("[SerialPort - receive()] JSON Parse Error:", parseError); // Optional: Log parse error
}
};
const errorHandler = (err) => {
console.error("[SerialPort - receive()] Error during receive:", err);
this.serialPort.off('data', dataHandler);
this.serialPort.off('error', errorHandler);
reject(err);
};
console.log("[SerialPort - receive()] Setting up data listener...");
this.serialPort.on('data', dataHandler);
this.serialPort.on('error', errorHandler);
});
}
async send(tx_data) {
return new Promise((resolve, reject) => {
this.m0Pin.digitalWrite(0);
this.m1Pin.digitalWrite(0);
const target_addr_high = (this.send_to >> 8) & 0xff;
const target_addr_low = this.send_to & 0xff;
const current_addr_high = (this.addr >> 8) & 0xff;
const current_addr_low = this.addr & 0xff;
const header = Buffer.from([target_addr_high, target_addr_low, current_addr_high, current_addr_low]);
const data = Buffer.from(tx_data, 'utf8'); // Encode string to Buffer
const bufferToSend = Buffer.concat([header, data]);
this.serialPort.write(bufferToSend, (err) => {
if (err) {
console.error('Serial port send error:', err);
reject(err);
} else {
console.log('Serial port sent data:', bufferToSend);
resolve();
}
});
});
}
}
// Example of how to use it (you'd need to provide the correct serial port)
async function main() {
const loraModule = new SX126X("/dev/ttyS0", 868, 0x1234, 22, false); // Example parameters
// You can add more function calls to loraModule object here to use other functionalities
console.log("LoRa module initialized and configured.");
}
main();
module.exports = SX126X;