diff options
Diffstat (limited to 'src/freedv_mixed_tx.c')
| -rw-r--r-- | src/freedv_mixed_tx.c | 610 |
1 files changed, 302 insertions, 308 deletions
diff --git a/src/freedv_mixed_tx.c b/src/freedv_mixed_tx.c index e323537..b902b12 100644 --- a/src/freedv_mixed_tx.c +++ b/src/freedv_mixed_tx.c @@ -27,350 +27,344 @@ */ #include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> #include <ctype.h> -#include <stdint.h> +#include <errno.h> #include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> -#include "freedv_api.h" #include "codec2.h" +#include "freedv_api.h" /********************************************************** - Encoding an ITU callsign (and 4 bit secondary station ID to a valid MAC address. - http://dmlinking.net/eth_ar.html + Encoding an ITU callsign (and 4 bit secondary station ID to a valid MAC + address. http://dmlinking.net/eth_ar.html */ // Lookup table for valid callsign characters -static char alnum2code[37] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 0 -}; +static char alnum2code[37] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 0}; // Encode a callsign and ssid into a valid MAC address -static int eth_ar_call2mac(uint8_t mac[6], char *callsign, int ssid, bool multicast) -{ - uint64_t add = 0; - int i; - - if (ssid > 15 || ssid < 0) - return -1; - - for (i = 7; i >= 0; i--) { - char c; - - if (i >= strlen(callsign)) { - c = 0; - } else { - c = toupper(callsign[i]); - } - - int j; - - for (j = 0; j < sizeof(alnum2code); j++) { - if (alnum2code[j] == c) - break; - } - if (j == sizeof(alnum2code)) - return -1; - - add *= 37; - add += j; - } - - mac[0] = ((add >> (40 - 6)) & 0xc0) | (ssid << 2) | 0x02 | multicast; - mac[1] = (add >> 32) & 0xff; - mac[2] = (add >> 24) & 0xff; - mac[3] = (add >> 16) & 0xff; - mac[4] = (add >> 8) & 0xff; - mac[5] = add & 0xff; - - return 0; -} +static int eth_ar_call2mac(uint8_t mac[6], char *callsign, int ssid, + bool multicast) { + uint64_t add = 0; + int i; + + if (ssid > 15 || ssid < 0) return -1; + + for (i = 7; i >= 0; i--) { + char c; + + if (i >= strlen(callsign)) { + c = 0; + } else { + c = toupper(callsign[i]); + } + int j; + + for (j = 0; j < sizeof(alnum2code); j++) { + if (alnum2code[j] == c) break; + } + if (j == sizeof(alnum2code)) return -1; + + add *= 37; + add += j; + } + + mac[0] = ((add >> (40 - 6)) & 0xc0) | (ssid << 2) | 0x02 | multicast; + mac[1] = (add >> 32) & 0xff; + mac[2] = (add >> 24) & 0xff; + mac[3] = (add >> 16) & 0xff; + mac[4] = (add >> 8) & 0xff; + mac[5] = add & 0xff; + + return 0; +} /********************************************************** - Data channel callback functions + Data channel callback functions */ - struct my_callback_state { - int calls; - - unsigned char mac[6]; + int calls; + + unsigned char mac[6]; }; /* - Called when a packet has been received - Should not be called in this tx-only test program + Called when a packet has been received + Should not be called in this tx-only test program */ -void my_datarx(void *callback_state, unsigned char *packet, size_t size) -{ - /* This should not happen while sending... */ - fprintf(stderr, "datarx callback called, this should not happen!\n"); +void my_datarx(void *callback_state, unsigned char *packet, size_t size) { + /* This should not happen while sending... */ + fprintf(stderr, "datarx callback called, this should not happen!\n"); } +/* + Called when a new packet can be send. -/* - Called when a new packet can be send. - - callback_state Private state variable, not touched by freedv. - packet Data array where new packet data is expected - size Available size in packet. On return the actual size of the packet + callback_state Private state variable, not touched by freedv. + packet Data array where new packet data is expected + size Available size in packet. On return the actual size of + the packet */ -void my_datatx(void *callback_state, unsigned char *packet, size_t *size) -{ - static int data_type; - struct my_callback_state *my_cb_state = callback_state; - my_cb_state->calls++; - - /* Data could come from a network interface, here we just make up some */ - - if (data_type % 4 == 1) { - /* - Generate a packet with simple test pattern (counting - */ - - /* Send a packet with data */ - int i; - - /* Destination: broadcast */ - memset(packet, 0xff, 6); - /* Source: our eth_ar encoded callsign+ssid */ - memcpy(packet+6, my_cb_state->mac, 6); - /* Ether type: experimental (since this is just a test pattern) */ - packet[12] = 0x01; - packet[13] = 0x01; - - for (i = 0; i < 64; i++) - packet[i + 14] = i; - *size = i + 14; - } else if (data_type % 4 == 2) { - /* - Generate an FPRS position report - */ - - /* Destination: broadcast */ - memset(packet, 0xff, 6); - /* Source: our eth_ar encoded callsign+ssid */ - memcpy(packet+6, my_cb_state->mac, 6); - /* Ether type: FPRS */ - packet[12] = 0x73; - packet[13] = 0x70; - - packet[14] = 0x07; // Position element Lon 86.925026 Lat 27.987850 - packet[15] = 0x3d; // - packet[16] = 0xd0; - packet[17] = 0x37; - packet[18] = 0xd0 | 0x08 | 0x01; - packet[19] = 0x3e; - packet[20] = 0x70; - packet[21] = 0x85; - - *size = 22; - } else { - /* - Set size to zero, the freedv api will insert a header frame - This is useful for identifying ourselves - */ - *size = 0; - } - - data_type++; +void my_datatx(void *callback_state, unsigned char *packet, size_t *size) { + static int data_type; + struct my_callback_state *my_cb_state = callback_state; + my_cb_state->calls++; + + /* Data could come from a network interface, here we just make up some */ + + if (data_type % 4 == 1) { + /* + Generate a packet with simple test pattern (counting + */ + + /* Send a packet with data */ + int i; + + /* Destination: broadcast */ + memset(packet, 0xff, 6); + /* Source: our eth_ar encoded callsign+ssid */ + memcpy(packet + 6, my_cb_state->mac, 6); + /* Ether type: experimental (since this is just a test pattern) */ + packet[12] = 0x01; + packet[13] = 0x01; + + for (i = 0; i < 64; i++) packet[i + 14] = i; + *size = i + 14; + } else if (data_type % 4 == 2) { + /* + Generate an FPRS position report + */ + + /* Destination: broadcast */ + memset(packet, 0xff, 6); + /* Source: our eth_ar encoded callsign+ssid */ + memcpy(packet + 6, my_cb_state->mac, 6); + /* Ether type: FPRS */ + packet[12] = 0x73; + packet[13] = 0x70; + + packet[14] = 0x07; // Position element Lon 86.925026 Lat 27.987850 + packet[15] = 0x3d; // + packet[16] = 0xd0; + packet[17] = 0x37; + packet[18] = 0xd0 | 0x08 | 0x01; + packet[19] = 0x3e; + packet[20] = 0x70; + packet[21] = 0x85; + + *size = 22; + } else { + /* + Set size to zero, the freedv api will insert a header frame + This is useful for identifying ourselves + */ + *size = 0; + } + + data_type++; } - -/* Determine the amount of 'energy' in the samples by squaring them - This is not a perfect VAD as noise may trigger it, but works well for demonstrations. +/* Determine the amount of 'energy' in the samples by squaring them + This is not a perfect VAD as noise may trigger it, but works well for + demonstrations. */ -static float samples_get_energy(short *samples, int nr) -{ - float e = 0; - int i; - - for (i = 0; i < nr; i++) { - e += (float)(samples[i] * samples[i]) / (8192); - } - e /= nr; - - return e; -} - -int main(int argc, char *argv[]) { - FILE *fin, *fout; - short *speech_in; - short *mod_out; - struct freedv *freedv; - struct my_callback_state my_cb_state; - int mode; - int n_speech_samples; - int n_nom_modem_samples; - char *callsign = "NOCALL"; - int ssid = 0; - bool multicast = false; - int use_codectx; - struct CODEC2 *c2; - int i; - float data_threshold = 15; - - if (argc < 4) { - printf("usage: %s 2400A|2400B|800XA InputRawSpeechFile OutputModemRawFile\n" - " [--codectx] [--callsign callsign] [--ssid ssid] [--mac-multicast 0|1] [--data-threshold val]\n", argv[0]); - printf("e.g %s 2400A hts1a.raw hts1a_fdmdv.raw\n", argv[0]); - exit(1); - } +static float samples_get_energy(short *samples, int nr) { + float e = 0; + int i; - mode = -1; - if (!strcmp(argv[1],"2400A")) - mode = FREEDV_MODE_2400A; - if (!strcmp(argv[1],"2400B")) - mode = FREEDV_MODE_2400B; - if (!strcmp(argv[1],"800XA")) - mode = FREEDV_MODE_800XA; - if (mode == -1) { - fprintf(stderr, "Error in mode: %s\n", argv[1]); - exit(0); - } + for (i = 0; i < nr; i++) { + e += (float)(samples[i] * samples[i]) / (8192); + } + e /= nr; - if (strcmp(argv[2], "-") == 0) fin = stdin; - else if ( (fin = fopen(argv[2],"rb")) == NULL ) { - fprintf(stderr, "Error opening input raw speech sample file: %s: %s.\n", argv[2], strerror(errno)); - exit(1); - } - - if (strcmp(argv[3], "-") == 0) fout = stdout; - else if ( (fout = fopen(argv[3],"wb")) == NULL ) { - fprintf(stderr, "Error opening output modem sample file: %s: %s.\n", argv[3], strerror(errno)); - exit(1); - } - - use_codectx = 0; - - if (argc > 4) { - for (i = 4; i < argc; i++) { - if (strcmp(argv[i], "--codectx") == 0) { - int c2_mode; - - if ((mode == FREEDV_MODE_700C) || (mode == FREEDV_MODE_700D) || (mode == FREEDV_MODE_800XA)) { - c2_mode = CODEC2_MODE_700C; - } else { - c2_mode = CODEC2_MODE_1300; - } - use_codectx = 1; - c2 = codec2_create(c2_mode); - assert(c2 != NULL); - } - if (strcmp(argv[i], "--callsign") == 0) { - callsign = argv[i+1]; - } - if (strcmp(argv[i], "--ssid") == 0) { - ssid = atoi(argv[i+1]); - } - if (strcmp(argv[i], "--mac-multicast") == 0) { - multicast = atoi(argv[i+1]); - } - if (strcmp(argv[i], "--data-threshold") == 0) { - data_threshold = atof(argv[i+1]); - } - } - } + return e; +} - freedv = freedv_open(mode); - assert(freedv != NULL); - - /* Generate our address */ - eth_ar_call2mac(my_cb_state.mac, callsign, ssid, multicast); - - freedv_set_data_header(freedv, my_cb_state.mac); - - freedv_set_verbose(freedv, 1); - - n_speech_samples = freedv_get_n_speech_samples(freedv); - n_nom_modem_samples = freedv_get_n_nom_modem_samples(freedv); - speech_in = (short*)malloc(sizeof(short)*n_speech_samples); - assert(speech_in != NULL); - mod_out = (short*)malloc(sizeof(short)*n_nom_modem_samples); - assert(mod_out != NULL); - //fprintf(stderr, "n_speech_samples: %d n_nom_modem_samples: %d\n", n_speech_samples, n_nom_modem_samples); - - /* set up callback for data packets */ - freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state); - - /* OK main loop */ - - while(fread(speech_in, sizeof(short), n_speech_samples, fin) == n_speech_samples) { - if (use_codectx == 0) { - /* Use the freedv_api to do everything: speech encoding, modulating - */ - float energy = samples_get_energy(speech_in, n_speech_samples); - - /* Is the audio fragment quiet? */ - if (energy < data_threshold) { - /* Insert a frame with data instead of speech */ - freedv_datatx(freedv, mod_out); - } else { - /* transmit voice frame */ - freedv_tx(freedv, mod_out, speech_in); - } +int main(int argc, char *argv[]) { + FILE *fin, *fout; + short *speech_in; + short *mod_out; + struct freedv *freedv; + struct my_callback_state my_cb_state; + int mode; + int n_speech_samples; + int n_nom_modem_samples; + char *callsign = "NOCALL"; + int ssid = 0; + bool multicast = false; + int use_codectx; + struct CODEC2 *c2; + int i; + float data_threshold = 15; + + if (argc < 4) { + printf( + "usage: %s 2400A|2400B|800XA InputRawSpeechFile OutputModemRawFile\n" + " [--codectx] [--callsign callsign] [--ssid ssid] [--mac-multicast " + "0|1] [--data-threshold val]\n", + argv[0]); + printf("e.g %s 2400A hts1a.raw hts1a_fdmdv.raw\n", argv[0]); + exit(1); + } + + mode = -1; + if (!strcmp(argv[1], "2400A")) mode = FREEDV_MODE_2400A; + if (!strcmp(argv[1], "2400B")) mode = FREEDV_MODE_2400B; + if (!strcmp(argv[1], "800XA")) mode = FREEDV_MODE_800XA; + if (mode == -1) { + fprintf(stderr, "Error in mode: %s\n", argv[1]); + exit(0); + } + + if (strcmp(argv[2], "-") == 0) + fin = stdin; + else if ((fin = fopen(argv[2], "rb")) == NULL) { + fprintf(stderr, "Error opening input raw speech sample file: %s: %s.\n", + argv[2], strerror(errno)); + exit(1); + } + + if (strcmp(argv[3], "-") == 0) + fout = stdout; + else if ((fout = fopen(argv[3], "wb")) == NULL) { + fprintf(stderr, "Error opening output modem sample file: %s: %s.\n", + argv[3], strerror(errno)); + exit(1); + } + + use_codectx = 0; + + if (argc > 4) { + for (i = 4; i < argc; i++) { + if (strcmp(argv[i], "--codectx") == 0) { + int c2_mode; + + if ((mode == FREEDV_MODE_700C) || (mode == FREEDV_MODE_700D) || + (mode == FREEDV_MODE_800XA)) { + c2_mode = CODEC2_MODE_700C; } else { - /* Use the freedv_api to do the modem part, encode ourselves - - First encode the frames - - Get activity from codec2 api - - Based on activity either send encoded voice or data - */ - int bits_per_codec_frame = freedv_get_bits_per_codec_frame(freedv); - int bits_per_modem_frame = freedv_get_bits_per_modem_frame(freedv); - int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - int bytes_per_modem_frame = (bits_per_modem_frame + 7) / 8; - int codec_frames = bits_per_modem_frame / bits_per_codec_frame; - int samples_per_frame = codec2_samples_per_frame(c2); - unsigned char encoded[bytes_per_codec_frame * codec_frames]; - unsigned char rawdata[bytes_per_modem_frame]; - unsigned char *enc_frame = encoded; - short *speech_frame = speech_in; - 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; - speech_frame += samples_per_frame; - } - energy /= codec_frames; - - /* Is the audio fragment quiet? */ - if (energy < data_threshold) { - /* Insert a frame with data instead of speech */ - freedv_datatx(freedv, mod_out); - } else { - /* Use the freedv_api to modulate already encoded frames */ - freedv_rawdata_from_codec_frames(freedv, rawdata, encoded); - freedv_rawdatatx(freedv, mod_out, rawdata); - } + c2_mode = CODEC2_MODE_1300; } + use_codectx = 1; + c2 = codec2_create(c2_mode); + assert(c2 != NULL); + } + if (strcmp(argv[i], "--callsign") == 0) { + callsign = argv[i + 1]; + } + if (strcmp(argv[i], "--ssid") == 0) { + ssid = atoi(argv[i + 1]); + } + if (strcmp(argv[i], "--mac-multicast") == 0) { + multicast = atoi(argv[i + 1]); + } + if (strcmp(argv[i], "--data-threshold") == 0) { + data_threshold = atof(argv[i + 1]); + } + } + } + + freedv = freedv_open(mode); + assert(freedv != NULL); + + /* Generate our address */ + eth_ar_call2mac(my_cb_state.mac, callsign, ssid, multicast); + + freedv_set_data_header(freedv, my_cb_state.mac); + + freedv_set_verbose(freedv, 1); + + n_speech_samples = freedv_get_n_speech_samples(freedv); + n_nom_modem_samples = freedv_get_n_nom_modem_samples(freedv); + speech_in = (short *)malloc(sizeof(short) * n_speech_samples); + assert(speech_in != NULL); + mod_out = (short *)malloc(sizeof(short) * n_nom_modem_samples); + assert(mod_out != NULL); + // fprintf(stderr, "n_speech_samples: %d n_nom_modem_samples: %d\n", + // n_speech_samples, n_nom_modem_samples); + + /* set up callback for data packets */ + freedv_set_callback_data(freedv, my_datarx, my_datatx, &my_cb_state); + + /* OK main loop */ + + while (fread(speech_in, sizeof(short), n_speech_samples, fin) == + n_speech_samples) { + if (use_codectx == 0) { + /* Use the freedv_api to do everything: speech encoding, modulating + */ + float energy = samples_get_energy(speech_in, n_speech_samples); + + /* Is the audio fragment quiet? */ + if (energy < data_threshold) { + /* Insert a frame with data instead of speech */ + freedv_datatx(freedv, mod_out); + } else { + /* transmit voice frame */ + freedv_tx(freedv, mod_out, speech_in); + } + } else { + /* Use the freedv_api to do the modem part, encode ourselves + - First encode the frames + - Get activity from codec2 api + - Based on activity either send encoded voice or data + */ + int bits_per_codec_frame = freedv_get_bits_per_codec_frame(freedv); + int bits_per_modem_frame = freedv_get_bits_per_modem_frame(freedv); + int bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; + int bytes_per_modem_frame = (bits_per_modem_frame + 7) / 8; + int codec_frames = bits_per_modem_frame / bits_per_codec_frame; + int samples_per_frame = codec2_samples_per_frame(c2); + unsigned char encoded[bytes_per_codec_frame * codec_frames]; + unsigned char rawdata[bytes_per_modem_frame]; + unsigned char *enc_frame = encoded; + short *speech_frame = speech_in; + 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; + speech_frame += samples_per_frame; + } + energy /= codec_frames; + + /* Is the audio fragment quiet? */ + if (energy < data_threshold) { + /* Insert a frame with data instead of speech */ + freedv_datatx(freedv, mod_out); + } else { + /* Use the freedv_api to modulate already encoded frames */ + freedv_rawdata_from_codec_frames(freedv, rawdata, encoded); + freedv_rawdatatx(freedv, mod_out, rawdata); + } + } - fwrite(mod_out, sizeof(short), n_nom_modem_samples, fout); - - /* if this is in a pipeline, we probably don't want the usual - buffering to occur */ - if (fout == stdout) fflush(stdout); + fwrite(mod_out, sizeof(short), n_nom_modem_samples, fout); - } + /* if this is in a pipeline, we probably don't want the usual + buffering to occur */ + if (fout == stdout) fflush(stdout); + } - free(speech_in); - free(mod_out); - freedv_close(freedv); - fclose(fin); - fclose(fout); + free(speech_in); + free(mod_out); + freedv_close(freedv); + fclose(fin); + fclose(fout); - fclose(stdin); - fclose(stderr); + fclose(stdin); + fclose(stderr); - return 0; + return 0; } - |
