openi2c
Version:
This library is a set of cross platform drivers for common I2C devices.
782 lines (781 loc) • 33.4 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.config = exports.BNO08X = exports.defaultConfig = void 0;
const utils_1 = require("../../utils");
const Module_1 = require("../Module");
const Packet_1 = require("./Packet");
__exportStar(require("./constants"), exports);
const constants_1 = require("./constants");
exports.defaultConfig = {
ADDRESS: 0x4B,
DATA_BUFFER_SIZE: 512, // Not sure if this is nessesary in the config.
PACKET_READ_TIMEOUT: 2.0,
};
class BNO08X extends Module_1.Module {
constructor(busNumber = 0, address = exports.defaultConfig.ADDRESS, config = exports.defaultConfig) {
super(busNumber, address, config);
this.commandBuffer = Buffer.alloc(12);
this.readings = {}; // for saving the most recent reading when decoding several packets
this.meCalibrationStartedAt = -1;
this.calibrationComplete = false;
this.magnetometerAccuracy = 0;
this.waitForInitialize = true;
this.initComplete = false;
this.idRead = false;
this.packetSlices = [];
// TODO: this is wrong there should be one per channel per direction
this.sequenceNumber = [0, 0, 0, 0, 0, 0];
this.twoEndedSequenceNumbers = new Map();
this.dcdSavedAt = -1;
this.dataBuffer = Buffer.alloc(this.config.DATA_BUFFER_SIZE);
}
/**
* Initialize the sensor
*/
init() {
return __awaiter(this, void 0, void 0, function* () {
for (let i = 0; i < 3; i++) {
// this.hardReset();
yield this.softReset();
try {
if (yield this.checkId()) {
return;
}
}
catch (error) {
yield (0, utils_1.sleep)(500);
}
}
throw new Error("Could not read ID");
});
}
getFeatureEnableReport(featureId, sensorSpecificConfig = 0, reportInterval = constants_1.DEFAULT_REPORT_INTERVAL) {
let setFeatureReport = Buffer.alloc(17);
setFeatureReport[0] = constants_1.SET_FEATURE_COMMAND;
setFeatureReport[1] = featureId;
setFeatureReport.writeUInt32LE(reportInterval, 5);
setFeatureReport.writeUInt32LE(sensorSpecificConfig, 13);
return setFeatureReport;
}
beginCalibration() {
return __awaiter(this, void 0, void 0, function* () {
yield this.sendMeCommand([
1, // calibrate accel
1, // calibrate gyro
1, // calibrate mag
constants_1.ME_CAL_CONFIG,
0, // calibrate planar acceleration
0, // 'on_table' calibration
0, // reserved
0, // reserved
0, // reserved
]);
this.calibrationComplete = false;
});
}
calibrationStatus() {
return __awaiter(this, void 0, void 0, function* () {
yield this.sendMeCommand([
0, // calibrate accel
0, // calibrate gyro
0, // calibrate mag
constants_1.ME_GET_CAL, // constant value for getting calibration status
0, // calibrate planar acceleration
0, // 'on_table' calibration
0, // reserved
0, // reserved
0, // reserved
]);
return this.magnetometerAccuracy;
});
}
sendMeCommand(subcommandParams) {
return __awaiter(this, void 0, void 0, function* () {
const startTime = Date.now();
const localBuffer = this.commandBuffer;
this.insertCommandRequestReport(constants_1.ME_CALIBRATE, this.commandBuffer, // should use this._dataBuffer :\ but sendPacket doesn't
this.getReportSeqId(constants_1.COMMAND_REQUEST), subcommandParams);
yield this.sendPacket(constants_1.BNO_CHANNEL_CONTROL, localBuffer);
this.incrementReportSeq(constants_1.COMMAND_REQUEST);
while (Date.now() - startTime < constants_1.DEFAULT_TIMEOUT) {
yield this.processAvailablePackets();
if (this.meCalibrationStartedAt > startTime) {
break;
}
}
});
}
incrementReportSeq(reportId) {
var _a;
const current = (_a = this.twoEndedSequenceNumbers.get(reportId)) !== null && _a !== void 0 ? _a : 0;
this.twoEndedSequenceNumbers.set(reportId, (current + 1) % 256);
}
getReportSeqId(reportId) {
var _a;
return (_a = this.twoEndedSequenceNumbers.get(reportId)) !== null && _a !== void 0 ? _a : 0;
}
insertCommandRequestReport(command, buffer, nextSequenceNumber, commandParams) {
if (commandParams && commandParams.length > 9) {
throw new Error(`Command request reports can only have up to 9 arguments but ${commandParams.length} were given`);
}
buffer.fill(0, 0, 12);
buffer[0] = constants_1.COMMAND_REQUEST;
buffer[1] = nextSequenceNumber;
buffer[2] = command;
if (commandParams === undefined) {
return;
}
commandParams.forEach((param, idx) => {
buffer[3 + idx] = param;
});
}
/**
* Used to enable a given feature of the BNO08x
*/
enableFeature(featureId) {
return __awaiter(this, void 0, void 0, function* () {
this.debug("\n********** Enabling feature id:", featureId, "**********");
let setFeatureReport;
if (featureId === constants_1.BNO_REPORT_ACTIVITY_CLASSIFIER) {
setFeatureReport = this.getFeatureEnableReport(featureId, constants_1.ENABLED_ACTIVITIES);
}
else {
setFeatureReport = this.getFeatureEnableReport(featureId);
}
let featureDependency = constants_1.RAW_REPORTS[featureId]; //rawReports.get(featureId, null);
if (featureDependency && !(featureDependency in this.readings)) {
this.debug("Enabling feature dependency:", featureDependency);
yield this.enableFeature(featureDependency);
}
// if the feature was enabled it will have a key in the readings dict
this.debug("Enabling", featureId);
yield this.sendPacket(constants_1.BNO_CHANNEL_CONTROL, setFeatureReport);
let startTime = Date.now(); // 1
while ((Date.now() - startTime) < constants_1.FEATURE_ENABLE_TIMEOUT) {
yield this.processAvailablePackets(10);
if (featureId in this.readings) {
return;
}
}
throw new Error("Was not able to enable feature " + featureId);
});
}
/**
* A tuple representing the acceleration measurements on the X, Y, and Z
* axes in meters per second squared
*/
acceleration() {
return __awaiter(this, void 0, void 0, function* () {
yield this.processAvailablePackets();
if (this.readings[constants_1.BNO_REPORT_ACCELEROMETER]) {
return this.readings[constants_1.BNO_REPORT_ACCELEROMETER];
}
else {
throw new Error("No accel report found, is it enabled?");
}
});
}
/**
* Get the roll pitch yaw on xyz axis using acceleration
*/
euler() {
return __awaiter(this, void 0, void 0, function* () {
// Placeholder values for acceleration on x, y, and z axes
// Replace these with actual accelerometer readings
const [ax, ay, az] = yield this.acceleration();
// Calculate roll and pitch based on the acceleration data
// Roll (rotation around x-axis)
const roll = Math.atan2(ay, az);
// Pitch (rotation around y-axis)
const pitch = Math.atan2(-ax, Math.sqrt(ay * ay + az * az));
// Yaw (rotation around z-axis) cannot be determined from acceleration alone
// Placeholder value for yaw
const yaw = 0; // This would require a magnetometer to calculate accurately
// Convert radians to degrees
const rollDeg = roll * (180 / Math.PI);
const pitchDeg = pitch * (180 / Math.PI);
const yawDeg = yaw * (180 / Math.PI);
return [rollDeg, pitchDeg, yawDeg];
});
}
/**
* A tuple representing Gyro's rotation measurements on the X, Y, and Z
* axes in radians per second
*/
gyro() {
return __awaiter(this, void 0, void 0, function* () {
yield this.processAvailablePackets();
if (this.readings[constants_1.BNO_REPORT_GYROSCOPE]) {
return this.readings[constants_1.BNO_REPORT_GYROSCOPE];
}
else {
throw new Error("No gyro report found, is it enabled?");
}
});
}
/**
* A tuple of the current magnetic field measurements on the X, Y, and Z axes
*/
magnetic() {
return __awaiter(this, void 0, void 0, function* () {
yield this.processAvailablePackets();
if (this.readings[constants_1.BNO_REPORT_MAGNETOMETER]) {
return this.readings[constants_1.BNO_REPORT_MAGNETOMETER];
}
else {
throw new Error("No magfield report found, is it enabled?");
}
});
}
/**
* The current heading in degrees
*/
heading() {
return __awaiter(this, void 0, void 0, function* () {
const [magX, magY] = yield this.magnetic(); // Assuming bno.magnetic() returns [magX, magY, magZ]
let heading = Math.atan2(magY, magX) * (180 / Math.PI); // Convert radians to degrees
if (heading < 0) {
heading += 360; // Adjust for negative values to get a full 360° range
}
return heading;
});
}
/**
* A quaternion representing the current rotation vector
*/
quaternion() {
return __awaiter(this, void 0, void 0, function* () {
yield this.processAvailablePackets();
if (this.readings[constants_1.BNO_REPORT_ROTATION_VECTOR]) {
return this.readings[constants_1.BNO_REPORT_ROTATION_VECTOR];
}
else {
throw new Error("No quaternion report found, is it enabled?");
}
});
}
/**
* A quaternion representing the current rotation vector expressed as a quaternion with no
* specific reference for heading, while roll and pitch are referenced against gravity. To
* prevent sudden jumps in heading due to corrections, the `gameQuaternion` property is not
* corrected using the magnetometer. Some drift is expected
*/
gameQuaternion() {
return __awaiter(this, void 0, void 0, function* () {
yield this.processAvailablePackets();
if (this.readings[constants_1.BNO_REPORT_ROTATION_VECTOR]) {
return this.readings[constants_1.BNO_REPORT_ROTATION_VECTOR];
}
else {
throw new Error("No quaternion report found, is it enabled?");
}
});
}
/**
* The number of steps detected since the sensor was initialized
*/
steps() {
return __awaiter(this, void 0, void 0, function* () {
yield this.processAvailablePackets();
if (this.readings[constants_1.BNO_REPORT_STEP_COUNTER]) {
return this.readings[constants_1.BNO_REPORT_STEP_COUNTER];
}
else {
throw new Error("No quaternion report found, is it enabled?");
}
});
}
processAvailablePackets() {
return __awaiter(this, arguments, void 0, function* (maxPackets = null) {
let processedCount = 0;
while (yield this.dataReady()) {
if (maxPackets && processedCount > maxPackets) {
return;
}
let packet;
try {
packet = yield this.readPacket();
}
catch (error) {
if (error instanceof Packet_1.PacketError) {
continue;
}
else {
throw error;
}
}
this.handlePacket(packet);
processedCount += 1;
}
this.debug(" ** DONE! **");
});
}
hardReset() {
return __awaiter(this, void 0, void 0, function* () { });
}
/**
* Reset the sensor to an initial unconfigured state
*/
softReset() {
return __awaiter(this, void 0, void 0, function* () {
this.debug("Soft resetting...", "");
const data = Buffer.from([1]);
yield this.sendPacket(constants_1.BNO_CHANNEL_EXE, data);
yield (0, utils_1.sleep)(500);
for (let i = 0; i < 3; i++) {
try {
const _packet = yield this.readPacket();
}
catch (error) {
if (error instanceof Packet_1.PacketError) {
yield (0, utils_1.sleep)(500);
}
else {
throw error;
}
}
}
this.debug("OK!");
});
}
checkId() {
return __awaiter(this, void 0, void 0, function* () {
this.debug("\n********** READ ID **********");
if (this.idRead) {
return true;
}
let data = Buffer.from([
constants_1.SHTP_REPORT_PRODUCT_ID_REQUEST,
0, // padding
]);
this.debug("\n** Sending ID Request Report **");
yield this.sendPacket(constants_1.BNO_CHANNEL_CONTROL, data);
this.debug("\n** Waiting for packet **");
// _a_ packet arrived, but which one?
// TODO this could cause an infinite loop? False never reached?
while (true) {
const packet = yield this.waitForPacketType(constants_1.BNO_CHANNEL_CONTROL, constants_1.SHTP_REPORT_PRODUCT_ID_RESPONSE);
let sensorId = this.parseSensorId(packet);
if (sensorId) {
this.idRead = true;
return true;
}
this.debug("Packet didn't have sensor ID report, trying again");
}
return false;
});
}
parseSensorId(packet) {
if (packet.data[0] !== constants_1.SHTP_REPORT_PRODUCT_ID_RESPONSE) {
return null;
}
const swMajor = packet.data.readUInt8(2);
const swMinor = packet.data.readUInt8(3);
const swPatch = packet.data.readUInt16LE(12);
const swPartNumber = packet.data.readUInt32LE(4);
const swBuildNumber = packet.data.readUInt32LE(8);
this.debug("FROM PACKET SLICE:");
this.debug(`*** Part Number: ${swPartNumber}`);
this.debug(`*** Software Version: ${swMajor}.${swMinor}.${swPatch}`);
this.debug(`*** Build: ${swBuildNumber}`);
return swPartNumber;
}
waitForPacketType(channelNumber_1) {
return __awaiter(this, arguments, void 0, function* (channelNumber, reportId = null, timeout = 5000.0) {
this.debug(`** Waiting for packet on channel ${channelNumber}${reportId ? ` with report id ${reportId.toString(16)}` : ""}`);
let start_time = Date.now();
// TODO make these async somehow.
while ((Date.now() - start_time) / 1000 < timeout) {
let newPacket = yield this.waitForPacket();
if (newPacket.channelNumber === channelNumber) {
if (reportId !== null) {
if (newPacket.reportId === reportId) {
return newPacket;
}
}
else {
return newPacket;
}
}
if (![constants_1.BNO_CHANNEL_EXE, constants_1.BNO_CHANNEL_SHTP_COMMAND].includes(newPacket.channelNumber)) {
this.debug("passing packet to handler for de-slicing");
this.handlePacket(newPacket);
}
}
throw new Error(`Timed out waiting for a packet on channel ${channelNumber}`);
});
}
reportLength(report_id) {
if (report_id < 0xF0) { // it's a sensor report
return constants_1.AVAIL_SENSOR_REPORTS[report_id][2];
}
return constants_1.REPORT_LENGTHS[report_id];
}
separateBatch(packet) {
const reportSlices = [];
// get first report id, loop up its report length
// read that many bytes, parse them
let nextByteIndex = 0;
while (nextByteIndex < packet.header.dataLength) {
const reportId = packet.data[nextByteIndex];
const requiredBytes = this.reportLength(reportId);
const unprocessedByteCount = packet.header.dataLength - nextByteIndex;
// handle incomplete remainder
if (unprocessedByteCount < requiredBytes) {
throw new Error("Unprocessable Batch bytes " + unprocessedByteCount);
}
// we have enough bytes to read
// add a slice to the list that was passed in
const reportSlice = packet.data.subarray(nextByteIndex, nextByteIndex + requiredBytes);
reportSlices.push([reportSlice[0], reportSlice]);
nextByteIndex = nextByteIndex + requiredBytes;
}
return reportSlices;
}
handlePacket(packet) {
try {
const packetSlices = this.separateBatch(packet);
while (packetSlices.length > 0) {
this.processReport(...packetSlices.pop());
}
}
catch (error) {
console.error(packet);
// throw error;
}
}
handleCommandResponse(reportBytes) {
// in origional code: _parse_command_response
// CMD response report:
// 0 Report ID = 0xF1
// 1 Sequence number
// 2 Command
// 3 Command sequence number
// 4 Response sequence number
// 5 R0-10 A set of response values. The interpretation of these values is specific
// to the response for each command.
const reportBody = Array.from(reportBytes.subarray(0, 5));
const responseValues = Array.from(reportBytes.subarray(5, 16));
const [_report_id, _seq_number, command, _command_seq_number, _response_seq_number] = reportBody;
const [commandStatus, ..._rest] = responseValues;
if (command === constants_1.ME_CALIBRATE && commandStatus === 0) {
this.meCalibrationStartedAt = Date.now();
}
if (command === constants_1.SAVE_DCD) {
if (commandStatus === 0) {
this.dcdSavedAt = Date.now();
}
else {
throw new Error("Unable to save calibration data");
}
}
}
handleControlReport(reportId, reportBytes) {
// if (reportId === SHTP_REPORT_PRODUCT_ID_RESPONSE) {
// // in origional code: _parse_sensor_id in main file not in class
// const sensorId = this.parseSensorId(reportBytes);
// if (!sensorId) {
// throw new Error(`Wrong report id for sensor id: ${reportBytes[0].toString(16)}`);
// }
// }
if (reportId === constants_1.GET_FEATURE_RESPONSE) {
// in origional code: _parse_get_feature_response_report
// unpack_from("<BBBHIII", report_bytes)
const getFeatureReport = [
reportBytes.readUint8(0), // report_id
reportBytes.readUint8(1),
reportBytes.readUint8(2),
reportBytes.readUInt16LE(3),
reportBytes.readUInt32LE(5),
reportBytes.readUInt32LE(9),
reportBytes.readUInt32LE(13)
];
const [_report_id, featureReportId, ..._remainder] = getFeatureReport;
this.readings[featureReportId] = constants_1.INITIAL_REPORTS[featureReportId] || [0.0, 0.0, 0.0];
}
if (reportId === constants_1.COMMAND_RESPONSE) {
this.handleCommandResponse(reportBytes);
}
}
processReport(reportId, reportBytes) {
if (reportId >= 0xF0) {
this.handleControlReport(reportId, reportBytes);
return;
}
// this.debug("\tProcessing report:", reports[report_id]);
// if (this._debug) {
// let outstr = "";
// for (let idx = 0; idx < report_bytes.length; idx++) {
// const packet_byte = report_bytes[idx];
// const packet_index = idx;
// if ((packet_index % 4) === 0) {
// outstr += `\nDBG::\t\t[0x${packet_index.toString(16).padStart(2, '0')}] `;
// }
// outstr += `0x${packet_byte.toString(16).padStart(2, '0')} `;
// }
// this._dbg(outstr);
// this._dbg("");
// }
if (reportId === constants_1.BNO_REPORT_STEP_COUNTER) {
this.readings[reportId] = this.parseStepCounterReport(reportBytes);
return;
}
if (reportId === constants_1.BNO_REPORT_SHAKE_DETECTOR) {
const shakeDetected = this.parseShakeReport(reportBytes);
if (!this.readings[constants_1.BNO_REPORT_SHAKE_DETECTOR]) {
this.readings[constants_1.BNO_REPORT_SHAKE_DETECTOR] = shakeDetected;
}
return;
}
if (reportId === constants_1.BNO_REPORT_STABILITY_CLASSIFIER) {
const stabilityClassification = this.parseStabilityClassifierReport(reportBytes);
this.readings[constants_1.BNO_REPORT_STABILITY_CLASSIFIER] = stabilityClassification;
return;
}
if (reportId === constants_1.BNO_REPORT_ACTIVITY_CLASSIFIER) {
const activityClassification = this.parseActivityClassifierReport(reportBytes);
this.readings[constants_1.BNO_REPORT_ACTIVITY_CLASSIFIER] = activityClassification;
return;
}
const [sensorData, accuracy] = this.parseSensorReportData(reportBytes);
if (reportId === constants_1.BNO_REPORT_MAGNETOMETER) {
this.magnetometerAccuracy = accuracy;
}
this.readings[reportId] = sensorData;
}
parseSensorReportData(reportBytes) {
let dataOffset = 4; // this may not always be true
const reportId = reportBytes[0];
const [scalar, count] = constants_1.AVAIL_SENSOR_REPORTS[reportId];
let isUnsigned = false;
if (constants_1.RAW_REPORTS[reportId]) {
// raw reports are unsigned
isUnsigned = true;
}
const results = [];
let accuracy = reportBytes.readUInt8(2) & 0b11;
for (let offsetIdx = 0; offsetIdx < count; offsetIdx++) {
const totalOffset = dataOffset + (offsetIdx * 2);
let rawData;
if (isUnsigned) {
rawData = reportBytes.readUint16LE(totalOffset);
}
else {
rawData = reportBytes.readInt16LE(totalOffset);
}
const scaledData = rawData * scalar;
results.push(scaledData);
}
return [results, accuracy];
}
parseStepCounterReport(reportBytes) {
const stepCount = reportBytes.readUInt16LE(8);
return stepCount;
}
parseShakeReport(reportBytes) {
const shakeDetected = (reportBytes.readUInt16LE(4) & 0x111) > 0;
return shakeDetected;
}
parseStabilityClassifierReport(reportBytes) {
const classificationBitfield = reportBytes.readUInt8(4);
const stabilityClassification = ["Unknown", "On Table", "Stationary", "Stable", "In motion"][classificationBitfield];
return stabilityClassification;
}
parseActivityClassifierReport(reportBytes) {
// 0 Report ID = 0x1E
// 1 Sequence number
// 2 Status
// 3 Delay
// 4 Page Number + EOS
// 5 Most likely state
// 6-15 Classification (10 x Page Number) + confidence
const activities = [
"Unknown",
"In-Vehicle",
"On-Bicycle",
"On-Foot",
"Still",
"Tilting",
"Walking",
"Running",
"OnStairs",
];
const endAndPageNumber = reportBytes.readUInt8(4);
const pageNumber = endAndPageNumber & 0x7F;
const mostLikely = reportBytes.readUInt8(5);
const confidences = Array.from(reportBytes.subarray(6, 15));
const classification = {};
classification["most_likely"] = activities[mostLikely];
for (let idx = 0; idx < confidences.length; idx++) {
const raw_confidence = confidences[idx];
const confidence = (10 * pageNumber) + raw_confidence;
const activity_string = activities[idx];
classification[activity_string] = confidence;
}
return classification;
}
waitForPacket(timeout) {
return __awaiter(this, void 0, void 0, function* () {
timeout = timeout || this.config.PACKET_READ_TIMEOUT;
let start_time = Date.now();
// TODO make these async somehow.
while ((Date.now() - start_time) / 1000 < timeout) {
if (!(yield this.dataReady())) {
continue;
}
let packet;
try {
packet = yield this.readPacket();
}
catch (error) {
if (error instanceof Packet_1.PacketError) {
continue;
}
else {
throw error;
}
}
return packet;
}
throw new Error("Timed out waiting for a packet");
});
}
readHeader() {
return __awaiter(this, void 0, void 0, function* () {
const buffer = Buffer.alloc(constants_1.BNO_HEADER_LEN);
yield this.readInto(buffer, buffer.length);
// this.readInto(this.dataBuffer, 4); // this is expecting a header
const packetHeader = Packet_1.Packet.headerFromBuffer(buffer);
this.debug(packetHeader);
return packetHeader;
});
}
readPacket() {
return __awaiter(this, void 0, void 0, function* () {
try {
// TODO Might be able to remove this and get header in a better way
// await this.readInto(this.dataBuffer, 4); // this is expecting a header
// const header = Packet.headerFromBuffer(this.dataBuffer);
// let packetByteCount = header.packetByteCount;
// const channelNumber = header.channelNumber;
// const sequenceNumber = header.sequenceNumber;
// this.sequenceNumber[channelNumber] = sequenceNumber;
// if (packetByteCount === 0) {
// this.debug("SKIPPING NO PACKETS AVAILABLE IN i2c._read_packet");
// throw new PacketError("No packet available");
// }
// packetByteCount -= 4;
// this.debug(
// "channel",
// channelNumber,
// "has",
// packetByteCount,
// "bytes available to read",
// );
// const header = await this.readHeader();
// HERE Have commented out is ready to see if it's receiving the data from the sensor and messing up all the other reads.
// I think we need to read the data as it comes in and then parse it into packets.
// const headerData = Buffer.alloc(4);
// await this.readInto(headerData, headerData.length);
// let packetByteCount = header.packetByteCount - 4;
const header = yield this.readHeader();
// this.updateSequenceNumber(header);
const buffer = Buffer.alloc(header.packetByteCount);
yield this.readInto(buffer, buffer.length);
const packet = new Packet_1.Packet(buffer);
// await this.read(packetByteCount);
// const newPacket = new Packet(this.dataBuffer);
this.debug(packet);
// this.updateSequenceNumber(packet.header);
return packet;
}
catch (error) {
throw new Packet_1.PacketError("Failed to load packet");
}
});
}
// This might no be nessesary since directions have different sequence numbers. Do we need to read with the same sequence number?
updateSequenceNumber(packetHeader) {
const channel = packetHeader.channelNumber;
const seq = packetHeader.sequenceNumber;
this.sequenceNumber[channel] = seq;
}
read(requestedReadLength) {
return __awaiter(this, void 0, void 0, function* () {
this.debug("trying to read", requestedReadLength, "bytes");
// +4 for the header
const totalReadLength = requestedReadLength + 4;
if (totalReadLength > this.config.DATA_BUFFER_SIZE) {
this.dataBuffer = Buffer.alloc(totalReadLength);
this.debug(`!!!!!!!!!!!! ALLOCATION: increased _data_buffer to Uint8Array(${totalReadLength}) !!!!!!!!!!!!!`);
}
yield this.readInto(this.dataBuffer, totalReadLength);
});
}
dataReady() {
return __awaiter(this, void 0, void 0, function* () {
let header = yield this.readHeader();
if (header.channelNumber > 5) {
this.debug("channel number out of range:", header.channelNumber);
}
let ready;
if (header.packetByteCount === 0x7FFF) {
console.log("Byte count is 0x7FFF/0xFFFF; Error?");
if (header.sequenceNumber === 0xFF) {
console.log("Sequence number is 0xFF; Error?");
}
ready = false;
}
else {
ready = header.dataLength > 0;
}
// this._dbg("\tdata ready", ready);
return ready;
});
}
sendPacket(channel, data) {
return __awaiter(this, void 0, void 0, function* () {
const dataLength = data.length;
const writeLength = dataLength + 4;
const buffer = Buffer.alloc(writeLength);
buffer.writeUInt16LE(writeLength, 0); // packet length MSB and LSB
buffer[2] = channel;
buffer[3] = this.sequenceNumber[channel];
data.forEach((byte, idx) => {
// Write the data into the buffer after the header
buffer[4 + idx] = byte;
});
const packet = new Packet_1.Packet(buffer);
this.debug("Sending packet:");
this.debug(packet);
yield this.write(buffer);
this.sequenceNumber[channel] = (this.sequenceNumber[channel] + 1) % 256; // Sequence number per channel that resets after 255
return this.sequenceNumber[channel];
});
}
}
exports.BNO08X = BNO08X;
exports.config = exports.defaultConfig;