UNPKG

openi2c

Version:

This library is a set of cross platform drivers for common I2C devices.

782 lines (781 loc) 33.4 kB
"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;