xpp: support per-port E1/T1 EC
authorOron Peled <oron.peled@xorcom.com>
Wed, 28 May 2014 12:58:54 +0000 (08:58 -0400)
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>
Sun, 29 Jun 2014 13:34:21 +0000 (16:34 +0300)
* 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.

xpp/Makefile
xpp/astribank_hexload.8
xpp/astribank_hexload.c
xpp/echo_loader.c
xpp/echo_loader.h
xpp/parse_span_specs.c [new file with mode: 0644]
xpp/parse_span_specs.h [new file with mode: 0644]
xpp/xpp_fxloader

index cb5a618..12909f2 100644 (file)
@@ -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
 
index 76fa491..27913ff 100644 (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 \-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 <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 
+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
index 0fa9010..582dd40 100644 (file)
@@ -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 <pri-spec>]    # 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;
                        }
index 2291214..ca92883 100644 (file)
@@ -31,6 +31,7 @@
 #include "echo_loader.h"
 #include "debug.h"
 #include <oct6100api/oct6100_api.h>
+#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);
index 6e4e3a7..2bffda2 100644 (file)
@@ -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 (file)
index 0000000..4cbc27f
--- /dev/null
@@ -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");
+       }
+}
diff --git a/xpp/parse_span_specs.h b/xpp/parse_span_specs.h
new file mode 100644 (file)
index 0000000..b7dddf9
--- /dev/null
@@ -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 */
index b5173a4..5c8bced 100644 (file)
@@ -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