//========================================================================== // 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 "varicode.h" #include #include #include #include #include #include "debug_alloc.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; char c; n_out = 0; while (n_in && (n_out < max_out)) { c = *ascii_in; if ((unsigned int)c >= 128) { c = ' '; } index = 2 * (unsigned int)(c); assert(index <= 254); 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; i < sizeof(varicode_table2); i += 2) { if (varicode_table2[i] == *ascii_in) packed = (unsigned short)varicode_table2[i + 1] << 8; } // 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[0] = 1; else varicode_out[0] = 0; if (packed & 0x4000) varicode_out[1] = 1; else varicode_out[1] = 0; if (packed & 0xc000) n_zeros = 0; else n_zeros += 2; // printf("packed: 0x%x *varicode_out: %d n_zeros: %d v_len: %d\n", // packed, *varicode_out, n_zeros,v_len ); packed <<= 2; varicode_out += 2; n_out += 2; v_len += 2; } assert(v_len <= VARICODE_MAX_BITS); n_in--; } assert((n_out % 2) == 0); /* outputs two bits at a time */ return n_out; } /* Code 3 simply allows the modem to pass incoming/outgoing bits to/from higher levels in the code. */ int varicode_encode3(short varicode_out[], char ascii_in[], int max_out, int n_in) { // We only support one bit at a time. assert(max_out >= 1 && n_in == 1); varicode_out[0] = ascii_in[0] != 0; return 1; } int varicode_encode(short varicode_out[], char ascii_in[], int max_out, int n_in, int code_num) { assert((code_num == 1) || (code_num == 2) || (code_num == 3)); if (code_num == 1) return varicode_encode1(varicode_out, ascii_in, max_out, n_in); else if (code_num == 2) return varicode_encode2(varicode_out, ascii_in, max_out, n_in); else return varicode_encode3(varicode_out, ascii_in, max_out, n_in); } void varicode_decode_init(struct VARICODE_DEC *dec_states, int code_num) { assert((code_num == 1) || (code_num == 2) || (code_num == 3)); dec_states->state = 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; } void varicode_set_code_num(struct VARICODE_DEC *dec_states, int code_num) { assert((code_num == 1) || (code_num == 2) || (code_num == 3)); dec_states->code_num = code_num; } /* 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; i < sizeof(varicode_table2); i += 2) { // printf("byte1: 0x%x 0x%x\n", byte1, (unsigned // char)varicode_table2[i+1]); if (byte1 == (unsigned char)varicode_table2[i + 1]) { found = 1; *single_ascii = varicode_table2[i]; // printf("found: %d i=%d char=%c ", found, i, *single_ascii); } } } 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; } 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_decode3(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in) { // We only handle one bit at a time. assert(max_out == 1 && n_in == 1); ascii_out[0] = varicode_in[0] != 0; return 1; } 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 if (dec_states->code_num == 2) return varicode_decode2(dec_states, ascii_out, varicode_in, max_out, n_in); else return varicode_decode3(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 < length; i++) ascii_in[i] = (char)i; } else { for (i = 0; i < length; i++) ascii_in[i] = varicode_table2[2 * i]; } // printf(" ascii_in: %s\n", ascii_in); n_varicode_bits_out = varicode_encode( varicode, ascii_in, VARICODE_MAX_BITS * length, length, code_num); printf(" n_varicode_bits_out: %d\n", n_varicode_bits_out); // for(i=0; i