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 <andreas(a)eversberg.eu>