UNPKG

@betaflight/api

Version:

A high-level API to read data from betaflight flight controllers

804 lines 38.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.readAdvancedConfig = exports.writeBoardAlignmentConfig = exports.readBoardAlignmentConfig = exports.commit = exports.reboot = exports.resetConfig = exports.calibrateAccelerometer = exports.writeArming = exports.readRCDeadband = exports.readRCTuning = exports.readRcValues = exports.writeEnabledFeatures = exports.readEnabledFeatures = exports.readExtendedStatus = exports.readStatus = exports.readAttitude = exports.readIMUData = exports.readRawGPS = exports.readAnalogValues = exports.readUID = exports.writeName = exports.readName = exports.readFcVariant = exports.readBoardInfo = exports.mergeDeep = exports.blackboxDevices = exports.gpsProtocols = exports.channelLetters = exports.availableFeatures = exports.MIXER_LIST = exports.mcuGroupFromId = exports.MCU_GROUPS = exports.rcSmoothingDerivativeTypes = exports.rcSmoothingInputTypes = exports.rcSmoothingTypes = exports.rcSmoothingChannels = exports.rcInterpolations = exports.spiRxProtocols = exports.serialRxProviders = exports.escProtocols = exports.initialiseSerialBackend = exports.baudRate = exports.ports = exports.packetErrors = exports.bytesWritten = exports.bytesRead = exports.isOpen = exports.close = exports.open = exports.apiVersion = void 0; exports.eraseDataFlash = exports.readSdCardSummary = exports.readDataFlashSummary = exports.readDataFlashChunk = exports.writePartialBlackboxConfig = exports.writeBlackboxConfig = exports.readBlackboxConfig = exports.writeGpsConfig = exports.readGpsConfig = exports.writeRssiConfig = exports.readRssiConfig = exports.writeRxMap = exports.readRxMap = exports.writePartialRxConfig = exports.writeRxConfig = exports.readRxConfig = exports.writeDisabledSensors = exports.readDisabledSensors = exports.writePartialBeeperConfig = exports.writeBeeperConfig = exports.readBeeperConfig = exports.writePartialAdvancedConfig = exports.writeAdvancedConfig = void 0; const semver_1 = __importDefault(require("semver")); const msp_1 = require("@betaflight/msp"); const codes_1 = __importDefault(require("./codes")); const types_1 = require("./types"); const features_1 = require("./features"); const utils_1 = require("./utils"); const huffman_1 = require("./huffman"); __exportStar(require("./osd"), exports); __exportStar(require("./power"), exports); __exportStar(require("./pid"), exports); __exportStar(require("./motors"), exports); __exportStar(require("./serial"), exports); __exportStar(require("./modes"), exports); __exportStar(require("./vtx"), exports); __exportStar(require("./types"), exports); var msp_2 = require("@betaflight/msp"); Object.defineProperty(exports, "apiVersion", { enumerable: true, get: function () { return msp_2.apiVersion; } }); Object.defineProperty(exports, "open", { enumerable: true, get: function () { return msp_2.open; } }); Object.defineProperty(exports, "close", { enumerable: true, get: function () { return msp_2.close; } }); Object.defineProperty(exports, "isOpen", { enumerable: true, get: function () { return msp_2.isOpen; } }); Object.defineProperty(exports, "bytesRead", { enumerable: true, get: function () { return msp_2.bytesRead; } }); Object.defineProperty(exports, "bytesWritten", { enumerable: true, get: function () { return msp_2.bytesWritten; } }); Object.defineProperty(exports, "packetErrors", { enumerable: true, get: function () { return msp_2.packetErrors; } }); Object.defineProperty(exports, "ports", { enumerable: true, get: function () { return msp_2.ports; } }); Object.defineProperty(exports, "baudRate", { enumerable: true, get: function () { return msp_2.baudRate; } }); Object.defineProperty(exports, "initialiseSerialBackend", { enumerable: true, get: function () { return msp_2.initialiseSerialBackend; } }); var features_2 = require("./features"); Object.defineProperty(exports, "escProtocols", { enumerable: true, get: function () { return features_2.escProtocols; } }); Object.defineProperty(exports, "serialRxProviders", { enumerable: true, get: function () { return features_2.serialRxProviders; } }); Object.defineProperty(exports, "spiRxProtocols", { enumerable: true, get: function () { return features_2.spiRxProtocols; } }); Object.defineProperty(exports, "rcInterpolations", { enumerable: true, get: function () { return features_2.rcInterpolations; } }); Object.defineProperty(exports, "rcSmoothingChannels", { enumerable: true, get: function () { return features_2.rcSmoothingChannels; } }); Object.defineProperty(exports, "rcSmoothingTypes", { enumerable: true, get: function () { return features_2.rcSmoothingTypes; } }); Object.defineProperty(exports, "rcSmoothingInputTypes", { enumerable: true, get: function () { return features_2.rcSmoothingInputTypes; } }); Object.defineProperty(exports, "rcSmoothingDerivativeTypes", { enumerable: true, get: function () { return features_2.rcSmoothingDerivativeTypes; } }); Object.defineProperty(exports, "MCU_GROUPS", { enumerable: true, get: function () { return features_2.MCU_GROUPS; } }); Object.defineProperty(exports, "mcuGroupFromId", { enumerable: true, get: function () { return features_2.mcuGroupFromId; } }); Object.defineProperty(exports, "MIXER_LIST", { enumerable: true, get: function () { return features_2.MIXER_LIST; } }); Object.defineProperty(exports, "availableFeatures", { enumerable: true, get: function () { return features_2.availableFeatures; } }); Object.defineProperty(exports, "channelLetters", { enumerable: true, get: function () { return features_2.channelLetters; } }); Object.defineProperty(exports, "gpsProtocols", { enumerable: true, get: function () { return features_2.gpsProtocols; } }); Object.defineProperty(exports, "blackboxDevices", { enumerable: true, get: function () { return features_2.blackboxDevices; } }); var utils_2 = require("./utils"); Object.defineProperty(exports, "mergeDeep", { enumerable: true, get: function () { return utils_2.mergeDeep; } }); const readBoardInfo = async (port) => { const api = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_BOARD_INFO }); return { boardIdentifier: String.fromCharCode(...(0, utils_1.times)(() => data.readU8(), 4)), boardVersion: data.readU16(), boardType: semver_1.default.gte(api, "1.35.0") ? data.readU8() : 0, targetCapabilities: (0, utils_1.unpackValues)(semver_1.default.gte(api, "1.37.0") ? data.readU8() : 0, (0, features_1.targetCapabilities)()), targetName: semver_1.default.gte(api, "1.37.0") ? String.fromCharCode(...(0, utils_1.times)(() => data.readU8(), data.readU8())) : "", boardName: semver_1.default.gte(api, "1.41.0") ? String.fromCharCode(...(0, utils_1.times)(() => data.readU8(), data.readU8())) : "", manufacturerId: semver_1.default.gte(api, "1.41.0") ? String.fromCharCode(...(0, utils_1.times)(() => data.readU8(), data.readU8())) : "", signature: semver_1.default.gte(api, "1.41.0") ? (0, utils_1.times)(() => data.readU8(), 32) : [], mcuTypeId: semver_1.default.gte(api, "1.41.0") ? data.readU8() : 255, configurationState: semver_1.default.gte(api, "1.42.0") ? data.readU8() : undefined, sampleRateHz: semver_1.default.gte(api, "1.43.0") ? data.readU16() : undefined, }; }; exports.readBoardInfo = readBoardInfo; const readFcVariant = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_FC_VARIANT }); return String.fromCharCode(...(0, utils_1.times)(() => data.readU8(), 4)); }; exports.readFcVariant = readFcVariant; const readName = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_NAME }); return String.fromCharCode(...(0, utils_1.times)(() => data.readU8(), data.byteLength)); }; exports.readName = readName; const MAX_NAME_BUFFER_SIZE = 64; const writeName = async (port, name) => { const buffer = Buffer.from(name.slice(0, MAX_NAME_BUFFER_SIZE)); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_NAME, data: buffer }); }; exports.writeName = writeName; const readUID = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_UID }); return (0, utils_1.times)(() => (data.readU32() + 16 ** 6).toString(16).substr(-6), 3).join(""); }; exports.readUID = readUID; const readAnalogValues = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_ANALOG }); const values = { voltage: data.readU8() / 10.0, mahDrawn: data.readU16(), rssi: Math.round((data.readU16() / 1023) * 100), amperage: data.read16() / 100, // A }; if (semver_1.default.gte((0, msp_1.apiVersion)(port), "1.41.0")) { values.voltage = data.readU16() / 100; } return values; }; exports.readAnalogValues = readAnalogValues; const readRawGPS = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RAW_GPS }); return { fix: !!data.readU8(), numSat: data.readU8(), lat: data.read32(), lon: data.read32(), alt: data.readU16(), speed: data.readU16(), groundCourse: data.readU16(), }; }; exports.readRawGPS = readRawGPS; const readIMUData = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RAW_IMU }); const accUnit = () => data.read16() / 512; const gyroUnit = () => data.read16() * (4 / 16.4); const mangetUnit = () => data.read16() / 1090; return { accelerometer: (0, utils_1.times)(accUnit, 3), gyroscope: (0, utils_1.times)(gyroUnit, 3), magnetometer: (0, utils_1.times)(mangetUnit, 3), }; }; exports.readIMUData = readIMUData; const readAttitude = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_ATTITUDE }); return { roll: data.read16() / 10.0, pitch: data.read16() / 10.0, yaw: data.read16(), // z }; }; exports.readAttitude = readAttitude; const extractStatus = (data) => ({ cycleTime: data.readU16(), i2cError: data.readU16(), sensors: (0, utils_1.unpackValues)(data.readU16(), (0, features_1.sensorBits)()), mode: data.readU32(), profile: data.readU8(), }); const readStatus = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_STATUS }); return extractStatus(data); }; exports.readStatus = readStatus; const readExtendedStatus = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_STATUS_EX }); const api = (0, msp_1.apiVersion)(port); const status = { ...extractStatus(data), cpuload: data.readU16(), numProfiles: 0, rateProfile: 0, armingDisabledFlags: [], }; if (semver_1.default.gte(api, "1.16.0")) { status.numProfiles = data.readU8(); status.rateProfile = data.readU8(); } if (semver_1.default.gte(api, "1.36.0")) { // skip all this data for some reason (0, utils_1.times)(() => data.readU8(), data.readU8()); const flags = (0, features_1.disarmFlagBits)(api); // Read arming disable flags const numFlags = data.readU8(); const flagBits = data.readU32(); // read the enabled disarm flags from the mask status.armingDisabledFlags = (0, utils_1.times)((i) => { var _a; return (flagBits & (1 << i)) !== 0 && ((_a = flags[i]) !== null && _a !== void 0 ? _a : types_1.DisarmFlags.UNKNOWN); }, numFlags).filter((flag) => typeof flag === "number"); } return status; }; exports.readExtendedStatus = readExtendedStatus; const readEnabledFeatures = async (port) => { const schema = (0, features_1.availableFeatures)((0, msp_1.apiVersion)(port)); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_FEATURE_CONFIG }); const featureMask = data.readU32(); return Object.entries(schema) .filter(([bit]) => (featureMask >> Number(bit)) % 2 !== 0) .map(([, feature]) => feature); }; exports.readEnabledFeatures = readEnabledFeatures; const writeEnabledFeatures = async (port, features) => { const schema = (0, features_1.availableFeatures)((0, msp_1.apiVersion)(port)); const buffer = new msp_1.WriteBuffer(); buffer.push32(Object.entries(schema) .filter(([, feature]) => features.includes(feature)) .reduce((acc, [bit]) => acc | (1 << Number(bit)), 0)); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_FEATURE_CONFIG, data: buffer, }); }; exports.writeEnabledFeatures = writeEnabledFeatures; const readRcValues = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RC }); return new Array(data.byteLength / 2).fill(0).map(() => data.readU16()); }; exports.readRcValues = readRcValues; const readRCTuning = async (port) => { const version = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RC_TUNING }); const tuning = { rcRate: 0, rcExpo: 0, rollPitchRate: 0, pitchRate: 0, rollRate: 0, yawRate: 0, dynamicThrottlePid: 0, throttleMid: 0, throttleExpo: 0, dynamicThrottleBreakpoint: 0, rcYawExpo: 0, rcYawRate: 0, rcPitchRate: 0, rcPitchExpo: 0, throttleLimitType: 0, throttleLimitPercent: 0, rollRateLimit: 0, pitchRateLimit: 0, yawRateLimit: 0, }; tuning.rcRate = parseFloat((data.readU8() / 100).toFixed(2)); tuning.rcExpo = parseFloat((data.readU8() / 100).toFixed(2)); if (semver_1.default.lt(version, "1.7.0")) { tuning.rollPitchRate = parseFloat((data.readU8() / 100).toFixed(2)); } else { tuning.rollRate = parseFloat((data.readU8() / 100).toFixed(2)); tuning.pitchRate = parseFloat((data.readU8() / 100).toFixed(2)); } tuning.yawRate = parseFloat((data.readU8() / 100).toFixed(2)); tuning.dynamicThrottlePid = parseFloat((data.readU8() / 100).toFixed(2)); tuning.throttleMid = parseFloat((data.readU8() / 100).toFixed(2)); tuning.throttleExpo = parseFloat((data.readU8() / 100).toFixed(2)); tuning.dynamicThrottleBreakpoint = semver_1.default.gte(version, "1.7.0") ? data.readU16() : 0; if (semver_1.default.gte(version, "1.10.0")) { tuning.rcYawExpo = parseFloat((data.readU8() / 100).toFixed(2)); if (semver_1.default.gte(version, "1.16.0")) { tuning.rcYawRate = parseFloat((data.readU8() / 100).toFixed(2)); } } if (semver_1.default.gte(version, "1.37.0")) { tuning.rcPitchRate = parseFloat((data.readU8() / 100).toFixed(2)); tuning.rcPitchExpo = parseFloat((data.readU8() / 100).toFixed(2)); } if (semver_1.default.gte(version, "1.41.0")) { tuning.throttleLimitType = data.readU8(); tuning.throttleLimitPercent = data.readU8(); } if (semver_1.default.gte(version, "1.42.0")) { tuning.rollRateLimit = data.readU16(); tuning.pitchRateLimit = data.readU16(); tuning.yawRateLimit = data.readU16(); } return tuning; }; exports.readRCTuning = readRCTuning; const readRCDeadband = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RC_DEADBAND }); return { deadband: data.readU8(), yawDeadband: data.readU8(), altHoldDeadhand: data.readU8(), deadband3dThrottle: semver_1.default.gte((0, msp_1.apiVersion)(port), "1.17.0") ? data.readU16() : 0, }; }; exports.readRCDeadband = readRCDeadband; const writeArming = async (port, { armingDisabled, runawayTakeoffPreventionDisabled, }) => { const data = new msp_1.WriteBuffer(); data.push8(Number(armingDisabled)); data.push8(Number(runawayTakeoffPreventionDisabled)); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_ARMING_DISABLE, data }); }; exports.writeArming = writeArming; const calibrateAccelerometer = async (port) => { await (0, msp_1.execute)(port, { code: codes_1.default.MSP_ACC_CALIBRATION }); // This command executes on the device, but doesn't actually produce anything // for about 2 seconds, so resolve after 2 seconds await (0, utils_1.sleep)(2000); }; exports.calibrateAccelerometer = calibrateAccelerometer; const resetConfig = async (port) => { await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RESET_CONF }); // This command executes on the device, but doesn't actually produce anything // for about 2 seconds, so resolve after 2 seconds await (0, utils_1.sleep)(2000); }; exports.resetConfig = resetConfig; /** * Set the device to reboot, returning true if successful */ const reboot = async (port, type) => { const api = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_REBOOT, data: type ? [type] : undefined, timeout: 3000, }).catch((e) => { if (!(0, msp_1.isOpen)(port)) { return undefined; } throw e; }); if (data && semver_1.default.gte(api, "1.40.0")) { const rebootType = data.read8(); if (rebootType === types_1.RebootTypes.MSC || rebootType === types_1.RebootTypes.MSC_UTC) { if (data.read8() === 0) { return false; } } } return true; }; exports.reboot = reboot; const commit = async (port) => { await (0, msp_1.execute)(port, { code: codes_1.default.MSP_EEPROM_WRITE }); }; exports.commit = commit; const readBoardAlignmentConfig = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_BOARD_ALIGNMENT_CONFIG }); return { roll: data.read16(), pitch: data.read16(), yaw: data.read16(), }; }; exports.readBoardAlignmentConfig = readBoardAlignmentConfig; const writeBoardAlignmentConfig = async (port, { roll, pitch, yaw }) => { await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_BOARD_ALIGNMENT_CONFIG, data: new msp_1.WriteBuffer().push16(roll).push16(pitch).push16(yaw), }); }; exports.writeBoardAlignmentConfig = writeBoardAlignmentConfig; const readAdvancedConfig = async (port) => { const api = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_ADVANCED_CONFIG }); const config = { gyroSyncDenom: 0, pidProcessDenom: 0, useUnsyncedPwm: false, fastPwmProtocol: 0, gyroToUse: 0, motorPwmRate: 0, digitalIdlePercent: 0, gyroUse32kHz: false, motorPwmInversion: 0, gyroHighFsr: 0, gyroMovementCalibThreshold: 0, gyroCalibDuration: 0, gyroOffsetYaw: 0, gyroCheckOverflow: 0, debugMode: 0, debugModeCount: 0, }; config.gyroSyncDenom = data.readU8(); config.pidProcessDenom = data.readU8(); config.useUnsyncedPwm = data.readU8() !== 0; config.fastPwmProtocol = (0, utils_1.toIdentifier)((0, features_1.escProtocols)(api), data.readU8()); config.motorPwmRate = data.readU16(); if (semver_1.default.gte(api, "1.24.0")) { config.digitalIdlePercent = data.readU16() / 100; } if (semver_1.default.gte(api, "1.25.0")) { const gyroUse32kHz = data.readU8(); if (semver_1.default.lt(api, "1.41.0")) { config.gyroUse32kHz = gyroUse32kHz !== 0; } } if (semver_1.default.gte(api, "1.42.0")) { config.motorPwmInversion = data.readU8(); // gyroToUse (read by MSP_SENSOR_ALIGNMENT) config.gyroToUse = data.readU8(); config.gyroHighFsr = data.readU8(); config.gyroMovementCalibThreshold = data.readU8(); config.gyroCalibDuration = data.readU16(); config.gyroOffsetYaw = data.readU16(); config.gyroCheckOverflow = data.readU8(); config.debugMode = data.readU8(); config.debugModeCount = data.readU8(); } return config; }; exports.readAdvancedConfig = readAdvancedConfig; const writeAdvancedConfig = async (port, config) => { var _a; const api = (0, msp_1.apiVersion)(port); const buffer = new msp_1.WriteBuffer(); buffer .push8(config.gyroSyncDenom) .push8(config.pidProcessDenom) .push8(config.useUnsyncedPwm ? 1 : 0) .push8((_a = (0, utils_1.fromIdentifier)((0, features_1.escProtocols)(api), config.fastPwmProtocol)) !== null && _a !== void 0 ? _a : config.fastPwmProtocol) .push16(config.motorPwmRate); if (semver_1.default.gte(api, "1.24.0")) { buffer.push16(config.digitalIdlePercent * 100); } if (semver_1.default.gte(api, "1.25.0")) { let gyroUse32kHz = 0; if (semver_1.default.lt(api, "1.41.0")) { gyroUse32kHz = config.gyroUse32kHz ? 1 : 0; } buffer.push8(gyroUse32kHz); } if (semver_1.default.gte(api, "1.42.0")) { buffer .push8(config.motorPwmInversion) .push8(config.gyroToUse) .push8(config.gyroHighFsr) .push8(config.gyroMovementCalibThreshold) .push16(config.gyroCalibDuration) .push16(config.gyroOffsetYaw) .push8(config.gyroCheckOverflow) .push8(config.debugMode); } await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_ADVANCED_CONFIG, data: buffer }); }; exports.writeAdvancedConfig = writeAdvancedConfig; exports.writePartialAdvancedConfig = (0, utils_1.partialWriteFunc)(exports.readAdvancedConfig, exports.writeAdvancedConfig); const ALLOWED_DSHOT_CONDITIONS = [types_1.Beepers.RX_SET, types_1.Beepers.RX_LOST]; const readBeeperConfig = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_BEEPER_CONFIG }); const api = (0, msp_1.apiVersion)(port); const beeperSchema = (0, features_1.beeperBits)(api); return { // For some reason, the flag bits are actually inverted for both // read and write conditions: (0, utils_1.unpackValues)(data.readU32(), beeperSchema, { inverted: true }), dshot: { tone: semver_1.default.gte(api, "1.37.0") ? data.readU8() : 0, conditions: semver_1.default.gte(api, "1.39.0") ? (0, utils_1.unpackValues)(data.readU32(), beeperSchema, { inverted: true, }).filter((beeper) => ALLOWED_DSHOT_CONDITIONS.includes(beeper)) : [], }, }; }; exports.readBeeperConfig = readBeeperConfig; const writeBeeperConfig = async (port, config) => { const api = (0, msp_1.apiVersion)(port); const beeperSchema = (0, features_1.beeperBits)(api); const buffer = new msp_1.WriteBuffer(); buffer.push32((0, utils_1.packValues)(config.conditions, beeperSchema, { inverted: true, })); if (semver_1.default.gte(api, "1.37.0")) { buffer.push8(config.dshot.tone); } if (semver_1.default.gte(api, "1.39.0")) { buffer.push32((0, utils_1.packValues)(config.dshot.conditions.filter((con) => ALLOWED_DSHOT_CONDITIONS.includes(con)), beeperSchema, { inverted: true })); } await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_BEEPER_CONFIG, data: buffer }); }; exports.writeBeeperConfig = writeBeeperConfig; exports.writePartialBeeperConfig = (0, utils_1.partialWriteFunc)(exports.readBeeperConfig, exports.writeBeeperConfig); const readDisabledSensors = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SENSOR_CONFIG }); const schema = (0, features_1.sensorBits)(); const disabled = []; schema.forEach((sensor) => { if (data.remaining() > 0 && data.read8() === 1) { disabled.push(sensor); } }); return disabled; }; exports.readDisabledSensors = readDisabledSensors; const writeDisabledSensors = async (port, disabledSensors) => { const buffer = new msp_1.WriteBuffer(); [types_1.Sensors.ACCELEROMETER, types_1.Sensors.BAROMETER, types_1.Sensors.MAGNETOMETER].forEach((sensor) => { buffer.push8(disabledSensors.includes(sensor) ? 1 : 0); }); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_SENSOR_CONFIG, data: buffer }); }; exports.writeDisabledSensors = writeDisabledSensors; const readRxConfig = async (port) => { const api = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RX_CONFIG }); const initial = { serialProvider: (0, utils_1.toIdentifier)((0, features_1.serialRxProviders)(api), data.readU8()), stick: { max: data.readU16(), center: data.readU16(), min: data.readU16(), }, spektrumSatBind: data.readU8(), rxMinUsec: data.readU16(), rxMaxUsec: data.readU16(), ...(semver_1.default.gte(api, "1.20.0") ? { interpolation: (0, utils_1.toIdentifier)((0, features_1.rcInterpolations)(), data.readU8()), interpolationInterval: data.readU8(), airModeActivateThreshold: data.readU16(), } : { interpolation: types_1.RcInterpolations.AUTO, interpolationInterval: 0, airModeActivateThreshold: 0, }), ...(semver_1.default.gte(api, "1.31.0") ? { spi: { protocol: (0, utils_1.toIdentifier)((0, features_1.spiRxProtocols)(api), data.readU8()), id: data.readU32(), rfChannelCount: data.readU8(), }, fpvCamAngleDegrees: data.readU8(), } : { spi: { protocol: types_1.SpiRxProtocols.NRF24_V202_250K, id: 0, rfChannelCount: 0, }, fpvCamAngleDegrees: 0, }), }; const smoothing = semver_1.default.gte(api, "1.40.0") ? { channels: (0, utils_1.toIdentifier)((0, features_1.rcSmoothingChannels)(), data.readU8()), type: (0, utils_1.toIdentifier)((0, features_1.rcSmoothingTypes)(), data.readU8()), inputCutoff: data.readU8(), derivativeCutoff: data.readU8(), inputType: (0, utils_1.toIdentifier)((0, features_1.rcSmoothingInputTypes)(), data.readU8()), derivativeType: (0, utils_1.toIdentifier)((0, features_1.rcSmoothingDerivativeTypes)(api), data.readU8()), } : { channels: types_1.RcSmoothingChannels.RP, type: types_1.RcSmoothingTypes.INTERPOLATION, inputCutoff: 0, derivativeCutoff: 0, inputType: types_1.RcSmoothingInputTypes.PT1, derivativeType: types_1.RcSmoothingDerivativeTypes.AUTO, }; return { ...initial, ...(semver_1.default.gte(api, "1.42.0") ? { usbCdcHidType: data.readU8() } : { usbCdcHidType: 0 }), rcSmoothing: { ...smoothing, ...(semver_1.default.gte(api, "1.42.0") ? { autoSmoothness: data.readU8(), } : { autoSmoothness: 0 }), }, }; }; exports.readRxConfig = readRxConfig; const writeRxConfig = async (port, config) => { var _a, _b, _c, _d, _e, _f, _g; const api = (0, msp_1.apiVersion)(port); const buffer = new msp_1.WriteBuffer(); buffer .push8((_a = (0, utils_1.fromIdentifier)((0, features_1.serialRxProviders)(api), config.serialProvider)) !== null && _a !== void 0 ? _a : config.serialProvider) .push16(config.stick.max) .push16(config.stick.center) .push16(config.stick.center) .push8(config.spektrumSatBind) .push16(config.rxMinUsec) .push16(config.rxMaxUsec); if (semver_1.default.gte(api, "1.20.0")) { buffer .push8((_b = (0, utils_1.fromIdentifier)((0, features_1.rcInterpolations)(), config.interpolation)) !== null && _b !== void 0 ? _b : config.interpolation) .push8(config.interpolationInterval) .push16(config.airModeActivateThreshold); } if (semver_1.default.gte(api, "1.31.0")) { buffer .push8((_c = (0, utils_1.fromIdentifier)((0, features_1.spiRxProtocols)(api), config.spi.protocol)) !== null && _c !== void 0 ? _c : config.spi.protocol) .push32(config.spi.id) .push8(config.spi.rfChannelCount) .push8(config.fpvCamAngleDegrees); } if (semver_1.default.gte(api, "1.40.0")) { buffer .push8((_d = (0, utils_1.fromIdentifier)((0, features_1.rcSmoothingChannels)(), config.rcSmoothing.channels)) !== null && _d !== void 0 ? _d : config.rcSmoothing.channels) .push8((_e = (0, utils_1.fromIdentifier)((0, features_1.rcSmoothingTypes)(), config.rcSmoothing.type)) !== null && _e !== void 0 ? _e : config.rcSmoothing.type) .push8(config.rcSmoothing.inputCutoff) .push8(config.rcSmoothing.derivativeCutoff) .push8((_f = (0, utils_1.fromIdentifier)((0, features_1.rcSmoothingInputTypes)(), config.rcSmoothing.inputType)) !== null && _f !== void 0 ? _f : config.rcSmoothing.inputType) .push8((_g = (0, utils_1.fromIdentifier)((0, features_1.rcSmoothingDerivativeTypes)(api), config.rcSmoothing.derivativeType)) !== null && _g !== void 0 ? _g : config.rcSmoothing.derivativeType); } if (semver_1.default.gte(api, "1.42.0")) { buffer.push8(config.usbCdcHidType).push8(config.rcSmoothing.autoSmoothness); } await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_RX_CONFIG, data: buffer }); }; exports.writeRxConfig = writeRxConfig; exports.writePartialRxConfig = (0, utils_1.partialWriteFunc)(exports.readRxConfig, exports.writeRxConfig); const readRxMap = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RX_MAP }); const schema = (0, features_1.channelLetters)(); const map = new Array(8).fill("A"); schema.forEach((letter) => { map[data.readU8()] = letter; }); return map; }; exports.readRxMap = readRxMap; const writeRxMap = async (port, map) => { const buffer = new msp_1.WriteBuffer(); const schema = (0, features_1.channelLetters)(); schema.forEach((letter) => { const value = typeof letter !== "number" ? map.indexOf(letter) : letter; buffer.push8(value); }); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_RX_MAP, data: buffer }); }; exports.writeRxMap = writeRxMap; const readRssiConfig = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_RSSI_CONFIG }); return { channel: data.readU8(), }; }; exports.readRssiConfig = readRssiConfig; const writeRssiConfig = async (port, config) => { const buffer = new msp_1.WriteBuffer(); buffer.push8(config.channel); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_RSSI_CONFIG, data: buffer }); }; exports.writeRssiConfig = writeRssiConfig; const readGpsConfig = async (port) => { const api = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_GPS_CONFIG }); // gps not enabled, not exactly good api from the FC if (data.byteLength === 0) { return { provider: types_1.GpsProtocols.NMEA, ubloxSbas: types_1.GpsSbasTypes.AUTO, autoConfig: false, autoBaud: false, homePointOnce: false, ubloxUseGalileo: false, }; } return { provider: (0, utils_1.toIdentifier)((0, features_1.gpsProtocols)(api), data.readU8()), ubloxSbas: data.readU8(), autoConfig: semver_1.default.gte(api, "1.34.0") ? data.readU8() === 1 : false, autoBaud: semver_1.default.gte(api, "1.34.0") ? data.readU8() === 1 : false, homePointOnce: semver_1.default.gte(api, "1.43.0") ? data.readU8() === 1 : false, ubloxUseGalileo: semver_1.default.gte(api, "1.43.0") ? data.readU8() === 1 : false, }; }; exports.readGpsConfig = readGpsConfig; const writeGpsConfig = async (port, config) => { var _a; const api = (0, msp_1.apiVersion)(port); const buffer = new msp_1.WriteBuffer(); buffer .push8((_a = (0, utils_1.fromIdentifier)((0, features_1.gpsProtocols)(api), config.provider)) !== null && _a !== void 0 ? _a : config.provider) .push8(config.ubloxSbas); if (semver_1.default.gte(api, "1.34.0")) { buffer.push8(config.autoConfig ? 1 : 0).push8(config.autoBaud ? 1 : 0); } if (semver_1.default.gte(api, "1.43.0")) { buffer .push8(config.homePointOnce ? 1 : 0) .push8(config.ubloxUseGalileo ? 1 : 0); } await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_GPS_CONFIG, data: buffer }); }; exports.writeGpsConfig = writeGpsConfig; const readBlackboxConfig = async (port) => { const api = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_BLACKBOX_CONFIG }); return { supported: (data.readU8() & 1) !== 0, device: (0, utils_1.toIdentifier)((0, features_1.blackboxDevices)(api), data.readU8()), rateNum: data.readU8(), rateDenom: data.readU8(), pDenom: semver_1.default.gte(api, "1.36.0") ? data.readU16() : 0, sampleRate: semver_1.default.gte(api, "1.44.0") ? data.readU8() : 0, }; }; exports.readBlackboxConfig = readBlackboxConfig; const writeBlackboxConfig = async (port, config) => { var _a; const api = (0, msp_1.apiVersion)(port); const buffer = new msp_1.WriteBuffer(); buffer .push8((_a = (0, utils_1.fromIdentifier)((0, features_1.blackboxDevices)(api), config.device)) !== null && _a !== void 0 ? _a : config.device) .push8(config.rateNum) .push8(config.rateDenom); if (semver_1.default.gte(api, "1.36.0")) { buffer.push16(config.pDenom); } if (semver_1.default.gte(api, "1.44.0")) { buffer.push8(config.sampleRate); } await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_BLACKBOX_CONFIG, data: buffer }); }; exports.writeBlackboxConfig = writeBlackboxConfig; exports.writePartialBlackboxConfig = (0, utils_1.partialWriteFunc)(exports.readBlackboxConfig, exports.writeBlackboxConfig); /** * Return the base 64 encoded result of the blackbox config */ const readDataFlashChunk = async (port, address, blockSize) => { const api = (0, msp_1.apiVersion)(port); const args = new msp_1.WriteBuffer(); args.push32(address); if (semver_1.default.gte(api, "1.31.0")) { args.push16(blockSize); } if (semver_1.default.gte(api, "1.36.0")) { args.push8(1); } const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_DATAFLASH_READ, data: args, timeout: 1000, match: (response) => response.readU32() === address, }); // ignore the address as this was // checked by the executor data.readU32(); const headerSize = semver_1.default.gte(api, "1.31.0") ? 7 : 4; const dataSize = semver_1.default.gte(api, "1.31.0") ? data.readU16() : data.buffer.byteLength - headerSize; const compressed = semver_1.default.gte(api, "1.31.0") && data.readU8() === 1; /* Strip that address off the front of the reply and deliver it separately so the caller doesn't have to * figure out the reply format: */ if (!compressed) { return Buffer.from(new Uint8Array(data.buffer, data.byteOffset + headerSize, dataSize)); } // Read compressed char count to avoid decoding stray bit sequences as bytes const compressedCharCount = data.readU16(); // Compressed format uses 2 additional bytes as a pseudo-header to denote the number of uncompressed bytes const compressedArray = Buffer.from(new Uint8Array(data.buffer, data.byteOffset + headerSize + 2, dataSize - 2)); const decompressedArray = (0, huffman_1.huffmanDecodeBuffer)(compressedArray, compressedCharCount); return decompressedArray; }; exports.readDataFlashChunk = readDataFlashChunk; const readDataFlashSummary = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_DATAFLASH_SUMMARY }); if (data.byteLength >= 13) { const flags = data.readU8(); return { ready: (flags & 1) !== 0, supported: (flags & 2) !== 0, sectors: data.readU32(), totalSize: data.readU32(), usedSize: data.readU32(), }; } // Firmware version too old to support MSP_DATAFLASH_SUMMARY return { ready: false, supported: false, sectors: 0, totalSize: 0, usedSize: 0, }; }; exports.readDataFlashSummary = readDataFlashSummary; const readSdCardSummary = async (port) => { const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SDCARD_SUMMARY }); const flags = data.readU8(); return { supported: (flags & 0x01) !== 0, state: data.readU8(), filesystemLastError: data.readU8(), freeSizeKB: data.readU32(), totalSizeKB: data.readU32(), }; }; exports.readSdCardSummary = readSdCardSummary; const eraseDataFlash = async (port) => { await (0, msp_1.execute)(port, { code: codes_1.default.MSP_DATAFLASH_ERASE }); }; exports.eraseDataFlash = eraseDataFlash; //# sourceMappingURL=index.js.map