blob: eb55c418b02eb897f8b91180b011d32010eba3d5 [file] [log] [blame]
Harald Weltedbb0f5a2016-10-18 23:51:54 +02001#include <stdio.h>
Harald Welte74d1e342016-10-19 00:06:22 +02002#include <time.h>
Harald Weltef4032322016-10-19 00:23:10 +02003#include <unistd.h>
Harald Weltec1b9cab2016-10-23 19:36:14 +02004#include <string.h>
Harald Welte74d1e342016-10-19 00:06:22 +02005
Harald Weltedbb0f5a2016-10-18 23:51:54 +02006#include <sys/time.h>
7
Harald Welte1df5cf42016-11-14 21:29:01 +01008#include <osmocom/core/bits.h>
Harald Weltedbb0f5a2016-10-18 23:51:54 +02009#include <osmocom/core/signal.h>
10#include <osmocom/core/logging.h>
11#include <osmocom/core/application.h>
Harald Welte525af182016-10-19 00:38:46 +020012#include <osmocom/abis/subchan_demux.h>
Harald Weltedbb0f5a2016-10-18 23:51:54 +020013
14#include "storage.h"
15#include "recorder.h"
Harald Welte1df5cf42016-11-14 21:29:01 +010016#include "flip_bits.h"
17#include "hdlc.h"
Harald Weltedbb0f5a2016-10-18 23:51:54 +020018
19struct e1_recorder g_recorder;
20
Harald Weltef4032322016-10-19 00:23:10 +020021enum mode {
22 MODE_PRINT,
23 MODE_BIN,
Harald Weltec1b9cab2016-10-23 19:36:14 +020024 MODE_SC,
Harald Weltef4032322016-10-19 00:23:10 +020025};
26
Harald Weltec1b9cab2016-10-23 19:36:14 +020027#define MAX_TS 32
28#define CHUNK_BYTES 160
29
30/* Ericsson super-channel */
31struct sc_state {
32 uint8_t ts_data[MAX_TS][CHUNK_BYTES];
33 uint8_t num_ts;
Harald Welte1df5cf42016-11-14 21:29:01 +010034 uint32_t ts_mask;
35 struct hdlc_proc hdlc;
Harald Weltec1b9cab2016-10-23 19:36:14 +020036};
37
38static struct sc_state g_sc_state[2];
39
Harald Weltef4032322016-10-19 00:23:10 +020040static enum mode g_mode = MODE_PRINT;
41static int g_filter_line = -1;
42static int g_filter_slot = -1;
Harald Welte525af182016-10-19 00:38:46 +020043static int g_filter_subslot = -1;
44static struct osmo_e1cap_pkthdr *g_last_pkthdr;
Harald Weltef4032322016-10-19 00:23:10 +020045
Harald Welte74d1e342016-10-19 00:06:22 +020046static char *timeval2str(struct timeval *tv)
47{
48 time_t nowtime;
49 struct tm *nowtm;
50 char tmbuf[64];
51 static char buf[64];
52
53 nowtime = tv->tv_sec;
54 nowtm = localtime(&nowtime);
55 strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
56 snprintf(buf, sizeof buf, "%s.%06ld", tmbuf, tv->tv_usec);
57 return buf;
58}
59
Harald Weltec1b9cab2016-10-23 19:36:14 +020060static int all_bytes_are(unsigned char ch, const uint8_t *data, int len)
61{
62 int i;
63
64 for (i = 0; i < len; i++) {
65 if (data[i] != ch)
66 return 0;
67 }
68 return 1;
69}
70
71static void handle_sc_out(struct sc_state *scs)
72{
Harald Welte1df5cf42016-11-14 21:29:01 +010073 unsigned int num_bytes = scs->num_ts * CHUNK_BYTES;
74 unsigned int num_bits = num_bytes * 8;
75 uint8_t out[32*CHUNK_BYTES];
76 ubit_t out_bits[32*CHUNK_BYTES*8];
Harald Weltec1b9cab2016-10-23 19:36:14 +020077 int i, j, k = 0;
78
79 /* re-shuffle the data from columns to lines */
80 for (i = 0; i < CHUNK_BYTES; i++) {
Harald Welte1df5cf42016-11-14 21:29:01 +010081 for (j = 0; j < scs->num_ts; j++)
Harald Weltec1b9cab2016-10-23 19:36:14 +020082 out[k++] = scs->ts_data[j][i];
83 }
Harald Welte1df5cf42016-11-14 21:29:01 +010084 //printf("num_bytes=%u %s\n", num_bytes, osmo_hexdump_nospc(out, num_bytes));
85 osmo_pbit2ubit_ext(out_bits, 0, out, 0, num_bits, 1);
86 //for (i = 0; i < num_bits; i++) fputc(out_bits[i] ? '1' : '.', stdout); fputc('\n', stdout);
87 process_raw_hdlc(&scs->hdlc, out_bits, num_bits);
Harald Weltec1b9cab2016-10-23 19:36:14 +020088}
89
90static void handle_sc_in(struct osmo_e1cap_pkthdr *pkt, const uint8_t *data, unsigned int len)
91{
92 struct sc_state *scs;
93
94 if (pkt->line_nr >= ARRAY_SIZE(g_sc_state)) {
95 fprintf(stderr, "Line number out of range\n");
96 exit(1);
97 }
98
99 scs = &g_sc_state[pkt->line_nr];
100 if (pkt->ts_nr >= ARRAY_SIZE(scs->ts_data)) {
101 fprintf(stderr, "Timeslot number out of range\n");
102 exit(1);
103 }
104
105 if (len != sizeof(scs->ts_data[pkt->ts_nr])) {
106 fprintf(stderr, "Insufficient data\n");
107 exit(1);
108 }
109
Harald Welte1df5cf42016-11-14 21:29:01 +0100110 if (pkt->ts_nr == 1) {
111 scs->ts_mask = 0;
112 memset(scs->ts_data, 0, sizeof(scs->ts_data));
113 }
114
115 /* copy over the data */
116 memcpy(scs->ts_data[pkt->ts_nr-1], data, len);
117 /* note that we have valid data for the given timeslot */
118 scs->ts_mask |= (1 << (pkt->ts_nr-1));
119
120 /* make sure we know what's the maximum timeslot number */
121 if (pkt->ts_nr > scs->num_ts)
122 scs->num_ts = pkt->ts_nr;
123
124 /* check if we have data for all needed timeslots */
125 uint32_t ts_mask = (1 << scs->num_ts) -1;
126 //printf("num_ts=%u, ts_mask=0x%x, scs_ts_mask=0x%x\n", scs->num_ts, ts_mask, scs->ts_mask);
127 if (scs->ts_mask == ts_mask) {
Harald Weltec1b9cab2016-10-23 19:36:14 +0200128 handle_sc_out(scs);
Harald Welte1df5cf42016-11-14 21:29:01 +0100129 }
Harald Weltec1b9cab2016-10-23 19:36:14 +0200130}
131
132
Harald Welte1df5cf42016-11-14 21:29:01 +0100133static void handle_data(struct osmo_e1cap_pkthdr *pkt, uint8_t *data, int len)
Harald Welte525af182016-10-19 00:38:46 +0200134{
Harald Welte1df5cf42016-11-14 21:29:01 +0100135 flip_buf_bits(data, len);
136#if 0
137 /* filter out all-ff/all-fe/all-7f */
138 if (all_bytes_are(0xff, data, len) ||
139 all_bytes_are(0x7f, data, len) ||
140 all_bytes_are(0x7e, data, len) ||
141 all_bytes_are(0xe7, data, len) ||
142 all_bytes_are(0x3f, data, len) ||
143 all_bytes_are(0xf3, data, len) ||
144 all_bytes_are(0x9f, data, len) ||
145 all_bytes_are(0xf9, data, len) ||
146 all_bytes_are(0xcf, data, len) ||
147 all_bytes_are(0xfc, data, len) ||
148 all_bytes_are(0xfe, data, len))
149 return;
150#endif
151
Harald Welte525af182016-10-19 00:38:46 +0200152 switch (g_mode) {
153 case MODE_PRINT:
154 printf("%s %02u/%02u %u (%u): %s\n",
155 timeval2str(&pkt->ts),
156 pkt->line_nr, pkt->ts_nr, pkt->capture_mode,
157 pkt->len,
158 osmo_hexdump_nospc(data, len));
159 break;
160 case MODE_BIN:
161 write(1, data, len);
162 break;
Harald Weltec1b9cab2016-10-23 19:36:14 +0200163 case MODE_SC:
164 handle_sc_in(pkt, data, len);
165 break;
Harald Welte525af182016-10-19 00:38:46 +0200166 }
167}
168
169static int subch_demux_out_cb(struct subch_demux *dmx, int ch, uint8_t *data,
170 int len, void *c)
171{
172 OSMO_ASSERT(ch == g_filter_subslot);
Harald Welte1df5cf42016-11-14 21:29:01 +0100173
Harald Welte525af182016-10-19 00:38:46 +0200174 handle_data(g_last_pkthdr, data, len);
175
176 return 0;
177}
178
Harald Weltef4032322016-10-19 00:23:10 +0200179static int handle_options(int argc, char **argv)
180{
181 int opt;
182
Harald Weltec1b9cab2016-10-23 19:36:14 +0200183 while ((opt = getopt(argc, argv, "l:s:bSu:")) != -1) {
Harald Weltef4032322016-10-19 00:23:10 +0200184 switch (opt) {
Harald Welte525af182016-10-19 00:38:46 +0200185 case 'l': /* Filter on E1 Line Number */
Harald Weltef4032322016-10-19 00:23:10 +0200186 g_filter_line = atoi(optarg);
187 break;
Harald Welte525af182016-10-19 00:38:46 +0200188 case 's': /* Filter on E1 Slot Number */
Harald Weltef4032322016-10-19 00:23:10 +0200189 g_filter_slot = atoi(optarg);
190 break;
Harald Welte525af182016-10-19 00:38:46 +0200191 case 'b': /* Raw binary output mode (for piping) */
Harald Weltef4032322016-10-19 00:23:10 +0200192 g_mode = MODE_BIN;
193 break;
Harald Weltec1b9cab2016-10-23 19:36:14 +0200194 case 'S': /* Super Channel Mode */
195 g_mode = MODE_SC;
196 break;
Harald Welte525af182016-10-19 00:38:46 +0200197 case 'u': /* 16k Sub-channel demux + filter */
198 g_filter_subslot = atoi(optarg);
199 if (g_filter_subslot < 0 || g_filter_subslot > 3)
200 exit(2);
201 break;
Harald Weltef4032322016-10-19 00:23:10 +0200202 default:
203 fprintf(stderr, "Unknown option '%c'\n", opt);
204 exit(EXIT_FAILURE);
205 break;
206 }
207 }
208
209 return 0;
210}
211
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200212int main(int argc, char **argv)
213{
214 struct osmo_e1cap_file *f;
215 struct osmo_e1cap_pkthdr *pkt;
Harald Weltef4032322016-10-19 00:23:10 +0200216 unsigned long num_pkt = 0;
Harald Welte525af182016-10-19 00:38:46 +0200217 struct subch_demux smux;
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200218
219 printf("sizeof(timeval) = %zu\n", sizeof(struct timeval));
220 printf("sizeof(osmo_e1cap_pkthdr) = %zu\n", sizeof(*pkt));
221
Harald Welte1df5cf42016-11-14 21:29:01 +0100222 memset(g_sc_state, 0, sizeof(g_sc_state));
223 init_flip_bits();
224
Harald Weltef4032322016-10-19 00:23:10 +0200225 handle_options(argc, argv);
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200226
Harald Weltef4032322016-10-19 00:23:10 +0200227 if (optind >= argc) {
228 fprintf(stderr, "Missing input file name\n");
229 exit(2);
230 }
231
232 f = osmo_e1cap_open(NULL, argv[optind++]);
233 if (!f) {
234 fprintf(stderr, "Unable to open input file\n");
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200235 exit(1);
Harald Weltef4032322016-10-19 00:23:10 +0200236 }
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200237
Harald Welte525af182016-10-19 00:38:46 +0200238 if (g_filter_subslot >= 0) {
239 smux.out_cb = subch_demux_out_cb;
240 subch_demux_init(&smux);
241 subch_demux_activate(&smux, g_filter_subslot);
242 }
243
Harald Welte1df5cf42016-11-14 21:29:01 +0100244// printf("hdlc=%s\n", osmo_hexdump(&g_sc_state[0].hdlc, sizeof(g_sc_state[0].hdlc)));
245
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200246 while ((pkt = osmo_e1cap_read_next(f))) {
Harald Weltef4032322016-10-19 00:23:10 +0200247 num_pkt++;
Harald Welte525af182016-10-19 00:38:46 +0200248 g_last_pkthdr = pkt;
Harald Weltef4032322016-10-19 00:23:10 +0200249
250 if (g_filter_line >= 0 && pkt->line_nr != g_filter_line)
251 continue;
252 if (g_filter_slot >= 0 && pkt->ts_nr != g_filter_slot)
253 continue;
254
Harald Welte525af182016-10-19 00:38:46 +0200255 if (g_filter_subslot >= 0) {
256 subch_demux_in(&smux, pkt->data, pkt->len);
257 continue;
Harald Weltef4032322016-10-19 00:23:10 +0200258 }
Harald Welte525af182016-10-19 00:38:46 +0200259
260 handle_data(pkt, pkt->data, pkt->len);
261
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200262 talloc_free(pkt);
263 }
Harald Weltef4032322016-10-19 00:23:10 +0200264
265 fprintf(stderr, "Processed a total of %lu packets\n", num_pkt);
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200266}