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[] = {
#ifdef DUMP
{ "dump", required_argument, &dump, 1 },
#endif
+ { "energy", no_argument, NULL, 0 },
{ "help", no_argument, NULL, 'h' },
{ NULL, no_argument, NULL, 0 }
};
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);
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));
dump_on(optarg);
}
#endif
+ else if (strcmp(long_options[option_index].name, "energy") == 0) {
+ report_energy = 1;
+ }
break;
case 'h':
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);
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) {
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++){
#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;
\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
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
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
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
}\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
}\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
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
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
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
/* 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);
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;
}
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);
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);
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] */
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++)
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;
}
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;
}
}
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;
/* 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;
}
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;
}
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);
}
}
}
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)
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ 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;
+}