Commit e77dfd454654c8ae786e7ba0e7981601a7ee35b1

Authored by Adhidarma Hadiwinoto
1 parent d54ac95033
Exists in master

queryIMEI

Showing 3 changed files with 24 additions and 2 deletions Inline Diff

lib/modem-commands.js
1 const MUTEX_COMMAND = 'COMMAND'; 1 const MUTEX_COMMAND = 'COMMAND';
2 // const MUTEX_SUBCOMMAND = 'SUBCOMMAND'; 2 // const MUTEX_SUBCOMMAND = 'SUBCOMMAND';
3 3
4 const ParserRegex = require('@serialport/parser-regex');
5
4 const logger = require('komodo-sdk/logger'); 6 const logger = require('komodo-sdk/logger');
5 const mutex = require('./mutex-common'); 7 const mutex = require('./mutex-common');
6 // const parsers = require('./serialport-parsers'); 8 const parsers = require('./serialport-parsers');
7 9
8 let port; 10 let port;
9 11
10 function writeToPort(data) { 12 function writeToPort(data) {
11 return new Promise((resolve) => { 13 return new Promise((resolve) => {
12 port.write(data, (err, bytesWritten) => { 14 port.write(data, (err, bytesWritten) => {
13 if (err) logger.warn(`ERROR: ${err.toString()}`); 15 if (err) logger.warn(`ERROR: ${err.toString()}`);
14 16
15 logger.verbose('OUTGOING', { bytesWritten, data: data.toString() }); 17 logger.verbose('OUTGOING', { bytesWritten, data: data.toString() });
16 resolve(bytesWritten); 18 resolve(bytesWritten);
17 }); 19 });
18 }); 20 });
19 } 21 }
20 22
21 exports.sleep = function sleep(ms) { 23 exports.sleep = function sleep(ms) {
22 return new Promise((resolve) => { 24 return new Promise((resolve) => {
23 setTimeout(() => { 25 setTimeout(() => {
24 resolve(); 26 resolve();
25 }, ms || 0); 27 }, ms || 0);
26 }); 28 });
27 }; 29 };
28 30
29 31
30 exports.setPort = function setPort(val) { 32 exports.setPort = function setPort(val) {
31 port = val; 33 port = val;
32 }; 34 };
33 35
34 exports.querySignalQuality = function querySignalQuality() { 36 exports.querySignalQuality = function querySignalQuality() {
35 return new Promise(async (resolve) => { 37 return new Promise(async (resolve) => {
36 if (!mutex.tryLock(MUTEX_COMMAND, 'querySignalQuality')) { 38 if (!mutex.tryLock(MUTEX_COMMAND, 'querySignalQuality')) {
37 resolve(false); 39 resolve(false);
38 return; 40 return;
39 } 41 }
40 42
41 await writeToPort('AT+CSQ\r'); 43 await writeToPort('AT+CSQ\r');
42 mutex.unlock(MUTEX_COMMAND, 'querySignalQuality'); 44 mutex.unlock(MUTEX_COMMAND, 'querySignalQuality');
43 resolve(true); 45 resolve(true);
44 }); 46 });
45 }; 47 };
46 48
47 exports.queryCOPS = function querySignalQuality() { 49 exports.queryCOPS = function querySignalQuality() {
48 return new Promise(async (resolve) => { 50 return new Promise(async (resolve) => {
49 await mutex.lock(MUTEX_COMMAND, 'queryCOPS'); 51 await mutex.lock(MUTEX_COMMAND, 'queryCOPS');
50 await writeToPort('AT+COPS?\r'); 52 await writeToPort('AT+COPS?\r');
51 mutex.unlock(MUTEX_COMMAND, 'queryCOPS'); 53 mutex.unlock(MUTEX_COMMAND, 'queryCOPS');
52 resolve(true); 54 resolve(true);
53 }); 55 });
54 }; 56 };
57
58 exports.queryIMEI = function queryIMEI() {
59 return new Promise(async (resolve) => {
60 const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
61 parser.on('data', (data) => {
62 logger.verbose('INCOMING', { parser: 'parserIMEI', data: data.toString() });
63 mutex.unlock(MUTEX_COMMAND, 'queryIMEI');
64 resolve();
65 });
66
67 await mutex.lock(MUTEX_COMMAND, 'queryIMEI');
68
69 port.pipe(parser);
70 await writeToPort('AT+CGSN\r');
71 port.unpipe(parser);
72 });
73 };
55 74
lib/serialport-parsers.js
1 const PARSER_READLINE_DELIMITER = '\r\n'; 1 const PARSER_READLINE_DELIMITER = '\r\n';
2 const PARSER_WAIT_FOR_OK_OR_ERROR_REGEX = /\r\n(?:OK|ERROR)\r\n/; 2 const PARSER_WAIT_FOR_OK_OR_ERROR_REGEX = /\r\n(?:OK|ERROR)\r\n/;
3 3
4 const pdu = require('node-pdu'); 4 const pdu = require('node-pdu');
5 const ParserReadline = require('@serialport/parser-readline'); 5 const ParserReadline = require('@serialport/parser-readline');
6 const ParserRegex = require('@serialport/parser-regex'); 6 const ParserRegex = require('@serialport/parser-regex');
7 7
8 const logger = require('komodo-sdk/logger'); 8 const logger = require('komodo-sdk/logger');
9 9
10 const dbCops = require('./db-cops'); 10 const dbCops = require('./db-cops');
11 11
12 let port; 12 let port;
13 13
14 exports.setPort = function setPort(val) { 14 exports.setPort = function setPort(val) {
15 logger.info('SERIALPORT-PARSERS: setting port'); 15 logger.info('SERIALPORT-PARSERS: setting port');
16 port = val; 16 port = val;
17 }; 17 };
18 18
19 exports.getPort = function getPort() { 19 exports.getPort = function getPort() {
20 return port; 20 return port;
21 }; 21 };
22 22
23 function parsePdu(data) { 23 function parsePdu(data) {
24 if (!data) return null; 24 if (!data) return null;
25 25
26 try { 26 try {
27 const result = pdu.parse(data.toString().trim() || ''); 27 const result = pdu.parse(data.toString().trim() || '');
28 return result; 28 return result;
29 } catch (e) { 29 } catch (e) {
30 return null; 30 return null;
31 } 31 }
32 } 32 }
33 33
34 function onCSQ(data) { 34 function onCSQ(data) {
35 const val = data.toString().trim().match(/\+CSQ:\s*(.*)/); 35 const val = data.toString().trim().match(/\+CSQ:\s*(.*)/);
36 if (!val || !val[1]) return null; 36 if (!val || !val[1]) return null;
37 37
38 logger.info('Signal quality extracted', { signalQuality: val[1] }); 38 logger.info('Signal quality extracted', { signalQuality: val[1] });
39 return val[1]; 39 return val[1];
40 } 40 }
41 41
42 function onPduDeliver(data, parsedData) { 42 function onPduDeliver(data, parsedData) {
43 const from = parsedData.getAddress && parsedData.getAddress().getPhone 43 const from = parsedData.getAddress && parsedData.getAddress().getPhone
44 ? parsedData.getAddress().getPhone() : null; 44 ? parsedData.getAddress().getPhone() : null;
45 45
46 const msg = parsedData.getData && parsedData.getData().getData 46 const msg = parsedData.getData && parsedData.getData().getData
47 ? parsedData.getData().getData() : null; 47 ? parsedData.getData().getData() : null;
48 48
49 logger.verbose('PDU processed', { from, msg }); 49 logger.verbose('PDU processed', { from, msg });
50 return { from, msg }; 50 return { from, msg };
51 } 51 }
52 52
53 function onCOPS(data) { 53 function onCOPS(data) {
54 const val = data.toString().trim().match(/\+COPS:\s*(.*)/); 54 const val = data.toString().trim().match(/\+COPS:\s*(.*)/);
55 if (!val || !val[1]) return null; 55 if (!val || !val[1]) return null;
56 56
57 const cops = val[1]; 57 const cops = val[1];
58 58
59 if (!cops) return null; 59 if (!cops) return null;
60 const [mode, format, networkId] = cops.split(','); 60 const [mode, format, networkId] = cops.split(',');
61 const networkName = networkId ? dbCops[networkId] || networkId : null; 61 const networkName = networkId ? dbCops[networkId] || networkId : null;
62 62
63 logger.verbose('COPS extracted', { 63 logger.verbose('COPS extracted', {
64 cops, mode, format, networkId, networkName, 64 cops, mode, format, networkId, networkName,
65 }); 65 });
66 66
67 return { 67 return {
68 cops, mode, format, networkId, networkName, 68 cops, mode, format, networkId, networkName,
69 }; 69 };
70 } 70 }
71 71
72 72
73 function isResultCodeIs(data, resultCode) { 73 function isResultCodeIs(data, resultCode) {
74 if (!data) return false; 74 if (!data) return false;
75 const cleanedData = (data.toString() || '').trim(); 75 const cleanedData = (data.toString() || '').trim();
76 if (!cleanedData) return false; 76 if (!cleanedData) return false;
77 77
78 if (resultCode.indexOf('+') !== 0) { 78 if (resultCode.indexOf('+') !== 0) {
79 // eslint-disable-next-line no-param-reassign 79 // eslint-disable-next-line no-param-reassign
80 resultCode = `+${resultCode}`; 80 resultCode = `+${resultCode}`;
81 } 81 }
82 82
83 if (resultCode.search(/:$/) < 0) { 83 if (resultCode.search(/:$/) < 0) {
84 // eslint-disable-next-line no-param-reassign 84 // eslint-disable-next-line no-param-reassign
85 resultCode += ':'; 85 resultCode += ':';
86 } 86 }
87 87
88 return cleanedData.indexOf(resultCode) === 0; 88 return cleanedData.indexOf(resultCode) === 0;
89 } 89 }
90 90
91 const parserReadline = new ParserReadline({ delimiter: PARSER_READLINE_DELIMITER }); 91 const parserReadline = new ParserReadline({ delimiter: PARSER_READLINE_DELIMITER });
92 parserReadline.on('data', (data) => { 92 parserReadline.on('data', (data) => {
93 logger.verbose('INCOMING', { parser: 'parserReadLine', data: `${data.toString()}${PARSER_READLINE_DELIMITER}` }); 93 logger.verbose('INCOMING', { parser: 'parserReadLine', data: `${data.toString()}${PARSER_READLINE_DELIMITER}` });
94 94
95 if (!data) return; 95 if (!data) return;
96 96
97 const pduParsed = parsePdu(data); 97 const pduParsed = parsePdu(data);
98 if (pduParsed) { 98 if (pduParsed) {
99 logger.verbose('PDU parsed', { type: (typeof pduParsed.getType === 'function') && pduParsed.getType() }); 99 logger.verbose('PDU parsed', { type: (typeof pduParsed.getType === 'function') && pduParsed.getType() });
100 } 100 }
101 101
102 if (pduParsed && pduParsed.constructor.name !== 'Deliver') { 102 if (pduParsed && pduParsed.constructor.name !== 'Deliver') {
103 logger.warn('Unknown PDU message type name. PLEASE REPORT IT TO DEVELOPER AT TEKTRANS', { typeName: pduParsed.constructor.name, type: pduParsed.getType(), data: data.toString().trim() }); 103 logger.warn('Unknown PDU message type name. PLEASE REPORT IT TO DEVELOPER AT TEKTRANS', { typeName: pduParsed.constructor.name, type: pduParsed.getType(), data: data.toString().trim() });
104 } 104 }
105 105
106 if (pduParsed && pduParsed.constructor.name === 'Deliver' && pduParsed.getType && pduParsed.getType().getSrr()) { 106 if (pduParsed && pduParsed.constructor.name === 'Deliver' && pduParsed.getType && pduParsed.getType().getSrr()) {
107 logger.verbose('Got a PDU SMS-DELIVER', { type: pduParsed.getType() }); 107 logger.verbose('Got a PDU SMS-DELIVER', { type: pduParsed.getType() });
108 onPduDeliver(data, pduParsed); 108 onPduDeliver(data, pduParsed);
109 } else if (isResultCodeIs(data, 'CSQ')) { 109 } else if (isResultCodeIs(data, 'CSQ')) {
110 logger.verbose('Got a signal quality report', { data: data.toString() }); 110 logger.verbose('Got a signal quality report', { data: data.toString() });
111 onCSQ(data); 111 onCSQ(data);
112 } else if (isResultCodeIs(data, 'COPS:')) { 112 } else if (isResultCodeIs(data, 'COPS:')) {
113 logger.verbose('Got a COPS report', { data: data.toString() }); 113 logger.verbose('Got a COPS report', { data: data.toString() });
114 onCOPS(data); 114 onCOPS(data);
115 } else if (isResultCodeIs(data, 'CMT')) { 115 } else if (isResultCodeIs(data, 'CMT')) {
116 logger.verbose('Got a new message report', { data: data.toString() }); 116 logger.verbose('Got a new message report', { data: data.toString() });
117 } else if (isResultCodeIs(data, 'CMTI')) { 117 } else if (isResultCodeIs(data, 'CMTI')) {
118 logger.verbose('Got a new message notification report', { data: data.toString() }); 118 logger.verbose('Got a new message notification report', { data: data.toString() });
119 } 119 }
120 }); 120 });
121 121
122 const parserWaitForOkOrError = new ParserRegex({ regex: PARSER_WAIT_FOR_OK_OR_ERROR_REGEX }); 122 const parserWaitForOkOrError = new ParserRegex({ regex: PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
123 parserWaitForOkOrError.on('data', (data) => { 123 parserWaitForOkOrError.on('data', (data) => {
124 logger.verbose('INCOMING', { parser: 'parserWaitForOkOrError', data: data.toString() }); 124 logger.verbose('INCOMING', { parser: 'parserWaitForOkOrError', data: data.toString() });
125 }); 125 });
126 126
127 127
128 exports.PARSER_READLINE_DELIMITER = PARSER_READLINE_DELIMITER;
129 exports.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX = PARSER_WAIT_FOR_OK_OR_ERROR_REGEX;
130
128 exports.parserReadline = parserReadline; 131 exports.parserReadline = parserReadline;
129 exports.parserWaitForOkOrError = parserWaitForOkOrError; 132 exports.parserWaitForOkOrError = parserWaitForOkOrError;
130 133
1 const SerialPort = require('serialport'); 1 const SerialPort = require('serialport');
2 2
3 const config = require('komodo-sdk/config'); 3 const config = require('komodo-sdk/config');
4 const logger = require('komodo-sdk/logger'); 4 const logger = require('komodo-sdk/logger');
5 5
6 6
7 const ParserInterByteTimeout = require('@serialport/parser-inter-byte-timeout'); 7 const ParserInterByteTimeout = require('@serialport/parser-inter-byte-timeout');
8 8
9 const parsers = require('./lib/serialport-parsers'); 9 const parsers = require('./lib/serialport-parsers');
10 const modemCommands = require('./lib/modem-commands'); 10 const modemCommands = require('./lib/modem-commands');
11 11
12 const parserInterByteTimeout = new ParserInterByteTimeout({ interval: 1000 }); 12 const parserInterByteTimeout = new ParserInterByteTimeout({ interval: 1000 });
13 parserInterByteTimeout.on('data', (data) => { 13 parserInterByteTimeout.on('data', (data) => {
14 logger.verbose('INCOMING', { parser: 'parserInterByteTimeout', data: data.toString() }); 14 logger.verbose('INCOMING', { parser: 'parserInterByteTimeout', data: data.toString() });
15 }); 15 });
16 16
17 let port; 17 let port;
18 18
19 function sleep(ms) { 19 function sleep(ms) {
20 return new Promise((resolve) => { 20 return new Promise((resolve) => {
21 setTimeout(() => { 21 setTimeout(() => {
22 resolve(); 22 resolve();
23 }, ms || 0); 23 }, ms || 0);
24 }); 24 });
25 } 25 }
26 26
27 function writeToPort(data) { 27 function writeToPort(data) {
28 return new Promise((resolve) => { 28 return new Promise((resolve) => {
29 port.write(data, (err, bytesWritten) => { 29 port.write(data, (err, bytesWritten) => {
30 if (err) logger.warn(`ERROR: ${err.toString()}`); 30 if (err) logger.warn(`ERROR: ${err.toString()}`);
31 31
32 logger.verbose('OUTGOING', { bytesWritten, data: data.toString() }); 32 logger.verbose('OUTGOING', { bytesWritten, data: data.toString() });
33 resolve(bytesWritten); 33 resolve(bytesWritten);
34 }); 34 });
35 }); 35 });
36 } 36 }
37 37
38 async function writeToPortDelayed(data, ms) { 38 async function writeToPortDelayed(data, ms) {
39 await sleep(ms || 500); 39 await sleep(ms || 500);
40 const result = writeToPort(data); 40 const result = writeToPort(data);
41 return result; 41 return result;
42 } 42 }
43 43
44 port = new SerialPort(config.modem.device, { baudRate: 115200 }, async (err) => { 44 port = new SerialPort(config.modem.device, { baudRate: 115200 }, async (err) => {
45 if (err) { 45 if (err) {
46 logger.warn(`Error opening modem. ${err}. Terminating modem ${config.modem.device}.`); 46 logger.warn(`Error opening modem. ${err}. Terminating modem ${config.modem.device}.`);
47 process.exit(1); 47 process.exit(1);
48 } 48 }
49 49
50 await writeToPortDelayed('AT\r'); 50 await writeToPortDelayed('AT\r');
51 51
52 const commands = [ 52 const commands = [
53 'AT&FE0\r', 53 'AT&FE0\r',
54 'AT+CGSN\r',
55 'AT+CIMI\r', 54 'AT+CIMI\r',
56 'AT+CMGF=0\r', 55 'AT+CMGF=0\r',
57 'AT+CNMI=1,2,0,1,0\r', 56 'AT+CNMI=1,2,0,1,0\r',
58 ]; 57 ];
59 58
60 const commandsCount = commands.length; 59 const commandsCount = commands.length;
61 // eslint-disable-next-line no-plusplus 60 // eslint-disable-next-line no-plusplus
62 for (let i = 0; i < commandsCount; i++) { 61 for (let i = 0; i < commandsCount; i++) {
63 // eslint-disable-next-line no-await-in-loop 62 // eslint-disable-next-line no-await-in-loop
64 await writeToPortDelayed(commands[i], 2000); 63 await writeToPortDelayed(commands[i], 2000);
65 } 64 }
66 65
67 if (config && config.modem_tester && config.modem_tester.commands 66 if (config && config.modem_tester && config.modem_tester.commands
68 && config.modem_tester.commands.length) { 67 && config.modem_tester.commands.length) {
69 const additionalCommandsLength = config.modem_tester.commands.length; 68 const additionalCommandsLength = config.modem_tester.commands.length;
70 // eslint-disable-next-line no-plusplus 69 // eslint-disable-next-line no-plusplus
71 for (let i = 0; i < additionalCommandsLength; i++) { 70 for (let i = 0; i < additionalCommandsLength; i++) {
72 // eslint-disable-next-line no-await-in-loop 71 // eslint-disable-next-line no-await-in-loop
73 await writeToPortDelayed(config.modem_tester.commands[i], 2000); 72 await writeToPortDelayed(config.modem_tester.commands[i], 2000);
74 } 73 }
75 } 74 }
76 75
76 await modemCommands.queryIMEI();
77 await modemCommands.queryCOPS(); 77 await modemCommands.queryCOPS();
78 await modemCommands.querySignalQuality(); 78 await modemCommands.querySignalQuality();
79 79
80 setInterval(() => { 80 setInterval(() => {
81 modemCommands.querySignalQuality(); 81 modemCommands.querySignalQuality();
82 }, 30000); 82 }, 30000);
83 }); 83 });
84 84
85 parsers.setPort(port); 85 parsers.setPort(port);
86 modemCommands.setPort(port); 86 modemCommands.setPort(port);
87 87
88 if (config && config.modem_tester && config.modem_tester.parser === 'regex') { 88 if (config && config.modem_tester && config.modem_tester.parser === 'regex') {
89 logger.info('Using parserWaitForOkOrError'); 89 logger.info('Using parserWaitForOkOrError');
90 port.pipe(parsers.parserWaitForOkOrError); 90 port.pipe(parsers.parserWaitForOkOrError);
91 } else if (config && config.modem_tester && config.modem_tester.parser === 'interbyte') { 91 } else if (config && config.modem_tester && config.modem_tester.parser === 'interbyte') {
92 logger.info('Using parserInterByteTimeout'); 92 logger.info('Using parserInterByteTimeout');
93 port.pipe(parserInterByteTimeout); 93 port.pipe(parserInterByteTimeout);
94 } else { 94 } else {
95 logger.info('Using parserReadline'); 95 logger.info('Using parserReadline');
96 port.pipe(parsers.parserReadline); 96 port.pipe(parsers.parserReadline);
97 } 97 }