From 412c3f0fe3c777d06836954a5c5feb3b150557e1 Mon Sep 17 00:00:00 2001 From: Oron Peled Date: Wed, 28 May 2014 08:58:54 -0400 Subject: [PATCH] xpp: support per-port E1/T1 EC * Added optional '-S ' argument to astribank_hexload: - Allow passing PRI span specification to EC firmware loader. - The span specifications is whitespace/comma separate list of items. - Each item is: : (Example: 3:T1) - The may use shell-like globbing (e.g: *:E1 or [12]:T1) - Any span not matched in the span specification will be set as without the new '-S' option (i.e: depends on the '-A' option). * Adapted xpp_fxloader: - Read specification for both device label and wildcard from /etc/dahdi/span-types.conf - If the result is non-empty, pass it as '-S ' to the EC firmware loader. --- xpp/Makefile | 2 +- xpp/astribank_hexload.8 | 31 +++++++- xpp/astribank_hexload.c | 9 ++- xpp/echo_loader.c | 32 +++++++-- xpp/echo_loader.h | 2 +- xpp/parse_span_specs.c | 152 ++++++++++++++++++++++++++++++++++++++++ xpp/parse_span_specs.h | 43 ++++++++++++ xpp/xpp_fxloader | 65 +++++++++-------- 8 files changed, 292 insertions(+), 44 deletions(-) create mode 100644 xpp/parse_span_specs.c create mode 100644 xpp/parse_span_specs.h diff --git a/xpp/Makefile b/xpp/Makefile index cb5a618..12909f2 100644 --- a/xpp/Makefile +++ b/xpp/Makefile @@ -54,7 +54,7 @@ OCT_DEFINES = \ -DcOCT6100_MAX_ECHO_CHANNELS=672 \ -DcOCT6100_MAX_MIXER_EVENTS=1344 -ECHO_LOADER_SRC = echo_loader.c +ECHO_LOADER_SRC = echo_loader.c parse_span_specs.c ECHO_LOADER = $(ECHO_LOADER_SRC:.c=.o) endif diff --git a/xpp/astribank_hexload.8 b/xpp/astribank_hexload.8 index 76fa491..27913ff 100644 --- a/xpp/astribank_hexload.8 +++ b/xpp/astribank_hexload.8 @@ -7,7 +7,7 @@ astribank_hexload \- Xorcom Astribank (xpp) firmware loader .B astribank_hexload \-D \fIdevice-path\fR \-p [\fIoptions\fR] \fIhexfile1 .. hexfile4\fR -.B astribank_hexload \-D \fIdevice-path\fR \-O [-A] [\fIoptions\fR] \fIimagefile\fR +.B astribank_hexload \-D \fIdevice-path\fR \-O [-A] [-S \fIspan-specs\fR] [\fIoptions\fR] \fIimagefile\fR .B astribank_hexload \-D \fIdevice-path\fR \-o [\fIoptions\fR] @@ -29,7 +29,7 @@ It can be used to load either an FPGA firmware or a PIC firmware. It is normally run by the script xpp_fxloader. .SH OPTIONS -.B \-D +.B \-D .I device-path .RS Required. The device to read from/write to. This is @@ -95,13 +95,38 @@ use for BRI and E1. If not set, the default mu-Law (G.711u), which is what you'd normally use for FXS, FXO and T1. .RE +.B \-S \fIspan-specs\fR +.RS +This option should only be used when loading Octasic echo canceller firmware +and only if the first Astribank module is PRI. + +Its goal is to allow specifying different \fIline-mode\fR (E1/T1/J1) in different +ports of the PRI module. \fBastribank_hexload\fR use the \fIspan-specs\fR argument +to select aLaw/uLaw for each of the PRI ports in the module. + +The \fIspan-specs\fR is a list of items separated by whitespace or commas. +Each item is composed of a port selector, colon and a \fIline-mode\fR specifier. +This syntax follows the syntax of specifiers in \fB/etc/dahdi/span-types.conf\fR. + +Examples: +.RS +3:E1 \- The 3'rd port is E1. + +*:T1 \- Any unspecified port is T1 (wildcard match). + +1:T1,2:T1,*:E1 \- First and second ports are T1, the rest are E1. +.RE + +If the \fB\-S\fR is not given, the PRI default is determined by the existance of the \fB\-A-fR option. +.RE + .SH SEE ALSO fxload(8), lsusb(8), astribank_tool(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 +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 diff --git a/xpp/astribank_hexload.c b/xpp/astribank_hexload.c index 0fa9010..582dd40 100644 --- a/xpp/astribank_hexload.c +++ b/xpp/astribank_hexload.c @@ -50,6 +50,7 @@ static void usage() #if HAVE_OCTASIC fprintf(stderr, "\t\t[-O] # Load Octasic firmware\n"); fprintf(stderr, "\t\t[-o] # Show Octasic version\n"); + fprintf(stderr, "\t\t[-S ] # Set PRI type specification string\n"); #endif fprintf(stderr, "\t\t[-F] # Load FPGA firmware\n"); fprintf(stderr, "\t\t[-p] # Load PIC firmware\n"); @@ -164,11 +165,12 @@ int main(int argc, char *argv[]) int opt_ecver = 0; #if HAVE_OCTASIC int opt_alaw = 0; + const char *span_spec = NULL; #endif int opt_dest = 0; int opt_sum = 0; enum dev_dest dest = DEST_NONE; - const char options[] = "vd:D:EFOopA"; + const char options[] = "vd:D:EFOopAS:"; int iface_num; int ret; @@ -210,6 +212,9 @@ int main(int argc, char *argv[]) case 'A': opt_alaw = 1; break; + case 'S': + span_spec = optarg; + break; #endif case 'p': opt_pic = 1; @@ -290,7 +295,7 @@ int main(int argc, char *argv[]) } #if HAVE_OCTASIC } else if (opt_echo) { - if((ret = load_echo(astribank, argv[optind], opt_alaw)) < 0) { + if((ret = load_echo(astribank, argv[optind], opt_alaw, span_spec)) < 0) { ERR("%s: Loading ECHO's failed\n", devpath); return 1; } diff --git a/xpp/echo_loader.c b/xpp/echo_loader.c index 2291214..ca92883 100644 --- a/xpp/echo_loader.c +++ b/xpp/echo_loader.c @@ -31,6 +31,7 @@ #include "echo_loader.h" #include "debug.h" #include +#include "parse_span_specs.h" #define DBG_MASK 0x03 #define TIMEOUT 1000 @@ -560,7 +561,7 @@ inline int get_ver(struct astribank_device *astribank) } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -UINT32 init_octasic(char *filename, struct astribank_device *astribank, int is_alaw) +UINT32 init_octasic(char *filename, struct astribank_device *astribank, struct span_specs *span_specs) { int cpld_ver; struct echo_mod *echo_mod; @@ -580,6 +581,8 @@ UINT32 init_octasic(char *filename, struct astribank_device *astribank, int is_a /* Channel resources.*/ tOCT6100_CHANNEL_OPEN ChannelOpen; UINT32 ulChanHndl; + enum tdm_codec tdm_codec; + int spanno; if (test_send(astribank) < 0) return cOCT6100_ERR_FATAL; @@ -729,7 +732,17 @@ UINT32 init_octasic(char *filename, struct astribank_device *astribank, int is_a /* Set the channel to work at the echo cancellation mode.*/ ChannelOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_NORMAL; - pcmLaw = (is_alaw ? cOCT6100_PCM_A_LAW: cOCT6100_PCM_U_LAW); + spanno = nChan % 4; + assert(spanno >= 0 && spanno < MAX_SPANNO); + tdm_codec = span_specs->span_is_alaw[spanno]; + if (tdm_codec == TDM_CODEC_UNKNOWN) { + AB_ERR(astribank, "Calculated bad alaw/ulaw on channel %d\n", nChan); + return cOCT6100_ERR_FATAL; + } + if (nChan < 4) + AB_INFO(astribank, "ECHO PRI port %d = %s\n", spanno+1, (tdm_codec == TDM_CODEC_ALAW) ? "alaw" : "ulaw"); + + pcmLaw = ((tdm_codec == TDM_CODEC_ALAW) ? cOCT6100_PCM_A_LAW: cOCT6100_PCM_U_LAW); /* Configure the TDM interface.*/ ChannelOpen.TdmConfig.ulRinPcmLaw = pcmLaw; @@ -825,15 +838,22 @@ UINT32 init_octasic(char *filename, struct astribank_device *astribank, int is_a } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -int load_echo(struct astribank_device *astribank, char *filename, int is_alaw) +int load_echo(struct astribank_device *astribank, char *filename, int default_is_alaw, const char *span_spec) { int ret; UINT32 octasic_status; + struct span_specs *span_specs; - AB_INFO(astribank, "Loading ECHOCAN Firmware: %s (%s)\n", - filename, (is_alaw) ? "alaw" : "ulaw"); + span_specs = parse_span_specifications(span_spec, default_is_alaw); + if (!span_specs) { + AB_ERR(astribank, "ECHO parsing span specs failed\n"); + return -EFAULT; + } + AB_INFO(astribank, "Loading ECHOCAN Firmware: %s (default %s)\n", + filename, (default_is_alaw) ? "alaw" : "ulaw"); usb_buffer_init(astribank, &usb_buffer); - octasic_status = init_octasic(filename, astribank, is_alaw); + octasic_status = init_octasic(filename, astribank, span_specs); + free_span_specifications(span_specs); if (octasic_status != cOCT6100_ERR_OK) { AB_ERR(astribank, "ECHO %s burning failed (%08X)\n", filename, octasic_status); diff --git a/xpp/echo_loader.h b/xpp/echo_loader.h index 6e4e3a7..2bffda2 100644 --- a/xpp/echo_loader.h +++ b/xpp/echo_loader.h @@ -26,7 +26,7 @@ #include "astribank_usb.h" int spi_send(struct astribank_device *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver); -int load_echo(struct astribank_device *astribank, char *filename, int is_alaw); +int load_echo(struct astribank_device *astribank, char *filename, int is_alaw, const char *span_spec); int echo_ver(struct astribank_device *astribank); #endif /* ECHO_LOADER_H */ diff --git a/xpp/parse_span_specs.c b/xpp/parse_span_specs.c new file mode 100644 index 0000000..4cbc27f --- /dev/null +++ b/xpp/parse_span_specs.c @@ -0,0 +1,152 @@ +/* + * Written by Oron Peled + * Copyright (C) 2014, Xorcom + * + * 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 "parse_span_specs.h" + +void free_span_specifications(struct span_specs *span_specs) +{ + if (span_specs) { + if (span_specs->buf) + free(span_specs->buf); + free(span_specs); + } +} + +static enum tdm_codec is_alaw_span_type(const char *span_type) +{ + assert(span_type); + if (strcmp(span_type, "E1") == 0) + return TDM_CODEC_ALAW; + else if (strcmp(span_type, "T1") == 0) + return TDM_CODEC_ULAW; + return TDM_CODEC_UNKNOWN; +} + +struct span_specs *parse_span_specifications(const char *spec_string, int default_is_alaw) +{ + struct span_specs *span_specs; + char *p; + int spanno; + int i; + + if (!spec_string) + return NULL; + /* Allocate and Initialize */ + span_specs = calloc(sizeof(char *), MAX_SPANNO); + if (!span_specs) + goto err; + for (spanno = 0; spanno < MAX_SPANNO; spanno++) + span_specs->span_is_alaw[spanno] = TDM_CODEC_UNKNOWN; + span_specs->buf = strdup(spec_string); + if (!span_specs->buf) + goto err; + for (i = 0;; i++) { + char *curr_item; + char *tokenize_key; + char *key; + char *value; + enum tdm_codec is_alaw; + int matched; + + /* Split to items */ + p = (i == 0) ? span_specs->buf : NULL; + p = strtok_r(p, " \t,", &curr_item); + if (!p) + break; + + /* Split to : */ + key = strtok_r(p, ":", &tokenize_key); + if (!key) { + fprintf(stderr, + "Missing ':' (item #%d inside '%s')\n", + i+1, spec_string); + goto err; + } + value = strtok_r(NULL, ":", &tokenize_key); + if (!value) { + fprintf(stderr, + "Missing value after ':' (item #%d inside '%s')\n", + i+1, spec_string); + goto err; + } + + /* Match span specification and set alaw/ulaw */ + is_alaw = is_alaw_span_type(value); + if (is_alaw == TDM_CODEC_UNKNOWN) { + fprintf(stderr, + "Illegal span type '%s' (item #%d inside '%s')\n", + value, i+1, spec_string); + goto err; + } + matched = 0; + for (spanno = 0; spanno < MAX_SPANNO; spanno++) { + char tmpbuf[BUFSIZ]; + + snprintf(tmpbuf, sizeof(tmpbuf), "%d", spanno + 1); + if (fnmatch(p, tmpbuf, 0) == 0) { + matched++; + span_specs->span_is_alaw[spanno] = is_alaw; + } + } + if (!matched) { + fprintf(stderr, + "Span specification '%s' does not match any span (item #%d inside '%s')\n", + key, i+1, spec_string); + goto err; + } + } + + /* Set defaults */ + for (spanno = 0; spanno < MAX_SPANNO; spanno++) { + if (span_specs->span_is_alaw[spanno] == TDM_CODEC_UNKNOWN) { + span_specs->span_is_alaw[spanno] = default_is_alaw; + } + } + return span_specs; +err: + free_span_specifications(span_specs); + return NULL; +} + +void print_span_specifications(struct span_specs *span_specs, FILE *output) +{ + int spanno; + + if (!span_specs) + return; + for (spanno = 0; spanno < MAX_SPANNO; spanno++) { + enum tdm_codec is_alaw; + + is_alaw = span_specs->span_is_alaw[spanno]; + fprintf(output, "%d %s\n", + spanno+1, (is_alaw == TDM_CODEC_ALAW) ? "alaw" : "ulaw"); + } +} diff --git a/xpp/parse_span_specs.h b/xpp/parse_span_specs.h new file mode 100644 index 0000000..b7dddf9 --- /dev/null +++ b/xpp/parse_span_specs.h @@ -0,0 +1,43 @@ +#ifndef PARSE_SPAN_SPECS_H +#define PARSE_SPAN_SPECS_H + +/* + * Written by Oron Peled + * Copyright (C) 2014, Xorcom + * + * 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. + * + */ + +#define MAX_SPANNO 4 /* E1/T1 spans -- always in first unit. 1-based */ + +enum tdm_codec { + TDM_CODEC_UNKNOWN, + TDM_CODEC_ULAW, + TDM_CODEC_ALAW, +}; + +struct span_specs { + char *buf; + enum tdm_codec span_is_alaw[MAX_SPANNO]; +}; + +struct span_specs *parse_span_specifications(const char *spec_string, int default_is_alaw); +void free_span_specifications(struct span_specs *span_specs); +void print_span_specifications(struct span_specs *span_specs, FILE *output); + +#endif /* PARSE_SPAN_SPECS_H */ diff --git a/xpp/xpp_fxloader b/xpp/xpp_fxloader index b5173a4..5c8bced 100644 --- a/xpp/xpp_fxloader +++ b/xpp/xpp_fxloader @@ -272,10 +272,12 @@ usb_firmware_all_devices() { } filter_span_types() { - #sed -n -e 's/#.*//' -e 's/[ \t]*$//' -e 's/^[ \t]*//' -e 's/^\*[ \t]\+\*://p' /etc/dahdi/span-types.conf + l="$1" sed < "$SPAN_TYPES_CONFIG" 2>/dev/null \ -e 's/#.*//' \ - -e 's/[ \t]*$//' + -e 's/[ \t]*$//' \ + -e 's/^[ \t]*//' \ + -e '/^$/d' | awk -vlabel="$l" '$1 == label { print $2 }' | tr -s ', \t\n' ',' } load_fw_device() { @@ -287,60 +289,61 @@ load_fw_device() { FPGA_1161*.hex) echo_file="$FIRMWARE_DIR/OCT6104E-256D.ima" law='' - law_str='uLaw' + dev_short=`echo "$dev" | sed -e 's,.*/usb/*,,'` abtool_output=`$ASTRIBANK_TOOL -D "$dev" -Q 2>&1` ec_card_type=`echo "$abtool_output" | grep 'CARD 4' | sed -e 's/.*type=//' -e 's/\..*//'` caps_num=`echo "$abtool_output" | grep 'ECHO ports' | sed -e 's/.*: *//'` if [ "$ec_card_type" = '5' ]; then - debug "ECHO burning into $dev: $echo_file" + debug "ECHO($dev_short): Firmware $echo_file" card_type=`echo "$abtool_output" | grep 'CARD 0' | sed -e 's/.*type=//' -e 's/\..*//'` case "$card_type" in 3) law="-A";; 4) - pri_protocol='' - dev_short=`echo "$dev" | sed -e 's,.*/usb/*,,' -e 's,/,:,'` + dev_lsusb=`echo "$dev_short" | tr '/' ':'` # Try modern configuration if [ -r "$SPAN_TYPES_CONFIG" ]; then # Try exact match by label - label=`lsusb -s "$dev_short" -v 2>/dev/null | awk '$1 == "iSerial" && $2 == 3 { print $3 }'` + label=`lsusb -s "$dev_lsusb" -v 2>/dev/null | awk '$1 == "iSerial" && $2 == 3 { print $3 }'` if [ "$label" != '' ]; then label="usb:$label" - debug "ECHO: checking device $dev_short [$label]" - pri_protocol=`filter_span_types | sed -n "s/^${label}[ \t]\+[0-9*]://p"` - if [ "$pri_protocol" != '' ]; then - debug "ECHO: device $dev_short [$label] will be set to $pri_protocol" + debug "ECHO($dev_short): Search span-types.conf for [$label]" + pri_spec=`filter_span_types "${label}"` + if [ "$pri_spec" != '' ]; then + debug "ECHO($dev_short): Found definitions for [$label] -- '$pri_spec'" fi else - debug "ECHO: Device $dev_short without a label" + debug "ECHO($dev_short): Device without a label" fi - # Fallback to wildcard match - if [ "$pri_protocol" = '' ]; then - pri_protocol=`filter_span_types | sed -n 's/^\*[ \t]\+\*://p'` - if [ "$pri_protocol" != '' ]; then - debug "ECHO: device $dev_short will be set to $pri_protocol (wildcard match)" - fi + # Check wildcard match + pri_spec_wildcard=`filter_span_types '*'` + if [ "$pri_spec_wildcard" != '' ]; then + debug "ECHO($dev_short): Found definitions for wildcard -- $pri_spec_wildcard" + fi + pri_spec=`echo "$pri_spec_wildcard $pri_spec" | tr -s ' \t\n' ','` + if [ "$pri_spec" != '' ]; then + pri_spec_params="-S $pri_spec" + debug "ECHO($dev_short): pri_spec_params='$pri_spec_params'" fi fi # Fallback to legacy xpp.conf - if [ "$pri_protocol" = '' -a -r "$XPP_CONFIG" ]; then - pri_protocol=`awk '/^pri_protocol/ {print $2}' $XPP_CONFIG` - if [ "$pri_protocol" != '' ]; then - debug "ECHO: device $dev_short will be set to $pri_protocol (legacy xpp.conf setting)" + default_pri_protocol='' + default_law='' + if [ -r "$XPP_CONFIG" ]; then + default_pri_protocol=`awk '/^pri_protocol/ {print $2}' $XPP_CONFIG` + if [ "$default_pri_protocol" != '' ]; then + debug "ECHO($dev_short): Found legacy xpp.conf setting -- $default_pri_protocol" + # "E1" or empty (implied E1) means aLaw + if [ "$default_pri_protocol" != 'T1' ]; then + default_law='-A' + fi fi fi - # "E1" or empty (implied E1) means aLaw - if [ "$pri_protocol" != 'T1' ]; then - law='-A' - fi ;; esac - if [ "$law" = '-A' ]; then - law_str="aLaw" - fi caps_num=`echo "$abtool_output" | grep 'ECHO ports' | sed -e 's/.*: *//'` - debug "ECHO: 1st module is $law_str, $caps_num channels allowed." + debug "ECHO($dev_short): $caps_num channels allowed." if [ "$caps_num" != '0' ]; then - run_astribank_hexload -D "$dev" -O $law "$echo_file" + run_astribank_hexload -D "$dev" -O $default_law $pri_spec_params "$echo_file" else echo "WARNING: ECHO burning was skipped (no capabilities)" fi