Skip to content

Instantly share code, notes, and snippets.

@ozzieg
Created August 9, 2014 20:16
Show Gist options
  • Save ozzieg/372449b1d900ed31c81d to your computer and use it in GitHub Desktop.
Save ozzieg/372449b1d900ed31c81d to your computer and use it in GitHub Desktop.
Electric Imp Device code utilizing the Firmata protocol based on Firmata implementation in Javascript from http://jgautier.github.com/firmata/. Utilizes the UART to talk to an Arduino.
server.log("Device started, impee_id " + hardware.getimpeeid() + " and mac = " + imp.getmacaddress() );
//------------------------------------------------------------------------------------------------------------------------------
// Uart57 for TX/RX
SERIAL <- hardware.uart57;
// FIRMATA CONSTANTS
const PIN_MODE = 0xF4;
const REPORT_DIGITAL = 0xD0;
const REPORT_ANALOG = 0xC0;
const DIGITAL_MESSAGE = 0x90;
const START_SYSEX = 0xF0;
const END_SYSEX = 0xF7;
const QUERY_FIRMWARE = 0x79;
const REPORT_VERSION = 0xF9;
const ANALOG_MESSAGE = 0xE0;
const EXTENDED_ANALOG = 0x6F;
const CAPABILITY_QUERY = 0x6B;
const CAPABILITY_RESPONSE = 0x6C;
const PIN_STATE_QUERY = 0x6D;
const PIN_STATE_RESPONSE = 0x6E;
const ANALOG_MAPPING_QUERY = 0x69;
const ANALOG_MAPPING_RESPONSE = 0x6A;
const I2C_REQUEST = 0x76;
const I2C_REPLY = 0x77;
const I2C_CONFIG = 0x78;
const STRING_DATA = 0x71;
const SYSTEM_RESET = 0xFF;
const PULSE_OUT = 0x73;
const PULSE_IN = 0x74;
const SAMPLING_INTERVAL = 0x7A;
const STEPPER = 0x72;
const ONEWIRE_DATA = 0x73;
MIDI_RESPONSE <- {};
SYSEX_RESPONSE <- {};
MIDI_RESPONSE[REPORT_VERSION] <- function(board) {
board.version.major = board.currentBuffer[1];
board.version.minor = board.currentBuffer[2];
board.emit("report-version");
};
MIDI_RESPONSE[ANALOG_MESSAGE] <- function(board) {
local value = board.currentBuffer[1] | (board.currentBuffer[2] << 7);
local port = board.currentBuffer[0] & 0x0F;
if (board.pins[board.analogPins[port]]) {
board.pins[board.analogPins[port]].value = value;
}
board.emit("analog-read-" + port, value);
board.emit("analog-read", {
pin= port,
value= value
});
};
MIDI_RESPONSE[DIGITAL_MESSAGE] <- function (board) {
local port = (board.currentBuffer[0] & 0x0F);
local portValue = board.currentBuffer[1] | (board.currentBuffer[2] << 7);
server.log("digital message: port: " + port + " value: " + portValue);
for (local i = 0; i < 8; i++) {
local pinNumber = 8 * port + i;
local pin = board.pins[pinNumber];
if (pin && (pin.mode == board.MODES.INPUT)) {
pin.value = (portValue >> (i & 0x07)) & 0x01;
this.MODES.emit("digital-read-" + pinNumber, pin.value);
board.emit("digital-read", {
pin= pinNumber,
value= pin.value
});
}
}
};
SYSEX_RESPONSE[CAPABILITY_RESPONSE] <- function(board) {
server.log("capability response received.");
};
SYSEX_RESPONSE[ANALOG_MAPPING_RESPONSE] <- function(board) {
server.log("analog mapping response received.");
local pin = 0;
local currentValue;
for (local i = 2; i < board.currentBuffer.length - 1; i++) {
currentValue = board.currentBuffer[i];
board.pins[pin].analogChannel = currentValue;
if (currentValue != 127) {
board.analogPins.push(pin);
}
pin++;
}
board.emit("analog-mapping-query");
};
SYSEX_RESPONSE[PIN_STATE_RESPONSE] <- function(board) {
server.log("analog mapping response received.");
};
SYSEX_RESPONSE[STRING_DATA] <- function(board) {
local str = format("%s", board.currentBuffer.slice(2, -1));
board.emit("string", str);
server.log("debug msg: " + str);
};
SYSEX_RESPONSE[QUERY_FIRMWARE] <- function (board) {
local firmwareBuf;
board.firmware.version.major = board.currentBuffer[2];
board.firmware.version.minor = board.currentBuffer[3];
for (local i = 4, length = board.currentBuffer.len() - 2; i < length; i += 2) {
firmwareBuf += format("%c", ((board.currentBuffer[i] & 0x7F) | ((board.currentBuffer[i + 1] & 0x7F) << 7)));
}
board.firmware.name = firmwareBuf;
board.emit("query-firmware");
};
board <- {
currentBuffer = [],
MODES = {
INPUT= 0x00,
OUTPUT= 0x01,
ANALOG= 0x02,
PWM= 0x03,
SERVO= 0x04,
SHIFT= 0x05,
I2C= 0x06,
ONEWIRE= 0x07,
STEPPER= 0x08,
IGNORE= 0x7F,
UNKOWN= 0x10
},
pins = [
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0 },
{ report = 0, value = 0, mode = 0, analogChannel = 0 },
{ report = 0, value = 0, mode = 0, analogChannel = 0 },
{ report = 0, value = 0, mode = 0, analogChannel = 0 },
{ report = 0, value = 0, mode = 0, analogChannel = 0 },
{ report = 0, value = 0, mode = 0, analogChannel = 0 },
{ report = 0, value = 0, mode = 0, analogChannel = 0 },
],
analogPins = [ 14, 15, 16, 17, 18, 19 ],
listeners = {},
sp = {},
version = { major = 0, minor = 0 },
firmware = { name = "", version = { major = 0, minor = 0 }},
function emit(event, data = null) {
//server.log("Event: " + event);
//server.log("Data: " + data);
if( event in listeners ) {
if( data != null ) {
listeners[event](board, data);
} else {
listeners[event](board);
}
}
},
function pinMode(pin, mode) {
board.pins[pin].mode = mode;
board.sp.write(format("%c%c%c", PIN_MODE, pin, mode));
},
function digitalWrite(pin, value) {
local port = math.abs(math.floor(pin / 8));
local portValue = 0;
board.pins[pin].value = value;
for (local i = 0; i < 8; i++) {
if (board.pins[8 * port + i].value) {
portValue = portValue | (1 << i);
}
}
board.sp.write(format("%c%c%c", DIGITAL_MESSAGE | port, portValue & 0x7F, (portValue >> 7) & 0x7F));
},
function analogRead(pin, callback) {
listeners["analog-read-" + pin] <- callback;
},
function digitalRead(pin, callback) {
listeners["digital-read-" + pin] <- callback;
},
function reportAnalogPin(pin, value) {
if(value == 0 || value == 1) {
board.pins[board.analogPins[pin]].report = value;
board.sp.write(format("%c%c", REPORT_ANALOG | pin, value));
}
},
function reportDigitalPin(pin, value) {
if(value == 0 || value == 1) {
board.pins[pin].report = value;
board.sp.write(format("%c%c", REPORT_DIGITAL | pin, value));
}
},
function reset() {
board.sp.write(format("%c", SYSTEM_RESET));
},
function queryCapabilities(callback) {
board.sp.write(format("%c%c%c", START_SYSEX, CAPABILITY_QUERY, END_SYSEX));
},
function queryAnalogMapping(callback) {
listeners["analog-mapping-query"] <- callback;
board.sp.write(format("%c%c%c", START_SYSEX, ANALOG_MAPPING_QUERY, END_SYSEX));
},
function queryFirmware(callback) {
listeners["query-firmware"] <- callback;
board.sp.write(format("%c%c%c", START_SYSEX, QUERY_FIRMWARE, END_SYSEX));
},
function queryPinState(pin, callback) {
board.sp.write(format("%c%c%c", START_SYSEX, PIN_STATE_QUERY, pin, END_SYSEX));
},
function reportVersion(callback) {
listeners["report-version"] <- callback;
board.sp.write(format("%c", REPORT_VERSION));
},
function setSamplingInterval(interval) {
local safeint = interval < 10 ? 10 : (interval > 65535 ? 65535 : interval); // constrained
board.sp.write(format("%c%c%c%c%c", START_SYSEX, SAMPLING_INTERVAL, (safeint & 0xFF),((safeint >> 8) & 0xFF), END_SYSEX));
},
function serialData() {
//server.log("received serial data");
local ch = board.sp.read();
local str = "";
while( ch != -1 ) {
board.currentBuffer.push(ch);
str += format("%c", ch);
ch = board.sp.read();
}
//server.log(str);
local cmd;
if( board.currentBuffer.len() > 0 ) {
if( board.currentBuffer[0] == START_SYSEX &&
SYSEX_RESPONSE[board.currentBuffer[1]] &&
board.currentBuffer[board.currentBuffer.len() - 1] == END_SYSEX ) {
SYSEX_RESPONSE[board.currentBuffer[1]](board);
board.currentBuffer.clear();
}
if( board.currentBuffer.len() == 3 && board.currentBuffer[0] != START_SYSEX ) {
cmd = board.currentBuffer[0] < 240 ? board.currentBuffer[0] & 0xF0 : board.currentBuffer[0];
if( MIDI_RESPONSE[cmd] ) {
MIDI_RESPONSE[cmd](board);
board.currentBuffer.clear();
} else {
board.currentBuffer.clear();
}
}
}
},
function init() {
board.reportVersion(function(board) {
server.log("board version: " + board.version.major + "." + board.version.minor);
board.queryFirmware(function(board) {
server.log("firmware: " + board.firmware.name);
});
});
}
};
//------------------------------------------------------------------------------------------------------------------------------
board.sp = SERIAL;
SERIAL.configure(57600, 8, PARITY_NONE, 1, NO_CTSRTS, board.serialData);
board.init();
//Example Usage:
board.setSamplingInterval(100);
board.reportAnalogPin(0, 1);
board.pinMode(6, board.MODES.OUTPUT);
board.pinMode(7, board.MODES.OUTPUT);
board.digitalWrite(6, 0);
board.digitalWrite(7. 0);
analogValues <- [];
analogValueIndex <- 0;
analogReady <- false;
board.analogRead(0, function(board, data) {
//server.log("value: " + data);
//save off last 30 values
if( analogValues.len() < 30 ) {
analogValues.push(data); //build up the array
} else {
analogReady = true;
analogValues[analogValueIndex] = data;
analogValueIndex++;
if( analogValueIndex == 30 ) {
analogValueIndex = 0;
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment