UNPKG

i2c-ftdi-d2xx

Version:

i2c protocol implementation with ftdi-d2xx on standard boards that features no level translators on SDA and SCL

260 lines (215 loc) 6.87 kB
const ftdi = require('ftdi-d2xx'); const { sleep } = require('./utils'); const STANDARD_TIMEOUT = 250; const I2C_CLOCK_DIVISOR = 29; const BUFFON_SCLH_SDAH = [0x80, 0xC3, 0xC3]; const BUFFON_SCLH_SDAL = [0x80, 0xC1, 0xC3]; const BUFFON_SCLL_SDAL = [0x80, 0xC0, 0xC3]; const BUFFON_SCLL_SDAH = [0x80, 0xC2, 0xC3]; const BUFOFF_SCLL_SDAL = [0x80, 0x00, 0xC0]; const BUFOFF_SCLH_SDAH = [0x80, 0x03, 0xC0]; const SCLL_SDAHIZ = [0x80, 0x80, 0xC1] let device; const isConnected = () => { const ftdiConnected = device?.is_connected || false; return ftdiConnected; } const getFtdiDevice = () => { return device; } const setClockDivider = async (res=null, divider = I2C_CLOCK_DIVISOR) => { try { await device.write(Uint8Array.from([0x86, divider % 256, Math.floor(divider / 256)])) await device.write(Uint8Array.from([0x8C])) //Three phase clock } catch (error) { if(res) { res.success = false; res.errors.push(error); } else { console.log(error); } } } const list = async (filtered = '') => { const devices = await ftdi.getDeviceInfoList(); const filterRegex = new RegExp(filtered); let validDevices; if (filtered) { validDevices = devices.filter(d => filterRegex.test(d.description)); } else { validDevices = devices; } return validDevices; } const close = async () => { const res = {success: false, errors: []} try { if (device && (device.is_connected)) { //Reset bit mode device.setBitMode(0, 0); await sleep(STANDARD_TIMEOUT); //Close connection device.close(); } res.success = true; } catch (error) { res.errors.push(error); } finally { return res; } } const open = async (serialNumber) => { const res = {success: false, errors: []}; try { if (device?.is_connected) { await close(); } //Open connection device = await ftdi.openDevice(serialNumber); //Reset bit mode device.setBitMode(0, 0); await sleep(STANDARD_TIMEOUT); //Set bit mode = MPSSE <-- I2C device.setBitMode(0, 2); res.success = true; setClockDivider(res); } catch (error) { console.log(error); res.errors.push(error); } finally { return res; } } const i2cStart = () => { return [ ...[...Array(8)].flatMap(_ => BUFFON_SCLH_SDAH), ...[...Array(8)].flatMap(_ => BUFFON_SCLH_SDAL), ...[...Array(8)].flatMap(_ => BUFFON_SCLL_SDAL) ]; } const i2cStop = () => { return [ ...[...Array(8)].flatMap(_ => BUFFON_SCLL_SDAL), ...[...Array(8)].flatMap(_ => BUFFON_SCLH_SDAL), ...[...Array(8)].flatMap(_ => BUFFON_SCLH_SDAH), ...BUFOFF_SCLH_SDAH ]; } const i2cByte = (byte) => { const command = [0x11, 0x00, 0x00]; const readAck = [0x22, 0x00]; const driveSdaAgainWithSclLow = [0x80, 0xC0, 0xC3] return [ ...command, byte % 256, ...SCLL_SDAHIZ, ...readAck, ...driveSdaAgainWithSclLow ]; } const i2cClock9 = (last=false) => { const clock8 = [0x20, 0x00, 0x00]; const ack = [ ...[...Array(8)].flatMap(_ => BUFFON_SCLL_SDAL), ...[...Array(8)].flatMap(_ => last ? BUFFON_SCLH_SDAH : BUFFON_SCLH_SDAL) ]; return [ ...SCLL_SDAHIZ, ...clock8, ...BUFFON_SCLL_SDAL, ...ack ] } const write = async (slaveId=0x00, register=0x00, data=0x00) => { const ftdiArray = [ ...i2cStart(), ...i2cByte(slaveId), ...i2cByte(register), ...i2cByte(data), ...i2cStop() ]; await device.write(Uint8Array.from(ftdiArray)); const acks = await device.read(3); const slaveAck = acks[0] % 2; const addressAck = acks[1] % 2; const dataAck = acks[2] % 2; const res = {slaveAck: slaveAck, addressAck: addressAck, dataAck: dataAck}; return res; } const burstWrite = async (slaveId=0x00, register=0x00, data=[0x00]) => { const ftdiArray = [ ...i2cStart(), ...i2cByte(slaveId), ...i2cByte(register), ...data.flatMap(d => i2cByte(d)), ...i2cStop() ]; await device.write(Uint8Array.from(ftdiArray)); const acks = [...(await device.read(2 + data.length))]; const slaveAck = acks.shift() % 2; const addressAck = acks.shift() % 2; let dataAcks = []; acks.forEach(a => { dataAcks.push(a % 2) }); const res = {slaveAck: slaveAck, addressAck: addressAck, dataAcks: dataAcks}; return res; } const sendCommand = async (slaveId=0x00, command=0x00) => { const ftdiArray = [ ...i2cStart(), ...i2cByte(slaveId), ...i2cByte(command), ...i2cStop() ]; await device.write(Uint8Array.from(ftdiArray)); const acks = await device.read(2); const slaveAck = acks[0] % 2; const commandAck = acks[1] % 2; const res = {slaveAck: slaveAck, commandAck: commandAck}; return res; } const ping = async (slaveId=0x00) => { const ftdiArray = [ ...i2cStart(), ...i2cByte(slaveId), ...i2cStop() ]; await device.write(Uint8Array.from(ftdiArray)); const acks = await device.read(1); const slaveAck = acks[0] % 2; const res = {slaveAck: slaveAck}; return res; } const read = async (slaveId=0x00, register=0x00, nBytes=1) => { const readBurst = [ ...[...Array(nBytes -1)].flatMap(_ => i2cClock9()), ...[...Array(1)].flatMap(_ => i2cClock9(true)), ] const ftdiArray = [ ...i2cStart(), ...i2cByte(slaveId), ...i2cByte(register), ...i2cStart(), ...i2cByte(slaveId + 1), ...SCLL_SDAHIZ, ...readBurst, ...i2cStop() ]; await device.write(Uint8Array.from(ftdiArray)); const results = [...(await device.read(3 + nBytes))]; const acks = results.slice(0,3); const data = results.slice(3,results.length); const res = {data: data, slaveAck: acks[0] % 2, addressAck: acks[1] % 2, readAck: acks[2] % 2}; return res; } module.exports.list = list; module.exports.open = open; module.exports.close = close; module.exports.isConnected = isConnected; module.exports.write = write; module.exports.burstWrite = burstWrite; module.exports.sendCommand = sendCommand; module.exports.ping = ping; module.exports.read = read; module.exports.getFtdiDevice = getFtdiDevice;