fxotune: Use DAHDI_SPECIFY when opening by integer channel number.
[dahdi/tools.git] / xpp / perl_modules / Dahdi / Chans.pm
1 package Dahdi::Chans;
2 #
3 # Written by Oron Peled <oron@actcom.co.il>
4 # Copyright (C) 2007, Xorcom
5 # This program is free software; you can redistribute and/or
6 # modify it under the same terms as Perl itself.
7 #
8 # $Id$
9 #
10 use strict;
11 use Dahdi::Utils;
12
13 =head1 NAME
14
15 Dahdi::Chans - Perl interface to a Dahdi channel information
16
17 This package allows access from perl to information about a Dahdi
18 channel. It is part of the Dahdi Perl package.
19
20 =head1 alarms()
21
22 In an array context returns a list of alarm strings (RED, BLUE, etc.)
23 for this channel (an empty list == false if there are no alarms).
24 In scalar context returns the number of alarms for a specific channel.
25
26 =head1 battery()
27
28 Returns 1 if channel reports to have battery (A remote PBX connected to
29 an FXO port), 0 if channel reports to not have battery and C<undef>
30 otherwise.
31
32 Currently only wcfxo and Astribank FXO modules report battery. For the
33 rest of the channels 
34
35 =head1 fqn()
36
37 (Fully Qualified Name) Returns the full "name" of the channel.
38
39 =head1 index()
40
41 Returns the number of this channel (in the span).
42
43 =head1 num()
44
45 Returns the number of this channel as a Dahdi channel.
46
47 =head signalling()
48
49 Returns the signalling set for this channel through /etc/dahdi/system.conf .
50 This is always empty before dahdi_cfg was run. And shows the "other" type
51 for FXS and for FXO.
52
53 =head1 span()
54
55 Returns a reference to the span to which this channel belongs.
56
57 =head1 type()
58
59 Returns the type of the channel: 'FXS', 'FXO', 'EMPTY', etc.
60
61 =cut
62
63 my @alarm_types = qw(BLUE YELLOW RED LOOP RECOVERING NOTOPEN);
64
65 # Taken from dahdi-base.c
66 my @sigtypes = (
67         "FXSLS",
68         "FXSKS",
69         "FXSGS",
70         "FXOLS",
71         "FXOKS",
72         "FXOGS",
73         "E&M-E1",
74         "E&M",
75         "Clear",
76         "HDLCRAW",
77         "HDLCFCS",
78         "HDLCNET",
79         "Hardware-assisted HDLC",
80         "MTP2",
81         "Slave",
82         "CAS",
83         "DACS",
84         "DACS+RBS",
85         "SF (ToneOnly)",
86         "Unconfigured",
87         "Reserved"
88         );
89
90 sub new($$$$$$) {
91         my $pack = shift or die "Wasn't called as a class method\n";
92         my $span = shift or die "Missing a span parameter\n";
93         my $index = shift;
94         my $line = shift or die "Missing an input line\n";
95         defined $index or die "Missing an index parameter\n";
96         my $self = {
97                         'SPAN' => $span,
98                         'INDEX' => $index,
99                 };
100         bless $self, $pack;
101         my ($num, $fqn, $rest) = split(/\s+/, $line, 3);
102         $num or die "Missing a channel number parameter\n";
103         $fqn or die "Missing a channel fqn parameter\n";
104         my $signalling = '';
105         my @alarms = ();
106         my $info = '';
107         if(defined $rest) {
108                 # remarks in parenthesis (In use), (no pcm)
109                 while($rest =~ s/\s*(\([^)]+\))\s*/ /) {
110                         $info .= " $1";
111                 }
112                 # Alarms
113                 foreach my $alarm (@alarm_types) {
114                         if($rest =~ s/\s*(\b${alarm}\b)\s*/ /) {
115                                 push(@alarms, $1);
116                         }
117                 }
118                 foreach my $sig (@sigtypes) {
119                         if($rest =~ s/^\Q$sig\E/ /) {
120                                 $signalling = $sig;
121                                 last;
122                         }
123                 }
124                 warn "Unrecognized garbage '$rest' in $fqn\n"
125                         if $rest =~ /\S/;
126         }
127         $self->{NUM} = $num;
128         $self->{FQN} = $fqn;
129         $self->{SIGNALLING} = $signalling;
130         $self->{ALARMS} = \@alarms;
131         $self->{INFO} = $info;
132         my $type;
133         if($fqn =~ m|\bXPP_(\w+)/.*$|) {
134                 $type = $1;             # An Astribank
135         } elsif ($fqn =~ m{\bWCFXO/.*}) {
136                 $type = "FXO"; # wcfxo - x100p and relatives.
137                 # A single port card. The driver issue RED alarm when
138                 # There's no better
139                 $self->{BATTERY} = !($span->description =~ /\bRED\b/);
140         } elsif ($fqn =~ m{\bFXS/.*}) {
141                 $type = "FXS"; # likely Rhino
142         } elsif ($fqn =~ m{\bFXO/.*}) {
143                 $type = "FXO"; # likely Rhino
144         } elsif ($fqn =~ m{---/.*}) {
145                 $type = "EMPTY"; # likely Rhino, empty slot.
146         } elsif ($fqn =~ m{\b(TE[24]|WCT1|Tor2|TorISA|WP[TE]1|cwain[12]|R[124]T1|AP40[124]|APE40[124])/.*}) {
147                 # TE[24]: Digium wct4xxp
148                 # WCT1: Digium single span card drivers?
149                 # Tor2: Tor PCI cards
150                 # TorISA: ISA ones (still used?) 
151                 # WP[TE]1: Sangoma. TODO: this one tells us if it is TE or NT.
152                 # cwain: Junghanns E1 card.
153                 # R[124]: Rhino r1t1/rxt1 cards
154                 # AP40[124]: Aligera AP40X cards
155                 # APE40[124]: Aligera APE40X cards
156                 $type = "PRI";
157         } elsif ($fqn =~ m{\b(WCBRI|B4|ZTHFC\d*|ztqoz\d*)/.*}) {
158                 # WCBRI: The Digium Hx8 series cards with BRI module.
159                 # B4: The Digium wcb4xxp DAHDI driver
160                 # ZTHFC: HFC-s single-port card (zaphfc/vzaphfc)
161                 # ztqoz: qozap (Junghanns) multi-port HFC card
162                 $type = "BRI";
163         } elsif ($fqn =~ m{\bDYN/.*}) {
164                 # DYN : Dynamic span (TDMOE)
165                 $type = "DYN"
166         } elsif ($fqn =~ m{\bztgsm/.*}) {
167                 # Junghanns GSM card
168                 $type = "GSM";
169         } elsif($signalling ne '') {
170                 $type = 'FXO' if $signalling =~ /^FXS/;
171                 $type = 'FXS' if $signalling =~ /^FXO/;
172         } else {
173                 $type = $self->probe_type();
174         }
175         $self->type($type);
176         $self->span()->type($type)
177                 if ! defined($self->span()->type()) ||
178                         $self->span()->type() eq 'UNKNOWN';
179         return $self;
180 }
181
182 =head1 probe_type()
183
184 In the case of some cards, the information in /proc/dahdi is not good
185 enough to tell the type of each channel. In this case an extra explicit
186 probe is needed.
187
188 Currently this is implemented by using some invocations of dahdi_cfg(8).
189
190 It may later be replaced by dahdi_scan(8).
191
192 =cut
193
194 my $dahdi_cfg = $ENV{DAHDI_CFG} || '/usr/sbin/dahdi_cfg';
195 sub probe_type($) {
196         my $self = shift;
197         my $fqn = $self->fqn;
198         my $num = $self->num;
199         my $type;
200
201         if($fqn =~ m:WCTDM/|WRTDM/|OPVXA1200/:) {
202                 my %maybe;
203
204                 undef %maybe;
205                 foreach my $sig (qw(fxo fxs)) {
206                         my $cmd = "echo ${sig}ks=$num | $dahdi_cfg -c /dev/fd/0";
207
208                         $maybe{$sig} = system("$cmd >/dev/null 2>&1") == 0;
209                 }
210                 if($maybe{fxo} and $maybe{fxs}) {
211                         $type = 'EMPTY';
212                 } elsif($maybe{fxo}) {
213                         $type = 'FXS';
214                 } elsif($maybe{fxs}) {
215                         $type = 'FXO';
216                 } else {
217                         $type = 'EMPTY';
218                 }
219         } else {
220                 $type = $self->type;
221         }
222         return $type;
223 }
224
225 sub battery($) {
226         my $self = shift or die;
227         my $span = $self->span or die;
228
229         return undef unless defined $self->type && $self->type eq 'FXO';
230         return $self->{BATTERY} if defined $self->{BATTERY};
231
232         my $xpd = Dahdi::Xpp::xpd_of_span($span);
233         my $index = $self->index;
234         return undef if !$xpd;
235
236         # It's an XPD (FXO)
237         my @lines = @{$xpd->lines};
238         my $line = $lines[$index];
239         return $line->battery;
240 }
241
242 sub alarms($) {
243         my $self = shift or die;
244         my @alarms = @{$self->{ALARMS}};
245
246         return @alarms;
247 }
248
249 sub blink($$) {
250         my $self = shift or die;
251         my $on = shift;
252         my $span = $self->span or die;
253
254         my $xpd = Dahdi::Xpp::xpd_of_span($span);
255         my $index = $self->index;
256         return undef if !$xpd;
257
258         my @lines = @{$xpd->lines};
259         my $line = $lines[$index];
260         return $line->blink($on);
261 }
262
263
264 1;