Commit 9883a918f3b35125a4a3fd583bd6a7b76b6469f1

Authored by Adhidarma Hadiwinoto
1 parent 5b0551633c
Exists in master

Urutan log

Showing 2 changed files with 5 additions and 9 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 ParserReadline = require('@serialport/parser-readline'); 4 const ParserReadline = require('@serialport/parser-readline');
5 const ParserRegex = require('@serialport/parser-regex'); 5 const ParserRegex = require('@serialport/parser-regex');
6 6
7 const logger = require('komodo-sdk/logger'); 7 const logger = require('komodo-sdk/logger');
8 const mutex = require('./mutex-common'); 8 const mutex = require('./mutex-common');
9 const parsers = require('./serialport-parsers'); 9 const parsers = require('./serialport-parsers');
10 const modemInfo = require('./modem-info'); 10 const modemInfo = require('./modem-info');
11 11
12 let port; 12 let port;
13 13
14 function writeToPort(data) { 14 function writeToPort(data) {
15 return new Promise((resolve) => { 15 return new Promise((resolve) => {
16 port.write(data, (err, bytesWritten) => { 16 port.write(data, (err, bytesWritten) => {
17 if (err) logger.warn(`ERROR: ${err.toString()}`); 17 if (err) logger.warn(`ERROR: ${err.toString()}`);
18 18
19 logger.verbose('OUTGOING', { bytesWritten, data: data.toString() }); 19 logger.verbose('OUTGOING', { data: data.toString(), bytesWritten, err });
20 resolve(bytesWritten); 20 resolve(bytesWritten);
21 }); 21 });
22 }); 22 });
23 } 23 }
24 24
25 exports.writeToPortAndWaitForReadline = function writeToPortAndWaitForReadline(cmd, lockName) { 25 exports.writeToPortAndWaitForReadline = function writeToPortAndWaitForReadline(cmd, lockName) {
26 return new Promise(async (resolve) => { 26 return new Promise(async (resolve) => {
27 const parser = new ParserReadline({ delimiter: parsers.PARSER_READLINE_DELIMITER }); 27 const parser = new ParserReadline({ delimiter: parsers.PARSER_READLINE_DELIMITER });
28 parser.on('data', (data) => { 28 parser.on('data', (data) => {
29 port.unpipe(parser); 29 port.unpipe(parser);
30 mutex.unlock(lockName || MUTEX_COMMAND, cmd.trim()); 30 mutex.unlock(lockName || MUTEX_COMMAND, cmd.trim());
31 resolve(data); 31 resolve(data);
32 }); 32 });
33 33
34 await mutex.lock(lockName || MUTEX_COMMAND, cmd.trim()); 34 await mutex.lock(lockName || MUTEX_COMMAND, cmd.trim());
35 port.pipe(parser); 35 port.pipe(parser);
36 await writeToPort(cmd); 36 await writeToPort(cmd);
37 }); 37 });
38 }; 38 };
39 39
40 exports.writeToPortAndWaitForOkOrError = function writeToPortAndWaitForOkOrError(cmd, lockName) { 40 exports.writeToPortAndWaitForOkOrError = function writeToPortAndWaitForOkOrError(cmd, lockName) {
41 const parserName = 'customParserWaitForOkOrError';
42 return new Promise(async (resolve) => { 41 return new Promise(async (resolve) => {
43 const parser = new ParserRegex({ regex: /(?:OK|ERROR)\r\n/ }); 42 const parser = new ParserRegex({ regex: /(?:OK|ERROR)\r\n/ });
44 parser.on('data', (data) => { 43 parser.on('data', (data) => {
45 logger.verbose('INCOMING', { parser: parserName, data: data.toString() });
46 logger.verbose(`Unpiping ${parserName}`);
47 port.unpipe(parser); 44 port.unpipe(parser);
48 mutex.unlock(lockName || MUTEX_COMMAND, cmd.trim()); 45 mutex.unlock(lockName || MUTEX_COMMAND, cmd.trim());
49 resolve(data); 46 resolve(data);
50 }); 47 });
51 48
52 await mutex.lock(lockName || MUTEX_COMMAND, cmd.trim()); 49 await mutex.lock(lockName || MUTEX_COMMAND, cmd.trim());
53 logger.verbose(`Piping ${parserName}`);
54 port.pipe(parser); 50 port.pipe(parser);
55 await writeToPort(cmd); 51 await writeToPort(cmd);
56 }); 52 });
57 }; 53 };
58 54
59 exports.sleep = function sleep(ms) { 55 exports.sleep = function sleep(ms) {
60 return new Promise((resolve) => { 56 return new Promise((resolve) => {
61 setTimeout(() => { 57 setTimeout(() => {
62 resolve(); 58 resolve();
63 }, ms || 0); 59 }, ms || 0);
64 }); 60 });
65 }; 61 };
66 62
67 63
68 exports.setPort = function setPort(val) { 64 exports.setPort = function setPort(val) {
69 port = val; 65 port = val;
70 }; 66 };
71 67
72 exports.querySignalQuality = function querySignalQuality() { 68 exports.querySignalQuality = function querySignalQuality() {
73 return new Promise(async (resolve) => { 69 return new Promise(async (resolve) => {
74 if (!mutex.tryLock(MUTEX_COMMAND, 'querySignalQuality')) { 70 if (!mutex.tryLock(MUTEX_COMMAND, 'querySignalQuality')) {
75 resolve(false); 71 resolve(false);
76 return; 72 return;
77 } 73 }
78 74
79 await writeToPort('AT+CSQ\r'); 75 await writeToPort('AT+CSQ\r');
80 mutex.unlock(MUTEX_COMMAND, 'querySignalQuality'); 76 mutex.unlock(MUTEX_COMMAND, 'querySignalQuality');
81 resolve(true); 77 resolve(true);
82 }); 78 });
83 }; 79 };
84 80
85 exports.queryCOPS = function querySignalQuality() { 81 exports.queryCOPS = function querySignalQuality() {
86 return new Promise(async (resolve) => { 82 return new Promise(async (resolve) => {
87 await mutex.lock(MUTEX_COMMAND, 'queryCOPS'); 83 await mutex.lock(MUTEX_COMMAND, 'queryCOPS');
88 await writeToPort('AT+COPS?\r'); 84 await writeToPort('AT+COPS?\r');
89 mutex.unlock(MUTEX_COMMAND, 'queryCOPS'); 85 mutex.unlock(MUTEX_COMMAND, 'queryCOPS');
90 resolve(true); 86 resolve(true);
91 }); 87 });
92 }; 88 };
93 89
94 exports.queryIMEI = function queryIMEI() { 90 exports.queryIMEI = function queryIMEI() {
95 return new Promise(async (resolve) => { 91 return new Promise(async (resolve) => {
96 const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX }); 92 const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
97 parser.on('data', (data) => { 93 parser.on('data', (data) => {
98 logger.verbose('INCOMING', { parser: 'parserIMEI', data: data.toString() }); 94 logger.verbose('INCOMING', { data: data.toString(), parser: 'parserIMEI' });
99 port.unpipe(parser); 95 port.unpipe(parser);
100 mutex.unlock(MUTEX_COMMAND, 'queryIMEI'); 96 mutex.unlock(MUTEX_COMMAND, 'queryIMEI');
101 modemInfo.imei = data.toString().trim(); 97 modemInfo.imei = data.toString().trim();
102 resolve(modemInfo.imei); 98 resolve(modemInfo.imei);
103 }); 99 });
104 100
105 await mutex.lock(MUTEX_COMMAND, 'queryIMEI'); 101 await mutex.lock(MUTEX_COMMAND, 'queryIMEI');
106 102
107 port.pipe(parser); 103 port.pipe(parser);
108 await writeToPort('AT+CGSN\r'); 104 await writeToPort('AT+CGSN\r');
109 }); 105 });
110 }; 106 };
111 107
112 exports.queryIMSI = function queryIMSI() { 108 exports.queryIMSI = function queryIMSI() {
113 return new Promise(async (resolve) => { 109 return new Promise(async (resolve) => {
114 const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX }); 110 const parser = new ParserRegex({ regex: parsers.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX });
115 parser.on('data', (data) => { 111 parser.on('data', (data) => {
116 logger.verbose('INCOMING', { parser: 'parserIMSI', data: data.toString() }); 112 logger.verbose('INCOMING', { data: data.toString(), parser: 'parserIMSI' });
117 port.unpipe(parser); 113 port.unpipe(parser);
118 mutex.unlock(MUTEX_COMMAND, 'queryIMSI'); 114 mutex.unlock(MUTEX_COMMAND, 'queryIMSI');
119 modemInfo.imsi = data.toString().trim(); 115 modemInfo.imsi = data.toString().trim();
120 resolve(modemInfo.imsi); 116 resolve(modemInfo.imsi);
121 }); 117 });
122 118
123 await mutex.lock(MUTEX_COMMAND, 'queryIMSI'); 119 await mutex.lock(MUTEX_COMMAND, 'queryIMSI');
124 120
125 port.pipe(parser); 121 port.pipe(parser);
126 await writeToPort('AT+CIMI\r'); 122 await writeToPort('AT+CIMI\r');
127 }); 123 });
128 }; 124 };
129 125
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', { data: `${data.toString()}${PARSER_READLINE_DELIMITER}`, parser: 'parserReadLine' });
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', { data: data.toString(), parser: 'parserWaitForOkOrError' });
125 }); 125 });
126 126
127 127
128 exports.PARSER_READLINE_DELIMITER = PARSER_READLINE_DELIMITER; 128 exports.PARSER_READLINE_DELIMITER = PARSER_READLINE_DELIMITER;
129 exports.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX = PARSER_WAIT_FOR_OK_OR_ERROR_REGEX; 129 exports.PARSER_WAIT_FOR_OK_OR_ERROR_REGEX = PARSER_WAIT_FOR_OK_OR_ERROR_REGEX;
130 130
131 exports.parserReadline = parserReadline; 131 exports.parserReadline = parserReadline;
132 exports.parserWaitForOkOrError = parserWaitForOkOrError; 132 exports.parserWaitForOkOrError = parserWaitForOkOrError;
133 133