//==========================================================================
// 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