From 507a085a24b4f58585b632b17117cbe6451754f7 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Sun, 29 Apr 2007 22:12:49 +0000 Subject: xpp rev. 3814: * Protocol no. 2.6: syncing improvements. * Support for 8-port Astribank BRI. * Firmware unloading now works: rmmod xpp_usb; /etc/hotplug/usb/xpp_fxloader reset * Defaults of kernel parameters are now part of parameter description. * World-readable kernel parameters. * No need for extra patch beyond bristuff for Astribank BRI. * Default poll intervals changed: 500 in BRI and FXO. * Allow changing FXS polls interval at run time. * BRI initalization fixed on SUSE (path to logger). * When using the SUSE zaptel rpm package, set modules_var=ZAPTEL_MODULES in /etc/sysconfig/zaptel . * zt_registration not verbose by default. * xpp_sync warns if FXO is sync slave. * Fixed genzaptelconf -z (zapscan output emulation). * PCM fixes. * Solves "multiple ticks" bug. No need for pcm_tasklets workaround. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@2477 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- xpp/utils/Makefile | 17 +- xpp/utils/adj_clock.8 | 144 --------- xpp/utils/adj_clock.c | 228 -------------- xpp/utils/fpga_load.8 | 22 +- xpp/utils/fpga_load.c | 217 ++++++------- xpp/utils/genzaptelconf | 604 +++++++++++++++++++++---------------- xpp/utils/genzaptelconf.8 | 12 +- xpp/utils/hexfile.c | 74 ++++- xpp/utils/hexfile.h | 1 + xpp/utils/lszaptel | 4 +- xpp/utils/xpp_blink | 115 +++++++ xpp/utils/xpp_fxloader | 34 ++- xpp/utils/xpp_sync | 42 ++- xpp/utils/zconf/Zaptel.pm | 5 +- xpp/utils/zconf/Zaptel/Chans.pm | 38 ++- xpp/utils/zconf/Zaptel/Span.pm | 58 +++- xpp/utils/zconf/Zaptel/Xpp.pm | 17 +- xpp/utils/zconf/Zaptel/Xpp/Xbus.pm | 36 ++- xpp/utils/zconf/Zaptel/Xpp/Xpd.pm | 31 +- xpp/utils/zt_registration | 19 +- 20 files changed, 930 insertions(+), 788 deletions(-) delete mode 100644 xpp/utils/adj_clock.8 delete mode 100644 xpp/utils/adj_clock.c create mode 100755 xpp/utils/xpp_blink (limited to 'xpp/utils') diff --git a/xpp/utils/Makefile b/xpp/utils/Makefile index a49818b..96b37db 100644 --- a/xpp/utils/Makefile +++ b/xpp/utils/Makefile @@ -46,12 +46,12 @@ 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 +PERL_SCRIPTS = zt_registration xpp_sync lszaptel xpp_blink +PERL_MANS = $(PERL_SCRIPTS:%=%.8) -TARGETS = init_fxo_modes print_modes adj_clock -PROG_INSTALL = genzaptelconf adj_clock -MAN_INSTALL = genzaptelconf.8 adj_clock.8 +TARGETS = init_fxo_modes print_modes +PROG_INSTALL = genzaptelconf +MAN_INSTALL = genzaptelconf.8 ifeq (1,$(PBX_LIBUSB)) TARGETS += libhexfile.a fpga_load test_parse PROG_INSTALL += fpga_load @@ -60,17 +60,14 @@ endif ifneq (,$(PERLLIBDIR)) PROG_INSTALL += $(PERL_SCRIPTS) MAN_INSTALL += $(PERL_MANS) +TARGETS += $(PERL_MANS) endif all: $(TARGETS) 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: all $(INSTALL) -d $(DESTDIR)$(SBINDIR) $(INSTALL) $(PROG_INSTALL) $(DESTDIR)$(SBINDIR)/ $(INSTALL) -d $(DESTDIR)$(DATADIR) diff --git a/xpp/utils/adj_clock.8 b/xpp/utils/adj_clock.8 deleted file mode 100644 index 0e9cf71..0000000 --- a/xpp/utils/adj_clock.8 +++ /dev/null @@ -1,144 +0,0 @@ -." $Id:$ -.TH adj_clock 8 "2006-10-18" -.SH "NAME" -adj_clock \(em Synchronize system clock to zaptel clock -.SH "SYNOPSIS" -.B adj_clock -.I [ -c -.B count -.I ] [ -i -.B interval -.I ] [ -t -.B period -.I ] [ -v ] - -.SH "DESCRIPTION" -.B adj_clock -compares synchronizes the system clock from Zaptel's clock: in each cycle -It will read 1024 * -.B interval -ticks from a Zaptel pseudo channel, which should take exactly -.B interval -seconds. It measures the time it did take, and uses -.I adjtimex(3) -to fix the system clock accordingly. - -Note that NTP servers usually use adjtimex. You may get strange behaviour -if you have a NTP server (such as ntpd(8)) running on the system. - -Output is sent to both the standard error and to the syslog. Syslog -messages are with facility daemon. - -.SH OPTIONS -.I -c -.B count -.RS -Run just -.B count -synchronization cycles. Default is to run forever. -.RE - -.I -i -.B interval -.RS -Loop interval (in seconds). Optional, as program should provide a sane value. - -Small values allow faster synchronization when the system is quiet. Even -a value as low as 10 should work. However they are much more suspectable -to short interruptions. - -.RE - -.I -t -.B period -.RS -Set the synchronization tolerance priod (micro-seconds). The default -is 100. Don't touch it unless you know what you're doing. -.RE - -.I -v -.RS -Be more verbose: log status messages even when synchronized. -.RE - -.SH FILES -.B /dev/zap/pseudo -.RS -.RE -The device file used to open a "pseudo" channel (a channels that -constantly streams voice and is synchronized by the master Zaptel -device). - -.SH SYNCHRONIZATION -Some more technical details. This explains the strange numbers the -program prints. - -In each cycle -.B adj_clock -measures -.B interval -seconds using Zaptel ticks. It then compares that to the system time -from gettimeofday(2). It then calls adjtimex(2) to slightly change the -rate of the system clock. It uses two parameters: -.B ticks, -which is a more -coarse one (1 tick will give roughly a change of rate of 9 seconds per -day) and -.I frequency, -which allows much finer settings. - -The program tries to set what it can by ticks, and the rest through -frequency. It considers itself "synchronized" when the rate difference -is small enough so -.I (a) -It does not have to use ticks anymore. And -.I (b) -The rest of the interval to change is smaller than the tolerance period -(100 micro-seconds, by default). - -The meaning of the parameters it prints is, thus: - -.I interval -.RS -The current interval parameter (seconds). -.RE - -.I diff_tick -.RS -The number of ticks it tries to set through adjtimex(2). -Anything different than 0 means we're still way off mark. -.RE - -.I diff_usec -.RS -The time difference (micro-seconds) that we need to overcome in the -first place. This is the difference between the system clock and the -measured zaptel clock. -.RE - -.I usec_left -.RS -How much of this difference (microseconds) we still need to adjust -after using ticks. This should be low enough (less than the tolerance -period). -.RE - -.SH SIGNALS -.B adj_clock -is so far an interactive program, and thus killed by SIGHUP. SIGUSR is -used to increase verbosity level and SIGUSR2 is used to reset verbosity -level to 0. When SIGUSR1 is recieved a status message will also be sent -to the logs. - -.SH SEE ALSO -ztcfg(8), zttest(8), adjtimex(2), gettimeofday(2), adjtimex(8) - -.SH AUTHOR - -This manual page was written by Tzafrir Cohen -Permission is granted to copy, distribute and/or modify this document under -the terms of the GNU General Public License, Version 2 any -later version published by the Free Software Foundation. - -On Debian systems, the complete text of the GNU General Public -License can be found in /usr/share/common-licenses/GPL. diff --git a/xpp/utils/adj_clock.c b/xpp/utils/adj_clock.c deleted file mode 100644 index 6dfa483..0000000 --- a/xpp/utils/adj_clock.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Written by Tzafrir Cohen - * Copyright (C) 2006, Xorcom - * - * Derived from zttest.c - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const char *rcsid = "$Id$"; - -#define FREQ_PER_TICK (64*1024) -#define USEC_PER_ZAP_TICK 1000 /* Zaptel tick in usec */ -#define USER_HZ 100 -#define SYNC_TOLERANCE 100 -#define DEFAULT_INTERVAL 60 - -static const char *program; -static int synced_time; /* time (seconds) we are so far synced */ -static int verbose = 0; -static int sync_tolerance = 100; - -void usage() { - fprintf(stderr, "%s: synchronize system clock from zaptel clock.\n" - "Version: %s\n" - "\n" - "Usage: %s [ -c COUNT ] [-i INTERVAL] [ -t PERIOD ] [-v]\n" - " %s -h\n" - "\n" - "Options:\n" - " -c only run COUNT cycles of synchronization (default: forever).\n" - " -i set cycle Interval to INTERVAL (in seconds. Default: %d).\n" - " -t sync tolerance to PERIOD (in usec. Default: %d). For debugging.\n" - " -v Be more Verbose\n" - " -h Print this Help text and exit.\n" - "", program, rcsid, program, program, DEFAULT_INTERVAL, - sync_tolerance); -} - -/* based on zttest.c */ - -/* - * Print a message to the log according to the value of synced_time - * - * All parameters are for the "Not Synced" warning message. - * TODO: Find a better way. - */ -void status_message(void) { - if (synced_time == 0) - syslog(LOG_NOTICE, "Not Synced.\n"); - else - syslog(LOG_INFO, "Good Sync for %d seconds\n", synced_time); - - return; -} - -/* - * interval: period, in seconds - * diff_usec: Current offset, in micro-seconds. - */ -int clock_sync(int interval, int diff_usec) -{ - struct timex cur_time = {.modes=0}; /* just query */ - int diff_tick; /* Difference in adjtimex ticks */ - int req_tick; /* Required adjtimex tick value */ - long long diff_freq; - long long req_freq; - int usec_left; /* Usec adjusted by frequency */ - int ret; - - ret = adjtimex(&cur_time); - - diff_tick = diff_usec / (interval * USER_HZ); - usec_left = diff_usec - diff_tick * (interval * USER_HZ); - diff_freq = usec_left * FREQ_PER_TICK / interval; - - req_tick = cur_time.tick - diff_tick; - req_freq = cur_time.freq - diff_freq; - - if(!diff_tick && abs(usec_left) < sync_tolerance) - synced_time += interval; - else - synced_time = 0; - status_message(); - if (verbose || !synced_time) - syslog(LOG_INFO, "interval: %d, diff_tick: %d, diff_usec: %d, usec_left: %d.\n", - interval, diff_tick, diff_usec, usec_left); - - /* set the clock rate */ - cur_time.freq = req_freq; - cur_time.tick = req_tick; - cur_time.modes = ADJ_TICK | ADJ_FREQUENCY; - ret = adjtimex(&cur_time); - if (ret < 0) - syslog(LOG_ERR, "Adjtimex failed to set frequency. New frequency: %lld. Error: %d (%s)\n", - req_freq, errno, strerror(errno)); - return 0; -} - -static int pass = 0; - -void hup_handler(int sig) -{ - if (verbose > 0) { - syslog(LOG_INFO, "--- Results after %d passes ---\n", pass); - status_message(); - } - closelog(); - exit(0); -} - -void sigusr1_handler(int sig) { - verbose++; - syslog(LOG_INFO, "Increased verbosity to %d (increase: SIGUSR1, reset: SIGUSR2).\n", verbose); - status_message(); -} - -void sigusr2_handler(int sig) { - verbose = 0; - syslog(LOG_INFO, "Set verbosity to 0 (increase: SIGUSR1, reset: SIGUSR2).\n"); -} - -void sync_cycle(int fd, int interval) -{ - char buf[1024]; /* TODO: why 1024 and not 1000? */ - struct timeval start; - struct timeval end; - long long usec; - int count = 0; - int i; - int res; - - gettimeofday(&start, NULL); - for (i=0; i < interval*8; i++) { - res = read(fd, buf, sizeof(buf)); - if (res < 0) { - syslog(LOG_ERR, "Failed to read from pseudo interface: %s\n", strerror(errno)); - exit(1); - } - count += res/8; - } - gettimeofday(&end, NULL); - - /* time difference in microseconds: */ - usec = (end.tv_sec - start.tv_sec) * 1000000; - usec += end.tv_usec - start.tv_usec; - - clock_sync(interval, usec - (count * USEC_PER_ZAP_TICK)); - - pass++; -} - -int main(int argc, char *argv[]) -{ - int fd; - int opt; - int interval = DEFAULT_INTERVAL; - int cycles_to_run = 0; - int i; - - program = argv[0]; - while((opt = getopt(argc, argv, "c:hi:t:v")) != -1) { - switch (opt) { - case 'h': usage(); exit(0); break; - case 'c': cycles_to_run = atoi(optarg); break; - case 'i': interval = atoi(optarg); break; /* number of seconds */ - case 't': sync_tolerance = atoi(optarg); break; /* usec */ - case 'v': verbose++; break; - default: - fprintf(stderr, "%s: Unknown option: %c. Aborting\n", argv[0], opt); - usage(); - exit(1); - } - } - - openlog(program, LOG_PERROR | LOG_PID, LOG_DAEMON); - fd = open("/dev/zap/pseudo", O_RDWR); - if (fd < 0) { - fprintf(stderr, "Unable to open zap interface: %s\n", strerror(errno)); - exit(1); - } - if (verbose >=1) - syslog(LOG_INFO, "Opened pseudo zap interface, measuring accuracy...\n"); - - signal(SIGHUP, hup_handler); - signal(SIGINT, hup_handler); - signal(SIGUSR1, sigusr1_handler); - signal(SIGUSR2, sigusr2_handler); - - if (cycles_to_run > 0) { - for(i=0; i= LOG_ERR) \ - fprintf(stderr, "%s: ERROR: " fmt, \ - progname, ## arg); \ + fprintf(stderr, "%s: ERROR (%d): " fmt, \ + progname, __LINE__, ## arg); \ } while(0); #define INFO(fmt, arg...) do { \ if(verbose >= LOG_INFO) \ @@ -35,14 +35,15 @@ static char *progname; #define SERIAL_SIZE 8 enum fpga_load_packet_types { - STATUS_REPLY = 0x01, - DATA_PACKET = 0x01, + PT_STATUS_REPLY = 0x01, + PT_DATA_PACKET = 0x01, #ifdef XORCOM_INTERNAL - EEPROM_SET = 0x04, + PT_EEPROM_SET = 0x04, #endif - EEPROM_GET = 0x08, - RENUMERATE = 0x10, - BAD_COMMAND = 0xAA + PT_EEPROM_GET = 0x08, + PT_RENUMERATE = 0x10, + PT_RESET = 0x20, + PT_BAD_COMMAND = 0xAA }; struct myeeprom { @@ -173,8 +174,8 @@ int get_usb_string(char *buf, unsigned int len, uint16_t item, usb_dev_handle *h } /* My device parameters */ -#define MY_INTERFACE 0 #define MY_CONFIG 1 +#define MY_INTERFACE 0 #define MY_ENDPOINTS 4 #define MY_EP_OUT 0x04 @@ -186,10 +187,10 @@ int get_usb_string(char *buf, unsigned int len, uint16_t item, usb_dev_handle *h #define TIMEOUT 5000 static const int my_endpoints[MY_ENDPOINTS] = { - 0x02, - 0x04, - 0x86, - 0x88 + FPGA_EP_OUT, + MY_EP_OUT, + FPGA_EP_IN, + MY_EP_IN }; void my_usb_device_cleanup(struct my_usb_device *mydev) @@ -226,12 +227,47 @@ static void show_device_info(const struct my_usb_device *mydev) data[4], data[5], data[6], data[7]); } -void dump_packet(const char *buf, int len) +void dump_packet(const char *msg, const char *buf, int len) { int i; for(i = 0; i < len; i++) - INFO("dump: %2d> 0x%02X\n", i, (uint8_t)buf[i]); + INFO("%s: %2d> 0x%02X\n", msg, i, (uint8_t)buf[i]); +} + +int send_usb(const char *msg, struct my_usb_device *mydev, int endpoint, struct fpga_packet_header *phead, int len, int timeout) +{ + char *p = (char *)phead; + int ret; + + if(verbose >= LOG_DEBUG) + dump_packet(msg, p, len); + ret = usb_bulk_write(mydev->handle, endpoint, p, len, timeout); + if(ret < 0) { + ERR("bulk_write failed: %s\n", usb_strerror()); + dump_packet("send_usb[ERR]", p, len); + return ret; + } else if(ret != len) { + ERR("bulk_write short write: %s\n", usb_strerror()); + dump_packet("send_usb[ERR]", p, len); + return -EFAULT; + } + return ret; +} + +int recv_usb(const char *msg, struct my_usb_device *mydev, int endpoint, char *buf, size_t len, int timeout) +{ + int ret; + + if(verbose >= LOG_DEBUG) + dump_packet(msg, buf, len); + ret = usb_bulk_read(mydev->handle, endpoint, buf, len, timeout); + if(ret < 0) { + ERR("bulk_read failed: %s\n", usb_strerror()); + dump_packet("recv_usb[ERR]", buf, len); + return ret; + } + return ret; } #ifdef XORCOM_INTERNAL @@ -244,39 +280,23 @@ int eeprom_set(struct my_usb_device *mydev, const struct myeeprom *eeprom) DBG("%s Start...\n", __FUNCTION__); assert(mydev != NULL); - phead->header.op = EEPROM_SET; + phead->header.op = PT_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) { - 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); - if(ret < 0) { - ERR("bulk_write failed: %s\n", usb_strerror()); + ret = send_usb("eeprom_set[W]", mydev, MY_EP_OUT, phead, len, TIMEOUT); + if(ret < 0) return ret; - } else if(ret != len) { - ERR("bulk_write short write: %s\n", usb_strerror()); - return -EFAULT; - } - ret = usb_bulk_read(mydev->handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT); - if(ret < 0) { - ERR("bulk_read failed: %s\n", usb_strerror()); + ret = recv_usb("eeprom_set[R]", mydev, MY_EP_IN, buf, sizeof(buf), TIMEOUT); + if(ret <= 0) return ret; - } else if(ret == 0) - return 0; phead = (struct fpga_packet_header *)buf; - if(phead->header.op == BAD_COMMAND) { - ERR("Firmware rejected EEPROM_SET command\n"); + if(phead->header.op == PT_BAD_COMMAND) { + ERR("Firmware rejected PT_EEPROM_SET command\n"); return -EINVAL; - } else if(phead->header.op != EEPROM_SET) { + } else if(phead->header.op != PT_EEPROM_SET) { ERR("Got unexpected reply op=%d\n", phead->header.op); return -EINVAL; } - if(verbose >= LOG_DEBUG) { - DBG("%s read %d bytes\n", __FUNCTION__, ret); - dump_packet(buf, ret); - } return 0; } #endif @@ -292,38 +312,22 @@ int eeprom_get(struct my_usb_device *mydev) assert(mydev != NULL); eeprom = &mydev->eeprom; DBG("%s Start...\n", __FUNCTION__); - phead->header.op = EEPROM_GET; + phead->header.op = PT_EEPROM_GET; len = sizeof(phead->header.op); /* warning: sending small packet */ - if(verbose >= LOG_DEBUG) { - 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); - if(ret < 0) { - ERR("bulk_write failed: %s\n", usb_strerror()); + ret = send_usb("eeprom_get[W]", mydev, MY_EP_OUT, phead, len, TIMEOUT); + if(ret < 0) return ret; - } else if(ret != len) { - ERR("bulk_write short write: %s\n", usb_strerror()); - return -EFAULT; - } - ret = usb_bulk_read(mydev->handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT); - if(ret < 0) { - ERR("bulk_read failed: %s\n", usb_strerror()); + ret = recv_usb("eeprom_get[R]", mydev, MY_EP_IN, buf, sizeof(buf), TIMEOUT); + if(ret <= 0) return ret; - } else if(ret == 0) - return 0; phead = (struct fpga_packet_header *)buf; - if(phead->header.op == BAD_COMMAND) { - ERR("BAD_COMMAND\n"); + if(phead->header.op == PT_BAD_COMMAND) { + ERR("PT_BAD_COMMAND\n"); return -EINVAL; - } else if(phead->header.op != EEPROM_GET) { + } else if(phead->header.op != PT_EEPROM_GET) { ERR("Got unexpected reply op=%d\n", phead->header.op); return -EINVAL; } - if(verbose >= LOG_DEBUG) { - DBG("%s read %d bytes\n", __FUNCTION__, ret); - dump_packet(buf, ret); - } memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE); return 0; } @@ -345,32 +349,23 @@ int send_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq) ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt); return -EINVAL; } - phead->header.op = DATA_PACKET; + phead->header.op = PT_DATA_PACKET; phead->d.data_packet.seq = seq; phead->d.data_packet.reserved = 0x00; memcpy(phead->d.data_packet.data, data, len); len += sizeof(hexline->d.content.header); 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()); + ret = send_usb("hexline[W]", mydev, MY_EP_OUT, phead, len, TIMEOUT); + if(ret < 0) return ret; - } else if(ret != len) { - ERR("bulk_write short write: %s\n", usb_strerror()); - return -EFAULT; - } - if (verbose >= LOG_DEBUG) - dump_packet((char*)phead, len); - ret = usb_bulk_read(mydev->handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT); - if(ret < 0) { - ERR("bulk_read failed: %s\n", usb_strerror()); + ret = recv_usb("hexline[R]", mydev, MY_EP_IN, buf, sizeof(buf), TIMEOUT); + if(ret <= 0) return ret; - } else if(ret == 0) - return 0; DBG("%04d-\r", seq); phead = (struct fpga_packet_header *)buf; - if(phead->header.op != STATUS_REPLY) { + if(phead->header.op != PT_STATUS_REPLY) { ERR("Got unexpected reply op=%d\n", phead->header.op); + dump_packet("hexline[ERR]", buf, ret); return -EINVAL; } status = (enum fpga_load_status)phead->d.status_reply.status; @@ -381,11 +376,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); - dump_packet(buf, ret); + dump_packet("hexline[ERR]", buf, ret); return -EPROTO; default: ERR("Unknown status reply %d\n", status); - dump_packet(buf, ret); + dump_packet("hexline[ERR]", buf, ret); return -EPROTO; } return 0; @@ -459,10 +454,6 @@ int my_usb_device_init(const char devpath[], struct my_usb_device *mydev) ERR("Failed to open usb device '%s/%s': %s\n", mydev->dev->bus->dirname, mydev->dev->filename, usb_strerror()); return 0; } - if(usb_reset(mydev->handle) != 0) { - ERR("Reseting device: usb: %s\n", usb_strerror()); - return 0; - } if(usb_set_configuration(mydev->handle, MY_CONFIG) != 0) { ERR("usb: %s\n", usb_strerror()); return 0; @@ -471,9 +462,13 @@ int my_usb_device_init(const char devpath[], struct my_usb_device *mydev) ERR("usb: %s\n", usb_strerror()); return 0; } + if(usb_reset(mydev->handle) != 0) { + ERR("Reseting device: usb: %s\n", usb_strerror()); + return 0; + } dev_desc = &mydev->dev->descriptor; config_desc = mydev->dev->config; - interface = config_desc->interface; + interface = &config_desc->interface[MY_INTERFACE]; iface_desc = interface->altsetting; INFO("Vendor:Product=%04X:%04X Class=%d (endpoints=%d)\n", dev_desc->idVendor, @@ -520,23 +515,18 @@ int my_usb_device_init(const char devpath[], struct my_usb_device *mydev) return 1; } -int renumerate_device(struct my_usb_device *mydev) +int renumerate_device(struct my_usb_device *mydev, enum fpga_load_packet_types pt) { char buf[PACKET_SIZE]; struct fpga_packet_header *phead = (struct fpga_packet_header *)buf; int ret; assert(mydev != NULL); - DBG("Renumerating\n"); - phead->header.op = RENUMERATE; - ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, 1, TIMEOUT); - if(ret < 0) { - ERR("bulk_write failed: %s\n", usb_strerror()); + DBG("Renumerating with 0x%X\n", pt); + phead->header.op = pt; + ret = send_usb("renumerate[W]", mydev, MY_EP_OUT, phead, 1, TIMEOUT); + if(ret < 0) return ret; - } else if(ret != 1) { - ERR("bulk_write short write: %s\n", usb_strerror()); - return -EFAULT; - } return 0; } @@ -597,8 +587,10 @@ void usage() { fprintf(stderr, "Usage: %s -D {/proc/bus/usb|/dev/bus/usb}// [options...]\n", progname); fprintf(stderr, "\tOptions:\n"); - fprintf(stderr, "\t\t[-b ] # output to \n"); + fprintf(stderr, "\t\t[-r] # Reset the device\n"); + fprintf(stderr, "\t\t[-b ] # Output to \n"); fprintf(stderr, "\t\t[-I ] # Input from \n"); + fprintf(stderr, "\t\t[-i] # Show hexfile information\n"); fprintf(stderr, "\t\t[-g] # Get eeprom from device\n"); #ifdef XORCOM_INTERNAL fprintf(stderr, "\t\t[-C srC byte] # Set Address sourCe (default: C0)\n"); @@ -627,6 +619,8 @@ int main(int argc, char *argv[]) const char *binfile = NULL; const char *hexfile = NULL; struct hexdata *hexdata = NULL; + int opt_reset = 0; + int opt_info = 0; int opt_read_eeprom = 0; #ifdef XORCOM_INTERNAL int opt_write_eeprom = 0; @@ -637,9 +631,9 @@ int main(int argc, char *argv[]) char *release = NULL; char *serial = NULL; uint8_t serial_buf[SERIAL_SIZE]; - const char options[] = "b:C:D:ghI:vV:P:R:S:"; + const char options[] = "rib:C:D:ghI:vV:P:R:S:"; #else - const char options[] = "b:D:ghI:v"; + const char options[] = "rib:D:ghI:v"; #endif int ret = 0; @@ -657,6 +651,12 @@ int main(int argc, char *argv[]) case 'D': devpath = optarg; break; + case 'r': + opt_reset = 1; + break; + case 'i': + opt_info = 1; + break; case 'b': binfile = optarg; break; @@ -725,10 +725,15 @@ int main(int argc, char *argv[]) ERR("Bailing out\n"); exit(1); } - if(binfile) { + if(opt_info) { + printf("%s: Version=%s Checksum=%d\n", + hexfile, hexdata->version_info, + calc_checksum(hexdata)); + } + if(binfile) dump_binary(hexdata, binfile); + if(!devpath) return 0; - } } if(!devpath) { ERR("Missing device path\n"); @@ -761,7 +766,7 @@ int main(int argc, char *argv[]) ret = -ENODEV; goto dev_err; } - ret = renumerate_device(&mydev); + ret = renumerate_device(&mydev, PT_RENUMERATE); if(ret < 0) { ERR("Renumeration failed: errno=%d\n", ret); goto dev_err; @@ -798,6 +803,14 @@ int main(int argc, char *argv[]) show_device_info(&mydev); } #endif + if(opt_reset) { + DBG("Reseting to default\n"); + ret = renumerate_device(&mydev, PT_RESET); + if(ret < 0) { + ERR("Renumeration to default failed: errno=%d\n", ret); + goto dev_err; + } + } DBG("Exiting\n"); dev_err: my_usb_device_cleanup(&mydev); diff --git a/xpp/utils/genzaptelconf b/xpp/utils/genzaptelconf index c5dedd4..4bf8a38 100755 --- a/xpp/utils/genzaptelconf +++ b/xpp/utils/genzaptelconf @@ -34,7 +34,7 @@ # (redhat/centos) # /etc/default/zaptel may override the following variables -VERSION=0.5.8 +VERSION=0.5.10 rcsid='$Id$' lc_country=us # set to: ls, ks or gs for (Loopstart, Kewlstart and GroundStart) @@ -59,15 +59,25 @@ fxs_immediate=no ZAPCONF_FILE=${ZAPCONF_FILE:-/etc/zaptel.conf} ZAPCONF_FILE_SYSTEM=$ZAPCONF_FILE ZAPATA_FILE=${ZAPATA_FILE:-/etc/asterisk/zapata-channels.conf} +ZAPSCAN_FILE=${ZAPSCAN_FILE:-/etc/asterisk/zapscan.conf} ZAPTEL_BOOT_DEBIAN=${ZAPTEL_BOOT_DEBIAN:-/etc/default/zaptel} ZAPTEL_BOOT_FEDORA=${ZAPTEL_BOOT_FEDORA:-/etc/sysconfig/zaptel} MODLIST_FILE=/etc/modules MODLIST_FILE_FEDORA=/etc/sysconfig/zaptel exten_base_dir=/etc/asterisk/extensions-phones.d exten_defs_file=/etc/asterisk/extensions-defs.conf +# perl utilities: +xpp_sync=/usr/sbin/xpp_sync +zt_registration=/usr/sbin/zt_registration # how long to wait for /dev/zap/ctl to appear? (seconds) DEVZAP_TIMEOUT=${DEVZAP_TIMEOUT:-20} ZTCFG=${ZTCFG:-/sbin/ztcfg} +# BRI/PRI spans will be in an additional per-span group whose number +# is SPAN_GROUP_BASE + span-number +SPAN_GROUP_BASE=10 +# set to "yes" to make BRI NT spans set overlapdial (handy for ISDN phones +# and other devices). +brint_overlap=no # a temporary directory to store whatever we need to remember. # @@ -77,14 +87,20 @@ tmp_dir= # A list of all modules: # - the list of modules which will be probed (in this order) if -d is used # - The module that will be deleted from /etc/modules , if -d -M is used -ALL_MODULES="zaphfc qozap ztgsm wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wanpipe wcusb xpp_usb" +ALL_MODULES="vzaphfc zaphfc qozap ztgsm wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wcte12xp wct1xxp wct4xxp wcte11xp wanpipe wcusb xpp_usb" + +# The name of the variable in /etc/sysconfig/zaptel into which to set +# the list of detected modules. +modules_var=MODULES +# On SuSE with the rpm package: +#modules_var=ZAPTEL_MODULES # What signalling to give to ZapBRI channels? # bri: bri_net; bri_cpe (Bristuffed Asterisk. No multi- support) # bri_ptmpi: bri_net_ptmp; bri_cpe_ptmp (Bristuffed Asterisk, multi- support) # pri: pri_net; pri_cpe (Recent Asterisk. Experimental) -ZAPBRI_SIGNALLING=bri -#ZAPBRI_SIGNALLING=bri_ptmp +#ZAPBRI_SIGNALLING=bri +ZAPBRI_SIGNALLING=bri_ptmp #ZAPBRI_SIGNALLING=pri # read default configuration from /etc/default/zaptel @@ -102,6 +118,8 @@ if [ ! -x "$ZTCFG" ]; then fi fi +XPP_SYNC=auto # sync mode. can be set to '0' or '1' or HOST explicitly. + # it is safe to use -c twice: the last one will be used. ztcfg_cmd="$ZTCFG -c $ZAPCONF_FILE" @@ -115,6 +133,7 @@ do_module_list=no verbose=no do_restart=yes fxsdisable=no +do_gen_zapscan=no span_te_timing_counter=1 @@ -123,7 +142,7 @@ bri) ZAPBRI_NET=bri_net; ZAPBRI_CPE=bri_cpe ;; pri) ZAPBRI_NET=pri_net; ZAPBRI_CPE=pri_cpe ;; bri_ptmp) ZAPBRI_NET=bri_net_ptmp; ZAPBRI_CPE=bri_cpe_ptmp ;; *) - echo >&2 "Incorrect value for ZAPBRI_SIGNALLING ($ZAPBRI_SIGNALLING). Abortring" + echo >&2 "Incorrect value for ZAPBRI_SIGNALLING ($ZAPBRI_SIGNALLING). Abortring" exit 1 ;; esac @@ -146,10 +165,10 @@ wait_for_zapctl() { # no point waiting. if [ -c /dev/zap/ctl ] || ! grep -q zaptel /proc/modules ; then return - fi - say "Waiting for /dev/zap/ctl to be generated" - devzap_found=0 - for i in `seq $DEVZAP_TIMEOUT`; do + fi + say "Waiting for /dev/zap/ctl to be generated" + devzap_found=0 + for i in `seq $DEVZAP_TIMEOUT`; do sleep 1 if [ -c /dev/zap/ctl ]; then devzap_found=1 @@ -157,8 +176,8 @@ wait_for_zapctl() { fi done if [ "$devzap_found" != 1 ]; then - say "Still no /dev/zap/ctl after $devzap_timeout seconds." - echo >&2 "No /dev/zap/ctl: cannot run ztcfg. Aborting." + say "Still no /dev/zap/ctl after $devzap_timeout seconds." + echo >&2 "No /dev/zap/ctl: cannot run ztcfg. Aborting." fi } @@ -192,15 +211,15 @@ update_module_list_debian() { update_module_list_fedora() { say "Updating modules list in zaptel init config $MODLIST_FILE_FEDORA." - sed -i.bak -e '/^MODULES=/d' "$MODLIST_FILE_FEDORA" - echo "MODULES=\"$*\"" >> "$MODLIST_FILE_FEDORA" + sed -i.bak -e "/^$modules_var=/d" "$MODLIST_FILE_FEDORA" + echo "$modules_var=\"$*\"" >> "$MODLIST_FILE_FEDORA" } update_module_list() { if [ -f "$MODLIST_FILE" ]; then - update_module_list_debian "$@" + update_module_list_debian "$@" elif [ -f "$MODLIST_FILE_FEDORA" ]; then - update_module_list_fedora "$@" + update_module_list_fedora "$@" else die "Can't find a modules list to update. Tried: $MODLIST_FILE, $MODLIST_FILE_FEDORA. Aborting" fi @@ -229,6 +248,26 @@ zap_reg_xpp() { done } +# Initialize the Xorcom Astribank (xpp/) +xpp_startup() { + # do nothing if the module xpp was not loaded, or if no + # Astribanks connected: + if [ ! -d /proc/xpp ]; then return 0; fi + if ! grep -q 'STATUS=connected' /proc/xpp/xbuses; then return 0; fi + + echo "Waiting for Astribank devices to initialize:" + cat /proc/xpp/XBUS-[0-9]*/waitfor_xpds 2>/dev/null || true + + # overriding locales for the above two, as perl can be noisy + # when locales are missing. + # No register all the devices if they didn't auto-register: + LC_ALL=C $zt_registration on + + # this one could actually be run after ztcfg: + LC_ALL=C $xpp_sync "$XPP_SYNC" +} + + usage() { program=`basename $0` @@ -251,6 +290,20 @@ usage() { echo >&2 " -v: verbose" echo >&2 " -s: Stop Asterisk before running, and start it at the end." echo >&2 " -R: Don't restart asterisk in the end." + echo >&2 " -z: also generate zapscan.conf for the asterisk GUI." +} + +# print /etc/asterisk/zapscan.conf for the Asterisk-GUI +# $1: port type. Currently only fxs/fxo . Note that this is the type, and +# not the signalling (which would be the fxo fir an fxs port. +# $2: port number. Probably a range of ports is also allowed. +print_zapscan_port () { + if [ "$do_gen_zapscan" != 'yes' ]; then return 0; fi + + echo " +[$2] +port=$1 +" >>$zapscan_file } # $1: channel number @@ -286,12 +339,12 @@ print_pattern() { else method="$fxs_default_start" fi + case "$sig" in + fxs) sig_name=FXO;; + fxo) sig_name=FXS;; + esac case "$mode" in list) - case "$sig" in - fxs) sig_name=FXO;; - fxo) sig_name=FXS;; - esac echo $chan $sig_name $astbank_type;; files) # sadly, both input ports and output ports go into the same span as @@ -400,18 +453,7 @@ print_pattern() { reset_zapata_entry $zapata_file $reset_values echo "" >> $zapata_file - # Keep a note of what channels we have identified - say "DEBUG: adding to channels list: channel: $chan, sig: $sig" - case "$sig" in - fxs) - echo $chan >$tmp_dir/fxo_$chan - say "DEBUG: FXO list now contains: `cat $tmp_dir/fxo_* |xargs`" - ;; - fxo) - echo $chan >$tmp_dir/fxs_$chan - say "DEBUG: FXS list now contains: `cat $tmp_dir/fxs_* |xargs`" - ;; - esac + print_zapscan_port "$sig" "$chan" ;; esac @@ -539,7 +581,7 @@ temporary_zapconf() { case "$1" in save) say "Temporarily moving zaptel.conf aside to work around broken modprobe.conf" - ZAPCONF_FILE_TMP=`mktemp -t zaptel.conf-XXXXXX` || die "Error creating temporary zaptel.conf" + ZAPCONF_FILE_TMP=`mktemp /tmp/genzaptelconf-zaptel.conf-XXXXXX` || die "Error creating temporary zaptel.conf" cp -a $ZAPCONF_FILE_SYSTEM $ZAPCONF_FILE_TMP echo -n >$ZAPCONF_FILE_SYSTEM ;; @@ -552,55 +594,244 @@ temporary_zapconf() { esac } -# TODO: kill this function. It is now unreferenced from anywhere. -check_tdm_sigtype() { - chan_num=$1 - sig_type=$2 - mode=$3 - - case "$sig_type" in - fxs)chan_sig_type=fxo;; - fxo)chan_sig_type=fxs;; - esac - -# print_pattern $chan_num $chan_sig_type $mode - - # if you get syntax error from this line, make sure you use 'bash' - # rather than 'sh' - $ztcfg_cmd -c <(print_pattern $chan_num $chan_sig_type zaptel) 2>/dev/null \ - || return 1 - if head -c1 /dev/zap/$chan_num >/dev/null 2>/dev/null - then - print_pattern $chan_num $chan_sig_type $mode - return 0 - else - return 1 - fi -} - # run after the channel's entry. Used to reset all the values reset_zapata_entry() { conf_file="$1"; shift for arg in "$@"; do case "$arg" in - busydetect) echo "busydetect=no" >>$conf_file;; - context) echo "context=default" >>$conf_file;; - immediate) echo "immediate=no" >>$conf_file;; - rxgain) echo "rxgain=0" >>$conf_file;; - txgain) echo "txgain=0" >>$conf_file;; - *) echo "$arg=" >>$conf_file;; + busydetect) echo "$arg=no" >>$conf_file;; + context) echo "$arg=default" >>$conf_file;; + immediate) echo "$arg=no" >>$conf_file;; + overlapdial) echo "$arg=no" >>$conf_file;; + rxgain) echo "$arg=0" >>$conf_file;; + txgain) echo "$arg=0" >>$conf_file;; + *) echo "$arg=" >>$conf_file;; esac done } +# we need to preserve the permissions of existing configurations files. +# However we also don't want to be left with incomplete configurations in +# case we are stopped in the middle. Thus we create a temporary file and +# mv it to the original file only when done. +# +# This function gives the temporary file the permissions of the original, +# or some sane defaults. +# +# The temporary file is generated here, and ths its name is passed through +# a variable whose name is passed as a parameter (new_var). +# +# $1: orig_cfg_file +# $2: new_var +gen_tmp_conf() { + orig_cfg_file=$1 + new_var=$2 + + # assign to new_var by reference: + eval $new_var=`mktemp /tmp/genzaptelconf-conf-XXXXXX` \ + || die "Unable to create temporary config file for $orig_cfg_file" + if [ -r "$orig_cfg_file" ]; then + chown --reference="$orig_cfg_file" ${!new_var} 2>/dev/null + chmod --reference="$orig_cfg_file" ${!new_var} 2>/dev/null + else + chmod 644 ${!new_var} + fi +} + +# Extract information from one digital channel (one line in a /proc/zaptel +# file). Information is saved to $tmp_dir/span_foo variables. +detect_digital_channel() { + line="$1" + chan_num="$2" + span_num="$3" + + # PRI/BRI channel + # Rather than identifying cards by the header line, we identify + # them by the channel names. This is shorter. + # This also allows us to count the channel numbers and check if + # we have a E1 span, a T1 span or a BRI span. + if [ "`cat $tmp_dir/span_begin`" = "-1" ] + then + echo $chan_num >$tmp_dir/span_begin + echo $span_num >$tmp_dir/span_num + # The Astribank channels provide the information of TE/NT in the channel name. So + # why not use it? + case "$line" in + *XPP_BRI_TE/*) echo 'te' >$tmp_dir/span_termtype;; + *XPP_BRI_NT/*) echo 'nt' >$tmp_dir/span_termtype;; + esac + case "$line" in + *ZTHFC*/*|*ztqoz*/*|*XPP_BRI_*/*) + # BRI channel + echo 'ccs' >$tmp_dir/span_framing + echo 'euroisdn' >$tmp_dir/span_switchtype + if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ] + then + echo $ZAPBRI_NET >$tmp_dir/span_signalling + else + echo $ZAPBRI_CPE >$tmp_dir/span_signalling + fi + ;; + *ztgsm*/*) + # Junghanns's GSM cards. + echo 'ccs' >$tmp_dir/span_framing + #Does this mean anything? + echo 'gsm' >$tmp_dir/span_signalling + ;; + *TE[24]/*|*WCT1/*|*Tor2/*|*TorISA/*|*WP[TE]1/*) + # PRI span (E1/T1) + echo 'esf' >$tmp_dir/span_framing + echo 'b8zs' >$tmp_dir/span_coding + echo 'national' >$tmp_dir/span_switchtype + echo 'pri_cpe' >$tmp_dir/span_signalling + # an example of country-specific setup. This is probably not accurate + # Contributions are welcome + case "$lc_country" in + nl) + # (Just an example for per-country info) + echo 'ccs' >$tmp_dir/span_framing + echo 'ami' >$tmp_dir/span_coding + #echo 'crc4' >$tmp_dir/span_yellow + #echo 'euroisdn' >$tmp_dir/span_switchtype + #echo 'pri_cpe' >$tmp_dir/span_signalling + ;; + il|de|au) + echo 'ccs' >$tmp_dir/span_framing + echo 'hdb3' >$tmp_dir/span_coding + echo 'crc4' >$tmp_dir/span_yellow + echo 'euroisdn' >$tmp_dir/span_switchtype + ;; + cl) + echo 'ccs' >$tmp_dir/span_framing + echo 'hdb3' >$tmp_dir/span_coding + #echo 'crc4' >$tmp_dir/span_yellow + echo 'national' >$tmp_dir/span_switchtype + ;; + esac + ;; + esac + fi + # span_lastd is always the one before last + # channel. span_bchan is the last: + echo $chan_num >$tmp_dir/span_end +} + +# read information from the $tmp_dir/span_foo files and generate +# configuration for the span and its channels. +write_digital_config() { + # if the current file we checked was not of a digital span, we have + # nothing to do: + if [ "`cat $tmp_dir/span_begin`" = -1 ]; then return; fi + + # read files to variables: + for suffix in num begin end timing lbo framing \ + coding switchtype signalling yellow termtype + do + eval span_$suffix=`cat $tmp_dir/span_$suffix 2>/dev/null` + done + + if [ "$span_yellow" != '' ]; then span_yellow=",$span_yellow"; fi + # exactly the same logic is used in asterisk's chan_zap.c. + # also not that $(( )) is bash-specific + case "$((1+ $span_end - $span_begin))" in + 2|3|24) #ztgsm, BRI or T1 + dchan=$span_end + bchans="$span_begin-$(($span_end-1))" + ;; + 31) #E1 + dchan="$(($span_begin+15))" + bchans="$span_begin-$(($span_begin+14)),$(($span_begin+16))-$span_end" + if [ "$span_switchtype" = 'national' ]; then + # don't leave an E1 span with defective defaults: + span_framing=ccs + span_coding=hdb3 + span_switchtype=euroisdn + fi + ;; + esac + # Let's assume that a TE span should get the clock from the remote unit, + # and NT spans should provide timing. Just as a sane default. + # If we have several TE spans, the first will have priority 1, + # second: 2, etc. + case "$span_signalling" in *_cpe*) + span_timing=$span_te_timing_counter + span_te_timing_counter=$(($span_te_timing_counter + 1)) + ;; + esac + case "$mode" in + files) + echo span=$span_num,$span_timing,$span_lbo,$span_framing,$span_coding$span_yellow >> $zaptel_file + # leave a comment in zaptel.conf that allows to tell if + # this span is TE or NT: + if [ "$span_termtype" != '' ] + then echo "# termtype: $span_termtype" >>$zaptel_file + fi + + echo bchan=$bchans >>$zaptel_file + echo dchan=$dchan >>$zaptel_file + if [ "$fxsdisable" = 'yes' ] && [ "$span_termtype" = 'nt' ]; then return; fi + # You should not send content to zapata.conf below this line + + span_group=$(($SPAN_GROUP_BASE + $span_num)) + + if [ "$span_termtype" != '' ] + then + # an ISDN card's span that we know if it is in NT mode or TE mode. + # NT is the same as FXS for us and TE is the same as FXO + if [ "$span_termtype" = 'nt' ] + then + echo "callerid=\"Channels $span_begin - $span_end\" <$span_begin>" >> $zapata_file + reset_values="$reset_values callerid" + #echo "mailbox=$exten" + if [ "$brint_overlap" = 'yes' ] + then + echo "overlapdial=yes" >> $zapata_file + reset_values="$reset_values overlapdial" + fi + if [ "$group_manual" != "yes" ] + then + echo "group=$group_phones,$span_group" >> $zapata_file + reset_values="$reset_values group" + fi + if [ "$context_manual" != "yes" ] + then + echo "context=$context_phones" >> $zapata_file + fi + else + #echo "mailbox=" + if [ "$group_manual" != "yes" ] + then + echo "group=$group_lines,$span_group" >> $zapata_file + reset_values="$reset_values group" + fi + if [ "$context_manual" != "yes" ] + then + echo "context=$context_lines" >> $zapata_file + reset_values="$reset_values context" + fi + fi + fi + echo "switchtype = $span_switchtype" >> $zapata_file + echo "signalling = $span_signalling" >> $zapata_file + echo "channel => $bchans" >> $zapata_file + reset_zapata_entry $zapata_file $reset_values + reset_values= + ;; + list) + echo "### BRI/PRI: $span_termtype" + echo "$bchans Data" + echo "$dchan Control" + #echo BRI/PRI: chans: $bchans, control: $dchan + ;; + esac +} + +# This is where the actual detection configuration detection work happens. genconf() { local mode=$1 local reset_values="" - # reset FXO list (global) - #say "DEBUG: resetting channels lists" - rm -f $tmp_dir/fx{s,o}_* # spanlist=`echo /proc/zaptel/* | grep -v '\*'` # spanlist=$(for i in `for i in /proc/zaptel/*; do if [ -f $i ]; then echo $i | cut -f 4 -d / ; fi; done | sort -n`; do echo -n "/proc/zaptel/$i "; done) @@ -613,22 +844,20 @@ genconf() { case "$mode" in - files) - local zaptel_file=`mktemp -t genzaptelconf-zaptel-XXXXXX` - local zapata_file=`mktemp -t genzaptelconf-zapata-XXXXXX` - if [ -r "${ZAPCONF_FILE}" ]; then - chown --reference="${ZAPCONF_FILE}" $zaptel_file || true - chmod --reference="${ZAPCONF_FILE}" $zaptel_file - else - chmod 644 $zaptel_file - fi - if [ -r "${ZAPATA_FILE}" ]; then - chown --reference="${ZAPATA_FILE}" $zapata_file || true - chmod --reference="${ZAPATA_FILE}" $zapata_file - else - chmod 644 $zapata_file - fi - cat <$zaptel_file + files) + if [ "$do_gen_zapscan" = 'yes' ]; then + gen_tmp_conf "$ZAPSCAN_FILE" zapscan_file + cat <$zapscan_file +; zapscan.conf: information about detected zaptel channels +; (currently: analog only) +; +; Automatically generated by $0 -- Please do not edit. + +EOF + fi + gen_tmp_conf "$ZAPTEL_FILE" zaptel_file + gen_tmp_conf "$ZAPATA_FILE" zapata_file + cat <$zaptel_file # Autogenerated by $0 -- do not hand edit # Zaptel Configuration File # @@ -638,7 +867,7 @@ genconf() { # It must be in the module loading order EOF - cat <$zapata_file + cat <$zapata_file ; Autogenerated by $0 -- do not hand edit ; Zaptel Channels Configurations (zapata.conf) ; @@ -672,10 +901,10 @@ EOF case "$mode" in list) echo "### $title";; files) - echo "" >>$zaptel_file - echo "# $title" >>$zaptel_file - echo "" >>$zapata_file - echo "; $title" >>$zapata_file + echo "" >>$zaptel_file + echo "# $title" >>$zaptel_file + echo "" >>$zapata_file + echo "; $title" >>$zapata_file ;; esac echo '-1' >$tmp_dir/span_begin @@ -749,74 +978,7 @@ EOF print_pattern -a input $chan_num fxo $mode ;; *ZTHFC*/*|*ztqoz*/*|*ztgsm/*|*TE[24]/*|*WCT1/*|*Tor2/*|*TorISA/*|*XPP_BRI_*/*|*WP[TE]1/*) - # PRI/BRI channel - # Rather than identifying cards by the header line, we identify them by the channel names - # This is shorter. This also allows us to count the channel numbers and check if a PRI - # card is E1 or T1. - if [ "`cat $tmp_dir/span_begin`" = "-1" ] - then - echo $chan_num >$tmp_dir/span_begin - echo $span_num >$tmp_dir/span_num - # The Astribank channels provide the information of TE/NT in the channel name. So - # why not use it? - case "$line" in - *XPP_BRI_TE/*) echo 'te' >$tmp_dir/span_termtype;; - *XPP_BRI_NT/*) echo 'nt' >$tmp_dir/span_termtype;; - esac - case "$line" in - *ZTHFC*/*|*ztqoz*/*|*XPP_BRI_*/*) - # BRI channel - echo 'ccs' >$tmp_dir/span_framing - echo 'euroisdn' >$tmp_dir/span_switchtype - if [ "`cat $tmp_dir/span_termtype`" = 'nt' 2>/dev/null ] - then - echo $ZAPBRI_NET >$tmp_dir/span_signalling - else - echo $ZAPBRI_CPE >$tmp_dir/span_signalling - fi - ;; - *ztgsm*/*) - # Junghanns's GSM cards. - echo 'ccs' >$tmp_dir/span_framing - # what switch type? Any meaning to it? - echo 'gsm' >$tmp_dir/span_signalling - ;; - *TE[24]/*|*WCT1/*|*Tor2/*|*TorISA/*|*WP[TE]1/*) - # PRI span (E1/T1) - echo 'esf' >$tmp_dir/span_framing - echo 'b8zs' >$tmp_dir/span_coding - echo 'national' >$tmp_dir/span_switchtype - echo 'pri_cpe' >$tmp_dir/span_signalling - # an example of country-specific setup. This is probably not accurate - # Contributions are welcome - case "$lc_country" in - nl) - # (Just an example for per-country info) - echo 'ccs' >$tmp_dir/span_framing - echo 'ami' >$tmp_dir/span_coding - #echo 'crc4' >$tmp_dir/span_yellow - #echo 'euroisdn' >$tmp_dir/span_switchtype - #echo 'pri_cpe' >$tmp_dir/span_signalling - ;; - il|de|au) - echo 'ccs' >$tmp_dir/span_framing - echo 'hdb3' >$tmp_dir/span_coding - echo 'crc4' >$tmp_dir/span_yellow - echo 'euroisdn' >$tmp_dir/span_switchtype - ;; - cl) - echo 'ccs' >$tmp_dir/span_framing - echo 'hdb3' >$tmp_dir/span_coding - #echo 'crc4' >$tmp_dir/span_yellow - echo 'national' >$tmp_dir/span_switchtype - ;; - esac - ;; - esac - fi - # span_lastd is always the one before last - # channel. span_bchan is the last: - echo $chan_num >$tmp_dir/span_end + detect_digital_channel "$line" "$chan_num" "$span_num" ;; '') ;; # Empty line (after span header) *) @@ -831,97 +993,7 @@ EOF done # end of part in sub-process. - if [ "`cat $tmp_dir/span_begin`" != -1 ] - then # write PRI span ocnfig: - # read files to variables: - for suffix in num begin end timing lbo framing \ - coding switchtype signalling yellow termtype - do - eval span_$suffix=`cat $tmp_dir/span_$suffix 2>/dev/null` - done - if [ "$span_yellow" != '' ]; then span_yellow=",$span_yellow"; fi - # exactly the same logic is used in asterisk's chan_zap.c. - # also not that $(( )) is bash-specific - case "$((1+ $span_end - $span_begin))" in - 2|3|24) #ztgsm, BRI or T1 - dchan=$span_end - bchans="$span_begin-$(($span_end-1))" - ;; - 31) #E1 - dchan="$(($span_begin+15))" - bchans="$span_begin-$(($span_begin+14)),$(($span_begin+16))-$span_end" - if [ "$span_switchtype" = 'national' ]; then - span_framing=ccs - span_coding=hdb3 - span_switchtype=euroisdn - fi - ;; - esac - # Let's assume that a TE span should get the clock from the remote unit, - # and NT spans should provide timing. Just as a sane default. - # If we have several TE spans, the first will have priority 1, - # second: 2, etc. - case "$span_signalling" in *_cpe*) - span_timing=$span_te_timing_counter - span_te_timing_counter=$(($span_te_timing_counter + 1)) - ;; - esac - case "$mode" in - files) - echo span=$span_num,$span_timing,$span_lbo,$span_framing,$span_coding$span_yellow >> $zaptel_file - if [ "$span_termtype" != '' ] - then echo "# termtype: $span_termtype" >>$zaptel_file - fi - echo bchan=$bchans >>$zaptel_file - echo dchan=$dchan >>$zaptel_file - - if [ "$span_termtype" != '' ] - then - # an ISDN card's span that we know if it is in NT mode or TE mode. - # NT is the same as FXS for us and TE is the same as FXO - if [ "$span_termtype" = 'nt' ] - then - echo "callerid=\"Channels $span_begin - $span_end\" <$span_begin>" >> $zapata_file - reset_values="$reset_values callerid" - #echo "mailbox=$exten" - if [ "$group_manual" != "yes" ] - then - echo "group=$group_phones" >> $zapata_file - reset_values="$reset_values group" - fi - if [ "$context_manual" != "yes" ] - then - echo "context=$context_phones" >> $zapata_file - fi - else # we have may have set it. So reset it: - echo "callerid=asreceived" >> $zapata_file - reset_values="$reset_values callerid" - #echo "mailbox=" - if [ "$group_manual" != "yes" ] - then - echo "group=$group_lines" >> $zapata_file - reset_values="$reset_values group" - fi - if [ "$context_manual" != "yes" ] - then - echo "context=$context_lines" >> $zapata_file - reset_values="$reset_values context" - fi - fi - fi - echo "switchtype = $span_switchtype" >> $zapata_file - echo "signalling = $span_signalling" >> $zapata_file - echo "channel => $bchans" >> $zapata_file - reset_zapata_entry $zapata_file $reset_values - ;; - list) - echo "### BRI/PRI: $span_termtype" - echo "$bchans Data" - echo "$dchan Control" - #echo BRI/PRI: chans: $bchans, control: $dchan - ;; - esac - fi + write_digital_config done if [ "$mode" = 'files' ] @@ -936,14 +1008,26 @@ EOF fi if [ "$mode" = 'files' ]; then - mv ${ZAPCONF_FILE} ${ZAPCONF_FILE}.bak + mv ${ZAPCONF_FILE} ${ZAPCONF_FILE}.bak 2>/dev/null mv $zaptel_file ${ZAPCONF_FILE} - mv ${ZAPATA_FILE} ${ZAPATA_FILE}.bak + mv ${ZAPATA_FILE} ${ZAPATA_FILE}.bak 2>/dev/nullk mv $zapata_file ${ZAPATA_FILE} + if [ "$do_gen_zapscan" = 'yes' ]; then + mv $ZAPSCAN_FILE $ZAPSCAN_FILE.bak 2>/dev/null + mv $zapscan_file $ZAPSCAN_FILE + fi + + zapata_file_name=`basename $ZAPATA_FILE` + if ! grep -q "^#include.*$zapata_file_name" \ + /etc/asterisk/zapata.conf + then + say "Note: generated $ZAPATA_FILE not included in zapata.conf" + say "To fix: echo '#include $zapata_file_name' >>/etc/asterisk/zapata.conf" + fi fi } -while getopts 'c:de:Fhlm:MRsuv' arg +while getopts 'c:de:Fhlm:MRsuvz' arg do case "$arg" in e) # guarantee that it is a number: @@ -959,6 +1043,7 @@ do M) do_module_list=yes; do_detect=yes ;; s) force_stop_ast=yes ;; R) do_restart=no ;; + z) do_gen_zapscan=yes ;; h) usage; exit 0;; *) echo >&2 "unknown parameter -$arg, Aborting"; usage; exit 1;; esac @@ -970,7 +1055,7 @@ if [ $# != 0 ]; then exit 1 fi -tmp_dir=`mktemp -d -t` || \ +tmp_dir=`mktemp -d /tmp/genzaptelconf-dir-XXXXXX` || \ die "$0: failed to create temporary directory. Aborting" @@ -991,14 +1076,14 @@ defaultzone=$loadzone # make sure asterisk is not in our way if [ "$force_stop_ast" = 'yes' ] then - /etc/init.d/asterisk stop 1>&2 + /etc/init.d/asterisk stop 1>&2 else # if asterisk is running and we wanted to detect modules # or simply to unload modules, asterisk needs to go away. if ( [ "$do_unload" = yes ] || [ "$do_detect" = yes ] ) && \ - pidof asterisk >/dev/null + pidof asterisk >/dev/null then - echo >&2 "Asterisk is already running. Configuration left untouched" + echo >&2 "Asterisk is already running. Configuration left untouched" echo >&2 "You can use the option -s to shut down Asterisk for the" echo >&2 "duration of the detection." exit 1 @@ -1019,7 +1104,8 @@ fi if [ "$mode" = list ]; then genconf list else - zap_reg_xpp + #zap_reg_xpp + xpp_startup wait_for_zapctl say "Generating '${ZAPCONF_FILE} and ${ZAPATA_FILE}'" genconf files @@ -1028,17 +1114,17 @@ fi if [ "$tmp_dir" != '' ] then - rm -rf "$tmp_dir" + rm -rf "$tmp_dir" fi if [ "$force_stop_ast" != 'yes' ] || [ "$do_restart" != 'yes' ] then - exit 0 + exit 0 fi if [ -x /etc/init.d/asterisk ] then - /etc/init.d/asterisk start 1>&2 + /etc/init.d/asterisk start 1>&2 fi # if in verbose mode: verify that asterisk is running @@ -1054,4 +1140,4 @@ if [ "$verbose" != 'no' ] fi fi -# vim:ts=2: +# vim:ts=8: diff --git a/xpp/utils/genzaptelconf.8 b/xpp/utils/genzaptelconf.8 index 081b52d..c3f6f73 100644 --- a/xpp/utils/genzaptelconf.8 +++ b/xpp/utils/genzaptelconf.8 @@ -5,7 +5,7 @@ .SH SYNOPSIS .PP .B genzaptelconf -[-sRdv] [-c ] [-e ] [ -F ] +[-sRdvzF] [-c ] [-e ] .B genzaptelconf [-sRdv] -l -- only list to standard output @@ -27,7 +27,7 @@ and .I PRI and .I BRI -(HFC, with ZapBRI) cards are basically identified as well. However the span +(with ZapBRI) cards are basically identified as well. However the span configiration is a default that I only hope is sane. Looking for feedback .SH OPTIONS @@ -126,6 +126,14 @@ Be verbose. lists the detected modules if is used. Lists detected channls. In the end tries to connect to asterisk to get a list of configured zaptel channels. .RE + +.B -z +.RS +emulate the operation of zapscan.bin: generate +.I /etc/asterisk/zapscan.conf +with the results of the scan. +.RE + .SH CONFIGURATION Look at the beginning of the script for a number of variables that can be overriden through the configuraion file. Some variables can also be diff --git a/xpp/utils/hexfile.c b/xpp/utils/hexfile.c index a4b12c5..5d6eaa7 100644 --- a/xpp/utils/hexfile.c +++ b/xpp/utils/hexfile.c @@ -278,6 +278,39 @@ int dump_hexfile2(struct hexdata *hexdata, FILE *outfile, uint8_t maxwidth) return 0; } +void process_comment(struct hexdata *hexdata, char buf[]) +{ + char *dollar_start; + char *dollar_end; + const char id_prefix[] = "Id: "; + char tmp[BUFSIZ]; + char *p; + int len; + + if(report_func) + report_func(LOG_INFO, "Comment: %s\n", buf + 1); + /* Search for RCS keywords */ + if((dollar_start = strchr(buf, '$')) == NULL) + return; + if((dollar_end = strchr(dollar_start + 1, '$')) == NULL) + return; + /* Crop the '$' signs */ + len = dollar_end - dollar_start; + len -= 2; + memcpy(tmp, dollar_start + 1, len); + tmp[len] = '\0'; + p = tmp; + if(strstr(tmp, id_prefix) == NULL) + return; + p += strlen(id_prefix); + if((p = strchr(p, ' ')) == NULL) + return; + p++; + strncpy(hexdata->version_info, p, BUFSIZ - 1); + if((p = strchr(hexdata->version_info, ' ')) != NULL) + *p = '\0'; +} + struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines) { FILE *fp; @@ -314,18 +347,7 @@ 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); - /* 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); + process_comment(hexdata, buf); continue; } if(buf[0] != ':') { @@ -383,3 +405,31 @@ void dump_binary(struct hexdata *hexdata, const char *outfile) fclose(fp); } +/* + * Algorithm lifted of sum(1) implementation from coreutils. + * We chose the default algorithm (BSD style). + */ +int calc_checksum(struct hexdata *hexdata) +{ + unsigned int i; + size_t len; + int ck = 0; + + for(i = 0; i < hexdata->maxlines; i++) { + struct hexline *hexline = hexdata->lines[i]; + unsigned char *p; + + if(!hexline) + break; + if(hexline->d.content.header.tt == TT_EOF) + continue; + len = hexline->d.content.header.ll; + p = hexline->d.content.tt_data.data; + for(; len; p++, len--) { + ck = (ck >> 1) + ((ck & 1) << 15); + ck += *p; + ck &= 0xffff; /* Keep it within bounds. */ + } + } + return ck; +} diff --git a/xpp/utils/hexfile.h b/xpp/utils/hexfile.h index 4c6e689..297cfba 100644 --- a/xpp/utils/hexfile.h +++ b/xpp/utils/hexfile.h @@ -116,6 +116,7 @@ struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines); int dump_hexfile(struct hexdata *hexdata, FILE *outfile); int dump_hexfile2(struct hexdata *hexdata, FILE *outfile, uint8_t maxwidth); void dump_binary(struct hexdata *hexdata, const char *outfile); +int calc_checksum(struct hexdata *hexdata); __END_DECLS #endif diff --git a/xpp/utils/lszaptel b/xpp/utils/lszaptel index af11b6e..4a6f8b9 100755 --- a/xpp/utils/lszaptel +++ b/xpp/utils/lszaptel @@ -5,7 +5,9 @@ # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); } use Zaptel; diff --git a/xpp/utils/xpp_blink b/xpp/utils/xpp_blink new file mode 100755 index 0000000..1993a81 --- /dev/null +++ b/xpp/utils/xpp_blink @@ -0,0 +1,115 @@ +#! /usr/bin/perl -w +# +# Written by Oron Peled +# 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; +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|bzzt} {span | xpd []}\n"; +} + +my $state = shift; +my $selector = shift; +usage unless defined($state) and $state =~ /^(on|off|bzzt)$/; +usage unless defined($selector) and $selector =~ /^(span|xpd)$/i; + +my $xpd; +my @xpds; +my @channels; + +if($selector =~ /^span$/i) { + my $number = shift; + usage unless defined($number) and $number =~ /^\d+/; + my $span = Zaptel::Span::by_number($number); + die "Unkown Span $number\n" unless $span; + $xpd = Zaptel::Xpp::xpd_of_span($span); + die "Span $number is not an XPD\n" unless defined $xpd; + my $xpdname = $xpd->fqn; + my $connector = $xpd->xbus->connector; + die "$xpdname is not connected\n" unless defined $connector; + push(@xpds, $xpd); + my @chans = $span->chans(); + @channels = join(' ', map { $_->num } @chans); + printf "Using %s (connected via $connector): channels @channels\n", $xpd->fqn; +} elsif($selector =~ /^xpd$/i) { + my $busnum = shift; + my $xpdnum = shift; + usage unless defined($busnum) and $busnum =~ /^\d+/; + my $xbus = Zaptel::Xpp::Xbus::by_number($busnum); + die "Unkown XBUS number $busnum\n" unless defined $xbus; + if(defined $xpdnum) { + usage unless $xpdnum =~ /^\d+/; + $xpd = $xbus->get_xpd_by_number($xpdnum); + die "Unkown XPD number $xpdnum on XBUS number $busnum\n" unless defined $xpd; + push(@xpds, $xpd); + } else { + @xpds = $xbus->xpds; + die "XBUS number $busnum has no XPDS!\n" unless @xpds; + } +} + +if($state eq 'on') { + $_->blink(1) foreach (@xpds); +} elsif($state eq 'off') { + $_->blink(0) foreach (@xpds); +} elsif($state eq 'bzzt') { + $_->blink(1) foreach (@xpds); + sleep 1; + $_->blink(0) foreach (@xpds); +} + +__END__ + +=head1 NAME + +xpp_blink - Blink the leds of a specified XPD + +=head1 SYNOPSIS + +xpp_blink {on|off|bzzt} {span | xpd []}\n"; + +=head1 DESCRIPTION + +Blink all the leds of an XPD. + +=head2 Blink mode: + +=over 16 + +=item on Turn on constant blink + +=item off Turn off blink + +=item bzzt Blink briefly for 1 second. + +=back + +=head2 Selector: + +=over 16 + +=item span Select by span number. This only work for XPD registered to zaptel. + +=item xpd Select by xbus + xpd numbers. If only xbus number is given, all the + XPDs of the selected xbus are blinked. + +=back + +=head1 EXAMPLES + + $ xpp_blink bzzt span 2 + + $ xpp_blink xpd 0 1 + + $ xpp_blink xpd 0 diff --git a/xpp/utils/xpp_fxloader b/xpp/utils/xpp_fxloader index 3d200e8..eb46ccc 100644 --- a/xpp/utils/xpp_fxloader +++ b/xpp/utils/xpp_fxloader @@ -48,6 +48,10 @@ set -e +# Make sure fxload is in the path: +PATH="$PATH:/usr/local/sbin:/sbin:/usr/sbin" +export PATH + me=`basename $0` DEFAULTS="/etc/default/zaptel" @@ -119,10 +123,22 @@ load_fw() { if [ "$devices" != '' ]; then sleep $REENUM_SLEEP_TIME; fi } -hexfile_version() { - hexfile=$1 +reset_fpga() { + v_id=$1 + p_id=$2 - grep '$Id:' "$hexfile" | sed -e 's/^.*$Id: *[^ ]\+ *//' -e 's/ .*$//' + devices=`find_dev $v_id $p_id` + for dev in $devices + do + $LOGGER "Resetting FPGA Firmware on $dev" + sleep_if_race + $FPGA_LOAD -D "$dev" -r 2>&1 >/dev/null | $LOGGER + status=$PIPESTATUS + if [ "$status" != 0 ]; then + echo "fpga_load failed remoivng with status $status" | $LOGGER + exit 78 + fi + done } load_fpga() { @@ -134,11 +150,10 @@ load_fpga() { for dev in $devices do card_ver=`$FPGA_LOAD -g -D $dev | sed -n 's/^.*Release: *//'` - firm_ver=`hexfile_version $FIRMWARE_DIR/$fw` - $LOGGER "FPGA Firmware $FIRMWARE_DIR/$fw (version: $firm_ver) into $dev" + $LOGGER "FPGA Firmware into $dev" sleep_if_race - $FPGA_LOAD -D "$dev" -I "$FIRMWARE_DIR/$fw" 2>&1 >/dev/null | $LOGGER + $FPGA_LOAD -D "$dev" -I "$FIRMWARE_DIR/$fw" -i | $LOGGER status=$PIPESTATUS if [ $status != 0 ]; then echo "fpga_load failed with status $status" | $LOGGER @@ -160,6 +175,10 @@ udev) PRODUCT="$2" # skip on to the rest of the script. Don't exit. ;; +reset) + # TODO: does the use of wildcards here work? + reset_fpga e4e4 '11[345][12]' + ;; xppdetect|load|usb) echo "--------- FIRMWARE LOADING: ($1)" @@ -195,6 +214,9 @@ esac ## Hotplug run ## +# allow disabling automatic hotplugging: +if [ "$XPP_HOTPLUG_DISABLED" != '' ]; then return 0; fi + if [ "$ACTION" = "add" ] && [ -w "$DEVICE" ] then $LOGGER "Trying to find what to do for product $PRODUCT, device $DEVICE" diff --git a/xpp/utils/xpp_sync b/xpp/utils/xpp_sync index 018d268..e1258d9 100755 --- a/xpp/utils/xpp_sync +++ b/xpp/utils/xpp_sync @@ -5,7 +5,9 @@ # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); } use Zaptel::Xpp; @@ -19,6 +21,7 @@ if(@ARGV == 1) { $autoselect = 1 if $sync =~ /^auto$/i; } + sub get_sorted_xpds() { my @good_xpds; @@ -31,7 +34,7 @@ sub get_sorted_xpds() { next; } next unless $isreg; # Skip unregistered XPDs - push(@good_xpds, $xpd); + push(@good_xpds, $xpd); } } @@ -70,21 +73,45 @@ sub do_set($) { die "Failed to set sync to '$sync'" unless Zaptel::Xpp::sync($sync); } +sub unique_xbus(@) { + my %seen; + + grep { !$seen{$_->xbus}++; } @_; +} + my $curr_sync = Zaptel::Xpp::sync; -my %xbus_seen; -my @sorted_xpds = grep { !$xbus_seen{$_->xbus}++; } get_sorted_xpds; +my @sync_xpds = unique_xbus(get_sorted_xpds()); + +sub check_fxo_host_sync() { + my @host_synced_xpds = grep { $_->xbus->num() ne $curr_sync } @sync_xpds; + my @host_synced_fxos = grep($_->type eq 'FXO', @host_synced_xpds); + if(@host_synced_fxos) { + my @bad_xbus = map { $_->xbus } unique_xbus(@host_synced_fxos); + our $lines = join("\n\t", map { $_->name } @bad_xbus); + print STDERR <<"END"; +========================================= +WARNING: FXO with HOST SYNC cause bad PCM + Affected Astribanks are: +----------------------------------------- + $lines +========================================= +END + } +} + if($sync) { if($autoselect) { - do_select(@sorted_xpds); + do_select(@sync_xpds); } else { $sync = uc($sync); do_set($sync); } + $curr_sync = Zaptel::Xpp::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) { + foreach my $xpd (@sync_xpds) { my $xbus = $xpd->xbus; my @xpds = $xbus->xpds; my @types = map { $_->type } @xpds; @@ -101,12 +128,13 @@ if($sync) { $next = $n + 1; } # Fill spaces to end - $n = 4; + my $n = 4; for(my $i = $next; $i < $n; $i++) { printf "%-3s ", ""; } printf "] (%s)\n", $xbus->connector; } + check_fxo_host_sync; } __END__ diff --git a/xpp/utils/zconf/Zaptel.pm b/xpp/utils/zconf/Zaptel.pm index 394aa8e..7642b0e 100644 --- a/xpp/utils/zconf/Zaptel.pm +++ b/xpp/utils/zconf/Zaptel.pm @@ -5,7 +5,10 @@ package Zaptel; # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; +use Zaptel::Span; my $proc_base = "/proc/zaptel"; diff --git a/xpp/utils/zconf/Zaptel/Chans.pm b/xpp/utils/zconf/Zaptel/Chans.pm index 31bc5f7..3364060 100644 --- a/xpp/utils/zconf/Zaptel/Chans.pm +++ b/xpp/utils/zconf/Zaptel/Chans.pm @@ -5,9 +5,12 @@ package Zaptel::Chans; # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; # Accessors (miniperl does not have Class:Accessor) +our $AUTOLOAD; sub AUTOLOAD { my $self = shift; my $name = uc($AUTOLOAD); @@ -36,11 +39,42 @@ sub new($$$$$) { $type = $1; # One of our AB } elsif(defined $info) { $type = (split(/\s+/, $info))[0]; + $type = 'FXS' if $type =~ /^FXS/; + $type = 'FXO' if $type =~ /^FXO/; } else { - $type = $fqn; + $type = undef; } $self->type($type); return $self; } +my $ztcfg = $ENV{ZTCFG} || '/sbin/ztcfg'; +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 | $ztcfg -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 = $self->type; + } + return $type; +} + 1; diff --git a/xpp/utils/zconf/Zaptel/Span.pm b/xpp/utils/zconf/Zaptel/Span.pm index 08ebae2..c020d2f 100644 --- a/xpp/utils/zconf/Zaptel/Span.pm +++ b/xpp/utils/zconf/Zaptel/Span.pm @@ -5,7 +5,9 @@ package Zaptel::Span; # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; use Zaptel::Chans; my $proc_base = "/proc/zaptel"; @@ -16,6 +18,7 @@ sub chans($) { } # Accessors (miniperl does not have Class:Accessor) +our $AUTOLOAD; sub AUTOLOAD { my $self = shift; my $name = uc($AUTOLOAD); @@ -27,6 +30,25 @@ sub AUTOLOAD { } } +sub by_number($) { + my $span_number = shift; + die "Missing span number" unless defined $span_number; + my @spans = Zaptel::spans(); + + my ($span) = grep { $_->num == $span_number } @spans; + return $span; +} + +my @bri_strings = ( + 'BRI_(NT|TE)', + '(?:quad|octo)BRI PCI ISDN Card.* \[(NT|TE)\]\ ', + 'octoBRI \[(NT|TE)\] ', + 'HFC-S PCI A ISDN.* \[(NT|TE)\] ' + ); + +our $ZAPBRI_NET = 'bri_net'; +our $ZAPBRI_CPE = 'bri_cpe'; + 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"; @@ -35,6 +57,17 @@ sub new($$) { open(F, "$proc_base/$num") or die "Failed to open '$proc_base/$num\n"; my $head = ; chomp $head; + foreach my $cardtype (@bri_strings) { + if($head =~ m/$cardtype/) { + $self->{IS_BRI} = 1; + $self->{TERMTYPE} = $1; + $self->{DCHAN_IDX} = 2; + $self->{BCHAN_LIST} = [ 0, 1 ]; + last; + } + } + die "$0: Unkown TERMTYPE [NT/TE]\n" + if $self->is_bri and !defined $self->{TERMTYPE}; ($self->{NAME}, $self->{DESCRIPTION}) = (split(/\s+/, $head, 4))[2, 3]; $self->{CHANS} = []; while() { @@ -47,7 +80,30 @@ sub new($$) { push(@{$self->{CHANS}}, $c); } close F; + if($self->is_bri()) { + $self->{CODING} = 'ami'; + $self->{YELLOW} = undef; + $self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}]; + $self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ]; + # Infer some info from channel name: + my $first_chan = ($self->chans())[0] || die "$0: No channels in span #$num\n"; + my $chan_fqn = $first_chan->fqn(); + if($chan_fqn =~ m(ZTHFC.*/|ztqoz.*/|XPP_BRI_.*/)) { # BRI + $self->{FRAMING} = 'ccs'; + $self->{SWITCHTYPE} = 'euroisdn'; + $self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $ZAPBRI_NET : $ZAPBRI_CPE ; + } elsif($chan_fqn =~ m(ztgsm.*/)) { # Junghanns's GSM cards. + $self->{FRAMING} = 'ccs'; + $self->{SIGNALLING} = 'gsm'; + } + } return $self; } +sub bchans($) { + my $self = shift || die; + + return @{$self->{BCHANS}}; +} + 1; diff --git a/xpp/utils/zconf/Zaptel/Xpp.pm b/xpp/utils/zconf/Zaptel/Xpp.pm index b627438..dd1f34c 100644 --- a/xpp/utils/zconf/Zaptel/Xpp.pm +++ b/xpp/utils/zconf/Zaptel/Xpp.pm @@ -5,7 +5,9 @@ package Zaptel::Xpp; # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; use Zaptel::Xpp::Xbus; my $proc_base = "/proc/xpp"; @@ -33,7 +35,7 @@ sub xbuses { $name =~ s/://; $name =~ /XBUS-(\d\d)/ or die "Bad XBUS number: $name"; my $num = $1; - @attr = map { $_ = uc($_); split(/=/); } @attr; + @attr = map { split(/=/); } @attr; my $xbus = Zaptel::Xpp::Xbus->new(NAME => $name, NUM => $num, @attr); push(@xbuses, $xbus); } @@ -51,6 +53,17 @@ sub xbuses { return sort $sorter @xbuses; } +sub xpd_of_span($) { + my $span = shift or die "Missing span parameter"; + return undef unless defined $span; + foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) { + foreach my $xpd ($xbus->xpds()) { + return $xpd if $xpd->fqn eq $span->name; + } + } + return undef; +} + sub sync { my $newsync = shift; my $result; diff --git a/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm b/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm index 8d9d340..772e050 100644 --- a/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm +++ b/xpp/utils/zconf/Zaptel/Xpp/Xbus.pm @@ -5,12 +5,15 @@ package Zaptel::Xpp::Xbus; # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; use Zaptel::Xpp::Xpd; my $proc_base = "/proc/xpp"; # Accessors (miniperl does not have Class:Accessor) +our $AUTOLOAD; sub AUTOLOAD { my $self = shift; my $name = uc($AUTOLOAD); @@ -27,9 +30,37 @@ sub xpds($) { return @{$xbus->{XPDS}}; } +sub by_number($) { + my $busnumber = shift; + die "Missing xbus number parameter" unless defined $busnumber; + my @xbuses = Zaptel::Xpp::xbuses(); + + my ($xbus) = grep { $_->num == $busnumber } @xbuses; + return $xbus; +} + +sub get_xpd_by_number($$) { + my $xbus = shift; + my $xpdnum = shift; + die "Missing XPD number parameter" unless defined $xpdnum; + my @xpds = $xbus->xpds; + return $xpds[$xpdnum]; +} + sub new($$) { my $pack = shift or die "Wasn't called as a class method\n"; - my $self = { @_ }; + my $self = {}; + while(@_) { + my ($k, $v) = @_; + shift; shift; + # Keys in all caps + $k = uc($k); + # Some values are in all caps as well + if($k =~ /^(STATUS)$/) { + $v = uc($v); + } + $self->{$k} = $v; + } bless $self, $pack; $self->{NAME} or die "Missing xbus name"; my $prefix = "$proc_base/" . $self->{NAME}; @@ -45,6 +76,7 @@ sub new($$) { ); push(@{$self->{XPDS}}, $xpd); } + @{$self->{XPDS}} = sort { $a->num <=> $b->num } @{$self->{XPDS}}; return $self; } diff --git a/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm b/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm index 180b7ea..94176b8 100644 --- a/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm +++ b/xpp/utils/zconf/Zaptel/Xpp/Xpd.pm @@ -5,11 +5,14 @@ package Zaptel::Xpp::Xpd; # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; my $proc_base = "/proc/xpp"; # Accessors (miniperl does not have Class:Accessor) +our $AUTOLOAD; sub AUTOLOAD { my $self = shift; my $name = uc($AUTOLOAD); @@ -21,6 +24,32 @@ sub AUTOLOAD { } } +sub blink($$) { + my $self = shift; + my $on = shift; + my $result; + + my $file = "$proc_base/" . $self->fqn . "/blink"; + die "$file is missing" unless -f $file; + # First query + open(F, "$file") or die "Failed to open $file for reading: $!"; + $result = ; + 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 zt_registration($$) { my $self = shift; my $on = shift; diff --git a/xpp/utils/zt_registration b/xpp/utils/zt_registration index 6ed388f..a1cb8ee 100755 --- a/xpp/utils/zt_registration +++ b/xpp/utils/zt_registration @@ -5,7 +5,9 @@ # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # -#use strict; +# $Id$ +# +use strict; BEGIN { my $dir = $0; $dir =~ s:/[^/]+$::; unshift(@INC, "$dir", "$dir/zconf"); } use Zaptel; @@ -19,36 +21,43 @@ sub usage { @ARGV == 0 or @ARGV == 1 or usage; my $on = shift; +my $verbose = 0; +my $should_output = 1; if(defined($on)) { # Translate to booleans $on = uc($on); $on =~ /^(ON|OFF|1|0)$/ or usage; $on = ($on eq 'ON') ? 1 : 0; + $should_output = 0 unless $verbose; } sub state2str($) { return (shift)?"on":"off"; } +sub myprintf { + printf @_ if $should_output; +} + my @spans = Zaptel::spans; foreach my $xbus (Zaptel::Xpp::xbuses('SORT_CONNECTOR')) { - printf "%-10s\t\t%s\n", $xbus->name, $xbus->connector; + myprintf "%-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; + myprintf "\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; + myprintf "2 %s %s\n", state2str($prev), $spanstr ; next; } if(!defined($prev)) { # Failure printf "Failed %s\n", $!; next; } - printf("%3s ==> %3s\n", state2str($prev), state2str($on)); + myprintf "3 %3s ==> %3s\n", state2str($prev), state2str($on); } } -- cgit v1.2.3