i2c-ftdi-d2xx
Version:
i2c protocol implementation with ftdi-d2xx on standard boards that features no level translators on SDA and SCL
196 lines (172 loc) • 7.8 kB
JavaScript
const fs = require("fs");
const i2c = require("./i2c");
const {
generateMask8Bit,
extractData,
insertData
} = require("./utils")
let regmap;
const readFile = (filepath) => {
return new Promise((resolve, reject) => {
fs.readFile(filepath, 'utf8', (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
};
const setRegisterMapByFilePath = async ({filepath}) => {
const regmapFile = await readFile(filepath);
regmap = JSON.parse(regmapFile);
return regmap;
};
const setRegisterMap = ({registerMap}) => {
regmap = registerMap;
return regmap;
};
const getRegisterMap = () => regmap;
const findRegisterFromField = (field) => {
let register;
if(regmap) {
register = Object.entries(regmap).find(r => Object.keys(regmap[r[0]].fields).includes(field));
} else {
throw('ERROR: no register map loaded .. before any communication you MUST load a valid register map with setRegisterMap')
}
return register ? {...register[1], name: register[0]} : null;
}
const i2cReadRegister = async ({slaveId, register, simulated = false}) => {
const result = await i2c.i2cReadAddress({slaveId: slaveId, regAddress: isNaN(register) ? regmap[register].address : register, simulated: simulated});
return {data: result.data, result: result.ack ? 'pass' : 'fail'}
};
const i2cReadRegistersWithDetails = async ({slaveId, registers = [], simulated = false}) => {
let data = {};
let acks = [];
if(regmap) {
for (let r of registers) {
const register = regmap[r];
const res = await i2c.i2cReadAddress({slaveId: slaveId, regAddress: register.address, simulated: simulated});
let registerData = {};
Object.keys(register.fields).forEach(f => {
const field = register.fields[f];
const fieldData = extractData(res.data, field.offset, field.size)
registerData[f] = res.ack ? fieldData : NaN;
});
data[r] = registerData;
acks.push(res.ack);
};
} else {
throw('ERROR: no register map loaded .. before any communication you MUST load a valid register map with setRegisterMap')
}
return {data: data, result: acks.every(a => a) ? 'pass' : 'fail'};
}
const i2cReadField = async ({slaveId, field, simulated = false}) => {
const register = findRegisterFromField(field);
const info = register.fields[field]
const {data, ack} = await i2c.i2cReadAddress({slaveId: slaveId, regAddress: register.address, simulated: simulated});
const fieldData = extractData(data, info.offset, info.size)
return {data: fieldData, result: ack ? 'pass' : 'fail'};
};
const i2cReadFields = async ({slaveId, fields = [], simulated = false}) => {
let data = {};
let results = [];
for(let f of fields){
const singleRes = await i2cReadField({slaveId: slaveId, field: f, simulated: simulated})
results.push(singleRes.result);
data[f] = singleRes.data
}
const result = results.every(r => r);
return {data: data, result: result ? 'pass' : 'fail'};
};
const i2cReadRegistersFields = async ({slaveId, registers = [], simulated = false}) => {
const read = {};
const acks = [];
for(r of registers) {
const {data, ack} = await i2c.i2cReadAddress({slaveId: slaveId, regAddress: isNaN(r) ? regmap[r].address : r, simulated: simulated});
acks.push(ack);
const fields = Object.keys(regmap[r].fields);
for (f of fields) {
const field = regmap[r].fields[f];
const mask = generateMask8Bit(field.offset, field.size)
read[f] = (data & mask) >> field.offset;
};
};
const result = acks.every(a => a) ? 'pass' : 'fail';
return {data: read, result: result};
};
const i2cReadAllFields = async ({slaveId, capAddress=256, bannedRegisters = [], simulated = false}) => {
const registers = Object.keys(regmap)
.filter(r => regmap[r].address < capAddress)
.filter(r => !bannedRegisters.includes(r));
const res = await i2cReadRegistersFields({slaveId: slaveId, registers: registers, simulated: simulated})
return res;
};
const i2cWriteRegister = async ({slaveId, register, data, simulated = false}) => {
const {ack} = await i2c.i2cWriteAddress({slaveId: slaveId, regAddress: isNaN(register) ? regmap[register].address : register, data: data, simulated: simulated})
const result = ack ? {result: "pass"} : {result: "fail"};
return result;
};
const i2cWriteField = async ({slaveId, field, data, simulated = false}) => {
const register = findRegisterFromField(field);
let res = {};
if (register.fields[field].size < 8) {
res = await i2c.i2cReadAddress({slaveId: slaveId, regAddress: register.address, simulated: simulated});
} else {
res.data = 0;
res.ack = true
}
let result;
if(res.ack) {
const newData = insertData(data, register.fields[field].offset, register.fields[field].size, res.data)
const {ack} = await i2c.i2cWriteAddress({slaveId: slaveId, regAddress: register.address, data: newData, simulated: simulated});
result = ack ? {result: "pass"} : {result: "fail"};
} else {
result = "fail";
}
return result;
};
const i2cWriteFields = async ({slaveId, fieldsDictionary, simulated = false}) => {
const results = {};
for(f of Object.keys(fieldsDictionary)) {
const res = await i2cWriteField({slaveId: slaveId, field: f, data: fieldsDictionary[f], simulated: simulated});
results[f] = res.result;
}
let result;
if (Object.values(results).every(r => r === "pass")) {
result = {result: "pass"}
} else if (Object.values(results).some(r => r === "pass")){
result = {result: "fail", error: `write failed for the following fields: ${Object.keys(results).filter(f => results[f] === 'fail').join(', ')}`}
} else {
result = {result: "fail", error: `write failed for all requested fields`}
}
return result
};
const i2cResetAllRegisters = async ({slaveId, bannedRegisters = [], simulated = false}) => {
const registers = Object.keys(regmap).filter(r => !bannedRegisters.includes(r));
const results = [];
for (r of registers) {
results.push(await i2c.i2cWriteAddress({slaveId: slaveId, regAddress: regmap[r].address, data: regmap[r].reset, simulated: simulated}));
};
if (results.every(r => r.ack)) {
return {result: "pass"};
} else if (results.some(r => r.ack)) {
return {result: "fail", error: "some registers failed to reset"};
} else {
return {result: "fail", error: "it was not possible to reset any register"};
}
};
module.exports.setRegisterMap = setRegisterMap;
module.exports.setRegisterMapByFilePath = setRegisterMapByFilePath;
module.exports.getRegisterMap = getRegisterMap;
module.exports.getFieldRegister = findRegisterFromField;
module.exports.i2cReadRegister = i2cReadRegister;
module.exports.i2cReadField = i2cReadField;
module.exports.i2cReadFields = i2cReadFields;
module.exports.i2cReadRegistersFields = i2cReadRegistersFields;
module.exports.i2cReadRegistersWithDetails = i2cReadRegistersWithDetails;
module.exports.i2cReadAllFields = i2cReadAllFields;
module.exports.i2cWriteRegister = i2cWriteRegister;
module.exports.i2cWriteField = i2cWriteField;
module.exports.i2cWriteFields = i2cWriteFields;
module.exports.i2cResetAllRegisters = i2cResetAllRegisters;