/** @module ble */
// Import the generated protobuf module
import $root from "./protobuf/protobuf.js";
const Dwarfii_Api = $root;
import { cmdMapping, responseMapping } from "./cmd_mapping.js";
/*** -------------------------------------------- ***/
/*** ---------------- MODULE_BLE ---------------- ***/
/*** -------------------------------------------- ***/
/**
* Calculates the buffers crc16.
*
* @param {any} buffer the data buffer.
* @return {number} the calculated crc16.
*
* Source: github.com/yaacov/node-modbus-serial
*/
function calculateCRC16(buffer) {
var crc = 0xffff;
var odd;
for (var i = 0; i < buffer.length; i++) {
crc = crc ^ buffer[i];
for (var j = 0; j < 8; j++) {
odd = crc & 0x0001;
crc = crc >> 1;
if (odd) {
crc = crc ^ 0xa001;
}
}
}
return crc;
}
/**
* GetArrayFromHexString
* @param {string} data
* @returns {array}
*/
function getArrayFromHexString(data) {
let c = [];
while (data.length) {
let x = data.substr(0, 2);
let z = parseInt(x, 16); // hex string to int
z = (z + 0xff + 1) & 0xff; // twos complement
c.push(z);
data = data.substr(2);
}
return c;
}
/**
* getDecimalToHexString
* @param {number} number
* @returns {string}
*/
function getDecimalToHex16bString(number) {
let x = number + 0xffff + 1; // twos complement
let result = x.toString(16); // to hex
result = ("0000" + result).substr(-4);
return result;
}
/*
export function testEncode() {
let a = [128, -24, 255, 10];
alert("Original is " + JSON.stringify(a)); // [3546,-24,99999,3322]
let b = a
.map(function (x) {
x = x + 0xff + 1; // twos complement
x = x.toString(16); // to hex
x = ("00" + x).substr(-2); // zero-pad to 2-digits
return x;
})
.join("");
alert("Hex string " + b); // 00000ddaffffffe80001869f00000cfa
c = [];
while (b.length) {
var x = b.substr(0, 2);
x = parseInt(x, 16); // hex string to int
x = (x + 0xff + 1) & 0xff; // twos complement
c.push(x);
b = b.substr(2);
}
alert("Converted back: " + JSON.stringify(c)); // [3546,-24,99999,3322]
}
*/
/**
* Execute Decoding Received Bluetooth Packet from the Dwarf II
* @param {Uint8Array} buffer
* @param {Object} classDecode Class of Message depending on the command
* @returns {Object}
*/
export function decodePacketBle(buffer, classDecode) {
// eslint-disable-next-line no-undef
// Obtain a message type
let decoded = classDecode.decode(buffer);
console.log(`decoded data = ${JSON.stringify(decoded)}`);
return decoded;
}
/**
* Generic Create Encoded Bluetooth Packet Function
* @param {number} cmd
* @param {Object} message
* @param {Object} class_message
* @returns {Uint8Array}
*/
export function createPacketBle(cmd, message, class_message) {
let frame_header = 0xaa;
let frame_end = 0x0d;
let protocol_id = 0x01;
let package_id = 0x00;
let total_id = 0x01;
let reserved1_id = 0x00;
let reserved2_id = 0x00;
// message
let message_buffer = message;
message_buffer = class_message.encode(message).finish();
let buffer = [];
// payload
let payload_init = [
frame_header,
protocol_id,
cmd,
package_id,
total_id,
reserved1_id,
reserved2_id,
];
console.log(`Packet payload = ${JSON.stringify(payload_init)}`);
buffer.push(...payload_init);
// data lenght
let data_length = message_buffer.length;
let data_length_hexa = getDecimalToHex16bString(data_length);
let data_length_array = getArrayFromHexString(data_length_hexa);
console.log(`Data lenght = ${JSON.stringify(data_length_array)}`);
buffer.push(...data_length_array);
// data
console.debug(
`message_buffer = ${Array.prototype.toString.call(message_buffer)}`
);
buffer.push(...message_buffer);
let CRC16 = calculateCRC16(buffer);
let CRC16_array = getArrayFromHexString(getDecimalToHex16bString(CRC16));
buffer.push(...CRC16_array);
buffer.push(frame_end);
console.debug(`buffer = ${Array.prototype.toString.call(buffer)}`);
return new Uint8Array(buffer);
}
/**
* Generic Analysing Encoded Received BLE Packet Function
* @param {ArrayBuffer|string} message_buffer Encoded Message Buffer
* @returns {string}
*/
export function analyzePacketBle(message_buffer, input_data = true) {
// Check if binary message_buffer
if (
message_buffer instanceof Uint8Array ||
message_buffer instanceof ArrayBuffer
) {
// binary frame
console.debug(" -> Binary data .....");
} else {
// Handle the case where message_buffer is undefined or null
return JSON.stringify({ text: "" });
}
// Get buffer received
let data_rcv = new Uint8Array(message_buffer);
console.debug(data_rcv);
// verify the data : 12 octets minimum
if (data_rcv.length < 12) {
console.error(
`analyzePacketBle error Decoding not enought data received ! nb bytes: ${data_rcv.length}`
);
return "";
}
// Obtain a message type
let decoded_message = {};
let Response_message = {};
let data_class = "";
// Decoding buffer received
let cmd = data_rcv[2];
let data_length = data_rcv[7] * 256 + data_rcv[8];
let data_buffer = new Uint8Array([]);
if (data_length > 0) data_buffer = data_rcv.slice(9, 9 + data_length);
console.debug(`receive message cmd = ${cmd}`);
console.debug(`receive message data_length = ${data_length}`);
// Analyze Data : depends of cmd
const cmdClass = cmdMapping[cmd];
console.debug(`cmdClass: ${cmdClass}`);
const responseClass = responseMapping[cmd];
console.debug(`responseClass: ${responseClass}`);
// Automatic Analyse Data
// Get Response Class Object
if (input_data) {
console.debug(`cmdClass: ${cmdClass}`);
data_class = "Dwarfii_Api." + cmdClass;
Response_message = eval(`new Dwarfii_Api.${cmdClass}()`);
Response_message = decodePacketBle(
data_buffer,
eval(`Dwarfii_Api.${cmdClass}`)
);
console.debug(`Not all Data!>> ${JSON.stringify(Response_message)}`);
} else {
// Response
console.debug(`responseClass: ${responseClass}`);
data_class = "Dwarfii_Api." + responseClass;
Response_message = eval(`new Dwarfii_Api.${responseClass}()`);
Response_message = decodePacketBle(
data_buffer,
eval(`Dwarfii_Api.${responseClass}`)
);
console.debug(`Not all Data!>> ${JSON.stringify(Response_message)}`);
}
// replace data value with new keys and also prototype key assigned by default.
// escape toJSON property of object
decoded_message = Object.assign({}, Response_message);
for (let key in Response_message) {
if (key !== "toJSON") {
decoded_message[key] = Response_message[key];
}
}
console.log(`End Analyze Packet >> ${JSON.stringify(decoded_message)}`);
return JSON.stringify(decoded_message);
}
/**
* 3.1.1 Request data
* Create Encoded Packet for the command Getconfig
* CMD instruction, value is 1
* @param {string} ble_psd ; //Default: "DWARF_12345678"
* @returns {Uint8Array}
*/
export function messageGetconfig(ble_psd) {
// Obtain classname depending of the command
// Obtain a message class
var cmd = 1;
const cmdClass = cmdMapping[cmd];
// let class_message = eval(`Dwarfii_Api.${cmdClass}`); // error in production!
let class_message = Dwarfii_Api.ReqGetconfig;
// Encode message
let message = class_message.create({
cmd: cmd,
blePsd: ble_psd,
});
console.log(
`class Message = ${cmdClass} created message = ${JSON.stringify(message)}`
);
// return encoded Message Packet
return createPacketBle(cmd, message, class_message);
}
/**
* 3.2 Configure WiFi AP mode
* Create Encoded Packet for the command Configure WiFi AP mode
* CMD instruction, value is 2
* @param {Number} wifi_type ; // 0-5G 1-2.4G
* @param {Number} auto_start ; // WiFi boot configuration 0 - boot not start 1 - boot start
* @param {Number} country_list ; // 0- do not configure country_list 1- configure country_list
* @param {string} country ; //
* @param {string} ble_psd ; //Default: "DWARF_12345678"
* @returns {Uint8Array}
*/
export function messageWifiAP(
wifi_type,
auto_start,
country_list,
country,
ble_psd
) {
// Obtain classname depending of the command
// Obtain a message class
var cmd = 2;
const cmdClass = cmdMapping[cmd];
let class_message = eval(`Dwarfii_Api.${cmdClass}`);
// Encode message
let message = class_message.create({
cmd: cmd,
wifiType: wifi_type,
autoStart: auto_start,
countryList: country_list,
country: country,
blePsd: ble_psd,
});
console.log(
`class Message = ${cmdClass} created message = ${JSON.stringify(message)}`
);
// return encoded Message Packet
return createPacketBle(cmd, message, class_message);
}
/**
* 3.3 Configure WiFi STA mode
* Create Encoded Packet for the command Configure WiFi AP mode
* CMD instruction, value is 2
* @param {Number} auto_start ; // WiFi boot configuration 0 - boot not start 1 - boot start
* @param {string} ble_psd ; // Default: "DWARF_12345678"
* @param {string} ssid ; // WiFi name of router to connect
* @param {string} psd ; // WiFi password of the router to be connected
* @returns {Uint8Array}
*/
export function messageWifiSTA(auto_start, ble_psd, ssid, psd) {
// Obtain classname depending of the command
// Obtain a message class
var cmd = 3;
const cmdClass = cmdMapping[cmd];
let class_message = eval(`Dwarfii_Api.${cmdClass}`);
// Encode message
let message = class_message.create({
cmd: cmd,
autoStart: auto_start,
blePsd: ble_psd,
ssid: ssid,
psd: psd,
});
console.log(
`class Message = ${cmdClass} created message = ${JSON.stringify(message)}`
);
// return encoded Message Packet
return createPacketBle(cmd, message, class_message);
}
/**
* 3.4 Reset Bluetooth WiFi
* Create Encoded Packet for the command Reset Bluetooth WiFi
* CMD instruction, value is 5
* @returns {Uint8Array}
*/
export function messageResetWifi() {
// Obtain classname depending of the command
// Obtain a message class
var cmd = 5;
const cmdClass = cmdMapping[cmd];
let class_message = eval(`Dwarfii_Api.${cmdClass}`);
// Encode message
let message = class_message.create({
cmd: cmd,
});
console.log(
`class Message = ${cmdClass} created message = ${JSON.stringify(message)}`
);
// return encoded Message Packet
return createPacketBle(cmd, message, class_message);
}
/**
* 3.5 Get WiFi list
* Create Encoded Packet for the command Get WiFi list
* CMD instruction, value is 6
* @returns {Uint8Array}
*/
export function messageGetWifiList() {
// Obtain classname depending of the command
// Obtain a message class
var cmd = 6;
const cmdClass = cmdMapping[cmd];
let class_message = eval(`Dwarfii_Api.${cmdClass}`);
// Encode message
let message = class_message.create({
cmd: cmd,
});
console.log(
`class Message = ${cmdClass} created message = ${JSON.stringify(message)}`
);
// return encoded Message Packet
return createPacketBle(cmd, message, class_message);
}
/**
* 3.6 Obtain device information
* Create Encoded Packet for the command Get device information
* CMD instruction, value is 7
* @returns {Uint8Array}
*/
export function messageGetSystemInfo() {
// Obtain classname depending of the command
// Obtain a message class
var cmd = 7;
const cmdClass = cmdMapping[cmd];
let class_message = eval(`Dwarfii_Api.${cmdClass}`);
// Encode message
let message = class_message.create({
cmd: cmd,
});
console.log(
`class Message = ${cmdClass} created message = ${JSON.stringify(message)}`
);
// return encoded Message Packet
return createPacketBle(cmd, message, class_message);
}