ggserver
Version:
GeoGate is an opensource GPS tracking server framework
166 lines (137 loc) • 6.05 kB
JavaScript
/*
* Copyright 2014 Fulup Ar Foll.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This adaptater takes AIS input in AIS/NMEA Binary Format from either GPSd or Socket
* And push event without creating a device per vessel
*/
'use strict';
var Debug = require("../lib/_Debug");
var TcpClient = require('../lib/_TcpClient'); // make each device a fake devid device
var TrackerCmd = require("../lib/_TrackerCmd");
// use localdev tree if available
var AisDecode;
if (process.env.GEOGATE !== 'dev')
AisDecode = require('ggencoder').AisDecode;
else AisDecode = require("../../encoder/ApiExport").AisDecode;
// this function scan active device table and remove dead one based on inactivity timeout
function SetGarbage (proxy, timeout) {
// let's call back ourself after timeout*1000/4
proxy.Debug (4, "SetGarbage timeout=%d", timeout);
setTimeout (function(){SetGarbage (proxy, timeout);}, timeout*500);
// let compute timeout timeout limit
var lastshow = new Date().getTime() - (timeout *1000);
for (var mmsi in proxy.vessels) {
var vessel = proxy.vessels[mmsi];
if (vessel.lastshow < lastshow) {
proxy.Debug (5, "Removed Vessel mmsi=%s", mmsi);
delete proxy.vessels [mmsi];
}
}
};
// Adapter is an object own by a given device controller that handle data connection
function DevAdapter (controller) {
this.id = controller.svc;
this.uid = "//" + controller.svcopts.adapter + "/" + controller.svc + "@" + controller.svcopts.hostname + ":" +controller.svcopts.remport;
this.info = 'AisProxyNmea';
this.control = 'tcpfeed'; // this adapter connect onto a remote server
this.debug = controller.svcopts.debug; // inherit debug from controller
this.cleanup = controller.svcopts.cleanup || 600; // inherit debug from controller
this.controller= controller; // keep a link to device controller and TCP socket
this.gateway = controller.gateway;
this.Debug (1,"uid=%s", this.uid);
this.session = {}; // special object to store AIS multipart messages
this.vessels = []; // cache for vessel positions
this.event = controller.gateway.backend.event; // hook backend event handler
SetGarbage (this, this.cleanup);
};
// Import debug method
DevAdapter.prototype.Debug = Debug;
// Ais as multiple devices attached to one single tcp session
DevAdapter.prototype.ClientConnect = function (socket) {
// in case we are facing gpsd send nmea watch command
socket.write ('?WATCH={"enable":true,"nmea":true}');
// attach line counter and tempry buffer to socket session
socket.lineidx = 0; // index within buffer
socket.linebuf = new Buffer (256); // intermediary buffer
};
// Ais cannot logout device, they may still exit with gpsd cleanup function
DevAdapter.prototype.ClientQuit = function (socket) {
};
DevAdapter.prototype.ParseBuffer = function(socket, buffer) {
this.Debug (9, "request=[%s]", buffer);
// split buffer multiple lines if any and remove \r\n
for (var idx=0; idx < buffer.length; idx++) {
switch (buffer [idx]) {
case 0x0A: // new line \n
var status = this.ParseLine (socket, socket.linebuf.toString ('ascii',0, socket.lineidx));
socket.lineidx=0;
break;
case 0x0D: break; // cariage return \r
default:
socket.linebuf[socket.lineidx] = buffer [idx];
socket.lineidx++;
}
}
};
// Process a full line Gpsd/Json send one object per line
DevAdapter.prototype.ParseLine = function(socket, line) {
var device;
this.Debug (8, "line=[%s]", line);
// send AIS message to parser
//try {
var ais= new AisDecode (line, this.session);
// } catch(e) {return;}
// check if message was valid
if (!ais.valid) return;
/* we handle static AIS message type 5,24 as authentication request
* and message 1,2,3,18 and position update resquest
* check ../GpsdAisDecode for more information on message types */
switch (ais.aistype) {
case 1:
case 2:
case 3:
case 18:
this.vessels[ais.mmsi] =
{ lat: ais.lat
, lon: ais.lon
, lastshow: new Date().getTime()
};
this.event.emit ("ais-data", ais, line);
break;
case 5: // static information class A
case 24: // static information class B
if (this.vessels[ais.mmsi]) {
ais.lat = this.vessels[ais.mmsi].lat;
ais.lon = this.vessels[ais.mmsi].lon;
}
this.event.emit ("ais-data", ais, line);
break;
default:
this.Debug (3,"Hoops: AIS aistype=%s not supported", ais.aistype);
}
};
// send a command to activate GPSd service
DevAdapter.prototype.SendCommand = function(device, action, arg1) {
switch (action) {
case TrackerCmd.SendTo.LOGOUT: break; // everthing was take care at TcpFeed level
default:
this.Debug (1,"Hoops %s UNKN_CMD=[%s]", this.uid, action);
return (-1);
};
// return OK status
this.Debug (5,"buffer=[%s]", this.packet);
return (0);
};
module.exports = DevAdapter; // http://openmymind.net/2012/2/3/Node-Require-and-Exports/