e1cap_dump: Add SC (Super Channel) mode

In the super channel mode, it seems the BTS transmits one byte in each
timeslot, accross the entire link.

This basically means that if you have a 10 byte long signalling message
to be sent, its first byte will be in TS1 up until the tenth byte in
TS10.

As we are reading in 160 byte chunks from the E1 timeslots, we build a
matrix with 160 columns (for each byte) and 24/30 rows (timeslots).  So
we write 24 times 160 bytes into the matrix.

Once we have completed all timeslots, we start to read the matrix by
reading byte 0 of each timeslot (in incrementing TS order), next byte 1
of each timeslot, ... until we end up having read 160 times 24 bytes
from the matrix.

The resulting bitstream needs to be HDLC-synchronized and the resulting
messages passed up for further decoding.
This commit is contained in:
Harald Welte 2016-10-23 19:36:14 +02:00
parent 4dc14a751b
commit c1b9cab053
1 changed files with 72 additions and 1 deletions

View File

@ -1,6 +1,7 @@
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
@ -17,8 +18,20 @@ struct e1_recorder g_recorder;
enum mode {
MODE_PRINT,
MODE_BIN,
MODE_SC,
};
#define MAX_TS 32
#define CHUNK_BYTES 160
/* Ericsson super-channel */
struct sc_state {
uint8_t ts_data[MAX_TS][CHUNK_BYTES];
uint8_t num_ts;
};
static struct sc_state g_sc_state[2];
static enum mode g_mode = MODE_PRINT;
static int g_filter_line = -1;
static int g_filter_slot = -1;
@ -39,6 +52,58 @@ static char *timeval2str(struct timeval *tv)
return buf;
}
static int all_bytes_are(unsigned char ch, const uint8_t *data, int len)
{
int i;
for (i = 0; i < len; i++) {
if (data[i] != ch)
return 0;
}
return 1;
}
static void handle_sc_out(struct sc_state *scs)
{
uint8_t out[scs->num_ts * CHUNK_BYTES];
int i, j, k = 0;
/* re-shuffle the data from columns to lines */
for (i = 0; i < CHUNK_BYTES; i++) {
for (j = 1; j < scs->num_ts; j++)
out[k++] = scs->ts_data[j][i];
}
printf("%s\n", osmo_hexdump_nospc(out, scs->num_ts * CHUNK_BYTES));
}
static void handle_sc_in(struct osmo_e1cap_pkthdr *pkt, const uint8_t *data, unsigned int len)
{
struct sc_state *scs;
if (pkt->line_nr >= ARRAY_SIZE(g_sc_state)) {
fprintf(stderr, "Line number out of range\n");
exit(1);
}
scs = &g_sc_state[pkt->line_nr];
if (pkt->ts_nr >= ARRAY_SIZE(scs->ts_data)) {
fprintf(stderr, "Timeslot number out of range\n");
exit(1);
}
if (len != sizeof(scs->ts_data[pkt->ts_nr])) {
fprintf(stderr, "Insufficient data\n");
exit(1);
}
memcpy(scs->ts_data[pkt->ts_nr], data, len);
if (pkt->ts_nr-1 > scs->num_ts)
scs->num_ts = pkt->ts_nr-1;
if (pkt->ts_nr == scs->num_ts)
handle_sc_out(scs);
}
static void handle_data(struct osmo_e1cap_pkthdr *pkt, const uint8_t *data, int len)
{
switch (g_mode) {
@ -52,6 +117,9 @@ static void handle_data(struct osmo_e1cap_pkthdr *pkt, const uint8_t *data, int
case MODE_BIN:
write(1, data, len);
break;
case MODE_SC:
handle_sc_in(pkt, data, len);
break;
}
}
@ -68,7 +136,7 @@ static int handle_options(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "l:s:bu:")) != -1) {
while ((opt = getopt(argc, argv, "l:s:bSu:")) != -1) {
switch (opt) {
case 'l': /* Filter on E1 Line Number */
g_filter_line = atoi(optarg);
@ -79,6 +147,9 @@ static int handle_options(int argc, char **argv)
case 'b': /* Raw binary output mode (for piping) */
g_mode = MODE_BIN;
break;
case 'S': /* Super Channel Mode */
g_mode = MODE_SC;
break;
case 'u': /* 16k Sub-channel demux + filter */
g_filter_subslot = atoi(optarg);
if (g_filter_subslot < 0 || g_filter_subslot > 3)