Implement support for TCH/FACCH on various TS including decryption
This commit is contained in:
parent
9cf449409f
commit
31d4d5eb21
|
@ -229,9 +229,8 @@ GS_new(GS_CTX *ctx)
|
||||||
* 142 bit
|
* 142 bit
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn)
|
GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn, int first_burst)
|
||||||
{
|
{
|
||||||
// int fn;
|
|
||||||
int bsic;
|
int bsic;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
@ -240,38 +239,48 @@ GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn)
|
||||||
|
|
||||||
memset(ctx->msg, 0, sizeof(ctx->msg));
|
memset(ctx->msg, 0, sizeof(ctx->msg));
|
||||||
|
|
||||||
#if 0
|
if (ts_ctx->type == TST_TCHF && type == NORMAL) {
|
||||||
if (ts != 0) {
|
/* Dieter: we came here because the burst might contain FACCH bits */
|
||||||
/* non-0 timeslots should end up in PCAP */
|
|
||||||
data = decode_cch(ctx, ctx->burst, &len);
|
|
||||||
if (data == NULL)
|
|
||||||
return -1;
|
|
||||||
// write_pcap_packet(ctx->pcap_fd, 0 /* arfcn */, ts, ctx->fn, data, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* if (ts == 0) {
|
|
||||||
if (type == SCH) {
|
|
||||||
// ret = decode_sch(src, &fn, &bsic);
|
|
||||||
if (ret != 0)
|
|
||||||
return 0;
|
|
||||||
if ((ctx->bsic > 0) && (bsic != ctx->bsic))
|
|
||||||
fprintf(stderr, "WARN: BSIC changed.\n");
|
|
||||||
//DEBUGF("FN %d, BSIC %d\n", fn, bsic);
|
|
||||||
ctx->fn = fn;
|
ctx->fn = fn;
|
||||||
ctx->bsic = bsic;
|
ts_ctx->burst_count2 = fn % 26;
|
||||||
/* Reset message concatenator */
|
|
||||||
// ts_ctx->burst_count = 0;
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* If we did not get Frame Number yet then return */
|
if (ts_ctx->burst_count2 >= 12)
|
||||||
// if (ctx->fn < 0)
|
ts_ctx->burst_count2--;
|
||||||
// return 0;
|
ts_ctx->burst_count2 = ts_ctx->burst_count2 % 8;
|
||||||
|
|
||||||
|
/* copy data bits and stealing flags to buffer */
|
||||||
|
memcpy(ts_ctx->burst2 + (116 * ts_ctx->burst_count2), src, 58);
|
||||||
|
memcpy(ts_ctx->burst2 + (116 * ts_ctx->burst_count2) + 58, src + 58 + 26, 58);
|
||||||
|
|
||||||
|
/* Return if not enough bursts for a full gsm message */
|
||||||
|
if ((ts_ctx->burst_count2 % 4) != 3)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
data = decode_facch(ctx, ts_ctx->burst2, &len, (ts_ctx->burst_count2 == 3) ? 1 : 0);
|
||||||
|
if (data == NULL) {
|
||||||
|
DEBUGF("cannot decode FACCH fnr=%d ts=%d\n", ctx->fn, ts);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_gsmdecode(0, 0, ts, ctx->fn, data, len);
|
||||||
|
|
||||||
|
if (ctx->gsmtap_fd >= 0) {
|
||||||
|
struct msgb *msg;
|
||||||
|
uint8_t chan_type = GSMTAP_CHANNEL_TCH_F;
|
||||||
|
uint8_t ss = 0;
|
||||||
|
int fn = (ctx->fn - 3); /* "- 3" for start of frame */
|
||||||
|
|
||||||
|
msg = gsmtap_makemsg(0, ts, chan_type, ss, ctx->fn, 0, 0, data, len);
|
||||||
|
if (msg)
|
||||||
|
write(ctx->gsmtap_fd, msg->data, msg->len);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* normal burst processing */
|
||||||
|
if (first_burst) /* Dieter: it is important to start with the correct burst */
|
||||||
|
ts_ctx->burst_count = 0;
|
||||||
|
|
||||||
// ctx->fn++;
|
|
||||||
// }
|
|
||||||
ctx->fn = fn;
|
ctx->fn = fn;
|
||||||
if (type == NORMAL) {
|
if (type == NORMAL) {
|
||||||
/* Interested in these frame numbers (cch)
|
/* Interested in these frame numbers (cch)
|
||||||
|
@ -290,18 +299,25 @@ GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn)
|
||||||
ts_ctx->burst_count = 0;
|
ts_ctx->burst_count = 0;
|
||||||
data = decode_cch(ctx, ts_ctx->burst, &len);
|
data = decode_cch(ctx, ts_ctx->burst, &len);
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
DEBUGF("cannot decode fnr=0x%08x ts=%d\n", ctx->fn, ts);
|
DEBUGF("cannot decode fnr=0x%06x (%6d) ts=%d\n", ctx->fn, ctx->fn, ts);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
//DEBUGF("OK TS %d, len %d\n", ts, len);
|
//DEBUGF("OK TS %d, len %d\n", ts, len);
|
||||||
|
|
||||||
out_gsmdecode(0, 0, ts, ctx->fn - 4, data, len);
|
out_gsmdecode(0, 0, ts, ctx->fn, data, len);
|
||||||
|
|
||||||
if (ctx->gsmtap_fd >= 0) {
|
if (ctx->gsmtap_fd >= 0) {
|
||||||
|
/* Dieter: set channel type according to configuration */
|
||||||
struct msgb *msg;
|
struct msgb *msg;
|
||||||
|
uint8_t chan_type = GSMTAP_CHANNEL_BCCH;
|
||||||
|
uint8_t ss = 0;
|
||||||
|
int fn = (ctx->fn - 3); /* "- 3" for start of frame */
|
||||||
|
|
||||||
|
chan_type = get_chan_type(ts_ctx->type, fn, &ss);
|
||||||
|
|
||||||
/* arfcn, ts, chan_type, ss, fn, signal, snr, data, len */
|
/* arfcn, ts, chan_type, ss, fn, signal, snr, data, len */
|
||||||
msg = gsmtap_makemsg(0, ts, GSMTAP_CHANNEL_BCCH, 0,
|
msg = gsmtap_makemsg(0, ts, chan_type, ss,
|
||||||
ctx->fn-4, 0, 0, data, len);
|
ctx->fn, 0, 0, data, len);
|
||||||
if (msg)
|
if (msg)
|
||||||
write(ctx->gsmtap_fd, msg->data,
|
write(ctx->gsmtap_fd, msg->data,
|
||||||
msg->len);
|
msg->len);
|
||||||
|
@ -318,13 +334,15 @@ GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Output data so that it can be parsed from gsmdeocde.
|
* Output data so that it can be parsed from gsmdecode.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
out_gsmdecode(char type, int arfcn, int ts, int fn, char *data, int len)
|
out_gsmdecode(char type, int arfcn, int ts, int fn, char *data, int len)
|
||||||
{
|
{
|
||||||
char *end = data + len;
|
char *end = data + len;
|
||||||
|
|
||||||
|
printf("%6d %d:", (fn + 0), ts);
|
||||||
|
|
||||||
/* FIXME: speed this up by first printing into an array */
|
/* FIXME: speed this up by first printing into an array */
|
||||||
while (data < end)
|
while (data < end)
|
||||||
printf(" %02.2x", (unsigned char)*data++);
|
printf(" %02.2x", (unsigned char)*data++);
|
||||||
|
|
|
@ -59,7 +59,7 @@ typedef struct
|
||||||
} GS_CTX;
|
} GS_CTX;
|
||||||
|
|
||||||
int GS_new(GS_CTX *ctx);
|
int GS_new(GS_CTX *ctx);
|
||||||
int GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn);
|
int GS_process(GS_CTX *ctx, int ts, int type, const unsigned char *src, int fn, int first_burst);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
GR_SWIG_BLOCK_MAGIC(gsm,receiver_cf);
|
GR_SWIG_BLOCK_MAGIC(gsm,receiver_cf);
|
||||||
|
|
||||||
gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
|
gsm_receiver_cf_sptr gsm_make_receiver_cf ( gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration);
|
||||||
|
|
||||||
class gsm_receiver_cf : public gr_block
|
class gsm_receiver_cf : public gr_block
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,14 +45,25 @@
|
||||||
//FIXME: decide to use this define or not
|
//FIXME: decide to use this define or not
|
||||||
|
|
||||||
//TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
//TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
||||||
void decrypt(const unsigned char * burst_binary, byte * KC, float * decrypted_data, unsigned FN)
|
void decrypt(const unsigned char * burst_binary, byte * KC, unsigned char * decrypted_data, unsigned FN)
|
||||||
{
|
{
|
||||||
byte AtoB[2*DATA_BITS];
|
byte AtoB[2*DATA_BITS];
|
||||||
|
|
||||||
|
/* KC is all zero: no decryption */
|
||||||
|
|
||||||
|
if(KC[0] == 0 && KC[1] == 0 && KC[2] == 0 && KC[3] == 0 &
|
||||||
|
KC[4] == 0 && KC[5] == 0 && KC[6] == 0 && KC[7] == 0) {
|
||||||
|
for (int i = 0; i < 148; i++) {
|
||||||
|
decrypted_data[i] = burst_binary[i];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
keysetup(KC, FN);
|
keysetup(KC, FN);
|
||||||
runA51(AtoB);
|
runA51(AtoB);
|
||||||
|
|
||||||
for (int i = 0; i < 148; i++) {
|
/* guard bits */
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
decrypted_data[i] = burst_binary[i];
|
decrypted_data[i] = burst_binary[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,13 +71,55 @@ void decrypt(const unsigned char * burst_binary, byte * KC, float * decrypted_da
|
||||||
decrypted_data[i+3] = AtoB[i] ^ burst_binary[i+3];
|
decrypted_data[i+3] = AtoB[i] ^ burst_binary[i+3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* stealing bits and midamble */
|
||||||
|
for (int i = 60; i < 88; i++) {
|
||||||
|
decrypted_data[i] = burst_binary[i];
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 57; i++) {
|
for (int i = 0; i < 57; i++) {
|
||||||
decrypted_data[i+88] = AtoB[i+57] ^ burst_binary[i+88];
|
decrypted_data[i+88] = AtoB[i+57] ^ burst_binary[i+88];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* guard bits */
|
||||||
|
for (int i = 145; i < 148; i++) {
|
||||||
|
decrypted_data[i] = burst_binary[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: this shouldn't be here */
|
||||||
|
void dump_bits(const unsigned char * burst_binary, unsigned char * decrypted_data, burst_counter burst_nr, bool first_burst)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Cipher bits */
|
||||||
|
printf("C%d %d %d: ", first_burst, burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod());
|
||||||
|
for (int i = 0; i < 57; i++)
|
||||||
|
printf("%d", burst_binary[i+3]);
|
||||||
|
for (int i = 0; i < 57; i++)
|
||||||
|
printf("%d", burst_binary[i+88]);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* Plain bits */
|
||||||
|
printf("P%d %d %d: ", first_burst, burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod());
|
||||||
|
for (int i = 0; i < 57; i++)
|
||||||
|
printf("%d", decrypted_data[i+3]);
|
||||||
|
for (int i = 0; i < 57; i++)
|
||||||
|
printf("%d", decrypted_data[i+88]);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* Keystream bits */
|
||||||
|
printf("S%d %d %d: ", first_burst, burst_nr.get_frame_nr(), burst_nr.get_frame_nr_mod());
|
||||||
|
for (int i = 0; i < 57; i++)
|
||||||
|
printf("%d", burst_binary[i+3] ^ decrypted_data[i+3]);
|
||||||
|
for (int i = 0; i < 57; i++)
|
||||||
|
printf("%d", burst_binary[i+88] ^ decrypted_data[i+88]);
|
||||||
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void gsm_receiver_cf::read_key(std::string key)
|
void gsm_receiver_cf::read_key(std::string key)
|
||||||
{
|
{
|
||||||
|
printf("Key: '%s'\n", key.c_str());
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int b;
|
int b;
|
||||||
for (i = 0;i < 8;i++) {
|
for (i = 0;i < 8;i++) {
|
||||||
|
@ -75,86 +128,133 @@ void gsm_receiver_cf::read_key(std::string key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gsm_receiver_cf::process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary)
|
void gsm_receiver_cf::read_configuration(std::string configuration)
|
||||||
{
|
{
|
||||||
float decrypted_data[148];
|
printf("Configuration: '%s'\n", configuration.c_str());
|
||||||
unsigned char * voice_frame;
|
|
||||||
|
|
||||||
// if (burst_nr.get_timeslot_nr() == 7) {
|
if ((char)configuration[0] == 0) {
|
||||||
|
printf(" No configuration set.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get timeslot */
|
||||||
|
int ts = atoi(configuration.c_str());
|
||||||
|
if (ts < 0 || ts > 7) {
|
||||||
|
printf(" Invalid TS: %d\n", ts);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" Configuration TS: %d\n", ts);
|
||||||
|
|
||||||
|
if((char)configuration[1] == 'C')
|
||||||
|
d_gs_ctx.ts_ctx[ts].type = TST_FCCH_SCH_BCCH_CCCH_SDCCH4;
|
||||||
|
else if((char)configuration[1] == 'B')
|
||||||
|
d_gs_ctx.ts_ctx[ts].type = TST_FCCH_SCH_BCCH_CCCH;
|
||||||
|
else if((char)configuration[1] == 'S')
|
||||||
|
d_gs_ctx.ts_ctx[ts].type = TST_SDCCH8;
|
||||||
|
else if((char)configuration[1] == 'T')
|
||||||
|
d_gs_ctx.ts_ctx[ts].type = TST_TCHF;
|
||||||
|
else {
|
||||||
|
printf(" Invalid configuration: %c\n", (char)configuration[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* any other timeslot than 0: turn TS0 off */
|
||||||
|
if(ts != 0) {
|
||||||
|
d_gs_ctx.ts_ctx[0].type = TST_OFF;
|
||||||
|
d_trace_sch = false;
|
||||||
|
printf(" TS0 is turned off\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void gsm_receiver_cf::process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary, bool first_burst)
|
||||||
|
{
|
||||||
|
unsigned char decrypted_data[148];
|
||||||
|
float decrypted_data_float[148];
|
||||||
|
unsigned char * voice_frame;
|
||||||
|
int ts = burst_nr.get_timeslot_nr();
|
||||||
|
|
||||||
|
/* no processing if turned off*/
|
||||||
|
if (d_gs_ctx.ts_ctx[ts].type == TST_OFF)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* handle traffic timeslots */
|
||||||
|
#if 0
|
||||||
|
/* always try to decrypt and decode traffic in TS 1...7 */
|
||||||
|
/* TODO: this will fail if there is unencrypted traffic in more than one TS */
|
||||||
if (burst_nr.get_timeslot_nr() >= 1 && burst_nr.get_timeslot_nr() <= 7) {
|
if (burst_nr.get_timeslot_nr() >= 1 && burst_nr.get_timeslot_nr() <= 7) {
|
||||||
|
#else
|
||||||
|
if (d_gs_ctx.ts_ctx[ts].type == TST_TCHF) {
|
||||||
|
#endif
|
||||||
decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod());
|
decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod());
|
||||||
|
|
||||||
GSM::Time time(burst_nr.get_frame_nr(), burst_nr.get_timeslot_nr());
|
int i;
|
||||||
GSM::RxBurst rxbrst(decrypted_data, time);
|
for (i = 0; i< 148; i++)
|
||||||
switch (burst_nr.get_timeslot_nr()) {
|
decrypted_data_float[i] = decrypted_data[i];
|
||||||
case 1:
|
|
||||||
if ( d_tch_decoder1.processBurst( rxbrst ) == true) {
|
GSM::Time time(burst_nr.get_frame_nr(), ts);
|
||||||
fwrite(d_tch_decoder1.get_voice_frame(), 1 , 33, d_gsm_file);
|
GSM::RxBurst rxbrst(decrypted_data_float, time);
|
||||||
|
if (ts - TIMESLOT1 >= 0 && ts - TIMESLOT1 < N_TCH_DECODER) {
|
||||||
|
if ( d_tch_decoder[ts - TIMESLOT1]->processBurst( rxbrst ) == true) {
|
||||||
|
fwrite(d_tch_decoder[ts - TIMESLOT1]->get_voice_frame(), 1 , 33, d_gsm_file);
|
||||||
}
|
}
|
||||||
break;
|
else if (rxbrst.Hl() || rxbrst.Hu()) {
|
||||||
case 2:
|
/* Stolen bits are set, might be FACCH */
|
||||||
if ( d_tch_decoder2.processBurst( rxbrst ) == true) {
|
GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst);
|
||||||
fwrite(d_tch_decoder2.get_voice_frame(), 1 , 33, d_gsm_file);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if ( d_tch_decoder3.processBurst( rxbrst ) == true) {
|
|
||||||
fwrite(d_tch_decoder3.get_voice_frame(), 1 , 33, d_gsm_file);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if ( d_tch_decoder4.processBurst( rxbrst ) == true) {
|
|
||||||
fwrite(d_tch_decoder4.get_voice_frame(), 1 , 33, d_gsm_file);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if ( d_tch_decoder5.processBurst( rxbrst ) == true) {
|
|
||||||
fwrite(d_tch_decoder5.get_voice_frame(), 1 , 33, d_gsm_file);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
if ( d_tch_decoder6.processBurst( rxbrst ) == true) {
|
|
||||||
fwrite(d_tch_decoder6.get_voice_frame(), 1 , 33, d_gsm_file);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
if ( d_tch_decoder7.processBurst( rxbrst ) == true) {
|
|
||||||
fwrite(d_tch_decoder7.get_voice_frame(), 1 , 33, d_gsm_file);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (burst_nr.get_timeslot_nr() == 0) {
|
/* handle SDCCH/8 timeslots */
|
||||||
GS_process(&d_gs_ctx, TIMESLOT0, 6, &burst_binary[3], burst_nr.get_frame_nr());
|
if (d_gs_ctx.ts_ctx[ts].type == TST_SDCCH8) {
|
||||||
|
decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod());
|
||||||
|
#if 1 /* dump cipher, plain and keystream bits */
|
||||||
|
dump_bits(burst_binary, decrypted_data, burst_nr, first_burst);
|
||||||
|
#endif
|
||||||
|
GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TS0 is special (TODO) */
|
||||||
|
if (ts == 0) {
|
||||||
|
memcpy(decrypted_data, burst_binary, sizeof(decrypted_data));
|
||||||
|
if (d_gs_ctx.ts_ctx[ts].type == TST_FCCH_SCH_BCCH_CCCH_SDCCH4) {
|
||||||
|
if (SDCCH_SACCH_4_MAP[burst_nr.get_frame_nr() % 51] != 0) { /* SDCCH/4 or SACCH/4 */
|
||||||
|
decrypt(burst_binary, d_KC, decrypted_data, burst_nr.get_frame_nr_mod());
|
||||||
|
#if 1 /* dump cipher, plain and keystream bits */
|
||||||
|
dump_bits(burst_binary, decrypted_data, burst_nr, first_burst);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GS_process(&d_gs_ctx, TIMESLOT0 + ts, NORMAL, &decrypted_data[3], burst_nr.get_frame_nr(), first_burst);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//TODO: this shouldn't be here also - the same reason
|
//TODO: this shouldn't be here also - the same reason
|
||||||
void gsm_receiver_cf::configure_receiver()
|
void gsm_receiver_cf::configure_receiver()
|
||||||
{
|
{
|
||||||
d_channel_conf.set_multiframe_type(TSC0, multiframe_51);
|
int ts;
|
||||||
|
printf("configure_receiver\n");
|
||||||
|
|
||||||
d_channel_conf.set_burst_types(TSC0, TEST_CCH_FRAMES, sizeof(TEST_CCH_FRAMES) / sizeof(unsigned), dummy_or_normal);
|
/* configure TS0, TS0 is special (TODO) */
|
||||||
d_channel_conf.set_burst_types(TSC0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst);
|
|
||||||
|
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT1, multiframe_26);
|
d_channel_conf.set_multiframe_type(TIMESLOT0, multiframe_51);
|
||||||
d_channel_conf.set_burst_types(TIMESLOT1, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
d_channel_conf.set_burst_types(TIMESLOT0, TEST_CCH_FRAMES, TEST_CCH_FIRST, sizeof(TEST_CCH_FRAMES) / sizeof(unsigned), normal_burst);
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT2, multiframe_26);
|
/* FCCH bursts */
|
||||||
d_channel_conf.set_burst_types(TIMESLOT2, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
d_channel_conf.set_burst_types(TIMESLOT0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst);
|
||||||
|
/* SCH bursts */
|
||||||
|
d_channel_conf.set_burst_types(TIMESLOT0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst);
|
||||||
|
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT3, multiframe_26);
|
/* configure TS1...TS7 */
|
||||||
d_channel_conf.set_burst_types(TIMESLOT3, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT4, multiframe_26);
|
|
||||||
d_channel_conf.set_burst_types(TIMESLOT4, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
|
||||||
|
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT5, multiframe_26);
|
|
||||||
d_channel_conf.set_burst_types(TIMESLOT5, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT6, multiframe_26);
|
|
||||||
d_channel_conf.set_burst_types(TIMESLOT6, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
|
||||||
|
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT7, multiframe_26);
|
|
||||||
d_channel_conf.set_burst_types(TIMESLOT7, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
|
||||||
|
|
||||||
|
for (ts = TIMESLOT1; ts < TIMESLOT7; ts++) {
|
||||||
|
if (d_gs_ctx.ts_ctx[ts].type == TST_TCHF) {
|
||||||
|
d_channel_conf.set_multiframe_type(ts, multiframe_26);
|
||||||
|
d_channel_conf.set_burst_types(ts, TRAFFIC_CHANNEL_F, sizeof(TRAFFIC_CHANNEL_F) / sizeof(unsigned), dummy_or_normal);
|
||||||
|
}
|
||||||
|
else if (d_gs_ctx.ts_ctx[ts].type == TST_SDCCH8) {
|
||||||
|
d_channel_conf.set_multiframe_type(ts, multiframe_51);
|
||||||
|
d_channel_conf.set_burst_types(ts, SDCCH_SACCH_8_FRAMES, SDCCH_SACCH_8_FIRST, sizeof(SDCCH_SACCH_8_FRAMES) / sizeof(unsigned), dummy_or_normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,9 +264,9 @@ typedef std::vector<float> vector_float;
|
||||||
typedef boost::circular_buffer<float> circular_buffer_float;
|
typedef boost::circular_buffer<float> circular_buffer_float;
|
||||||
|
|
||||||
gsm_receiver_cf_sptr
|
gsm_receiver_cf_sptr
|
||||||
gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key)
|
gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration)
|
||||||
{
|
{
|
||||||
return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr, key));
|
return gsm_receiver_cf_sptr(new gsm_receiver_cf(tuner, synchronizer, osr, key, configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int MIN_IN = 1; // mininum number of input streams
|
static const int MIN_IN = 1; // mininum number of input streams
|
||||||
|
@ -177,7 +277,7 @@ static const int MAX_OUT = 1; // maximum number of output streams
|
||||||
/*
|
/*
|
||||||
* The private constructor
|
* The private constructor
|
||||||
*/
|
*/
|
||||||
gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key)
|
gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration)
|
||||||
: gr_block("gsm_receiver",
|
: gr_block("gsm_receiver",
|
||||||
gr_make_io_signature(MIN_IN, MAX_IN, sizeof(gr_complex)),
|
gr_make_io_signature(MIN_IN, MAX_IN, sizeof(gr_complex)),
|
||||||
gr_make_io_signature(MIN_OUT, MAX_OUT, 142 * sizeof(float))),
|
gr_make_io_signature(MIN_OUT, MAX_OUT, 142 * sizeof(float))),
|
||||||
|
@ -190,13 +290,7 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer,
|
||||||
d_state(first_fcch_search),
|
d_state(first_fcch_search),
|
||||||
d_burst_nr(osr),
|
d_burst_nr(osr),
|
||||||
d_failed_sch(0),
|
d_failed_sch(0),
|
||||||
d_tch_decoder1( GSM::gFACCH_TCHFMapping ), //!!
|
d_trace_sch(true)
|
||||||
d_tch_decoder2( GSM::gFACCH_TCHFMapping ), //!!
|
|
||||||
d_tch_decoder3( GSM::gFACCH_TCHFMapping ), //!!
|
|
||||||
d_tch_decoder4( GSM::gFACCH_TCHFMapping ), //!!
|
|
||||||
d_tch_decoder5( GSM::gFACCH_TCHFMapping ), //!!
|
|
||||||
d_tch_decoder6( GSM::gFACCH_TCHFMapping ), //!!
|
|
||||||
d_tch_decoder7( GSM::gFACCH_TCHFMapping ) //!!
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0));
|
gmsk_mapper(SYNC_BITS, N_SYNC_BITS, d_sch_training_seq, gr_complex(0.0, -1.0));
|
||||||
|
@ -212,7 +306,10 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer,
|
||||||
gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint);
|
gmsk_mapper(train_seq[i], N_TRAIN_BITS, d_norm_training_seq[i], startpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
d_gsm_file = fopen( "speech.gsm", "wb" ); //!!
|
for (i = 0; i < N_TCH_DECODER; i++)
|
||||||
|
d_tch_decoder[i] = new GSM::TCHFACCHL1Decoder(GSM::gFACCH_TCHFMapping);
|
||||||
|
|
||||||
|
d_gsm_file = fopen( "speech.au.gsm", "wb" ); //!!
|
||||||
d_hex_to_int['0'] = 0; //!!
|
d_hex_to_int['0'] = 0; //!!
|
||||||
d_hex_to_int['4'] = 4; //!!
|
d_hex_to_int['4'] = 4; //!!
|
||||||
d_hex_to_int['8'] = 8; //!!
|
d_hex_to_int['8'] = 8; //!!
|
||||||
|
@ -230,8 +327,14 @@ gsm_receiver_cf::gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer,
|
||||||
d_hex_to_int['b'] = 0xb; //!!
|
d_hex_to_int['b'] = 0xb; //!!
|
||||||
d_hex_to_int['f'] = 0xf; //!!
|
d_hex_to_int['f'] = 0xf; //!!
|
||||||
read_key(key); //!!
|
read_key(key); //!!
|
||||||
/* Initialize GSM Stack */
|
|
||||||
|
/* Initialize GSM Stack, clear d_gs_ctx */
|
||||||
GS_new(&d_gs_ctx); //TODO: remove it! it's not a right place for a decoder
|
GS_new(&d_gs_ctx); //TODO: remove it! it's not a right place for a decoder
|
||||||
|
|
||||||
|
/* configuration is stored in d_gs_ctx */
|
||||||
|
read_configuration(configuration);
|
||||||
|
|
||||||
|
configure_receiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -295,16 +398,23 @@ gsm_receiver_cf::general_work(int noutput_items,
|
||||||
burst_start = get_sch_chan_imp_resp(input, &channel_imp_resp[0]); //get channel impulse response from it
|
burst_start = get_sch_chan_imp_resp(input, &channel_imp_resp[0]); //get channel impulse response from it
|
||||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //detect bits using MLSE detection
|
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //detect bits using MLSE detection
|
||||||
if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //decode SCH burst
|
if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //decode SCH burst
|
||||||
|
if(d_trace_sch)
|
||||||
|
{
|
||||||
DCOUT("sch burst_start: " << burst_start);
|
DCOUT("sch burst_start: " << burst_start);
|
||||||
DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3);
|
DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3);
|
||||||
|
}
|
||||||
d_burst_nr.set(t1, t2, t3, 0); //set counter of bursts value
|
d_burst_nr.set(t1, t2, t3, 0); //set counter of bursts value
|
||||||
|
|
||||||
|
#if 0 /* Dieter: now done in constructor */
|
||||||
//configure the receiver - tell him where to find which burst type
|
//configure the receiver - tell him where to find which burst type
|
||||||
d_channel_conf.set_multiframe_type(TIMESLOT0, multiframe_51); //in the timeslot nr.0 bursts changes according to t3 counter
|
d_channel_conf.set_multiframe_type(TIMESLOT0, multiframe_51); //in the timeslot nr.0 bursts changes according to t3 counter
|
||||||
configure_receiver();//TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
configure_receiver();//TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
||||||
|
// Dieter: don't call it, otherwise overwrites configuration of configure_receiver()
|
||||||
d_channel_conf.set_burst_types(TIMESLOT0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); //tell where to find fcch bursts
|
d_channel_conf.set_burst_types(TIMESLOT0, FCCH_FRAMES, sizeof(FCCH_FRAMES) / sizeof(unsigned), fcch_burst); //tell where to find fcch bursts
|
||||||
d_channel_conf.set_burst_types(TIMESLOT0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); //sch bursts
|
d_channel_conf.set_burst_types(TIMESLOT0, SCH_FRAMES, sizeof(SCH_FRAMES) / sizeof(unsigned), sch_burst); //sch bursts
|
||||||
d_channel_conf.set_burst_types(TIMESLOT0, BCCH_FRAMES, sizeof(BCCH_FRAMES) / sizeof(unsigned), normal_burst);//!and maybe normal bursts of the BCCH logical channel
|
d_channel_conf.set_burst_types(TIMESLOT0, BCCH_FRAMES, sizeof(BCCH_FRAMES) / sizeof(unsigned), normal_burst);//!and maybe normal bursts of the BCCH logical channel
|
||||||
|
#endif
|
||||||
|
|
||||||
d_burst_nr++;
|
d_burst_nr++;
|
||||||
|
|
||||||
consume_each(burst_start + BURST_SIZE * d_OSR); //consume samples up to next guard period
|
consume_each(burst_start + BURST_SIZE * d_OSR); //consume samples up to next guard period
|
||||||
|
@ -326,6 +436,7 @@ gsm_receiver_cf::general_work(int noutput_items,
|
||||||
unsigned char output_binary[BURST_SIZE];
|
unsigned char output_binary[BURST_SIZE];
|
||||||
|
|
||||||
burst_type b_type = d_channel_conf.get_burst_type(d_burst_nr); //get burst type for given burst number
|
burst_type b_type = d_channel_conf.get_burst_type(d_burst_nr); //get burst type for given burst number
|
||||||
|
bool first_burst = d_channel_conf.get_first_burst(d_burst_nr); // first burst of four ?
|
||||||
|
|
||||||
switch (b_type) {
|
switch (b_type) {
|
||||||
case fcch_burst: { //if it's FCCH burst
|
case fcch_burst: { //if it's FCCH burst
|
||||||
|
@ -355,9 +466,12 @@ gsm_receiver_cf::general_work(int noutput_items,
|
||||||
if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //and decode SCH data
|
if (decode_sch(&output_binary[3], &t1, &t2, &t3, &d_ncc, &d_bcc) == 0) { //and decode SCH data
|
||||||
// d_burst_nr.set(t1, t2, t3, 0); //but only to check if burst_start value is correct
|
// d_burst_nr.set(t1, t2, t3, 0); //but only to check if burst_start value is correct
|
||||||
d_failed_sch = 0;
|
d_failed_sch = 0;
|
||||||
DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3);
|
|
||||||
offset = burst_start - floor((GUARD_PERIOD) * d_OSR); //compute offset from burst_start - burst should start after a guard period
|
offset = burst_start - floor((GUARD_PERIOD) * d_OSR); //compute offset from burst_start - burst should start after a guard period
|
||||||
|
if(d_trace_sch)
|
||||||
|
{
|
||||||
|
DCOUT("bcc: " << d_bcc << " ncc: " << d_ncc << " t1: " << t1 << " t2: " << t2 << " t3: " << t3);
|
||||||
DCOUT(offset);
|
DCOUT(offset);
|
||||||
|
}
|
||||||
to_consume += offset; //adjust with offset number of samples to be consumed
|
to_consume += offset; //adjust with offset number of samples to be consumed
|
||||||
} else {
|
} else {
|
||||||
d_failed_sch++;
|
d_failed_sch++;
|
||||||
|
@ -373,7 +487,7 @@ gsm_receiver_cf::general_work(int noutput_items,
|
||||||
case normal_burst: //if it's normal burst
|
case normal_burst: //if it's normal burst
|
||||||
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); //get channel impulse response for given training sequence number - d_bcc
|
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc); //get channel impulse response for given training sequence number - d_bcc
|
||||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //MLSE detection of bits
|
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary); //MLSE detection of bits
|
||||||
process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
process_normal_burst(d_burst_nr, output_binary, first_burst); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dummy_or_normal: {
|
case dummy_or_normal: {
|
||||||
|
@ -389,7 +503,7 @@ gsm_receiver_cf::general_work(int noutput_items,
|
||||||
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc);
|
burst_start = get_norm_chan_imp_resp(input, &channel_imp_resp[0], d_bcc);
|
||||||
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary);
|
detect_burst(input, &channel_imp_resp[0], burst_start, output_binary);
|
||||||
if (!output_binary[0] && !output_binary[1] && !output_binary[2]) {
|
if (!output_binary[0] && !output_binary[1] && !output_binary[2]) {
|
||||||
process_normal_burst(d_burst_nr, output_binary); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
process_normal_burst(d_burst_nr, output_binary, first_burst); //TODO: this shouldn't be here - remove it when gsm receiver's interface will be ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,14 @@
|
||||||
#include <string>//!!
|
#include <string>//!!
|
||||||
#include <map>//!!
|
#include <map>//!!
|
||||||
|
|
||||||
|
#define N_TCH_DECODER 7 /* for TS1..TS7 */
|
||||||
|
|
||||||
class gsm_receiver_cf;
|
class gsm_receiver_cf;
|
||||||
|
|
||||||
typedef boost::shared_ptr<gsm_receiver_cf> gsm_receiver_cf_sptr;
|
typedef boost::shared_ptr<gsm_receiver_cf> gsm_receiver_cf_sptr;
|
||||||
typedef std::vector<gr_complex> vector_complex;
|
typedef std::vector<gr_complex> vector_complex;
|
||||||
|
|
||||||
gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
|
gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration);
|
||||||
|
|
||||||
/** GSM Receiver GNU Radio block
|
/** GSM Receiver GNU Radio block
|
||||||
*
|
*
|
||||||
|
@ -57,13 +59,8 @@ class gsm_receiver_cf : public gr_block
|
||||||
std::map<char,int> d_hex_to_int;
|
std::map<char,int> d_hex_to_int;
|
||||||
FILE * d_gsm_file; //!!
|
FILE * d_gsm_file; //!!
|
||||||
byte d_KC[8]; //!!
|
byte d_KC[8]; //!!
|
||||||
GSM::TCHFACCHL1Decoder d_tch_decoder1; //!!
|
GSM::TCHFACCHL1Decoder *d_tch_decoder[N_TCH_DECODER]; //!!
|
||||||
GSM::TCHFACCHL1Decoder d_tch_decoder2; //!!
|
bool d_trace_sch;
|
||||||
GSM::TCHFACCHL1Decoder d_tch_decoder3; //!!
|
|
||||||
GSM::TCHFACCHL1Decoder d_tch_decoder4; //!!
|
|
||||||
GSM::TCHFACCHL1Decoder d_tch_decoder5; //!!
|
|
||||||
GSM::TCHFACCHL1Decoder d_tch_decoder6; //!!
|
|
||||||
GSM::TCHFACCHL1Decoder d_tch_decoder7; //!!
|
|
||||||
/**@name Configuration of the receiver */
|
/**@name Configuration of the receiver */
|
||||||
//@{
|
//@{
|
||||||
const int d_OSR; ///< oversampling ratio
|
const int d_OSR; ///< oversampling ratio
|
||||||
|
@ -117,8 +114,8 @@ class gsm_receiver_cf : public gr_block
|
||||||
// GSM Stack
|
// GSM Stack
|
||||||
GS_CTX d_gs_ctx;//TODO: remove it! it'a not right place for a decoder
|
GS_CTX d_gs_ctx;//TODO: remove it! it'a not right place for a decoder
|
||||||
|
|
||||||
friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
|
friend gsm_receiver_cf_sptr gsm_make_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration);
|
||||||
gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key);
|
gsm_receiver_cf(gr_feval_dd *tuner, gr_feval_dd *synchronizer, int osr, std::string key, std::string configuration);
|
||||||
|
|
||||||
/** Function whis is used to search a FCCH burst and to compute frequency offset before
|
/** Function whis is used to search a FCCH burst and to compute frequency offset before
|
||||||
* "synchronized" state of the receiver
|
* "synchronized" state of the receiver
|
||||||
|
@ -233,7 +230,12 @@ class gsm_receiver_cf : public gr_block
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary);
|
void read_configuration(std::string configuration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void process_normal_burst(burst_counter burst_nr, const unsigned char * burst_binary, bool first_burst);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
|
@ -82,3 +82,24 @@ burst_type channel_configuration::get_burst_type(burst_counter burst_nr)
|
||||||
|
|
||||||
return d_timeslots_descriptions[timeslot_nr].get_burst_type(nr);
|
return d_timeslots_descriptions[timeslot_nr].get_burst_type(nr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool channel_configuration::get_first_burst(burst_counter burst_nr)
|
||||||
|
{
|
||||||
|
uint32_t timeslot_nr = burst_nr.get_timeslot_nr();
|
||||||
|
multiframe_type m_type = d_timeslots_descriptions[timeslot_nr].get_type();
|
||||||
|
uint32_t nr;
|
||||||
|
|
||||||
|
switch (m_type) {
|
||||||
|
case multiframe_26:
|
||||||
|
nr = burst_nr.get_t2();
|
||||||
|
break;
|
||||||
|
case multiframe_51:
|
||||||
|
nr = burst_nr.get_t3();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nr = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return d_timeslots_descriptions[timeslot_nr].get_first_burst(nr);
|
||||||
|
}
|
||||||
|
|
|
@ -38,10 +38,12 @@ class multiframe_configuration
|
||||||
private:
|
private:
|
||||||
multiframe_type d_type;
|
multiframe_type d_type;
|
||||||
std::vector<burst_type> d_burst_types;
|
std::vector<burst_type> d_burst_types;
|
||||||
|
std::vector<bool> d_first_burst;
|
||||||
public:
|
public:
|
||||||
multiframe_configuration() {
|
multiframe_configuration() {
|
||||||
d_type = unknown;
|
d_type = unknown;
|
||||||
fill(d_burst_types.begin(), d_burst_types.end(), empty);
|
fill(d_burst_types.begin(), d_burst_types.end(), empty);
|
||||||
|
fill(d_first_burst.begin(), d_first_burst.end(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
~multiframe_configuration() {}
|
~multiframe_configuration() {}
|
||||||
|
@ -49,9 +51,13 @@ class multiframe_configuration
|
||||||
void set_type(multiframe_type type) {
|
void set_type(multiframe_type type) {
|
||||||
if (type == multiframe_26) {
|
if (type == multiframe_26) {
|
||||||
d_burst_types.resize(26);
|
d_burst_types.resize(26);
|
||||||
|
d_first_burst.resize(26);
|
||||||
} else {
|
} else {
|
||||||
d_burst_types.resize(51);
|
d_burst_types.resize(51);
|
||||||
|
d_first_burst.resize(51);
|
||||||
}
|
}
|
||||||
|
fill(d_burst_types.begin(), d_burst_types.end(), empty);
|
||||||
|
fill(d_first_burst.begin(), d_first_burst.end(), false);
|
||||||
|
|
||||||
d_type = type;
|
d_type = type;
|
||||||
}
|
}
|
||||||
|
@ -60,6 +66,10 @@ class multiframe_configuration
|
||||||
d_burst_types[nr] = type;
|
d_burst_types[nr] = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_first_burst(int nr, bool first_burst) {
|
||||||
|
d_first_burst[nr] = first_burst;
|
||||||
|
}
|
||||||
|
|
||||||
multiframe_type get_type() {
|
multiframe_type get_type() {
|
||||||
return d_type;
|
return d_type;
|
||||||
}
|
}
|
||||||
|
@ -67,6 +77,10 @@ class multiframe_configuration
|
||||||
burst_type get_burst_type(int nr) {
|
burst_type get_burst_type(int nr) {
|
||||||
return d_burst_types[nr];
|
return d_burst_types[nr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get_first_burst(int nr) {
|
||||||
|
return d_first_burst[nr];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class burst_counter
|
class burst_counter
|
||||||
|
@ -154,11 +168,20 @@ class channel_configuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_burst_types(int timeslot_nr, const unsigned mapping[], const unsigned first_burst[], unsigned mapping_size, burst_type b_type) {
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < mapping_size; i++) {
|
||||||
|
d_timeslots_descriptions[timeslot_nr].set_burst_type(mapping[i], b_type);
|
||||||
|
d_timeslots_descriptions[timeslot_nr].set_first_burst(mapping[i], first_burst[i] != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_single_burst_type(int timeslot_nr, int burst_nr, burst_type b_type) {
|
void set_single_burst_type(int timeslot_nr, int burst_nr, burst_type b_type) {
|
||||||
d_timeslots_descriptions[timeslot_nr].set_burst_type(burst_nr, b_type);
|
d_timeslots_descriptions[timeslot_nr].set_burst_type(burst_nr, b_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
burst_type get_burst_type(burst_counter burst_nr);
|
burst_type get_burst_type(burst_counter burst_nr);
|
||||||
|
bool get_first_burst(burst_counter burst_nr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCLUDED_GSM_RECEIVER_CONFIG_H */
|
#endif /* INCLUDED_GSM_RECEIVER_CONFIG_H */
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#echo "go.sh <file.cfile> [decim==112]"
|
#echo "go.sh <file.cfile> [decim==112]"
|
||||||
|
|
||||||
|
KEY=$4
|
||||||
|
CONFIGURATION=$3
|
||||||
DECIM=$2
|
DECIM=$2
|
||||||
FILE=$1
|
FILE=$1
|
||||||
|
|
||||||
|
@ -9,4 +11,16 @@ if [ $DECIM"x" = x ]; then
|
||||||
DECIM=112
|
DECIM=112
|
||||||
fi
|
fi
|
||||||
|
|
||||||
./gsm_receive.py -d "$DECIM" -I "$FILE" | ../../../gsmdecode/src/gsmdecode -i
|
if [ $CONFIGURATION"x" = x ]; then
|
||||||
|
CONFIGURATION=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$KEY""x" = x ]; then
|
||||||
|
KEY="00 00 00 00 00 00 00 00"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use GSMTAP with WireShark instead of gmsdecode !
|
||||||
|
|
||||||
|
#./gsm_receive.py -d "$DECIM" -I "$FILE" -c "$CONFIGURATION" -k "$KEY" | ../../../gsmdecode/src/gsmdecode -i
|
||||||
|
|
||||||
|
./gsm_receive.py -d "$DECIM" -I "$FILE" -c "$CONFIGURATION" -k "$KEY"
|
||||||
|
|
|
@ -82,7 +82,7 @@ class gsm_receiver_first_blood(gr.top_block):
|
||||||
return interpolator
|
return interpolator
|
||||||
|
|
||||||
def _set_receiver(self):
|
def _set_receiver(self):
|
||||||
receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr, self.options.key.replace(' ', '').lower())
|
receiver = gsm.receiver_cf(self.tuner_callback, self.synchronizer_callback, self.options.osr, self.options.key.replace(' ', '').lower(), self.options.configuration.upper())
|
||||||
return receiver
|
return receiver
|
||||||
|
|
||||||
def _process_options(self):
|
def _process_options(self):
|
||||||
|
@ -97,6 +97,8 @@ class gsm_receiver_first_blood(gr.top_block):
|
||||||
help="Output filename")
|
help="Output filename")
|
||||||
parser.add_option("-k", "--key", type="string", default="AD 6A 3E C2 B4 42 E4 00",
|
parser.add_option("-k", "--key", type="string", default="AD 6A 3E C2 B4 42 E4 00",
|
||||||
help="KC session key")
|
help="KC session key")
|
||||||
|
parser.add_option("-c", "--configuration", type="string", default="",
|
||||||
|
help="Decoder configuration")
|
||||||
|
|
||||||
(options, args) = parser.parse_args ()
|
(options, args) = parser.parse_args ()
|
||||||
return (options, args)
|
return (options, args)
|
||||||
|
|
Loading…
Reference in New Issue