diff options
Diffstat (limited to 'xpp/utils')
-rw-r--r-- | xpp/utils/Makefile | 40 | ||||
-rw-r--r-- | xpp/utils/fpga_load.c | 71 | ||||
-rwxr-xr-x | xpp/utils/genzaptelconf | 28 | ||||
-rw-r--r-- | xpp/utils/hexfile.c | 73 | ||||
-rw-r--r-- | xpp/utils/hexfile.h | 1 | ||||
-rwxr-xr-x | xpp/utils/lszaptel | 54 | ||||
-rw-r--r-- | xpp/utils/test_parse.c | 1 | ||||
-rw-r--r-- | xpp/utils/xpp_fxloader | 2 | ||||
-rwxr-xr-x | xpp/utils/xpp_sync | 152 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel.pm | 24 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Chans.pm | 46 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Span.pm | 53 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Xpp.pm | 88 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Xpp/Xbus.pm | 51 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Xpp/Xpd.pm | 64 | ||||
-rwxr-xr-x | xpp/utils/zt_registration | 77 |
16 files changed, 754 insertions, 71 deletions
diff --git a/xpp/utils/Makefile b/xpp/utils/Makefile index ef6325d..d54848b 100644 --- a/xpp/utils/Makefile +++ b/xpp/utils/Makefile @@ -27,6 +27,8 @@ DATADIR = $(datadir)/zaptel MANDIR = $(mandir)/man8 HOTPLUG_USB_DIR = /etc/hotplug/usb UDEV_RULES_DIR = /etc/udev/rules.d +# Perl disabled by default, until we see it is safe: +#PERLLIBDIR = $(shell eval `perl -V:sitelib`; echo "$$sitelib") XPD_FIRMWARE = $(wildcard ../firmwares/*.hex) XPD_INIT_DATA = $(XPD_FIRMWARE) init_fxo_modes @@ -37,10 +39,21 @@ XPD_INIT = $(wildcard ../init_card_?_*) ../calibrate_slics HOSTCC ?= $(CC) ZAPTEL_DIR ?= ../.. +ifeq (,$(PBX_LIBUSB)) +# No PBX_LIBUSB? Maybe we compile against zaptel-1.2 +# Let's make a poor man detection of libusb +PBX_LIBUSB = $(shell if [ -r /usr/include/usb.h ]; then echo 1; else echo 0; fi) +endif + WCTDM=$(ZAPTEL_DIR)/wctdm.c CFLAGS = -g -Wall $(EXTRA_CFLAGS) +%.8: % + pod2man --section 8 $^ > $@ || $(RM) $@ +PERL_SCRIPTS = zt_registration xpp_sync lszaptel +PERL_MANS = zt_registration.8 xpp_sync.8 lszaptel.8 + TARGETS = init_fxo_modes print_modes adj_clock PROG_INSTALL = genzaptelconf adj_clock MAN_INSTALL = genzaptelconf.8 adj_clock.8 @@ -49,12 +62,22 @@ TARGETS += libhexfile.a fpga_load test_parse PROG_INSTALL += fpga_load MAN_INSTALL += fpga_load.8 endif +ifneq (,$(PERLLIBDIR)) +PROG_INSTALL += $(PERL_SCRIPTS) +MAN_INSTALL += $(PERL_MANS) +endif all: $(TARGETS) -install: all - $(INSTALL) -d $(DESTDIR)$(BINDIR) - $(INSTALL) $(PROG_INSTALL) $(DESTDIR)$(BINDIR)/ +docs: $(PERL_MANS) + +# give an ugly warning if Timer::Hires is missing: +sanity_checks: + perl -c ../calibrate_slics >/dev/null || true + +install: all sanity_checks + $(INSTALL) -d $(DESTDIR)$(SBINDIR) + $(INSTALL) $(PROG_INSTALL) $(DESTDIR)$(SBINDIR)/ $(INSTALL) -d $(DESTDIR)$(DATADIR) $(INSTALL_DATA) $(XPD_INIT_DATA) $(DESTDIR)$(DATADIR)/ $(INSTALL) $(XPD_INIT) $(DESTDIR)$(DATADIR)/ @@ -65,6 +88,17 @@ install: all $(INSTALL) xpp_fxloader $(DESTDIR)$(HOTPLUG_USB_DIR)/ $(INSTALL) -d $(DESTDIR)$(UDEV_RULES_DIR) $(INSTALL_DATA) xpp.rules $(DESTDIR)$(UDEV_RULES_DIR)/ +ifneq (,$(PERLLIBDIR)) + $(INSTALL) -d $(DESTDIR)$(PERLLIBDIR) + for i in Zaptel Zaptel/Xpp; \ + do \ + $(INSTALL) -d "$(DESTDIR)$(PERLLIBDIR)/$$i"; \ + done + for i in Zaptel.pm Zaptel/Xpp/Xbus.pm Zaptel/Xpp/Xpd.pm Zaptel/Xpp.pm Zaptel/Span.pm Zaptel/Chans.pm; \ + do \ + $(INSTALL_DATA) "zconf/$$i" "$(DESTDIR)$(PERLLIBDIR)/$$i"; \ + done +endif libhexfile.a: hexfile.o $(AR) cru $@ $^ diff --git a/xpp/utils/fpga_load.c b/xpp/utils/fpga_load.c index 426e6a6..2c03704 100644 --- a/xpp/utils/fpga_load.c +++ b/xpp/utils/fpga_load.c @@ -10,8 +10,21 @@ static const char rcsid[] = "$Id$"; -#define ERR(fmt, arg...) fprintf(stderr, "%s: ERROR: " fmt, progname, ## arg) -#define INFO(fmt, arg...) fprintf(stderr, "%s: " fmt, progname, ## arg) +#define ERR(fmt, arg...) do { \ + if(verbose >= LOG_ERR) \ + fprintf(stderr, "%s: ERROR: " fmt, \ + progname, ## arg); \ + } while(0); +#define INFO(fmt, arg...) do { \ + if(verbose >= LOG_INFO) \ + fprintf(stderr, "%s: " fmt, \ + progname, ## arg); \ + } while(0); +#define DBG(fmt, arg...) do { \ + if(verbose >= LOG_DEBUG) \ + fprintf(stderr, "%s: DBG: " fmt, \ + progname, ## arg); \ + } while(0); static int verbose = LOG_WARNING; static char *progname; @@ -229,14 +242,13 @@ int eeprom_set(struct my_usb_device *mydev, const struct myeeprom *eeprom) char buf[PACKET_SIZE]; struct fpga_packet_header *phead = (struct fpga_packet_header *)buf; - if(verbose >= LOG_DEBUG) - INFO("%s Start...\n", __FUNCTION__); + DBG("%s Start...\n", __FUNCTION__); assert(mydev != NULL); phead->header.op = EEPROM_SET; memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE); len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op); if(verbose >= LOG_DEBUG) { - INFO("%s write %d bytes\n", __FUNCTION__, len); + DBG("%s write %d bytes\n", __FUNCTION__, len); dump_packet((char *)phead, len); } ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, len, TIMEOUT); @@ -262,7 +274,7 @@ int eeprom_set(struct my_usb_device *mydev, const struct myeeprom *eeprom) return -EINVAL; } if(verbose >= LOG_DEBUG) { - INFO("%s read %d bytes\n", __FUNCTION__, ret); + DBG("%s read %d bytes\n", __FUNCTION__, ret); dump_packet(buf, ret); } return 0; @@ -279,12 +291,11 @@ int eeprom_get(struct my_usb_device *mydev) assert(mydev != NULL); eeprom = &mydev->eeprom; - if(verbose >= LOG_DEBUG) - INFO("%s Start...\n", __FUNCTION__); + DBG("%s Start...\n", __FUNCTION__); phead->header.op = EEPROM_GET; len = sizeof(phead->header.op); /* warning: sending small packet */ if(verbose >= LOG_DEBUG) { - INFO("%s write %d bytes\n", __FUNCTION__, len); + DBG("%s write %d bytes\n", __FUNCTION__, len); dump_packet(buf, len); } ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, len, TIMEOUT); @@ -310,7 +321,7 @@ int eeprom_get(struct my_usb_device *mydev) return -EINVAL; } if(verbose >= LOG_DEBUG) { - INFO("%s read %d bytes\n", __FUNCTION__, ret); + DBG("%s read %d bytes\n", __FUNCTION__, ret); dump_packet(buf, ret); } memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE); @@ -339,8 +350,7 @@ int send_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq) phead->d.data_packet.reserved = 0x00; memcpy(phead->d.data_packet.data, data, len); len += sizeof(hexline->d.content.header); - if(verbose >= LOG_DEBUG) - INFO("%04d+\r", seq); + DBG("%04d+\r", seq); ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, len, TIMEOUT); if(ret < 0) { ERR("bulk_write failed: %s\n", usb_strerror()); @@ -357,8 +367,7 @@ int send_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq) return ret; } else if(ret == 0) return 0; - if(verbose >= LOG_INFO) - INFO("%04d-\r", seq); + DBG("%04d-\r", seq); phead = (struct fpga_packet_header *)buf; if(phead->header.op != STATUS_REPLY) { ERR("Got unexpected reply op=%d\n", phead->header.op); @@ -372,13 +381,11 @@ int send_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq) case FW_FAIL_RESET: case FW_FAIL_TRANS: ERR("status reply %s (%d)\n", load_status2str(status), status); - if(verbose >= LOG_INFO) - dump_packet(buf, ret); + dump_packet(buf, ret); return -EPROTO; default: ERR("Unknown status reply %d\n", status); - if(verbose >= LOG_INFO) - dump_packet(buf, ret); + dump_packet(buf, ret); return -EPROTO; } return 0; @@ -468,9 +475,11 @@ int my_usb_device_init(const char devpath[], struct my_usb_device *mydev) config_desc = mydev->dev->config; interface = config_desc->interface; iface_desc = interface->altsetting; - if(verbose >= LOG_INFO) - INFO("Vendor:Product=%04X:%04X Class=%d (endpoints=%d)\n", - dev_desc->idVendor, dev_desc->idProduct, dev_desc->bDeviceClass, iface_desc->bNumEndpoints); + INFO("Vendor:Product=%04X:%04X Class=%d (endpoints=%d)\n", + dev_desc->idVendor, + dev_desc->idProduct, + dev_desc->bDeviceClass, + iface_desc->bNumEndpoints); if(iface_desc->bInterfaceClass != 0xFF) { ERR("Wrong Interface class %d\n", iface_desc->bInterfaceClass); return 0; @@ -518,8 +527,7 @@ int renumerate_device(struct my_usb_device *mydev) int ret; assert(mydev != NULL); - if(verbose >= LOG_INFO) - INFO("Renumerating\n"); + DBG("Renumerating\n"); phead->header.op = RENUMERATE; ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, 1, TIMEOUT); if(ret < 0) { @@ -541,10 +549,11 @@ int fpga_load(struct my_usb_device *mydev, const struct hexdata *hexdata) unsigned int j = 0; int ret; int finished = 0; + const char *v = hexdata->version_info; + v = (v[0]) ? v : "Unknown"; assert(mydev != NULL); - if(verbose >= LOG_INFO) - INFO("Start...\n"); + INFO("FPGA_LOAD (version %s)\n", v); /* * i - is the line number * j - is the sequence number, on USB 2, i=j, but on @@ -561,8 +570,7 @@ int fpga_load(struct my_usb_device *mydev, const struct hexdata *hexdata) return 0; } if(hexline->d.content.header.tt == TT_EOF) { - if(verbose >= LOG_INFO) - INFO("End of data\n"); + DBG("End of data\n"); finished = 1; continue; } @@ -579,8 +587,7 @@ int fpga_load(struct my_usb_device *mydev, const struct hexdata *hexdata) j += ret; } } - if(verbose >= LOG_INFO) - INFO("Finished...\n"); + DBG("Finished...\n"); return 1; } @@ -731,8 +738,7 @@ int main(int argc, char *argv[]) if(vendor || product || release || serial || source ) opt_read_eeprom = opt_write_eeprom = 1; #endif - if(verbose >= LOG_INFO) - INFO("Startup %s\n", devpath); + DBG("Startup %s\n", devpath); if(!my_usb_device_init(devpath, &mydev)) { ERR("Failed to initialize USB device '%s'\n", devpath); @@ -792,8 +798,7 @@ int main(int argc, char *argv[]) show_device_info(&mydev); } #endif - if(verbose >= LOG_INFO) - INFO("Exiting\n"); + DBG("Exiting\n"); dev_err: my_usb_device_cleanup(&mydev); return ret; diff --git a/xpp/utils/genzaptelconf b/xpp/utils/genzaptelconf index a5fb0b0..c5dedd4 100755 --- a/xpp/utils/genzaptelconf +++ b/xpp/utils/genzaptelconf @@ -37,6 +37,9 @@ VERSION=0.5.8 rcsid='$Id$' lc_country=us +# set to: ls, ks or gs for (Loopstart, Kewlstart and GroundStart) +# on FXS channels (FXO signalling). +fxs_default_start=ls base_exten=6000 # If set: no context changes are made in zapata-channels.conf #context_manual=yes @@ -267,17 +270,22 @@ print_pattern() { local chan=$1 local sig=$2 #fxs/fxo local mode=$3 - local method='ks' - - # Coutries in which we need to use busydetect: - # United Arab Emirats, Israel, Slovenia - case "$lc_country" in - ae|il|si) - if [ "$sig" = 'fxs' ]; then + local method + + if [ "$sig" = 'fxs' ]; then + # Coutries in which we need to use busydetect: + # United Arab Emirats, Israel, Slovenia + case "$lc_country" in + ae|il|si) method=ls - fi - ;; - esac + ;; + *) + method=ks + ;; + esac + else + method="$fxs_default_start" + fi case "$mode" in list) case "$sig" in diff --git a/xpp/utils/hexfile.c b/xpp/utils/hexfile.c index f6e4149..a4b12c5 100644 --- a/xpp/utils/hexfile.c +++ b/xpp/utils/hexfile.c @@ -57,6 +57,38 @@ int checksum(struct hexline *hexline) return chksm & 0xFF; } +int dump_hexline(int recordno, struct hexline *line, FILE *outfile) +{ + uint8_t ll; + uint16_t offset; + uint8_t tt; + uint8_t old_chksum; + uint8_t new_chksum; + uint8_t *data; + unsigned int i; + + ll = line->d.content.header.ll; + offset = line->d.content.header.offset; + tt = line->d.content.header.tt; + fprintf(outfile, ":%02X%04X%02X", ll, offset, tt); + data = line->d.content.tt_data.data; + for(i = 0; i < ll; i++) { + fprintf(outfile, "%02X", data[i]); + } + old_chksum = data[ll]; + data[ll] = 0; + new_chksum = 0xFF - checksum(line) + 1; + data[ll] = old_chksum; + fprintf(outfile, "%02X\n", new_chksum); + if(new_chksum != old_chksum) { + if(report_func) + report_func(LOG_ERR, "record #%d: new_chksum(%02X) != old_chksum(%02X)\n", + recordno, new_chksum, old_chksum); + return 0; + } + return 1; +} + static int update_hexline(struct hexdata *hexdata, char *buf) { int ret; @@ -142,8 +174,10 @@ static int update_hexline(struct hexdata *hexdata, char *buf) } hexline->d.content.header.ll--; /* Fix the checksum */ if(checksum(hexline) != 0) { - if(report_func) - report_func(LOG_ERR, "Bad checksum\n"); + if(report_func) { + report_func(LOG_ERR, "Bad checksum (%d instead of 0)\n", checksum(hexline)); + dump_hexline(last_line, hexline, stderr); + } return -EINVAL; } if(hexdata->got_eof) @@ -166,14 +200,7 @@ void free_hexdata(struct hexdata *hexdata) int dump_hexfile(struct hexdata *hexdata, FILE *outfile) { - uint8_t ll; - uint16_t offset; - uint8_t tt; - uint8_t old_chksum; - uint8_t new_chksum; - uint8_t *data; unsigned int i; - unsigned int j; for(i = 0; i <= hexdata->last_line; i++) { struct hexline *line = hexdata->lines[i]; @@ -182,20 +209,8 @@ int dump_hexfile(struct hexdata *hexdata, FILE *outfile) report_func(LOG_ERR, "Missing line at #%d\n", i); return -EINVAL; } - ll = line->d.content.header.ll; - offset = line->d.content.header.offset; - tt = line->d.content.header.tt; - fprintf(outfile, ":%02X%04X%02X", ll, offset, tt); - data = line->d.content.tt_data.data; - for(j = 0; j < ll; j++) { - fprintf(outfile, "%02X", data[j]); - } - old_chksum = data[ll]; - data[ll] = 0; - new_chksum = 0xFF - checksum(line) + 1; - data[ll] = old_chksum; - assert(new_chksum == old_chksum); - fprintf(outfile, "%02X\n", new_chksum); + if(!dump_hexline(i, line, outfile)) + return -EINVAL; } return 0; } @@ -299,8 +314,18 @@ struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines) } chomp(buf); if(buf[0] == '#') { + char *dollar_start; + char *dollar_end; + if(report_func) - report_func(LOG_INFO, "Comment '%s'\n", buf + 1); + report_func(LOG_INFO, "Comment: %s\n", buf + 1); + /* Search for RCS keywords */ + if((dollar_start = strchr(buf, '$')) == NULL) + continue; + if((dollar_end = strchr(dollar_start + 1, '$')) == NULL) + continue; + *(dollar_end + 1) = '\0'; + strncpy(hexdata->version_info, dollar_start, BUFSIZ - 1); continue; } if(buf[0] != ':') { diff --git a/xpp/utils/hexfile.h b/xpp/utils/hexfile.h index c7f5df0..4c6e689 100644 --- a/xpp/utils/hexfile.h +++ b/xpp/utils/hexfile.h @@ -101,6 +101,7 @@ struct hexdata { unsigned int maxlines; unsigned int last_line; int got_eof; + char version_info[BUFSIZ]; struct hexline *lines[ZERO_SIZE]; }; diff --git a/xpp/utils/lszaptel b/xpp/utils/lszaptel new file mode 100755 index 0000000..af11b6e --- /dev/null +++ b/xpp/utils/lszaptel @@ -0,0 +1,54 @@ +#! /usr/bin/perl -w +# +# 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. +# +#use strict; +BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); } + +use Zaptel; +use Zaptel::Span; + +foreach my $span (Zaptel::spans()) { + printf "### Span %2d: %s %s\n", $span->num, $span->name, $span->description; + foreach my $chan ($span->chans()) { + my %type_map = ( + OUT => 'Output', + IN => 'Input' + ); + my ($type) = map { $type_map{$_} or $_ } $chan->type; + printf "%3d %s\n", $chan->num, $type; + } +} + +__END__ + +=head1 NAME + +lszaptel - List all zaptel channels with their types and spans. + +=head1 SYNOPSIS + +lszaptel + +=head1 DESCRIPTION + +Example output: + + ### Span 1: XBUS-03/XPD-00 "Xorcom XPD #3/0: FXS" + 1 FXS + 2 FXS + 3 FXS + 4 FXS + 5 FXS + 6 FXS + 7 FXS + 8 FXS + 9 Output + 10 Output + 11 Input + 12 Input + 13 Input + 14 Input diff --git a/xpp/utils/test_parse.c b/xpp/utils/test_parse.c index bdcdea7..c98ca83 100644 --- a/xpp/utils/test_parse.c +++ b/xpp/utils/test_parse.c @@ -27,6 +27,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "Parsing failed\n"); return 1; } + fprintf(stderr, "=== %s === (version: %s)\n", argv[i], hd->version_info); dump_hexfile2(hd, stdout, 60 ); free_hexdata(hd); } diff --git a/xpp/utils/xpp_fxloader b/xpp/utils/xpp_fxloader index 918a712..3d200e8 100644 --- a/xpp/utils/xpp_fxloader +++ b/xpp/utils/xpp_fxloader @@ -136,7 +136,7 @@ load_fpga() { card_ver=`$FPGA_LOAD -g -D $dev | sed -n 's/^.*Release: *//'` firm_ver=`hexfile_version $FIRMWARE_DIR/$fw` - $LOGGER "FPGA Firmware $FIRMWARE_DIR/$fw into $dev" + $LOGGER "FPGA Firmware $FIRMWARE_DIR/$fw (version: $firm_ver) into $dev" sleep_if_race $FPGA_LOAD -D "$dev" -I "$FIRMWARE_DIR/$fw" 2>&1 >/dev/null | $LOGGER status=$PIPESTATUS diff --git a/xpp/utils/xpp_sync b/xpp/utils/xpp_sync new file mode 100755 index 0000000..018d268 --- /dev/null +++ b/xpp/utils/xpp_sync @@ -0,0 +1,152 @@ +#! /usr/bin/perl -w +# +# 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. +# +#use strict; +BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); } + +use Zaptel::Xpp; +use Zaptel::Xpp::Xbus; + +my $sync; +my $autoselect; + +if(@ARGV == 1) { + $sync = shift; + $autoselect = 1 if $sync =~ /^auto$/i; +} + +sub get_sorted_xpds() { + my @good_xpds; + + foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) { + next unless $xbus->status eq 'CONNECTED'; + foreach my $xpd ($xbus->xpds()) { + my $isreg = $xpd->zt_registration(); + if(!defined($isreg)) { # Failure + printf STDERR "%s: Failed %s\n", $xpd->fqn, $!; + next; + } + next unless $isreg; # Skip unregistered XPDs + push(@good_xpds, $xpd); + } + } + + my @bri_xpds = grep { $_->type =~ /BRI/; } @good_xpds; + my @fxo_xpds = grep { $_->type eq 'FXO'; } @good_xpds; + my @fxs_xpds = grep { $_->type eq 'FXS'; } @good_xpds; + return (@bri_xpds, @fxo_xpds, @fxs_xpds); +} + +sub do_select(@) { + my $found; + + foreach my $xpd (@_) { + my $xbus = $xpd->xbus; + my $busnum = $xbus->name; + die "Uknown bus name" unless $busnum; + $busnum =~ s/XBUS-//; + die "bad bus name" unless $busnum =~ /^\d+$/; + #printf "Setting sync: %-10s (%s)\n", $xpd->fqn, $xpd->type; + if(Zaptel::Xpp::sync($busnum)) { + #print "SET $busnum\n"; + $found = 1; + last; + } else { + print STDERR "Failed to set $busnum: $!\n"; + } + } + if(!$found) { + print STDERR "Fall back to HOST sync\n"; + die "Failed to set HOST sync\n" unless Zaptel::Xpp::sync('HOST'); + } +} + +sub do_set($) { + my $sync = shift; + die "Failed to set sync to '$sync'" unless Zaptel::Xpp::sync($sync); +} + +my $curr_sync = Zaptel::Xpp::sync; +my %xbus_seen; +my @sorted_xpds = grep { !$xbus_seen{$_->xbus}++; } get_sorted_xpds; +if($sync) { + if($autoselect) { + do_select(@sorted_xpds); + } else { + $sync = uc($sync); + do_set($sync); + } + #print "New sync: ", Zaptel::Xpp::sync, "\n"; +} else { + print "Current sync: ", $curr_sync, "\n"; + print "Best Available Syncers:\n"; + foreach my $xpd (@sorted_xpds) { + my $xbus = $xpd->xbus; + my @xpds = $xbus->xpds; + my @types = map { $_->type } @xpds; + my $mark = ($curr_sync =~ /\d+/ and $xbus->num == $curr_sync)?"+":""; + printf "\t%1s %s [ ", $mark, $xbus->name; + my $next = 0; + foreach my $x (sort { $a->num <=> $b->num } @xpds) { + my $n = $x->num; + # Fill spaces + for(my $i = $next; $i < $n; $i++) { + printf "%-3s ", ""; + } + printf "%-3s ", $x->type; + $next = $n + 1; + } + # Fill spaces to end + $n = 4; + for(my $i = $next; $i < $n; $i++) { + printf "%-3s ", ""; + } + printf "] (%s)\n", $xbus->connector; + } +} + +__END__ + +=head1 NAME + +xpp_sync - Handle sync selection of Xorcom XPD's. + +=head1 SYNOPSIS + +xpp_sync [auto|host|nn] + +=head1 DESCRIPTION + +Without parameters, the current syncer. Either HOST or the XBUS number. +Then a list of the 3 best XPD's for syncing. + +=head2 Parameters + +=over + +=item auto + +Automatically selects the best XPD for syncing (with HOST fallback). + +=item host + +Set HOST synchronization (XPP timers). + +=item nn + +Set XBUS number nn as sync source. + +=back + +=head2 Example output: + + Current sync: 03 + Best Available Syncers: + XBUS-00: FXS FXO (USB-0000:00:10.4-4) + + XBUS-03: FXS FXS FXS FXS (USB-0000:00:10.4-1) + XBUS-02: FXS FXS FXS FXS (USB-0000:00:10.4-2) + XBUS-01: FXS FXS FXS FXS (USB-0000:00:10.4-3) diff --git a/xpp/utils/zconf/Zaptel.pm b/xpp/utils/zconf/Zaptel.pm new file mode 100644 index 0000000..394aa8e --- /dev/null +++ b/xpp/utils/zconf/Zaptel.pm @@ -0,0 +1,24 @@ +package Zaptel; +# +# 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. +# +#use strict; + +my $proc_base = "/proc/zaptel"; + +sub spans() { + my @spans; + + -d $proc_base or die "Missing '$proc_base'. Perhaps zaptel module isn't loaded?\n"; + foreach my $zfile (glob "$proc_base/*") { + $zfile =~ s:$proc_base/::; + my $span = Zaptel::Span->new($zfile); + push(@spans, $span); + } + return sort { $a->num <=> $b->num } @spans; +} + +1; diff --git a/xpp/utils/zconf/Zaptel/Chans.pm b/xpp/utils/zconf/Zaptel/Chans.pm new file mode 100644 index 0000000..31bc5f7 --- /dev/null +++ b/xpp/utils/zconf/Zaptel/Chans.pm @@ -0,0 +1,46 @@ +package Zaptel::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. +# +#use strict; + +# Accessors (miniperl does not have Class:Accessor) +sub AUTOLOAD { + my $self = shift; + my $name = uc($AUTOLOAD); + $name =~ s/.*://; # strip fully-qualified portion + if (@_) { + return $self->{$name} = shift; + } else { + return $self->{$name}; + } +} + +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 $num = shift or die "Missing a channel number parameter\n"; + my $fqn = shift or die "Missing a channel fqn parameter\n"; + my $info = shift; + my $self = {}; + bless $self, $pack; + $self->span($span); + $self->num($num); + $self->fqn($fqn); + $self->info($info); + my $type; + if($fqn =~ m|\bXPP_(\w+)/.*$|) { + $type = $1; # One of our AB + } elsif(defined $info) { + $type = (split(/\s+/, $info))[0]; + } else { + $type = $fqn; + } + $self->type($type); + return $self; +} + +1; diff --git a/xpp/utils/zconf/Zaptel/Span.pm b/xpp/utils/zconf/Zaptel/Span.pm new file mode 100644 index 0000000..08ebae2 --- /dev/null +++ b/xpp/utils/zconf/Zaptel/Span.pm @@ -0,0 +1,53 @@ +package Zaptel::Span; +# +# 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. +# +#use strict; +use Zaptel::Chans; + +my $proc_base = "/proc/zaptel"; + +sub chans($) { + my $span = shift; + return @{$span->{CHANS}}; +} + +# Accessors (miniperl does not have Class:Accessor) +sub AUTOLOAD { + my $self = shift; + my $name = uc($AUTOLOAD); + $name =~ s/.*://; # strip fully-qualified portion + if (@_) { + return $self->{$name} = shift; + } else { + return $self->{$name}; + } +} + +sub new($$) { + my $pack = shift or die "Wasn't called as a class method\n"; + my $num = shift or die "Missing a span number parameter\n"; + my $self = { NUM => $num }; + bless $self, $pack; + open(F, "$proc_base/$num") or die "Failed to open '$proc_base/$num\n"; + my $head = <F>; + chomp $head; + ($self->{NAME}, $self->{DESCRIPTION}) = (split(/\s+/, $head, 4))[2, 3]; + $self->{CHANS} = []; + while(<F>) { + chomp; + s/^\s*//; + s/\s*$//; + next unless /\S/; + my ($chan, $name, $info) = split(/\s+/, $_, 3); + my $c = Zaptel::Chans->new($self, $chan, $name, $info); + push(@{$self->{CHANS}}, $c); + } + close F; + return $self; +} + +1; diff --git a/xpp/utils/zconf/Zaptel/Xpp.pm b/xpp/utils/zconf/Zaptel/Xpp.pm new file mode 100644 index 0000000..b627438 --- /dev/null +++ b/xpp/utils/zconf/Zaptel/Xpp.pm @@ -0,0 +1,88 @@ +package Zaptel::Xpp; +# +# 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. +# +#use strict; +use Zaptel::Xpp::Xbus; + +my $proc_base = "/proc/xpp"; + +# Static Functions + +# Nominal sorters for xbuses +sub by_name { + return $a cmp $b; +} + +sub by_connector { + return $a->connector cmp $b->connector; +} + +sub xbuses { + my $optsort = shift || 'SORT_NAME'; + my @xbuses; + + open(F, "$proc_base/xbuses") || + die "$0: Failed to open $proc_base/xbuses. xpp module is loaded?\n"; + while(<F>) { + chomp; + my ($name, @attr) = split; + $name =~ s/://; + $name =~ /XBUS-(\d\d)/ or die "Bad XBUS number: $name"; + my $num = $1; + @attr = map { $_ = uc($_); split(/=/); } @attr; + my $xbus = Zaptel::Xpp::Xbus->new(NAME => $name, NUM => $num, @attr); + push(@xbuses, $xbus); + } + close F; + my $sorter; + if($optsort eq "SORT_CONNECTOR") { + $sorter = \&by_connector; + } elsif($optsort eq "SORT_NAME") { + $sorter = \&by_name; + } elsif(ref($optsort) eq 'CODE') { + $sorter = $optsort; + } else { + die "Unknown optional sorter '$optsort'"; + } + return sort $sorter @xbuses; +} + +sub sync { + my $newsync = shift; + my $result; + my $newapi = 0; + + my $file = "$proc_base/sync"; + die "$file is missing" unless -f $file; + # First query + open(F, "$file") or die "Failed to open $file for reading: $!"; + while(<F>) { + chomp; + /SYNC=/ and $newapi = 1; + s/#.*//; + if(/\S/) { # First non-comment line + s/^SYNC=\D*// if $newapi; + $result = $_; + last; + } + } + close F; + if(defined($newsync)) { # Now change + open(F, ">$file") or die "Failed to open $file for writing: $!"; + if($newsync eq 'HOST') { + print F "HOST"; + } elsif($newsync =~ /^(\d+)$/) { + print F ($newapi)? "SYNC=$1" : "$1 0"; + } else { + die "Bad sync parameter '$newsync'"; + } + close(F) or die "Failed in closing $file: $!"; + } + return $result; +} + +1; diff --git a/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm b/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm new file mode 100644 index 0000000..8d9d340 --- /dev/null +++ b/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm @@ -0,0 +1,51 @@ +package Zaptel::Xpp::Xbus; +# +# 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. +# +#use strict; +use Zaptel::Xpp::Xpd; + +my $proc_base = "/proc/xpp"; + +# Accessors (miniperl does not have Class:Accessor) +sub AUTOLOAD { + my $self = shift; + my $name = uc($AUTOLOAD); + $name =~ s/.*://; # strip fully-qualified portion + if (@_) { + return $self->{$name} = shift; + } else { + return $self->{$name}; + } +} + +sub xpds($) { + my $xbus = shift; + return @{$xbus->{XPDS}}; +} + +sub new($$) { + my $pack = shift or die "Wasn't called as a class method\n"; + my $self = { @_ }; + bless $self, $pack; + $self->{NAME} or die "Missing xbus name"; + my $prefix = "$proc_base/" . $self->{NAME}; + @{$self->{XPDS}} = (); + foreach my $fqn (glob "$prefix/XPD-??") { + $fqn =~ s:$proc_base/::; + $fqn =~ /(\d+)$/; + my $num = $1; + my $xpd = Zaptel::Xpp::Xpd->new( + FQN => $fqn, + NUM =>, $num, + XBUS => $self + ); + push(@{$self->{XPDS}}, $xpd); + } + return $self; +} + +1; diff --git a/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm b/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm new file mode 100644 index 0000000..180b7ea --- /dev/null +++ b/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm @@ -0,0 +1,64 @@ +package Zaptel::Xpp::Xpd; +# +# 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. +# +#use strict; + +my $proc_base = "/proc/xpp"; + +# Accessors (miniperl does not have Class:Accessor) +sub AUTOLOAD { + my $self = shift; + my $name = uc($AUTOLOAD); + $name =~ s/.*://; # strip fully-qualified portion + if (@_) { + return $self->{$name} = shift; + } else { + return $self->{$name}; + } +} + +sub zt_registration($$) { + my $self = shift; + my $on = shift; + my $result; + + my $file = "$proc_base/" . $self->fqn . "/zt_registration"; + die "$file is missing" unless -f $file; + # First query + open(F, "$file") or die "Failed to open $file for reading: $!"; + $result = <F>; + chomp $result; + close F; + if(defined($on) and $on ne $result) { # Now change + open(F, ">$file") or die "Failed to open $file for writing: $!"; + print F ($on)?"1":"0"; + if(!close(F)) { + if($! == 17) { # EEXISTS + # good + } else { + undef $result; + } + } + } + return $result; +} + +sub new($$) { + my $pack = shift or die "Wasn't called as a class method\n"; + my $self = { @_ }; + bless $self, $pack; + my $dir = "$proc_base/" . $self->fqn; + $self->{DIR} = $dir; + my ($name) = glob "$dir/*_info"; + die "Missing info file in $dir" unless $name; + $name =~ s|^.*/||; # basename + die "Bad info file name ($name) in $dir" if $name !~ /(\w+)_info/; + $self->{TYPE} = uc($1); + return $self; +} + +1; diff --git a/xpp/utils/zt_registration b/xpp/utils/zt_registration new file mode 100755 index 0000000..6ed388f --- /dev/null +++ b/xpp/utils/zt_registration @@ -0,0 +1,77 @@ +#! /usr/bin/perl -w +# +# 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. +# +#use strict; +BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); } + +use Zaptel; +use Zaptel::Span; +use Zaptel::Xpp; +use Zaptel::Xpp::Xbus; + +sub usage { + die "Usage: $0 [on|off|1|0]\n"; +} + +@ARGV == 0 or @ARGV == 1 or usage; +my $on = shift; + +if(defined($on)) { # Translate to booleans + $on = uc($on); + $on =~ /^(ON|OFF|1|0)$/ or usage; + $on = ($on eq 'ON') ? 1 : 0; +} + +sub state2str($) { + return (shift)?"on":"off"; +} + +my @spans = Zaptel::spans; + +foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) { + printf "%-10s\t\t%s\n", $xbus->name, $xbus->connector; + next unless $xbus->status eq 'CONNECTED'; + foreach my $xpd ($xbus->xpds()) { + my $prev = $xpd->zt_registration($on); + printf "\t%-10s: ", $xpd->fqn; + if(!defined($on)) { # Query only + my ($span) = grep { $_->name eq $xpd->fqn } @spans; + my $spanstr = ($span) ? ("Span " . $span->num) : ""; + printf "%s %s\n", state2str($prev), $spanstr; + next; + } + if(!defined($prev)) { # Failure + printf "Failed %s\n", $!; + next; + } + printf("%3s ==> %3s\n", state2str($prev), state2str($on)); + } +} + +__END__ + +=head1 NAME + +zt_registration - Handle registration of Xorcom XPD modules in zaptel. + +=head1 SYNOPSIS + +zt_registration [on|off] + +=head1 DESCRIPTION + +Without parameters, show all connected XPD's sorted by physical connector order. +Each one is show to be unregistered (off), or registered to a specific zaptel span +(the span number is shown). + +All registerations/deregisterations are sorted by physical connector string. + +=head2 Parameters + +off -- deregisters all XPD's from zaptel. + +on -- registers all XPD's to zaptel. |