xpp: support per-port E1/T1 EC

* Added optional '-S <span-spec>' 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: <span>:<type> (Example: 3:T1)
  - The <span> 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 <span-spec>' to
    the EC firmware loader.
This commit is contained in:
Oron Peled 2014-05-28 08:58:54 -04:00 committed by Tzafrir Cohen
parent fc459c374c
commit 412c3f0fe3
8 changed files with 292 additions and 44 deletions

View File

@ -54,7 +54,7 @@ OCT_DEFINES = \
-DcOCT6100_MAX_ECHO_CHANNELS=672 \ -DcOCT6100_MAX_ECHO_CHANNELS=672 \
-DcOCT6100_MAX_MIXER_EVENTS=1344 -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) ECHO_LOADER = $(ECHO_LOADER_SRC:.c=.o)
endif endif

View File

@ -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 \-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] .B astribank_hexload \-D \fIdevice-path\fR \-o [\fIoptions\fR]
@ -95,6 +95,31 @@ 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. what you'd normally use for FXS, FXO and T1.
.RE .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 .SH SEE ALSO
fxload(8), lsusb(8), astribank_tool(8) fxload(8), lsusb(8), astribank_tool(8)

View File

@ -50,6 +50,7 @@ static void usage()
#if HAVE_OCTASIC #if HAVE_OCTASIC
fprintf(stderr, "\t\t[-O] # Load Octasic firmware\n"); fprintf(stderr, "\t\t[-O] # Load Octasic firmware\n");
fprintf(stderr, "\t\t[-o] # Show Octasic version\n"); fprintf(stderr, "\t\t[-o] # Show Octasic version\n");
fprintf(stderr, "\t\t[-S <pri-spec>] # Set PRI type specification string\n");
#endif #endif
fprintf(stderr, "\t\t[-F] # Load FPGA firmware\n"); fprintf(stderr, "\t\t[-F] # Load FPGA firmware\n");
fprintf(stderr, "\t\t[-p] # Load PIC 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; int opt_ecver = 0;
#if HAVE_OCTASIC #if HAVE_OCTASIC
int opt_alaw = 0; int opt_alaw = 0;
const char *span_spec = NULL;
#endif #endif
int opt_dest = 0; int opt_dest = 0;
int opt_sum = 0; int opt_sum = 0;
enum dev_dest dest = DEST_NONE; enum dev_dest dest = DEST_NONE;
const char options[] = "vd:D:EFOopA"; const char options[] = "vd:D:EFOopAS:";
int iface_num; int iface_num;
int ret; int ret;
@ -210,6 +212,9 @@ int main(int argc, char *argv[])
case 'A': case 'A':
opt_alaw = 1; opt_alaw = 1;
break; break;
case 'S':
span_spec = optarg;
break;
#endif #endif
case 'p': case 'p':
opt_pic = 1; opt_pic = 1;
@ -290,7 +295,7 @@ int main(int argc, char *argv[])
} }
#if HAVE_OCTASIC #if HAVE_OCTASIC
} else if (opt_echo) { } 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); ERR("%s: Loading ECHO's failed\n", devpath);
return 1; return 1;
} }

View File

@ -31,6 +31,7 @@
#include "echo_loader.h" #include "echo_loader.h"
#include "debug.h" #include "debug.h"
#include <oct6100api/oct6100_api.h> #include <oct6100api/oct6100_api.h>
#include "parse_span_specs.h"
#define DBG_MASK 0x03 #define DBG_MASK 0x03
#define TIMEOUT 1000 #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; int cpld_ver;
struct echo_mod *echo_mod; struct echo_mod *echo_mod;
@ -580,6 +581,8 @@ UINT32 init_octasic(char *filename, struct astribank_device *astribank, int is_a
/* Channel resources.*/ /* Channel resources.*/
tOCT6100_CHANNEL_OPEN ChannelOpen; tOCT6100_CHANNEL_OPEN ChannelOpen;
UINT32 ulChanHndl; UINT32 ulChanHndl;
enum tdm_codec tdm_codec;
int spanno;
if (test_send(astribank) < 0) if (test_send(astribank) < 0)
return cOCT6100_ERR_FATAL; 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.*/ /* Set the channel to work at the echo cancellation mode.*/
ChannelOpen.ulEchoOperationMode = cOCT6100_ECHO_OP_MODE_NORMAL; 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.*/ /* Configure the TDM interface.*/
ChannelOpen.TdmConfig.ulRinPcmLaw = pcmLaw; 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; int ret;
UINT32 octasic_status; UINT32 octasic_status;
struct span_specs *span_specs;
AB_INFO(astribank, "Loading ECHOCAN Firmware: %s (%s)\n", span_specs = parse_span_specifications(span_spec, default_is_alaw);
filename, (is_alaw) ? "alaw" : "ulaw"); 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); 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) { if (octasic_status != cOCT6100_ERR_OK) {
AB_ERR(astribank, "ECHO %s burning failed (%08X)\n", AB_ERR(astribank, "ECHO %s burning failed (%08X)\n",
filename, octasic_status); filename, octasic_status);

View File

@ -26,7 +26,7 @@
#include "astribank_usb.h" #include "astribank_usb.h"
int spi_send(struct astribank_device *astribank, uint16_t addr, uint16_t data, int recv_answer, int ver); 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); int echo_ver(struct astribank_device *astribank);
#endif /* ECHO_LOADER_H */ #endif /* ECHO_LOADER_H */

152
xpp/parse_span_specs.c Normal file
View File

@ -0,0 +1,152 @@
/*
* Written by Oron Peled <oron@actcom.co.il>
* 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 <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <regex.h>
#include <fnmatch.h>
#include <sys/time.h>
#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 <span>:<type> */
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");
}
}

43
xpp/parse_span_specs.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef PARSE_SPAN_SPECS_H
#define PARSE_SPAN_SPECS_H
/*
* Written by Oron Peled <oron@actcom.co.il>
* 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 */

View File

@ -272,10 +272,12 @@ usb_firmware_all_devices() {
} }
filter_span_types() { 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 \ sed < "$SPAN_TYPES_CONFIG" 2>/dev/null \
-e 's/#.*//' \ -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() { load_fw_device() {
@ -287,60 +289,61 @@ load_fw_device() {
FPGA_1161*.hex) FPGA_1161*.hex)
echo_file="$FIRMWARE_DIR/OCT6104E-256D.ima" echo_file="$FIRMWARE_DIR/OCT6104E-256D.ima"
law='' law=''
law_str='uLaw' dev_short=`echo "$dev" | sed -e 's,.*/usb/*,,'`
abtool_output=`$ASTRIBANK_TOOL -D "$dev" -Q 2>&1` abtool_output=`$ASTRIBANK_TOOL -D "$dev" -Q 2>&1`
ec_card_type=`echo "$abtool_output" | grep 'CARD 4' | sed -e 's/.*type=//' -e 's/\..*//'` 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/.*: *//'` caps_num=`echo "$abtool_output" | grep 'ECHO ports' | sed -e 's/.*: *//'`
if [ "$ec_card_type" = '5' ]; then 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/\..*//'` card_type=`echo "$abtool_output" | grep 'CARD 0' | sed -e 's/.*type=//' -e 's/\..*//'`
case "$card_type" in case "$card_type" in
3) law="-A";; 3) law="-A";;
4) 4)
pri_protocol='' dev_lsusb=`echo "$dev_short" | tr '/' ':'`
dev_short=`echo "$dev" | sed -e 's,.*/usb/*,,' -e 's,/,:,'`
# Try modern configuration # Try modern configuration
if [ -r "$SPAN_TYPES_CONFIG" ]; then if [ -r "$SPAN_TYPES_CONFIG" ]; then
# Try exact match by label # 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 if [ "$label" != '' ]; then
label="usb:$label" label="usb:$label"
debug "ECHO: checking device $dev_short [$label]" debug "ECHO($dev_short): Search span-types.conf for [$label]"
pri_protocol=`filter_span_types | sed -n "s/^${label}[ \t]\+[0-9*]://p"` pri_spec=`filter_span_types "${label}"`
if [ "$pri_protocol" != '' ]; then if [ "$pri_spec" != '' ]; then
debug "ECHO: device $dev_short [$label] will be set to $pri_protocol" debug "ECHO($dev_short): Found definitions for [$label] -- '$pri_spec'"
fi fi
else else
debug "ECHO: Device $dev_short without a label" debug "ECHO($dev_short): Device without a label"
fi fi
# Fallback to wildcard match # Check wildcard match
if [ "$pri_protocol" = '' ]; then pri_spec_wildcard=`filter_span_types '*'`
pri_protocol=`filter_span_types | sed -n 's/^\*[ \t]\+\*://p'` if [ "$pri_spec_wildcard" != '' ]; then
if [ "$pri_protocol" != '' ]; then debug "ECHO($dev_short): Found definitions for wildcard -- $pri_spec_wildcard"
debug "ECHO: device $dev_short will be set to $pri_protocol (wildcard match)"
fi 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
fi fi
# Fallback to legacy xpp.conf # Fallback to legacy xpp.conf
if [ "$pri_protocol" = '' -a -r "$XPP_CONFIG" ]; then default_pri_protocol=''
pri_protocol=`awk '/^pri_protocol/ {print $2}' $XPP_CONFIG` default_law=''
if [ "$pri_protocol" != '' ]; then if [ -r "$XPP_CONFIG" ]; then
debug "ECHO: device $dev_short will be set to $pri_protocol (legacy xpp.conf setting)" default_pri_protocol=`awk '/^pri_protocol/ {print $2}' $XPP_CONFIG`
fi if [ "$default_pri_protocol" != '' ]; then
fi debug "ECHO($dev_short): Found legacy xpp.conf setting -- $default_pri_protocol"
# "E1" or empty (implied E1) means aLaw # "E1" or empty (implied E1) means aLaw
if [ "$pri_protocol" != 'T1' ]; then if [ "$default_pri_protocol" != 'T1' ]; then
law='-A' default_law='-A'
fi
fi
fi fi
;; ;;
esac esac
if [ "$law" = '-A' ]; then
law_str="aLaw"
fi
caps_num=`echo "$abtool_output" | grep 'ECHO ports' | sed -e 's/.*: *//'` 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 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 else
echo "WARNING: ECHO burning was skipped (no capabilities)" echo "WARNING: ECHO burning was skipped (no capabilities)"
fi fi