summaryrefslogtreecommitdiff
path: root/xpp/perl_modules/Dahdi/Chans.pm
blob: 820deefac054307697658e79fc427224d89b9562 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
package Dahdi::Chans;
#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2007, Xorcom
# This program is free software; you can redistribute and/or
# modify it under the same terms as Perl itself.
#
# $Id$
#
use strict;
use Dahdi::Utils;

=head1 NAME

Dahdi::Chans - Perl interface to a Dahdi channel information

This package allows access from perl to information about a Dahdi
channel. It is part of the Dahdi Perl package.

=head1 alarms()

In an array context returns a list of alarm strings (RED, BLUE, etc.)
for this channel (an empty list == false if there are no alarms).
In scalar context returns the number of alarms for a specific channel.

=head1 battery()

Returns 1 if channel reports to have battery (A remote PBX connected to
an FXO port), 0 if channel reports to not have battery and C<undef>
otherwise.

Currently only wcfxo and Astribank FXO modules report battery. For the
rest of the channels 

=head1 fqn()

(Fully Qualified Name) Returns the full "name" of the channel.

=head1 index()

Returns the number of this channel (in the span).

=head1 num()

Returns the number of this channel as a Dahdi channel.

=head signalling()

Returns the signalling set for this channel through /etc/dahdi/system.conf .
This is always empty before dahdi_cfg was run. And shows the "other" type
for FXS and for FXO.

=head1 span()

Returns a reference to the span to which this channel belongs.

=head1 type()

Returns the type of the channel: 'FXS', 'FXO', 'EMPTY', etc.

=cut

my @alarm_types = qw(BLUE YELLOW RED LOOP RECOVERING NOTOPEN);

# Taken from dahdi-base.c
my @sigtypes = (
	"FXSLS",
	"FXSKS",
	"FXSGS",
	"FXOLS",
	"FXOKS",
	"FXOGS",
	"E&M",
	"E&M-E1",
	"Clear",
	"HDLCRAW",
	"HDLCFCS",
	"HDLCNET",
	"Hardware-assisted HDLC",
	"MTP2",
	"Slave",
	"CAS",
	"DACS",
	"DACS+RBS",
	"SF (ToneOnly)",
	"Unconfigured"
	);

sub new($$$$$$) {
	my $pack = shift or die "Wasn't called as a class method\n";
	my $span = shift or die "Missing a span parameter\n";
	my $index = shift;
	my $line = shift or die "Missing an input line\n";
	defined $index or die "Missing an index parameter\n";
	my $self = {
			'SPAN' => $span,
			'INDEX' => $index,
		};
	bless $self, $pack;
	my ($num, $fqn, $rest) = split(/\s+/, $line, 3);
	$num or die "Missing a channel number parameter\n";
	$fqn or die "Missing a channel fqn parameter\n";
	my $signalling = '';
	my @alarms = ();
	my $info = '';
	if(defined $rest) {
		# remarks in parenthesis (In use), (no pcm)
		while($rest =~ s/\s*(\([^)]+\))\s*/ /) {
			$info .= " $1";
		}
		# Alarms
		foreach my $alarm (@alarm_types) {
			if($rest =~ s/\s*(\b${alarm}\b)\s*/ /) {
				push(@alarms, $1);
			}
		}
		foreach my $sig (@sigtypes) {
			if($rest =~ s/^\Q$sig\E/ /) {
				$signalling = $sig;
				last;
			}
		}
		warn "Unrecognized garbage '$rest' in $fqn\n"
			if $rest =~ /\S/;
	}
	$self->{NUM} = $num;
	$self->{FQN} = $fqn;
	$self->{SIGNALLING} = $signalling;
	$self->{ALARMS} = \@alarms;
	$self->{INFO} = $info;
	my $type;
	if($fqn =~ m|\bXPP_(\w+)/.*$|) {
		$type = $1;		# An Astribank
	} elsif ($fqn =~ m{\bWCFXO/.*}) {
		$type = "FXO"; # wcfxo - x100p and relatives.
		# A single port card. The driver issue RED alarm when
		# There's no better
		$self->{BATTERY} = !($span->description =~ /\bRED\b/);
	} elsif ($fqn =~ m{\bFXS/.*}) {
		$type = "FXS"; # likely Rhino
	} elsif ($fqn =~ m{\bFXO/.*}) {
		$type = "FXO"; # likely Rhino
	} elsif ($fqn =~ m{---/.*}) {
		$type = "EMPTY"; # likely Rhino, empty slot.
	} elsif ($fqn =~ m{\b(TE[24]|WCT1|Tor2|TorISA|WP[TE]1|cwain[12]|R[124]T1)/.*}) {
		# TE[24]: Digium wct4xxp
		# WCT1: Digium single span card drivers?
		# Tor2: Tor PCI cards
		# TorISA: ISA ones (still used?) 
		# WP[TE]1: Sangoma. TODO: this one tells us if it is TE or NT.
		# cwain: Junghanns E1 card.
		# R[124]: Rhino r1t1/rxt1 cards
		$type = "PRI";
	} elsif ($fqn =~ m{\b(WCBRI|B4|ZTHFC\d*|ztqoz\d*)/.*}) {
		# WCBRI: The Digium Hx8 series cards with BRI module.
		# B4: The Digium wcb4xxp DAHDI driver
		# ZTHFC: HFC-s single-port card (zaphfc/vzaphfc)
		# ztqoz: qozap (Junghanns) multi-port HFC card
		$type = "BRI";
        } elsif ($fqn =~ m{\bDYN/.*}) {
                # DYN : Dynamic span (TDMOE)
                $type = "DYN"
	} elsif ($fqn =~ m{\bztgsm/.*}) {
		# Junghanns GSM card
		$type = "GSM";
	} elsif($signalling ne '') {
		$type = 'FXO' if $signalling =~ /^FXS/;
		$type = 'FXS' if $signalling =~ /^FXO/;
	} else {
		$type = $self->probe_type();
	}
	$self->type($type);
	$self->span()->type($type)
		if ! defined($self->span()->type()) ||
			$self->span()->type() eq 'UNKNOWN';
	return $self;
}

=head1 probe_type()

In the case of some cards, the information in /proc/dahdi is not good
enough to tell the type of each channel. In this case an extra explicit
probe is needed.

Currently this is implemented by using some invocations of dahdi_cfg(8).

It may later be replaced by dahdi_scan(8).

=cut

my $dahdi_cfg = $ENV{DAHDI_CFG} || '/usr/sbin/dahdi_cfg';
sub probe_type($) {
	my $self = shift;
	my $fqn = $self->fqn;
	my $num = $self->num;
	my $type;

	if($fqn =~ m:WCTDM/|WRTDM/|OPVXA1200/:) {
		my %maybe;

		undef %maybe;
		foreach my $sig (qw(fxo fxs)) {
			my $cmd = "echo ${sig}ks=$num | $dahdi_cfg -c /dev/fd/0";

			$maybe{$sig} = system("$cmd >/dev/null 2>&1") == 0;
		}
		if($maybe{fxo} and $maybe{fxs}) {
			$type = 'EMPTY';
		} elsif($maybe{fxo}) {
			$type = 'FXS';
		} elsif($maybe{fxs}) {
			$type = 'FXO';
		} else {
			$type = 'EMPTY';
		}
	} else {
		$type = $self->type;
	}
	return $type;
}

sub battery($) {
	my $self = shift or die;
	my $span = $self->span or die;

	return undef unless defined $self->type && $self->type eq 'FXO';
	return $self->{BATTERY} if defined $self->{BATTERY};

	my $xpd = $span->xpd;
	my $index = $self->index;
	return undef if !$xpd;

	# It's an XPD (FXO)
	my @lines = @{$xpd->lines};
	my $line = $lines[$index];
	return $line->battery;
}

sub alarms($) {
	my $self = shift or die;
	my @alarms = @{$self->{ALARMS}};

	return @alarms;
}

sub blink($$) {
	my $self = shift or die;
	my $on = shift;
	my $span = $self->span or die;

	my $xpd = $span->xpd;
	my $index = $self->index;
	return undef if !$xpd;

	my @lines = @{$xpd->lines};
	my $line = $lines[$index];
	return $line->blink($on);
}


1;