@betaflight/api
Version:
A high-level API to read data from betaflight flight controllers
177 lines • 6.37 kB
JavaScript
import { apiVersion, execute, WriteBuffer } from "@betaflight/msp";
import semver from "semver";
import codes from "../codes";
import { partialWriteFunc, times } from "../utils";
import { VtxDeviceTypes, } from "./types";
export { VtxDeviceTypes };
export const readVtxConfig = async (port) => {
const api = apiVersion(port);
const data = await execute(port, { code: codes.MSP_VTX_CONFIG });
return {
type: data.readU8(),
band: data.readU8(),
channel: data.readU8(),
power: data.readU8(),
pitMode: data.readU8() !== 0,
frequency: data.readU16(),
deviceReady: data.readU8() !== 0,
lowPowerDisarm: data.readU8(),
...(semver.gte(api, "1.42.0")
? {
pitModeFrequency: data.readU16(),
table: {
available: data.readU8() !== 0,
numBands: data.readU8(),
numBandChannels: data.readU8(),
numPowerLevels: data.readU8(),
},
}
: {
pitModeFrequency: 0,
table: {
available: false,
numBands: 0,
numBandChannels: 0,
numPowerLevels: 0,
},
}),
};
};
export const writeVtxConfig = async (port, config, clearVtxTable = false) => {
const buffer = new WriteBuffer();
const api = apiVersion(port);
buffer
.push16(config.frequency)
.push8(config.power)
.push8(config.pitMode ? 1 : 0)
.push8(config.lowPowerDisarm);
if (semver.gte(api, "1.42.0")) {
buffer
.push16(config.pitModeFrequency)
.push8(config.band)
.push8(config.channel)
.push16(config.frequency)
.push8(config.table.numBands)
.push8(config.table.numBandChannels)
.push8(config.table.numPowerLevels)
.push8(clearVtxTable ? 1 : 0);
}
await execute(port, { code: codes.MSP_SET_VTX_CONFIG, data: buffer });
};
export const clearVtxTable = async (port) => {
const config = await readVtxConfig(port);
await writeVtxConfig(port, config, true);
};
export const writePartialVtxConfig = partialWriteFunc(readVtxConfig, writeVtxConfig);
/**
* Read the VTX table row, row number indexes from 1
*/
export const readVtxTablePowerLevelsRow = async (port, rowNumber) => {
const buffer = new WriteBuffer();
buffer.push8(rowNumber);
const data = await execute(port, {
code: codes.MSP_VTXTABLE_POWERLEVEL,
data: buffer,
});
return {
rowNumber: data.readU8(),
value: data.readU16(),
label: String.fromCharCode(...times(() => data.readU8(), data.readU8())),
};
};
export const writeVtxTablePowerLevelsRow = async (port, row) => {
const buffer = new WriteBuffer();
buffer.push8(row.rowNumber).push16(row.value);
buffer.push8(row.label.length);
buffer.push(...Buffer.from(row.label));
await execute(port, {
code: codes.MSP_SET_VTXTABLE_POWERLEVEL,
data: buffer,
});
};
/**
* Read the VTX table row, row number indexes from 1
*/
export const readVtxTableBandsRow = async (port, rowNumber) => {
const buffer = new WriteBuffer();
buffer.push8(rowNumber);
const data = await execute(port, {
code: codes.MSP_VTXTABLE_BAND,
data: buffer,
});
return {
rowNumber: data.readU8(),
name: String.fromCharCode(...times(() => data.readU8(), data.readU8())),
letter: String.fromCharCode(data.readU8()),
isFactoryBand: data.readU8() !== 0,
frequencies: times(() => data.readU16(), data.readU8()),
};
};
export const writeVtxTableBandsRow = async (port, row) => {
const buffer = new WriteBuffer();
buffer.push8(row.rowNumber);
buffer.push8(row.name.length);
buffer.push(...Buffer.from(row.name));
if (row.letter !== "") {
buffer.push8(row.letter.charCodeAt(0));
}
else {
buffer.push8(" ".charCodeAt(0));
}
buffer.push8(row.isFactoryBand ? 1 : 0);
buffer.push8(row.frequencies.length);
row.frequencies.forEach((frequency) => {
buffer.push16(frequency);
});
await execute(port, { code: codes.MSP_SET_VTXTABLE_BAND, data: buffer });
};
export const readVtxDeviceStatus = async (port) => {
const data = await execute(port, { code: codes.MSP2_GET_VTX_DEVICE_STATUS });
if (data.byteLength < 1) {
return undefined;
}
const vtxType = data.readU8();
const deviceIsReady = Boolean(data.readU8());
const isBandAndChannelAvailable = Boolean(data.readU8());
const band = data.readU8();
const channel = data.readU8();
const powerIndexAvailable = Boolean(data.readU8());
const powerIndex = data.readU8();
const frequencyAvailable = Boolean(data.readU8());
const frequency = data.readU16();
const vtxStatusAvailable = Boolean(data.readU8());
const vtxStatus = data.readU32(); // pitmode and/or locked
const powerLevelCount = data.readU8();
const powersAndLevels = times(() => [data.readU16(), data.readU16()], powerLevelCount);
const baseConfig = {
deviceIsReady,
band: isBandAndChannelAvailable ? band : undefined,
channel: isBandAndChannelAvailable ? channel : undefined,
powerIndex: powerIndexAvailable ? powerIndex : undefined,
frequency: frequencyAvailable ? frequency : undefined,
vtxStatus: vtxStatusAvailable ? vtxStatus : undefined,
levels: powersAndLevels.map((value) => value[0]),
powers: powersAndLevels.map((value) => value[1]),
};
data.readU8(); // custom device status size
switch (vtxType) {
case VtxDeviceTypes.VTXDEV_SMARTAUDIO:
return {
type: vtxType,
version: data.readU8(),
mode: data.readU8(),
orfreq: data.readU8(),
willBootIntoPitMode: Boolean(data.readU8()),
...baseConfig,
};
case VtxDeviceTypes.VTXDEV_RTC6705:
case VtxDeviceTypes.VTXDEV_TRAMP:
case VtxDeviceTypes.VTXDEV_UNKNOWN:
default:
return {
type: vtxType,
...baseConfig,
};
}
};
//# sourceMappingURL=index.js.map