var dgram = require('dgram'); var protocol = require('./protocol'); var BufferReader = require('buffer-reader'); var responseHandlers = {}; function registerResponseHandler(command, callback) { if (!responseHandlers.hasOwnProperty(command)) responseHandlers[command] = [callback]; else responseHandlers[command].push(callback); } function callResponseHandlers(command, reader, error) { if (!responseHandlers.hasOwnProperty(command)) return; newHandlers = []; responseHandlers[command].forEach(function(callback) { if (!callback(reader, error)) newHandlers.push(callback); }); responseHandlers[command] = newHandlers; } var serverHost = ''; var serverPort = 0; var client = dgram.createSocket('udp4'); client.on('message', function (message, remote) { console.log(message.toString('hex')); if (message.length < 2) return; var reader = new BufferReader(message); if (reader.nextInt8() !== protocol.Command.Reply) return; var command = reader.nextInt8(); if (command === protocol.Command.Error) callResponseHandlers(reader.nextInt8(), reader, true) else callResponseHandlers(command, reader, false); }); function requestResponse(buffer, callback) { if (buffer === null || buffer.length == 0) return; console.log('> ' + buffer.toString('hex')); var command = buffer.readInt8(0); var cancelled = false; var timeout = setTimeout(function() { cancelled = true; callback(null, true); clearTimeout(timeout); }, 2000); registerResponseHandler(command, function(reader, error) { if (cancelled) return; clearTimeout(timeout); callback(reader, error); return true; }); client.send(buffer, 0, buffer.length, serverPort, serverHost, function(err, bytes) { if (err) onError(); }); } function readModeData(mode, reader) { switch (mode) { case protocol.Mode.Static: return { brightness: reader.nextInt16LE() }; case protocol.Mode.Custom: var values = []; while (reader.tell() < reader.buf.length) values.push(reader.nextInt16LE()); return { brightness: values }; case protocol.Mode.Alternate: return { interval: reader.nextInt16LE(), brightness: reader.nextInt16LE() }; case protocol.Mode.Slide: return { interval: reader.nextInt16LE(), brightness: reader.nextInt16LE(), direction: reader.nextInt8(), fadeOutTime: reader.nextInt16LE() }; } return null; } function lsb(value) { return value & 0xFF; } function msb(value) { return (value >> 8) & 0xFF; } function writeModeData(mode, data) { switch (mode) { case protocol.Mode.Static: if (typeof(data.brightness) == 'undefined') data.brightness = 0; return new Buffer([protocol.Command.SetMode, mode, lsb(data.brightness), msb(data.brightness)]); case protocol.Mode.Custom: var brightness = typeof(data.brightness) !== 'undefined' ? data.brightness.split(',') : []; var valueCount = Math.min(16, brightness.length); var buffer = Buffer.alloc(2 + (valueCount * 2)); buffer.writeInt8(protocol.Command.SetMode, 0); buffer.writeInt8(mode, 1); for (var index = 0; index < valueCount; index++) buffer.writeInt16LE(brightness[index], 2 + (index * 2)); return buffer; case protocol.Mode.Alternate: if (typeof(data.brightness) == 'undefined') data.brightness = 0; if (typeof(data.interval) == 'undefined') data.interval = 500; return new Buffer([protocol.Command.SetMode, mode, lsb(data.interval), msb(data.interval), lsb(data.brightness), msb(data.brightness)]); case protocol.Mode.Slide: if (typeof(data.brightness) == 'undefined') data.brightness = 0; if (typeof(data.interval) == 'undefined') data.interval = 500; if (typeof(data.direction) == 'undefined') data.direction = 0; if (typeof(data.fadeOutTime) == 'undefined') data.fadeOutTime = 0; return new Buffer([protocol.Command.SetMode, mode, lsb(data.interval), msb(data.interval), lsb(data.brightness), msb(data.brightness), data.direction, lsb(data.fadeOutTime), msb(data.fadeOutTime)]); } } module.exports = { init: function(host, port) { serverHost = host; serverPort = port; }, ping: function(callback) { requestResponse(new Buffer([protocol.Command.Ping]), function(reader, error) { if (!error) { callback( { stepCount: reader.nextInt8() }, false); } else callback(null, true); }); }, getMode: function(callback) { requestResponse(new Buffer([protocol.Command.GetMode]), function(reader, error) { if (!error) { var data = { mode: reader.nextInt8() }; data.data = readModeData(data.mode, reader); callback(data, false); } else callback(null, true); }); }, setMode: function(mode, data, callback) { if (!protocol.Mode.hasOwnProperty(mode)) return; requestResponse(writeModeData(protocol.Mode[mode], data), function(reader, error) { if (!error) { var data = { mode: reader.nextInt8() }; data.data = readModeData(data.mode, reader); callback(data, false); } else callback(null, true); }); } }