File Coverage

blib/lib/Device/Gsm.pm
Criterion Covered Total %
statement 24 500 4.8
branch 0 196 0.0
condition 0 99 0.0
subroutine 8 35 22.8
pod 19 24 79.1
total 51 854 5.9


line stmt bran cond sub pod time code
1             # Device::Gsm - a Perl class to interface GSM devices as AT modems
2             # Copyright (C) 2002-2012 Cosimo Streppone, cosimo@cpan.org
3             # Copyright (C) 2006-2011 Grzegorz Wozniak, wozniakg@gmail.com
4             #
5             # This program is free software; you can redistribute it and/or modify
6             # it only under the terms of Perl itself.
7             #
8             # This program is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11             # Perl licensing terms for more details.
12              
13             package Device::Gsm;
14              
15             $Device::Gsm::VERSION = '1.60';
16              
17 6     6   83653 use strict;
  6         14  
  6         276  
18 6     6   8558 use Device::Modem 1.47;
  6         364756  
  6         215  
19 6     6   6072 use Device::Gsm::Sms;
  6         26  
  6         187  
20 6     6   59 use Device::Gsm::Pdu;
  6         15  
  6         253  
21 6     6   85 use Device::Gsm::Charset;
  6         11  
  6         154  
22 6     6   35 use Device::Gsm::Sms::Token;
  6         11  
  6         142  
23 6     6   7394 use Time::HiRes qw(sleep);
  6         13723  
  6         32  
24 6     6   1399 use constant USSD_DCS => 15;
  6         14  
  6         68915  
25              
26             @Device::Gsm::ISA = ('Device::Modem');
27              
28             %Device::Gsm::USSD_RESPONSE_CODES = (
29             0 =>
30             'No further user action required (network initiated USSD-Notify, or no further information needed after mobile Initiated operation)',
31             1 =>
32             'Further user action required (network initiated USSD-Request, or further information needed after mobile initiated operation)',
33             2 =>
34             'USSD terminated by network. the reason for the termination is indicated by the index stored in %Device::Gsm::USSD_TERMINATION_CODES',
35             3 => 'Other local client has responded',
36             4 => 'Operation not supported',
37             5 => 'Network time out'
38             );
39             %Device::Gsm::USSD_TERMINATION_CODES = (
40             0 => 'NO_CAUSE',
41             1 => 'CC_BUSY',
42             2 => 'PARAMETER_ERROR',
43             3 => 'INVALID_NUMBER',
44             4 => 'OUTGOING_CALL_BARRED',
45             5 => 'TOO_MANY_CALLS_ON_HOLD',
46             6 => 'NORMAL',
47             10 => 'DROPPED',
48             12 => 'NETWORK',
49             13 => 'INVALID_CALL_ID',
50             14 => 'NORMAL_CLEARING',
51             16 => 'TOO_MANY_ACTIVE_CALLS',
52             17 => 'UNASSIGNED_NUMBER',
53             18 => 'NO_ROUTE_TO_DEST',
54             19 => 'RESOURCE_UNAVAILABLE',
55             20 => 'CALL_BARRED',
56             21 => 'USER_BUSY',
57             22 => 'NO_ANSWER',
58             23 => 'CALL_REJECTED',
59             24 => 'NUMBER_CHANGED',
60             25 => 'DEST_OUT_OF_ORDER',
61             26 => 'SIGNALING_ERROR',
62             27 => 'NETWORK_ERROR',
63             28 => 'NETWORK_BUSY',
64             29 => 'NOT_SUBSCRIBED',
65             31 => 'SERVICE_UNAVAILABLE',
66             32 => 'SERVICE_NOT_SUPPORTED',
67             33 => 'PREPAY_LIMIT_REACHED',
68             35 => 'INCOMPATIBLE_DEST',
69             43 => 'ACCESS_DENIED',
70             45 => 'FEATURE_NOT_AVAILABLE',
71             46 => 'WRONG_CALL_STATE',
72             47 => 'SIGNALING_TIMEOUT',
73             48 => 'MAX_MPTY_PARTICIPANTS_EXCEEDED',
74             49 => 'SYSTEM_FAILURE',
75             50 => 'DATA_MISSING',
76             51 => 'BASIC_SERVICE_NOT_PROVISIONED',
77             52 => 'ILLEGAL_SS_OPERATION',
78             53 => 'SS_INCOMPATIBILITY',
79             54 => 'SS_NOT_AVAILABLE',
80             55 => 'SS_SUBSCRIPTION_VIOLATION',
81             56 => 'INCORRECT_PASSWORD',
82             57 => 'TOO_MANY_PASSWORD_ATTEMPTS',
83             58 => 'PASSWORD_REGISTRATION_FAILURE',
84             59 => 'ILLEGAL_EQUIPMENT',
85             60 => 'UNKNOWN_SUBSCRIBER',
86             61 => 'ILLEGAL_SUBSCRIBER',
87             62 => 'ABSENT_SUBSCRIBER',
88             63 => 'USSD_BUSY',
89             65 => 'CANNOT_TRANSFER_MPTY_CALL',
90             66 => 'BUSY_WITH_UNANSWERED_CALL',
91             68 => 'UNANSWERED_CALL_PENDING',
92             69 => 'USSD_CANCELED',
93             70 => 'PRE_EMPTION',
94             71 => 'OPERATION_NOT_ALLOWED',
95             72 => 'NO_FREE_BEARER_AVAILABLE',
96             73 => 'NBR_SN_EXCEEDED',
97             74 => 'NBR_USER_EXCEEDED',
98             75 => 'NOT_ALLOWED_BY_CC',
99             76 => 'MODIFIED_TO_SS_BY_CC',
100             77 => 'MODIFIED_TO_CALL_BY_CC',
101             78 => 'CALL_MODIFIED_BY_CC',
102             90 => 'FDN_FAILURE'
103             );
104              
105             # Connection defaults to 19200 baud. This seems to be the optimal
106             # rate for serial links to new gsm phones.
107             $Device::Gsm::BAUDRATE = 19200;
108              
109             # Time to wait after network register command (secs)
110             $Device::Gsm::REGISTER_DELAY = 2;
111              
112             # Connect on serial port to gsm device
113             # see parameters on Device::Modem::connect()
114             sub connect {
115 0     0 1   my $me = shift;
116 0           my %aOpt;
117 0 0         %aOpt = @_ if (@_);
118              
119             #
120             # If you have problems with bad characters being trasmitted across serial link,
121             # try different baud rates, as below...
122             #
123             # .---------------------------------.
124             # | Model (phone/modem) | Baudrate |
125             # |---------------------+-----------|
126             # | Falcom Swing (A2D) | 9600 |
127             # | Siemens C35/C45 | 19200 |
128             # | Nokia phones | 19200 |
129             # | Nokia Communicator | 9600 |
130             # | Digicom | 9600 |
131             # `---------------------------------'
132             #
133             # GSM class defaults to 19200 baud
134             #
135 0   0       $aOpt{'baudrate'} ||= $Device::Gsm::BAUDRATE;
136              
137 0           $me->SUPER::connect(%aOpt);
138             }
139              
140             sub disconnect {
141 0     0 1   my $me = shift;
142 0           $me->SUPER::disconnect();
143 0           sleep 0.05;
144             }
145              
146             #
147             # Get/set phone date and time
148             #
149             sub datetime {
150 0     0 1   my $self = shift;
151 0           my $ok = undef; # ok/err flag
152 0           my $datetime = undef; # datetime string
153 0           my @time = (); # array in "localtime" format
154              
155             # Test support for clock function
156 0 0         if ($self->test_command('+CCLK')) {
157              
158 0 0         if (@_) {
159              
160             # If called with "$self->datetime(time())" format
161 0 0         if (@_ == 1) {
162              
163             # $_[0] must be result of `time()' func
164 0           @time = localtime($_[0]);
165             }
166             else {
167              
168             # If called with "$self->datetime(localtime())" format
169             # @_ here is the result of `localtime()' func
170 0           @time = @_;
171             }
172              
173 0           $datetime = sprintf(
174             '%02d/%02d/%02d,%02d:%02d:%02d',
175             $time[5] - 100, # year
176             1 + $time[4], # month
177             $time[3], # day
178             @time[ 2, 1, 0 ], # hr,min,secs
179             );
180              
181             # Set time of phone
182 0           $self->atsend(qq{AT+CCLK="$datetime"} . Device::Modem::CR);
183 0           $ok = $self->parse_answer($Device::Modem::STD_RESPONSE);
184              
185 0 0         $self->log->write(
186             'info',
187             "write datetime ($datetime) to phone => ("
188             . ($ok ? 'OK' : 'FAILED') . ")"
189             );
190              
191             }
192             else {
193              
194 0           $self->atsend('AT+CCLK?' . Device::Modem::CR);
195 0           ($ok, $datetime)
196             = $self->parse_answer($Device::Modem::STD_RESPONSE);
197              
198             #warn('datetime='.$datetime);
199 0 0 0       if ( $ok
200             && $datetime
201             =~ m|\+CCLK:\s*"?(\d\d)/(\d\d)/(\d\d)\,(\d\d):(\d\d):(\d\d)"?|
202             )
203             {
204 0           $datetime = "$1/$2/$3 $4:$5:$6";
205 0           $self->log->write(
206             'info',
207             "read datetime from phone ($datetime)"
208             );
209             }
210             else {
211 0           $self->log->write(
212             'warn',
213             "datetime format ($datetime) not recognized"
214             );
215 0           $datetime = undef;
216             }
217              
218             }
219              
220             }
221              
222 0           return $datetime;
223              
224             }
225              
226             #
227             # Delete a message from sim card
228             #
229             sub delete_sms {
230 0     0 1   my $self = shift;
231 0           my $msg_index = shift;
232 0           my $storage = shift;
233 0           my $ok;
234              
235 0 0 0       if (!defined $msg_index || $msg_index eq '') {
236 0           $self->log->write(
237             'warn',
238             'undefined message number. cannot delete sms message'
239             );
240 0           return 0;
241             }
242              
243             # Set default SMS storage if supported
244 0           $self->storage($storage);
245              
246 0           $self->atsend(qq{AT+CMGD=$msg_index} . Device::Modem::CR);
247              
248 0           my $ans = $self->parse_answer($Device::Modem::STD_RESPONSE);
249 0 0 0       if (index($ans, 'OK') > -1 || $ans =~ /\+CMGD/) {
250 0           $ok = 1;
251             }
252              
253             $self->log->write(
254 0 0 0       'info',
255             "deleting sms n.$msg_index from storage "
256             . ($storage || "default")
257             . " (result: `$ans') => "
258             . ($ok ? 'ok' : '*FAILED*')
259             );
260              
261 0           return $ok;
262             }
263              
264             #
265             # Call forwarding
266             #
267             sub forward {
268 0     0 1   my ($self, $reason, $mode, $number) = @_;
269              
270 0   0       $reason = lc $reason || 'unconditional';
271 0   0       $mode = lc $mode || 'register';
272 0   0       $number ||= '';
273              
274 0           my %reasons = (
275             'unconditional' => 0,
276             'busy' => 1,
277             'no reply' => 2,
278             'unreachable' => 3
279             );
280              
281 0           my %modes = (
282             'disable' => 0,
283             'enable' => 1,
284             'query' => 2,
285             'register' => 3,
286             'erase' => 4
287             );
288              
289 0           my $reasoncode = $reasons{$reason};
290 0           my $modecode = $modes{$mode};
291              
292 0           $self->log->write(
293             'info',
294             qq{setting $reason call forwarding to [$number]}
295             );
296 0           $self->atsend(
297             qq{AT+CCFC=$reasoncode,$modecode,"$number"} . Device::Modem::CR);
298              
299 0           return $self->parse_answer($Device::Modem::STD_RESPONSE, 15000);
300             }
301              
302             #
303             # Hangup and terminate active call(s)
304             # this overrides the `Device::Modem::hangup()' method
305             #
306             sub hangup {
307 0     0 1   my $self = shift;
308 0           $self->log->write('info', 'hanging up...');
309 0           $self->attention();
310 0           $self->atsend('AT+CHUP' . Device::Modem::CR);
311 0           $self->flag('OFFHOOK', 0);
312 0           $self->answer(undef, 5000);
313             }
314              
315             #
316             # Who is the manufacturer of this device?
317             #
318             sub manufacturer {
319 0     0 1   my $self = shift;
320 0           my ($ok, $man);
321              
322             # We can't test for command support, because some phones, mainly Motorola
323             # will spit out an error, instead of telling if CGMI is supported.
324 0           $self->atsend('AT+CGMI' . Device::Modem::CR);
325 0           ($ok, $man) = $self->parse_answer($Device::Modem::STD_RESPONSE);
326              
327 0 0         if ($ok ne 'OK') {
328 0           $self->log->write(
329             'warn',
330             'manufacturer command ended with error [' . $ok . $man . ']'
331             );
332 0           return undef;
333             }
334              
335             # Again, seems that Motorola phones will re-echo
336             # the CGMI command header, instead of giving us the
337             # manufacturer info we want. Thanks to Niolay Shaplov
338             # for reporting (RT #31540)
339 0 0         if ($man =~ /\+CGMI:\ \"(.*)\"/s) {
340 0           $man = $1;
341             }
342              
343             $self->log->write(
344 0           'info',
345             'manufacturer of this device appears to be [' . $man . ']'
346             );
347              
348 0   0       return $man || $ok;
349             }
350              
351             #
352             # Set text or pdu mode for gsm devices. If no parameter passed, returns current mode
353             #
354             sub mode {
355 0     0 1   my $self = shift;
356              
357 0 0         if (@_) {
358 0           my $mode = lc $_[0];
359 0 0         if ($mode eq 'text') {
360 0           $mode = 1;
361             }
362             else {
363 0           $mode = 0;
364             }
365 0 0         $self->{'_mode'} = $mode ? 'text' : 'pdu';
366 0           $self->log->write(
367             'info',
368             'setting mode to [' . $self->{'_mode'} . ']'
369             );
370 0           $self->atsend(qq{AT+CMGF=$mode} . Device::Modem::CR);
371              
372 0           return $self->parse_answer($Device::Modem::STD_RESPONSE);
373             }
374              
375 0   0       return ($self->{'_mode'} || '');
376              
377             }
378              
379             #
380             # What is the model of this device?
381             #
382             sub model {
383 0     0 1   my $self = shift;
384 0           my ($code, $model);
385              
386             # Test if manufacturer code command is supported
387 0 0         if ($self->test_command('+CGMM')) {
388              
389 0           $self->atsend('AT+CGMM' . Device::Modem::CR);
390 0           ($code, $model) = $self->parse_answer($Device::Modem::STD_RESPONSE);
391              
392 0   0       $self->log->write(
393             'info',
394             'model of this device is [' . ($model || '') . ']'
395             );
396              
397             }
398              
399 0   0       return $model || $code;
400             }
401              
402             #
403             # Get handphone serial number (IMEI number)
404             #
405             sub imei {
406 0     0 1   my $self = shift;
407 0           my ($code, $imei);
408              
409             # Test if manufacturer code command is supported
410 0 0         if ($self->test_command('+CGSN')) {
411              
412 0           $self->atsend('AT+CGSN' . Device::Modem::CR);
413 0           ($code, $imei) = $self->parse_answer($Device::Modem::STD_RESPONSE);
414              
415 0           $self->log->write('info', 'IMEI code is [' . $imei . ']');
416              
417             }
418 0   0       return $imei || $code;
419             }
420              
421             # Alias for `imei()' is `serial_number()'
422             *serial_number = *imei;
423              
424             #
425             # Get mobile phone signal quality (expressed in dBm)
426             #
427             sub signal_quality {
428 0     0 1   my $self = shift;
429              
430             # Error code, dBm (signal power), bit error rate
431 0           my ($code, @dBm, $dBm, $ber);
432              
433             # Test if signal quality command is implemented
434 0 0         if ($self->test_command('+CSQ')) {
435              
436 0           $self->atsend('AT+CSQ' . Device::Modem::CR);
437 0           ($code, @dBm)
438             = $self->parse_answer($Device::Modem::STD_RESPONSE, 15000);
439              
440             # Vodafone data cards send out response to commands with
441             # many empty lines in between, so +CSQ response is not the very
442             # first line of answer.
443 0           for (@dBm) {
444 0 0         if (/\+CSQ:/) {
445 0           $dBm = $_;
446 0           last;
447             }
448             }
449              
450             # Some gsm software send CSQ command result as "+CSQ: xx,yy"
451 0 0         if ($dBm =~ /\+CSQ:\s*(\d+),(\d+)/) {
    0          
452              
453 0           ($dBm, $ber) = ($1, $2);
454              
455             # Further process dBm number to obtain real dB power
456 0 0         if ($dBm > 30) {
457 0           $dBm = -51;
458             }
459             else {
460 0           $dBm = -113 + ($dBm << 1);
461             }
462              
463 0           $self->log->write(
464             'info',
465             'signal dBm power is ['
466             . $dBm
467             . '], bit error rate ['
468             . $ber . ']'
469             );
470              
471             # Other versions put out "+CSQ: xx" only...
472             }
473             elsif ($dBm =~ /\+CSQ:\s*(\d+)/) {
474              
475 0           $dBm = $1;
476              
477 0           $self->log->write('info', 'signal is [' . $dBm . '] "bars"');
478              
479             }
480             else {
481              
482 0           $self->log->write('warn', 'cannot obtain signal dBm power');
483              
484             }
485              
486             }
487             else {
488              
489 0           $self->log->write('warn', 'signal quality command not supported!');
490              
491             }
492              
493 0           return $dBm;
494              
495             }
496              
497             #
498             # Get the GSM software version on this device
499             #
500             sub software_version {
501 0     0 1   my $self = shift;
502 0           my ($code, $ver);
503              
504             # Test if manufacturer code command is supported
505 0 0         if ($self->test_command('+CGMR')) {
506              
507 0           $self->atsend('AT+CGMR' . Device::Modem::CR);
508 0           ($code, $ver) = $self->parse_answer($Device::Modem::STD_RESPONSE);
509              
510 0           $self->log->write('info', 'GSM version is [' . $ver . ']');
511              
512             }
513              
514 0   0       return $ver || $code;
515             }
516              
517             #
518             # Test support for a specific command
519             #
520             sub test_command {
521 0     0 1   my ($self, $command) = @_;
522              
523             # Support old code adding a `+' if not specified
524             # TODO to be removed in 1.30 ?
525 0 0         if ($command =~ /^[a-zA-Z]/) {
526 0           $command = '+' . $command;
527             }
528              
529             # Standard test procedure for every command
530             $self->log->write(
531 0           'info',
532             'testing support for command [' . $command . ']'
533             );
534 0           $self->atsend("AT$command=?" . Device::Modem::CR);
535              
536             # If answer is ok, command is supported
537 0   0       my $ok = ($self->answer($Device::Modem::STD_RESPONSE) || '') =~ /OK/o;
538 0 0         $self->log->write(
539             'info',
540             'command [' . $command . '] is ' . ($ok ? '' : 'not ') . 'supported'
541             );
542              
543 0           $ok;
544             }
545              
546             #
547             # Read all messages on SIM card (XXX must be registered on network)
548             #
549             sub messages {
550 0     0 1   my ($self, $storage) = @_;
551 0           my @messages;
552              
553             # By default (old behaviour) messages are read from sim card
554 0   0       $storage ||= 'SM';
555              
556 0 0         $self->log->write('info', 'Reading messages on '
557             . ($storage eq 'SM' ? 'Sim card' : 'phone memory'));
558              
559             # Register on network (give your PIN number for this!)
560             #return undef unless $self->register();
561 0           $self->register();
562              
563             #
564             # Read messages (TODO need to check if device supports CMGL with `stat'=4)
565             #
566 0 0         if ($self->mode() eq 'text') {
567 0           warn 'Read messages in text mode is not implemented yet.';
568              
569             #@messages = $self->_read_messages_text();
570             }
571             else {
572              
573             # Set default storage if supported
574 0           $self->storage($storage);
575              
576 0           push @messages, $self->_read_messages_pdu();
577             }
578              
579 0           return @messages;
580             }
581              
582             sub storage {
583 0     0 1   my $self = shift;
584 0           my $ok = 0;
585              
586             # Set default SMS storage if supported by phone
587 0 0 0       if (@_ && (my $storage = uc $_[0])) {
588 0 0         return unless $self->test_command('+CPMS');
589 0           $self->atsend(qq{AT+CPMS="$storage"} . Device::Modem::CR);
590              
591             # Read and discard the answer
592 0           $self->answer($Device::Modem::STD_RESPONSE, 5000);
593 0           $self->{_storage} = $storage;
594             }
595              
596 0           return $self->{_storage};
597             }
598              
599             #
600             # Register to GSM service provider network
601             #
602             sub register {
603 0     0 1   my $me = shift;
604 0           my $lOk = 0;
605              
606             # Check for connection
607 0 0         if (!$me->{'CONNECTED'}) {
608 0           $me->log->write('info', 'Not yet connected. Doing it now...');
609 0 0         if (!$me->connect()) {
610 0           $me->log->write('warning', 'No connection!');
611 0           return $lOk;
612             }
613             }
614              
615             # On some phones, registration doesn't work, so you can skip it entirely
616             # by passing 'assume_registered => 1' to the new() constructor
617 0 0 0       if (exists $me->{'assume_registered'} && $me->{'assume_registered'}) {
618 0           return $me->{'REGISTERED'} = 1;
619             }
620              
621             # Send PIN status query
622 0           $me->log->write('info', 'PIN status query');
623 0           $me->atsend('AT+CPIN?' . Device::Modem::CR);
624              
625             # Get answer
626 0           my $cReply = $me->answer($Device::Modem::STD_RESPONSE, 10000);
627              
628 0 0 0       if (!defined $cReply || $cReply eq "") {
629 0           $me->log->write('warn',
630             'Could not get a reply for the AT+CPIN command');
631 0           return;
632             }
633              
634 0 0         if ($cReply =~ /(READY|SIM PIN2)/) {
    0          
635              
636             # Iridium satellite phones rest saying "SIM PIN2" when they are registered...
637              
638 0           $me->log->write(
639             'info',
640             'Already registered on network. Ready to send.'
641             );
642 0           $lOk = 1;
643              
644             }
645             elsif ($cReply =~ /SIM PIN/) {
646              
647             # Pin request, sending PIN code
648 0           $me->log->write('info', 'PIN requested: sending...');
649 0           $me->atsend(qq[AT+CPIN="$$me{'pin'}"] . Device::Modem::CR);
650              
651             # Get reply
652 0           $cReply = $me->answer($Device::Modem::STD_RESPONSE, 10000);
653              
654             # Test reply
655 0 0         if ($cReply !~ /ERROR/) {
656 0           $me->log->write('info', 'PIN accepted. Ready to send.');
657 0           $lOk = 1;
658             }
659             else {
660 0           $me->log->write('warning', 'PIN rejected');
661 0           $lOk = 0;
662             }
663              
664             }
665              
666             # Store status in object and return
667 0           $me->{'REGISTERED'} = $lOk;
668              
669 0           return $lOk;
670             }
671              
672             # send_sms( %options )
673             #
674             # recipient => '+39338101010'
675             # class => 'flash' | 'normal'
676             # validity => [ default = 24 hours ]
677             # content => 'text-only for now'
678             # mode => 'text' | 'pdu' (default = 'pdu')
679             #
680             sub send_sms {
681              
682 0     0 1   my ($me, %opt) = @_;
683              
684 0           my $lOk = 0;
685 0           my $mr;
686 0 0 0       return unless $opt{'recipient'} and $opt{'content'};
687              
688             # Check if registered to network
689 0 0         if (!$me->{'REGISTERED'}) {
690 0           $me->log->write('info', 'Not yet registered, doing now...');
691 0           $me->register();
692              
693             # Wait some time to allow SIM registering to network
694 0           $me->wait($Device::Gsm::REGISTER_DELAY << 10);
695             }
696              
697             # Again check if now registered
698 0 0         if (!$me->{'REGISTERED'}) {
699              
700 0           $me->log->write('warning', 'ERROR in registering to network');
701 0           return $lOk;
702              
703             }
704              
705             # Ok, registered. Select mode to send SMS
706 0   0       $opt{'mode'} ||= 'PDU';
707 0 0         if (uc $opt{'mode'} ne 'TEXT') {
708              
709 0           ($lOk, $mr) = $me->_send_sms_pdu(%opt);
710              
711             }
712             else {
713              
714 0           ($lOk, $mr) = $me->_send_sms_text(%opt);
715             }
716              
717             # Return result of sending
718 0 0         return wantarray ? ($lOk, $mr) : $lOk;
719             }
720              
721             # send_csms( %options )
722             #
723             # recipient => '+39338101010'
724             # class => 'flash' | 'normal'
725             # validity => [ default = 24 hours ]
726             # content => 'text-only above 160 chars'
727             #
728             sub send_csms {
729              
730 0     0 0   my ($me, %opt) = @_;
731              
732 0           my $lOk = 0;
733 0           my @mrs;
734 0 0 0       return unless $opt{'recipient'} and $opt{'content'};
735              
736             # Check if registered to network
737 0 0         if (!$me->{'REGISTERED'}) {
738 0           $me->log->write('info', 'Not yet registered, doing now...');
739 0           $me->register();
740              
741             # Wait some time to allow SIM registering to network
742 0           $me->wait($Device::Gsm::REGISTER_DELAY << 10);
743             }
744              
745             # Again check if now registered
746 0 0         if (!$me->{'REGISTERED'}) {
747              
748 0           $me->log->write('warning', 'ERROR in registering to network');
749 0           return 0;
750              
751             }
752              
753             # Ok, registered. Select mode to send SMS
754 0   0       $opt{'mode'} ||= 'PDU';
755              
756 0 0         if (uc $opt{'mode'} eq 'TEXT') {
757 0           $me->log->write('warning', 'CSMS only in PDU mode, switching');
758 0           until (uc($me->{'_mode'}) ne 'PDU') {
759 0 0         $me->mode('pdu') or sleep 0.05;
760             }
761             }
762 0           my @text_parts;
763              
764             #ensure we have to send CSMS
765 0 0         if (Device::Gsm::Charset::gsm0338_length($opt{'content'}) <= 160) {
766 0           my @send_return = $me->_send_sms_pdu(%opt);
767 0 0         if ($send_return[0]) {
768 0           $lOk++;
769 0           push(@mrs, $send_return[1]);
770             }
771             else {
772 0           $lOk = 0;
773 0           $#mrs = -1;
774             }
775             }
776             else {
777 0           my $udh = new Sms::Token("UDH");
778 0           my $ref_num = sprintf("%02X", (int(rand(255))));
779 0           my @text_parts = Device::Gsm::Charset::gsm0338_split($opt{'content'});
780 0           my $parts = scalar(@text_parts);
781 0           $parts = sprintf("%02X", $parts);
782 0           my $padding
783             = Sms::Token::UDH::calculate_padding(Sms::Token::UDH::IEI_T_8_L);
784 0           my $part_count = 1;
785 0           foreach my $text_part (@text_parts) {
786 0           my $part = sprintf("%02X", $part_count);
787 0           my ($len_hex, $encoded_text)
788             = Device::Gsm::Pdu::encode_text7_udh($text_part, $padding);
789 0           $part_count++;
790 0           $opt{'content'} = $text_part;
791 0           $opt{'pdu_msg'}
792             = sprintf("%02X",
793             hex($len_hex) + Sms::Token::UDH::IEI_T_8_L + 2)
794             . $udh->encode(
795             Sms::Token::UDH::IEI_T_8 => $ref_num . $parts . $part)
796             . $encoded_text;
797 0           my @send_return = $me->send_sms_pdu_long(%opt);
798 0 0         if ($send_return[0]) {
799 0           $lOk++;
800 0           push(@mrs, $send_return[1]);
801              
802             }
803             else {
804 0           $lOk = 0;
805 0           $#mrs = -1;
806 0           last;
807             }
808 0           sleep 0.05;
809             }
810             }
811              
812             # Return result of sending
813 0 0         return wantarray ? ($lOk, @mrs) : $lOk;
814             }
815              
816             #
817             #
818             # read messages in pdu mode
819             #
820             #
821             sub _read_messages_pdu {
822 0     0     my $self = shift;
823              
824 0           $self->mode('pdu');
825              
826 0           $self->atsend(q{AT+CMGL=4} . Device::Modem::CR);
827 0           my ($messages) = $self->answer($Device::Modem::STD_RESPONSE, 5000);
828              
829             # Catch the case that the msgs are returned with gaps between them
830 0           while (my $more = $self->answer($Device::Modem::STD_RESPONSE, 200)) {
831              
832             #-- $self->answer will chomp trailing newline, add it back
833 0           $messages .= "\n";
834 0           $messages .= $more;
835             }
836              
837             # Ok, messages read, now convert from PDU and store in object
838 0           $self->log->write('debug', 'Messages=' . $messages);
839              
840 0           my @data = split /[\r\n]+/m, $messages;
841              
842             # Check for errors on SMS reading
843 0           my $code;
844 0 0         if (($code = pop @data) =~ /ERROR/) {
845 0           $self->log->write(
846             'error',
847             'cannot read SMS messages on SIM: [' . $code . ']'
848             );
849 0           return ();
850             }
851              
852 0           my @message = ();
853 0           my $current;
854              
855             # Current sms storage memory (ME or SM)
856 0           my $storage = $self->storage();
857              
858             #
859             # Parse received data (result of +CMGL command)
860             #
861 0           while (@data) {
862              
863 0           $self->log->write('debug', 'data[] = ', $data[0]);
864 0           my $header = shift @data;
865 0           my $pdu = shift @data;
866              
867             # Instance new message object
868 0           my $msg = new Device::Gsm::Sms(
869             header => $header,
870             pdu => $pdu,
871              
872             # XXX mode => $self->mode(),
873             storage => $storage,
874             parent => $self # Ref to parent Device::Gsm class
875             );
876              
877             # Check if message has been instanced correctly
878 0 0         if (ref $msg) {
879 0           push @message, $msg;
880             }
881             else {
882 0           $self->log->write(
883             'info',
884             "could not instance message $header $pdu!"
885             );
886             }
887              
888             }
889              
890             $self->log->write(
891 0           'info',
892             'found ' . (scalar @message) . ' messages on SIM. Reading.'
893             );
894              
895 0           return @message;
896              
897             }
898              
899             #
900             # _send_sms_text( %options ) : sends message in text mode
901             #
902             sub _send_sms_text {
903 0     0     my ($me, %opt) = @_;
904              
905 0           my $num = $opt{'recipient'};
906 0           my $text = $opt{'content'};
907              
908 0 0 0       return 0 unless $num and $text;
909              
910 0           my $lOk = 0;
911 0           my $mr;
912             my $cReply;
913              
914             # Select text format for messages
915 0           $me->mode('text');
916 0           $me->log->write('info', 'Selected text format for message sending');
917              
918             # Send sms in text mode
919 0           $me->atsend(qq[AT+CMGS="$num"] . Device::Modem::CR);
920              
921             # Wait a bit before sending the text. Some GSM software needs it.
922 0           $me->wait($Device::Modem::WAITCMD);
923              
924             # Complete message sending
925 0           $text = Device::Gsm::Charset::iso8859_to_gsm0338($text);
926 0           $me->atsend($text . Device::Modem::CTRL_Z);
927              
928             # Get reply and check for errors
929 0           $cReply = $me->answer('+CMGS', 2000);
930 0 0         if ($cReply =~ /OK$/i) {
931 0           $cReply =~ /\+CMGS:\s*(\d+)/i;
932 0           $me->log->write('info', "Sent SMS (text mode) to $num!");
933 0           $lOk = 1;
934 0           $mr = $1;
935             }
936             else {
937 0           $me->log->write('warning', "ERROR in sending SMS");
938             }
939              
940 0 0         return wantarray ? ($lOk, $mr) : $lOk;
941             }
942              
943             #
944             # _send_sms_pdu( %options ) : sends message in PDU mode
945             #
946             sub _send_sms_pdu {
947 0     0     my ($me, %opt, $is_gsm0338) = @_;
948              
949             # Get options
950 0           my $num = $opt{'recipient'};
951 0           my $text = $opt{'content'};
952              
953 0 0 0       return 0 unless $num and $text;
954              
955 0           $me->atsend(q[ATE1] . Device::Modem::CR);
956 0           $me->answer($Device::Modem::STD_RESPONSE);
957              
958             # Select class of sms (normal or *flash sms*)
959 0   0       my $class = $opt{'class'} || 'normal';
960 0 0         $class = $class eq 'normal' ? '00' : 'F0';
961              
962             #Validity period value
963             #0 to 143 (TP-VP + 1) * 5 minutes (i.e. 5 minutes intervals up to 12 hours)
964             #144 to 167 12 hours + ((TP-VP - 143) * 30 minutes)
965             #168 to 196 (TP-VP - 166) * 1 day
966             #197 to 255 (TP-VP - 192) * 1 week
967             #default 24h
968 0           my $vp = 'A7';
969 0 0         if (defined $opt{'validity_period'}) {
970 0           $vp = sprintf("%02X", $opt{'validity_period'});
971             }
972              
973             # Status report requested?
974 0           my $status_report = 0;
975 0 0 0       if (exists $opt{'status_report'} && $opt{'status_report'}) {
976 0           $status_report = 1;
977             }
978              
979 0           my $lOk = 0;
980 0           my $mr = undef;
981 0           my $cReply;
982              
983             # Send sms in PDU mode
984              
985             #
986             # Example of sms send in PDU mode
987             #
988             #AT+CMGS=22
989             #> 0011000A8123988277190000AA0AE8329BFD4697D9EC37
990             #+CMGS: 111
991             #
992             #OK
993              
994             # Encode DA
995 0           my $enc_da = Device::Gsm::Pdu::encode_address($num);
996 0           $me->log->write('info', 'encoded dest. address is [' . $enc_da . ']');
997              
998             # Encode text
999 0 0         $is_gsm0338 or $text = Device::Gsm::Charset::iso8859_to_gsm0338($text);
1000 0           my $enc_msg = Device::Gsm::Pdu::encode_text7($text);
1001 0           $me->log->write(
1002             'info',
1003             'encoded 7bit text (w/length) is [' . $enc_msg . ']'
1004             );
1005              
1006             # Build PDU data
1007 0 0         my $pdu = uc join(
1008             '',
1009             '00',
1010             ($status_report ? '31' : '11'),
1011             '00',
1012             $enc_da,
1013             '00',
1014             $class,
1015             $vp,
1016             $enc_msg
1017             );
1018              
1019 0           $me->log->write('info', 'due to send PDU [' . $pdu . ']');
1020              
1021             # Sending main SMS command ( with length )
1022 0           my $len = ((length $pdu) >> 1) - 1;
1023              
1024             #$me->log->write('info', 'AT+CMGS='.$len.' string sent');
1025              
1026             # Select PDU format for messages
1027 0           $me->atsend(q[AT+CMGF=0] . Device::Modem::CR);
1028 0           $me->answer($Device::Modem::STD_RESPONSE);
1029 0           $me->log->write('info', 'Selected PDU format for msg sending');
1030              
1031             # Send SMS length
1032 0           $me->atsend(qq[AT+CMGS=$len] . Device::Modem::CR);
1033 0           $me->answer($Device::Modem::STD_RESPONSE);
1034              
1035             # Sending SMS content encoded as PDU
1036 0           $me->log->write('info', 'PDU sent [' . $pdu . ' + CTRLZ]');
1037 0           $me->atsend($pdu . Device::Modem::CTRL_Z);
1038              
1039             # Get reply and check for errors
1040 0           $cReply = $me->answer($Device::Modem::STD_RESPONSE, 30000);
1041 0           $me->log->write('debug', "SMS reply: $cReply\r\n");
1042              
1043 0 0         if ($cReply =~ /OK$/i) {
1044 0           $cReply =~ /\+CMGS:\s*(\d+)/i;
1045 0           $me->log->write('info', "Sent SMS (pdu mode) to $num!");
1046 0           $lOk = 1;
1047 0           $mr = $1;
1048              
1049             }
1050             else {
1051 0           $cReply =~ /(\+CMGS:.*)/;
1052 0           $me->log->write('warning', "ERROR in sending SMS: $1");
1053             }
1054              
1055 0 0         return wantarray ? ($lOk, $mr) : $lOk;
1056             }
1057              
1058             sub send_sms_pdu_long {
1059 0     0 0   my ($me, %opt) = @_;
1060              
1061             # Get options
1062 0           my $num = $opt{'recipient'};
1063 0           my $text = $opt{'content'};
1064 0           my $pdu_msg = $opt{'pdu_msg'};
1065              
1066 0 0 0       return 0 unless $num and $text and $pdu_msg;
      0        
1067              
1068 0           $me->atsend(q[ATE1] . Device::Modem::CR);
1069 0           $me->answer($Device::Modem::STD_RESPONSE);
1070              
1071             # Select class of sms (normal or *flash sms*)
1072 0   0       my $class = $opt{'class'} || 'normal';
1073 0 0         $class = $class eq 'normal' ? '00' : 'F0';
1074              
1075             #Validity period value
1076             #0 to 143 (TP-VP + 1) * 5 minutes (i.e. 5 minutes intervals up to 12 hours)
1077             #144 to 167 12 hours + ((TP-VP - 143) * 30 minutes)
1078             #168 to 196 (TP-VP - 166) * 1 day
1079             #197 to 255 (TP-VP - 192) * 1 week
1080             #default 24h
1081 0           my $vp = 'A7';
1082 0 0         if (defined $opt{'validity_period'}) {
1083 0           $vp = sprintf("%02X", $opt{'validity_period'});
1084             }
1085              
1086             # Status report requested?
1087 0           my $status_report = 0;
1088 0 0 0       if (exists $opt{'status_report'} && $opt{'status_report'}) {
1089 0           $status_report = 1;
1090             }
1091              
1092 0           my $lOk = 0;
1093 0           my $mr = undef;
1094 0           my $cReply;
1095              
1096             # Send sms in PDU mode
1097              
1098             #
1099             # Example of sms send in PDU mode
1100             #
1101             #AT+CMGS=22
1102             #> 0011000A8123988277190000AA0AE8329BFD4697D9EC37
1103             #+CMGS: 111
1104             #
1105             #OK
1106              
1107             # Encode DA
1108 0           my $enc_da = Device::Gsm::Pdu::encode_address($num);
1109 0           $me->log->write('info', 'encoded dest. address is [' . $enc_da . ']');
1110              
1111             # Encode text
1112             #$text = Device::Gsm::Charset::iso8859_to_gsm0338($text);
1113             #my $enc_msg = Device::Gsm::Pdu::encode_text7($text);
1114 0           $me->log->write(
1115             'info',
1116             'encoded 7bit text (w/length) is [' . $pdu_msg . ']'
1117             );
1118              
1119             # Build PDU data
1120 0 0         my $pdu = uc join(
1121             '',
1122              
1123             #we use default SMSC address(don supply one)
1124             '00',
1125              
1126             #as you can see when UDH is present we set 6 bit of of first octet, you can recognize CSM that way, I prefer regex :) (se UD.pm)
1127             ($status_report ? '71' : '51'),
1128              
1129             #message reference, my G24 returns own MR after successful sending, setting this value did nothing in that case, but other modems may behave differently
1130             '00',
1131             $enc_da,
1132              
1133             #protocol identifier (0x00 use default)
1134             '00',
1135              
1136             #data coding scheme (flash sms or normal, coding etc. more about:http://www.dreamfabric.com/sms/dcs.html)
1137             $class,
1138             $vp,
1139             $pdu_msg
1140             );
1141              
1142 0           $me->log->write('info', 'due to send PDU [' . $pdu . ']');
1143              
1144             # Sending main SMS command ( with length )
1145 0           my $len = ((length $pdu) >> 1) - 1;
1146              
1147             #$me->log->write('info', 'AT+CMGS='.$len.' string sent');
1148              
1149             # Select PDU format for messages
1150 0           $me->atsend(q[AT+CMGF=0] . Device::Modem::CR);
1151 0           $me->answer($Device::Modem::STD_RESPONSE);
1152 0           $me->log->write('info', 'Selected PDU format for msg sending');
1153              
1154             # Send SMS length
1155 0           $me->atsend(qq[AT+CMGS=$len] . Device::Modem::CR);
1156 0           $me->answer($Device::Modem::STD_RESPONSE);
1157              
1158             # Sending SMS content encoded as PDU
1159 0           $me->log->write('info', 'PDU sent [' . $pdu . ' + CTRLZ]');
1160 0           $me->atsend($pdu . Device::Modem::CTRL_Z);
1161              
1162             # Get reply and check for errors
1163 0           $cReply = $me->answer($Device::Modem::STD_RESPONSE, 30000);
1164 0           $me->log->write('debug', "SMS reply: $cReply\r\n");
1165              
1166 0 0         if ($cReply =~ /OK$/i) {
1167 0           $cReply =~ /\+CMGS:\s*(\d+)/i;
1168 0           $me->log->write('info', "Sent SMS (pdu mode) to $num!");
1169 0           $lOk = 1;
1170 0           $mr = $1;
1171             }
1172             else {
1173 0           $cReply =~ /(\+CMGS:.*)/;
1174 0           $me->log->write('warning', "ERROR in sending SMS: $1");
1175             }
1176              
1177 0 0         return wantarray ? ($lOk, $mr) : $lOk;
1178             }
1179              
1180             #
1181             # Set or request service center number
1182             #
1183             sub service_center {
1184              
1185 0     0 1   my $self = shift;
1186 0           my $nCenter;
1187 0           my $lOk = 1;
1188 0           my $code;
1189              
1190             # If additional parameter is supplied, store new message center number
1191 0 0         if (@_) {
1192 0           $nCenter = shift();
1193              
1194             # Remove all non numbers or `+' sign
1195 0           $nCenter =~ s/[^0-9+]//g;
1196              
1197             # Send AT command
1198 0           $self->atsend(qq[AT+CSCA="$nCenter"] . Device::Modem::CR);
1199              
1200             # Check for modem answer
1201 0           $lOk = ($self->answer($Device::Modem::STD_RESPONSE) =~ /OK/);
1202              
1203 0 0         if ($lOk) {
1204 0           $self->log->write(
1205             'info',
1206             'service center number [' . $nCenter . '] stored'
1207             );
1208             }
1209             else {
1210 0           $self->log->write(
1211             'warning',
1212             'unexpected response for "service_center" command'
1213             );
1214             }
1215              
1216             }
1217             else {
1218              
1219 0           $self->log->write('info', 'requesting service center number');
1220 0           $self->atsend('AT+CSCA?' . Device::Modem::CR);
1221              
1222             # Get answer and check for errors
1223 0           ($code, $nCenter) = $self->parse_answer($Device::Modem::STD_RESPONSE);
1224              
1225 0 0         if ($code =~ /ERROR/) {
1226 0           $self->log->write(
1227             'warning',
1228             'error status for "service_center" command'
1229             );
1230 0           $lOk = 0;
1231             }
1232             else {
1233              
1234             # $nCenter =~ tr/\r\nA-Z//s;
1235 0           $self->log->write(
1236             'info',
1237             'service center number is [' . $nCenter . ']'
1238             );
1239              
1240             # Return service center number
1241 0           $lOk = $nCenter;
1242             }
1243              
1244             }
1245              
1246             # Status flag or service center number
1247 0           return $lOk;
1248              
1249             }
1250              
1251             sub network {
1252 0     0 1   my $self = $_[0];
1253 0           my $network;
1254              
1255             #if( ! $self->test_command('COPS') )
1256             #{
1257             # print 'NO COMMAND';
1258             # return undef;
1259             #}
1260              
1261 0           $self->atsend('AT+COPS?' . Device::Modem::CR);
1262              
1263             # Parse COPS answer, the 3rd string is the network name
1264 0           my $ans = $self->answer();
1265 0 0         if ($ans =~ /"([^"]*)"/) {
1266 0           $network = $1;
1267 0           $self->log->write('info', 'Received network name [' . $network . ']');
1268             }
1269             else {
1270 0           $self->log->write('info', 'Received no network name');
1271             }
1272              
1273             # Try to decode the network name
1274 0           require Device::Gsm::Networks;
1275 0           my $netname = Device::Gsm::Networks::name($network);
1276 0 0 0       if (!defined $netname || $netname eq 'unknown') {
1277 0           $netname = undef;
1278             }
1279             return wantarray
1280 0 0         ? ($netname, $network)
1281             : $netname;
1282              
1283             }
1284              
1285             #
1286             #returns simcard MSISDN
1287             #
1288             sub selfnum {
1289 0     0 0   my $self = shift;
1290 0           my @selfnum;
1291             my $selfnum;
1292 0 0         if ($self->test_command('CNUM')) {
1293 0           $self->atsend('AT+CNUM' . Device::Modem::CR);
1294 0           my $ans = $self->answer($Device::Modem::STD_RESPONSE);
1295 0           my @answer = split /[\r\n]+/m, $ans;
1296 0           foreach (@answer) {
1297 0 0         if ($_ =~ /^\+CNUM: /) {
1298 0           my @temp = split /,/, $';
1299 0           $temp[1] =~ s/"//g;
1300 0 0         if ($temp[1] =~ /\d{9,}/) {
1301 0 0         !$selfnum and $selfnum = $temp[1];
1302 0           push(@selfnum, $temp[1]);
1303             }
1304             }
1305             }
1306 0 0         if ($selfnum) {
1307 0           $self->log->write('info', 'Received number [' . "@selfnum" . ']');
1308             return wantarray
1309             ? @selfnum
1310 0 0         : $selfnum;
1311             }
1312             else {
1313 0           $self->log->write('info', 'Received no numbers');
1314 0           return "";
1315             }
1316              
1317             }
1318              
1319             #
1320             #On my motorola G24 for messages with alphanumeric sender sender() returns malformed characters
1321             #on globetrotter option 505 everything is all right. I wrote this at beggining of playng with you module,
1322             #and almost forgot about it. I'll investigate this bug in future.
1323             #
1324             }
1325              
1326             sub get_literal_header {
1327 0     0 0   my ($self, $index) = @_;
1328 0           my $header = '';
1329              
1330             #set text mode
1331 0           $self->atsend('AT+CMGF=1' . Device::Modem::CR);
1332 0           sleep 0.05;
1333 0 0         if ($self->answer($Device::Modem::STD_RESPONSE) =~ /OK/) {
1334 0           $self->log->write('warning', 'Text mode set');
1335             }
1336             else {
1337 0           $self->log->write('warning', 'Text mode not set');
1338 0           $self->log->write('warning', 'Trying restore PDU mode');
1339 0           $self->atsend('AT+CMGF=0' . Device::Modem::CR);
1340 0           sleep 0.05;
1341 0 0         $self->answer($Device::Modem::STD_RESPONSE) =~ /OK/
1342             and $self->log->write('warning', 'PDU mode restored');
1343 0           return;
1344             }
1345 0           $self->atsend('AT+MMGR=' . $index . Device::Modem::CR);
1346 0           my $ans = $self->answer();
1347 0 0         if ($ans =~ /\+MMGR:/) {
1348 0           my @temp = split(/,/, $');
1349 0           $header = $temp[1];
1350 0           $header =~ s/\"|\'//g;
1351             }
1352 0           $self->atsend('AT+CMGF=0' . Device::Modem::CR);
1353 0           sleep 0.05;
1354 0 0 0       $self->answer($Device::Modem::STD_RESPONSE) =~ /OK/
1355             and $self->log->write('warning', 'PDU mode Set')
1356             or return;
1357 0           return $header;
1358             }
1359              
1360             sub send_ussd {
1361 0     0 0   my ($self, $message) = @_;
1362 0           my $answer = '';
1363 0           my $encoded = Device::Gsm::Pdu::encode_text7_ussd($message);
1364 0 0         if ($self->test_command("CUSD")) {
1365 0           my $at_command
1366             = 'AT+CUSD=1,"' . $encoded . '",' . USSD_DCS . Device::Modem::CR;
1367 0           $self->atsend($at_command);
1368 0           my $expect = qr/ERROR|OK|\+CUSD:/;
1369 0           my $cReadChars = $Device::Modem::READCHARS;
1370 0           $Device::Modem::READCHARS = 300;
1371 0           my $response = '';
1372 0           $response = $self->answer($expect, 1000);
1373              
1374             # Catch the case that the msgs are returned with gaps between them
1375 0 0         $response =~ m/OK/
1376             and $response .= "\n" . $self->answer($expect, 15000);
1377 0           $Device::Modem::READCHARS = $cReadChars;
1378 0 0         if ($response =~ m/OK/) {
1379 0           $self->log->write('warning',
1380             'send_ussd command: "'
1381             . $message
1382             . '" OK, AT: '
1383             . $at_command . " "
1384             . 'response: '
1385             . $response);
1386 0 0         if ($response =~ m/\+CUSD:\s*(\d+)\s*,/) {
1387 0           my $response_code = $1;
1388 0           $self->log->write('warning',
1389             "Have a ussd_response code: $response_code=>"
1390             . $Device::Gsm::USSD_RESPONSE_CODES{$1});
1391 0           $response = $';
1392 0 0         if ($response_code < 2) {
    0          
1393 0 0         if ($response =~ m/\s*\"?([0-9A-F]+)\"?\s*,\s*(\d*)\s*/) {
1394 0           my $ussd_response = $1;
1395 0 0         my $ussd_dcs = length($2) ? $2 : USSD_DCS;
1396 0           $self->log->write('warning',
1397             "Have a ussd_response message: $ussd_response, dcs: $ussd_dcs"
1398             );
1399 0 0 0       ($ussd_dcs == 15 or $ussd_dcs == 0)
      0        
1400             and $answer
1401             = Device::Gsm::Pdu::decode_text7_ussd(
1402             $ussd_response)
1403             and $ussd_dcs = -1;
1404 0 0 0       $ussd_dcs == 72
1405             and $answer
1406             = Device::Gsm::Pdu::decode_text_UCS2(
1407             $ussd_response)
1408             and $ussd_dcs = -1;
1409 0 0 0       $ussd_dcs == 68
1410             and $answer
1411             = Device::Gsm::Pdu::decode_text8($ussd_response)
1412             and $ussd_dcs = -1;
1413 0 0         $ussd_dcs != -1
1414             and $self->log->write('warning',
1415             "Cant decode ussd_response message with dcs: $ussd_dcs"
1416             );
1417              
1418             }
1419              
1420             }
1421             elsif ($response_code == 2) {
1422 0 0         $response =~ m/\s*(\d+)\s*/
1423             and $self->log->write('warning',
1424             "Have a ussd_termintion code: $1=>"
1425             . $Device::Gsm::USSD_TERMINATION_CODES{$1});
1426             }
1427             }
1428             }
1429             else {
1430 0           $self->log->write('warning',
1431             'Error send_ussd command: '
1432             . $at_command
1433             . ", returned: "
1434             . $response);
1435 0           return '';
1436              
1437             }
1438             }
1439             else {
1440 0           $self->log->write('warning',
1441             'Error send_ussd AT+CUSD command not supported');
1442 0           return '';
1443             }
1444 0           return $answer;
1445             }
1446             1;
1447              
1448             __END__