/* Implementation of TETRA burst synchronization */ /* (C) 2011 by Harald Welte * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include //#define DEBUG #include #include #include #include struct tetra_phy_state t_phy_state; void tetra_burst_rx_cb(const uint8_t *burst, unsigned int len, enum tetra_train_seq type, void *priv); static void make_bitbuf_space(struct tetra_rx_state *trs, unsigned int len) { unsigned int bitbuf_space = sizeof(trs->bitbuf) - trs->bits_in_buf; if (bitbuf_space < len) { unsigned int delta = len - bitbuf_space; DEBUGP("bitbuf left: %u, shrinking by %u\n", bitbuf_space, delta); memmove(trs->bitbuf, trs->bitbuf + delta, trs->bits_in_buf - delta); trs->bits_in_buf -= delta; trs->bitbuf_start_bitnum += delta; bitbuf_space = sizeof(trs->bitbuf) - trs->bits_in_buf; } } /* input a raw bitstream into the tetra burst synchronizaer */ int tetra_burst_sync_in(struct tetra_rx_state *trs, uint8_t *bits, unsigned int len) { int rc; unsigned int train_seq_offs; DEBUGP("burst_sync_in: %u bits, state %u\n", len, trs->state); /* First: append the data to the bitbuf */ make_bitbuf_space(trs, len); memcpy(trs->bitbuf + trs->bits_in_buf, bits, len); trs->bits_in_buf += len; switch (trs->state) { case RX_S_UNLOCKED: if (trs->bits_in_buf < TETRA_BITS_PER_TS*2) { /* wait for more bits to arrive */ DEBUGP("-> waiting for more bits to arrive\n"); return len; } DEBUGP("-> trying to find training sequence between bit %u and %u\n", trs->bitbuf_start_bitnum, trs->bits_in_buf); rc = tetra_find_train_seq(trs->bitbuf, trs->bits_in_buf, (1 << TETRA_TRAIN_SYNC), &train_seq_offs); if (rc < 0) return rc; printf("found SYNC training sequence in bit #%u\n", train_seq_offs); trs->state = RX_S_KNOW_FSTART; trs->next_frame_start_bitnum = trs->bitbuf_start_bitnum + train_seq_offs + 296; #if 0 if (train_seq_offs < 214) { /* not enough leading bits for start of burst */ /* we just drop everything that we received so far */ trs->bitbuf_start_bitnum += trs->bits_in_buf; trs->bits_in_buf = 0; } #endif break; case RX_S_KNOW_FSTART: /* we are locked, i.e. already know when the next frame should start */ if (trs->bitbuf_start_bitnum + trs->bits_in_buf < trs->next_frame_start_bitnum) return 0; else { /* shift start of frame to start of bitbuf */ int offset = trs->next_frame_start_bitnum - trs->bitbuf_start_bitnum; int bits_remaining = trs->bits_in_buf - offset; memmove(trs->bitbuf, trs->bitbuf+offset, bits_remaining); trs->bits_in_buf = bits_remaining; trs->bitbuf_start_bitnum += offset; trs->next_frame_start_bitnum += TETRA_BITS_PER_TS; trs->state = RX_S_LOCKED; } case RX_S_LOCKED: if (trs->bits_in_buf < TETRA_BITS_PER_TS) { /* not sufficient data for the full frame yet */ return len; } else { /* we have successfully received (at least) one frame */ tetra_tdma_time_add_tn(&t_phy_state.time, 1); printf("\nBURST"); DEBUGP(": %s", osmo_ubit_dump(trs->bitbuf, TETRA_BITS_PER_TS)); printf("\n"); rc = tetra_find_train_seq(trs->bitbuf, trs->bits_in_buf, (1 << TETRA_TRAIN_NORM_1)| (1 << TETRA_TRAIN_NORM_2)| (1 << TETRA_TRAIN_SYNC), &train_seq_offs); switch (rc) { case TETRA_TRAIN_SYNC: if (train_seq_offs == 214) tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv); else { fprintf(stderr, "#### SYNC burst at offset %u?!?\n", train_seq_offs); trs->state = RX_S_UNLOCKED; } break; case TETRA_TRAIN_NORM_1: case TETRA_TRAIN_NORM_2: case TETRA_TRAIN_NORM_3: if (train_seq_offs == 244) tetra_burst_rx_cb(trs->bitbuf, TETRA_BITS_PER_TS, rc, trs->burst_cb_priv); else fprintf(stderr, "#### SYNC burst at offset %u?!?\n", train_seq_offs); break; default: fprintf(stderr, "#### could not find successive burst training sequence\n"); trs->state = RX_S_UNLOCKED; break; } /* move remainder to start of buffer */ trs->bits_in_buf -= TETRA_BITS_PER_TS; memmove(trs->bitbuf, trs->bitbuf+TETRA_BITS_PER_TS, trs->bits_in_buf); trs->bitbuf_start_bitnum += TETRA_BITS_PER_TS; trs->next_frame_start_bitnum += TETRA_BITS_PER_TS; } break; } return len; }