Commit 71a0b3ff60b7492030fe39ddaf2a8a1d01bc7820

Authored by Adhidarma Hadiwinoto
1 parent 65f1ac9a4c
Exists in master

Tamabahan pilihan untuk reset sesi USSD

Showing 2 changed files with 6 additions and 10 deletions Inline Diff

lib/http-command-server/router-ussd.js
1 'use strict'; 1 'use strict';
2 2
3 const express = require('express'); 3 const express = require('express');
4 4
5 const modem = require('../modem'); 5 const modem = require('../modem');
6 6
7 const router = express.Router(); 7 const router = express.Router();
8 module.exports = router; 8 module.exports = router;
9 9
10 /** 10 /**
11 * Eksekusi kode USSD 11 * Eksekusi kode USSD
12 * @param {object} req - Objek request Express 12 * @param {object} req - Objek request Express
13 * 13 *
14 * Pilihan req.query.include_cusd2: 14 * Pilihan req.query.include_cusd2:
15 * -1: sebelum
15 * 0: tidak (default) 16 * 0: tidak (default)
16 * 1: sesudah 17 * 1: sesudah
17 * -1: sebelum 18 * 2: sebelum dan sesudah
18 * 19 *
19 * @param {object} req.query - Objek query string request Express 20 * @param {object} req.query - Objek query string request Express
20 * @param {string} req.query.code - Kode USSD yang ingin dieksekusi 21 * @param {string} req.query.code - Kode USSD yang ingin dieksekusi
21 * @param {number} [req.query.include_cusd2=0] - Apakah ingin mengeksekusi CUSD=2 secara otomatis 22 * @param {number} [req.query.include_cusd2=0] - Apakah ingin mengeksekusi CUSD=2 secara otomatis
22 * @param {object} res - Objek respon Express 23 * @param {object} res - Objek respon Express
23 */ 24 */
24 async function handlerIndex(req, res) { 25 async function handlerIndex(req, res) {
25 if (!req.query || !req.query.code || typeof req.query.code !== 'string') { 26 if (!req.query || !req.query.code || typeof req.query.code !== 'string') {
26 res.json({ 27 res.json({
27 status: 'NOT-OK', 28 status: 'NOT-OK',
28 error: 'INVALID-PARAMETER', 29 error: 'INVALID-PARAMETER',
29 message: 'Undefined parameter: code', 30 message: 'Undefined parameter: code',
30 }); 31 });
31 32
32 return; 33 return;
33 } 34 }
34 35
35 const reply = await modem.executeUSSD(req.query.code, req.query.include_cusd2); 36 const reply = await modem.executeUSSD(req.query.code, req.query.include_cusd2);
36 res.json({ 37 res.json({
37 status: 'OK', 38 status: 'OK',
38 error: false, 39 error: false,
39 code: req.query.code, 40 code: req.query.code,
40 include_cusd2: req.query.include_cusd2, 41 include_cusd2: req.query.include_cusd2,
41 message: reply, 42 message: reply,
42 }); 43 });
43 } 44 }
44 45
45 router.get('/', handlerIndex); 46 router.get('/', handlerIndex);
46 47
1 'use strict'; 1 'use strict';
2 2
3 const INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS = 60000; 3 const INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS = 60000;
4 const MAX_LAST_DATA_AGE_MS = 3 * 60 * 1000; 4 const MAX_LAST_DATA_AGE_MS = 3 * 60 * 1000;
5 const REGEX_WAIT_FOR_OK_OR_ERROR = /\n(?:OK|ERROR)\r/; 5 const REGEX_WAIT_FOR_OK_OR_ERROR = /\n(?:OK|ERROR)\r/;
6 // const REGEX_WAIT_FOR_OK_OR_ERROR_USSD = /\n(?:OK|ERROR)\r/; 6 // const REGEX_WAIT_FOR_OK_OR_ERROR_USSD = /\n(?:OK|ERROR)\r/;
7 7
8 const CUSD2_BEFORE = -1;
9 const CUSD2_AFTER = 1;
10
11 const moment = require('moment'); 8 const moment = require('moment');
12 const SerialPort = require('serialport'); 9 const SerialPort = require('serialport');
13 const ParserReadline = require('@serialport/parser-readline'); 10 const ParserReadline = require('@serialport/parser-readline');
14 // const ParserDelimiter = require('@serialport/parser-delimiter'); 11 // const ParserDelimiter = require('@serialport/parser-delimiter');
15 12
16 const ParserRegex = require('@serialport/parser-regex'); 13 const ParserRegex = require('@serialport/parser-regex');
17 14
18 const config = require('komodo-sdk/config'); 15 const config = require('komodo-sdk/config');
19 const logger = require('komodo-sdk/logger'); 16 const logger = require('komodo-sdk/logger');
20 17
21 const mutex = require('./mutex'); 18 const mutex = require('./mutex');
22 const common = require('./common'); 19 const common = require('./common');
23 const sms = require('./sms'); 20 const sms = require('./sms');
24 const dbCops = require('./db-cops'); 21 const dbCops = require('./db-cops');
25 const reportSender = require('./report-sender'); 22 const reportSender = require('./report-sender');
26 // const msisdn = require('./msisdn'); 23 // const msisdn = require('./msisdn');
27 const registerModem = require('./register-modem'); 24 const registerModem = require('./register-modem');
28 // const counters = require('./counters'); 25 // const counters = require('./counters');
29 26
30 const modemInfo = { 27 const modemInfo = {
31 device: config.modem.device, 28 device: config.modem.device,
32 manufacturer: null, 29 manufacturer: null,
33 model: null, 30 model: null,
34 imei: null, 31 imei: null,
35 imsi: null, 32 imsi: null,
36 msisdn: null, 33 msisdn: null,
37 cops: null, 34 cops: null,
38 networkId: null, 35 networkId: null,
39 networkName: null, 36 networkName: null,
40 signalStrength: null, 37 signalStrength: null,
41 signalStrengthTs: null, 38 signalStrengthTs: null,
42 signalStrengthTsReadable: null, 39 signalStrengthTsReadable: null,
43 // messageSentCounter: null, 40 // messageSentCounter: null,
44 // messageReceivedCounter: null, 41 // messageReceivedCounter: null,
45 }; 42 };
46 43
47 let lastTs = new Date(); 44 let lastTs = new Date();
48 45
49 let port; 46 let port;
50 47
51 const parserReadLine = new ParserReadline(); 48 const parserReadLine = new ParserReadline();
52 49
53 const parserWaitForOK = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 50 const parserWaitForOK = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
54 parserWaitForOK.on('data', () => { 51 parserWaitForOK.on('data', () => {
55 mutex.releaseLockWaitForCommand(); 52 mutex.releaseLockWaitForCommand();
56 }); 53 });
57 54
58 function writeToPort(data) { 55 function writeToPort(data) {
59 return new Promise((resolve) => { 56 return new Promise((resolve) => {
60 port.write(data, (err, bytesWritten) => { 57 port.write(data, (err, bytesWritten) => {
61 if (err) logger.warn(`ERROR: ${err.toString()}`); 58 if (err) logger.warn(`ERROR: ${err.toString()}`);
62 logger.verbose(`* OUT: ${data}`); 59 logger.verbose(`* OUT: ${data}`);
63 resolve(bytesWritten); 60 resolve(bytesWritten);
64 }); 61 });
65 }); 62 });
66 } 63 }
67 64
68 async function readSMS(slot) { 65 async function readSMS(slot) {
69 const parserCMGR = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 66 const parserCMGR = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
70 parserCMGR.on('data', (data) => { 67 parserCMGR.on('data', (data) => {
71 if (data) { 68 if (data) {
72 try { 69 try {
73 reportSender.incomingSMS(sms.extract(data.toString().trim()), modemInfo); 70 reportSender.incomingSMS(sms.extract(data.toString().trim()), modemInfo);
74 } catch (e) { 71 } catch (e) {
75 logger.warn(`Exception on reporting new message. ${e.toString()}`, { smsObj: e.smsObj, dataFromModem: data }); 72 logger.warn(`Exception on reporting new message. ${e.toString()}`, { smsObj: e.smsObj, dataFromModem: data });
76 73
77 process.exit(0); 74 process.exit(0);
78 } 75 }
79 } 76 }
80 port.unpipe(parserCMGR); 77 port.unpipe(parserCMGR);
81 mutex.releaseLockWaitForCommand(); 78 mutex.releaseLockWaitForCommand();
82 }); 79 });
83 80
84 // const parserCMGD = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK }); 81 // const parserCMGD = new ParserDelimiter({ delimiter: DELIMITER_WAIT_FOR_OK });
85 const parserCMGD = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 82 const parserCMGD = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
86 parserCMGD.on('data', () => { 83 parserCMGD.on('data', () => {
87 port.unpipe(parserCMGD); 84 port.unpipe(parserCMGD);
88 mutex.releaseLockWaitForCommand(); 85 mutex.releaseLockWaitForCommand();
89 }); 86 });
90 87
91 logger.info(`Reading SMS on slot ${slot}`); 88 logger.info(`Reading SMS on slot ${slot}`);
92 await mutex.setLockWaitForCommand(); 89 await mutex.setLockWaitForCommand();
93 port.pipe(parserCMGR); 90 port.pipe(parserCMGR);
94 await writeToPort(`AT+CMGR=${slot}\r`); 91 await writeToPort(`AT+CMGR=${slot}\r`);
95 logger.info(`Finished reading SMS on slot ${slot}`); 92 logger.info(`Finished reading SMS on slot ${slot}`);
96 93
97 logger.info(`Deleting message on slot ${slot}`); 94 logger.info(`Deleting message on slot ${slot}`);
98 await mutex.setLockWaitForCommand(); 95 await mutex.setLockWaitForCommand();
99 port.pipe(parserCMGD); 96 port.pipe(parserCMGD);
100 await writeToPort(`AT+CMGD=${slot}\r`); 97 await writeToPort(`AT+CMGD=${slot}\r`);
101 logger.info('Message processing has completed'); 98 logger.info('Message processing has completed');
102 } 99 }
103 100
104 function onIncomingSMS(data) { 101 function onIncomingSMS(data) {
105 const value = common.extractValueFromReadLineData(data); 102 const value = common.extractValueFromReadLineData(data);
106 if (!value) return; 103 if (!value) return;
107 104
108 const chunks = value.split(','); 105 const chunks = value.split(',');
109 if (!chunks && !chunks[1]) return; 106 if (!chunks && !chunks[1]) return;
110 107
111 const slot = chunks[1]; 108 const slot = chunks[1];
112 109
113 logger.info(`Incoming SMS on slot ${slot}`); 110 logger.info(`Incoming SMS on slot ${slot}`);
114 readSMS(slot); 111 readSMS(slot);
115 } 112 }
116 113
117 function onCOPS(data) { 114 function onCOPS(data) {
118 modemInfo.cops = common.extractValueFromReadLineData(data).trim(); 115 modemInfo.cops = common.extractValueFromReadLineData(data).trim();
119 logger.info(`Connected Network: ${modemInfo.cops}`); 116 logger.info(`Connected Network: ${modemInfo.cops}`);
120 117
121 if (!modemInfo.cops) return; 118 if (!modemInfo.cops) return;
122 119
123 [, , modemInfo.networkId] = modemInfo.cops.split(','); 120 [, , modemInfo.networkId] = modemInfo.cops.split(',');
124 121
125 if (modemInfo.networkId) { 122 if (modemInfo.networkId) {
126 modemInfo.networkName = dbCops[modemInfo.networkId] || modemInfo.networkId; 123 modemInfo.networkName = dbCops[modemInfo.networkId] || modemInfo.networkId;
127 } 124 }
128 } 125 }
129 126
130 parserReadLine.on('data', (data) => { 127 parserReadLine.on('data', (data) => {
131 logger.verbose(`* IN: ${data}`); 128 logger.verbose(`* IN: ${data}`);
132 if (data) { 129 if (data) {
133 lastTs = new Date(); 130 lastTs = new Date();
134 if (data.indexOf('+CSQ: ') === 0) { 131 if (data.indexOf('+CSQ: ') === 0) {
135 const signalStrength = common.extractValueFromReadLineData(data).trim(); 132 const signalStrength = common.extractValueFromReadLineData(data).trim();
136 if (signalStrength) { 133 if (signalStrength) {
137 modemInfo.signalStrength = signalStrength; 134 modemInfo.signalStrength = signalStrength;
138 modemInfo.signalStrengthTs = new Date(); 135 modemInfo.signalStrengthTs = new Date();
139 modemInfo.signalStrengthTsReadable = moment(modemInfo.signalStrengthTs).format('YYYY-MM-DD HH:mm:ss'); 136 modemInfo.signalStrengthTsReadable = moment(modemInfo.signalStrengthTs).format('YYYY-MM-DD HH:mm:ss');
140 logger.info(`Signal strength: ${modemInfo.signalStrength}`); 137 logger.info(`Signal strength: ${modemInfo.signalStrength}`);
141 registerModem(modemInfo); 138 registerModem(modemInfo);
142 } 139 }
143 } else if (data.indexOf('+CMTI: ') === 0) { 140 } else if (data.indexOf('+CMTI: ') === 0) {
144 // counters.increment('MESSAGE_RECEIVED', modemInfo); 141 // counters.increment('MESSAGE_RECEIVED', modemInfo);
145 onIncomingSMS(data); 142 onIncomingSMS(data);
146 } else if (data.indexOf('+COPS: ') === 0) { 143 } else if (data.indexOf('+COPS: ') === 0) {
147 onCOPS(data); 144 onCOPS(data);
148 } 145 }
149 } 146 }
150 }); 147 });
151 148
152 async function simpleSubCommand(cmd, callback) { 149 async function simpleSubCommand(cmd, callback) {
153 const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 150 const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
154 parser.on('data', (data) => { 151 parser.on('data', (data) => {
155 port.unpipe(parser); 152 port.unpipe(parser);
156 mutex.releaseLockWaitForSubCommand(); 153 mutex.releaseLockWaitForSubCommand();
157 154
158 if (data) { 155 if (data) {
159 if (callback) callback(null, data.toString().trim()); 156 if (callback) callback(null, data.toString().trim());
160 } 157 }
161 }); 158 });
162 159
163 return new Promise(async (resolve) => { 160 return new Promise(async (resolve) => {
164 await mutex.setLockWaitForSubCommand(); 161 await mutex.setLockWaitForSubCommand();
165 port.pipe(parser); 162 port.pipe(parser);
166 writeToPort(cmd); 163 writeToPort(cmd);
167 164
168 await mutex.setLockWaitForSubCommand(); 165 await mutex.setLockWaitForSubCommand();
169 mutex.releaseLockWaitForSubCommand(); 166 mutex.releaseLockWaitForSubCommand();
170 167
171 resolve(); 168 resolve();
172 }); 169 });
173 } 170 }
174 171
175 function readManufacturer() { 172 function readManufacturer() {
176 return new Promise((resolve) => { 173 return new Promise((resolve) => {
177 simpleSubCommand('AT+CGMI\r', (err, result) => { 174 simpleSubCommand('AT+CGMI\r', (err, result) => {
178 modemInfo.manufacturer = result; 175 modemInfo.manufacturer = result;
179 logger.info(`Manufacturer: ${result}`); 176 logger.info(`Manufacturer: ${result}`);
180 resolve(result); 177 resolve(result);
181 }); 178 });
182 }); 179 });
183 } 180 }
184 181
185 function readModel() { 182 function readModel() {
186 return new Promise((resolve) => { 183 return new Promise((resolve) => {
187 simpleSubCommand('AT+CGMM\r', (err, result) => { 184 simpleSubCommand('AT+CGMM\r', (err, result) => {
188 modemInfo.model = result; 185 modemInfo.model = result;
189 logger.info(`Model: ${result}`); 186 logger.info(`Model: ${result}`);
190 resolve(result); 187 resolve(result);
191 }); 188 });
192 }); 189 });
193 } 190 }
194 191
195 function readIMEI() { 192 function readIMEI() {
196 return new Promise((resolve) => { 193 return new Promise((resolve) => {
197 simpleSubCommand('AT+CGSN\r', (err, result) => { 194 simpleSubCommand('AT+CGSN\r', (err, result) => {
198 modemInfo.imei = result; 195 modemInfo.imei = result;
199 logger.info(`IMEI: ${result}`); 196 logger.info(`IMEI: ${result}`);
200 resolve(result); 197 resolve(result);
201 }); 198 });
202 }); 199 });
203 } 200 }
204 201
205 function readIMSI() { 202 function readIMSI() {
206 return new Promise((resolve) => { 203 return new Promise((resolve) => {
207 simpleSubCommand('AT+CIMI\r', (err, result) => { 204 simpleSubCommand('AT+CIMI\r', (err, result) => {
208 modemInfo.imsi = result; 205 modemInfo.imsi = result;
209 logger.info(`IMSI: ${result}`); 206 logger.info(`IMSI: ${result}`);
210 207
211 if (result) { 208 if (result) {
212 /* 209 /*
213 modemInfo.msisdn = msisdn[result]; 210 modemInfo.msisdn = msisdn[result];
214 if (modemInfo.msisdn) { 211 if (modemInfo.msisdn) {
215 logger.info(`MSISDN: ${modemInfo.msisdn}`); 212 logger.info(`MSISDN: ${modemInfo.msisdn}`);
216 registerModem(modemInfo); 213 registerModem(modemInfo);
217 } 214 }
218 */ 215 */
219 } else { 216 } else {
220 logger.warn(`IMSI not detected. Please insert a sim card to your modem. Terminating ${config.modem.device}.`); 217 logger.warn(`IMSI not detected. Please insert a sim card to your modem. Terminating ${config.modem.device}.`);
221 process.exit(2); 218 process.exit(2);
222 } 219 }
223 resolve(result); 220 resolve(result);
224 }); 221 });
225 }); 222 });
226 } 223 }
227 224
228 function readCOPS() { 225 function readCOPS() {
229 return new Promise((resolve) => { 226 return new Promise((resolve) => {
230 simpleSubCommand('AT+COPS?\r', (err, result) => { 227 simpleSubCommand('AT+COPS?\r', (err, result) => {
231 resolve(result); 228 resolve(result);
232 }); 229 });
233 }); 230 });
234 } 231 }
235 232
236 function deleteInbox() { 233 function deleteInbox() {
237 return new Promise((resolve) => { 234 return new Promise((resolve) => {
238 simpleSubCommand('AT+CMGD=0,4\r', (err, result) => { 235 simpleSubCommand('AT+CMGD=0,4\r', (err, result) => {
239 resolve(result); 236 resolve(result);
240 }); 237 });
241 }); 238 });
242 } 239 }
243 240
244 async function querySignalStrength() { 241 async function querySignalStrength() {
245 const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 242 const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
246 parser.on('data', () => { 243 parser.on('data', () => {
247 port.unpipe(parser); 244 port.unpipe(parser);
248 mutex.releaseLockWaitForCommand(); 245 mutex.releaseLockWaitForCommand();
249 }); 246 });
250 247
251 if (mutex.tryLockWaitForCommand()) { 248 if (mutex.tryLockWaitForCommand()) {
252 port.pipe(parser); 249 port.pipe(parser);
253 await writeToPort('AT+CSQ\r'); 250 await writeToPort('AT+CSQ\r');
254 } 251 }
255 } 252 }
256 253
257 function registerModemToCenterPeriodically() { 254 function registerModemToCenterPeriodically() {
258 registerModem(modemInfo); 255 registerModem(modemInfo);
259 256
260 setInterval(() => { 257 setInterval(() => {
261 registerModem(modemInfo); 258 registerModem(modemInfo);
262 }, 60 * 1000); 259 }, 60 * 1000);
263 } 260 }
264 261
265 async function registerSignalStrengthBackgroundQuery() { 262 async function registerSignalStrengthBackgroundQuery() {
266 logger.info('Registering background signal strength query'); 263 logger.info('Registering background signal strength query');
267 264
268 querySignalStrength(); 265 querySignalStrength();
269 266
270 setInterval(() => { 267 setInterval(() => {
271 querySignalStrength(); 268 querySignalStrength();
272 }, config.interval_beetwen_signal_strength_ms || INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS); 269 }, config.interval_beetwen_signal_strength_ms || INTERVAL_BEETWEN_SIGNAL_STRENGTH_MS);
273 } 270 }
274 271
275 async function sendSMS(destination, msg) { 272 async function sendSMS(destination, msg) {
276 if (typeof destination !== 'string' || typeof msg !== 'string' || !destination.trim() || !msg.trim()) return; 273 if (typeof destination !== 'string' || typeof msg !== 'string' || !destination.trim() || !msg.trim()) return;
277 274
278 const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 275 const parser = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
279 parser.on('data', () => { 276 parser.on('data', () => {
280 port.unpipe(parser); 277 port.unpipe(parser);
281 mutex.releaseLockWaitForSubCommand(); 278 mutex.releaseLockWaitForSubCommand();
282 }); 279 });
283 280
284 logger.verbose('Waiting for command lock to send message'); 281 logger.verbose('Waiting for command lock to send message');
285 await mutex.setLockWaitForCommand(); 282 await mutex.setLockWaitForCommand();
286 283
287 logger.info('Sending message', { destination, msg }); 284 logger.info('Sending message', { destination, msg });
288 // counters.increment('MESSAGE_SENT', modemInfo); 285 // counters.increment('MESSAGE_SENT', modemInfo);
289 286
290 const correctedDestination = `+${destination}`.replace(/^0/, '62').replace(/^\++/, '+'); 287 const correctedDestination = `+${destination}`.replace(/^0/, '62').replace(/^\++/, '+');
291 288
292 logger.verbose('Waiting for lock before set to text mode'); 289 logger.verbose('Waiting for lock before set to text mode');
293 await mutex.setLockWaitForSubCommand(); 290 await mutex.setLockWaitForSubCommand();
294 port.pipe(parser); 291 port.pipe(parser);
295 await writeToPort('AT+CMGF=1\r'); 292 await writeToPort('AT+CMGF=1\r');
296 293
297 logger.verbose('Waiting for lock before writing message'); 294 logger.verbose('Waiting for lock before writing message');
298 await mutex.setLockWaitForSubCommand(); 295 await mutex.setLockWaitForSubCommand();
299 port.pipe(parser); 296 port.pipe(parser);
300 await writeToPort(`AT+CMGS="${correctedDestination}"\r${msg}${Buffer.from([0x1A])}`); 297 await writeToPort(`AT+CMGS="${correctedDestination}"\r${msg}${Buffer.from([0x1A])}`);
301 298
302 await mutex.setLockWaitForSubCommand(); 299 await mutex.setLockWaitForSubCommand();
303 mutex.releaseLockWaitForSubCommand(); 300 mutex.releaseLockWaitForSubCommand();
304 301
305 logger.info('Message has been sent'); 302 logger.info('Message has been sent');
306 303
307 setTimeout(() => { 304 setTimeout(() => {
308 logger.verbose('Releasing command lock'); 305 logger.verbose('Releasing command lock');
309 mutex.releaseLockWaitForCommand(); 306 mutex.releaseLockWaitForCommand();
310 }, config.wait_for_release_lock_wait_for_command_ms || 2000); 307 }, config.wait_for_release_lock_wait_for_command_ms || 2000);
311 } 308 }
312 /** 309 /**
313 * Ekseksusi kode USSD. 310 * Ekseksusi kode USSD.
314 * 311 *
315 * Pilihan includeCUSD2: 312 * Pilihan includeCUSD2:
313 * -1: sebelum
316 * 0: tidak (default) 314 * 0: tidak (default)
317 * 1: sesudah 315 * 1: sesudah
318 * -1: sebelum 316 * 2: sebelum dan sesudah
319 * 317 *
320 * @param {string} code - Kode USSD 318 * @param {string} code - Kode USSD
321 * @param {number} [includeCUSD2=0] - Apakah ingin otomatis memasukkan CUSD=2 319 * @param {number} [includeCUSD2=0] - Apakah ingin otomatis memasukkan CUSD=2
322 */ 320 */
323 function executeUSSD(code, includeCUSD2) { 321 function executeUSSD(code, includeCUSD2) {
324 return new Promise(async (resolve) => { 322 return new Promise(async (resolve) => {
325 const parserMain = new ParserReadline({ delimiter: '\r\n' }); 323 const parserMain = new ParserReadline({ delimiter: '\r\n' });
326 // const parserMain = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 324 // const parserMain = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
327 parserMain.on('data', (data) => { 325 parserMain.on('data', (data) => {
328 port.unpipe(parserMain); 326 port.unpipe(parserMain);
329 mutex.releaseLockWaitForSubCommand(); 327 mutex.releaseLockWaitForSubCommand();
330 resolve(data); 328 resolve(data);
331 }); 329 });
332 330
333 const parserCUSD2 = new ParserReadline({ delimiter: '\r\n' }); 331 const parserCUSD2 = new ParserReadline({ delimiter: '\r\n' });
334 // const parserCUSD2 = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR }); 332 // const parserCUSD2 = new ParserRegex({ regex: REGEX_WAIT_FOR_OK_OR_ERROR });
335 parserCUSD2.on('data', () => { 333 parserCUSD2.on('data', () => {
336 port.unpipe(parserCUSD2); 334 port.unpipe(parserCUSD2);
337 mutex.releaseLockWaitForSubCommand(); 335 mutex.releaseLockWaitForSubCommand();
338 }); 336 });
339 337
340 logger.verbose('Waiting for command lock to execute USSD'); 338 logger.verbose('Waiting for command lock to execute USSD');
341 await mutex.setLockWaitForCommand(); 339 await mutex.setLockWaitForCommand();
342 340
343 if (includeCUSD2 === CUSD2_BEFORE) { 341 if (includeCUSD2 === -1 || includeCUSD2 === 2) {
344 logger.info('Terminating existing USSD session'); 342 logger.info('Terminating existing USSD session');
345 await mutex.setLockWaitForSubCommand(); 343 await mutex.setLockWaitForSubCommand();
346 port.pipe(parserCUSD2); 344 port.pipe(parserCUSD2);
347 await writeToPort('AT+CUSD=2\r'); 345 await writeToPort('AT+CUSD=2\r');
348 } 346 }
349 347
350 await mutex.setLockWaitForSubCommand(); 348 await mutex.setLockWaitForSubCommand();
351 port.pipe(parserMain); 349 port.pipe(parserMain);
352 await writeToPort(`AT+CUSD=1,"${code}",15\r`); 350 await writeToPort(`AT+CUSD=1,"${code}",15\r`);
353 351
354 if (includeCUSD2 === CUSD2_AFTER) { 352 if (includeCUSD2 === 1 || includeCUSD2 === 2) {
355 logger.info('Terminating existing USSD session'); 353 logger.info('Terminating existing USSD session');
356 await mutex.setLockWaitForSubCommand(); 354 await mutex.setLockWaitForSubCommand();
357 port.pipe(parserCUSD2); 355 port.pipe(parserCUSD2);
358 await writeToPort('AT+CUSD=2\r'); 356 await writeToPort('AT+CUSD=2\r');
359 } 357 }
360 358
361 await mutex.setLockWaitForSubCommand(); 359 await mutex.setLockWaitForSubCommand();
362 mutex.releaseLockWaitForSubCommand(); 360 mutex.releaseLockWaitForSubCommand();
363 361
364 mutex.releaseLockWaitForCommand(); 362 mutex.releaseLockWaitForCommand();
365 }); 363 });
366 } 364 }
367 365
368 function init() { 366 function init() {
369 port = new SerialPort(config.modem.device, { baudRate: 115200 }, (err) => { 367 port = new SerialPort(config.modem.device, { baudRate: 115200 }, (err) => {
370 if (err) { 368 if (err) {
371 logger.warn(`Error opening modem. ${err}. Terminating modem ${config.modem.device}.`); 369 logger.warn(`Error opening modem. ${err}. Terminating modem ${config.modem.device}.`);
372 process.exit(1); 370 process.exit(1);
373 } 371 }
374 372
375 registerModem(modemInfo); 373 registerModem(modemInfo);
376 }); 374 });
377 port.pipe(parserReadLine); 375 port.pipe(parserReadLine);
378 376
379 setInterval(() => { 377 setInterval(() => {
380 if ((new Date() - lastTs) > MAX_LAST_DATA_AGE_MS) { 378 if ((new Date() - lastTs) > MAX_LAST_DATA_AGE_MS) {
381 logger.warn(`No data for more than ${MAX_LAST_DATA_AGE_MS} ms. Modem might be unresponsive. Terminating modem ${config.modem.device}.`); 379 logger.warn(`No data for more than ${MAX_LAST_DATA_AGE_MS} ms. Modem might be unresponsive. Terminating modem ${config.modem.device}.`);
382 process.exit(0); 380 process.exit(0);
383 } 381 }
384 }, 30 * 1000); 382 }, 30 * 1000);
385 383
386 port.on('open', async () => { 384 port.on('open', async () => {
387 await mutex.setLockWaitForCommand(); 385 await mutex.setLockWaitForCommand();
388 386
389 logger.info('Modem opened'); 387 logger.info('Modem opened');
390 await writeToPort('\r'); 388 await writeToPort('\r');
391 await simpleSubCommand('AT\r'); 389 await simpleSubCommand('AT\r');
392 390
393 logger.info('Initializing modem to factory set'); 391 logger.info('Initializing modem to factory set');
394 await simpleSubCommand('AT&F\r'); 392 await simpleSubCommand('AT&F\r');
395 393
396 logger.info('Disabling echo'); 394 logger.info('Disabling echo');
397 await simpleSubCommand('ATE0\r'); 395 await simpleSubCommand('ATE0\r');
398 396
399 logger.info('Set to text mode'); 397 logger.info('Set to text mode');
400 await simpleSubCommand('AT+CMGF=1\r'); 398 await simpleSubCommand('AT+CMGF=1\r');
401 399
402 await readCOPS(); 400 await readCOPS();
403 401
404 await readManufacturer(); 402 await readManufacturer();
405 await readModel(); 403 await readModel();
406 await readIMEI(); 404 await readIMEI();
407 await readIMSI(); 405 await readIMSI();
408 406
409 if (!config.disable_delete_inbox_on_startup) { 407 if (!config.disable_delete_inbox_on_startup) {
410 logger.info('Deleting existing messages'); 408 logger.info('Deleting existing messages');
411 await deleteInbox(); 409 await deleteInbox();
412 } 410 }
413 411
414 mutex.releaseLockWaitForCommand(); 412 mutex.releaseLockWaitForCommand();
415 logger.verbose('Init completed'); 413 logger.verbose('Init completed');
416 414
417 registerModemToCenterPeriodically(); 415 registerModemToCenterPeriodically();
418 registerSignalStrengthBackgroundQuery(); 416 registerSignalStrengthBackgroundQuery();
419 }); 417 });
420 } 418 }
421 419
422 init(); 420 init();
423 421
424 exports.CUSD2_BEFORE = CUSD2_BEFORE;
425 exports.CUSD2_AFTER = CUSD2_AFTER;
426
427 exports.modemInfo = modemInfo; 422 exports.modemInfo = modemInfo;
428 exports.sendSMS = sendSMS; 423 exports.sendSMS = sendSMS;
429 exports.executeUSSD = executeUSSD; 424 exports.executeUSSD = executeUSSD;