@betaflight/api
Version:
A high-level API to read data from betaflight flight controllers
216 lines • 7.78 kB
JavaScript
import { apiVersion, execute, WriteBuffer } from "@betaflight/msp";
import semver from "semver";
import codes from "../codes";
import { times } from "../utils";
import { MeterIndentiers, BatteryCurrentMeterSources, BatteryVoltageMeterSources, } from "./types";
export { MeterIndentiers, BatteryCurrentMeterSources, BatteryVoltageMeterSources, };
export const readVoltageMeters = async (port) => {
const data = await execute(port, { code: codes.MSP_VOLTAGE_METERS });
return times(() => ({
id: data.readU8(),
voltage: data.readU8() / 10.0,
}), data.byteLength / 2);
};
export const readCurrentMeters = async (port) => {
const data = await execute(port, { code: codes.MSP_CURRENT_METERS });
return times(() => ({
id: data.readU8(),
mAhDrawn: data.readU16(),
amperage: data.readU16() / 1000, // A
}), data.byteLength / 5);
};
export const readLegacyVoltageMeterConfig = async (port) => {
const api = apiVersion(port);
if (semver.gte(api, "1.36.0")) {
throw new Error("Not a legacy device");
}
const data = await execute(port, { code: codes.MSP_VOLTAGE_METER_CONFIG });
return {
vbat: {
scale: data.readU8(),
minCellVoltage: data.readU8() / 10,
maxCellVoltage: data.readU8() / 10,
warningCellVoltage: data.readU8() / 10, // 10-50
},
meterType: semver.gte(api, "1.23.0") ? data.readU8() : 0,
};
};
export const writeLegacyVoltageMeterConfig = async (port, config) => {
const api = apiVersion(port);
if (semver.gte(api, "1.36.0")) {
throw new Error("Not a legacy device");
}
const buffer = new WriteBuffer();
buffer
.push8(config.vbat.scale)
.push8(Math.round(config.vbat.minCellVoltage * 10))
.push8(Math.round(config.vbat.maxCellVoltage * 10))
.push8(Math.round(config.vbat.warningCellVoltage * 10));
if (semver.gte(api, "1.23.0")) {
buffer.push8(config.meterType);
}
await execute(port, {
code: codes.MSP_SET_VOLTAGE_METER_CONFIG,
data: buffer,
});
};
export const readVoltageMeterConfigs = async (port) => {
const api = apiVersion(port);
if (semver.lt(api, "1.36.0")) {
throw new Error("Use readLegacyVoltageMeterConfig");
}
const data = await execute(port, { code: codes.MSP_VOLTAGE_METER_CONFIG });
return times(() => {
const subframeLength = data.readU8();
if (subframeLength !== 5) {
// discard this config because it's the wrong length
times(() => data.readU8(), subframeLength);
return undefined;
}
return {
id: data.readU8(),
sensorType: data.readU8(),
vbat: {
scale: data.readU8(),
resDivVal: data.readU8(),
resDivMultiplier: data.readU8(),
},
};
}, data.readU8()).filter(Boolean);
};
export const writeVoltageMeterConfig = async (port, id, config) => {
const api = apiVersion(port);
if (semver.lt(api, "1.36.0")) {
throw new Error("Use writeLegacyVoltageMeterConfig");
}
const buffer = new WriteBuffer();
buffer
.push8(id)
.push8(config.vbat.scale)
.push8(config.vbat.resDivVal)
.push8(config.vbat.resDivMultiplier);
await execute(port, {
code: codes.MSP_SET_VOLTAGE_METER_CONFIG,
data: buffer,
});
};
export const readLegacyCurrentMeterConfig = async (port) => {
const api = apiVersion(port);
if (semver.lt(api, "1.36.0")) {
throw new Error("Use readCurrentMeterConfigs");
}
const data = await execute(port, { code: codes.MSP_CURRENT_METER_CONFIG });
return {
scale: data.read16(),
offset: data.read16(),
meterType: data.readU8(),
batteryCapacity: data.readU16(),
};
};
export const writeLegacyCurrentMeterConfig = async (port, config) => {
const api = apiVersion(port);
if (semver.lt(api, "1.36.0")) {
throw new Error("Use readCurrentMeterConfigs");
}
const buffer = new WriteBuffer();
buffer
.push16(config.scale)
.push16(config.offset)
.push8(config.meterType)
.push16(config.batteryCapacity);
await execute(port, {
code: codes.MSP_SET_CURRENT_METER_CONFIG,
data: buffer,
});
};
export const readCurrentMeterConfigs = async (port) => {
const api = apiVersion(port);
if (semver.lt(api, "1.36.0")) {
throw new Error("Use readLegacyCurrentMeterConfig");
}
const data = await execute(port, { code: codes.MSP_CURRENT_METER_CONFIG });
return times(() => {
const subframeLength = data.readU8();
if (subframeLength !== 6) {
// discard this config because it's the wrong length
times(() => data.readU8(), subframeLength);
return undefined;
}
return {
id: data.readU8(),
sensorType: data.readU8(),
scale: data.read16(),
offset: data.read16(),
};
}, data.readU8()).filter(Boolean);
};
export const writeCurrentMeterConfig = async (port, id, config) => {
const api = apiVersion(port);
if (semver.lt(api, "1.36.0")) {
throw new Error("Use writeLegacyCurrentMeterConfig");
}
const buffer = new WriteBuffer();
buffer.push8(id).push16(config.scale).push16(config.offset);
await execute(port, {
code: codes.MSP_SET_CURRENT_METER_CONFIG,
data: buffer,
});
};
export const readBatteryState = async (port) => {
const api = apiVersion(port);
const data = await execute(port, { code: codes.MSP_BATTERY_STATE });
return {
cellCount: data.readU8(),
capacity: data.readU16(),
// @ts-expect-error typescript is erroring here
// but this shouldn't be a problem
voltage: data.readU8() / 10,
mAhDrawn: data.readU16(),
amperage: data.readU16() / 100,
...(semver.gte(api, "1.41.0")
? {
batteryState: data.readU8(),
voltage: data.readU16() / 100,
}
: { batteryState: 0 }),
};
};
export const readBatteryConfig = async (port) => {
const api = apiVersion(port);
const data = await execute(port, { code: codes.MSP_BATTERY_CONFIG });
const config = {
vbat: {
minCellVoltage: data.readU8() / 10,
maxCellVoltage: data.readU8() / 10,
warningCellVoltage: data.readU8() / 10, // 10-50
},
capacity: data.readU16(),
voltageMeterSource: data.readU8(),
currentMeterSource: data.readU8(),
};
if (semver.gte(api, "1.41.0")) {
config.vbat.minCellVoltage = data.readU16() / 100;
config.vbat.maxCellVoltage = data.readU16() / 100;
config.vbat.warningCellVoltage = data.readU16() / 100;
}
return config;
};
export const writeBatteryConfig = async (port, config) => {
const api = apiVersion(port);
const buffer = new WriteBuffer();
buffer
.push8(Math.round(config.vbat.minCellVoltage * 10))
.push8(Math.round(config.vbat.maxCellVoltage * 10))
.push8(Math.round(config.vbat.warningCellVoltage * 10))
.push16(config.capacity)
.push8(config.voltageMeterSource)
.push8(config.currentMeterSource);
if (semver.gte(api, "1.41.0")) {
buffer
.push16(Math.round(config.vbat.minCellVoltage * 100))
.push16(Math.round(config.vbat.maxCellVoltage * 100))
.push16(Math.round(config.vbat.warningCellVoltage * 100));
}
await execute(port, { code: codes.MSP_SET_BATTERY_CONFIG, data: buffer });
};
//# sourceMappingURL=index.js.map