obniz
Version:
obniz sdk for javascript
226 lines (207 loc) • 6.1 kB
JavaScript
const ObnizUtil = require('../utils/util');
class PeripheralI2C {
constructor(Obniz, id) {
this.Obniz = Obniz;
this.id = id;
this._reset();
this.onerror = undefined;
}
_reset() {
this.observers = [];
this.state = {};
this.used = false;
this.onwritten = undefined;
}
addObserver(callback) {
if (callback) {
this.observers.push(callback);
}
}
start(arg) {
let err = ObnizUtil._requiredKeys(arg, ['mode', 'sda', 'scl']);
if (err) {
throw new Error("I2C start param '" + err + "' required, but not found ");
}
this.state = ObnizUtil._keyFilter(arg, [
'mode',
'sda',
'scl',
'pull',
'gnd',
]);
let ioKeys = ['sda', 'scl', 'gnd'];
for (let key of ioKeys) {
if (this.state[key] && !this.Obniz.isValidIO(this.state[key])) {
throw new Error("i2c start param '" + key + "' are to be valid io no");
}
}
let mode = this.state.mode;
let clock = typeof arg.clock === 'number' ? parseInt(arg.clock) : null;
let slave_address =
typeof arg.slave_address === 'number'
? parseInt(arg.slave_address)
: null;
let slave_address_length =
typeof arg.slave_address_length === 'number'
? parseInt(arg.slave_address_length)
: null;
if (mode !== 'master' && mode !== 'slave') {
throw new Error('i2c: invalid mode ' + mode);
}
if (mode === 'master') {
if (clock === null) {
throw new Error('i2c: please specify clock when master mode');
}
if (clock <= 0 || clock > 1 * 1000 * 1000) {
throw new Error('i2c: invalid clock ' + clock);
}
if (arg.pull === '5v' && clock > 400 * 1000) {
throw new Error(
'i2c: please use under 400khz when internal 5v internal pull-up'
);
}
if (arg.pull === '3v' && clock > 100 * 1000) {
throw new Error(
'i2c: please use under 100khz when internal 3v internal pull-up'
);
}
} else {
if (slave_address === null) {
throw new Error('i2c: please specify slave_address');
}
if (slave_address < 0 || slave_address > 0x7f) {
throw new Error('i2c: invalid slave_address');
}
if (slave_address < 0 || slave_address > 0x7f) {
throw new Error('i2c: invalid slave_address');
}
if (slave_address_length !== null && slave_address_length !== 7) {
throw new Error('i2c: invalid slave_address_length. please specify 7');
}
}
this.Obniz.getIO(this.state.sda).drive('open-drain');
this.Obniz.getIO(this.state.scl).drive('open-drain');
if (this.state.pull) {
this.Obniz.getIO(this.state.sda).pull(this.state.pull);
this.Obniz.getIO(this.state.scl).pull(this.state.pull);
} else {
this.Obniz.getIO(this.state.sda).pull(null);
this.Obniz.getIO(this.state.scl).pull(null);
}
if (this.state.gnd !== undefined) {
this.Obniz.getIO(this.state.gnd).output(false);
let ioNames = {};
ioNames[this.state.gnd] = 'gnd';
this.Obniz.display.setPinNames('i2c' + this.id, ioNames);
}
let startObj = ObnizUtil._keyFilter(this.state, ['mode', 'sda', 'scl']);
if (mode === 'master') {
startObj.clock = clock;
} else {
startObj.slave_address = slave_address;
if (slave_address_length) {
startObj.slave_address_length = slave_address_length;
}
}
let obj = {};
obj['i2c' + this.id] = startObj;
this.used = true;
this.Obniz.send(obj);
}
write(address, data) {
if (!this.used) {
throw new Error(`i2c${this.id} is not started`);
}
address = parseInt(address);
if (isNaN(address)) {
throw new Error('i2c: please specify address');
}
if (address < 0 || address > 0x7f) {
throw new Error('i2c: invalid address');
}
if (!data) {
throw new Error('i2c: please provide data');
}
if (data.length > 1024) {
throw new Error('i2c: data should be under 1024 bytes');
}
let obj = {};
obj['i2c' + this.id] = {
address,
data,
};
this.Obniz.send(obj);
}
readWait(address, length) {
if (!this.used) {
throw new Error(`i2c${this.id} is not started`);
}
address = parseInt(address);
if (isNaN(address)) {
throw new Error('i2c: please specify address');
}
if (address < 0 || address > 0x7f) {
throw new Error('i2c: invalid address');
}
length = parseInt(length);
if (isNaN(length) || length < 0) {
throw new Error('i2c: invalid length to read');
}
if (length > 1024) {
throw new Error('i2c: data length should be under 1024 bytes');
}
let self = this;
return new Promise(function(resolve, reject) {
self.addObserver(resolve);
let obj = {};
obj['i2c' + self.id] = {
address,
read: length,
};
self.Obniz.send(obj);
});
}
notified(obj) {
if (obj && typeof obj === 'object') {
if (obj.data) {
if (obj.mode === 'slave' && typeof this.onwritten === 'function') {
this.onwritten(obj.data, obj.address);
} else {
// TODO: we should compare byte length from sent
let callback = this.observers.shift();
if (callback) {
callback(obj.data);
}
}
}
if (obj.warning) {
this.Obniz.warning({
alert: 'warning',
message: `i2c${this.id}: ${obj.warning.message}`,
});
}
if (obj.error) {
const message = `i2c${this.id}: ${obj.error.message}`;
if (typeof this.onerror === 'function') {
this.onerror(new Error(message));
} else {
this.Obniz.error({
alert: 'error',
message: message,
});
}
}
}
}
isUsed() {
return this.used;
}
end() {
this.state = {};
let obj = {};
obj['i2c' + this.id] = null;
this.Obniz.send(obj);
this.used = false;
}
}
module.exports = PeripheralI2C;