Applied Jeroen's patch to add data channel support to 800AX
authorbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 4 May 2016 05:18:52 +0000 (05:18 +0000)
committerbaobrien <baobrien@01035d8c-6547-0410-b346-abe4f91aad63>
Wed, 4 May 2016 05:18:52 +0000 (05:18 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2796 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/src/c2dec.c
codec2-dev/src/freedv_api.c
codec2-dev/src/freedv_data_channel.c
codec2-dev/src/freedv_data_channel.h
codec2-dev/src/freedv_rx.c
codec2-dev/src/freedv_tx.c
codec2-dev/src/freedv_vhf_framing.c
codec2-dev/unittest/CMakeLists.txt
codec2-dev/unittest/tfreedv_data_channel.c [new file with mode: 0644]

index 1e261ac65e03388fdc791f27fe27753cf6ed0ae2..bb9905834ef8b41364655dcf110c8475fadf4140 100644 (file)
@@ -58,6 +58,7 @@ int main(int argc, char *argv[])
     float          ber, r, burst_length, burst_period, burst_timer, ber_est;
     unsigned char  mask;
     int            natural, dump, softdec, bit, ret;
+    int            report_energy;
 
     char* opt_string = "h:";
     struct option long_options[] = {
@@ -70,6 +71,7 @@ int main(int argc, char *argv[])
         #ifdef DUMP
         { "dump", required_argument, &dump, 1 },
         #endif
+       { "energy", no_argument, NULL, 0 },
         { "help", no_argument, NULL, 'h' },
         { NULL, no_argument, NULL, 0 }
     };
@@ -119,6 +121,7 @@ int main(int argc, char *argv[])
     burst_length = burst_period = 0.0;
     burst_timer = 0.0;
     dump = natural = softdec = 0;
+    report_energy = 0;
 
     codec2 = codec2_create(mode);
     nsam = codec2_samples_per_frame(codec2);
@@ -147,7 +150,7 @@ int main(int argc, char *argv[])
                nstart_bit = atoi(optarg);
             } else if(strcmp(long_options[option_index].name, "endbit") == 0) {
                nend_bit = atoi(optarg);
-             } else if(strcmp(long_options[option_index].name, "berfile") == 0) {
+            } else if(strcmp(long_options[option_index].name, "berfile") == 0) {
                if ((fber = fopen(optarg,"wt")) == NULL) {
                    fprintf(stderr, "Error opening BER file: %s %s.\n",
                             optarg, strerror(errno));
@@ -161,6 +164,9 @@ int main(int argc, char *argv[])
                    dump_on(optarg);
             }
             #endif
+           else if (strcmp(long_options[option_index].name, "energy") == 0) {
+               report_energy = 1;
+           }
             break;
 
         case 'h':
@@ -269,6 +275,9 @@ int main(int argc, char *argv[])
             codec2_set_softdec(codec2, softdec_bits);
         }
 
+        if (report_energy)
+           fprintf(stderr, "Energy: %1.3f\n", codec2_get_energy(codec2, bits));
+
        codec2_decode_ber(codec2, buf, bits, ber_est);
        fwrite(buf, sizeof(short), nsam, fout);
 
@@ -303,7 +312,7 @@ void print_help(const struct option* long_options, int num_opts, char* argv[])
        int i;
        char *option_parameters;
        fprintf(stderr, "\nc2dec - Codec 2 decoder and bit error simulation program\n"
-               "usage: %s 3200|2400|1400}1300|1200 InputFile OutputRawFile [OPTIONS]\n\n"
+               "usage: %s 3200|2400|1600|1400|1300|1200|700|700B InputFile OutputRawFile [OPTIONS]\n\n"
                 "Options:\n", argv[0]);
         for(i=0; i<num_opts-1; i++) {
                if(long_options[i].has_arg == no_argument) {
index 60de1e583dd47cf9006cfb80d211d8e876e1be44..53b75983f9599275a8867ea2b6ae2aff8d7f453e 100644 (file)
@@ -453,13 +453,16 @@ static void freedv_tx_fsk_data(struct freedv *f, short mod_out[]) {
     int  i;
     float *tx_float; /* To hold on to modulated samps from fsk/fmfsk */
     
-    fvhff_frame_data_bits(f->deframer, FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits));
+    if (f->mode != FREEDV_MODE_800XA)
+       fvhff_frame_data_bits(f->deframer, FREEDV_VHF_FRAME_A,(uint8_t*)(f->tx_bits));
+    else
+        fvhff_frame_data_bits(f->deframer, FREEDV_HF_FRAME_B,(uint8_t*)(f->tx_bits));
         
     /* Allocate floating point buffer for FSK mod */
     tx_float = alloca(sizeof(float)*f->n_nom_modem_samples);
         
     /* do 4fsk mod */
-    if(f->mode == FREEDV_MODE_2400A){
+    if(f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_800XA){
         fsk_mod(f->fsk,tx_float,(uint8_t*)(f->tx_bits));
         /* Convert float samps to short */
         for(i=0; i<f->n_nom_modem_samples; i++){
@@ -760,7 +763,10 @@ int  freedv_data_ntxframes (struct freedv *f){
     #ifndef CORTEX_M4
     if (f->mode == FREEDV_MODE_2400A || f->mode == FREEDV_MODE_2400B) {
         if (f->deframer->fdc)
-            return freedv_data_get_n_tx_frames(f->deframer->fdc);
+            return freedv_data_get_n_tx_frames(f->deframer->fdc, 8);
+    } else if (f->mode == FREEDV_MODE_800XA) {
+        if (f->deframer->fdc)
+            return freedv_data_get_n_tx_frames(f->deframer->fdc, 6);
     }
     #endif
     return 0;
index 723412e4dfcab3b0886ee72d8534d16ffa2b1fc1..32ba6eb7c9b7849fc856d28f386a622f0d5bc65b 100644 (file)
@@ -82,6 +82,27 @@ static unsigned short fdc_crc(unsigned char *buffer, size_t len)
 \r
     return crc ^ 0xffff;\r
 }\r
+\r
+/* CRC4 0x03 polynomal */\r
+static unsigned char fdc_crc4(unsigned char *buffer, size_t len)\r
+{\r
+    unsigned char crc = 0x0f;\r
+    size_t i;\r
+    \r
+    for (i = 0; i < len; i++, buffer++) {\r
+        int shift;\r
+       \r
+        for (shift = 7; shift <= 0; shift--) {\r
+            crc <<= 1;\r
+            if ((*buffer >> shift) & 0x1)\r
+                crc |= 1;\r
+            if (crc & 0x10)\r
+                crc ^= 0x03;\r
+       }\r
+    }\r
+    \r
+    return crc & 0x0f;\r
+}\r
  \r
 struct freedv_data_channel *freedv_data_channel_create(void)\r
 {\r
@@ -118,8 +139,15 @@ void freedv_data_set_cb_tx(struct freedv_data_channel *fdc, freedv_data_callback
     fdc->cb_tx_state = state;\r
 }\r
 \r
-void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char data[8], int from_bit, int bcast_bit, int end_bits)\r
+void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int from_bit, int bcast_bit, int crc_bit, int end_bits)\r
 {\r
+    int copy_bits;\r
+    if (end_bits) {\r
+        copy_bits = end_bits;\r
+    } else {\r
+        copy_bits = size;\r
+    }\r
+\r
     /* New packet? */\r
     if (fdc->packet_rx_cnt == 0) {\r
         /* Does the packet have a compressed from field? */\r
@@ -129,18 +157,34 @@ void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char
            fdc->packet_rx_cnt += 6;        \r
                }\r
        if (bcast_bit) {\r
-           /* Compressed to: fill in broadcast address */\r
-           memcpy(fdc->packet_rx + fdc->packet_rx_cnt, fdc_header_bcast, sizeof(fdc_header_bcast));\r
-           fdc->packet_rx_cnt += 6;\r
+            if (!from_bit) {\r
+                /* Copy from header and modify size and end_bits accordingly */\r
+                memcpy(fdc->packet_rx + fdc->packet_rx_cnt, data, 6);\r
+                fdc->packet_rx_cnt += 6;\r
+                copy_bits -= 6;\r
+                if (copy_bits < 0)\r
+                    copy_bits = 0;\r
+                data += 6;\r
+            }\r
+            /* Compressed to: fill in broadcast address */\r
+            memcpy(fdc->packet_rx + fdc->packet_rx_cnt, fdc_header_bcast, sizeof(fdc_header_bcast));\r
+            fdc->packet_rx_cnt += 6;\r
        }\r
+        if (crc_bit) {\r
+            unsigned char calc_crc = fdc_crc4(data, size);\r
+            if (calc_crc == end_bits) {\r
+               /* It is a single header field, remember it for later */\r
+                memcpy(fdc->packet_rx + 6, data, 6);\r
+               memcpy(fdc->packet_rx, fdc_header_bcast, 6);\r
+                if (fdc->cb_rx) {\r
+                    fdc->cb_rx(fdc->cb_rx_state, fdc->packet_rx, 12);\r
+                }\r
+            }\r
+            fdc->packet_rx_cnt = 0;\r
+            return;\r
+        }\r
     }\r
     \r
-    int copy_bits;\r
-    if (end_bits) {\r
-        copy_bits = end_bits;\r
-    } else {\r
-        copy_bits = 8;\r
-    }\r
     if (fdc->packet_rx_cnt + copy_bits >= FREEDV_DATA_CHANNEL_PACKET_MAX) {\r
         /* Something went wrong... this can not be a real packet */\r
        fdc->packet_rx_cnt = 0;\r
@@ -157,7 +201,7 @@ void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char
         rx_crc |= fdc->packet_rx[fdc->packet_rx_cnt - 2];\r
 \r
         if (rx_crc == calc_crc) {\r
-            if (fdc->packet_rx_cnt == 8) {\r
+            if (fdc->packet_rx_cnt == size) {\r
                /* It is a single header field, remember it for later */\r
                 memcpy(fdc->rx_header, fdc->packet_rx, 6);\r
             }\r
@@ -179,10 +223,11 @@ void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char
     }\r
 }\r
 \r
-void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char data[8], int *from_bit, int *bcast_bit, int *end_bits)\r
+void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int *from_bit, int *bcast_bit, int *crc_bit, int *end_bits)\r
 {\r
     *from_bit = 0;\r
     *bcast_bit = 0;\r
+    *crc_bit = 0;\r
     \r
     if (!fdc->packet_tx_size) {\r
         fdc->packet_tx_cnt = 0;\r
@@ -193,12 +238,23 @@ void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char
         }\r
        if (!fdc->packet_tx_size) {\r
            /* Nothing to send, insert a header frame */\r
-           memcpy(fdc->packet_tx, fdc->tx_header, 8);\r
-           fdc->packet_tx_size = 8;\r
+           memcpy(fdc->packet_tx, fdc->tx_header, size);\r
+            if (size < 8) {\r
+                *end_bits = fdc_crc4(fdc->tx_header, size);\r
+                *crc_bit = 1;\r
+                memcpy(data, fdc->tx_header, size);\r
+\r
+                return;\r
+            } else {\r
+                fdc->packet_tx_size = size;\r
+            }            \r
        } else {\r
            /* new packet */\r
            unsigned short crc;\r
             unsigned char tmp[6];\r
+            \r
+            *from_bit = !memcmp(fdc->packet_tx + 6, fdc->tx_header, 6);\r
+            *bcast_bit = !memcmp(fdc->packet_tx, fdc_header_bcast, 6);\r
 \r
             memcpy(tmp, fdc->packet_tx, 6);\r
            memcpy(fdc->packet_tx, fdc->packet_tx + 6, 6);\r
@@ -211,22 +267,23 @@ void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char
            fdc->packet_tx[fdc->packet_tx_size] = (crc >> 8) & 0xff;\r
            fdc->packet_tx_size++;\r
            \r
-           if (!memcmp(fdc->packet_tx, fdc->tx_header, 6)) {\r
-               *from_bit = 1;\r
+           if (*from_bit) {\r
                fdc->packet_tx_cnt = 6;\r
-               \r
-               if (!memcmp(fdc->packet_tx + 6, fdc_header_bcast, 6)) {\r
-                   *bcast_bit = 1;\r
-                   fdc->packet_tx_cnt += 6;\r
-               }\r
-           }\r
+            } else {\r
+                if (*bcast_bit) {\r
+                    memcpy(fdc->packet_tx + 6, fdc->packet_tx, 6);\r
+                }\r
+            }\r
+            if (*bcast_bit) {\r
+                fdc->packet_tx_cnt += 6;\r
+            }\r
        }\r
     }\r
     if (fdc->packet_tx_size) {\r
         int copy = fdc->packet_tx_size - fdc->packet_tx_cnt;\r
        \r
-        if (copy > 8) {\r
-            copy = 8;\r
+        if (copy > size) {\r
+            copy = size;\r
            *end_bits = 0;\r
         } else {\r
             *end_bits = copy;\r
@@ -246,8 +303,8 @@ void freedv_data_set_header(struct freedv_data_channel *fdc, unsigned char *head
     fdc->tx_header[7] = (crc >> 8) & 0xff;\r
 }\r
 \r
-int freedv_data_get_n_tx_frames(struct freedv_data_channel *fdc)\r
+int freedv_data_get_n_tx_frames(struct freedv_data_channel *fdc, size_t size)\r
 {\r
-    /* packet will be send in 8 byte frames */\r
-    return (fdc->packet_tx_size + 7) / 8;\r
+    /* packet will be send in 'size' byte frames */\r
+    return (fdc->packet_tx_size + size-1) / size;\r
 }\r
index cae25149a803aa7f2a335b5bef5ca5b101dd6349..e12f6dc39db64efbf6722c54ed609018f707c91b 100644 (file)
@@ -61,10 +61,10 @@ void freedv_data_channel_destroy(struct freedv_data_channel *fdc);
 void freedv_data_set_cb_rx(struct freedv_data_channel *fdc, freedv_data_callback_rx cb, void *state);\r
 void freedv_data_set_cb_tx(struct freedv_data_channel *fdc, freedv_data_callback_tx cb, void *state);\r
 \r
-void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char data[8], int from_bit, int bcast_bit, int end_bits);\r
-void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char data[8], int *from_bit, int *bcast_bit, int *end_bits);\r
+void freedv_data_channel_rx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int from_bit, int bcast_bit, int crc_bit, int end_bits);\r
+void freedv_data_channel_tx_frame(struct freedv_data_channel *fdc, unsigned char *data, size_t size, int *from_bit, int *bcast_bit, int *crc_bit, int *end_bits);\r
 \r
 void freedv_data_set_header(struct freedv_data_channel *fdc, unsigned char *header);\r
-int freedv_data_get_n_tx_frames(struct freedv_data_channel *fdc);\r
+int freedv_data_get_n_tx_frames(struct freedv_data_channel *fdc, size_t size);\r
 \r
 #endif /* _FREEDV_DATA_CHANNEL_H */\r
index f351452c78c16a75393268ab3894b1bc72db6e8b..59d265e6bfa532835fd7de3aebb46470c2e8828c 100644 (file)
@@ -208,16 +208,16 @@ int main(int argc, char *argv[]) {
             /* deccode the speech ourself (or send it to elsewhere, e.g. network) */
             if (nout) {
                 unsigned char *enc_frame = encoded;
-               short *speech_frame = speech_out;
-               
-               nout = 0;
-               for (i = 0; i < codec_frames; i++) {
-                   codec2_decode(c2, speech_frame, enc_frame);
-                   enc_frame += bytes_per_codec_frame;
-                   speech_frame += samples_per_frame;
-                   nout += samples_per_frame;
-               }
-           }
+                short *speech_frame = speech_out;
+                
+                nout = 0;
+                for (i = 0; i < codec_frames; i++) {
+                    codec2_decode(c2, speech_frame, enc_frame);
+                    enc_frame += bytes_per_codec_frame;
+                    speech_frame += samples_per_frame;
+                    nout += samples_per_frame;
+                }
+            }
         }
 
         nin = freedv_nin(freedv);
index f434f06164e16c1e944e551a21e95be80709e23d..e56dd06a54d624d58dc6ee743b0822f63634e4b5 100644 (file)
@@ -75,7 +75,7 @@ void my_datatx(void *callback_state, unsigned char *packet, size_t *size) {
         int i;
        for (i = 0; i < 64; i++)
            packet[i] = i;
-       *size = i;
+        *size = i;
     } else {
         /* set size to zero, the freedv api will insert a header frame */
         *size = 0;
@@ -143,24 +143,23 @@ int main(int argc, char *argv[]) {
             }
             if (strcmp(argv[i], "--codectx") == 0) {
                 int c2_mode;
-
+                
                 if (mode == FREEDV_MODE_700)  {
-                   c2_mode = CODEC2_MODE_700;
-               } else if ((mode == FREEDV_MODE_700B)|| (mode == FREEDV_MODE_800XA)) {
+                    c2_mode = CODEC2_MODE_700;
+                } else if ((mode == FREEDV_MODE_700B)|| (mode == FREEDV_MODE_800XA)) {
                     c2_mode = CODEC2_MODE_700B;
                 } else {
                     c2_mode = CODEC2_MODE_1300;
                 }
                 use_codectx = 1;
-
                 c2 = codec2_create(c2_mode);
                 assert(c2 != NULL);
             }
-           if (strcmp(argv[i], "--datatx") == 0) {
-               unsigned char header[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc };
-               freedv_set_data_header(freedv, header);
-               use_datatx = 1;
-           }
+            if (strcmp(argv[i], "--datatx") == 0) {
+                unsigned char header[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc };
+                freedv_set_data_header(freedv, header);
+                use_datatx = 1;
+            }
         }
     }
     freedv_set_snr_squelch_thresh(freedv, -100.0);
@@ -200,30 +199,30 @@ int main(int argc, char *argv[]) {
             unsigned char encoded[bytes_per_codec_frame * codec_frames];
             unsigned char *enc_frame = encoded;
             short *speech_frame = speech_in;
-           float energy = 0;
+            float energy = 0;
 
             /* Encode the speech ourself (or get it from elsewhere, e.g. network) */
             for (i = 0; i < codec_frames; i++) {
                 codec2_encode(c2, enc_frame, speech_frame);
                 energy += codec2_get_energy(c2, enc_frame);
-               enc_frame += bytes_per_codec_frame;
+                enc_frame += bytes_per_codec_frame;
                 speech_frame += samples_per_frame;
-           }
-           energy /= codec_frames;
-           
-           /* Is the audio fragment quiet? */
-           if (use_datatx && energy < 1.0) {
+            }
+            energy /= codec_frames;
+            fprintf(stderr,"energy:%f\n",energy);
+            /* Is the audio fragment quiet? */
+            if (use_datatx && energy < 1.0) {
                 /* Insert a frame with data instead of speech */
-               freedv_datatx(freedv, mod_out);
+                freedv_datatx(freedv, mod_out);
             } else {
                 /* Use the freedv_api to modulate already encoded frames */
                 freedv_codectx(freedv, mod_out, encoded);
             }
-       }
+        }
 
         fwrite(mod_out, sizeof(short), n_nom_modem_samples, fout);
 
-       /* if this is in a pipeline, we probably don't want the usual
+        /* if this is in a pipeline, we probably don't want the usual
            buffering to occur */
 
         if (fout == stdout) fflush(stdout);
index 63757f6f30e118a65f3a40081cafbe01ccf09695..11d59945a0f4870281de26c3d1da4df0cedcb5ff 100644 (file)
@@ -64,8 +64,11 @@ static const uint8_t A_blank[] =   {1,0,1,0,0,1,1,1, /* Padding[0:3] Proto[0:3]
                                     0,0,0,0,0,0,1,0, /* Voice[48:51] Proto[12:15] */
                                     0,1,1,1,0,0,1,0};/* Proto[16:19] Padding[4:7] */
 
-/* HF Type B UW */
+/* HF Type B voice UW */
 static const uint8_t B_uw_v[] =    {0,1,1,0,0,1,1,1};
+
+/* HF Type B data UW */
+static const uint8_t B_uw_d[] =    {1,1,1,1,0,0,1,0};
                                     
 /* Blank HF type B frame */
 static const uint8_t B_blank[] =   {0,1,1,0,0,1,1,1, /* UW[0:7]                                          */
@@ -165,6 +168,7 @@ void fvhff_frame_data_bits(struct freedv_vhf_deframer * def, int frame_type,
         int end_bits;
         int from_bit;
         int bcast_bit;
+       int crc_bit;
 
         /* Fill out frame with blank frame prototype */
         for(i=0; i<4; i++)
@@ -177,7 +181,7 @@ void fvhff_frame_data_bits(struct freedv_vhf_deframer * def, int frame_type,
             bits_out[40 + i] = A_uw_d[i];
         
         if (def->fdc)
-                freedv_data_channel_tx_frame(def->fdc, data, &from_bit, &bcast_bit, &end_bits);
+                freedv_data_channel_tx_frame(def->fdc, data, 8, &from_bit, &bcast_bit, &crc_bit, &end_bits);
         else
             return;
 
@@ -198,7 +202,40 @@ void fvhff_frame_data_bits(struct freedv_vhf_deframer * def, int frame_type,
         }
 
         for (i = 0; i < 4; i++)
-        bits_out[88 + i] = (end_bits >> (3-i)) & 0x1;
+            bits_out[88 + i] = (end_bits >> (3-i)) & 0x1;
+    } else if (frame_type == FREEDV_HF_FRAME_B){
+        uint8_t data[6];
+        int end_bits;
+        int from_bit;
+        int bcast_bit;
+       int crc_bit;
+
+        /* Fill out frame with blank prototype */
+        for(i=0; i<64; i++)
+            bits_out[i] = B_blank[i];
+
+        /* UW data */
+        for (i=0; i < 8; i++)
+            bits_out[0 + i] = B_uw_d[i];
+        
+        if (def->fdc)
+                freedv_data_channel_tx_frame(def->fdc, data, 6, &from_bit, &bcast_bit, &crc_bit, &end_bits);
+        else
+            return;
+
+        bits_out[56] = from_bit;
+        bits_out[57] = bcast_bit;
+        bits_out[58] = crc_bit;
+        bits_out[59] = 0; /* unused */
+
+        /* Fill in data bits */
+        ibit = 0;
+        for(i=8; i<56; i++){   /* First half */
+            bits_out[i] = UNPACK_BIT_MSBFIRST(data,ibit);
+            ibit++;
+        }
+        for (i = 0; i < 4; i++)
+            bits_out[60 + i] = (end_bits >> (3-i)) & 0x1;
     }
 }
 
@@ -318,7 +355,6 @@ static int fvhff_match_uw(struct freedv_vhf_deframer * def,uint8_t bits[],int to
     int uw_len      = def->uw_size;
     int iuw,ibit;
     const uint8_t * uw[2];
-    int can_be_data;
     int uw_offset;
     int diff[2] = { 0, 0 };
     int i;
@@ -328,16 +364,14 @@ static int fvhff_match_uw(struct freedv_vhf_deframer * def,uint8_t bits[],int to
     /* Set up parameters for the standard type of frame */
     if(frame_type == FREEDV_VHF_FRAME_A){
         uw[0] = A_uw_v;
-               uw[1] = A_uw_d;
+        uw[1] = A_uw_d;
         uw_len = 16;
         uw_offset = 40;
-        can_be_data = 1;
     } else if(frame_type == FREEDV_HF_FRAME_B){
         uw[0] = B_uw_v;
-        uw[1] = B_uw_v;
+        uw[1] = B_uw_d;
         uw_len = 8;
         uw_offset = 0;
-        can_be_data = 0;
     } else {
         return 0;
     }
@@ -356,7 +390,7 @@ static int fvhff_match_uw(struct freedv_vhf_deframer * def,uint8_t bits[],int to
         match[i] = diff[i] <= tol;
     }
     /* Pick the best matching UW */
-    if (diff[0] < diff[1] || !can_be_data) {
+    if (diff[0] < diff[1]) {
         r = match[0];
         *rdiff = diff[0];
         *pt = FRAME_PAYLOAD_TYPE_VOICE;
@@ -509,7 +543,49 @@ static void fvhff_extract_frame_data(struct freedv_vhf_deframer * def,uint8_t bi
         }
     
         if (def->fdc) {
-            freedv_data_channel_rx_frame(def->fdc, data, from_bit, bcast_bit, end_bits);
+            freedv_data_channel_rx_frame(def->fdc, data, 8, from_bit, bcast_bit, 0, end_bits);
+        }
+    } else if(frame_type == FREEDV_HF_FRAME_B){
+        uint8_t data[6];
+        int end_bits = 0;
+        int from_bit;
+        int bcast_bit;
+       int crc_bit;
+        
+        ibit = 0;
+        memset(data,0,6);
+        
+        /* Extract and pack first c2 frame, MSB first */
+        iframe = bitptr+8;
+        if(iframe >= frame_size) iframe-=frame_size;
+        for(;ibit<48;ibit++){
+            data[ibit>>3] |= (bits[iframe]&0x1)<<(7-(ibit&0x7));
+            iframe++;
+            if(iframe >= frame_size) iframe=0;
+        }
+
+        iframe = bitptr+56;
+        if(iframe >= frame_size) iframe-=frame_size;
+        from_bit = bits[iframe];
+        iframe++;
+        if(iframe >= frame_size) iframe-=frame_size;
+        bcast_bit = bits[iframe];
+        iframe++;
+        if(iframe >= frame_size) iframe-=frame_size;
+        crc_bit = bits[iframe];
+        
+        /* Extract endbits value, MSB first*/
+        iframe = bitptr+60;
+        ibit = 0;
+        if(iframe >= frame_size) iframe-=frame_size;
+        for(;ibit<4;ibit++){
+            end_bits |= (bits[iframe]&0x1)<<(3-(ibit));
+            iframe++;
+            if(iframe >= frame_size) iframe=0;
+        }
+
+        if (def->fdc) {
+            freedv_data_channel_rx_frame(def->fdc, data, 7, from_bit, bcast_bit, crc_bit, end_bits);
         }
     }
 }
index e365cd7b8bd39fb90746838313493734e75ea4e3..a3713d56d30cbc9768b9274ec14a09819ec16e75 100644 (file)
@@ -72,6 +72,9 @@ target_link_libraries(tfmfsk m)
 add_executable(tdeframer tdeframer.c)
 target_link_libraries(tdeframer m codec2)
 
+add_executable(tfreedv_data_channel tfreedv_data_channel.c)
+target_link_libraries(tfreedv_data_channel codec2)
+
 #add_executable(t48_8 t48_8.c ../src/fdmdv.c ../src/kiss_fft.c)
 #target_link_libraries(t48_8 codec2)
 
diff --git a/codec2-dev/unittest/tfreedv_data_channel.c b/codec2-dev/unittest/tfreedv_data_channel.c
new file mode 100644 (file)
index 0000000..b67fe9e
--- /dev/null
@@ -0,0 +1,277 @@
+/*---------------------------------------------------------------------------*\
+
+  FILE........: tfreedv_data_channel
+  AUTHOR......: Jeroen Vreeken
+  DATE CREATED: May 3 2016
+
+  Tests for the data channel code.
+  Data channel frame behaviour is tested with test vectors.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2016 Jeroen Vreeken
+
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License version 2, as
+  published by the Free Software Foundation.  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 General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "freedv_data_channel.h"
+
+#include <stdio.h>
+#include <string.h>
+
+unsigned char test_header[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+
+
+struct testvec {
+    char *testname;
+    
+    unsigned char *data;
+    size_t data_size;
+    
+    size_t frame_size;
+    
+    unsigned char *frame_data;
+    size_t frame_data_size;
+
+    unsigned char *flags;
+} testvec[] = {
+    {
+        "Regular packet, does not match header and no broadcast",
+        (unsigned char[]){ 
+            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11, 0x12
+        },
+        0x12,
+        8,
+        (unsigned char[]){ 
+            0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x01, 0x02,
+            0x03, 0x04, 0x05, 0x06, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11, 0x12, 0x47, 0x6e
+        },
+        0x14,
+        (unsigned char[]){ 0x00, 0x00, 0x04 },
+    },
+    {
+        "Header",
+        NULL,
+        0,
+        8,
+        (unsigned char[]){ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x5a, 0x60 },
+        0x08,
+        (unsigned char[]){ 0x08 },
+    },
+    {
+        "Broadcast packet",
+        (unsigned char[]){ 
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x22,
+            0x33, 0x44, 0x55, 0x66, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11
+        },
+        0x19,
+        8,
+        (unsigned char[]){ 
+            0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11, 0x3c, 0xbe
+        },
+        0x0f,
+        (unsigned char[]){ 0xc0, 0x07 },
+    },
+    {
+        "Broadcast packet, header does not match",
+        (unsigned char[]){ 
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x22,
+            0xbb, 0xcc, 0xdd, 0xee, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11
+        },
+        0x19,
+        8,
+        (unsigned char[]){ 
+            0xaa, 0x22,
+            0xbb, 0xcc, 0xdd, 0xee, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11, 0x1a, 0x68
+        },
+        0x15,
+        (unsigned char[]){ 0x40, 0x00, 0x05 },
+    },
+    {
+        "Header 6 bytes",
+        NULL,
+        0,
+        6,
+        (unsigned char[]){ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 },
+        0x06,
+        (unsigned char[]){ 0x2f },
+    },
+    {
+        "Broadcast packet, header does not match (6 byte frames)",
+        (unsigned char[]){ 
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0x22,
+            0xbb, 0xcc, 0xdd, 0xee, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11
+        },
+        0x19,
+        6,
+        (unsigned char[]){ 
+            0xaa, 0x22,
+            0xbb, 0xcc, 0xdd, 0xee, 0x05, 0x06, 0x07, 0x08, 
+            0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+            0x11, 0x1a, 0x68
+        },
+        0x15,
+        (unsigned char[]){ 0x40, 0x00, 0x00, 0x03 },
+    },
+};
+
+
+static int ret = 0;
+static int vector = 0;
+static size_t frame_data_pos = 0;
+static int rx_done = 0;
+
+void *tx_cb_arg = (void*)0xaa55;
+void *rx_cb_arg = (void*)0xbb44;
+
+void tfreedv_data_callback_tx(void *arg, unsigned char *packet, size_t *size)
+{
+    if (tx_cb_arg != arg) {
+        ret++;
+        printf("FAIL: %s called with wrong argument value\n", __func__);
+    }
+    printf("--------------------------------------\n");
+    printf("TX callback called for test %zd bytes data for test %d:\n'%s'\n",
+        testvec[vector].data_size, vector,
+        testvec[vector].testname);
+
+    memcpy(packet, testvec[vector].data, testvec[vector].data_size);
+    *size = testvec[vector].data_size;
+    
+    return;
+}
+
+void tfreedv_data_callback_rx(void *arg, unsigned char *packet, size_t size)
+{
+    if (rx_cb_arg != arg) {
+        ret++;
+        printf("FAIL: %s called with wrong argument value\n", __func__);
+    }
+    printf("RX callback called with %zd bytes\n", size);
+    
+    if (testvec[vector].data_size) {
+        size_t data_size = testvec[vector].data_size;
+        if (data_size != size) {
+            printf("FAIL: Received size does not match test vector: %zd != %zd\n",
+                size, data_size);
+            ret++;
+        } else {
+            size_t i;
+            for (i = 0; i < data_size; i++) {
+                if (packet[i] != testvec[vector].data[i]) {
+                    printf("FAIL: byte %zd does not match 0x%02x != 0x%02x\n",
+                        i, packet[i], testvec[vector].data[i]);
+                    ret++;
+                }
+            }
+        }
+    } else {
+        if (size != 12) {
+            printf("FAIL: Received header is not 12 bytes: %zd\n", size);
+            ret++;
+        } else {
+            if (memcmp(packet+6, test_header, 6)) {
+                printf("FAIL: Header does not match!\n");
+                ret++;
+            }
+        }
+    }
+    
+    rx_done = 1;
+}
+
+int main(int argc, char **argv)
+{
+    struct freedv_data_channel *fdc;
+    
+    fdc = freedv_data_channel_create();
+
+    freedv_data_set_header(fdc, test_header);
+    freedv_data_set_cb_tx(fdc, tfreedv_data_callback_tx, tx_cb_arg);
+    freedv_data_set_cb_rx(fdc, tfreedv_data_callback_rx, rx_cb_arg);
+
+    while (vector < sizeof(testvec)/sizeof(struct testvec)) {
+        size_t frame_size = testvec[vector].frame_size;
+        unsigned char frame[frame_size];
+        int from, bcast, crc, end;
+        int i;
+        size_t check_size;
+        unsigned char flags;
+       
+        freedv_data_channel_tx_frame(fdc, frame, frame_size, &from, &bcast, &crc, &end);
+
+        check_size = frame_size;
+        if (frame_data_pos + check_size > testvec[vector].frame_data_size)
+            check_size = testvec[vector].frame_data_size - frame_data_pos;
+        
+        flags = from * 0x80 + bcast * 0x40 + crc * 0x20 + end;
+        printf("0x%02x:", flags);
+        for (i = 0; i < check_size; i++) {
+            if (frame[i] != testvec[vector].frame_data[frame_data_pos + i]) {
+                printf(" [0x%02x!=0x%02x]", 
+                    frame[i], testvec[vector].frame_data[frame_data_pos + i]);
+                ret++;
+            } else {
+                printf(" 0x%02x", frame[i]);
+            }
+        }
+        printf("\n");
+        
+        if (flags != testvec[vector].flags[frame_data_pos / frame_size]) {
+            printf("FAIL: Flags byte does not match 0x%02x != 0x%02x\n",
+                flags, testvec[vector].flags[frame_data_pos / frame_size]);
+            ret++;
+        }
+
+        freedv_data_channel_rx_frame(fdc, frame, frame_size, from, bcast, crc, end);
+
+        frame_data_pos += frame_size;
+
+        if (frame_data_pos >= testvec[vector].frame_data_size) {
+                vector++;
+                frame_data_pos = 0;
+                if (!rx_done) {
+                    printf("FAIL: RX callback not executed\n");
+                    ret++;
+                }
+                rx_done = 0;
+        }
+    }
+
+    freedv_data_channel_destroy(fdc);
+
+    printf("--------------------------------------\n");
+    printf("tfreedv_data_channel test result: ");
+    if (ret) {
+        printf("Failed %d\n", ret);
+    } else {
+        printf("Passed\n");
+    }
+
+    return ret;
+}