| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# Device::Modem - a Perl class to interface generic modems (AT-compliant) |
|
2
|
|
|
|
|
|
|
# Copyright (C) 2002-2014 Cosimo Streppone, cosimo@cpan.org |
|
3
|
|
|
|
|
|
|
# |
|
4
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or |
|
5
|
|
|
|
|
|
|
# modify it under the same terms as Perl itself. |
|
6
|
|
|
|
|
|
|
# |
|
7
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
|
8
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
9
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
10
|
|
|
|
|
|
|
# Perl licensing terms for details. |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
package Device::Modem; |
|
13
|
|
|
|
|
|
|
$VERSION = '1.57'; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
BEGIN { |
|
16
|
|
|
|
|
|
|
|
|
17
|
1
|
50
|
|
1
|
|
2965
|
if( index($^O, 'Win') >= 0 ) { # MSWin32 (and not darwin, cygwin, ...) |
|
18
|
|
|
|
|
|
|
|
|
19
|
0
|
|
|
|
|
0
|
require Win32::SerialPort; |
|
20
|
0
|
|
|
|
|
0
|
import Win32::SerialPort; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Import line status constants from Win32::SerialPort module |
|
23
|
0
|
|
|
|
|
0
|
*Device::Modem::MS_CTS_ON = *Win32::SerialPort::MS_CTS_ON; |
|
24
|
0
|
|
|
|
|
0
|
*Device::Modem::MS_DSR_ON = *Win32::SerialPort::MS_DSR_ON; |
|
25
|
0
|
|
|
|
|
0
|
*Device::Modem::MS_RING_ON = *Win32::SerialPort::MS_RING_ON; |
|
26
|
0
|
|
|
|
|
0
|
*Device::Modem::MS_RLSD_ON = *Win32::SerialPort::MS_RLSD_ON; |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
} else { |
|
29
|
|
|
|
|
|
|
|
|
30
|
1
|
|
|
|
|
1327
|
require Device::SerialPort; |
|
31
|
1
|
|
|
|
|
41146
|
import Device::SerialPort; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Import line status constants from Device::SerialPort module |
|
34
|
1
|
|
|
|
|
5
|
*Device::Modem::MS_CTS_ON = *Device::SerialPort::MS_CTS_ON; |
|
35
|
1
|
|
|
|
|
3
|
*Device::Modem::MS_DSR_ON = *Device::SerialPort::MS_DSR_ON; |
|
36
|
1
|
|
|
|
|
3
|
*Device::Modem::MS_RING_ON = *Device::SerialPort::MS_RING_ON; |
|
37
|
1
|
|
|
|
|
36
|
*Device::Modem::MS_RLSD_ON = *Device::SerialPort::MS_RLSD_ON; |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
1
|
|
|
1
|
|
20
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
37
|
|
|
43
|
1
|
|
|
1
|
|
7
|
use Carp (); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
30
|
|
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Constants definition |
|
46
|
1
|
|
|
1
|
|
5
|
use constant CTRL_Z => chr(26); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
95
|
|
|
47
|
1
|
|
|
1
|
|
6
|
use constant CR => "\r"; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
5194
|
|
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Connection defaults |
|
50
|
|
|
|
|
|
|
$Device::Modem::DEFAULT_PORT = index($^O, 'Win') >= 0 ? 'COM1' : '/dev/modem'; |
|
51
|
|
|
|
|
|
|
$Device::Modem::DEFAULT_INIT_STRING = 'S7=45 S0=0 L1 V1 X4 &c1 E1 Q0'; |
|
52
|
|
|
|
|
|
|
$Device::Modem::BAUDRATE = 19200; |
|
53
|
|
|
|
|
|
|
$Device::Modem::DATABITS = 8; |
|
54
|
|
|
|
|
|
|
$Device::Modem::STOPBITS = 1; |
|
55
|
|
|
|
|
|
|
$Device::Modem::HANDSHAKE= 'none'; |
|
56
|
|
|
|
|
|
|
$Device::Modem::PARITY = 'none'; |
|
57
|
|
|
|
|
|
|
$Device::Modem::TIMEOUT = 500; # milliseconds |
|
58
|
|
|
|
|
|
|
$Device::Modem::READCHARS= 130; |
|
59
|
|
|
|
|
|
|
$Device::Modem::WAITCMD = 200; # milliseconds |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# Setup text and numerical response codes |
|
62
|
|
|
|
|
|
|
@Device::Modem::RESPONSE = ( 'OK', undef, 'RING', 'NO CARRIER', 'ERROR', undef, 'NO DIALTONE', 'BUSY' ); |
|
63
|
|
|
|
|
|
|
$Device::Modem::STD_RESPONSE = qr/^(OK|ERROR|COMMAND NOT SUPPORT)$/m; |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
#%Device::Modem::RESPONSE = ( |
|
66
|
|
|
|
|
|
|
# 'OK' => 'Command executed without errors', |
|
67
|
|
|
|
|
|
|
# 'RING' => 'Detected phone ring', |
|
68
|
|
|
|
|
|
|
# 'NO CARRIER' => 'Link not established or disconnected', |
|
69
|
|
|
|
|
|
|
# 'ERROR' => 'Invalid command or command line too long', |
|
70
|
|
|
|
|
|
|
# 'NO DIALTONE' => 'No dial tone, dialing not possible or wrong mode', |
|
71
|
|
|
|
|
|
|
# 'BUSY' => 'Remote terminal busy' |
|
72
|
|
|
|
|
|
|
#); |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# object constructor (prepare only object) |
|
75
|
|
|
|
|
|
|
sub new { |
|
76
|
0
|
|
|
0
|
1
|
|
my($proto,%aOpt) = @_; # Get reference to object |
|
77
|
|
|
|
|
|
|
# Options of object |
|
78
|
0
|
|
0
|
|
|
|
my $class = ref($proto) || $proto; # Get reference to class |
|
79
|
|
|
|
|
|
|
|
|
80
|
0
|
|
|
|
|
|
$aOpt{'ostype'} = $^O; # Store OSTYPE in object |
|
81
|
0
|
0
|
|
|
|
|
$aOpt{'ostype'} = 'windoze' if index( $aOpt{'ostype'}, 'Win' ) >= 0; |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# Initialize flags array |
|
84
|
0
|
|
|
|
|
|
$aOpt{'flags'} = {}; |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
# Start as not connected |
|
87
|
0
|
|
|
|
|
|
$aOpt{'CONNECTED'} = 0; |
|
88
|
|
|
|
|
|
|
|
|
89
|
0
|
|
0
|
|
|
|
$aOpt{'port'} ||= $Device::Modem::DEFAULT_PORT; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Instance log object |
|
92
|
0
|
|
0
|
|
|
|
$aOpt{'log'} ||= 'file'; |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Force logging to file if this is windoze and user requested syslog mechanism |
|
95
|
0
|
0
|
0
|
|
|
|
$aOpt{'log'} = 'file' if( $aOpt{'ostype'} eq 'windoze' && $aOpt{'log'} =~ /syslog/i ); |
|
96
|
0
|
|
0
|
|
|
|
$aOpt{'loglevel'} ||= 'warning'; |
|
97
|
|
|
|
|
|
|
|
|
98
|
0
|
0
|
|
|
|
|
if( ! ref $aOpt{'log'} ) { |
|
99
|
0
|
|
|
|
|
|
my($method, @options) = split ',', delete $aOpt{'log'}; |
|
100
|
0
|
|
|
|
|
|
my $logclass = 'Device/Modem/Log/'.ucfirst(lc $method).'.pm'; |
|
101
|
0
|
|
|
|
|
|
my $package = 'Device::Modem::Log::'.ucfirst lc $method; |
|
102
|
0
|
|
|
|
|
|
eval { require $logclass; }; |
|
|
0
|
|
|
|
|
|
|
|
103
|
0
|
0
|
|
|
|
|
unless($@) { |
|
104
|
0
|
|
|
|
|
|
$aOpt{'_log'} = $package->new( $class, @options ); |
|
105
|
|
|
|
|
|
|
} else { |
|
106
|
0
|
|
|
|
|
|
print STDERR "Failed to require Log package: $@\n"; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
} else { |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# User passed an already instanced log object |
|
111
|
0
|
|
|
|
|
|
$aOpt{'_log'} = $aOpt{'log'}; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
|
|
114
|
0
|
0
|
0
|
|
|
|
if( ref $aOpt{'_log'} && $aOpt{'_log'}->can('loglevel') ) { |
|
115
|
0
|
|
|
|
|
|
$aOpt{'_log'}->loglevel($aOpt{'loglevel'}); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
|
bless \%aOpt, $class; # Instance $class object |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub attention { |
|
122
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
123
|
0
|
|
|
|
|
|
$self->log->write('info', 'sending attention sequence...'); |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# Send attention sequence |
|
126
|
0
|
|
|
|
|
|
$self->atsend('+++'); |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Wait for response |
|
129
|
0
|
|
|
|
|
|
$self->answer(); |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub dial { |
|
133
|
0
|
|
|
0
|
1
|
|
my($self, $number, $timeout, $mode) = @_; |
|
134
|
0
|
|
|
|
|
|
my $ok = 0; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Default timeout in seconds |
|
137
|
0
|
|
0
|
|
|
|
$timeout ||= 30; |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# Default is data calls |
|
140
|
0
|
0
|
0
|
|
|
|
if (! defined $mode) { |
|
|
|
0
|
|
|
|
|
|
|
141
|
0
|
|
|
|
|
|
$mode = 'DATA'; |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
# Numbers with ';' mean voice calls |
|
144
|
|
|
|
|
|
|
elsif ($mode =~ m{VOICE}i || $number =~ m{;}) { |
|
145
|
0
|
|
|
|
|
|
$mode = 'VOICE'; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
# Invalid input, or explicit 'DATA' call |
|
148
|
|
|
|
|
|
|
else { |
|
149
|
0
|
|
|
|
|
|
$mode = 'DATA'; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Check if we have already dialed some number... |
|
153
|
0
|
0
|
|
|
|
|
if ($self->flag('CARRIER')) { |
|
154
|
0
|
|
|
|
|
|
$self->log->write( 'warning', 'line is already connected, ignoring dial()' ); |
|
155
|
0
|
|
|
|
|
|
return; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# Check if no number supplied |
|
159
|
0
|
0
|
|
|
|
|
if (! defined $number) { |
|
160
|
|
|
|
|
|
|
# |
|
161
|
|
|
|
|
|
|
# XXX Here we could enable ATDL command (dial last number) |
|
162
|
|
|
|
|
|
|
# |
|
163
|
0
|
|
|
|
|
|
$self->log->write( 'warning', 'cannot dial without a number!' ); |
|
164
|
0
|
|
|
|
|
|
return; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# Remove all non number chars plus some others allowed |
|
168
|
|
|
|
|
|
|
# Thanks to Pierre Hilson for the `#' (UMTS) |
|
169
|
|
|
|
|
|
|
# and to Marek Jaros for the `;' (voice calls) |
|
170
|
0
|
|
|
|
|
|
$number =~ s{[^0-9,\(\)\*\-#;\sp]}{}g; |
|
171
|
|
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
|
my $suffix = ''; |
|
173
|
0
|
0
|
|
|
|
|
if ($mode eq 'VOICE') { |
|
174
|
0
|
|
|
|
|
|
$self->log->write('info', 'trying to make a voice call'); |
|
175
|
0
|
|
|
|
|
|
$suffix = ';'; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Dial number and wait for response |
|
179
|
0
|
0
|
|
|
|
|
if( length $number == 1 ) { |
|
180
|
0
|
|
|
|
|
|
$self->log->write('info', 'dialing address book number ['.$number.']' ); |
|
181
|
|
|
|
|
|
|
|
|
182
|
0
|
|
|
|
|
|
$self->atsend( 'ATDS' . $number . $suffix . CR ); |
|
183
|
|
|
|
|
|
|
} else { |
|
184
|
0
|
|
|
|
|
|
$self->log->write('info', 'dialing number ['.$number.']' ); |
|
185
|
0
|
|
|
|
|
|
$self->atsend( 'ATDT' . $number . $suffix . CR ); |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
# XXX Check response times here (timeout!) |
|
189
|
0
|
|
|
|
|
|
my $ans = $self->answer( qr/[A-Z]/, $timeout * 1000 ); |
|
190
|
|
|
|
|
|
|
|
|
191
|
0
|
0
|
0
|
|
|
|
if( (index($ans,'CONNECT') > -1) || (index($ans,'RING') > -1) ) { |
|
192
|
0
|
|
|
|
|
|
$ok = 1; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# Turn on/off `CARRIER' flag |
|
196
|
0
|
|
|
|
|
|
$self->flag('CARRIER', $ok); |
|
197
|
|
|
|
|
|
|
|
|
198
|
0
|
|
|
|
|
|
$self->log->write('info', 'dialing result = '.$ok); |
|
199
|
0
|
0
|
|
|
|
|
return wantarray ? ($ok, $ans) : $ok; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# Enable/disable local echo of commands (enabling echo can cause everything else to fail, I think) |
|
203
|
|
|
|
|
|
|
sub echo { |
|
204
|
0
|
|
|
0
|
1
|
|
my($self, $lEnable) = @_; |
|
205
|
|
|
|
|
|
|
|
|
206
|
0
|
0
|
|
|
|
|
$self->log->write( 'info', ( $lEnable ? 'enabling' : 'disabling' ) . ' echo' ); |
|
207
|
0
|
0
|
|
|
|
|
$self->atsend( ($lEnable ? 'ATE1' : 'ATE0') . CR ); |
|
208
|
|
|
|
|
|
|
|
|
209
|
0
|
|
|
|
|
|
$self->answer($Device::Modem::STD_RESPONSE); |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# Terminate current call (XXX not tested) |
|
213
|
|
|
|
|
|
|
sub hangup { |
|
214
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
215
|
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
$self->log->write('info', 'hanging up...'); |
|
217
|
0
|
|
|
|
|
|
$self->atsend( 'ATH0' . CR ); |
|
218
|
0
|
|
|
|
|
|
my $ok = $self->answer($Device::Modem::STD_RESPONSE); |
|
219
|
0
|
0
|
|
|
|
|
unless ($ok) { |
|
220
|
0
|
|
|
|
|
|
$self->attention(); |
|
221
|
0
|
|
|
|
|
|
$self->atsend( 'ATH0' . CR ); |
|
222
|
0
|
|
|
|
|
|
$self->answer($Device::Modem::STD_RESPONSE, 5000); |
|
223
|
|
|
|
|
|
|
} |
|
224
|
0
|
|
|
|
|
|
$self->_reset_flags(); |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# Checks if modem is enabled (for now, it works ok for modem OFF/ON case) |
|
228
|
|
|
|
|
|
|
sub is_active { |
|
229
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
230
|
0
|
|
|
|
|
|
my $lOk; |
|
231
|
|
|
|
|
|
|
|
|
232
|
0
|
|
0
|
|
|
|
$self->log->write('info', 'testing modem activity on port ' . ($self->options->{'port'} || '') ); |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# Modem is active if already connected to a line |
|
235
|
0
|
0
|
|
|
|
|
if( $self->flag('CARRIER') ) { |
|
236
|
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
|
$self->log->write('info', 'carrier is '.$self->flag('CARRIER').', modem is connected, it should be active'); |
|
238
|
0
|
|
|
|
|
|
$lOk = 1; |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
} else { |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# XXX Old mode to test modem ... |
|
243
|
|
|
|
|
|
|
# Try sending an echo enable|disable command |
|
244
|
|
|
|
|
|
|
#$self->attention(); |
|
245
|
|
|
|
|
|
|
#$self->verbose(0); |
|
246
|
|
|
|
|
|
|
#$lOk = $self->verbose(1); |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# If DSR signal is on, modem is active |
|
249
|
0
|
|
|
|
|
|
my %sig = $self->status(); |
|
250
|
0
|
|
|
|
|
|
$lOk = $sig{DSR}; |
|
251
|
0
|
|
|
|
|
|
undef %sig; |
|
252
|
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
# If we have no success, try to reset |
|
254
|
0
|
0
|
|
|
|
|
if( ! $lOk ) { |
|
255
|
0
|
|
|
|
|
|
$self->log->write('warning', 'modem not responding... trying to reset'); |
|
256
|
0
|
|
|
|
|
|
$lOk = $self->reset(); |
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
$self->log->write('info', 'modem reset result = '.$lOk); |
|
262
|
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
|
return $lOk; |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# Take modem off hook, prepare to dial |
|
267
|
|
|
|
|
|
|
sub offhook { |
|
268
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
269
|
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
$self->log->write('info', 'taking off hook'); |
|
271
|
0
|
|
|
|
|
|
$self->atsend( 'ATH1' . CR ); |
|
272
|
|
|
|
|
|
|
|
|
273
|
0
|
|
|
|
|
|
$self->flag('OFFHOOK', 1); |
|
274
|
|
|
|
|
|
|
|
|
275
|
0
|
|
|
|
|
|
return 1; |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
# Get/Set S* registers value: S_register( number [, new_value] ) |
|
279
|
|
|
|
|
|
|
# returns undef on failure ( zero is a good value ) |
|
280
|
|
|
|
|
|
|
sub S_register { |
|
281
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
282
|
0
|
|
|
|
|
|
my $register = shift; |
|
283
|
0
|
|
|
|
|
|
my $value = 0; |
|
284
|
|
|
|
|
|
|
|
|
285
|
0
|
0
|
|
|
|
|
return unless $register; |
|
286
|
|
|
|
|
|
|
|
|
287
|
0
|
|
|
|
|
|
my $ok; |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# If `new_value' supplied, we want to update value of this register |
|
290
|
0
|
0
|
|
|
|
|
if( @_ ) { |
|
291
|
|
|
|
|
|
|
|
|
292
|
0
|
|
|
|
|
|
my $new_value = shift; |
|
293
|
0
|
|
|
|
|
|
$new_value =~ s|\D||g; |
|
294
|
0
|
|
|
|
|
|
$self->log->write('info', 'storing value ['.$new_value.'] into register S'.$register); |
|
295
|
0
|
|
|
|
|
|
$self->atsend( sprintf( 'AT S%02d=%d' . CR, $register, $new_value ) ); |
|
296
|
|
|
|
|
|
|
|
|
297
|
0
|
0
|
|
|
|
|
$value = ( index( $self->answer(), 'OK' ) != -1 ) ? $new_value : undef; |
|
298
|
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
} else { |
|
300
|
|
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
|
$self->atsend( sprintf( 'AT S%d?' . CR, $register ) ); |
|
302
|
0
|
|
|
|
|
|
($ok, $value) = $self->parse_answer(); |
|
303
|
|
|
|
|
|
|
|
|
304
|
0
|
0
|
|
|
|
|
if( index($ok, 'OK') != -1 ) { |
|
305
|
0
|
|
|
|
|
|
$self->log->write('info', 'value of S'.$register.' register seems to be ['.$value.']'); |
|
306
|
|
|
|
|
|
|
} else { |
|
307
|
0
|
|
|
|
|
|
$value = undef; |
|
308
|
0
|
|
|
|
|
|
$self->log->write('err', 'error reading value of S'.$register.' register'); |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# Return updated value of register |
|
314
|
0
|
|
|
|
|
|
$self->log->write('info', 'S'.$register.' = '.$value); |
|
315
|
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
|
return $value; |
|
317
|
|
|
|
|
|
|
} |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# Repeat the last commands (this comes gratis with `A/' at-command) |
|
320
|
|
|
|
|
|
|
sub repeat { |
|
321
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
322
|
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
|
$self->log->write('info', 'repeating last command' ); |
|
324
|
0
|
|
|
|
|
|
$self->atsend( 'A/' . CR ); |
|
325
|
|
|
|
|
|
|
|
|
326
|
0
|
|
|
|
|
|
$self->answer(); |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# Complete modem reset |
|
330
|
|
|
|
|
|
|
sub reset { |
|
331
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
332
|
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
$self->log->write('warning', 'resetting modem on '.$self->{'port'} ); |
|
334
|
0
|
|
|
|
|
|
$self->hangup(); |
|
335
|
0
|
|
|
|
|
|
my $result = $self->send_init_string(); |
|
336
|
0
|
|
|
|
|
|
$self->_reset_flags(); |
|
337
|
0
|
|
|
|
|
|
return $result; |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# Return an hash with the status of main modem signals |
|
341
|
|
|
|
|
|
|
sub status { |
|
342
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
343
|
0
|
|
|
|
|
|
$self->log->write('info', 'getting modem line status on '.$self->{'port'}); |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
# This also relies on Device::SerialPort |
|
346
|
0
|
|
|
|
|
|
my $status = $self->port->modemlines(); |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# See top of module for these constants, exported by (Win32|Device)::SerialPort |
|
349
|
0
|
|
|
|
|
|
my %signal = ( |
|
350
|
|
|
|
|
|
|
CTS => $status & Device::Modem::MS_CTS_ON, |
|
351
|
|
|
|
|
|
|
DSR => $status & Device::Modem::MS_DSR_ON, |
|
352
|
|
|
|
|
|
|
RING => $status & Device::Modem::MS_RING_ON, |
|
353
|
|
|
|
|
|
|
RLSD => $status & Device::Modem::MS_RLSD_ON |
|
354
|
|
|
|
|
|
|
); |
|
355
|
|
|
|
|
|
|
|
|
356
|
0
|
|
|
|
|
|
$self->log->write('info', 'modem on '.$self->{'port'}.' status is ['.$status.']'); |
|
357
|
0
|
|
|
|
|
|
$self->log->write('info', "CTS=$signal{CTS} DSR=$signal{DSR} RING=$signal{RING} RLSD=$signal{RLSD}"); |
|
358
|
|
|
|
|
|
|
|
|
359
|
0
|
|
|
|
|
|
return %signal; |
|
360
|
|
|
|
|
|
|
} |
|
361
|
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
# Of little use here, but nice to have it |
|
363
|
|
|
|
|
|
|
# restore_factory_settings( profile ) |
|
364
|
|
|
|
|
|
|
# profile can be 0 or 1 |
|
365
|
|
|
|
|
|
|
sub restore_factory_settings { |
|
366
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
367
|
0
|
|
|
|
|
|
my $profile = shift; |
|
368
|
0
|
0
|
|
|
|
|
$profile = 0 unless defined $profile; |
|
369
|
|
|
|
|
|
|
|
|
370
|
0
|
|
|
|
|
|
$self->log->write('warning', 'restoring factory settings '.$profile.' on '.$self->{'port'} ); |
|
371
|
0
|
|
|
|
|
|
$self->atsend( 'AT&F'.$profile . CR); |
|
372
|
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
|
$self->answer($Device::Modem::STD_RESPONSE); |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# Store telephone number in modem's internal address book, to dial later |
|
377
|
|
|
|
|
|
|
# store_number( position, number ) |
|
378
|
|
|
|
|
|
|
sub store_number { |
|
379
|
0
|
|
|
0
|
1
|
|
my( $self, $position, $number ) = @_; |
|
380
|
0
|
|
|
|
|
|
my $ok = 0; |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# Check parameters |
|
383
|
0
|
0
|
0
|
|
|
|
unless( defined($position) && $number ) { |
|
384
|
0
|
|
|
|
|
|
$self->log->write('warning', 'store_number() called with wrong parameters'); |
|
385
|
0
|
|
|
|
|
|
return $ok; |
|
386
|
|
|
|
|
|
|
} |
|
387
|
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
|
$self->log->write('info', 'storing number ['.$number.'] into memory ['.$position.']'); |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# Remove all non-numerical chars from position and number |
|
391
|
0
|
|
|
|
|
|
$position =~ s/\D//g; |
|
392
|
0
|
|
|
|
|
|
$number =~ s/[^0-9,]//g; |
|
393
|
|
|
|
|
|
|
|
|
394
|
0
|
|
|
|
|
|
$self->atsend( sprintf( 'AT &Z%d=%s' . CR, $position, $number ) ); |
|
395
|
|
|
|
|
|
|
|
|
396
|
0
|
0
|
|
|
|
|
if( index( $self->answer(), 'OK' ) != -1 ) { |
|
397
|
0
|
|
|
|
|
|
$self->log->write('info', 'stored number ['.$number.'] into memory ['.$position.']'); |
|
398
|
0
|
|
|
|
|
|
$ok = 1; |
|
399
|
|
|
|
|
|
|
} else { |
|
400
|
0
|
|
|
|
|
|
$self->log->write('warning', 'error storing number ['.$number.'] into memory ['.$position.']'); |
|
401
|
0
|
|
|
|
|
|
$ok = 0; |
|
402
|
|
|
|
|
|
|
} |
|
403
|
|
|
|
|
|
|
|
|
404
|
0
|
|
|
|
|
|
return $ok; |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Enable/disable verbose response messages against numerical response messages |
|
408
|
|
|
|
|
|
|
# XXX I need to manage also numerical values... |
|
409
|
|
|
|
|
|
|
sub verbose { |
|
410
|
0
|
|
|
0
|
1
|
|
my($self, $lEnable) = @_; |
|
411
|
|
|
|
|
|
|
|
|
412
|
0
|
0
|
|
|
|
|
$self->log->write( 'info', ( $lEnable ? 'enabling' : 'disabling' ) . ' verbose messages' ); |
|
413
|
0
|
0
|
|
|
|
|
$self->atsend( ($lEnable ? 'ATQ0V1' : 'ATQ0V0') . CR ); |
|
414
|
|
|
|
|
|
|
|
|
415
|
0
|
|
|
|
|
|
$self->answer($Device::Modem::STD_RESPONSE); |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
sub wait { |
|
419
|
0
|
|
|
0
|
1
|
|
my( $self, $msec ) = @_; |
|
420
|
|
|
|
|
|
|
|
|
421
|
0
|
|
|
|
|
|
$self->log->write('debug', 'waiting for '.$msec.' msecs'); |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
# Perhaps Time::HiRes here is not so useful, since I tested `select()' system call also on Windows |
|
424
|
0
|
|
|
|
|
|
select( undef, undef, undef, $msec / 1000 ); |
|
425
|
0
|
|
|
|
|
|
return 1; |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# Set a named flag. Flags are now: OFFHOOK, CARRIER |
|
430
|
|
|
|
|
|
|
sub flag { |
|
431
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
432
|
0
|
|
|
|
|
|
my $cFlag = uc shift; |
|
433
|
|
|
|
|
|
|
|
|
434
|
0
|
0
|
|
|
|
|
$self->{'_flags'}->{$cFlag} = shift() if @_; |
|
435
|
|
|
|
|
|
|
|
|
436
|
0
|
|
|
|
|
|
$self->{'_flags'}->{$cFlag}; |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
# reset internal flags that tell the status of modem (XXX to be extended) |
|
440
|
|
|
|
|
|
|
sub _reset_flags { |
|
441
|
0
|
|
|
0
|
|
|
my $self = shift(); |
|
442
|
|
|
|
|
|
|
|
|
443
|
0
|
|
|
|
|
|
map { $self->flag($_, 0) } |
|
|
0
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
'OFFHOOK', 'CARRIER'; |
|
445
|
|
|
|
|
|
|
} |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# initialize modem with some basic commands (XXX &C0) |
|
448
|
|
|
|
|
|
|
# send_init_string( [my_init_string] ) |
|
449
|
|
|
|
|
|
|
# my_init_string goes without 'AT' prefix |
|
450
|
|
|
|
|
|
|
sub send_init_string { |
|
451
|
0
|
|
|
0
|
1
|
|
my($self, $cInit) = @_; |
|
452
|
0
|
0
|
|
|
|
|
$cInit = $self->options->{'init_string'} unless defined $cInit; |
|
453
|
|
|
|
|
|
|
# If no Init string then do nothing! |
|
454
|
0
|
0
|
|
|
|
|
if ($cInit) { |
|
455
|
0
|
|
|
|
|
|
$self->attention(); |
|
456
|
0
|
|
|
|
|
|
$self->atsend('AT '.$cInit. CR ); |
|
457
|
0
|
|
|
|
|
|
return $self->answer($Device::Modem::STD_RESPONSE); |
|
458
|
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
} |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# returns log object reference or nothing if it is not defined |
|
462
|
|
|
|
|
|
|
sub log { |
|
463
|
0
|
|
|
0
|
1
|
|
my $me = shift; |
|
464
|
0
|
0
|
|
|
|
|
if( ref $me->{'_log'} ) { |
|
465
|
0
|
|
|
|
|
|
return $me->{'_log'}; |
|
466
|
|
|
|
|
|
|
} else { |
|
467
|
0
|
|
|
|
|
|
return {}; |
|
468
|
|
|
|
|
|
|
} |
|
469
|
|
|
|
|
|
|
} |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# instances (Device|Win32)::SerialPort object and initializes communications |
|
472
|
|
|
|
|
|
|
sub connect { |
|
473
|
0
|
|
|
0
|
1
|
|
my $me = shift(); |
|
474
|
|
|
|
|
|
|
|
|
475
|
0
|
|
|
|
|
|
my %aOpt = (); |
|
476
|
0
|
0
|
|
|
|
|
if( @_ ) { |
|
477
|
0
|
|
|
|
|
|
%aOpt = @_; |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
0
|
|
|
|
|
|
my $lOk = 0; |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# Set default values if missing |
|
483
|
0
|
|
0
|
|
|
|
$aOpt{'baudrate'} ||= $Device::Modem::BAUDRATE; |
|
484
|
0
|
|
0
|
|
|
|
$aOpt{'databits'} ||= $Device::Modem::DATABITS; |
|
485
|
0
|
|
0
|
|
|
|
$aOpt{'parity'} ||= $Device::Modem::PARITY; |
|
486
|
0
|
|
0
|
|
|
|
$aOpt{'stopbits'} ||= $Device::Modem::STOPBITS; |
|
487
|
0
|
|
0
|
|
|
|
$aOpt{'handshake'}||= $Device::Modem::HANDSHAKE; |
|
488
|
0
|
|
0
|
|
|
|
$aOpt{'max_reset_iter'} ||= 0; |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
# Store communication options in object |
|
491
|
0
|
|
|
|
|
|
$me->{'_comm_options'} = \%aOpt; |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# Connect on serial (use different mod for win32) |
|
494
|
0
|
0
|
|
|
|
|
if( $me->ostype eq 'windoze' ) { |
|
495
|
0
|
|
|
|
|
|
$me->port( new Win32::SerialPort($me->{'port'}) ); |
|
496
|
|
|
|
|
|
|
} else { |
|
497
|
0
|
|
|
|
|
|
$me->port( new Device::SerialPort($me->{'port'}) ); |
|
498
|
|
|
|
|
|
|
} |
|
499
|
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
# Check connection |
|
501
|
0
|
0
|
|
|
|
|
unless( ref $me->port ) { |
|
502
|
0
|
|
|
|
|
|
$me->log->write( 'err', '*FAILED* connect on '.$me->{'port'} ); |
|
503
|
0
|
|
|
|
|
|
return $lOk; |
|
504
|
|
|
|
|
|
|
} |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
# Set communication options |
|
507
|
0
|
|
|
|
|
|
my $oPort = $me->port; |
|
508
|
0
|
|
|
|
|
|
$oPort -> baudrate ( $me->options->{'baudrate'} ); |
|
509
|
0
|
|
|
|
|
|
$oPort -> databits ( $me->options->{'databits'} ); |
|
510
|
0
|
|
|
|
|
|
$oPort -> stopbits ( $me->options->{'stopbits'} ); |
|
511
|
0
|
|
|
|
|
|
$oPort -> parity ( $me->options->{'parity'} ); |
|
512
|
0
|
|
|
|
|
|
$oPort -> handshake( $me->options->{'handshake'} ); |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
# Non configurable options |
|
515
|
0
|
|
|
|
|
|
$oPort -> buffers ( 10000, 10000 ); |
|
516
|
0
|
|
|
|
|
|
$oPort -> read_const_time ( 20 ); # was 500 |
|
517
|
0
|
|
|
|
|
|
$oPort -> read_char_time ( 0 ); |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
# read_interval() seems to be unsupported on Device::SerialPort, |
|
520
|
|
|
|
|
|
|
# while allowed on Win32::SerialPort... |
|
521
|
0
|
0
|
|
|
|
|
if( $oPort->can('read_interval') ) |
|
522
|
|
|
|
|
|
|
{ |
|
523
|
0
|
|
|
|
|
|
$oPort->read_interval( 20 ); |
|
524
|
|
|
|
|
|
|
} |
|
525
|
|
|
|
|
|
|
|
|
526
|
0
|
|
|
|
|
|
$oPort -> are_match ( 'OK' ); |
|
527
|
0
|
|
|
|
|
|
$oPort -> lookclear; |
|
528
|
|
|
|
|
|
|
|
|
529
|
0
|
0
|
|
|
|
|
unless ( $oPort -> write_settings ) { |
|
530
|
0
|
|
|
|
|
|
$me->log->write('err', '*FAILED* write_settings on '.$me->{'port'} ); |
|
531
|
0
|
|
|
|
|
|
return $lOk; |
|
532
|
|
|
|
|
|
|
} |
|
533
|
0
|
|
|
|
|
|
$oPort -> purge_all; |
|
534
|
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# Get the modems attention |
|
536
|
|
|
|
|
|
|
# Send multiple reset commands looking for a sensible response. |
|
537
|
|
|
|
|
|
|
# A small number of modems need time to settle down and start responding to the serial port |
|
538
|
0
|
|
|
|
|
|
my $iter = 0; |
|
539
|
0
|
|
|
|
|
|
my $ok = 0; |
|
540
|
0
|
|
|
|
|
|
my $blank = 0; |
|
541
|
0
|
|
0
|
|
|
|
while ( ($iter < $aOpt{'max_reset_iter'}) && ($ok < 2) && ($blank < 3) ) { |
|
|
|
|
0
|
|
|
|
|
|
542
|
0
|
|
|
|
|
|
$me->atsend('AT E0'. CR ); |
|
543
|
0
|
|
|
|
|
|
my $rslt = $me->answer($Device::Modem::STD_RESPONSE, 1500); |
|
544
|
|
|
|
|
|
|
# print "Res: $rslt \r\n"; |
|
545
|
0
|
|
|
|
|
|
$iter+=1; |
|
546
|
0
|
0
|
0
|
|
|
|
if ($rslt && $rslt =~ /^OK/) { |
|
547
|
0
|
|
|
|
|
|
$ok+=1; |
|
548
|
|
|
|
|
|
|
} else { |
|
549
|
0
|
|
|
|
|
|
$ok=0; |
|
550
|
|
|
|
|
|
|
} |
|
551
|
0
|
0
|
|
|
|
|
if (!$rslt) { |
|
552
|
0
|
|
|
|
|
|
$blank++; |
|
553
|
|
|
|
|
|
|
} else { |
|
554
|
0
|
|
|
|
|
|
$blank=0; |
|
555
|
|
|
|
|
|
|
} |
|
556
|
|
|
|
|
|
|
} |
|
557
|
0
|
0
|
|
|
|
|
if ($aOpt{'max_reset_iter'}) { |
|
558
|
0
|
|
|
|
|
|
$me->log->write('debug', "DEBUG CONNECT: $iter : $ok : $blank\n"); # DEBUG |
|
559
|
|
|
|
|
|
|
} |
|
560
|
0
|
|
|
|
|
|
$me-> log -> write('info', 'sending init string...' ); |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# Set default initialization string if none supplied |
|
563
|
0
|
0
|
|
|
|
|
my $init_string = defined $me->options->{'init_string'} |
|
564
|
|
|
|
|
|
|
? $me->options->{'init_string'} |
|
565
|
|
|
|
|
|
|
: $Device::Modem::DEFAULT_INIT_STRING; |
|
566
|
|
|
|
|
|
|
|
|
567
|
0
|
|
0
|
|
|
|
my $init_response = $me->send_init_string($init_string) || ''; |
|
568
|
0
|
|
|
|
|
|
$me-> log -> write('debug', "init response: $init_response\n"); # DEBUG |
|
569
|
0
|
|
|
|
|
|
$me-> _reset_flags(); |
|
570
|
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
# Disable local echo |
|
572
|
0
|
|
|
|
|
|
$me-> echo(0); |
|
573
|
|
|
|
|
|
|
|
|
574
|
0
|
|
|
|
|
|
$me-> log -> write('info', 'Ok connected' ); |
|
575
|
0
|
|
|
|
|
|
$me-> {'CONNECTED'} = 1; |
|
576
|
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
} |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# $^O is stored into object |
|
580
|
|
|
|
|
|
|
sub ostype { |
|
581
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
582
|
0
|
|
|
|
|
|
$self->{'ostype'}; |
|
583
|
|
|
|
|
|
|
} |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
# returns Device::SerialPort reference to hash options |
|
586
|
|
|
|
|
|
|
sub options { |
|
587
|
0
|
|
|
0
|
0
|
|
my $self = shift(); |
|
588
|
0
|
0
|
|
|
|
|
@_ ? $self->{'_comm_options'} = shift() |
|
589
|
|
|
|
|
|
|
: $self->{'_comm_options'}; |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
# returns Device::SerialPort object handle |
|
593
|
|
|
|
|
|
|
sub port { |
|
594
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
595
|
|
|
|
|
|
|
|
|
596
|
0
|
0
|
|
|
|
|
if (@_) { |
|
597
|
0
|
|
|
|
|
|
return ($self->{'_comm_object'} = shift); |
|
598
|
|
|
|
|
|
|
} |
|
599
|
|
|
|
|
|
|
|
|
600
|
0
|
|
|
|
|
|
my $port_obj = $self->{'_comm_object'}; |
|
601
|
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
# Maybe the port was disconnected? |
|
603
|
0
|
0
|
0
|
|
|
|
if (defined $self->{'CONNECTED'} && |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
604
|
|
|
|
|
|
|
$self->{'CONNECTED'} == 1 && # We were connected |
|
605
|
|
|
|
|
|
|
(! defined $port_obj || ! $port_obj)) { # Now we aren't anymore |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
# Avoid recursion on ourselves |
|
608
|
0
|
|
|
|
|
|
$self->{'CONNECTED'} = 0; |
|
609
|
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
# Try to reconnect if possible |
|
611
|
0
|
|
|
|
|
|
my $connect_options = $self->options; |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
# No connect options probably because we didn't ever connect |
|
614
|
0
|
0
|
|
|
|
|
if (! $connect_options) { |
|
615
|
0
|
|
|
|
|
|
Carp::croak("Not connected"); |
|
616
|
|
|
|
|
|
|
} |
|
617
|
|
|
|
|
|
|
|
|
618
|
0
|
|
|
|
|
|
$self->connect(%{ $connect_options }); |
|
|
0
|
|
|
|
|
|
|
|
619
|
0
|
|
|
|
|
|
$port_obj = $self->{'_comm_object'}; |
|
620
|
|
|
|
|
|
|
} |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
# Still not connected? bail out |
|
623
|
0
|
0
|
0
|
|
|
|
if (! defined $port_obj || ! $port_obj) { |
|
624
|
0
|
|
|
|
|
|
Carp::croak("Not connected"); |
|
625
|
|
|
|
|
|
|
} |
|
626
|
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
return $port_obj; |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
# disconnect serial port |
|
631
|
|
|
|
|
|
|
sub disconnect { |
|
632
|
0
|
|
|
0
|
1
|
|
my $me = shift; |
|
633
|
0
|
|
|
|
|
|
$me->port->close(); |
|
634
|
0
|
|
|
|
|
|
$me->log->write('info', 'Disconnected from '.$me->{'port'} ); |
|
635
|
|
|
|
|
|
|
} |
|
636
|
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
# Send AT command to device on serial port (command must include CR for now) |
|
638
|
|
|
|
|
|
|
sub atsend { |
|
639
|
0
|
|
|
0
|
1
|
|
my( $me, $msg ) = @_; |
|
640
|
0
|
|
|
|
|
|
my $cnt = 0; |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
# Write message on port |
|
643
|
0
|
|
|
|
|
|
$me->port->purge_all(); |
|
644
|
0
|
|
|
|
|
|
$cnt = $me->port->write($msg); |
|
645
|
|
|
|
|
|
|
|
|
646
|
0
|
|
|
|
|
|
my $lbuf=length($msg); |
|
647
|
0
|
|
|
|
|
|
my $ret; |
|
648
|
|
|
|
|
|
|
|
|
649
|
0
|
|
|
|
|
|
while ($cnt < $lbuf) |
|
650
|
|
|
|
|
|
|
{ |
|
651
|
0
|
|
|
|
|
|
$ret = $me->port->write(substr($msg, $cnt)); |
|
652
|
0
|
|
|
|
|
|
$me->write_drain(); |
|
653
|
0
|
0
|
|
|
|
|
last unless defined $ret; |
|
654
|
0
|
|
|
|
|
|
$cnt += $ret; |
|
655
|
|
|
|
|
|
|
} |
|
656
|
|
|
|
|
|
|
|
|
657
|
0
|
|
|
|
|
|
$me->log->write('debug', 'atsend: wrote '.$cnt.'/'.length($msg).' chars'); |
|
658
|
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
# If wrote all chars of `msg', we are successful |
|
660
|
0
|
|
|
|
|
|
return $cnt == length $msg; |
|
661
|
|
|
|
|
|
|
} |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
# Call write_drain() if platform allows to (no call for Win32) |
|
664
|
|
|
|
|
|
|
sub write_drain |
|
665
|
|
|
|
|
|
|
{ |
|
666
|
0
|
|
|
0
|
1
|
|
my $me = shift; |
|
667
|
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
# No write_drain() call for win32 systems |
|
669
|
0
|
0
|
|
|
|
|
return if $me->ostype eq 'windoze'; |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
# No write_drain() if no port object available |
|
672
|
0
|
|
|
|
|
|
my $port = $me->port; |
|
673
|
0
|
0
|
|
|
|
|
return unless $port; |
|
674
|
|
|
|
|
|
|
|
|
675
|
0
|
|
|
|
|
|
return $port->write_drain(); |
|
676
|
|
|
|
|
|
|
} |
|
677
|
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
# answer() takes strings from the device until a pattern |
|
679
|
|
|
|
|
|
|
# is encountered or a timeout happens. |
|
680
|
|
|
|
|
|
|
sub _answer { |
|
681
|
0
|
|
|
0
|
|
|
my $me = shift; |
|
682
|
0
|
|
|
|
|
|
my($expect, $timeout) = @_; |
|
683
|
0
|
0
|
|
|
|
|
$expect = $Device::Modem::STD_RESPONSE if (! defined($expect)); |
|
684
|
0
|
0
|
|
|
|
|
$timeout = $Device::Modem::TIMEOUT if (! defined($timeout)); |
|
685
|
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
# If we expect something, we must first match against serial input |
|
687
|
0
|
|
0
|
|
|
|
my $done = (defined $expect and $expect ne ''); |
|
688
|
|
|
|
|
|
|
|
|
689
|
0
|
0
|
0
|
|
|
|
$me->log->write('debug', 'answer: expecting ['.($expect||'').']'.($timeout ? ' or '.($timeout/1000).' seconds timeout' : '' ) ); |
|
690
|
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
# Main read cycle |
|
692
|
0
|
|
|
|
|
|
my $cycles = 0; |
|
693
|
0
|
|
|
|
|
|
my $idle_cycles = 0; |
|
694
|
0
|
|
|
|
|
|
my $answer; |
|
695
|
0
|
|
|
|
|
|
my $start_time = time(); |
|
696
|
0
|
|
|
|
|
|
my $end_time = 0; |
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
# If timeout was defined, check max time (timeout is in milliseconds) |
|
699
|
0
|
|
0
|
|
|
|
$me->log->write('debug', 'answer: timeout value is '.($timeout||'undef')); |
|
700
|
|
|
|
|
|
|
|
|
701
|
0
|
0
|
0
|
|
|
|
if( defined $timeout && $timeout > 0 ) { |
|
702
|
0
|
|
|
|
|
|
$end_time = $start_time + ($timeout / 1000); |
|
703
|
0
|
0
|
|
|
|
|
$end_time++ if $end_time == $start_time; |
|
704
|
0
|
|
|
|
|
|
$me->log->write( debug => 'answer: end time set to '.$end_time ); |
|
705
|
|
|
|
|
|
|
} |
|
706
|
|
|
|
|
|
|
|
|
707
|
0
|
|
|
|
|
|
do { |
|
708
|
0
|
|
|
|
|
|
my ($what, $howmany); |
|
709
|
0
|
|
|
|
|
|
$what = $me->port->read(1) . $me->port->input; |
|
710
|
0
|
|
|
|
|
|
$howmany = length($what); |
|
711
|
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
# Timeout count incremented only on empty readings |
|
713
|
0
|
0
|
0
|
|
|
|
if( defined $what && $howmany > 0 ) { |
|
|
|
0
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
# Add received chars to answer string |
|
716
|
0
|
|
|
|
|
|
$answer .= $what; |
|
717
|
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
# Check if buffer matches "expect string" |
|
719
|
0
|
0
|
|
|
|
|
if( defined $expect ) { |
|
720
|
0
|
|
|
|
|
|
my $copy = $answer; |
|
721
|
0
|
|
|
|
|
|
$copy =~ s/\r(\n)?/\n/g; # Convert line endings from "\r" or "\r\n" to "\n" |
|
722
|
0
|
0
|
0
|
|
|
|
$done = ( defined $copy && $copy =~ $expect ) ? 1 : 0; |
|
723
|
0
|
0
|
|
|
|
|
$me->log->write( debug => 'answer: matched expect: '.$expect ) if ($done); |
|
724
|
|
|
|
|
|
|
} |
|
725
|
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
# Check if we reached max time for timeout (only if end_time is defined) |
|
727
|
|
|
|
|
|
|
} elsif( $end_time > 0 ) { |
|
728
|
|
|
|
|
|
|
|
|
729
|
0
|
0
|
|
|
|
|
$done = (time >= $end_time) ? 1 : 0; |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
# Read last chars in read queue |
|
732
|
0
|
0
|
|
|
|
|
if( $done ) |
|
733
|
|
|
|
|
|
|
{ |
|
734
|
0
|
|
|
|
|
|
$me->log->write('info', 'reached timeout max wait without response'); |
|
735
|
|
|
|
|
|
|
} |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
# Else we have done |
|
738
|
|
|
|
|
|
|
} else { |
|
739
|
|
|
|
|
|
|
|
|
740
|
0
|
|
|
|
|
|
$done = 1; |
|
741
|
|
|
|
|
|
|
} |
|
742
|
|
|
|
|
|
|
|
|
743
|
0
|
|
|
|
|
|
$me->log->write('debug', 'done='.$done.' end='.$end_time.' now='.time().' start='.$start_time ); |
|
744
|
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
} while (not $done); |
|
746
|
|
|
|
|
|
|
|
|
747
|
0
|
|
0
|
|
|
|
$me->log->write('info', 'answer: read ['.($answer||'').']' ); |
|
748
|
|
|
|
|
|
|
|
|
749
|
|
|
|
|
|
|
# Flush receive and trasmit buffers |
|
750
|
0
|
|
|
|
|
|
$me->port->purge_all; |
|
751
|
|
|
|
|
|
|
|
|
752
|
0
|
|
|
|
|
|
return $answer; |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
} |
|
755
|
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
sub answer { |
|
757
|
|
|
|
|
|
|
|
|
758
|
0
|
|
|
0
|
1
|
|
my $me = shift(); |
|
759
|
0
|
|
|
|
|
|
my $answer = $me->_answer(@_); |
|
760
|
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
# Trim result of beginning and ending CR+LF (XXX) |
|
762
|
0
|
0
|
|
|
|
|
if( defined $answer ) { |
|
763
|
0
|
|
|
|
|
|
$answer =~ s/^[\r\n]+//; |
|
764
|
0
|
|
|
|
|
|
$answer =~ s/[\r\n]+$//; |
|
765
|
|
|
|
|
|
|
} |
|
766
|
|
|
|
|
|
|
|
|
767
|
0
|
|
0
|
|
|
|
$me->log->write('info', 'answer: `'.($answer||'').'\'' ); |
|
768
|
|
|
|
|
|
|
|
|
769
|
0
|
|
|
|
|
|
return $answer; |
|
770
|
|
|
|
|
|
|
} |
|
771
|
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
# parse_answer() cleans out answer() result as response code + |
|
773
|
|
|
|
|
|
|
# useful information (useful in informative commands, for example |
|
774
|
|
|
|
|
|
|
# Gsm command AT+CGMI) |
|
775
|
|
|
|
|
|
|
sub parse_answer { |
|
776
|
0
|
|
|
0
|
1
|
|
my $me = shift; |
|
777
|
|
|
|
|
|
|
|
|
778
|
0
|
|
|
|
|
|
my $buff = $me->answer( @_ ); |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# Separate response code from information |
|
781
|
0
|
0
|
0
|
|
|
|
if( defined $buff && $buff ne '' ) { |
|
782
|
|
|
|
|
|
|
|
|
783
|
0
|
|
|
|
|
|
my @buff = split /[\r\n]+/o, $buff; |
|
784
|
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
# Remove all empty lines before/after response |
|
786
|
0
|
|
|
|
|
|
shift @buff while $buff[0] =~ /^[\r\n]+/o; |
|
787
|
0
|
|
|
|
|
|
pop @buff while $buff[-1] =~ /^[\r\n]+/o; |
|
788
|
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
# Extract responde code |
|
790
|
0
|
|
|
|
|
|
$buff = join( CR, @buff ); |
|
791
|
0
|
|
|
|
|
|
my $code = pop @buff; |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
return |
|
794
|
|
|
|
|
|
|
wantarray |
|
795
|
0
|
0
|
|
|
|
|
? ($code, @buff) |
|
796
|
|
|
|
|
|
|
: $buff; |
|
797
|
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
} else { |
|
799
|
|
|
|
|
|
|
|
|
800
|
0
|
|
|
|
|
|
return ''; |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
} |
|
803
|
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
} |
|
805
|
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
1; |
|
807
|
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
=head1 NAME |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
Device::Modem - Perl extension to talk to modem devices connected via serial port |
|
811
|
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=head1 WARNING |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
This is B software, so use it at your own risk, |
|
815
|
|
|
|
|
|
|
and without B warranty! Have fun. |
|
816
|
|
|
|
|
|
|
|
|
817
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
use Device::Modem; |
|
820
|
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
my $modem = new Device::Modem( port => '/dev/ttyS1' ); |
|
822
|
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
if( $modem->connect( baudrate => 9600 ) ) { |
|
824
|
|
|
|
|
|
|
print "connected!\n"; |
|
825
|
|
|
|
|
|
|
} else { |
|
826
|
|
|
|
|
|
|
print "sorry, no connection with serial port!\n"; |
|
827
|
|
|
|
|
|
|
} |
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
$modem->attention(); # send `attention' sequence (+++) |
|
830
|
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
($ok, $answer) = $modem->dial('02270469012'); # dial phone number |
|
832
|
|
|
|
|
|
|
$ok = $modem->dial(3); # 1-digit parameter = dial number stored in memory 3 |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
$modem->echo(1); # enable local echo (0 to disable) |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
$modem->offhook(); # Take off hook (ready to dial) |
|
837
|
|
|
|
|
|
|
$modem->hangup(); # returns modem answer |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
$modem->is_active(); # Tests whether modem device is active or not |
|
840
|
|
|
|
|
|
|
# So far it works for modem OFF/ modem ON condition |
|
841
|
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
$modem->reset(); # hangup + attention + restore setting 0 (Z0) |
|
843
|
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
$modem->restore_factory_settings(); # Handle with care! |
|
845
|
|
|
|
|
|
|
$modem->restore_factory_settings(1); # Same with preset profile 1 (can be 0 or 1) |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
$modem->send_init_string(); # Send initialization string |
|
848
|
|
|
|
|
|
|
# Now this is fixed to 'AT H0 Z S7=45 S0=0 Q0 V1 E0 &C0 X4' |
|
849
|
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
# Get/Set value of S1 register |
|
851
|
|
|
|
|
|
|
my $S1 = $modem->S_register(1); |
|
852
|
|
|
|
|
|
|
my $S1 = $modem->S_register(1, 55); # Don't do that if you definitely don't know! |
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
# Get status of managed signals (CTS, DSR, RLSD, RING) |
|
855
|
|
|
|
|
|
|
my %signal = $modem->status(); |
|
856
|
|
|
|
|
|
|
if( $signal{DSR} ) { print "Data Set Ready signal active!\n"; } |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
# Stores this number in modem memory number 3 |
|
859
|
|
|
|
|
|
|
$modem->store_number(3, '01005552817'); |
|
860
|
|
|
|
|
|
|
|
|
861
|
|
|
|
|
|
|
$modem->repeat(); # Repeat last command |
|
862
|
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
$modem->verbose(1); # Normal text responses (0=numeric codes) |
|
864
|
|
|
|
|
|
|
|
|
865
|
|
|
|
|
|
|
# Some raw AT commands |
|
866
|
|
|
|
|
|
|
$modem->atsend( 'ATH0' ); |
|
867
|
|
|
|
|
|
|
print $modem->answer(); |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
$modem->atsend( 'ATDT01234567' . Device::Modem::CR ); |
|
870
|
|
|
|
|
|
|
print $modem->answer(); |
|
871
|
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
|
|
873
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
874
|
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
C class implements basic B device abstraction. |
|
876
|
|
|
|
|
|
|
It can be inherited by sub classes (as C), which are based on serial connections. |
|
877
|
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
|
|
879
|
|
|
|
|
|
|
=head2 Things C can do |
|
880
|
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
=over 4 |
|
882
|
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
=item * |
|
884
|
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
connect to a modem on your serial port |
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
=item * |
|
888
|
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
test if the modem is alive and working |
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
=item * |
|
892
|
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
dial a number and connect to a remote modem |
|
894
|
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
=item * |
|
896
|
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
work with registers and settings of the modem |
|
898
|
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
=item * |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
issue standard or arbitrary C commands, getting results from modem |
|
902
|
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
=back |
|
904
|
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
=head2 Things C can't do yet |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
=over 4 |
|
908
|
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
=item * |
|
910
|
|
|
|
|
|
|
|
|
911
|
|
|
|
|
|
|
Transfer a file to a remote modem |
|
912
|
|
|
|
|
|
|
|
|
913
|
|
|
|
|
|
|
=item * |
|
914
|
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
Control a terminal-like (or a PPP) connection. This should really not |
|
916
|
|
|
|
|
|
|
be very hard to do anyway. |
|
917
|
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
=item * |
|
919
|
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
Many others... |
|
921
|
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
=back |
|
923
|
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
=head2 Things it will never be able to do |
|
925
|
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
=over 4 |
|
927
|
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
=item * |
|
929
|
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
Coffee :-) |
|
931
|
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
=back |
|
933
|
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
=head2 Examples |
|
936
|
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
In the `examples' directory, there are some scripts that should work without big problems, |
|
938
|
|
|
|
|
|
|
that you can take as (yea) examples: |
|
939
|
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
=over 4 |
|
941
|
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
=item `examples/active.pl' |
|
943
|
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
Tests if modem is alive |
|
945
|
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
=item `examples/caller-id.pl' |
|
947
|
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
Waits for an incoming call and displays date, time and phone number of the caller. |
|
949
|
|
|
|
|
|
|
Normally this is available everywhere, but you should check your local phone line |
|
950
|
|
|
|
|
|
|
and settings. |
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
=item `examples/dial.pl' |
|
953
|
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
Dials a phone number and display result of call |
|
955
|
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
=item `examples/shell.pl' |
|
957
|
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
(Very) poor man's minicom/hyperterminal utility |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
=item `examples/xmodem.pl' |
|
961
|
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
First attempt at a test script to receive a file via xmodem protocol. |
|
963
|
|
|
|
|
|
|
Please be warned that this thing does not have a chance to work. It's |
|
964
|
|
|
|
|
|
|
only a (very low priority) work in progress... |
|
965
|
|
|
|
|
|
|
|
|
966
|
|
|
|
|
|
|
If you want to help out, be welcome! |
|
967
|
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
=back |
|
970
|
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
=head1 METHODS |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
=head2 answer() |
|
974
|
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
One of the most used methods, waits for an answer from the device. It waits until |
|
976
|
|
|
|
|
|
|
$timeout (seconds) is reached (but don't rely on this time to be very correct) or until an |
|
977
|
|
|
|
|
|
|
expected string is encountered. Example: |
|
978
|
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
$answer = $modem->answer( [$expect [, $timeout]] ) |
|
980
|
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
Returns C<$answer> that is the string received from modem stripped of all |
|
982
|
|
|
|
|
|
|
B and B chars B at the beginning and at the end of the |
|
983
|
|
|
|
|
|
|
string. No in-between B are stripped. |
|
984
|
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
Note that if you need the raw answer from the modem, you can use the _answer() (note |
|
986
|
|
|
|
|
|
|
that underscore char before answer) method, which does not strip anything from the response, |
|
987
|
|
|
|
|
|
|
so you get the real modem answer string. |
|
988
|
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
Parameters: |
|
990
|
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
=over 4 |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
=item * |
|
994
|
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
C<$expect> - Can be a regexp compiled with C or a simple substring. Input coming from the |
|
996
|
|
|
|
|
|
|
modem is matched against this parameter. If input matches, result is returned. |
|
997
|
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
=item * |
|
999
|
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
C<$timeout> - Expressed in milliseconds. After that time, answer returns result also if nothing |
|
1001
|
|
|
|
|
|
|
has been received. Example: C<10000>. Default: C<$Device::Modem::TIMEOUT>, currently 500 ms. |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
=back |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
=head2 atsend() |
|
1008
|
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
Sends a raw C command to the device connected. Note that this method is most used |
|
1010
|
|
|
|
|
|
|
internally, but can be also used to send your own custom commands. Example: |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
$ok = $modem->atsend( $msg ) |
|
1013
|
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
The only parameter is C<$msg>, that is the raw AT command to be sent to |
|
1015
|
|
|
|
|
|
|
modem expressed as string. You must include the C prefix and final |
|
1016
|
|
|
|
|
|
|
B and/or B manually. There is the special constant |
|
1017
|
|
|
|
|
|
|
C that can be used to include such a char sequence into the at command. |
|
1018
|
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
Returns C<$ok> flag that is true if all characters are sent successfully, false |
|
1020
|
|
|
|
|
|
|
otherwise. |
|
1021
|
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
Example: |
|
1023
|
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
# Enable verbose messages |
|
1025
|
|
|
|
|
|
|
$modem->atsend( 'AT V1' . Device::Modem::CR ); |
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
# The same as: |
|
1028
|
|
|
|
|
|
|
$modem->verbose(1); |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
|
|
1031
|
|
|
|
|
|
|
=head2 attention() |
|
1032
|
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
This command sends an B sequence to modem. This allows modem |
|
1034
|
|
|
|
|
|
|
to pass in B and accept B commands. Example: |
|
1035
|
|
|
|
|
|
|
|
|
1036
|
|
|
|
|
|
|
$ok = $modem->attention() |
|
1037
|
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
=head2 connect() |
|
1039
|
|
|
|
|
|
|
|
|
1040
|
|
|
|
|
|
|
Connects C object to the specified serial port. |
|
1041
|
|
|
|
|
|
|
There are options (the same options that C has) to control |
|
1042
|
|
|
|
|
|
|
the parameters associated to serial link. Example: |
|
1043
|
|
|
|
|
|
|
|
|
1044
|
|
|
|
|
|
|
$ok = $modem->connect( [%options] ) |
|
1045
|
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
List of allowed options follows: |
|
1047
|
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
=over 4 |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
=item C |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
Controls the speed of serial communications. The default is B<19200> baud, that should |
|
1053
|
|
|
|
|
|
|
be supported by all modern modems. However, here you can supply a custom value. |
|
1054
|
|
|
|
|
|
|
Common speed values: 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, |
|
1055
|
|
|
|
|
|
|
115200. |
|
1056
|
|
|
|
|
|
|
This parameter is handled directly by C object. |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
=item C |
|
1059
|
|
|
|
|
|
|
|
|
1060
|
|
|
|
|
|
|
This tells how many bits your data word is composed of. |
|
1061
|
|
|
|
|
|
|
Default (and most common setting) is C<8>. |
|
1062
|
|
|
|
|
|
|
This parameter is handled directly by C object. |
|
1063
|
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
=item C |
|
1065
|
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
Sets the handshake (or flow control) method for the serial port. |
|
1067
|
|
|
|
|
|
|
By default it is C, but can be either C (hardware flow control) |
|
1068
|
|
|
|
|
|
|
or C (software flow control). These flow control modes may or may not |
|
1069
|
|
|
|
|
|
|
work depending on your modem device or software. |
|
1070
|
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
=item C |
|
1072
|
|
|
|
|
|
|
|
|
1073
|
|
|
|
|
|
|
Custom initialization string can be supplied instead of the built-in one, that is the |
|
1074
|
|
|
|
|
|
|
following: C, that is taken shamelessly from |
|
1075
|
|
|
|
|
|
|
C utility, I think. |
|
1076
|
|
|
|
|
|
|
|
|
1077
|
|
|
|
|
|
|
=item C |
|
1078
|
|
|
|
|
|
|
|
|
1079
|
|
|
|
|
|
|
Controls how parity bit is generated and checked. |
|
1080
|
|
|
|
|
|
|
Can be B, B or B. Default is B. |
|
1081
|
|
|
|
|
|
|
This parameter is handled directly by C object. |
|
1082
|
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
=item C |
|
1084
|
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
Tells how many bits are used to identify the end of a data word. |
|
1086
|
|
|
|
|
|
|
Default (and most common usage) is C<1>. |
|
1087
|
|
|
|
|
|
|
This parameter is handled directly by C object. |
|
1088
|
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
=back |
|
1090
|
|
|
|
|
|
|
|
|
1091
|
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
|
|
1093
|
|
|
|
|
|
|
=head2 dial() |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
Dials a telephone number. Can perform both voice and data calls. |
|
1096
|
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
Usage: |
|
1098
|
|
|
|
|
|
|
|
|
1099
|
|
|
|
|
|
|
$ok = $modem->dial($number); |
|
1100
|
|
|
|
|
|
|
$ok = $modem->dial($number, $timeout); |
|
1101
|
|
|
|
|
|
|
$ok = $modem->dial($number, $timeout, $mode); |
|
1102
|
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
Takes the modem off hook, dials the specified number and returns |
|
1104
|
|
|
|
|
|
|
modem answer. |
|
1105
|
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
Regarding voice calls, you B be able to send your voice through. |
|
1107
|
|
|
|
|
|
|
You probably have to connect an analog microphone, and just speak. |
|
1108
|
|
|
|
|
|
|
Or use a GSM phone. For voice calls, a simple C<;> is appended to the |
|
1109
|
|
|
|
|
|
|
number to be dialed. |
|
1110
|
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
If the number to dial is 1 digit only, extracts the number from the address book, provided your device has one. See C. |
|
1112
|
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
Examples: |
|
1114
|
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
# Simple usage. Timeout and mode are optional. |
|
1116
|
|
|
|
|
|
|
$ok = $mode->dial('123456789'); |
|
1117
|
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
# List context: allows to get at exact modem answer |
|
1119
|
|
|
|
|
|
|
# like `CONNECT 19200/...', `BUSY', `NO CARRIER', ... |
|
1120
|
|
|
|
|
|
|
# Also, 30 seconds timeout |
|
1121
|
|
|
|
|
|
|
($ok, $answer) = $modem->dial('123456789', 30); |
|
1122
|
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
If called in B, returns only success of connection. |
|
1124
|
|
|
|
|
|
|
If modem answer contains the C string, C returns |
|
1125
|
|
|
|
|
|
|
successful state, otherwise a false value is returned. |
|
1126
|
|
|
|
|
|
|
|
|
1127
|
|
|
|
|
|
|
If called in B, returns the same C<$ok> flag, but also the |
|
1128
|
|
|
|
|
|
|
exact modem answer to the dial operation in the C<$answer> scalar. |
|
1129
|
|
|
|
|
|
|
C<$answer> typically can contain strings like: |
|
1130
|
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
=over 4 |
|
1132
|
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
=item C |
|
1134
|
|
|
|
|
|
|
|
|
1135
|
|
|
|
|
|
|
=item C |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
=item C |
|
1138
|
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
=back |
|
1140
|
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
and so on ... all standard modem answers to a dial command. |
|
1142
|
|
|
|
|
|
|
|
|
1143
|
|
|
|
|
|
|
Parameters are: |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
=over 4 |
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
=item C<$number> |
|
1148
|
|
|
|
|
|
|
|
|
1149
|
|
|
|
|
|
|
B, this is the phone number to dial. |
|
1150
|
|
|
|
|
|
|
If C<$number> is only 1 digit, it is interpreted as: |
|
1151
|
|
|
|
|
|
|
B>. |
|
1152
|
|
|
|
|
|
|
|
|
1153
|
|
|
|
|
|
|
So if your code is: |
|
1154
|
|
|
|
|
|
|
|
|
1155
|
|
|
|
|
|
|
$modem->dial( 2, 10 ); |
|
1156
|
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
This means: dial number in the modem internal address book |
|
1158
|
|
|
|
|
|
|
(see C for a way to read/write address book) |
|
1159
|
|
|
|
|
|
|
in position number B<2> and wait for a timeout of B<10> seconds. |
|
1160
|
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
=item C<$timeout> |
|
1162
|
|
|
|
|
|
|
|
|
1163
|
|
|
|
|
|
|
B, default is B<30 seconds>. |
|
1164
|
|
|
|
|
|
|
|
|
1165
|
|
|
|
|
|
|
Timeout expressed in seconds to wait for the remote device |
|
1166
|
|
|
|
|
|
|
to answer. Please do not expect an B wait for the number of |
|
1167
|
|
|
|
|
|
|
seconds you specified. |
|
1168
|
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
=item C<$mode> |
|
1170
|
|
|
|
|
|
|
|
|
1171
|
|
|
|
|
|
|
B, default is C, as string. |
|
1172
|
|
|
|
|
|
|
Allows to specify the type of call. Can be either: |
|
1173
|
|
|
|
|
|
|
|
|
1174
|
|
|
|
|
|
|
=over 4 |
|
1175
|
|
|
|
|
|
|
|
|
1176
|
|
|
|
|
|
|
=item C (default) |
|
1177
|
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
To perform a B. |
|
1179
|
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
=item C |
|
1181
|
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
To perform a B, if your device supports it. |
|
1183
|
|
|
|
|
|
|
No attempt to verify whether your device can do that will be made. |
|
1184
|
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
=back |
|
1186
|
|
|
|
|
|
|
|
|
1187
|
|
|
|
|
|
|
=back |
|
1188
|
|
|
|
|
|
|
|
|
1189
|
|
|
|
|
|
|
=head2 disconnect() |
|
1190
|
|
|
|
|
|
|
|
|
1191
|
|
|
|
|
|
|
Disconnects C object from serial port. This method calls underlying |
|
1192
|
|
|
|
|
|
|
C of C object. |
|
1193
|
|
|
|
|
|
|
Example: |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
$modem->disconnect(); |
|
1196
|
|
|
|
|
|
|
|
|
1197
|
|
|
|
|
|
|
=head2 echo() |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
|
|
|
|
|
|
Enables or disables local echo of commands. This is managed automatically by C |
|
1200
|
|
|
|
|
|
|
object. Normally you should not need to worry about this. Usage: |
|
1201
|
|
|
|
|
|
|
|
|
1202
|
|
|
|
|
|
|
$ok = $modem->echo( $enable ) |
|
1203
|
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
=head2 hangup() |
|
1205
|
|
|
|
|
|
|
|
|
1206
|
|
|
|
|
|
|
Does what it is supposed to do. Hang up the phone thus terminating any active call. |
|
1207
|
|
|
|
|
|
|
Usage: |
|
1208
|
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
$ok = $modem->hangup(); |
|
1210
|
|
|
|
|
|
|
|
|
1211
|
|
|
|
|
|
|
=head2 is_active() |
|
1212
|
|
|
|
|
|
|
|
|
1213
|
|
|
|
|
|
|
Can be used to check if there is a modem attached to your computer. |
|
1214
|
|
|
|
|
|
|
If modem is alive and responding (on serial link, not to a remote call), |
|
1215
|
|
|
|
|
|
|
C returns true (1), otherwise returns false (0). |
|
1216
|
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
Test of modem activity is done through DSR (Data Set Ready) signal. If |
|
1218
|
|
|
|
|
|
|
this signal is in off state, modem is probably turned off, or not working. |
|
1219
|
|
|
|
|
|
|
From my tests I've found that DSR stays in "on" state after more or less |
|
1220
|
|
|
|
|
|
|
one second I turn off my modem, so know you know that. |
|
1221
|
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
Example: |
|
1223
|
|
|
|
|
|
|
|
|
1224
|
|
|
|
|
|
|
if( $modem->is_active() ) { |
|
1225
|
|
|
|
|
|
|
# Ok! |
|
1226
|
|
|
|
|
|
|
} else { |
|
1227
|
|
|
|
|
|
|
# Modem turned off? |
|
1228
|
|
|
|
|
|
|
} |
|
1229
|
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
=head2 log() |
|
1231
|
|
|
|
|
|
|
|
|
1232
|
|
|
|
|
|
|
Simple accessor to log object instanced at object creation time. |
|
1233
|
|
|
|
|
|
|
Used internally. If you want to know the gory details, see C objects. |
|
1234
|
|
|
|
|
|
|
You can also see the B for how to log something without knowing |
|
1235
|
|
|
|
|
|
|
all the gory details. |
|
1236
|
|
|
|
|
|
|
|
|
1237
|
|
|
|
|
|
|
Hint: |
|
1238
|
|
|
|
|
|
|
$modem->log->write('warning', 'ok, my log message here'); |
|
1239
|
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
=head2 new() |
|
1241
|
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
C constructor. This takes several options. A basic example: |
|
1243
|
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
my $modem = Device::Modem->new( port => '/dev/ttyS0' ); |
|
1245
|
|
|
|
|
|
|
|
|
1246
|
|
|
|
|
|
|
if under Linux or some kind of unix machine, or |
|
1247
|
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
my $modem = Device::Modem->new( port => 'COM1' ); |
|
1249
|
|
|
|
|
|
|
|
|
1250
|
|
|
|
|
|
|
if you are using a Win32 machine. |
|
1251
|
|
|
|
|
|
|
|
|
1252
|
|
|
|
|
|
|
This builds the C object with all the default parameters. |
|
1253
|
|
|
|
|
|
|
This should be fairly usable if you want to connect to a real modem. |
|
1254
|
|
|
|
|
|
|
Note that I'm testing it with a B<3Com US Robotics 56K Message> modem |
|
1255
|
|
|
|
|
|
|
at B<19200> baud and works ok. |
|
1256
|
|
|
|
|
|
|
|
|
1257
|
|
|
|
|
|
|
List of allowed options: |
|
1258
|
|
|
|
|
|
|
|
|
1259
|
|
|
|
|
|
|
=over 4 |
|
1260
|
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
=item * |
|
1262
|
|
|
|
|
|
|
|
|
1263
|
|
|
|
|
|
|
C - serial port to connect to. On Unix, can be also a convenient link as |
|
1264
|
|
|
|
|
|
|
F (the default value). For Win32, C can be used. |
|
1265
|
|
|
|
|
|
|
|
|
1266
|
|
|
|
|
|
|
=item * |
|
1267
|
|
|
|
|
|
|
|
|
1268
|
|
|
|
|
|
|
C - this specifies the method and eventually the filename for logging. |
|
1269
|
|
|
|
|
|
|
Logging process with C is controlled by B, stored under |
|
1270
|
|
|
|
|
|
|
F folder. At present, there are two main plugins: C and C. |
|
1271
|
|
|
|
|
|
|
C does not work with Win32 machines. |
|
1272
|
|
|
|
|
|
|
When using C plug-in, all log information will be written to a default filename |
|
1273
|
|
|
|
|
|
|
if you don't specify one yourself. The default is F<%WINBOOTDIR%\temp\modem.log> on |
|
1274
|
|
|
|
|
|
|
Win32 and F on Unix. |
|
1275
|
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
Also there is the possibility to pass a B, if this object |
|
1277
|
|
|
|
|
|
|
provides the following C call: |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
$log_object->write( $loglevel, $logmessage ) |
|
1280
|
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
You can simply pass this object (already instanced) as the C property. |
|
1282
|
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
Examples: |
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
# For Win32, default is to log in "%WINBOOTDIR%/temp/modem.log" file |
|
1286
|
|
|
|
|
|
|
my $modem = Device::Modem->new( port => 'COM1' ); |
|
1287
|
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
# Unix, custom logfile |
|
1289
|
|
|
|
|
|
|
my $modem = Device::Modem->new( port => '/dev/ttyS0', log => 'file,/home/neo/matrix.log' ) |
|
1290
|
|
|
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
# With custom log object |
|
1292
|
|
|
|
|
|
|
my $modem = Device::modem->new( port => '/dev/ttyS0', log => My::LogObj->new() ); |
|
1293
|
|
|
|
|
|
|
|
|
1294
|
|
|
|
|
|
|
=item * |
|
1295
|
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
C - default logging level. One of (order of decrescent verbosity): C, |
|
1297
|
|
|
|
|
|
|
C, C, C, C, C, C, C, C. |
|
1298
|
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
=back |
|
1300
|
|
|
|
|
|
|
|
|
1301
|
|
|
|
|
|
|
|
|
1302
|
|
|
|
|
|
|
=head2 offhook() |
|
1303
|
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
Takes the modem "off hook", ready to dial. Normally you don't need to use this. |
|
1305
|
|
|
|
|
|
|
Also C goes automatically off hook before dialing. |
|
1306
|
|
|
|
|
|
|
|
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
|
|
1309
|
|
|
|
|
|
|
=head2 parse_answer() |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
This method works like C, it accepts the same parameters, but it |
|
1312
|
|
|
|
|
|
|
does not return the raw modem answer. Instead, it returns the answer string |
|
1313
|
|
|
|
|
|
|
stripped of all B/B characters at the beginning B at the end. |
|
1314
|
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
C is meant as an easy way of extracting result code |
|
1316
|
|
|
|
|
|
|
(C, C, ...) and information strings that can be sent by modem |
|
1317
|
|
|
|
|
|
|
in response to specific commands. Example: |
|
1318
|
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
> AT xSHOW_MODELx |
|
1320
|
|
|
|
|
|
|
US Robotics 56K Message |
|
1321
|
|
|
|
|
|
|
OK |
|
1322
|
|
|
|
|
|
|
> |
|
1323
|
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
In this example, C is the result and C is the |
|
1325
|
|
|
|
|
|
|
informational message. |
|
1326
|
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
In fact, another difference with C is in the return value(s). |
|
1328
|
|
|
|
|
|
|
Here are some examples: |
|
1329
|
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
$modem->atsend( '?my_at_command?' ); |
|
1331
|
|
|
|
|
|
|
$answer = $modem->parse_answer(); |
|
1332
|
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
where C<$answer> is the complete response string, or: |
|
1334
|
|
|
|
|
|
|
|
|
1335
|
|
|
|
|
|
|
($result, @lines) = $modem->parse_answer(); |
|
1336
|
|
|
|
|
|
|
|
|
1337
|
|
|
|
|
|
|
where C<$result> is the C or C final message and C<@lines> is |
|
1338
|
|
|
|
|
|
|
the array of information messages (one or more lines). For the I example, |
|
1339
|
|
|
|
|
|
|
C<$result> would hold "C" and C<@lines> would consist of only 1 line with |
|
1340
|
|
|
|
|
|
|
the string "C". |
|
1341
|
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
|
|
1343
|
|
|
|
|
|
|
=head2 port() |
|
1344
|
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
Used internally. Accesses the C underlying object. If you need to |
|
1346
|
|
|
|
|
|
|
experiment or do low-level serial calls, you may want to access this. Please report |
|
1347
|
|
|
|
|
|
|
any usage of this kind, because probably (?) it is possible to include it in a higher |
|
1348
|
|
|
|
|
|
|
level method. |
|
1349
|
|
|
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
As of 1.52, C will automatically try to reconnect if it detects |
|
1351
|
|
|
|
|
|
|
a bogus underlying port object. It will reconnect with the same options used |
|
1352
|
|
|
|
|
|
|
when Cing the first time. |
|
1353
|
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
If no connection has taken place yet, then B |
|
1355
|
|
|
|
|
|
|
will be attempted. |
|
1356
|
|
|
|
|
|
|
|
|
1357
|
|
|
|
|
|
|
=head2 repeat() |
|
1358
|
|
|
|
|
|
|
|
|
1359
|
|
|
|
|
|
|
Repeats the last C command issued. |
|
1360
|
|
|
|
|
|
|
Usage: |
|
1361
|
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
$ok = $modem->repeat() |
|
1363
|
|
|
|
|
|
|
|
|
1364
|
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
=head2 reset() |
|
1366
|
|
|
|
|
|
|
|
|
1367
|
|
|
|
|
|
|
Tries in any possible way to reset the modem to the starting state, hanging up all |
|
1368
|
|
|
|
|
|
|
active calls, resending the initialization string and preparing to receive C |
|
1369
|
|
|
|
|
|
|
commands. |
|
1370
|
|
|
|
|
|
|
|
|
1371
|
|
|
|
|
|
|
|
|
1372
|
|
|
|
|
|
|
|
|
1373
|
|
|
|
|
|
|
=head2 restore_factory_settings() |
|
1374
|
|
|
|
|
|
|
|
|
1375
|
|
|
|
|
|
|
Restores the modem default factory settings. There are normally two main "profiles", |
|
1376
|
|
|
|
|
|
|
two different memories for all modem settings, so you can load profile 0 and profile 1, |
|
1377
|
|
|
|
|
|
|
that can be different depending on your modem manufacturer. |
|
1378
|
|
|
|
|
|
|
|
|
1379
|
|
|
|
|
|
|
Usage: |
|
1380
|
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
$ok = $modem->restore_factory_settings( [$profile] ) |
|
1382
|
|
|
|
|
|
|
|
|
1383
|
|
|
|
|
|
|
If no C<$profile> is supplied, C<0> is assumed as default value. |
|
1384
|
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
Check on your modem hardware manual for the meaning of these B. |
|
1386
|
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
|
|
1388
|
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
=head2 S_register() |
|
1390
|
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
Gets or sets an B value. These are some internal modem registers that |
|
1392
|
|
|
|
|
|
|
hold important information that controls all modem behaviour. If you don't know |
|
1393
|
|
|
|
|
|
|
what you are doing, don't use this method. Usage: |
|
1394
|
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
$value = $modem->S_register( $reg_number [, $new_value] ); |
|
1396
|
|
|
|
|
|
|
|
|
1397
|
|
|
|
|
|
|
C<$reg_number> ranges from 0 to 99 (sure?). |
|
1398
|
|
|
|
|
|
|
If no C<$new_value> is supplied, return value is the current register value. |
|
1399
|
|
|
|
|
|
|
If a C<$new_value> is supplied (you want to set the register value), return value |
|
1400
|
|
|
|
|
|
|
is the new value or C if there was an error setting the new value. |
|
1401
|
|
|
|
|
|
|
|
|
1402
|
|
|
|
|
|
|
|
|
1403
|
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
Examples: |
|
1405
|
|
|
|
|
|
|
|
|
1406
|
|
|
|
|
|
|
# Get value of S7 register |
|
1407
|
|
|
|
|
|
|
$modem->S_register(7); |
|
1408
|
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
# Set value of S0 register to 0 |
|
1410
|
|
|
|
|
|
|
$modem->S_register(0, 0); |
|
1411
|
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
|
|
1413
|
|
|
|
|
|
|
=head2 send_init_string() |
|
1414
|
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
Sends the initialization string to the connected modem. Usage: |
|
1416
|
|
|
|
|
|
|
|
|
1417
|
|
|
|
|
|
|
$ok = $modem->send_init_string( [$init_string] ); |
|
1418
|
|
|
|
|
|
|
|
|
1419
|
|
|
|
|
|
|
If you specified an C as an option to C object constructor, |
|
1420
|
|
|
|
|
|
|
that is taken by default to initialize the modem. |
|
1421
|
|
|
|
|
|
|
Else you can specify C<$init_string> parameter to use your own custom intialization |
|
1422
|
|
|
|
|
|
|
string. Be careful! |
|
1423
|
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
=head2 status() |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
Returns status of main modem signals as managed by C (or C) objects. |
|
1427
|
|
|
|
|
|
|
The signals reported are: |
|
1428
|
|
|
|
|
|
|
|
|
1429
|
|
|
|
|
|
|
=over 4 |
|
1430
|
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
=item CTS |
|
1432
|
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
Clear to send |
|
1434
|
|
|
|
|
|
|
|
|
1435
|
|
|
|
|
|
|
=item DSR |
|
1436
|
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
Data set ready |
|
1438
|
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
=item RING |
|
1440
|
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
Active if modem is ringing |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
=item RLSD |
|
1444
|
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
??? Released line ??? |
|
1446
|
|
|
|
|
|
|
|
|
1447
|
|
|
|
|
|
|
=back |
|
1448
|
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
Return value of C call is a hash, where each key is a signal name and |
|
1450
|
|
|
|
|
|
|
each value is > 0 if signal is active, 0 otherwise. |
|
1451
|
|
|
|
|
|
|
Usage: |
|
1452
|
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
... |
|
1454
|
|
|
|
|
|
|
my %sig = $modem->status(); |
|
1455
|
|
|
|
|
|
|
for ('CTS','DSR','RING','RLSD') { |
|
1456
|
|
|
|
|
|
|
print "Signal $_ is ", ($sig{$_} > 0 ? 'on' : 'off'), "\n"; |
|
1457
|
|
|
|
|
|
|
} |
|
1458
|
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
=head2 store_number() |
|
1460
|
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
Store telephone number in modem internal address book, to be dialed later (see C method). |
|
1462
|
|
|
|
|
|
|
Usage: |
|
1463
|
|
|
|
|
|
|
|
|
1464
|
|
|
|
|
|
|
$ok = $modem->store_number( $position, $number ) |
|
1465
|
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
where C<$position> is the address book memory slot to store phone number (usually from 0 to 9), |
|
1467
|
|
|
|
|
|
|
and C<$number> is the number to be stored in the slot. |
|
1468
|
|
|
|
|
|
|
Return value is true if operation was successful, false otherwise. |
|
1469
|
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
=head2 verbose() |
|
1471
|
|
|
|
|
|
|
|
|
1472
|
|
|
|
|
|
|
Enables or disables verbose messages. This is managed automatically by C |
|
1473
|
|
|
|
|
|
|
object. Normally you should not need to worry about this. Usage: |
|
1474
|
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
$ok = $modem->verbose( $enable ) |
|
1476
|
|
|
|
|
|
|
|
|
1477
|
|
|
|
|
|
|
=head2 wait() |
|
1478
|
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
Waits (yea) for a given amount of time (in milliseconds). Usage: |
|
1480
|
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
$modem->wait( [$msecs] ) |
|
1482
|
|
|
|
|
|
|
|
|
1483
|
|
|
|
|
|
|
Wait is implemented via C |
|
1484
|
|
|
|
|
|
|
Don't know if this is really a problem on some platforms. |
|
1485
|
|
|
|
|
|
|
|
|
1486
|
|
|
|
|
|
|
=head2 write_drain() |
|
1487
|
|
|
|
|
|
|
|
|
1488
|
|
|
|
|
|
|
Only a simple wrapper around C method. |
|
1489
|
|
|
|
|
|
|
Disabled for Win32 platform, that doesn't have that. |
|
1490
|
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
=head1 REQUIRES |
|
1493
|
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
=over 4 |
|
1495
|
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
=item Device::SerialPort (Win32::SerialPort for Win32 machines) |
|
1497
|
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
=back |
|
1499
|
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
=head1 EXPORT |
|
1501
|
|
|
|
|
|
|
|
|
1502
|
|
|
|
|
|
|
None |
|
1503
|
|
|
|
|
|
|
|
|
1504
|
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
|
|
1506
|
|
|
|
|
|
|
=head1 TO-DO |
|
1507
|
|
|
|
|
|
|
|
|
1508
|
|
|
|
|
|
|
=over 4 |
|
1509
|
|
|
|
|
|
|
|
|
1510
|
|
|
|
|
|
|
=item AutoScan |
|
1511
|
|
|
|
|
|
|
|
|
1512
|
|
|
|
|
|
|
An AT command script with all interesting commands is run |
|
1513
|
|
|
|
|
|
|
when `autoscan' is invoked, creating a `profile' of the |
|
1514
|
|
|
|
|
|
|
current device, with list of supported commands, and database |
|
1515
|
|
|
|
|
|
|
of brand/model-specific commands |
|
1516
|
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
=item Serial speed autodetect |
|
1518
|
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
Now if you connect to a different baud rate than that of your modem, |
|
1520
|
|
|
|
|
|
|
probably you will get no response at all. It would be nice if C |
|
1521
|
|
|
|
|
|
|
could auto-detect the speed to correctly connect at your modem. |
|
1522
|
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
=item File transfers |
|
1524
|
|
|
|
|
|
|
|
|
1525
|
|
|
|
|
|
|
It would be nice to implement C<[xyz]modem> like transfers between |
|
1526
|
|
|
|
|
|
|
two C objects connected with two modems. |
|
1527
|
|
|
|
|
|
|
|
|
1528
|
|
|
|
|
|
|
=back |
|
1529
|
|
|
|
|
|
|
|
|
1530
|
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
=head1 FAQ |
|
1532
|
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
There is a minimal FAQ document for this module online at |
|
1534
|
|
|
|
|
|
|
L |
|
1535
|
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
=head1 SUPPORT |
|
1537
|
|
|
|
|
|
|
|
|
1538
|
|
|
|
|
|
|
Please feel free to contact me at my e-mail address L |
|
1539
|
|
|
|
|
|
|
for any information, to resolve problems you can encounter with this module |
|
1540
|
|
|
|
|
|
|
or for any kind of commercial support you may need. |
|
1541
|
|
|
|
|
|
|
|
|
1542
|
|
|
|
|
|
|
=head1 AUTHOR |
|
1543
|
|
|
|
|
|
|
|
|
1544
|
|
|
|
|
|
|
Cosimo Streppone, L |
|
1545
|
|
|
|
|
|
|
|
|
1546
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
1547
|
|
|
|
|
|
|
|
|
1548
|
|
|
|
|
|
|
(C) 2002-2014 Cosimo Streppone, L |
|
1549
|
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
This library is free software; you can only redistribute it and/or |
|
1551
|
|
|
|
|
|
|
modify it under the same terms as Perl itself. |
|
1552
|
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
1554
|
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
Device::SerialPort, |
|
1556
|
|
|
|
|
|
|
Win32::SerialPort, |
|
1557
|
|
|
|
|
|
|
Device::Gsm, |
|
1558
|
|
|
|
|
|
|
perl |
|
1559
|
|
|
|
|
|
|
|
|
1560
|
|
|
|
|
|
|
=cut |
|
1561
|
|
|
|
|
|
|
|
|
1562
|
|
|
|
|
|
|
# vim: set ts=4 sw=4 tw=120 nowrap nu |