From e2c336ff4fc5a65678bab56f16d4ad5f50a4f679 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Mon, 4 Aug 2014 08:56:27 +0000 Subject: [PATCH] added txt support to freedv api git-svn-id: https://svn.code.sf.net/p/freetel/code@1785 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/src/CMakeLists.txt | 1 + codec2-dev/src/freedv_api.c | 90 +++--- codec2-dev/src/freedv_api.h | 38 ++- codec2-dev/src/freedv_rx.c | 12 + codec2-dev/src/freedv_tx.c | 40 ++- codec2-dev/src/varicode.c | 479 ++++++++++++++++++++++++++++++++ codec2-dev/src/varicode.h | 51 ++++ codec2-dev/src/varicode_table.h | 338 ++++++++++++++++++++++ 8 files changed, 997 insertions(+), 52 deletions(-) create mode 100644 codec2-dev/src/varicode.c create mode 100644 codec2-dev/src/varicode.h create mode 100644 codec2-dev/src/varicode_table.h diff --git a/codec2-dev/src/CMakeLists.txt b/codec2-dev/src/CMakeLists.txt index eb1d70af..f84442ef 100644 --- a/codec2-dev/src/CMakeLists.txt +++ b/codec2-dev/src/CMakeLists.txt @@ -184,6 +184,7 @@ set(CODEC2_SRCS codebookge.c golay23.c freedv_api.c + varicode.c ) add_library(codec2 ${CODEC2_SRCS}) diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c index 2c623349..69d2eaa2 100644 --- a/codec2-dev/src/freedv_api.c +++ b/codec2-dev/src/freedv_api.c @@ -8,7 +8,7 @@ embedding FreeDV in other programs. TODO: - [ ] speex tx/rx works + [X] speex tx/rx works [ ] txt messages [ ] optional test tx framemode @@ -39,6 +39,7 @@ #include "codec2.h" #include "codec2_fdmdv.h" #include "golay23.h" +#include "varicode.h" #include "freedv_api.h" /*---------------------------------------------------------------------------*\ @@ -96,6 +97,12 @@ struct freedv *freedv_open(int mode) { || (f->tx_bits == NULL) || (f->rx_bits == NULL) || (f->fdmdv_bits == NULL)) return NULL; + varicode_decode_init(&f->varicode_dec_states, 0); + f->nvaricode_bits = 0; + f->varicode_bit_index = 0; + f->freedv_get_next_tx_char = NULL; + f->freedv_put_next_rx_char = NULL; + golay23_init(); return f; @@ -129,14 +136,15 @@ void freedv_close(struct freedv *freedv) { Takes a frame of input speech samples, encodes and modulates them to produce a frame of modem samples that can be sent to the transmitter. - Both speech_in[] and mod_out[] are FREEDV_NSAMPLES long. + speech_in[] and mod_out[] are sampled at 8 kHz, 16 bit shorts, + and FREEDV_NSAMPLES long. \*---------------------------------------------------------------------------*/ void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) { int bit, byte, i, j; int bits_per_codec_frame, bits_per_fdmdv_frame; - int data, codeword1; + int data, codeword1, data_flag_index; COMP tx_fdm[2*FDMDV_NOM_SAMPLES_PER_FRAME]; bits_per_codec_frame = codec2_bits_per_frame(f->codec2); @@ -156,6 +164,27 @@ void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) { } } + // spare bit in frame that codec defines. Use this 1 + // bit/frame to send txt messages + + data_flag_index = codec2_get_spare_bit_index(f->codec2); + assert(data_flag_index != -1); // not supported for all rates + + if (f->nvaricode_bits) { + f->codec_bits[data_flag_index] = f->tx_varicode_bits[f->varicode_bit_index++]; + f->nvaricode_bits--; + } + + if (f->nvaricode_bits == 0) { + /* get new char and encode */ + char s[2]; + if (f->freedv_get_next_tx_char != NULL) { + s[0] = (*f->freedv_get_next_tx_char)(f->callback_state); + f->nvaricode_bits = varicode_encode(f->tx_varicode_bits, s, VARICODE_MAX_BITS, 1, 0); + f->varicode_bit_index = 0; + } + } + if (f->mode == FREEDV_MODE_1600) { /* Protect first 12 out of first 16 excitation bits with (23,12) Golay Code: @@ -219,6 +248,8 @@ int freedv_nin(struct freedv *f) { Takes a frame of samples from the radio receiver, demodulates them, then decodes them, producing a frame of decoded speech samples. + Both demod_in[] and speech_out[] are 16 bit shorts sampled at 8 kHz. + To account for difference in the transmit and receive sample clock frequencies, the number of demod_in[] samples is time varying. It is the responsibility of the caller to pass the correct number of @@ -235,8 +266,10 @@ int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) { COMP rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME]; int bits_per_codec_frame, bytes_per_codec_frame, bits_per_fdmdv_frame; int reliable_sync_bit, i, j, bit, byte, nin_prev, nout; - int recd_codeword, codeword1; + int recd_codeword, codeword1, data_flag_index, n_ascii, valid; struct FDMDV_STATS fdmdv_stats; + short abit[1]; + char ascii_out; bits_per_codec_frame = codec2_bits_per_frame(f->codec2); bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; @@ -288,6 +321,24 @@ int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) { } } + // extract txt msg data bit ------------------------------------------------------------ + + data_flag_index = codec2_get_spare_bit_index(f->codec2); + assert(data_flag_index != -1); // not supported for all rates + + abit[0] = f->codec_bits[data_flag_index]; + + n_ascii = varicode_decode(&f->varicode_dec_states, &ascii_out, abit, 1, 1); + assert((n_ascii == 0) || (n_asacii == 1)); + if (n_ascii && (f->freedv_put_next_rx_char != NULL)) { + (*f->freedv_put_next_rx_char)(f->callback_state, ascii_out); + } + + // reconstruct missing bit we steal for data bit and decode speech + + valid = codec2_rebuild_spare_bit(f->codec2, f->codec_bits); + assert(valid != -1); + // pack bits, MSB received first bit = 7; @@ -325,34 +376,3 @@ int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) { return nout; } -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_tx_text - AUTHOR......: David Rowe - DATE CREATED: 3 August 2014 - - Attempt to transmit an ASCII character. Will return non-zero if - character was accepted, zero if the (single character) buffer is - full. - -\*---------------------------------------------------------------------------*/ - -int freedv_tx_text(struct freedv *mode, char c) { - return 0; -} - -/*---------------------------------------------------------------------------*\ - - FUNCTION....: freedv_tx_text - AUTHOR......: David Rowe - DATE CREATED: 3 August 2014 - - Attempt to receive an ASCII character. Will return non-zero if a new - character is available, zero otherwise. - -\*---------------------------------------------------------------------------*/ - -int freedv_rx_text(struct freedv *mode, char *c) { - return 0; -} - diff --git a/codec2-dev/src/freedv_api.h b/codec2-dev/src/freedv_api.h index b126c499..a79b1ee7 100644 --- a/codec2-dev/src/freedv_api.h +++ b/codec2-dev/src/freedv_api.h @@ -32,21 +32,34 @@ #define FREEDV_MODE_1600 0 #define FREEDV_NSAMPLES 320 +#include "varicode.h" struct freedv { - int mode; - void *codec2; - struct FDMDV *fdmdv; - unsigned char *packed_codec_bits; - int *codec_bits; - int *tx_bits; - int *fdmdv_bits; - int *rx_bits; - int tx_sync_bit; - float snr_thresh; - int nin; -}; + int mode; + void *codec2; + struct FDMDV *fdmdv; + unsigned char *packed_codec_bits; + int *codec_bits; + int *tx_bits; + int *fdmdv_bits; + int *rx_bits; + int tx_sync_bit; + float snr_thresh; + int nin; + struct VARICODE_DEC varicode_dec_states; + short tx_varicode_bits[VARICODE_MAX_BITS]; + int nvaricode_bits; + int varicode_bit_index; + + /* user defined function ptrs to produce and consume ASCII + characters using aux txt channel */ + + char (*freedv_get_next_tx_char)(void *callback_state); + void (*freedv_put_next_rx_char)(void *callback_state, char c); + void *callback_state; + +}; struct freedv *freedv_open(int mode); void freedv_close(struct freedv *freedv); @@ -54,5 +67,4 @@ void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]); int freedv_nin(struct freedv *f); int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]); - #endif diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c index 8208f8f4..aab32424 100644 --- a/codec2-dev/src/freedv_rx.c +++ b/codec2-dev/src/freedv_rx.c @@ -35,6 +35,10 @@ #include "freedv_api.h" +void my_put_next_rx_char(void *callback_state, char c) { + fprintf(stderr, "%c", c); +} + int main(int argc, char *argv[]) { FILE *fin, *fout; short speech_out[FREEDV_NSAMPLES]; @@ -65,6 +69,8 @@ int main(int argc, char *argv[]) { freedv = freedv_open(FREEDV_MODE_1600); assert(freedv != NULL); + freedv->freedv_put_next_rx_char = &my_put_next_rx_char; + /* Note we need to work out how many samples demod needs on each call (nin). This is used to adjust for differences in the tx and rx sample clock frequencies. Note also the number of output @@ -75,6 +81,12 @@ int main(int argc, char *argv[]) { nout = freedv_rx(freedv, speech_out, demod_in); fwrite(speech_out, sizeof(short), nout, fout); nin = freedv_nin(freedv); + + /* if this is in a pipeline, we probably don't want the usual + buffering to occur */ + + if (fout == stdout) fflush(stdout); + if (fin == stdin) fflush(stdin); } freedv_close(freedv); diff --git a/codec2-dev/src/freedv_tx.c b/codec2-dev/src/freedv_tx.c index 255d5c76..ac0cdca8 100644 --- a/codec2-dev/src/freedv_tx.c +++ b/codec2-dev/src/freedv_tx.c @@ -33,11 +33,28 @@ #include "freedv_api.h" +struct my_callback_state { + char tx_str[80]; + char *ptx_str; +}; + +char my_get_next_tx_char(void *callback_state) { + struct my_callback_state* pstate = (struct my_callback_state*)callback_state; + char c = *pstate->ptx_str++; + + if (*pstate->ptx_str == 0) { + pstate->ptx_str = pstate->tx_str; + } + + return c; +} + int main(int argc, char *argv[]) { - FILE *fin, *fout; - short speech_in[FREEDV_NSAMPLES]; - short mod_out[FREEDV_NSAMPLES]; - struct freedv *freedv; + FILE *fin, *fout; + short speech_in[FREEDV_NSAMPLES]; + short mod_out[FREEDV_NSAMPLES]; + struct freedv *freedv; + struct my_callback_state my_cb_state; if (argc < 3) { printf("usage: %s InputRawSpeechFile OutputModemRawFile\n", argv[0]); @@ -62,9 +79,24 @@ int main(int argc, char *argv[]) { freedv = freedv_open(FREEDV_MODE_1600); assert(freedv != NULL); + /* set up callback for txt msg chars */ + + sprintf(my_cb_state.tx_str, "cq cq cq hello world\n"); + my_cb_state.ptx_str = my_cb_state.tx_str; + freedv->callback_state = (void*)&my_cb_state; + freedv->freedv_get_next_tx_char = &my_get_next_tx_char; + + /* OK main loop */ + while(fread(speech_in, sizeof(short), FREEDV_NSAMPLES, fin) == FREEDV_NSAMPLES) { freedv_tx(freedv, mod_out, speech_in); fwrite(mod_out, sizeof(short), FREEDV_NSAMPLES, fout); + + /* if this is in a pipeline, we probably don't want the usual + buffering to occur */ + + if (fout == stdout) fflush(stdout); + if (fin == stdin) fflush(stdin); } freedv_close(freedv); diff --git a/codec2-dev/src/varicode.c b/codec2-dev/src/varicode.c new file mode 100644 index 00000000..26de09a6 --- /dev/null +++ b/codec2-dev/src/varicode.c @@ -0,0 +1,479 @@ +//========================================================================== +// Name: varicode.h +// Purpose: Varicode encoded and decode functions +// Created: Nov 24, 2012 +// Authors: David Rowe +// +// To test: +// $ gcc varicode.c -o varicode -DVARICODE_UNITTEST -Wall +// $ ./varicode +// +// License: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2.1, +// 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 General Public License +// along with this program; if not, see . +// +//========================================================================== + +#include +#include +#include +#include +#include +#include "varicode.h" +#include "varicode_table.h" + + +/* + output is an unpacked array of bits of maximum size max_out. Note + unpacked arrays are a more suitable form for modulator input. + + Code 1 covers the entire ASCII char set. +*/ + +int varicode_encode1(short varicode_out[], char ascii_in[], int max_out, int n_in) { + int n_out, index, n_zeros, v_len; + unsigned short byte1, byte2, packed; + + n_out = 0; + + while(n_in && (n_out < max_out)) { + + assert((unsigned int)(*ascii_in) < 128); + + index = 2*(unsigned int)(*ascii_in); + byte1 = varicode_table1[index]; + byte2 = varicode_table1[index+1]; + packed = (byte1 << 8) + byte2; + + //printf("n_in: %d ascii_in: %c index: %d packed 0x%x\n", n_in, *ascii_in, index, packed); + ascii_in++; + + n_zeros = 0; + v_len = 0; + while ((n_zeros < 2) && (n_out < max_out) && (v_len <= VARICODE_MAX_BITS)) { + if (packed & 0x8000) { + *varicode_out = 1; + n_zeros = 0; + } + else { + *varicode_out = 0; + n_zeros++; + } + //printf("packed: 0x%x *varicode_out: %d n_zeros: %d v_len: %d\n", packed, *varicode_out, n_zeros,v_len ); + packed <<= 1; + varicode_out++; + n_out++; + v_len++; + } + assert(v_len <= VARICODE_MAX_BITS); + + n_in--; + } + + return n_out; +} + + +/* + Code 2 covers a subset, but is more efficient that Code 1 (282 + compared to 1315 bits on unittest) Unsupported characters are + replaced by spaces. We encode/decode two bits at a time. +*/ + +int varicode_encode2(short varicode_out[], char ascii_in[], int max_out, int n_in) { + int n_out, n_zeros, v_len, i; + unsigned short packed; + + n_out = 0; + + while(n_in && (n_out < max_out)) { + + packed = varicode_table2[0]; // default to space if char not found + + // see if our character exists + for(i=0; istate = 0; + dec_states->n_zeros = 0; + dec_states->v_len = 0; + dec_states->packed = 0; + dec_states->code_num = code_num; + dec_states->n_in = 0; + dec_states->in[0] = dec_states->in[1] = 0; +} + + +/* Code 1 decode function, accepts one bit at a time */ + +static int decode_one_bit(struct VARICODE_DEC *s, char *single_ascii, short varicode_in, int long_code) +{ + int found=0, i; + unsigned short byte1, byte2; + + //printf("decode_one_bit : state: %d varicode_in: %d packed: 0x%x n_zeros: %d\n", + // s->state, varicode_in, s->packed, s->n_zeros); + + if (s->state == 0) { + if (!varicode_in) + return 0; + else + s->state = 1; + } + + if (s->state == 1) { + if (varicode_in) { + s->packed |= (0x8000 >> s->v_len); + s->n_zeros = 0; + } + else { + s->n_zeros++; + } + s->v_len++; + found = 0; + + /* end of character code */ + + if (s->n_zeros == 2) { + if (s->v_len) { + /* run thru table but note with bit errors we might not actually find a match */ + + byte1 = s->packed >> 8; + //printf("looking for byte1 : 0x%x ... ", byte1); + byte2 = s->packed & 0xff; + + for(i=0; i<128; i++) { + if ((byte1 == varicode_table1[2*i]) && (byte2 == varicode_table1[2*i+1])) { + found = 1; + *single_ascii = i; + } + } + } + varicode_decode_init(s, s->code_num); + } + + /* code can run too long if we have a bit error */ + + if (s->v_len > VARICODE_MAX_BITS) + varicode_decode_init(s, s->code_num); + } + + return found; +} + + +/* Code 2 decode function, accepts two bits at a time */ + +static int decode_two_bits(struct VARICODE_DEC *s, char *single_ascii, short varicode_in1, short varicode_in2) +{ + int found=0, i; + unsigned short byte1; + + if (s->state == 0) { + if (!(varicode_in1 || varicode_in2)) + return 0; + else + s->state = 1; + } + + if (s->state == 1) { + if (varicode_in1) + s->packed |= (0x8000 >> s->v_len); + if (varicode_in2) + s->packed |= (0x4000 >> s->v_len); + if (varicode_in1 || varicode_in2) + s->n_zeros = 0; + else + s->n_zeros+=2; + + s->v_len+=2; + + found = 0; + + /* end of character code */ + + if (s->n_zeros == 2) { + if (s->v_len) { + /* run thru table but note with bit errors we might not actually find a match */ + + byte1 = s->packed >> 8; + //printf("looking for byte1 : 0x%x ... ", byte1); + for(i=0; icode_num); + } + + /* code can run too long if we have a bit error */ + + if (s->v_len > VARICODE_MAX_BITS) + varicode_decode_init(s, s->code_num); + } + + return found; +} + + +int varicode_decode1(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in) { + int output, n_out; + char single_ascii = 0; + + n_out = 0; + + //printf("varicode_decode: n_in: %d\n", n_in); + + while(n_in && (n_out < max_out)) { + output = decode_one_bit(dec_states, &single_ascii, varicode_in[0], 0); + varicode_in++; + n_in--; + + if (output) { + *ascii_out++ = single_ascii; + n_out++; + } + } + + return n_out; +} + + +int varicode_decode2(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in) { + int output, n_out; + char single_ascii = 0; + + n_out = 0; + + //printf("varicode_decode2: n_in: %d varicode_in[0] %d dec_states->n_in: %d\n", n_in, varicode_in[0], dec_states->n_in); + //printf("%d ", varicode_in[0]); + while(n_in && (n_out < max_out)) { + + // keep two bit buffer so we can process two at a time + + dec_states->in[0] = dec_states->in[1]; + dec_states->in[1] = varicode_in[0]; + dec_states->n_in++; + varicode_in++; + n_in--; + + if (dec_states->n_in == 2) { + output = decode_two_bits(dec_states, &single_ascii, dec_states->in[0], dec_states->in[1]); + + dec_states->n_in = 0; + + if (output) { + //printf(" output: %d single_ascii: 0x%x %c\n", output, (int)single_ascii, single_ascii); + *ascii_out++ = single_ascii; + n_out++; + } + } + } + + return n_out; +} + + +int varicode_decode(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in) { + if (dec_states->code_num == 1) + return varicode_decode1(dec_states, ascii_out, varicode_in, max_out, n_in); + else + return varicode_decode2(dec_states, ascii_out, varicode_in, max_out, n_in); +} + + +#ifdef VARICODE_UNITTEST +void test_varicode(int code_num) { + char *ascii_in; + short *varicode; + int i, n_varicode_bits_out, n_ascii_chars_out, length, half, n_out, j, len; + char *ascii_out; + struct VARICODE_DEC dec_states; + + if (code_num == 1) { + printf("long code:\n"); + length = sizeof(varicode_table1)/2; + } + else { + printf("short code:\n"); + length = sizeof(varicode_table2)/2; + } + //length = 10; + ascii_in = (char*)malloc(length); + varicode = (short*)malloc(VARICODE_MAX_BITS*sizeof(short)*length); + ascii_out = (char*)malloc(length); + + // 1. test all Varicode codes ------------------------------------------------------------- + + if (code_num == 1) { + for(i=0; i. +// +//========================================================================== + +#ifndef __VARICODE__ +#define __VARICODE__ + +#ifdef __cplusplus +extern "C" { + +#endif + +#define VARICODE_MAX_BITS (10+2) /* max varicode bits for each ascii character */ + /* 10 bits for code plus 2 0 bits for inter-character space */ + +struct VARICODE_DEC { + int state; + int n_zeros; + int v_len; + unsigned short packed; + int code_num; + int n_in; + int in[2]; +}; + +int varicode_encode(short varicode_out[], char ascii_in[], int max_out, int n_in, int code_num); +void varicode_decode_init(struct VARICODE_DEC *dec_states, int code_num); +int varicode_decode(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/codec2-dev/src/varicode_table.h b/codec2-dev/src/varicode_table.h new file mode 100644 index 00000000..08f38fd5 --- /dev/null +++ b/codec2-dev/src/varicode_table.h @@ -0,0 +1,338 @@ +//========================================================================== +// Name: varicode_table.h +// Purpose: Varicode look up table +// Created: Nov 24, 2012 +// Authors: Clint Turner, KA7OEI, Peter Martinez, G3PLX +// +// License: +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2.1, +// 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 General Public License +// along with this program; if not, see . +// +//========================================================================== + +/* The following table defines the PKS31 varicode. There are 128 entries, +corresponding to ASCII characters 0-127 with two bytes for each entry. The bits +for the varicode are to be shifted out MSB-first for both bytes, with the first byte +in the table being the first one to be sent. + +More than one zero in sequence signifies the end of the character (i.e. +two zeroes are the intercharacter sequence, so at least two zeroes should always be +sent before the next character is sent. + +This file is constructed with information from the article "PSK31 Fundamentals" +by Peter Martinez, G3PLX by Clint Turner, KA7OEI +*/ +unsigned char const varicode_table1[256] = { + 0b10101010, + 0b11000000, // 0 NUL + 0b10110110, + 0b11000000, // 1 SOH + 0b10111011, + 0b01000000, // 2 STX + 0b11011101, + 0b11000000, // 3 ETX + 0b10111010, + 0b11000000, // 4 EOT + 0b11010111, + 0b11000000, // 5 ENQ + 0b10111011, + 0b11000000, // 6 ACK + 0b10111111, + 0b01000000, // 7 BEL + 0b10111111, + 0b11000000, // 8 BS + 0b11101111, + 0b00000000, // 9 HT + 0b11101000, + 0b00000000, // 10 LF + 0b11011011, + 0b11000000, // 11 VT + 0b10110111, + 0b01000000, // 12 FF + 0b11111000, + 0b00000000, // 13 CR + 0b11011101, + 0b01000000, // 14 SO + 0b11101010, + 0b11000000, // 15 SI + 0b10111101, + 0b11000000, // 16 DLE + 0b10111101, + 0b01000000, // 17 DC1 + 0b11101011, + 0b01000000, // 18 DC2 + 0b11101011, + 0b11000000, // 19 DC3 + 0b11010110, + 0b11000000, // 20 DC4 + 0b11011010, + 0b11000000, // 21 NAK + 0b11011011, + 0b01000000, // 22 SYN + 0b11010101, + 0b11000000, // 23 ETB + 0b11011110, + 0b11000000, // 24 CAN + 0b11011111, + 0b01000000, // 25 EM + 0b11101101, + 0b11000000, // 26 SUB + 0b11010101, + 0b01000000, // 27 ESC + 0b11010111, + 0b01000000, // 28 FS + 0b11101110, + 0b11000000, // 29 GS + 0b10111110, + 0b11000000, // 30 RS + 0b11011111, + 0b11000000, // 31 US + 0b10000000, + 0b00000000, // 32 SP + 0b11111111, + 0b10000000, // 33 ! + 0b10101111, + 0b10000000, // 34 " + 0b11111010, + 0b10000000, // 35 # + 0b11101101, + 0b10000000, // 36 $ + 0b10110101, + 0b01000000, // 37 % + 0b10101110, + 0b11000000, // 38 & + 0b10111111, + 0b10000000, // 39 ' + 0b11111011, + 0b00000000, // 40 ( + 0b11110111, + 0b00000000, // 41 ) + 0b10110111, + 0b10000000, // 42 * + 0b11101111, + 0b10000000, // 43 + + 0b11101010, + 0b00000000, // 44 , + 0b11010100, + 0b00000000, // 45 - + 0b10101110, + 0b00000000, // 46 . + 0b11010111, + 0b10000000, // 47 / + 0b10110111, + 0b00000000, // 48 0 + 0b10111101, + 0b00000000, // 49 1 + 0b11101101, + 0b00000000, // 50 2 + 0b11111111, + 0b00000000, // 51 3 + 0b10111011, + 0b10000000, // 52 4 + 0b10101101, + 0b10000000, // 53 5 + 0b10110101, + 0b10000000, // 54 6 + 0b11010110, + 0b10000000, // 55 7 + 0b11010101, + 0b10000000, // 56 8 + 0b11011011, + 0b10000000, // 57 9 + 0b11110101, + 0b00000000, // 58 : + 0b11011110, + 0b10000000, // 59 ; + 0b11110110, + 0b10000000, // 60 < + 0b10101010, + 0b00000000, // 61 = + 0b11101011, + 0b10000000, // 62 > + 0b10101011, + 0b11000000, // 63 ? + 0b10101111, + 0b01000000, // 64 @ + 0b11111010, + 0b00000000, // 65 A + 0b11101011, + 0b00000000, // 66 B + 0b10101101, + 0b00000000, // 67 C + 0b10110101, + 0b00000000, // 68 D + 0b11101110, + 0b00000000, // 69 E + 0b11011011, + 0b00000000, // 70 F + 0b11111101, + 0b00000000, // 71 G + 0b10101010, + 0b10000000, // 72 H + 0b11111110, + 0b00000000, // 73 I + 0b11111110, + 0b10000000, // 74 J + 0b10111110, + 0b10000000, // 75 K + 0b11010111, + 0b00000000, // 76 L + 0b10111011, + 0b00000000, // 77 M + 0b11011101, + 0b00000000, // 78 N + 0b10101011, + 0b00000000, // 79 O + 0b11010101, + 0b00000000, // 80 P + 0b11101110, + 0b10000000, // 81 Q + 0b10101111, + 0b00000000, // 82 R + 0b11011110, + 0b00000000, // 83 S + 0b11011010, + 0b00000000, // 84 T + 0b10101011, + 0b10000000, // 85 U + 0b11011010, + 0b10000000, // 86 V + 0b10101110, + 0b10000000, // 87 W + 0b10111010, + 0b10000000, // 88 X + 0b10111101, + 0b10000000, // 89 Y + 0b10101011, + 0b01000000, // 90 Z + 0b11111011, + 0b10000000, // 91 [ + 0b11110111, + 0b10000000, // 92 "\" + 0b11111101, + 0b10000000, // 93 ] + 0b10101111, + 0b11000000, // 94 ^ + 0b10110110, + 0b10000000, // 95 _ (underline) + 0b10110111, + 0b11000000, // 96 ` + 0b10110000, + 0b00000000, // 97 a + 0b10111110, + 0b00000000, // 98 b + 0b10111100, + 0b00000000, // 99 c + 0b10110100, + 0b00000000, // 100 d + 0b11000000, + 0b00000000, // 101 e + 0b11110100, + 0b00000000, // 102 f + 0b10110110, + 0b00000000, // 103 g + 0b10101100, + 0b00000000, // 104 h + 0b11010000, + 0b00000000, // 105 i + 0b11110101, + 0b10000000, // 106 j + 0b10111111, + 0b00000000, // 107 k + 0b11011000, + 0b00000000, // 108 l + 0b11101100, + 0b00000000, // 109 m + 0b11110000, + 0b00000000, // 110 n + 0b11100000, + 0b00000000, // 111 o + 0b11111100, + 0b00000000, // 112 p + 0b11011111, + 0b10000000, // 113 q + 0b10101000, + 0b00000000, // 114 r + 0b10111000, + 0b00000000, // 115 s + 0b10100000, + 0b00000000, // 116 t + 0b11011100, + 0b00000000, // 117 u + 0b11110110, + 0b00000000, // 118 v + 0b11010110, + 0b00000000, // 119 w + 0b11011111, + 0b00000000, // 120 x + 0b10111010, + 0b00000000, // 121 y + 0b11101010, + 0b10000000, // 122 z + 0b10101101, + 0b11000000, // 123 { + 0b11011101, + 0b10000000, // 124 | + 0b10101101, + 0b01000000, // 125 } + 0b10110101, + 0b11000000, // 126 ~ + 0b11101101, + 0b01000000, // 127 (del) +}; + +// This code was used on FDMDV version 1, and is more compact that Code 1, but only covers a subset +// of the ASCII cahacter set + +char const varicode_table2[] = { + + ' ' ,0b11000000, + 13 ,0b01000000, // CR, end of message + '=' ,0b10000000, + '1' ,0b11110000, + '2' ,0b01110000, + '3' ,0b10110000, + '4' ,0b11010000, + '5' ,0b01010000, + '6' ,0b10010000, + '7' ,0b11100000, + '8' ,0b01100000, + '9' ,0b10100000, + 'a' ,0b11111100, + 'b' ,0b01111100, + 'c' ,0b10111100, + 'd' ,0b11011100, + 'e' ,0b01011100, + 'f' ,0b10011100, + 'g' ,0b11101100, + 'h' ,0b01101100, + 'i' ,0b10101100, + 'j' ,0b11110100, + 'k' ,0b01110100, + 'l' ,0b10110100, + 'm' ,0b11010100, + 'n' ,0b01010100, + 'o' ,0b10010100, + 'p' ,0b11100100, + 'q' ,0b01100100, + 'r' ,0b10100100, + 's' ,0b11111000, + 't' ,0b01111000, + 'u' ,0b10111000, + 'v' ,0b11011000, + 'w' ,0b01011000, + 'x' ,0b10011000, + 'y' ,0b11101000, + 'z' ,0b01101000, + '0' ,0b10101000 +}; + -- 2.25.1