blob: 7bbb71e2a0e0f2c31d69998a9e7c670b4eb83220 [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
8#include <osmocom/core/signal.h>
9#include <osmocom/core/logging.h>
10#include <osmocom/core/application.h>
Harald Welte525af182016-10-19 00:38:46 +020011#include <osmocom/abis/subchan_demux.h>
Harald Weltedbb0f5a2016-10-18 23:51:54 +020012
13#include "storage.h"
14#include "recorder.h"
15
16struct e1_recorder g_recorder;
17
Harald Weltef4032322016-10-19 00:23:10 +020018enum mode {
19 MODE_PRINT,
20 MODE_BIN,
Harald Weltec1b9cab2016-10-23 19:36:14 +020021 MODE_SC,
Harald Weltef4032322016-10-19 00:23:10 +020022};
23
Harald Weltec1b9cab2016-10-23 19:36:14 +020024#define MAX_TS 32
25#define CHUNK_BYTES 160
26
27/* Ericsson super-channel */
28struct sc_state {
29 uint8_t ts_data[MAX_TS][CHUNK_BYTES];
30 uint8_t num_ts;
31};
32
33static struct sc_state g_sc_state[2];
34
Harald Weltef4032322016-10-19 00:23:10 +020035static enum mode g_mode = MODE_PRINT;
36static int g_filter_line = -1;
37static int g_filter_slot = -1;
Harald Welte525af182016-10-19 00:38:46 +020038static int g_filter_subslot = -1;
39static struct osmo_e1cap_pkthdr *g_last_pkthdr;
Harald Weltef4032322016-10-19 00:23:10 +020040
Harald Welte74d1e342016-10-19 00:06:22 +020041static char *timeval2str(struct timeval *tv)
42{
43 time_t nowtime;
44 struct tm *nowtm;
45 char tmbuf[64];
46 static char buf[64];
47
48 nowtime = tv->tv_sec;
49 nowtm = localtime(&nowtime);
50 strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
51 snprintf(buf, sizeof buf, "%s.%06ld", tmbuf, tv->tv_usec);
52 return buf;
53}
54
Harald Weltec1b9cab2016-10-23 19:36:14 +020055static int all_bytes_are(unsigned char ch, const uint8_t *data, int len)
56{
57 int i;
58
59 for (i = 0; i < len; i++) {
60 if (data[i] != ch)
61 return 0;
62 }
63 return 1;
64}
65
66static void handle_sc_out(struct sc_state *scs)
67{
68 uint8_t out[scs->num_ts * CHUNK_BYTES];
69 int i, j, k = 0;
70
71 /* re-shuffle the data from columns to lines */
72 for (i = 0; i < CHUNK_BYTES; i++) {
73 for (j = 1; j < scs->num_ts; j++)
74 out[k++] = scs->ts_data[j][i];
75 }
76 printf("%s\n", osmo_hexdump_nospc(out, scs->num_ts * CHUNK_BYTES));
77}
78
79static void handle_sc_in(struct osmo_e1cap_pkthdr *pkt, const uint8_t *data, unsigned int len)
80{
81 struct sc_state *scs;
82
83 if (pkt->line_nr >= ARRAY_SIZE(g_sc_state)) {
84 fprintf(stderr, "Line number out of range\n");
85 exit(1);
86 }
87
88 scs = &g_sc_state[pkt->line_nr];
89 if (pkt->ts_nr >= ARRAY_SIZE(scs->ts_data)) {
90 fprintf(stderr, "Timeslot number out of range\n");
91 exit(1);
92 }
93
94 if (len != sizeof(scs->ts_data[pkt->ts_nr])) {
95 fprintf(stderr, "Insufficient data\n");
96 exit(1);
97 }
98
99 memcpy(scs->ts_data[pkt->ts_nr], data, len);
100 if (pkt->ts_nr-1 > scs->num_ts)
101 scs->num_ts = pkt->ts_nr-1;
102 if (pkt->ts_nr == scs->num_ts)
103 handle_sc_out(scs);
104}
105
106
Harald Welte525af182016-10-19 00:38:46 +0200107static void handle_data(struct osmo_e1cap_pkthdr *pkt, const uint8_t *data, int len)
108{
109 switch (g_mode) {
110 case MODE_PRINT:
111 printf("%s %02u/%02u %u (%u): %s\n",
112 timeval2str(&pkt->ts),
113 pkt->line_nr, pkt->ts_nr, pkt->capture_mode,
114 pkt->len,
115 osmo_hexdump_nospc(data, len));
116 break;
117 case MODE_BIN:
118 write(1, data, len);
119 break;
Harald Weltec1b9cab2016-10-23 19:36:14 +0200120 case MODE_SC:
121 handle_sc_in(pkt, data, len);
122 break;
Harald Welte525af182016-10-19 00:38:46 +0200123 }
124}
125
126static int subch_demux_out_cb(struct subch_demux *dmx, int ch, uint8_t *data,
127 int len, void *c)
128{
129 OSMO_ASSERT(ch == g_filter_subslot);
130 handle_data(g_last_pkthdr, data, len);
131
132 return 0;
133}
134
Harald Weltef4032322016-10-19 00:23:10 +0200135static int handle_options(int argc, char **argv)
136{
137 int opt;
138
Harald Weltec1b9cab2016-10-23 19:36:14 +0200139 while ((opt = getopt(argc, argv, "l:s:bSu:")) != -1) {
Harald Weltef4032322016-10-19 00:23:10 +0200140 switch (opt) {
Harald Welte525af182016-10-19 00:38:46 +0200141 case 'l': /* Filter on E1 Line Number */
Harald Weltef4032322016-10-19 00:23:10 +0200142 g_filter_line = atoi(optarg);
143 break;
Harald Welte525af182016-10-19 00:38:46 +0200144 case 's': /* Filter on E1 Slot Number */
Harald Weltef4032322016-10-19 00:23:10 +0200145 g_filter_slot = atoi(optarg);
146 break;
Harald Welte525af182016-10-19 00:38:46 +0200147 case 'b': /* Raw binary output mode (for piping) */
Harald Weltef4032322016-10-19 00:23:10 +0200148 g_mode = MODE_BIN;
149 break;
Harald Weltec1b9cab2016-10-23 19:36:14 +0200150 case 'S': /* Super Channel Mode */
151 g_mode = MODE_SC;
152 break;
Harald Welte525af182016-10-19 00:38:46 +0200153 case 'u': /* 16k Sub-channel demux + filter */
154 g_filter_subslot = atoi(optarg);
155 if (g_filter_subslot < 0 || g_filter_subslot > 3)
156 exit(2);
157 break;
Harald Weltef4032322016-10-19 00:23:10 +0200158 default:
159 fprintf(stderr, "Unknown option '%c'\n", opt);
160 exit(EXIT_FAILURE);
161 break;
162 }
163 }
164
165 return 0;
166}
167
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200168int main(int argc, char **argv)
169{
170 struct osmo_e1cap_file *f;
171 struct osmo_e1cap_pkthdr *pkt;
Harald Weltef4032322016-10-19 00:23:10 +0200172 unsigned long num_pkt = 0;
Harald Welte525af182016-10-19 00:38:46 +0200173 struct subch_demux smux;
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200174
175 printf("sizeof(timeval) = %zu\n", sizeof(struct timeval));
176 printf("sizeof(osmo_e1cap_pkthdr) = %zu\n", sizeof(*pkt));
177
Harald Weltef4032322016-10-19 00:23:10 +0200178 handle_options(argc, argv);
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200179
Harald Weltef4032322016-10-19 00:23:10 +0200180 if (optind >= argc) {
181 fprintf(stderr, "Missing input file name\n");
182 exit(2);
183 }
184
185 f = osmo_e1cap_open(NULL, argv[optind++]);
186 if (!f) {
187 fprintf(stderr, "Unable to open input file\n");
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200188 exit(1);
Harald Weltef4032322016-10-19 00:23:10 +0200189 }
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200190
Harald Welte525af182016-10-19 00:38:46 +0200191 if (g_filter_subslot >= 0) {
192 smux.out_cb = subch_demux_out_cb;
193 subch_demux_init(&smux);
194 subch_demux_activate(&smux, g_filter_subslot);
195 }
196
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200197 while ((pkt = osmo_e1cap_read_next(f))) {
Harald Weltef4032322016-10-19 00:23:10 +0200198 num_pkt++;
Harald Welte525af182016-10-19 00:38:46 +0200199 g_last_pkthdr = pkt;
Harald Weltef4032322016-10-19 00:23:10 +0200200
201 if (g_filter_line >= 0 && pkt->line_nr != g_filter_line)
202 continue;
203 if (g_filter_slot >= 0 && pkt->ts_nr != g_filter_slot)
204 continue;
205
Harald Welte525af182016-10-19 00:38:46 +0200206 if (g_filter_subslot >= 0) {
207 subch_demux_in(&smux, pkt->data, pkt->len);
208 continue;
Harald Weltef4032322016-10-19 00:23:10 +0200209 }
Harald Welte525af182016-10-19 00:38:46 +0200210
211 handle_data(pkt, pkt->data, pkt->len);
212
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200213 talloc_free(pkt);
214 }
Harald Weltef4032322016-10-19 00:23:10 +0200215
216 fprintf(stderr, "Processed a total of %lu packets\n", num_pkt);
Harald Weltedbb0f5a2016-10-18 23:51:54 +0200217}