diff options
Diffstat (limited to 'xpp/utils')
-rw-r--r-- | xpp/utils/Makefile | 17 | ||||
-rw-r--r-- | xpp/utils/adj_clock.8 | 144 | ||||
-rw-r--r-- | xpp/utils/adj_clock.c | 228 | ||||
-rw-r--r-- | xpp/utils/fpga_load.8 | 22 | ||||
-rw-r--r-- | xpp/utils/fpga_load.c | 217 | ||||
-rwxr-xr-x | xpp/utils/genzaptelconf | 85 | ||||
-rw-r--r-- | xpp/utils/hexfile.c | 74 | ||||
-rw-r--r-- | xpp/utils/hexfile.h | 1 | ||||
-rwxr-xr-x | xpp/utils/lszaptel | 4 | ||||
-rwxr-xr-x | xpp/utils/xpp_blink | 115 | ||||
-rw-r--r-- | xpp/utils/xpp_fxloader | 34 | ||||
-rwxr-xr-x | xpp/utils/xpp_sync | 42 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel.pm | 5 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Chans.pm | 38 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Span.pm | 58 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Xpp.pm | 17 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Xpp/Xbus.pm | 36 | ||||
-rw-r--r-- | xpp/utils/zconf/Zaptel/Xpp/Xpd.pm | 31 | ||||
-rwxr-xr-x | xpp/utils/zt_registration | 19 |
19 files changed, 645 insertions, 542 deletions
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 <tzafrir.cohen@xorcom.com> -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 <tzafrir.cohen@xorcom.com> - * 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 <sys/timex.h> -#include <linux/param.h> -#include <syslog.h> -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/time.h> -#include <sys/signal.h> -#include <math.h> - -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<cycles_to_run; i++) { - sync_cycle(fd, interval); - } - hup_handler(0); /* exit */; - } - - /* else (option -c not provided): run forever. */ - for(;;) { - sync_cycle(fd, interval); - } -} diff --git a/xpp/utils/fpga_load.8 b/xpp/utils/fpga_load.8 index 640bbfd..412a839 100644 --- a/xpp/utils/fpga_load.8 +++ b/xpp/utils/fpga_load.8 @@ -5,10 +5,10 @@ ztcfg \- reads and loads zaptel.conf .SH SYNOPSIS .B fpga_load -[\fB-g\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR +[\fB-g\fR] [\fB-r\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR .B fpga_load -[\fB-g\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\fR] +[\fB-g\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\fR] [\fB-i\fR] .B fpga_load -h @@ -36,6 +36,11 @@ On older systems that use usbfs, it is usually /proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR. .RE +.B -r +.RS +Reset the Astribank and renumerate its USB connection to power on product ID. +.RE + .B -g .RS Dump all eeprom data to standard output. @@ -47,9 +52,20 @@ Dump all eeprom data to standard output. The firmware file to write to the device. .RE +.B -i +.RS +Show information about the firmware file (valid only with \fB-I\fR option). +Example: +.PP + ./FPGA_1151.hex: Version=3297 Checksum=58270 + +In particular, the calculated checksum should match the output of \fIsum(1)\fR +on the binary firmware file generated by the \fB-b\fR option. +.RE + .B -v .RS -Be verobse. +Increase verbosity. May be used multiple times. .RE .B -h diff --git a/xpp/utils/fpga_load.c b/xpp/utils/fpga_load.c index 2c03704..1cbd749 100644 --- a/xpp/utils/fpga_load.c +++ b/xpp/utils/fpga_load.c @@ -12,8 +12,8 @@ static const char rcsid[] = "$Id$"; #define ERR(fmt, arg...) do { \ if(verbose >= 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}/<bus>/<dev> [options...]\n", progname); fprintf(stderr, "\tOptions:\n"); - fprintf(stderr, "\t\t[-b <binfile>] # output to <binfile>\n"); + fprintf(stderr, "\t\t[-r] # Reset the device\n"); + fprintf(stderr, "\t\t[-b <binfile>] # Output to <binfile>\n"); fprintf(stderr, "\t\t[-I <hexfile>] # Input from <hexfile>\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 67a0263..4bf8a38 100755 --- a/xpp/utils/genzaptelconf +++ b/xpp/utils/genzaptelconf @@ -66,12 +66,18 @@ 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. # @@ -83,6 +89,12 @@ tmp_dir= # - The module that will be deleted from /etc/modules , if -d -M is used 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) @@ -106,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" @@ -197,8 +211,8 @@ 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() { @@ -234,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` @@ -306,8 +340,8 @@ print_pattern() { method="$fxs_default_start" fi case "$sig" in - fxs) sig_name=FXO; sig_name_sc=fxo ;; - fxo) sig_name=FXS; sig_name_sc=fxs ;; + fxs) sig_name=FXO;; + fxo) sig_name=FXS;; esac case "$mode" in list) @@ -419,7 +453,7 @@ print_pattern() { reset_zapata_entry $zapata_file $reset_values echo "" >> $zapata_file - print_zapscan_port "$sig_name_sc" "$chan" + print_zapscan_port "$sig" "$chan" ;; esac @@ -547,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 ;; @@ -566,12 +600,13 @@ reset_zapata_entry() { 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 } @@ -594,7 +629,9 @@ gen_tmp_conf() { orig_cfg_file=$1 new_var=$2 - eval $new_var=`mktemp -t genzaptelconf-zapata-XXXXXX` # assign by reference + # 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 @@ -731,8 +768,12 @@ write_digital_config() { 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" != '' ] @@ -744,6 +785,11 @@ write_digital_config() { 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 @@ -970,6 +1016,14 @@ EOF 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 } @@ -1001,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" @@ -1050,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 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 <oron@actcom.co.il> +# Copyright (C) 2007, Xorcom +# This program is free software; you can redistribute and/or +# modify it under the same terms as Perl itself. +# +# $Id$ +# +use strict; +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 <number> | xpd <bus num> [<xpd num>]}\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 <number> | xpd <bus num> [<xpd num>]}\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 = <F>; 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(<F>) { @@ -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 = <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 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); } } |