@betaflight/api
Version:
A high-level API to read data from betaflight flight controllers
296 lines • 15.1 kB
JavaScript
;
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