jolly has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmo-e1d/+/41139?usp=email )


Change subject: Add Channel-Associated Signalling (CAS) support
......................................................................

Add Channel-Associated Signalling (CAS) support

CAS frames are sent and received repeatedly. They consist of 16 frames
(octets) on time slot 16. This is a CAS multi frame. This multiframe
carries 30 individual CAS signaling channels.

Whenever a CAS frame is received, the included 30 CAS channels are
forwarded to the application with a message of 30 octets, one octet for
each CAS channel.

The application requests to transmit a CAS frame by sending a message
with 30 octets, one for each CAS channel. Most recent CAS frame will be
transmitted repeatedly until the application sends a new message.

The 30 octets in the message correspond to the signaling channels of
these 30 time slots:
     1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15
    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31

The lower 4 bits of each octet in the message represent the signaling
sub-channels: A, B, C and D. They are packed like this: '0000ABCD'

Change-Id: Ib4f5e6ef02c9b0d1eec2a86d9c48376112805972
---
M include/osmocom/e1d/proto.h
M src/ctl.c
M src/e1d.h
M src/mux_demux.c
M src/proto.c
M src/vty.c
6 files changed, 178 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-e1d refs/changes/39/41139/1

diff --git a/include/osmocom/e1d/proto.h b/include/osmocom/e1d/proto.h
index 6481b62..e4219df 100644
--- a/include/osmocom/e1d/proto.h
+++ b/include/osmocom/e1d/proto.h
@@ -118,6 +118,8 @@
        E1DP_TSMODE_RAW         = 0x10,
        /*! Timeslot is in HLDC-FCS mode; e1d will run software HDLC processor. 
*/
        E1DP_TSMODE_HDLCFCS     = 0x11,
+       /*! Timeslot is in CAS mode; e1d will run software CAS processor. */
+       E1DP_TSMODE_CAS         = 0x12,
 };

 /*! Flag that can be used as osmo_e1dp_ts_config.flags to force opening a TS. 
*/
diff --git a/src/ctl.c b/src/ctl.c
index a9818b3..d8f47ba 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -92,6 +92,9 @@
        case E1_TS_MODE_HDLCFCS:
                ti->cfg.mode = E1DP_TSMODE_HDLCFCS;
                break;
+       case E1_TS_MODE_CAS:
+               ti->cfg.mode = E1DP_TSMODE_CAS;
+               break;
        case E1_TS_MODE_OFF:
                ti->cfg.mode = E1DP_TSMODE_OFF;
                break;
@@ -141,6 +144,7 @@

        switch (mode) {
        case E1_TS_MODE_HDLCFCS:
+       case E1_TS_MODE_CAS:
                sock_type = SOCK_SEQPACKET;
                break;
        case E1_TS_MODE_RAW:
@@ -163,6 +167,11 @@
                osmo_isdnhdlc_rcv_init(&ts->hdlc.rx, OSMO_HDLC_F_BITREVERSE);
        }

+       if (mode == E1_TS_MODE_CAS) {
+               memset(&ts->cas.tx, 0, sizeof(ts->cas.tx));
+               memset(ts->cas.tx.buf, 0xff, sizeof(ts->cas.tx.buf));
+       }
+
        int flags = fcntl(ts->fd, F_GETFL);
        if (flags < 0)
                goto out_err;
@@ -387,6 +396,14 @@
        case E1DP_TSMODE_HDLCFCS:
                mode = E1_TS_MODE_HDLCFCS;
                break;
+       case E1DP_TSMODE_CAS:
+               if (hdr->ts != 16) {
+                       LOGPTS(ts, DE1D, LOGL_NOTICE, "Client request CAS for 
timeslot %d, "
+                              "only timeslot 16 is allowed.\n", hdr->ts);
+                       return 0;
+               }
+               mode = E1_TS_MODE_CAS;
+               break;
        default:
                LOGPTS(ts, DE1D, LOGL_NOTICE, "Client request for unknown mode 
%u\n", cfg->mode);
                return 0;
diff --git a/src/e1d.h b/src/e1d.h
index 55e5415..0a2b265 100644
--- a/src/e1d.h
+++ b/src/e1d.h
@@ -75,6 +75,7 @@
        E1_TS_MODE_OFF = 0,
        E1_TS_MODE_RAW,
        E1_TS_MODE_HDLCFCS,
+       E1_TS_MODE_CAS,
 };
 extern const struct value_string e1_ts_mode_names[];

@@ -83,6 +84,26 @@
        E1_FRAMING_MODE_NO_CRC4,
 };

+enum e1_cas_state {
+       E1_CAS_STATE_UNSYNC = 0,
+       E1_CAS_STATE_SYNC,
+};
+
+#define E1_CAS_SYNC_VALID      4
+
+struct e1_cas_tx {
+       uint8_t frame_count;
+       uint8_t buf[30];
+};
+
+struct e1_cas_rx {
+       enum e1_cas_state state;
+       uint8_t frame_count;
+       uint8_t sync_count;
+       uint8_t buf[30];
+       bool    new_data;
+};
+
 struct e1_ts {
        struct e1_line *line;
        uint8_t id;
@@ -101,6 +122,12 @@
                int tx_len;
        } hdlc;

+       /* CAS handling */
+       struct {
+               struct e1_cas_tx tx;
+               struct e1_cas_rx rx;
+       } cas;
+
        /* RAW handling */
        struct {
                uint8_t *rx_buf;                /* actual buffer storage */
diff --git a/src/mux_demux.c b/src/mux_demux.c
index 72379fe..f5bea91 100644
--- a/src/mux_demux.c
+++ b/src/mux_demux.c
@@ -118,6 +118,45 @@
        return len;
 }

+static int
+_e1_tx_cas(struct e1_ts *ts, uint8_t *buf, int len)
+{
+       int rv, i;
+       bool got_update = false;
+
+       /* Get most recent update of all the signaling bits, if any. */
+       while ((rv = recv(ts->fd, ts->cas.tx.buf, sizeof(ts->cas.tx.buf), 
MSG_TRUNC)) > 0) {
+               if (rv > (int)sizeof(ts->cas.tx.buf)) {
+                       LOGPTS(ts, DXFR, LOGL_ERROR, "Truncated message: Client 
tries to "
+                                                    "send %d bytes but our 
buffer is limited to %zu\n",
+                              rv, sizeof(ts->cas.tx.buf));
+                       rv = sizeof(ts->cas.tx.buf);
+               }
+               LOGPTS(ts, DXFR, LOGL_DEBUG, "TX CAS Message: %s\n", 
osmo_hexdump(ts->cas.tx.buf, rv));
+               for (i = 0; i < ((rv < 15) ? rv : 15); i++) {
+                       if ((ts->cas.tx.buf[i] & 0xf) == 0x0) {
+                               LOGPTS(ts, DXFR, LOGL_ERROR,
+                                      "TX CAS ERROR: Channel %d/30 imitates 
frame alignment.\n", i + 1);
+                       }
+               }
+               got_update = true;
+       }
+       if (!got_update && ((rv < 0 && errno != EAGAIN) || rv == 0))
+               return rv;
+
+       for (i = 0; i < len; i++) {
+               if ((ts->cas.tx.frame_count) == 0) {
+                       buf[i] = 0x0b;
+               } else {
+                       buf[i] = ts->cas.tx.buf[(ts->cas.tx.frame_count) - 1] 
<< 4;
+                       buf[i] |= ts->cas.tx.buf[(ts->cas.tx.frame_count) + 14];
+               }
+               ts->cas.tx.frame_count = (ts->cas.tx.frame_count + 1) & 0xf;
+       }
+
+       return len;
+}
+
 /* read from a timeslot-FD (direction application -> hardware) */
 static int
 _e1_ts_read(struct e1_ts *ts, uint8_t *buf, size_t len)
@@ -131,6 +170,9 @@
        case E1_TS_MODE_HDLCFCS:
                l = _e1_tx_hdlcfs(ts, buf, len);
                break;
+       case E1_TS_MODE_CAS:
+               l = _e1_tx_cas(ts, buf, len);
+               break;
        default:
                OSMO_ASSERT(0);
                break;
@@ -306,6 +348,91 @@
        return len;
 }

+static int
+_e1_rx_cas(struct e1_ts *ts, const uint8_t *buf, int len)
+{
+       int rv = 1, i;
+
+       for (i = 0; i < len; i++) {
+               switch (ts->cas.rx.state) {
+               case E1_CAS_STATE_UNSYNC:
+                       /* Find sync mark '0000xxxx'. */
+                       if (!ts->cas.rx.sync_count) {
+                               /* If we found our first sync mark, align with 
it. */
+                               if ((buf[i] & 0xf0) == 0x00) {
+                                       ts->cas.rx.sync_count = 1;
+                                       ts->cas.rx.frame_count = 0;
+                               }
+                               break;
+                       }
+                       /* This is not a sync mark. */
+                       if ((buf[i] & 0xf0) != 0x00) {
+                               if (ts->cas.rx.frame_count != 0)
+                                       break;
+                               /* If we expect a sync mark, reset sync 
counter. */
+                               ts->cas.rx.sync_count = 0;
+                               break;
+                       }
+                       /* This is a sync mark. */
+                       if (ts->cas.rx.frame_count != 0) {
+                               /* We got a sync mark at different frame count, 
align again. */
+                               ts->cas.rx.sync_count = 1;
+                               ts->cas.rx.frame_count = 0;
+                               break;
+                       }
+                       /* Count until the sync is valid. */
+                       if (++ts->cas.rx.sync_count < E1_CAS_SYNC_VALID)
+                               break;
+                       ts->cas.rx.state = E1_CAS_STATE_SYNC;
+                       LOGPTS(ts, DE1D, LOGL_INFO, "CAS frame now in sync.\n");
+                       /* FALLTHRU */
+               case E1_CAS_STATE_SYNC:
+                       /* Check if we are still in sync. */
+                       if (ts->cas.rx.frame_count == 0) {
+                               if ((buf[i] & 0xf0) == 0x00) {
+                                       /* Set valid-counter to upper limit. */
+                                       ts->cas.rx.sync_count = 
E1_CAS_SYNC_VALID;
+                               } else {
+                                       /* Count down until sync expires. */
+                                       if (--ts->cas.rx.sync_count == 0) {
+                                               LOGPTS(ts, DE1D, LOGL_INFO, 
"CAS frame sync lost.\n");
+                                               ts->cas.rx.sync_count = 0;
+                                               ts->cas.rx.state = 
E1_CAS_STATE_UNSYNC;
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+                       /* Skip frame, if sync was not found for this frame. */
+                       if (ts->cas.rx.sync_count < E1_CAS_SYNC_VALID)
+                               break;
+                       /* Store received subframe. */
+                       if (ts->cas.rx.buf[ts->cas.rx.frame_count - 1] != 
(buf[i] >> 4)) {
+                               ts->cas.rx.buf[ts->cas.rx.frame_count - 1] = 
(buf[i] >> 4);
+                               ts->cas.rx.new_data = true;
+                       }
+                       if (ts->cas.rx.buf[ts->cas.rx.frame_count + 14] != 
(buf[i] & 0x0f)) {
+                               ts->cas.rx.buf[ts->cas.rx.frame_count + 14] = 
(buf[i] & 0x0f);
+                               ts->cas.rx.new_data = true;
+                       }
+                       /* Forward mulitframe to application. Even if there is 
no change, the appliction
+                        * may need it to clock a filter (for detecting stable 
signals). */
+                       if (ts->cas.rx.frame_count == 15) {
+                               rv = write(ts->fd, ts->cas.rx.buf, 
sizeof(ts->cas.rx.buf));
+                               if (ts->cas.rx.new_data) {
+                                       LOGPTS(ts, DXFR, LOGL_DEBUG, "RX CAS 
Message: %s\n",
+                                               osmo_hexdump(ts->cas.rx.buf, 
sizeof(ts->cas.rx.buf)));
+                                       ts->cas.rx.new_data = false;
+                               }
+                       }
+                       break;
+               }
+               ts->cas.rx.frame_count = (ts->cas.rx.frame_count + 1) % 16;
+       }
+
+       return (rv <= 0) ? rv : i;
+}
+
 /* write data to a timeslot (hardware -> application direction) */
 static int
 _e1_ts_write(struct e1_ts *ts, const uint8_t *buf, size_t len)
@@ -319,6 +446,9 @@
        case E1_TS_MODE_HDLCFCS:
                rv = _e1_rx_hdlcfs(ts, buf, len);
                break;
+       case E1_TS_MODE_CAS:
+               rv = _e1_rx_cas(ts, buf, len);
+               break;
        default:
                OSMO_ASSERT(0);
                break;
diff --git a/src/proto.c b/src/proto.c
index b7e50bc..acd7e8c 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -65,6 +65,7 @@
        { E1DP_TSMODE_OFF,      "OFF" },
        { E1DP_TSMODE_RAW,      "RAW" },
        { E1DP_TSMODE_HDLCFCS,  "HDLC-FCS" },
+       { E1DP_TSMODE_CAS,      "CAS" },
        { 0, NULL }
 };

diff --git a/src/vty.c b/src/vty.c
index 3e80204..77ed708 100644
--- a/src/vty.c
+++ b/src/vty.c
@@ -158,6 +158,7 @@
        { E1_TS_MODE_OFF,       "off" },
        { E1_TS_MODE_RAW,       "raw" },
        { E1_TS_MODE_HDLCFCS,   "hdlc-fcs" },
+       { E1_TS_MODE_CAS,       "cas" },
        { 0, NULL }
 };


--
To view, visit https://gerrit.osmocom.org/c/osmo-e1d/+/41139?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: osmo-e1d
Gerrit-Branch: master
Gerrit-Change-Id: Ib4f5e6ef02c9b0d1eec2a86d9c48376112805972
Gerrit-Change-Number: 41139
Gerrit-PatchSet: 1
Gerrit-Owner: jolly <[email protected]>

Reply via email to