From 22742744fe65534723296391cd5d4a79987c0b37 Mon Sep 17 00:00:00 2001 From: baobrien Date: Mon, 18 Sep 2017 05:06:16 +0000 Subject: [PATCH] More work on TDMA; RX starting to come together git-svn-id: https://svn.code.sf.net/p/freetel/code@3368 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/src/tdma.c | 156 ++++++++++++++++++++++++++++++++++++------ codec2-dev/src/tdma.h | 33 ++++++--- 2 files changed, 158 insertions(+), 31 deletions(-) diff --git a/codec2-dev/src/tdma.c b/codec2-dev/src/tdma.c index 8739dcd5..eafca1af 100644 --- a/codec2-dev/src/tdma.c +++ b/codec2-dev/src/tdma.c @@ -97,11 +97,13 @@ struct TDMA_MODEM * tdma_create(struct TDMA_MODE_SETTINGS mode){ slot->next_slot = last_slot; slot->slot_local_frame_offset = 0; slot->state = rx_no_sync; + slot->bad_uw_count = 0; slot_fsk = fsk_create_hbr(Fs,Rs,P,M,Rs,Rs); if(slot_fsk == NULL) goto cleanup_bad_alloc; - fsk_enable_burst_mode(slot_fsk, slot_size); + /* NOTE/TODO: demod one extra symbol (probably of zeros) off the end of the frame */ + fsk_enable_burst_mode(slot_fsk, slot_size+1); slot->fsk = slot_fsk; last_slot = slot; @@ -154,6 +156,7 @@ u32 tdma_get_N(tdma_t * tdma){ return slot_size * (Fs/Rs); } +/* Convience function to look up a slot from it's index number */ static slot_t * tdma_get_slot(tdma_t * tdma, u32 slot_idx){ /* Don't try and index beyond the end */ if(slot_idx >= tdma->settings.n_slots) return NULL; @@ -171,7 +174,7 @@ static slot_t * tdma_get_slot(tdma_t * tdma, u32 slot_idx){ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" -void tdma_demod_end_slot(tdma_t * tdma,u32 slot_idx){ +int tdma_demod_end_slot(tdma_t * tdma,u32 slot_idx, u8 * bit_buf){ struct TDMA_MODE_SETTINGS mode = tdma->settings; u32 Rs = mode.sym_rate; @@ -183,44 +186,60 @@ void tdma_demod_end_slot(tdma_t * tdma,u32 slot_idx){ u32 Ts = Fs/Rs; u32 bits_per_sym = M==2?1:2; u32 slot_samps = slot_size*Ts; - size_t nbits = slot_size*bits_per_sym; + u32 buffer_samps = slot_samps*n_slots; + size_t nbits = (slot_size+1)*bits_per_sym; u32 frame_bits = frame_size*bits_per_sym; - u8 bit_buf[nbits]; /* Samples that belong to this frame */ - COMP frame_samps[slot_size*Ts]; + COMP frame_samps[(slot_size+1)*Ts]; COMP * sample_buffer = tdma->sample_buffer; slot_t * slot = tdma_get_slot(tdma,slot_idx); - //slot_t * slot = tdma->slots; struct FSK * fsk = slot->fsk; - int nin = fsk_nin(fsk); + /* Zero out tail end of bit buffer so we can get last symbol out of demod */ + /* TODO: This is a hack. Look into better burst mode support in FSK */ + size_t i; + for(i = slot_samps; i< (slot_size+1)*Ts; i++){ + frame_samps[i].real = 0; + frame_samps[i].imag = 0; + } /* Pull out the frame and demod */ - size_t move_samps = slot_samps*sizeof(COMP); - uintptr_t move_from = ((uintptr_t)sample_buffer) + (tdma->sample_sync_offset)*sizeof(COMP); - uintptr_t move_to = (uintptr_t)frame_samps; /* Don't really need this, but it's cleaner than doing it all in memmove */ - memcpy((void*)move_to,(void*)move_from,move_samps); + memcpy(&frame_samps[0],&sample_buffer[tdma->sample_sync_offset],slot_samps*sizeof(COMP)); + /* Demodulate the frame */ fsk_demod(fsk,bit_buf,frame_samps); - size_t delta,off; + i32 delta,off; off = fvhff_search_uw(bit_buf,nbits,TDMA_UW_V,16,&delta); - u32 f_start = off- (frame_bits-16)/2; + i32 f_start = off- (frame_bits-16)/2; + int f_valid = 0; /* Flag indicating wether or not we've found a UW; + + /* Check frame tolerance and sync state*/ + if(slot->state == rx_sync){ + f_valid = delta <= tdma->settings.frame_sync_tol; + }else if(slot->state == rx_no_sync){ + f_valid = delta <= tdma->settings.first_sync_tol; + } + /* Calculate offset (in samps) from start of frame */ - /* Note: FSK outputs one bit from the last batch */ - u32 frame_offset = (f_start-bits_per_sym)*Ts; + /* Note: FSK outputs one symbol from the last batch, so we have to account for that */ + i32 target_frame_offset = ((slot_size-frame_size)/2)*Ts; + i32 frame_offset = ((f_start-bits_per_sym)*(Ts/bits_per_sym)) - target_frame_offset; + if(f_valid) + slot->slot_local_frame_offset = frame_offset; - fprintf(stderr,"slot: %d offset: %d delta: %d f1:%.3f\n",slot_idx,off,delta,fsk->f_est[0]); - for(int i=0; ioff && i<=off+16) || i==f_start || i==(f_start+frame_bits)){ + fprintf(stderr,"slot: %d fstart:%d offset: %d delta: %d f1:%.3f EbN0:%f\n",slot_idx,frame_offset,off,delta,fsk->f_est[0],fsk->EbNodB); + for(i=0; ioff && i<=off+16) || i==f_start || i==(f_start+frame_bits-1)){ if(bit_buf[i]) fprintf(stderr,"1̲"); else fprintf(stderr,"0̲"); } else fprintf(stderr,"%d",bit_buf[i]); } fprintf(stderr,"\n"); -} + return f_valid; +} /* We got a new slot's worth of samples. Run the slot modem and try to get slot sync */ /* This will probably also work for the slot_sync state */ void tdma_rx_pilot_sync(tdma_t * tdma){ @@ -228,16 +247,106 @@ void tdma_rx_pilot_sync(tdma_t * tdma){ u32 Rs = mode.sym_rate; u32 Fs = mode.samp_rate; u32 slot_size = mode.slot_size; - //u32 frame_size = mode.frame_size; + u32 frame_size = mode.frame_size; u32 n_slots = mode.n_slots; u32 M = mode.fsk_m; u32 Ts = Fs/Rs; + u32 slot_samps = slot_size*Ts; u32 bits_per_sym = M==2?1:2; + slot_t * slot = tdma_get_slot(tdma,tdma->slot_cur); + struct FSK * fsk = slot->fsk; + size_t nbits = (slot_size+1)*bits_per_sym; + size_t slot_offset = tdma->sample_sync_offset; + u8 bit_buf[nbits]; + COMP * sample_buffer = tdma->sample_buffer; + COMP frame_samps[(slot_size+1)*Ts]; + u32 frame_bits = frame_size*bits_per_sym; + + /* Compensate for frame timing offset sliding towards end of buffer */ + /* As in, don't demodulate this slot since we're getting ahead of ourselves */ + if( (slot_offset+slot_samps) > (slot_samps*n_slots-(slot_samps/4)) ){ + /* Move slot offset back by 1 slot and don't increment slot index. We'll just handle this one on the next batch of samps */ + tdma->sample_sync_offset -= slot_samps; + return; + } + + /* Demod a slot in the sample buffer */ + //int f_valid = tdma_demod_end_slot(tdma,tdma->slot_cur,bit_buf); + + /* Samples that belong to this frame */ + + /* Zero out tail end of bit buffer so we can get last symbol out of demod */ + /* TODO: This is a hack. Look into better burst mode support in FSK */ + size_t i; + for(i = slot_samps; i< (slot_size+1)*Ts; i++){ + frame_samps[i].real = 0; + frame_samps[i].imag = 0; + } + + /* Pull out the frame and demod */ + memcpy(&frame_samps[0],&sample_buffer[tdma->sample_sync_offset],slot_samps*sizeof(COMP)); + + /* Demodulate the frame */ + fsk_demod(fsk,bit_buf,frame_samps); + + size_t delta,off; + off = fvhff_search_uw(bit_buf,nbits,TDMA_UW_V,16,&delta); + i32 f_start = off- (frame_bits-16)/2; + int f_valid = 0; /* Flag indicating wether or not we've found a UW; + + /* Check frame tolerance and sync state*/ + if(slot->state == rx_sync){ + f_valid = delta <= tdma->settings.frame_sync_tol; + }else if(slot->state == rx_no_sync){ + f_valid = delta <= tdma->settings.first_sync_tol; + } + + /* Calculate offset (in samps) from start of frame */ + /* Note: FSK outputs one symbol from the last batch, so we have to account for that */ + i32 target_frame_offset = ((slot_size-frame_size)/2)*Ts; + i32 frame_offset = ((f_start-bits_per_sym)*(Ts/bits_per_sym)) - target_frame_offset; + if(f_valid) + slot->slot_local_frame_offset = frame_offset; + + + i32 single_slot_offset = slot->slot_local_frame_offset; + /* Flag indicating wether or not we should call the callback */ + int do_frame_found_call = 0; + + /* TODO: deal with re-demod for frames just outside of buffer */ + /* Do single slot state machine */ + if( slot->state == rx_sync){ + if(!f_valid){ /* on bad UW, increment bad uw count and possibly unsync */ + slot->bad_uw_count++; + if(slot->bad_uw_count > tdma->settings.frame_sync_baduw_tol){ + slot->state = rx_no_sync; + }else{ + do_frame_found_call = 1; + } + }else{ /* Good UW found */ + slot->bad_uw_count = 0; + do_frame_found_call = 1; + } + }else if(slot->state == rx_no_sync){ + if(f_valid){ + slot->state = rx_sync; + do_frame_found_call; + } + } + + - tdma_demod_end_slot(tdma,tdma->slot_cur); tdma->slot_cur++; if(tdma->slot_cur >= n_slots) tdma->slot_cur = 0; + + /* Compensate for frame timing offset sliding towards the start of buffer */ + /* Do so by running this again, demodulating two slots, and moving the slot offset one slot forward */ + if( slot_offset < (slot_samps/4) ){ + tdma->sample_sync_offset += slot_samps; + tdma_rx_pilot_sync(tdma); + } + } void tdma_rx_no_sync(tdma_t * tdma, COMP * samps, u64 timestamp){ @@ -322,4 +431,9 @@ void tdma_rx(tdma_t * tdma, COMP * samps,u64 timestamp){ } +void tdma_set_rx_cb(tdma_t * tdma,tdma_cb_rx_frame rx_callback){ + tdma->rx_callback = rx_callback; +} + + #pragma GCC diagnostic pop diff --git a/codec2-dev/src/tdma.h b/codec2-dev/src/tdma.h index de6d78b7..f99723ea 100644 --- a/codec2-dev/src/tdma.h +++ b/codec2-dev/src/tdma.h @@ -42,7 +42,10 @@ typedef int32_t i32; typedef uint8_t u8; typedef float f32; -//typedef void (*tdma_cb_rx_frame)() +/* Callback typedef that just returns the bits of the frame */ +/* TODO: write this a bit better */ +typedef void (*tdma_cb_rx_frame)(u8* frame_bits,u32 slot); + /* The state for an individual slot */ enum slot_state { @@ -78,7 +81,8 @@ struct TDMA_FRAME { struct TDMA_SLOT { struct FSK * fsk; /* The FSK modem for this slot */ enum slot_state state; /* Current local slot state */ - uint32_t slot_local_frame_offset; /* Where the RX frame starts, in samples, from the perspective of the modem */ + i32 slot_local_frame_offset; /* Where the RX frame starts, in samples, from the perspective of the modem */ + u32 bad_uw_count; /* How many bad UWs have we gotten since synchronized */ struct TDMA_SLOT * next_slot; /* Next slot in a linked list of slots */ }; @@ -87,19 +91,24 @@ typedef struct TDMA_SLOT slot_t; /* Structure for tracking basic TDMA modem config */ struct TDMA_MODE_SETTINGS { - uint32_t sym_rate; /* Modem symbol rate */ - uint32_t fsk_m; /* Number of modem tones */ - uint32_t samp_rate; /* Modem samplerate */ - uint32_t slot_size; /* Number of symbols per slot, including quiet padding time */ - uint32_t frame_size; /* Number of symbols per frame, not inclduing quiet padding */ - uint32_t n_slots; /* Number of TDMA slots */ - uint32_t frame_type; /* Frame type number for framer/deframer */ + u32 sym_rate; /* Modem symbol rate */ + u32 fsk_m; /* Number of modem tones */ + u32 samp_rate; /* Modem samplerate */ + u32 slot_size; /* Number of symbols per slot, including quiet padding time */ + u32 frame_size; /* Number of symbols per frame, not inclduing quiet padding */ + u32 n_slots; /* Number of TDMA slots */ + u32 frame_type; /* Frame type number for framer/deframer */ + u32 uw_len; /* Length of unique word */ + u32 pilot_sync_tol; /* UW errors allowed for a valid pilot sync */ + u32 first_sync_tol; /* UW errors allowed for a valid first frame sync */ + u32 frame_sync_tol; /* UW errors allowed to maintain a frame sync */ + u32 frame_sync_baduw_tol; /* How many bad UWs before calling a frame unsynced */ }; /* Declaration of basic 4800bps freedv tdma mode, defined in tdma.h */ //struct TDMA_MODE_SETTINGS FREEDV_4800T; -#define FREEDV_4800T {2400,4,48000,48,44,2,FREEDV_VHF_FRAME_AT} +#define FREEDV_4800T {2400,4,48000,48,44,2,FREEDV_VHF_FRAME_AT,16,4,4,4} /* TDMA modem */ struct TDMA_MODEM { @@ -111,6 +120,7 @@ struct TDMA_MODEM { size_t sample_sync_offset; /* Offset into the sample buffer where slot 0 starts */ uint64_t timestamp; /* Timestamp of oldest sample in samp buffer */ uint32_t slot_cur; /* Current slot coming in */ + tdma_cb_rx_frame rx_callback; }; typedef struct TDMA_MODEM tdma_t; @@ -133,4 +143,7 @@ void tdma_rx(tdma_t * tdma, COMP * samps,u64 timestamp); /* Hideous debug function */ void tdma_print_stuff(tdma_t * tdma); +/* Set the RX callback function */ +void tdma_set_rx_cb(tdma_t * tdma,tdma_cb_rx_frame rx_callback); + #endif -- 2.25.1