index.js 7.28 KB
const MUTEX_COMMAND = 'COMMAND';
exports.MUTEX_COMMAND = MUTEX_COMMAND;

const MUTEX_SUBCOMMAND = 'SUBCOMMAND';
exports.MUTEX_SUBCOMMAND = MUTEX_SUBCOMMAND;

const pdu = require('node-pdu');

const ParserReadline = require('@serialport/parser-readline');
const ParserRegex = require('@serialport/parser-regex');

const logger = require('komodo-sdk/logger');
const mutex = require('../mutex-common');
const parsers = require('../serialport-parsers');
const modemInfo = require('../modem-info');

let port;

function writeToPort(data) {
    return new Promise((resolve) => {
        modemInfo.lastWriteTs = new Date();
        port.write(data, (err, bytesWritten) => {
            if (err) logger.warn(`ERROR: ${err.toString()}`);

            logger.verbose('OUTGOING', { data: data.toString(), bytesWritten, err });
            resolve(bytesWritten);
        });
    });
}

exports.writeToPortAndWaitForReadline = function writeToPortAndWaitForReadline(cmd, lockName) {
    let resolved = false;

    return new Promise(async (resolve) => {
        const parser = new ParserReadline({ delimiter: parsers.PARSER_READLINE_DELIMITER });
        parser.on('data', (data) => {
            port.unpipe(parser);
            mutex.unlock(lockName || MUTEX_COMMAND, cmd.trim());
            if (!resolved) {
                resolved = true;
                resolve(data);
            }
        });

        await mutex.lock(lockName || MUTEX_COMMAND, cmd.trim());
        port.pipe(parser);
        await writeToPort(cmd);
    });
};

exports.writeToPortAndWaitForOkOrError = function writeToPortAndWaitForOkOrError(cmd, lockName) {
    return new Promise(async (resolve) => {
        const parser = new ParserRegex({ regex: /(?:OK|ERROR)\r\n/ });
        parser.on('data', (data) => {
            port.unpipe(parser);
            mutex.unlock(lockName || MUTEX_COMMAND, cmd.trim());
            resolve(data);
        });

        await mutex.lock(lockName || MUTEX_COMMAND, cmd.trim());
        port.pipe(parser);
        await writeToPort(cmd);
    });
};

exports.sleep = function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, ms || 0);
    });
};


exports.setPort = function setPort(val) {
    port = val;
};

exports.querySignalQuality = function querySignalQuality() {
    return new Promise(async (resolve) => {
        if (!mutex.tryLock(MUTEX_COMMAND, 'querySignalQuality')) {
            resolve(false);
            return;
        }

        await writeToPort('AT+CSQ\r');
        mutex.unlock(MUTEX_COMMAND, 'querySignalQuality');
        resolve(true);
    });
};

exports.queryCOPS = function queryCOPS(lockName) {
    return new Promise(async (resolve) => {
        await mutex.lock(lockName || MUTEX_COMMAND, 'queryCOPS');
        await writeToPort('AT+COPS?\r');
        mutex.unlock(lockName || MUTEX_COMMAND, 'queryCOPS');
        resolve(true);
    });
};

exports.queryCOPSAndSignalQuality = function queryCOPSAndSignalQuality(skipOnLocked) {
    return new Promise(async (resolve) => {
        if (!skipOnLocked) {
            await mutex.lock(MUTEX_COMMAND);
        } else if (!mutex.tryLock(MUTEX_COMMAND, 'queryCOPSAndSignalQuality')) {
            resolve(false);
            return;
        }

        await this.writeToPortAndWaitForOkOrError('AT+COPS?\r', MUTEX_SUBCOMMAND);
        await this.writeToPortAndWaitForOkOrError('AT+CSQ\r', MUTEX_SUBCOMMAND);

        mutex.unlock(MUTEX_COMMAND, 'queryCopsAndSignalQuality');
        resolve(true);
    });
};

exports.queryIMEI = function queryIMEI(lockName) {
    return new Promise(async (resolve) => {
        const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
        parser.on('data', (data) => {
            logger.verbose('INCOMING', { data: data.toString(), parser: 'parserIMEI' });
            port.unpipe(parser);
            mutex.unlock(lockName || MUTEX_COMMAND, 'queryIMEI');
            modemInfo.imei = data.toString().trim() || null;
            logger.info('IMEI extracted', { imei: modemInfo.imei });
            resolve(modemInfo.imei);
        });

        await mutex.lock(lockName || MUTEX_COMMAND, 'queryIMEI');

        port.pipe(parser);
        await writeToPort('AT+CGSN\r');
    });
};

exports.queryIMSI = function queryIMSI(lockName) {
    return new Promise(async (resolve) => {
        const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
        parser.on('data', (data) => {
            logger.verbose('INCOMING', { data: data.toString(), parser: 'parserIMSI' });
            port.unpipe(parser);
            mutex.unlock(lockName || MUTEX_COMMAND, 'queryIMSI');
            modemInfo.imsi = data.toString().trim() || null;
            logger.info('IMSI extracted', { imsi: modemInfo.imsi });
            resolve(modemInfo.imsi);
        });

        await mutex.lock(lockName || MUTEX_COMMAND, 'queryIMSI');

        port.pipe(parser);
        await writeToPort('AT+CIMI\r');
    });
};

exports.queryIMEIAndIMSI = async function queryIMEIAndIMSI() {
    await mutex.lock(MUTEX_COMMAND, 'queryIMEIAndIMSI');

    const imei = await this.queryIMEI(MUTEX_SUBCOMMAND);
    const imsi = await this.queryIMSI(MUTEX_SUBCOMMAND);

    await mutex.unlock(MUTEX_COMMAND, 'queryIMEIAndIMSI');
    return { imei, imsi };
};

exports.queryManufacturer = function queryManufacturer(lockName) {
    return new Promise(async (resolve) => {
        const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
        parser.on('data', (data) => {
            logger.verbose('INCOMING', { data: data.toString(), parser: 'parserManufacturer' });
            port.unpipe(parser);
            mutex.unlock(lockName || MUTEX_COMMAND, 'parserManufacturer');
            modemInfo.manufacturer = data.toString().trim() || null;
            logger.info('Manufacturer extracted', { manufacturer: modemInfo.manufacturer });
            resolve(modemInfo.manufacturer);
        });

        await mutex.lock(lockName || MUTEX_COMMAND, 'queryManufacturer');

        port.pipe(parser);
        await writeToPort('AT+CGMI\r');
    });
};

exports.queryModel = function queryModel(lockName) {
    return new Promise(async (resolve) => {
        const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
        parser.on('data', (data) => {
            logger.verbose('INCOMING', { data: data.toString(), parser: 'parserModel' });
            port.unpipe(parser);
            mutex.unlock(lockName || MUTEX_COMMAND, 'parserModel');
            modemInfo.model = data.toString().trim() || null;
            logger.info('Model extracted', { model: modemInfo.model });
            resolve(modemInfo.model);
        });

        await mutex.lock(lockName || MUTEX_COMMAND, 'queryModel');

        port.pipe(parser);
        await writeToPort('AT+CGMM\r');
    });
};

exports.sendSMS = function sendSMS(destination, msg) {
    return new Promise(async (resolve) => {
        
    });
};

exports.initATCommands = async function initATCommands() {
    await mutex.lock(MUTEX_COMMAND, 'INIT MODEM');
    await this.writeToPortAndWaitForOkOrError('\rATE0\r', MUTEX_SUBCOMMAND);
    await this.writeToPortAndWaitForOkOrError('AT+CMGF=0\r', MUTEX_SUBCOMMAND);
    await this.writeToPortAndWaitForOkOrError('AT+CNMI=1,2,0,1,0\r', MUTEX_SUBCOMMAND);
    mutex.unlock(MUTEX_COMMAND, 'INIT MODEM');
};