Commit 8cc26734 authored by Anders Blomdell's avatar Anders Blomdell
Browse files

Changed encoding/decoding of packed32 type to be big endian.

Testcase for some of the encoding/decoding functions.
parent 366de880
......@@ -2,7 +2,7 @@
# Use LLVM clang if it's found.
CC = $(shell hash clang 2>/dev/null && echo clang || echo gcc)
CFLAGS = -g -Wall -Werror -I. -Itest
CFLAGS = -g -Wall -Werror -O3 -I. -Itest
LDFLAGS = -L.
LDLIBS_TEST = -lcunit -llabcomm
......@@ -10,6 +10,7 @@ OBJS= labcomm.o labcomm_dynamic_buffer_writer.o labcomm_fd_reader_writer.o labco
LABCOMMC_PATH=../../compiler
LABCOMMC_JAR=$(LABCOMMC_PATH)/labComm.jar
TESTS=test_labcomm_private test_labcomm test_labcomm_errors
TEST_DIR=test
TESTDATA_DIR=$(TEST_DIR)/testdata
TEST_GEN_DIR=$(TESTDATA_DIR)/gen
......@@ -51,15 +52,15 @@ $(CREATED_DIRS):
mkdir -p $@
## NB! the tests need CUnit to be installed
run-test: $(TEST_DIR)/test_labcomm $(TEST_DIR)/test_labcomm_errors \
| $(TEST_DIR)
test/test_labcomm
test/test_labcomm_errors
run-test: $(TESTS:%=run-test-%)
run-test-%: $(TEST_DIR)/% | $(TEST_DIR)
$<
$(TEST_DIR)/%.o: $(TEST_DIR)/%.c
$(CC) $(CFLAGS) -o $@ -c $<
$(TEST_DIR)/%: $(TEST_DIR)/%.o | liblabcomm.a
$(TEST_DIR)/%: $(TEST_DIR)/%.o liblabcomm.a
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(LDLIBS_TEST)
$(TEST_GEN_DIR)/%.c $(TEST_GEN_DIR)/%.h: $(TESTDATA_DIR)/%.lc \
......@@ -88,3 +89,4 @@ distclean: clean
# Extra dependencies
$(TEST_DIR)/test_labcomm: $(TEST_GEN_DIR)/test_sample.o
$(TEST_DIR)/test_labcomm_private.o: labcomm_private.h
......@@ -3,10 +3,6 @@
#include "labcomm.h"
extern int labcomm_dynamic_buffer_reader(
labcomm_reader_t *reader,
labcomm_reader_action_t action);
extern int labcomm_dynamic_buffer_writer(
labcomm_writer_t *writer,
labcomm_writer_action_t action,
......
......@@ -8,6 +8,7 @@
#include <stdio.h>
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "labcomm.h"
......@@ -117,31 +118,52 @@ LABCOMM_DECODE(long, long long)
LABCOMM_DECODE(float, float)
LABCOMM_DECODE(double, double)
/*
* Unpack a 32 bit unsigned number from a sequence bytes, where the
* first byte is prefixed with a variable length bit pattern that
* indicates the number of bytes used for encoding. The encoding
* is inspired by the UTF-8 encoding.
*
* 0b0 - 1 byte (0x00000000 - 0x0000007f)
* 0b10 - 2 bytes (0x00000080 - 0x00003fff)
* 0b110 - 3 bytes (0x00004000 - 0x001fffff)
* 0b1110 - 4 bytes (0x00200000 - 0x0fffffff)
* 0b11110 - 5 bytes (0x10000000 - 0xffffffff) [4 bits unused]
*/
static inline unsigned int labcomm_unpack32(labcomm_reader_t *r)
{
unsigned int res=0;
unsigned char i=0;
unsigned char cont=1;
do {
unsigned int result = 0;
int n, i;
unsigned char tag;
if (r->pos >= r->count) {
r->read(r, labcomm_reader_continue);
}
#ifdef IDIOTDEBUG
{
int k;
for(k=0; k<=r->pos; k++) printf("%2x\n", r->data[k]);
tag = r->data[r->pos];
r->pos++;
if (tag < 0x80) {
n = 1;
result = tag;
} else if (tag < 0xc0) {
n = 2;
result = tag & 0x3f;
} else if (tag < 0xe0) {
n = 3;
result = tag & 0x1f;
} else if (tag < 0xf0) {
n = 4;
result = tag & 0x0f;
} else {
n = 5;
}
#endif
unsigned char c = r->data[r->pos];
res |= (c & 0x7f) << 7*i;
cont = c & 0x80;
#ifdef IDIOTDEBUG
printf("unpack32: %x (%x, %d, %d)\n", res, c, i, cont);
#endif
i++;
for (i = 1 ; i < n ; i++) {
if (r->pos >= r->count) {
r->read(r, labcomm_reader_continue);
}
result = (result << 8) | r->data[r->pos];
r->pos++;
} while(cont);
return res;
}
return result;
}
static inline unsigned int labcomm_decode_packed32(labcomm_decoder_t *d)
......@@ -229,13 +251,14 @@ void labcomm_internal_encode(
labcomm_signature_t *signature,
void *value);
/* Should these really be visible? */
void labcomm_encoder_start(struct labcomm_encoder *e,
labcomm_signature_t *s) ;
void labcomm_encoder_start(
labcomm_encoder_t *encoder,
labcomm_signature_t *signature);
//HERE BE DRAGONS: is the signature_t* needed here?
void labcomm_encoder_end(struct labcomm_encoder *e,
labcomm_signature_t *s) ;
void labcomm_encoder_end(
labcomm_encoder_t *encoder,
labcomm_signature_t *signature);
......@@ -284,28 +307,51 @@ LABCOMM_ENCODE(float, float)
LABCOMM_ENCODE(double, double)
/*
* Pack the 32 bit number data as a sequence of 7 bit chunks, represented in bytes
* with the high bit meaning that more data is to come.
* Pack the 32 bit unsigned number data as a sequence bytes, where the
* first byte is prefixed with a variable length bit pattern that
* indicates the number of bytes used for encoding. The encoding
* is inspired by the UTF-8 encoding.
*
* The chunks are sent "little endian": each 7 bit chunk is more significant than
* the previous.
* 0b0 - 1 byte (0x00000000 - 0x0000007f)
* 0b10 - 2 bytes (0x00000080 - 0x00003fff)
* 0b110 - 3 bytes (0x00004000 - 0x001fffff)
* 0b1110 - 4 bytes (0x00200000 - 0x0fffffff)
* 0b11110 - 5 bytes (0x10000000 - 0xffffffff) [4 bits unused]
*/
static inline void labcomm_pack32(labcomm_writer_t *w, unsigned int data)
{
unsigned int tmp;
tmp = data;
while (tmp >= 0x80) {
if (w->pos >= w->count) {
w->write(w, labcomm_writer_continue);
int n;
unsigned char tag;
unsigned char tmp[4] = { (data >> 24) & 0xff,
(data >> 16) & 0xff,
(data >> 8) & 0xff,
(data ) & 0xff };
if (data < 0x80) {
n = 1;
tag = 0x00;
} else if (data < 0x4000) {
n = 2;
tag = 0x80;
} else if (data < 0x200000) {
n = 3;
tag = 0xc0;
} else if (data < 0x10000000) {
n = 4;
tag = 0xe0;
} else {
n = 5;
tag = 0xf0;
}
w->data[w->pos] = (tmp & 0x7f) | 0x80;
w->pos++;
tmp >>= 7;
if (w->pos + n - 1 >= w->count) {
w->write(w, labcomm_writer_continue, n);
}
switch (n) {
case 5: w->data[w->pos++] = tag; tag = 0;
case 4: w->data[w->pos++] = tmp[0] | tag; tag = 0;
case 3: w->data[w->pos++] = tmp[1] | tag; tag = 0;
case 2: w->data[w->pos++] = tmp[2] | tag; tag = 0;
case 1: w->data[w->pos++] = tmp[3] | tag;
}
w->data[w->pos] = tmp;
w->pos++;
}
static inline void labcomm_encode_packed32(labcomm_encoder_t *e, unsigned int data)
......@@ -313,6 +359,7 @@ static inline void labcomm_encode_packed32(labcomm_encoder_t *e, unsigned int da
labcomm_pack32(&e->writer, data);
}
static inline void labcomm_write_string(labcomm_writer_t *w, char *s)
{
int length, i;
......
#include <stdint.h>
#include <string.h>
#include "labcomm_private.h"
int test_write(struct labcomm_writer *w, labcomm_writer_action_t a, ...)
{
fprintf(stderr, "test_write should not be called\n");
exit(1);
}
int test_read(struct labcomm_reader *r, labcomm_reader_action_t a)
{
fprintf(stderr, "test_read should not be called\n");
exit(1);
}
static unsigned char buffer[128];
static labcomm_encoder_t encoder = {
.context = NULL,
.writer = {
.context = NULL,
.data = buffer,
.data_size = sizeof(buffer),
.count = sizeof(buffer),
.pos = 0,
.error = 0,
.write = test_write,
.ioctl = NULL,
.on_error = NULL,
},
.do_register = NULL,
.do_encode = NULL,
.on_error = NULL,
};
static labcomm_decoder_t decoder = {
.context = NULL,
.reader = {
.context = NULL,
.data = buffer,
.data_size = sizeof(buffer),
.count = sizeof(buffer),
.pos = 0,
// .error = 0,
.read = test_read,
.ioctl = NULL,
.on_error = NULL,
},
.do_register = NULL,
// .do_decode = NULL,
.on_error = NULL,
};
typedef unsigned int packed32;
typedef unsigned char boolean;
#define TEST_WRITE_READ(type, format, value, expect_count, expect_bytes) \
{ \
type decoded; \
encoder.writer.pos = 0; \
labcomm_encode_##type(&encoder, value); \
writer_assert(#type, __LINE__, expect_count, (uint8_t*)expect_bytes); \
decoder.reader.pos = 0; \
decoded = labcomm_decode_##type(&decoder); \
if (decoded != value) { \
fprintf(stderr, "Decode error" format " != " format " @%s:%d \n", value, decoded, \
__FILE__, __LINE__); \
exit(1); \
} \
}
static void writer_assert(char *type,
int line,
int count,
uint8_t *bytes)
{
if (encoder.writer.pos != count) {
fprintf(stderr,
"Wrong number of bytes written for '%s' (%d != %d) @%s:%d\n",
type, encoder.writer.pos, count, __FILE__, line);
exit(1);
}
if (memcmp(encoder.writer.data, bytes, count) != 0) {
int i;
fprintf(stderr, "Wrong bytes written for '%s' ( ", type);
for (i = 0 ; i < count ; i++) {
fprintf(stderr, "%2.2x ", encoder.writer.data[i]);
}
fprintf(stderr, "!= ");
for (i = 0 ; i < count ; i++) {
fprintf(stderr, "%2.2x ", bytes[i]);
}
fprintf(stderr, ") @%s:%d\n", __FILE__, line);
exit(1);
}
}
int main(void)
{
TEST_WRITE_READ(packed32, "%d", 0x0, 1, "\x00");
TEST_WRITE_READ(packed32, "%d", 0x7f, 1, "\x7f");
TEST_WRITE_READ(packed32, "%d", 0x80, 2, "\x80\x80");
TEST_WRITE_READ(packed32, "%d", 0x3fff, 2, "\xbf\xff");
TEST_WRITE_READ(packed32, "%d", 0x4000, 3, "\xc0\x40\x00");
TEST_WRITE_READ(packed32, "%d", 0x1fffff, 3, "\xdf\xff\xff");
TEST_WRITE_READ(packed32, "%d", 0x200000, 4, "\xe0\x20\x00\x00");
TEST_WRITE_READ(packed32, "%d", 0xfffffff, 4, "\xef\xff\xff\xff");
TEST_WRITE_READ(packed32, "%d", 0x10000000, 5, "\xf0\x10\x00\x00\x00");
TEST_WRITE_READ(packed32, "%d", 0xffffffff, 5, "\xf0\xff\xff\xff\xff");
TEST_WRITE_READ(boolean, "%d", 0, 1, "\00");
TEST_WRITE_READ(short, "%d", 0, 2, "\x00\x00");
TEST_WRITE_READ(short, "%d", 0x7fff, 2, "\x7f\xff");
TEST_WRITE_READ(short, "%d", -1, 2, "\xff\xff");
TEST_WRITE_READ(int, "%d", 0, 4, "\x00\x00\x00\x00");
TEST_WRITE_READ(int, "%d", 0x7fffffff, 4, "\x7f\xff\xff\xff");
TEST_WRITE_READ(int, "%d", -1, 4, "\xff\xff\xff\xff");
TEST_WRITE_READ(float, "%f", 0.0, 4, "\x00\x00\x00\x00");
TEST_WRITE_READ(float, "%f", 1.0, 4, "\x3f\x80\x00\x00");
TEST_WRITE_READ(float, "%f", 2.0, 4, "\x40\x00\x00\x00");
TEST_WRITE_READ(float, "%f", 0.5, 4, "\x3f\x00\x00\x00");
TEST_WRITE_READ(float, "%f", 0.25, 4, "\x3e\x80\x00\x00");
TEST_WRITE_READ(float, "%f", -0.0, 4, "\x80\x00\x00\x00");
TEST_WRITE_READ(float, "%f", -1.0, 4, "\xbf\x80\x00\x00");
TEST_WRITE_READ(float, "%f", -2.0, 4, "\xc0\x00\x00\x00");
TEST_WRITE_READ(float, "%f", -0.5, 4, "\xbf\x00\x00\x00");
TEST_WRITE_READ(float, "%f", -0.25, 4, "\xbe\x80\x00\x00");
TEST_WRITE_READ(double, "%f", 0.0, 8, "\x00\x00\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", 1.0, 8, "\x3f\xf0\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", 2.0, 8, "\x40\x00\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", 0.5, 8, "\x3f\xe0\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", 0.25, 8, "\x3f\xd0\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", -0.0, 8, "\x80\x00\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", -1.0, 8, "\xbf\xf0\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", -2.0, 8, "\xc0\x00\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", -0.5, 8, "\xbf\xe0\x00\x00\x00\x00\x00\x00");
TEST_WRITE_READ(double, "%f", -0.25, 8, "\xbf\xd0\x00\x00\x00\x00\x00\x00");
fprintf(stderr, "%s succeded\n", __FILE__);
return 0;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment