UNPKG

node-red-contrib-lorawan

Version:

Node-RED module for the LoRaWAN RN2483 and RN2903 radio modules

202 lines (181 loc) 5.24 kB
var util = require('util'); var EventEmitter = require('events'); var SerialPort = require('serialport'); const Delimiter = require('@serialport/parser-delimiter') const RN2483 = require('./commands.js'); // LoRaWAN constructor function LoRaWAN(config) { EventEmitter.call(this); this.config = config; this.isListening = false; this.callbackStack = []; this._initSerial(); } util.inherits(LoRaWAN, EventEmitter); LoRaWAN.prototype.init = function () { var me = this; if (me.serialConnection.isOpen) { me.emit('open' + me.config.id); me.initRN2483(); } else { me.serialConnection.open(function (err) { if (err) { me.emit('error' + me.config.id, err); } else { me.emit('open' + me.config.id); me.initRN2483(); } }); } }; LoRaWAN.prototype.initRN2483 = function () { var me = this; var async = require('async'); var cmds_sequence = me.init_sequence_p2p; console.log(cmds_sequence); async.eachSeries(cmds_sequence, function (item, next) { me.send(item, function (err, data) { if (me.responseOK(item, data)) next(); else return; }) }, function (err) { if (err == null) console.log('Initialisation OK !'); else console.log('Error on initialization: ' + err); }); } LoRaWAN.prototype.searchCmd = function (cmd) { while ((typeof RN2483.commands[cmd] == 'undefined') && (cmd != '')) cmd = cmd.substr(0, cmd.lastIndexOf(" ")); return cmd; } LoRaWAN.prototype.searchResponse = function (cmd, response) { var tab = response.toString('ascii').split(' '); var i = 1; var answer = tab[0]; while ((typeof RN2483.commands[cmd][answer] == 'undefined') && (i <= tab.length)) { answer = answer + " " + tab[i]; console.log(answer); i = i + 1; } if (i > tab.length) return ''; else return answer; } LoRaWAN.prototype.responseOK = function (cmd, response) { console.log('Verify CMD = ' + cmd + ' with RSP = ' + response); cmd = this.searchCmd(cmd); response = this.searchResponse(cmd, response); // Should check response if (cmd != '') switch (RN2483.commands[cmd][response]) { case 0: return true; default: return false; } } LoRaWAN.prototype._initSerial = function () { var me = this; this.serialConnection = new SerialPort(this.config.serialPort, { autoOpen: false, lock: this.config.lock, baudRate: this.config.baudRate, dataBits: this.config.dataBits, stopBits: this.config.stopBits, parity: this.config.parity, }); this.init_sequence_p2p = [ 'mac pause', 'radio set pwr ' + this.config.modeP2P_radioPwr, 'radio set freq ' + this.config.modeP2P_radioFreq, 'radio set sf ' + this.config.modeP2P_radioSf, 'radio set cr ' + this.config.modeP2P_radioCr, 'radio set bw ' + this.config.modeP2P_radioBw, 'radio set crc ' + this.config.modeP2P_radioCRC ]; this.serialConnection.parser = this.serialConnection.pipe(new Delimiter({ delimiter: '\r\n' })); this.serialConnection.on('disconnect', function () { me.emit('disconnect' + me.config.id); }); }; LoRaWAN.prototype.close = function (cb) { var me = this; // me.lorawanAPI.removeAllListeners('frame_object'); me.removeAllListeners('open' + me.config.id); me.removeAllListeners('data' + me.config.id); me.removeAllListeners('sent' + me.config.id); me.removeAllListeners('error' + me.config.id); me.removeAllListeners('disconnect' + me.config.id); if (me.serialConnection.isOpen) { me.serialConnection.close(cb); } }; LoRaWAN.prototype.listen = function () { var me = this; if (!me.isListening) { me.isListening = true; this.serialConnection.parser.on('data', function (data) { console.log('DATA: ' + data) // if stack is not empty, we receive a response to a sent command if (me.callbackStack.length > 0) { var item = me.callbackStack.pop(); var cmd = item.data; var callback = item.callback; console.log('Answer to "' + cmd + '": ' + data.toString('ascii')); callback(null, data); } else { // else we receive a data from radio to send console.log("Received without call: " + data.toString('ascii')); // MUST analyse radio rx or radio err to know if its ok or timeout me.emit('data' + me.config.id, data); } }).on('error', function (err) { me.emit('error' + me.config.id, err); }); } }; LoRaWAN.prototype.transmit = function (cmd) { var me = this; me.send(cmd, function (err, data) { if (me.responseOK(cmd, data)) { console.log('CMD: ' + cmd + ' result = ' + data); } }); } LoRaWAN.prototype.send = function (data, callback) { var me = this; if (me.serialConnection.isOpen) { try { console.log("Send command " + data); me.serialConnection.write(data + "\r\n", function (err, res) { if (err) { //TODO: this is not right with our protocol // I'm assuming that if there is an error on the line // you won't receive serial data for the request. Hence // we remove the callback from the stack. me.callbackStack.splice(me.callbackStack.indexOf({ data, callback }), 1); callback(err); }; }); me.callbackStack.unshift({ data, callback }); me.emit('sent' + me.config.id); } catch (error) { me.emit('error' + me.config.id, error); } } }; module.exports = LoRaWAN;