di-sensors
Version:
Drivers and examples for using DI_Sensors in Node.js
807 lines (628 loc) • 29.9 kB
JavaScript
// https://www.dexterindustries.com/GoPiGo/
// https://github.com/DexterInd/DI_Sensors
//
// Copyright (c) 2017 Dexter Industries
// Released under the MIT license (http://choosealicense.com/licenses/mit/).
// For more information see https://github.com/DexterInd/GoPiGo3/blob/master/LICENSE.md
const Sensor = require('./base/sensor');
class VL53L0X extends Sensor {
static SYSRANGE_START = 0x00;
static SYSTEM_THRESH_HIGH = 0x0C;
static SYSTEM_THRESH_LOW = 0x0E;
static SYSTEM_SEQUENCE_CONFIG = 0x01;
static SYSTEM_RANGE_CONFIG = 0x09;
static SYSTEM_INTERMEASUREMENT_PERIOD = 0x04;
static SYSTEM_INTERRUPT_CONFIG_GPIO = 0x0A;
static GPIO_HV_MUX_ACTIVE_HIGH = 0x84;
static SYSTEM_INTERRUPT_CLEAR = 0x0B;
static RESULT_INTERRUPT_STATUS = 0x13;
static RESULT_RANGE_STATUS = 0x14;
static RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN = 0xBC;
static RESULT_CORE_RANGING_TOTAL_EVENTS_RTN = 0xC0;
static RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF = 0xD0;
static RESULT_CORE_RANGING_TOTAL_EVENTS_REF = 0xD4;
static RESULT_PEAK_SIGNAL_RATE_REF = 0xB6;
static ALGO_PART_TO_PART_RANGE_OFFSET_MM = 0x28;
static I2C_SLAVE_DEVICE_ADDRESS = 0x8A;
static MSRC_CONFIG_CONTROL = 0x60;
static PRE_RANGE_CONFIG_MIN_SNR = 0x27;
static PRE_RANGE_CONFIG_VALID_PHASE_LOW = 0x56;
static PRE_RANGE_CONFIG_VALID_PHASE_HIGH = 0x57;
static PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT = 0x64;
static FINAL_RANGE_CONFIG_MIN_SNR = 0x67;
static FINAL_RANGE_CONFIG_VALID_PHASE_LOW = 0x47;
static FINAL_RANGE_CONFIG_VALID_PHASE_HIGH = 0x48;
static FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT = 0x44;
static PRE_RANGE_CONFIG_SIGMA_THRESH_HI = 0x61;
static PRE_RANGE_CONFIG_SIGMA_THRESH_LO = 0x62;
static PRE_RANGE_CONFIG_VCSEL_PERIOD = 0x50;
static PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x51;
static PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO = 0x52;
static SYSTEM_HISTOGRAM_BIN = 0x81;
static HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT = 0x33;
static HISTOGRAM_CONFIG_READOUT_CTRL = 0x55;
static FINAL_RANGE_CONFIG_VCSEL_PERIOD = 0x70;
static FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI = 0x71;
static FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO = 0x72;
static CROSSTALK_COMPENSATION_PEAK_RATE_MCPS = 0x20;
static MSRC_CONFIG_TIMEOUT_MACROP = 0x46;
static SOFT_RESET_GO2_SOFT_RESET_N = 0xBF;
static IDENTIFICATION_MODEL_ID = 0xC0;
static IDENTIFICATION_REVISION_ID = 0xC2;
static OSC_CALIBRATE_VAL = 0xF8;
static GLOBAL_CONFIG_VCSEL_WIDTH = 0x32;
static GLOBAL_CONFIG_SPAD_ENABLES_REF_0 = 0xB0;
static GLOBAL_CONFIG_SPAD_ENABLES_REF_1 = 0xB1;
static GLOBAL_CONFIG_SPAD_ENABLES_REF_2 = 0xB2;
static GLOBAL_CONFIG_SPAD_ENABLES_REF_3 = 0xB3;
static GLOBAL_CONFIG_SPAD_ENABLES_REF_4 = 0xB4;
static GLOBAL_CONFIG_SPAD_ENABLES_REF_5 = 0xB5;
static GLOBAL_CONFIG_REF_EN_START_SELECT = 0xB6;
static DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD = 0x4E;
static DYNAMIC_SPAD_REF_EN_START_OFFSET = 0x4F;
static POWER_MANAGEMENT_GO1_POWER_FORCE = 0x80;
static VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV = 0x89;
static ALGO_PHASECAL_LIM = 0x30;
static ALGO_PHASECAL_CONFIG_TIMEOUT = 0x30;
static ADDRESS_DEFAULT = 0x29;
static ADDRESS = VL53L0X.ADDRESS_DEFAULT;
static VcselPeriodPreRange = 0;
static VcselPeriodFinalRange = 1;
constructor(address = 0x2A, timeout = 0.5, bus = 'RPI_1') {
super(bus, VL53L0X.ADDRESS);
this.ioTimeout = 0;
this.didTimeout = false;
try {
this.reset(address);
} catch (err) {
console.log(err);
this.reset(VL53L0X.ADDRESS);
}
this.setAddress(address);
this.init();
this.setTimeout(timeout);
}
reset(address) {
try {
this.i2c.setAddress(address);
this.i2c.writeReg8(VL53L0X.SOFT_RESET_GO2_SOFT_RESET_N, 0x00);
} catch (err) {
console.log(err);
// do nothing
}
VL53L0X.ADDRESS = VL53L0X.ADDRESS_DEFAULT;
this.i2c.setAddress(VL53L0X.ADDRESS);
let value = true;
let t1 = new Date().getTime();
while (value) {
value = this.i2c.readReg8u(VL53L0X.IDENTIFICATION_MODEL_ID);
const t2 = new Date().getTime();
if (t2 - t1 >= 0.1) {
throw new Error('I/O Error');
}
this.i2c.mwait(1);
}
this.i2c.writeReg8(VL53L0X.SOFT_RESET_GO2_SOFT_RESET_N, 0x01);
value = false;
t1 = new Date().getTime();
while (!value) {
value = this.i2c.readReg8u(VL53L0X.IDENTIFICATION_MODEL_ID);
const t2 = new Date().getTime();
if (t2 - t1 >= 0.1) {
throw new Error('I/O Error');
}
this.i2c.mwait(1);
}
}
setAddress(address) {
address &= 0x7f;
try {
this.i2c.writeReg8(VL53L0X.I2C_SLAVE_DEVICE_ADDRESS, address);
VL53L0X.ADDRESS = address;
this.i2c.setAddress(VL53L0X.ADDRESS);
} catch (err) {
console.log(err);
this.i2c.setAddress(address);
this.i2c.writeReg8(VL53L0X.I2C_SLAVE_DEVICE_ADDRESS, address);
VL53L0X.ADDRESS = address;
this.i2c.setAddress(VL53L0X.ADDRESS);
}
}
init() {
this.i2c.writeReg8(VL53L0X.VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV, (this.i2c.readReg8u(VL53L0X.VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01)); // set bit 0
// "Set I2C standard mode"
this.i2c.writeReg8(0x88, 0x00);
this.i2c.writeReg8(0x80, 0x01);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x00, 0x00);
this.stopVariable = this.i2c.readReg8u(0x91);
this.i2c.writeReg8(0x00, 0x01);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x80, 0x00);
// disable SIGNAL_RATE_MSRC (bit 1) and SIGNAL_RATE_PRE_RANGE (bit 4) limit checks
this.i2c.writeReg8(VL53L0X.MSRC_CONFIG_CONTROL, (this.i2c.readReg8u(VL53L0X.MSRC_CONFIG_CONTROL) | 0x12));
// set final range signal rate limit to 0.25 MCPS (million counts per second)
this.setSignalRateLimit(0.25);
this.i2c.writeReg8(VL53L0X.SYSTEM_SEQUENCE_CONFIG, 0xFF);
// VL53L0X_DataInit() end
// VL53L0X_StaticInit() begin
// spad_count, spad_type_is_aperture, success = this.getSpadInfo()
const spadInfo = this.getSpadInfo();
if (!spadInfo[2]) {
return false;
}
// The SPAD map (RefGoodSpadMap) is read by VL53L0X_get_info_from_device() in
// the API, but the same data seems to be more easily readable from
// GLOBAL_CONFIG_SPAD_ENABLES_REF_0 through _6, so read it from there
const refSpadMap = this.i2c.readRegList(VL53L0X.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, 6);
// -- VL53L0X_set_reference_spads() begin (assume NVM values are valid)
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(VL53L0X.DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
this.i2c.writeReg8(VL53L0X.DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(VL53L0X.GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4);
let firstSpadToEnable;
if (spadInfo[1]) {
firstSpadToEnable = 12; // 12 is the first aperture spad
} else {
firstSpadToEnable = 0;
}
let spadsEnabled = 0;
for (let i = 0, len = 48; i < len; i++) {
if (i < firstSpadToEnable || spadsEnabled === spadInfo[0]) {
refSpadMap[parseInt(i / 8, 0)] &= ~(1 << (i % 8));
} else if (refSpadMap[parseInt(i / 8, 0)] >> (i % 8) & 0x1) {
spadsEnabled += 1;
}
}
this.i2c.writeRegList(VL53L0X.GLOBAL_CONFIG_SPAD_ENABLES_REF_0, refSpadMap);
// -- VL53L0X_set_reference_spads() end
// -- VL53L0X_load_tuning_settings() begin
// DefaultTuningSettings from vl53l0x_tuning.h
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x00, 0x00);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x09, 0x00);
this.i2c.writeReg8(0x10, 0x00);
this.i2c.writeReg8(0x11, 0x00);
this.i2c.writeReg8(0x24, 0x01);
this.i2c.writeReg8(0x25, 0xFF);
this.i2c.writeReg8(0x75, 0x00);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x4E, 0x2C);
this.i2c.writeReg8(0x48, 0x00);
this.i2c.writeReg8(0x30, 0x20);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x30, 0x09);
this.i2c.writeReg8(0x54, 0x00);
this.i2c.writeReg8(0x31, 0x04);
this.i2c.writeReg8(0x32, 0x03);
this.i2c.writeReg8(0x40, 0x83);
this.i2c.writeReg8(0x46, 0x25);
this.i2c.writeReg8(0x60, 0x00);
this.i2c.writeReg8(0x27, 0x00);
this.i2c.writeReg8(0x50, 0x06);
this.i2c.writeReg8(0x51, 0x00);
this.i2c.writeReg8(0x52, 0x96);
this.i2c.writeReg8(0x56, 0x08);
this.i2c.writeReg8(0x57, 0x30);
this.i2c.writeReg8(0x61, 0x00);
this.i2c.writeReg8(0x62, 0x00);
this.i2c.writeReg8(0x64, 0x00);
this.i2c.writeReg8(0x65, 0x00);
this.i2c.writeReg8(0x66, 0xA0);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x22, 0x32);
this.i2c.writeReg8(0x47, 0x14);
this.i2c.writeReg8(0x49, 0xFF);
this.i2c.writeReg8(0x4A, 0x00);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x7A, 0x0A);
this.i2c.writeReg8(0x7B, 0x00);
this.i2c.writeReg8(0x78, 0x21);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x23, 0x34);
this.i2c.writeReg8(0x42, 0x00);
this.i2c.writeReg8(0x44, 0xFF);
this.i2c.writeReg8(0x45, 0x26);
this.i2c.writeReg8(0x46, 0x05);
this.i2c.writeReg8(0x40, 0x40);
this.i2c.writeReg8(0x0E, 0x06);
this.i2c.writeReg8(0x20, 0x1A);
this.i2c.writeReg8(0x43, 0x40);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x34, 0x03);
this.i2c.writeReg8(0x35, 0x44);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x31, 0x04);
this.i2c.writeReg8(0x4B, 0x09);
this.i2c.writeReg8(0x4C, 0x05);
this.i2c.writeReg8(0x4D, 0x04);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x44, 0x00);
this.i2c.writeReg8(0x45, 0x20);
this.i2c.writeReg8(0x47, 0x08);
this.i2c.writeReg8(0x48, 0x28);
this.i2c.writeReg8(0x67, 0x00);
this.i2c.writeReg8(0x70, 0x04);
this.i2c.writeReg8(0x71, 0x01);
this.i2c.writeReg8(0x72, 0xFE);
this.i2c.writeReg8(0x76, 0x00);
this.i2c.writeReg8(0x77, 0x00);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x0D, 0x01);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x80, 0x01);
this.i2c.writeReg8(0x01, 0xF8);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x8E, 0x01);
this.i2c.writeReg8(0x00, 0x01);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x80, 0x00);
// -- VL53L0X_load_tuning_settings() end
// "Set interrupt config to new sample ready"
// -- VL53L0X_SetGpioConfig() begin
this.i2c.writeReg8(VL53L0X.SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04);
this.i2c.writeReg8(VL53L0X.GPIO_HV_MUX_ACTIVE_HIGH, this.i2c.readReg8u(VL53L0X.GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10); // active low
this.i2c.writeReg8(VL53L0X.SYSTEM_INTERRUPT_CLEAR, 0x01);
// -- VL53L0X_SetGpioConfig() end
this.measurementTimingBudgetUs = this.get_measurementTimingBudget();
// "Disable MSRC and TCC by default"
// MSRC = Minimum Signal Rate Check
// TCC = Target CentreCheck
// -- VL53L0X_SetSequenceStepEnable() begin
this.i2c.writeReg8(VL53L0X.SYSTEM_SEQUENCE_CONFIG, 0xE8);
// -- VL53L0X_SetSequenceStepEnable() end
// "Recalculate timing budget"
this.setMeasurementTimingBudget(VL53L0X.measurementTimingBudgetUs);
// VL53L0X_StaticInit() end
// VL53L0X_PerformRefCalibration() begin (VL53L0X_perform_ref_calibration())
// -- VL53L0X_perform_vhv_calibration() begin
this.i2c.writeReg8(VL53L0X.SYSTEM_SEQUENCE_CONFIG, 0x01);
if (!this.performSingleRefCalibration(0x40)) {
return false;
}
// -- VL53L0X_perform_vhv_calibration() end
// -- VL53L0X_perform_phase_calibration() begin
this.i2c.writeReg8(VL53L0X.SYSTEM_SEQUENCE_CONFIG, 0x02);
if (!this.performSingleRefCalibration(0x00)) {
return false;
}
// -- VL53L0X_perform_phase_calibration() end
// "restore the previous Sequence Config"
this.i2c.writeReg8(VL53L0X.SYSTEM_SEQUENCE_CONFIG, 0xE8);
// VL53L0X_PerformRefCalibration() end
return true;
}
setSignalRateLimit(limitMcps) {
if (limitMcps < 0 || limitMcps > 511.99) {
return false;
}
// Q9.7 fixed point format (9 integer bits, 7 fractional bits)
this.i2c.writeReg16(VL53L0X.FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, parseInt(limitMcps * (1 << 7), 0));
return true;
}
getSpadInfo() {
this.i2c.writeReg8(0x80, 0x01);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x00, 0x00);
this.i2c.writeReg8(0xFF, 0x06);
this.i2c.writeReg8(0x83, this.i2c.readReg8u(0x83) | 0x04);
this.i2c.writeReg8(0xFF, 0x07);
this.i2c.writeReg8(0x81, 0x01);
this.i2c.writeReg8(0x80, 0x01);
this.i2c.writeReg8(0x94, 0x6b);
this.i2c.writeReg8(0x83, 0x00);
this.start_timeout();
while (this.i2c.readReg8u(0x83) === 0x00) {
if (this.checkTimeoutExpired()) {
return [0, 0, false];
}
}
this.i2c.writeReg8(0x83, 0x01);
const tmp = this.i2c.readReg8u(0x92);
const count = tmp & 0x7f;
const typeIsAperture = (tmp >> 7) & 0x01;
this.i2c.writeReg8(0x81, 0x00);
this.i2c.writeReg8(0xFF, 0x06);
this.i2c.writeReg8(0x83, this.i2c.readReg8u(0x83 & ~0x04));
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x00, 0x01);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x80, 0x00);
return [count, typeIsAperture, true];
}
checkTimeoutExpired() {
const t1 = new Date().getTime();
if (this.ioTimeout > 0 && (t1 - this.timeoutStart) > this.ioTimeout) {
return true;
}
return false;
}
startTimeout() {
this.timeoutStart = new Date().getTime();
}
getMeasurementTimingBudget() {
const StartOverhead = 1910; // note that this is different than the value in set_
const EndOverhead = 960;
const MsrcOverhead = 660;
const TccOverhead = 590;
const DssOverhead = 690;
const PreRangeOverhead = 660;
const FinalRangeOverhead = 550;
let budgetUs = StartOverhead + EndOverhead;
const enables = this.getSequenceStepEnables();
const timeouts = this.getSequenceStepTimeouts(enables.pre_range);
if (enables.tcc) {
budgetUs += (timeouts.msrc_dss_tcc_us + TccOverhead);
}
if (enables.dss) {
budgetUs += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
} else if (enables.msrc) {
budgetUs += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
}
if (enables.pre_range) {
budgetUs += (timeouts.pre_range_us + PreRangeOverhead);
}
if (enables.final_range) {
budgetUs += (timeouts.final_range_us + FinalRangeOverhead);
}
this.measurementTimingBudgetUs = budgetUs; // store for internal reuse
return budgetUs;
}
getSequenceStepEnables() {
const sequenceConfig = this.i2c.readReg8u(VL53L0X.SYSTEM_SEQUENCE_CONFIG);
return {
'tcc': (sequenceConfig >> 4) & 0x1,
'msrc': (sequenceConfig >> 2) & 0x1,
'dss': (sequenceConfig >> 3) & 0x1,
'pre_range': (sequenceConfig >> 6) & 0x1,
'final_range': (sequenceConfig >> 7) & 0x1
};
}
getSequenceStepTimeout(preRange) {
const SequenceStepTimeouts = { 'pre_range_vcsel_periodPclks': 0, 'final_range_vcsel_periodPclks': 0, 'msrc_dss_tcc_mclks': 0, 'pre_range_mclks': 0, 'final_range_mclks': 0, 'msrc_dss_tcc_us': 0, 'pre_range_us': 0, 'final_range_us': 0 };
SequenceStepTimeouts.pre_range_vcsel_periodPclks = this.getVcselPulsePeriod(this.VcselPeriodPreRange);
SequenceStepTimeouts.msrc_dss_tcc_mclks = this.i2c.readReg8u(VL53L0X.MSRC_CONFIG_TIMEOUT_MACROP) + 1;
SequenceStepTimeouts.msrc_dss_tcc_us = this.timeoutMclksToMicroseconds(SequenceStepTimeouts.msrc_dss_tcc_mclks, SequenceStepTimeouts.pre_range_vcsel_periodPclks);
SequenceStepTimeouts.pre_range_mclks = this.decodeTimeout(this.i2c.readReg16u(VL53L0X.PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI));
SequenceStepTimeouts.pre_range_us = this.timeoutMclksToMicroseconds(SequenceStepTimeouts.pre_range_mclks, SequenceStepTimeouts.pre_range_vcsel_periodPclks);
SequenceStepTimeouts.final_range_vcsel_periodPclks = this.getVcselPulsePeriod(this.VcselPeriodFinalRange);
SequenceStepTimeouts.final_range_mclks = this.decodeTimeout(this.i2c.readReg16u(VL53L0X.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI));
if (preRange) {
SequenceStepTimeouts.final_range_mclks -= SequenceStepTimeouts.preRangeMclks;
}
SequenceStepTimeouts.final_range_us = this.timeoutMclksToMicroseconds(SequenceStepTimeouts.final_range_mclks, SequenceStepTimeouts.final_range_vcsel_periodPclks);
return SequenceStepTimeouts;
}
decodeVcselPeriod(regVal) {
return (((regVal) + 1) << 1);
}
getVcselPulsePeriod(type) {
if (type === this.VcselPeriodPreRange) {
return this.decodeVcselPeriod(this.i2c.readReg8u(VL53L0X.PRE_RANGE_CONFIG_VCSEL_PERIOD));
} else if (type === this.VcselPeriodFinalRange) {
return this.decodeVcselPeriod(this.i2c.readReg8u(VL53L0X.FINAL_RANGE_CONFIG_VCSEL_PERIOD));
}
return 255;
}
timeoutMclksToMicroseconds(timeoutPeriodMclks, vcselPeriodPclks) {
const macroPeriodNs = this.calcMacroPeriod(vcselPeriodPclks);
return ((timeoutPeriodMclks * macroPeriodNs) + (macroPeriodNs / 2)) / 1000;
}
calcMacroPeriod(vcselPeriodPclks) {
return (((2304 * vcselPeriodPclks * 1655) + 500) / 1000);
}
decodeTimeout(regVal) {
return ((regVal & 0x00FF) << ((regVal & 0xFF00) >> 8)) + 1;
}
setMeasurementTimingBudget(budgetUs) {
const StartOverhead = 1320; // note that this is different than the value in get_
const EndOverhead = 960;
const MsrcOverhead = 660;
const TccOverhead = 590;
const DssOverhead = 690;
const PreRangeOverhead = 660;
const FinalRangeOverhead = 550;
const MinTimingBudget = 20000;
if (budgetUs < MinTimingBudget) {
return false;
}
let usedBudgetUs = StartOverhead + EndOverhead;
const enables = this.getSequenceStepEnables();
const timeouts = this.getSequenceStepTimeout(enables.pre_range);
if (enables.tcc) {
usedBudgetUs += (timeouts.msrc_dss_tcc_us + TccOverhead);
}
if (enables.dss) {
usedBudgetUs += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
} else if (enables.msrc) {
usedBudgetUs += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
}
if (enables.pre_range) {
usedBudgetUs += (timeouts.pre_range_us + PreRangeOverhead);
}
if (enables.final_range) {
usedBudgetUs += FinalRangeOverhead;
}
if (usedBudgetUs > budgetUs) {
return false;
}
const finalRangeTimeoutUs = budgetUs - usedBudgetUs;
let finalRangeTimeoutMclks = this.timeoutMicrosecondsToMclks(finalRangeTimeoutUs, timeouts.final_range_vcsel_periodPclks);
if (enables.pre_range) {
finalRangeTimeoutMclks += timeouts.pre_range_mclks;
}
this.i2c.writeReg16(VL53L0X.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, this.encodeTimeout(finalRangeTimeoutMclks));
this.measurementTimingBudgetUs = budgetUs;
return true;
}
encodeTimeout(timeoutMclks) {
let lsByte = 0;
let msByte = 0;
if (timeoutMclks > 0) {
lsByte = timeoutMclks - 1;
while ((parseInt(lsByte, 0) & 0xFFFFFF00) > 0) {
lsByte /= 2; // >>=
msByte += 1;
}
return ((msByte << 8) | (parseInt(lsByte, 0) & 0xFF));
}
return 0;
}
timeoutMicrosecondsToMclks(timeoutPeriodUs, vcselPeriodPclks) {
const macroPeriodNs = this.calcMacroPeriod(vcselPeriodPclks);
return (((timeoutPeriodUs * 1000) + (macroPeriodNs / 2)) / macroPeriodNs);
}
performSingleRefCalibration(vhvInitByte) {
this.i2c.writeReg8(VL53L0X.SYSRANGE_START, 0x01 | vhvInitByte);
this.startTimeout();
while ((this.i2c.readReg8u(VL53L0X.RESULT_INTERRUPT_STATUS) & 0x07) === 0) {
if (this.checkTimeoutExpired()) {
return false;
}
}
this.i2c.writeReg8(VL53L0X.SYSTEM_INTERRUPT_CLEAR, 0x01);
this.i2c.writeReg8(VL53L0X.SYSRANGE_START, 0x00);
return true;
}
setTimeout(timeout) {
this.ioTimeout = timeout;
}
startContinuous(periodMs = 0) {
this.i2c.writeReg8(0x80, 0x01);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x00, 0x00);
this.i2c.writeReg8(0x91, this.stopVariable);
this.i2c.writeReg8(0x00, 0x01);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x80, 0x00);
if (periodMs !== 0) {
const oscCalibrateVal = this.i2c.readReg16u(VL53L0X.OSC_CALIBRATE_VAL);
if (oscCalibrateVal !== 0) {
periodMs *= oscCalibrateVal;
}
this.i2c.writeReg32(VL53L0X.SYSTEM_INTERMEASUREMENT_PERIOD, periodMs);
this.i2c.writeReg8(VL53L0X.SYSRANGE_START, 0x04);
} else {
this.i2c.writeReg8(VL53L0X.SYSRANGE_START, 0x02);
}
}
readRangeContinuousMillimiters() {
this.startTimeout();
while ((this.i2c.readReg8u(VL53L0X.RESULT_INTERRUPT_STATUS) & 0x07) === 0) {
if (this.checkTimeoutExpired()) {
this.didTimeout = true;
console.log('readRangeContinuousMillimiters timeout');
}
}
const range = this.i2c.readReg16u(VL53L0X.RESULT_RANGE_STATUS + 10);
this.i2c.writeReg8(VL53L0X.SYSTEM_INTERRUPT_CLEAR, 0x01);
return range;
}
timeoutOccurred() {
const ret = this.didTimeout;
this.didTimeout = false;
return ret;
}
setVcselPulsePeriod(type, periodPclks) {
const vcselPeriodReg = this.encodeVcselPeriod(periodPclks);
const enables = this.getSequenceStepEnables();
const timeouts = this.getSequenceStepTimeouts(enables.pre_range);
if (type === this.VcselPeriodPreRange) {
if (periodPclks === 12) {
this.i2c.writeReg8(VL53L0X.PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x18);
} else if (periodPclks === 14) {
this.i2c.writeReg8(VL53L0X.PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x30);
} else if (periodPclks === 16) {
this.i2c.writeReg8(VL53L0X.PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x40);
} else if (periodPclks === 18) {
this.i2c.writeReg8(VL53L0X.PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x50);
} else {
return false;
}
this.i2c.writeReg8(VL53L0X.PRE_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
this.i2c.writeReg8(VL53L0X.PRE_RANGE_CONFIG_VCSEL_PERIOD, vcselPeriodReg);
const newPreRangeTimeoutMclks = VL53L0X.timeoutMicrosecondsToMclks(timeouts.pre_range_us, periodPclks);
this.i2c.writeReg16(VL53L0X.PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, this.encodeTimeout(newPreRangeTimeoutMclks));
const newMsrcTimeoutMclks = this.timeoutMicrosecondsToMclks(timeouts.msrc_dss_tcc_us, periodPclks);
if (newMsrcTimeoutMclks > 256) {
this.i2c.writeReg8(VL53L0X.MSRC_CONFIG_TIMEOUT_MACROP, 255);
} else {
this.i2c.writeReg8(VL53L0X.MSRC_CONFIG_TIMEOUT_MACROP, (newMsrcTimeoutMclks - 1));
}
} else if (type === this.VcselPeriodFinalRange) {
if (periodPclks === 8) {
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x10);
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
this.i2c.writeReg8(VL53L0X.GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_LIM, 0x30);
this.i2c.writeReg8(0xFF, 0x00);
} else if (periodPclks === 10) {
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x28);
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
this.i2c.writeReg8(VL53L0X.GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_LIM, 0x20);
this.i2c.writeReg8(0xFF, 0x00);
} else if (periodPclks === 12) {
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x38);
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
this.i2c.writeReg8(VL53L0X.GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_LIM, 0x20);
this.i2c.writeReg8(0xFF, 0x00);
} else if (periodPclks === 14) {
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x48);
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);
this.i2c.writeReg8(VL53L0X.GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(VL53L0X.ALGO_PHASECAL_LIM, 0x20);
this.i2c.writeReg8(0xFF, 0x00);
} else {
return false;
}
this.i2c.writeReg8(VL53L0X.FINAL_RANGE_CONFIG_VCSEL_PERIOD, vcselPeriodReg);
let newFinalRangeTimeoutMclks = this.timeoutMicrosecondsToMclks(timeouts.final_range_us, periodPclks);
if (enables.pre_range) {
newFinalRangeTimeoutMclks += timeouts.pre_range_mclks;
}
this.i2c.writeReg16(VL53L0X.FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, this.encodeTimeout(newFinalRangeTimeoutMclks));
} else {
return false;
}
this.setMeasurementTimingBudget(this.measurementTimingBudgetUs);
const sequenceConfig = this.i2c.readReg8u(VL53L0X.SYSTEM_SEQUENCE_CONFIG);
this.i2c.writeReg8(VL53L0X.SYSTEM_SEQUENCE_CONFIG, 0x02);
this.performSingleRefCalibration(0x0);
this.i2c.writeReg8(VL53L0X.SYSTEM_SEQUENCE_CONFIG, sequenceConfig);
return true;
}
readRangeSingleMillimiters() {
this.i2c.writeReg8(0x80, 0x01);
this.i2c.writeReg8(0xFF, 0x01);
this.i2c.writeReg8(0x00, 0x00);
this.i2c.writeReg8(0x91, this.stopVariable);
this.i2c.writeReg8(0x00, 0x01);
this.i2c.writeReg8(0xFF, 0x00);
this.i2c.writeReg8(0x80, 0x00);
this.i2c.writeReg8(VL53L0X.SYSRANGE_START, 0x01);
this.startTimeout();
while (this.i2c.readReg8u(VL53L0X.SYSRANGE_START) & 0x01) {
if (this.checkTimeoutExpired()) {
this.didTimeout = true;
console.log('read_range_single_millimeters timeout');
}
}
return this.readRangeContinuousMillimeters();
}
encodeVcselPeriod(periodPclks) {
return ((periodPclks >> 1) - 1);
}
}
module.exports = VL53L0X;