UNPKG

@betaflight/api

Version:

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

296 lines 15.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.writeOSDChar = exports.writeOSDTimer = exports.writeOSDStatisticItem = exports.writePartialOSDParameters = exports.writeOSDUnitMode = exports.writeOSDVideoSystem = exports.writeOSDSelectedProfile = exports.writeOSDWarning = exports.writeOSDAlarm = exports.writeOSDDisplayItem = exports.readOSDConfig = exports.OSDPrecisionTypes = exports.OSDStatisticFields = exports.OSDUnitTypes = exports.osdFields = exports.OSDFields = exports.osdWarnings = exports.OSDWarnings = exports.osdTimerSources = exports.OSDTimerSources = exports.osdAlarms = exports.OSDAlarms = exports.OSDVideoTypes = void 0; const semver_1 = __importDefault(require("semver")); const msp_1 = require("@betaflight/msp"); const utils_1 = require("../utils"); const constants_1 = require("./constants"); Object.defineProperty(exports, "osdFields", { enumerable: true, get: function () { return constants_1.osdFields; } }); Object.defineProperty(exports, "osdTimerSources", { enumerable: true, get: function () { return constants_1.osdTimerSources; } }); Object.defineProperty(exports, "osdWarnings", { enumerable: true, get: function () { return constants_1.osdWarnings; } }); Object.defineProperty(exports, "osdAlarms", { enumerable: true, get: function () { return constants_1.osdAlarms; } }); const codes_1 = __importDefault(require("../codes")); const types_1 = require("./types"); Object.defineProperty(exports, "OSDVideoTypes", { enumerable: true, get: function () { return types_1.OSDVideoTypes; } }); Object.defineProperty(exports, "OSDAlarms", { enumerable: true, get: function () { return types_1.OSDAlarms; } }); Object.defineProperty(exports, "OSDTimerSources", { enumerable: true, get: function () { return types_1.OSDTimerSources; } }); Object.defineProperty(exports, "OSDWarnings", { enumerable: true, get: function () { return types_1.OSDWarnings; } }); Object.defineProperty(exports, "OSDFields", { enumerable: true, get: function () { return types_1.OSDFields; } }); Object.defineProperty(exports, "OSDUnitTypes", { enumerable: true, get: function () { return types_1.OSDUnitTypes; } }); Object.defineProperty(exports, "OSDStatisticFields", { enumerable: true, get: function () { return types_1.OSDStatisticFields; } }); Object.defineProperty(exports, "OSDPrecisionTypes", { enumerable: true, get: function () { return types_1.OSDPrecisionTypes; } }); const isVisible = (positionData, profile) => positionData !== -1 && (positionData & (constants_1.OSD_VALUE_VISIBLE << profile)) !== 0; const unpackPosition = (positionData) => ({ x: positionData & 0x001f, y: (positionData >> 5) & 0x001f, }); const unpackLegacyPosition = (positionData) => positionData === -1 ? { x: 0, y: 0 } : { x: positionData, y: 0 }; const packLegacyPosition = (position, visible) => { if (visible) { return position.x === -1 ? 0 : position.x; } return -1; }; const inWriteOrder = (values, sortOrder, subsitutions) => sortOrder.map((orderedKey, i) => { var _a; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return (_a = values.find(({ key }) => key === orderedKey)) !== null && _a !== void 0 ? _a : subsitutions[i]; }); const readOSDConfig = async (port) => { var _a, _b; const api = (0, msp_1.apiVersion)(port); const data = await (0, msp_1.execute)(port, { code: codes_1.default.MSP_OSD_CONFIG }); const expectedDisplayItems = (0, constants_1.osdFields)(api); const flagsData = data.readU8(); const hasOSD = flagsData !== 0; const flag0Active = (0, utils_1.bitCheck)(flagsData, 0); const videoSystem = hasOSD ? (_a = constants_1.OSD_VIDEO_VALUE_TO_TYPE[data.readU8()]) !== null && _a !== void 0 ? _a : types_1.OSDVideoTypes.AUTO : types_1.OSDVideoTypes.AUTO; const unitMode = hasOSD && semver_1.default.gte(api, "1.21.0") && flag0Active ? (_b = constants_1.OSD_UNIT_VALUE_TO_TYPE[data.readU8()]) !== null && _b !== void 0 ? _b : types_1.OSDUnitTypes.IMPERIAL : types_1.OSDUnitTypes.IMPERIAL; const alarms = hasOSD && semver_1.default.gte(api, "1.21.0") && flag0Active ? [ { key: types_1.OSDAlarms.RSSI, value: data.readU8() }, { key: types_1.OSDAlarms.CAP, value: data.readU16() }, ] : []; let displayItemsCount = expectedDisplayItems.length; if (hasOSD && semver_1.default.gte(api, "1.36.0") && flag0Active) { // This value was obsoleted by the introduction of configurable timers, and has been reused to encode the number of display elements sent in this command data.readU8(); const tmp = data.readU8(); if (semver_1.default.gte(api, "1.37.0")) { displayItemsCount = tmp; } } else { alarms.push({ key: types_1.OSDAlarms.TIME, value: data.readU16() }); } if (hasOSD && semver_1.default.gte(api, "1.36.0") && flag0Active) { alarms.push({ key: types_1.OSDAlarms.ALT, value: data.readU16() }); } const haveMax7456Video = (0, utils_1.bitCheck)(flagsData, 4) || (flagsData === 1 && semver_1.default.lt(api, "1.34.0")); const flags = { hasOSD, haveMax7456Video, isMax7456Detected: (0, utils_1.bitCheck)(flagsData, 5) || (haveMax7456Video && semver_1.default.lt(api, "1.43.0")), haveOsdFeature: (0, utils_1.bitCheck)(flagsData, 0) || (flagsData === 1 && semver_1.default.lt(api, "1.34.0")), isOsdSlave: (0, utils_1.bitCheck)(flagsData, 1) && semver_1.default.gte(api, "1.34.0"), }; // Read display element positions, the parsing is done later because we need the number of profiles const itemPositions = semver_1.default.gte(api, "1.21.0") ? (0, utils_1.times)(() => data.readU16(), displayItemsCount) : (0, utils_1.times)(() => data.read16(), displayItemsCount); const expectedStaticFields = (0, constants_1.osdStatisticFields)(api); const staticItems = semver_1.default.gte(api, "1.36.0") ? (0, utils_1.times)((i) => { var _a; return ({ key: (_a = expectedStaticFields[i]) !== null && _a !== void 0 ? _a : types_1.OSDStatisticFields.UNKNOWN, enabled: data.readU8() === 1, }); }, data.readU8()) : []; // Parse configurable timers const timersCount = data.readU8(); const timerSources = (0, constants_1.osdTimerSources)(api); const timers = semver_1.default.gte(api, "1.36.0") ? (0, utils_1.times)((i) => { var _a, _b; const timerData = data.readU16(); return { key: i, src: (_a = timerSources[timerData & 0x0f]) !== null && _a !== void 0 ? _a : types_1.OSDTimerSources.UNKNOWN, precision: (_b = constants_1.OSD_PRECISION_VALUE_TO_TYPE[(timerData >> 4) & 0x0f]) !== null && _b !== void 0 ? _b : types_1.OSDPrecisionTypes.SECOND, time: (timerData >> 8) & 0xff, }; }, timersCount) : []; // Parse warning const expectedWarnings = (0, constants_1.osdWarnings)(api); let warningCount = expectedWarnings.length; let warningFlags = data.readU16(); if (semver_1.default.gte(api, "1.41.0")) { warningCount = data.readU8(); // the flags were replaced with a 32bit version warningFlags = data.readU32(); } const warnings = semver_1.default.gte(api, "1.36.0") ? (0, utils_1.times)((i) => { var _a; return ({ key: (_a = expectedWarnings[i]) !== null && _a !== void 0 ? _a : types_1.OSDWarnings.UNKNOWN, enabled: (warningFlags & (1 << i)) !== 0, }); }, warningCount) : []; const osdProfiles = semver_1.default.gte(api, "1.41.0") ? { count: data.readU8(), selected: data.readU8() - 1, } : { count: 1, selected: 0, }; const parameters = { overlayRadioMode: semver_1.default.gte(api, "1.41.0") ? data.readU8() : 0, cameraFrameWidth: semver_1.default.gte(api, "1.43.0") ? data.readU8() : 24, cameraFrameHeight: semver_1.default.gte(api, "1.43.0") ? data.readU8() : 11, }; const displayItems = itemPositions.map((positionData, i) => { var _a; return ({ key: (_a = expectedDisplayItems[i]) !== null && _a !== void 0 ? _a : types_1.OSDFields.UNKNOWN, position: semver_1.default.gte(api, "1.21.0") ? unpackPosition(positionData) : unpackLegacyPosition(positionData), visibilityProfiles: (0, utils_1.times)((profileIndex) => isVisible(positionData, profileIndex), osdProfiles.count), }); }); return { flags, statisticItems: staticItems, displayItems, alarms, warnings, timers, videoSystem, osdProfiles, parameters, unitMode, }; }; exports.readOSDConfig = readOSDConfig; const writeOSDDisplayItem = async (port, { key, visibilityProfiles, position }) => { var _a; const data = new msp_1.WriteBuffer(); const api = (0, msp_1.apiVersion)(port); const itemOrder = (0, constants_1.osdFields)(api); const index = itemOrder.indexOf(key); if (index === -1) { throw new Error(`OSDFields.${types_1.OSDFields[key]} does not exist on device`); } const packedPosition = semver_1.default.gte(api, "1.21.0") ? visibilityProfiles.reduce((packedVisible, visibilityProfile, i) => packedVisible | (visibilityProfile ? constants_1.OSD_VALUE_VISIBLE << i : 0), 0) | ((position.y & 0x001f) << 5) | position.x : packLegacyPosition(position, (_a = visibilityProfiles[0]) !== null && _a !== void 0 ? _a : false); data.push8(index); data.push16(packedPosition); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_OSD_CONFIG, data, }); }; exports.writeOSDDisplayItem = writeOSDDisplayItem; const writeOSDOtherData = async (port, { flags, videoSystem, unitMode, alarms, warnings, osdProfiles, parameters, }) => { var _a, _b, _c, _d, _e, _f, _g, _h; const api = (0, msp_1.apiVersion)(port); const data = new msp_1.WriteBuffer(); data.push(-1, videoSystem); if (flags.hasOSD && semver_1.default.gte(api, "1.21.0")) { data.push8(unitMode); // watch out, order matters! match the firmware data.push8((_b = (_a = alarms[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 0); data.push16((_d = (_c = alarms[1]) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : 0); if (semver_1.default.lt(api, "1.36.0")) { data.push16((_f = (_e = alarms[2]) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : 0); } else { // This value is unused by the firmware with configurable timers data.push16(0); } data.push16((_h = (_g = alarms[3]) === null || _g === void 0 ? void 0 : _g.value) !== null && _h !== void 0 ? _h : 0); if (semver_1.default.gte(api, "1.37.0")) { const warningFlags = warnings.reduce((acc, warning, i) => (warning.enabled ? acc | (1 << i) : acc), 0); data.push16(warningFlags); if (semver_1.default.gte(api, "1.41.0")) { data.push32(warningFlags); data.push8(osdProfiles.selected + 1); data.push8(parameters.overlayRadioMode); } if (semver_1.default.gte(api, "1.43.0")) { data.push8(parameters.cameraFrameWidth); data.push8(parameters.cameraFrameHeight); } } } await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_OSD_CONFIG, data }); }; const writeOSDAlarm = async (port, alarm) => { const osdConfig = await (0, exports.readOSDConfig)(port); await writeOSDOtherData(port, { ...osdConfig, alarms: inWriteOrder([alarm], (0, constants_1.osdAlarms)(), osdConfig.alarms), }); }; exports.writeOSDAlarm = writeOSDAlarm; const writeOSDWarning = async (port, warning) => { const api = (0, msp_1.apiVersion)(port); const osdConfig = await (0, exports.readOSDConfig)(port); await writeOSDOtherData(port, { ...osdConfig, warnings: inWriteOrder([warning], (0, constants_1.osdWarnings)(api), osdConfig.warnings), }); }; exports.writeOSDWarning = writeOSDWarning; const writeOSDSelectedProfile = async (port, selectedIndex) => { const osdConfig = await (0, exports.readOSDConfig)(port); await writeOSDOtherData(port, { ...osdConfig, osdProfiles: { ...osdConfig.osdProfiles, selected: selectedIndex }, }); }; exports.writeOSDSelectedProfile = writeOSDSelectedProfile; const writeOSDVideoSystem = async (port, videoSystem) => { const osdConfig = await (0, exports.readOSDConfig)(port); await writeOSDOtherData(port, { ...osdConfig, videoSystem }); }; exports.writeOSDVideoSystem = writeOSDVideoSystem; const writeOSDUnitMode = async (port, unitMode) => { const osdConfig = await (0, exports.readOSDConfig)(port); await writeOSDOtherData(port, { ...osdConfig, unitMode }); }; exports.writeOSDUnitMode = writeOSDUnitMode; const writePartialOSDParameters = async (port, parameters) => { const osdConfig = await (0, exports.readOSDConfig)(port); await writeOSDOtherData(port, { ...osdConfig, parameters: (0, utils_1.mergeDeep)(osdConfig.parameters, parameters), }); }; exports.writePartialOSDParameters = writePartialOSDParameters; const writeOSDStatisticItem = async (port, { key, enabled }) => { const data = new msp_1.WriteBuffer(); const staticItemsOrder = (0, constants_1.osdStatisticFields)((0, msp_1.apiVersion)(port)); const index = staticItemsOrder.indexOf(key); if (index === -1) { throw new Error(`OSDStaticFields.${types_1.OSDStatisticFields[key]} does not exist on device`); } data.push8(index); data.push16(Number(enabled)); data.push8(0); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_OSD_CONFIG, data }); }; exports.writeOSDStatisticItem = writeOSDStatisticItem; const writeOSDTimer = async (port, timer) => { const data = new msp_1.WriteBuffer(); data.push(-2, timer.key); data.push16((timer.src & 0x0f) | ((timer.precision & 0x0f) << 4) | ((timer.time & 0xff) << 8)); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_SET_OSD_CONFIG, data }); }; exports.writeOSDTimer = writeOSDTimer; const writeOSDChar = async (port, charIndex, charBytes) => { const buffer = new msp_1.WriteBuffer(); buffer.push8(charIndex); buffer.push(...charBytes); await (0, msp_1.execute)(port, { code: codes_1.default.MSP_OSD_CHAR_WRITE, data: buffer }); }; exports.writeOSDChar = writeOSDChar; //# sourceMappingURL=index.js.map