Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 79 additions & 13 deletions lib/particle.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ var errors = {
};

var pins = [
{ id: "D0", modes: [0, 1, 3, 4] },
{ id: "D1", modes: [0, 1, 3, 4] },
{ id: "D2", modes: [0, 1, 3, 4] },
{ id: "D3", modes: [0, 1, 3, 4] },
{ id: "D0", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "D1", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "D2", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "D3", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "D4", modes: [0, 1] },
{ id: "D5", modes: [0, 1] },
{ id: "D6", modes: [0, 1] },
Expand All @@ -26,14 +26,14 @@ var pins = [
{ id: "", modes: [] },
{ id: "", modes: [] },

{ id: "A0", modes: [0, 1, 2, 3, 4] },
{ id: "A1", modes: [0, 1, 2, 3, 4] },
{ id: "A0", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "A1", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "A2", modes: [0, 1, 2] },
{ id: "A3", modes: [0, 1, 2] },
{ id: "A4", modes: [0, 1, 2, 3, 4] },
{ id: "A5", modes: [0, 1, 2, 3, 4] },
{ id: "A6", modes: [0, 1, 2, 3, 4] },
{ id: "A7", modes: [0, 1, 2, 3, 4] }
{ id: "A4", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 1000, servoMax: 2000 }},
{ id: "A5", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "A6", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
{ id: "A7", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
];

var modes = Object.freeze({
Expand Down Expand Up @@ -252,6 +252,7 @@ function Particle(opts) {
name: pin.id,
supportedModes: pin.modes,
mode: pin.modes[0],
pwm: pin.pwm,
value: 0
};
});
Expand Down Expand Up @@ -479,10 +480,9 @@ Particle.prototype.pinMode = function(pin, mode) {
return this;
};

["analogWrite", "digitalWrite", "servoWrite"].forEach(function(fn) {
["analogWrite", "digitalWrite"].forEach(function(fn) {
var isAnalog = fn === "analogWrite";
var isServo = fn === "servoWrite";
var action = isAnalog ? 0x02 : (isServo ? 0x41 : 0x01);
var action = isAnalog ? 0x02 : 0x01;

Particle.prototype[fn] = function(pin, value) {
var state = priv.get(this);
Expand All @@ -502,6 +502,67 @@ Particle.prototype.pinMode = function(pin, mode) {
};
});

Particle.prototype.servoWrite = function(pin, value) {
var state = priv.get(this);
var buffer;
var offset = pin[0] === "A" ? 10 : 0;
var pinInt = (String(pin).replace(/A|D/i, "") | 0) + offset;

if (value < 544) {
buffer = new Buffer(3);
value = constrain(value, 0, 180);
buffer[0] = 0x41;
buffer[1] = pinInt;
buffer[2] = value;
} else {
buffer = new Buffer(4);
value = constrain(value, this.pins[pinInt].pwm.servoMin, this.pins[pinInt].pwm.servoMax);
buffer[0] = 0x43;
buffer[1] = pinInt;
buffer[2] = value & 0x7f;
buffer[3] = value >> 7;
}

// console.log(buffer);
state.socket.write(buffer);
this.pins[pinInt].value = value;

return this;
};

Particle.prototype.servoConfig = function(pin, min, max) {
var offset = pin[0] === "A" ? 10 : 0;
var pinInt = (String(pin).replace(/A|D/i, "") | 0) + offset;
var temp;

if (typeof pin === "object" && pin !== null) {
temp = pin;
pin = temp.pin;
min = temp.min;
max = temp.max;
}

if (typeof pin === "undefined") {
throw new Error("servoConfig: pin must be specified");
}

if (typeof min === "undefined") {
throw new Error("servoConfig: min must be specified");
}

if (typeof max === "undefined") {
throw new Error("servoConfig: max must be specified");
}

if (this.pins[pinInt].mode !== modes.SERVO) {
this.pinMode(pinInt, modes.SERVO);
}

pins[pinInt].pwm.servoMin = min;
pins[pinInt].pwm.servoMax = max;

};

// TODO: Define protocol for gather this information.
["analogRead", "digitalRead"].forEach(function(fn) {
var isAnalog = fn === "analogRead";
Expand Down Expand Up @@ -812,6 +873,11 @@ Particle.prototype.close = function() {
state.server.close();
};

function scale(value, inMin, inMax, outMin, outMax) {
return (value - inMin) * (outMax - outMin) /
(inMax - inMin) + outMin;
}

function constrain(value, lower, upper) {
return Math.min(upper, Math.max(lower, value));
}
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "particle-io",
"description": "Particle Core & Photon IO Plugin for Johnny-Five",
"version": "0.14.0",
"version": "0.15.0",
"homepage": "https://github.com/rwaldron/particle-io",
"author": {
"name": "Rick Waldron <waldron.rick@gmail.com>",
Expand Down Expand Up @@ -31,6 +31,10 @@
{
"name": "Brian Genisio",
"email": "<BrianGenisio@Gmail.com>"
},
{
"name": "Donovan Buck",
"email": "<donovan@donovan.bz>"
}
],
"keywords": [
Expand Down
30 changes: 29 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ board.on("ready", function() {

**servoWrite(pin, value)**

> Sets the pin to a value between 0 and 180, where the value represents degrees of the servo horn. The value is converted to a PWM signal. PWM is available on D0, D1, A0, A1, A4, A5, A6 and A7.
> If the value is less than 544, sets the pin to a value constrained between 0 and 180, where the value represents degrees of the servo horn. If the value is 545 or greater, sets the pin to a value in microseconds.

Example:
```js
Expand All @@ -228,6 +228,34 @@ board.on("ready", function() {
});
```

```js
var board = new Particle(...);

board.on("ready", function() {

// Set the servo duty cycle to 1759 microseconds
// Note that the servo pwm frequency is 50mhz and
// the default servo range is 600-2400 microseconds
this.servoWrite("D0", 1759);

});
```

**servoConfig(pin, min, max)**

> Sets the range for the servo PWM duty cycle. The default range is 600 - 2400 microseconds. Can be called instead of pin mode.

Example:
```js
var board = new Particle(...);

board.on("ready", function() {

this.servoConfig("D0", 690, 2310);

});
```


**digitalRead(pin, handler)** Setup a continuous read handler for specific digital pin (D0-D7).

Expand Down
57 changes: 55 additions & 2 deletions test/particle.js
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,6 @@ exports["Particle.prototype.servoWrite"] = {
}
test.done();
},

servoWriteDigital: function(test) {
test.expect(3);

Expand All @@ -774,7 +773,6 @@ exports["Particle.prototype.servoWrite"] = {
}
test.done();
},

servoWriteAnalog: function(test) {
test.expect(3);

Expand All @@ -787,6 +785,61 @@ exports["Particle.prototype.servoWrite"] = {
for (var i = 0; i < sent.length; i++) {
test.equal(sent[i], buffer.readUInt8(i));
}
test.done();
},
servoWriteOutsideRange: function(test) {
test.expect(3);

var sent = [0x41, 10, 180];

this.particle.servoWrite("A0", 220);

var buffer = this.socketwrite.args[0][0];

for (var i = 0; i < sent.length; i++) {
test.equal(sent[i], buffer.readUInt8(i));
}
test.done();
},
servoWriteMicroseconds: function(test) {
test.expect(4);

var sent = [0x43, 10, 14, 12];

this.particle.servoWrite("A0", 1550);

var buffer = this.socketwrite.args[0][0];

for (var i = 0; i < sent.length; i++) {
test.equal(sent[i], buffer.readUInt8(i));
}
test.done();
},
servoWriteMicrosecondsOutsideRange: function(test) {
test.expect(4);

var sent = [0x43, 10, 96, 18];

this.particle.servoWrite("A0", 3000);

var buffer = this.socketwrite.args[0][0];

for (var i = 0; i < sent.length; i++) {
test.equal(sent[i], buffer.readUInt8(i));
}
test.done();
},
servoConfig: function(test) {
test.expect(4);

test.equal(this.particle.pins[10].pwm.servoMin, 600);
test.equal(this.particle.pins[10].pwm.servoMax, 2400);

this.particle.servoConfig("A0", 1000, 2000);

test.equal(this.particle.pins[10].pwm.servoMin, 1000);
test.equal(this.particle.pins[10].pwm.servoMax, 2000);

test.done();
}
};
Expand Down