i2c-ftdi-d2xx
Version:
i2c protocol implementation with ftdi-d2xx on standard boards that features no level translators on SDA and SCL
139 lines (129 loc) • 4.93 kB
JavaScript
const ftdi = require('./ftdi');
const {readFile, writeFile, createFileIfItDoesNotExist} = require('./file-manager');
let emulatedDevicePath;
const i2cReadAddress = async ({slaveId, regAddress, simulated}) => {
let data;
let ack = false;
if (simulated) {
try {
const read = JSON.parse(await readFile(emulatedDevicePath));
data = read[regAddress];
ack = true;
} catch (error) {
data = 255;
ack = false;
}
} else {
if (ftdi.isConnected() && slaveId) {
const i2cRead = await ftdi.read(Number(slaveId), Number(regAddress), 1)
data = i2cRead.data[0];
ack = (i2cRead.slaveAck === 0) && (i2cRead.readAck === 0) && (i2cRead.addressAck === 0)
}
}
return {data: data, ack: ack}
}
const i2cReadBurst = async ({slaveId, regAddress, nBytes, simulated = false}) => {
let data;
let ack = false;
if (simulated) {
try {
const read = JSON.parse(await readFile(emulatedDevicePath));
data = [...Array(nBytes)].map((_, i) => read[regAddress + i]);
ack = true;
} catch (error) {
data = [...Array(nBytes)].map((_) => 255);
ack = false;
}
} else {
if (ftdi.isConnected() && slaveId) {
const i2cRead = await ftdi.read(Number(slaveId), Number(regAddress), Number(nBytes));
data = i2cRead.data;
ack = (i2cRead.slaveAck === 0) && (i2cRead.readAck === 0) && (i2cRead.addressAck === 0);
}
}
return {data: data, ack: ack}
}
const i2cWriteAddress = async ({slaveId, regAddress, data, simulated}) => {
let ack = false;
if (simulated) {
await createFileIfItDoesNotExist(emulatedDevicePath);
const emulatedDevice = JSON.parse(await readFile(emulatedDevicePath));
emulatedDevice[regAddress] = data;
await writeFile(JSON.stringify(emulatedDevice, null, 2), emulatedDevicePath);
ack = true;
} else {
if (ftdi.isConnected() && slaveId) {
const res = await ftdi.write(Number(slaveId), Number(regAddress), Number(data));
ack = (res.slaveAck === 0) && (res.addressAck === 0) && (res.dataAck === 0);
}
}
return {ack: ack};
}
const i2cWriteBurst = async ({slaveId, regAddress, data, simulated = false}) => {
let ack = false;
if (simulated) {
await createFileIfItDoesNotExist(emulatedDevicePath);
let emulatedDevice
try {
emulatedDevice = JSON.parse(await readFile(emulatedDevicePath));
} catch (error) {
if (error instanceof SyntaxError && error.message.includes('Unexpected end of JSON input')) {
emulatedDevice = {};
} else {
throw new error.constructor(error.message)
}
}
data.forEach((d, i) => {
emulatedDevice[Number(regAddress) + i] = d;
});
await writeFile(JSON.stringify(emulatedDevice, null, 2), emulatedDevicePath);
ack = true;
} else {
if ((regAddress || regAddress === 0) && data.every(d => !isNaN(d))) {
const burstData = data.map(d => Number(d));
if (ftdi.isConnected() && slaveId) {
const res = await ftdi.burstWrite(Number(slaveId), Number(regAddress), burstData);
ack = (res.slaveAck === 0) && (res.addressAck === 0) && (res.dataAcks.every(a => a === 0))
}
}
}
return {ack: ack};
}
const scanI2cBus = async () => {
const slaves = [];
for(let i = 0; i < 256; i += 2) {
if (ftdi.isConnected()) {
const res = await ftdi.ping(i);
if (res.slaveAck === 0) {
slaves.push(i);
}
}
}
return slaves;
}
const scanDeviceRegisters = async ({slaveId}) => {
const registers = [];
if(slaveId) {
for(let i = 0; i < 256; i++) {
if (ftdi.isConnected()) {
const res = await ftdi.sendCommand(Number(slaveId), i);
if (res.slaveAck === 0 && res.commandAck === 0) {
registers.push(i);
}
}
}
}
return registers;
}
const setEmulatedDevicePath = async ({filepath}) => {
await createFileIfItDoesNotExist(filepath);
emulatedDevicePath = filepath;
return true;
}
module.exports.i2cReadAddress = i2cReadAddress;
module.exports.i2cReadBurst = i2cReadBurst;
module.exports.i2cWriteAddress = i2cWriteAddress;
module.exports.i2cWriteBurst = i2cWriteBurst;
module.exports.scanI2cBus = scanI2cBus;
module.exports.scanDeviceRegisters = scanDeviceRegisters;
module.exports.setEmulatedDevicePath = setEmulatedDevicePath;