diff --git a/index.js b/index.js index 9e995d0..a8e3c0f 100644 --- a/index.js +++ b/index.js @@ -31,10 +31,10 @@ var iridium = { buffer: "", data: "", messagePending:0, - binary: {mode: false, buffer: new Buffer(512), bufferCounter: 0}, + binary: {mode: false, buffer: new Buffer(512), bufferCounter: 0}, errors: [ /ERROR/ - ], + ], lock:0, pending:0, globals: { @@ -47,13 +47,13 @@ var iridium = { maxAttempts: 10, //max attempts to send a message port: "/dev/ttyUSB0", flowControl: false - }, + }, // emit a 'ringalert' event if the SBDRING unsollicited response is received sbdring: function() { iridiumEvents.emit('ringalert'); }, - - + + // log if debug enabled log: function(message) { if(iridium.globals.debug){ @@ -71,23 +71,23 @@ var iridium = { var regerr = m[2]; iridium.log("Registration result: "+regevent+" with error "+regerr); }, - + unsollicited: { "SBDRING": { - pattern: /^SBDRING/, + pattern: /^SBDRING/, execute: 'sbdring' }, "AREG": { - pattern: /^\+AREG/, + pattern: /^\+AREG/, execute: 'areg' } }, - + // this is the modem initialization process - echo off, clear all buffers (MO & MT) // query registration status (should return 2 = registered) // enable ring alert (AT+SBDMTA=1) - + init: function() { iridium.batchProcess([ iridium.echoOff, @@ -105,44 +105,46 @@ var iridium = { }else{ iridium.log("Batch process completed OK", err, results); } - + }); }, - + initComplete: function(callback) { iridiumEvents.emit('initialized'); iridium.log("[SBD] IRIDIUM INITIALIZED"); callback(null); }, - - + + sendCompressedMessage: function(text, callback){ zlib.deflateRaw(new Buffer(text,'utf-8'), function(err, buffer) { if (!err) { iridium.log("Text compressed, initial length "+text.length+", compressed length "+buffer.length); - + iridium.c_attempt = 0; iridium.mailboxSend(buffer, callback); } - }); + }); }, mailboxCheck: function() { if (iridium.lock) { iridium.pending++; } else { - iridium.sendMessage(""); + iridium.sendMessage("", function(message) { + iridium.log(message); + }); } }, - + mailboxSend: function(buffer, callback){ iridium.c_attempt++; - if(iridium.c_attempt <= iridium.globals.maxAttempts){ + if(iridium.c_attempt <= iridium.globals.maxAttempts){ iridium.lock=1; iridium.sendBinaryMessage(buffer, function(err, momsn) { if (err==null) { if (buffer) iridium.log("[SBD] Binary message sent successfully, assigned MOMSN "+momsn); - + // check to see if there are other messages pending - if there are, send a new mailbox check to fetch them in 1 second if (iridium.pending>0) setTimeout(function() { iridium.sendMessage(""); @@ -151,32 +153,32 @@ var iridium = { iridium.lock=0; } callback(false,momsn); - + } else { iridium.log("[SBD] Iridium returned error "+err+", will retry in 20s"); setTimeout(function() { iridium.mailboxSend(buffer, callback); }, 20000); } - - }); + + }); }else{ iridium.log('[SBD] Failed to send. The maxAttempts of send requests has been reached.'); callback({error:'Failed to send. The maxAttempts of send requests has been reached.'}); } }, - + sendBinaryMessage: function(message, callback, maxWait) { - + if (message.length==0) { iridium.sendMessage(message, callback, maxWait); return; } - - var buffer = (message instanceof Buffer)?message:new Buffer(message); - + + var buffer = (message instanceof Buffer)?message:new Buffer(message); + var command = "AT+SBDWB="+buffer.length; - + var ob = new Buffer(buffer.length+2); var sum = 0; for (var i=0;i>=8; ob[buffer.length]=sum&0xff; - - - - // first write the binary message to storage - issue AT+SBDWB and wait for the modem to say READY + + + + // first write the binary message to storage - issue AT+SBDWB and wait for the modem to say READY iridium.AT(command, /READY/, ALL, function(err, text) { - + if (err) { iridium.messagePending = 0; iridium.clearMOBuffers(function() { @@ -199,7 +201,7 @@ var iridium = { }); return; } - + // send the binary message and wait for OK iridium.ATS(ob, OK, ALL, function(berr) { if (berr) { @@ -209,11 +211,11 @@ var iridium = { }); return; } - - + + iridium.messagePending = 1; iridium.waitForNetwork(function(xerr) { - + if (xerr) { iridium.messagePending = 0; iridium.clearMOBuffers(function() { @@ -221,29 +223,29 @@ var iridium = { }); return; } - - - + + + iridium.messagePending=2; iridium.disableSignalMonitoring(function(xcallback) { iridium.initiateSession(callback); }); }, iridium.globals.maxWait); - + }); }); }, // send a message via SBD and call back when done sendMessage: function(message, callback, maxWait) { - + // if no message is given, this is a mailbox check, so clear the MO storage - var command = message?"AT+SBDWT="+message:"AT+SBDD0"; - + var command = message?"AT+SBDWT="+message:"AT+SBDD0"; + // write the MO message, wait for network (+CIEV event) // disable signal monitoring (+CIER=0) then send the message (+SBDIXA) - + iridium.AT(command, OK, ALL, function(err, text) { - + if (err) { iridium.messagePending = 0; iridium.clearMOBuffers(function() { @@ -251,10 +253,10 @@ var iridium = { }); return; } - + iridium.messagePending = 1; iridium.waitForNetwork(function(xerr) { - + if (xerr) { iridium.messagePending = 0; iridium.clearMOBuffers(function() { @@ -262,9 +264,9 @@ var iridium = { }); return; } - - - + + + iridium.messagePending=2; iridium.disableSignalMonitoring(function(xcallback) { iridium.initiateSession(callback); @@ -272,7 +274,7 @@ var iridium = { }, maxWait); }); }, - + // in binary mode we do not stop at OK or any other regexp, it's all time-based (it reads all available data for bufferTimeout seconds) enableBinaryMode: function(bufferTimeout) { iridium.binary.mode = true; @@ -284,7 +286,7 @@ var iridium = { iridium.binary.mode = false; }, bufferTimeout); }, - + // read line by line or a whole binary blob, depending on the mode readSBD: function(emitter, buffer) { serialEmitter = emitter; @@ -304,14 +306,14 @@ var iridium = { }); } }, - - + + // open the serial port // config options are: "debug" (set to 1 to monitor the AT commands and response // and "port" (the actual device to use - defaults to /dev/ttyUSB0) - + open: function(config) { - + if (config) { //change globals... for(var key in config){ @@ -337,14 +339,14 @@ var iridium = { delete(er); return; } - + for (x in iridium.unsollicited) { if (iridium.unsollicited[x].pattern.test(data)) { iridium[iridium.unsollicited[x].execute](data); return; } } - + for (x in iridium.errors) { if (iridium.errors[x].test(data)) { df(iridium.errors[x], iridium.buffer); @@ -354,8 +356,8 @@ var iridium = { return; } } - - + + if (!kr || kr.test(data)) { iridium.buffer+=(data+"\n"); } @@ -364,15 +366,15 @@ var iridium = { iridium.buffer=""; delete(df); delete(er); - - - + + + } }); _serialPort.on("error", function (error) { iridium.log("ERROR: "+error); }); - + _serialPort.on("open", function() { if(iridium.globals.flowControl){ iridium.init(); @@ -380,16 +382,16 @@ var iridium = { iridium.disableFlowControl(iridium.init); } }); - + }, - - - - + + + + waitForNetwork: function(callback, maxWait) { iridium.ATS("AT+CIER=1,1,0,0", /\+CIEV:0,[^0]/, ALL, callback, iridium.globals.maxWait?iridium.globals.maxWait:iridium.globals.timeoutForever); }, - + getSystemTime: function(callback) { iridium.AT("AT+CCLK?", OK, ALL, function(err, result) { if (err) callback(err); @@ -400,16 +402,16 @@ var iridium = { var ctime = new Date(Date.UTC(2000+Number(m[1]), m[2]-1, m[3], m[4], m[5], m[6])); callback(null, ctime); } - + } }); }, - + disableFlowControl: function(callback){ iridium.log("[SDB] DISABLING FLOW CONTROL"); iridium.ATS("AT&K0", OK, ALL, callback, iridium.globals.simpleTimeout); }, - + disableSignalMonitoring: function(callback) { iridium.ATS("AT+CIER=0,0,0,0", OK, ALL, callback, iridium.globals.simpleTimeout); }, @@ -419,47 +421,47 @@ var iridium = { ringAlertEnable: function(callback) { iridium.ATS("AT+SBDMTA=1", OK, ALL, callback, iridium.globals.simpleTimeout); }, - + echoOff: function(callback) { iridium.ATS("ATE0", OK, ALL, callback, iridium.globals.simpleTimeout); }, - + enableRegistration: function(callback) { iridium.ATS("AT+SBDAREG=1", OK, ALL, callback, iridium.globals.simpleTimeout); }, - + clearMOBuffers: function(callback) { iridium.ATS("AT+SBDD0", OK, ALL, callback, iridium.globals.simpleTimeout); }, - + clearMTBuffers: function(callback) { iridium.ATS("AT+SBDD1", OK, ALL, callback, iridium.globals.simpleTimeout); }, - + clearBuffers: function(callback) { iridium.ATS("AT+SBDD2", OK, ALL, callback, iridium.globals.simpleTimeout); }, - + // emit a 'newmessage' event containing the message // and the number of queued messages still waiting at the server readBinaryMessage: function(mtqueued, callback) { iridium.enableBinaryMode(1000); iridium.AT("AT+SBDRB", false, false, function(err, buffer) { - + if (err) { iridium.clearMTBuffers(function() { callback(err); }); return; } - + var ib = buffer; var messageLength = ib.readUInt16BE(0); var messageBuffer = new Buffer(messageLength); ib.copy(messageBuffer, 0, 2, messageLength+2); - - - + + + iridium.log("Received message is "+messageBuffer.toString('hex')); iridium.binary.mode = false; iridium.pending = mtqueued; @@ -467,20 +469,20 @@ var iridium = { iridium.clearMTBuffers(callback); }, iridium.globals.simpleTimeout); }, - - + + // emit a 'newmessage' event containing the message // and the number of queued messages still waiting at the server readMessage: function(mtqueued, callback) { iridium.AT("AT+SBDRT", OK, ALL, function(err, text) { - + if (err) { iridium.clearMTBuffers(function() { callback(err); }); return; } - + var m = text.match(/SBDRT:[^]{2}(.*)/); var rmessage = m[1]; iridium.log("Received message is "+rmessage); @@ -489,12 +491,12 @@ var iridium = { }, iridium.globals.simpleTimeout); }, - + // most important function, initiates a SBD session and sends/receives messages initiateSession: function(callback) { iridium.AT("AT+SBDIXA", OK, /\+SBDIX/, function(err, text) { - - + + if (err) { iridium.messagePending = 1; iridium.clearMOBuffers(function() { @@ -503,16 +505,16 @@ var iridium = { return; } var m = text.match(/\+SBDIX: (\d+), (\d+), (\d+), (\d+), (\d+), (\d+)/); - + if(m && m.length){ - + var status = m[1]; var momsn = m[2]; var mtstatus = m[3]; var mtmsn = m[4]; var mtlen = m[5]; var mtqueued = m[6]; - + if (status<=4) { iridium.log("MO message transferred successfully"); iridium.messagePending = 0; @@ -538,57 +540,57 @@ var iridium = { }); return; } - - + + if (mtqueued>0) { iridium.log("There are still "+mtqueued+" messages waiting!"); } - + if (mtstatus==0) { iridium.log("No MT messages are pending"); iridium.finishSession(callback,momsn); } else if (mtstatus==1) { iridium.log("A MT message has been transferred, use AT+SBDRT to read it"); - - + + //disableFlowControl(function(){ - + iridium.readBinaryMessage(mtqueued, function() { iridium.clearMOBuffers(function(err) { callback(err, momsn); }); }); - + //}); - + return; } else { iridium.log("Error determining MT status: "+mtstatus); iridium.finishSession(callback,momsn); } - - + + }else{ iridium.log("Error parsing SBDIX!"); iridium.finishSession(callback,momsn); } - - + + }); }, finishSession: function(callback,momsn){ iridium.clearMOBuffers(function(err) { callback(err, momsn); - }); + }); }, // simplified AT command function - when you don't care about the result // the end callback is simply a null function (does nothing) ATS: function(command, endregexp, keepregexp, callback, timeout) { iridium.AT(command, endregexp, keepregexp, callback, timeout); }, - - + + // send an AT command to the modem and call datafunction when complete // endregexp is the regular expression that marks the end of the response (usually the string OK) // keepregexp tells it to filter the response and keep only the lines that match it @@ -608,7 +610,7 @@ var iridium = { iridium.log("Sending a timeout event for command "+command); //datafunction("TIMEOUT"); }, timeout); - + if (command instanceof Buffer) { iridium.log("[BINARY] > "+command.toString('hex')); _serialPort.write(command); @@ -617,10 +619,10 @@ var iridium = { _serialPort.write(command+"\r"); } } - - - - + + + + } -module.exports = iridium; \ No newline at end of file +module.exports = iridium;