diff --git a/compiler/C_CodeGen.jrag b/compiler/C_CodeGen.jrag index f79bbfce3698346a3c38fb50cb50f85b1292b1b2..c352ce81e2aba3923ebbd538c8ad6988cf07ecb4 100644 --- a/compiler/C_CodeGen.jrag +++ b/compiler/C_CodeGen.jrag @@ -641,19 +641,9 @@ aspect C_Encoder { env.println(")"); env.println("{"); env.indent(); - env.println("labcomm_encoder_start(e, &labcomm_signature_" + - env.prefix + getName() + ");"); - env.println("labcomm_encode_type_index(e, &labcomm_signature_" + - env.prefix + getName() + ");"); - env.println("{"); - env.indent(); getType().C_emitEncoder(env); env.unindent(); env.println("}"); - env.println("labcomm_encoder_end(e, &labcomm_signature_" + - env.prefix + getName() + ");"); - env.unindent(); - env.println("}"); // Typesafe encode wrapper env.println("void labcomm_encode_" + env.prefix + getName() + "("); @@ -664,7 +654,9 @@ aspect C_Encoder { env.println("{"); env.indent(); env.println("labcomm_internal_encode(e, &labcomm_signature_" + - env.prefix + getName() + ", v);"); + env.prefix + getName() + + ", (labcomm_encode_typecast_t)encode_" + getName() + + ", v);"); env.unindent(); env.println("}"); } diff --git a/lib/c/Makefile b/lib/c/Makefile index f201fa66a5421b35325bc66f1c86984d6a71b822..4f578ee40f92fdc8a3694737b3cbac11ceb5edc8 100644 --- a/lib/c/Makefile +++ b/lib/c/Makefile @@ -10,7 +10,8 @@ OBJS= labcomm.o labcomm_dynamic_buffer_writer.o labcomm_fd_reader.o labcomm_fd_w LABCOMMC_PATH=../../compiler LABCOMMC_JAR=$(LABCOMMC_PATH)/labComm.jar -TESTS=test_labcomm_basic_type_encoding test_labcomm test_labcomm_errors +TESTS=test_labcomm_basic_type_encoding test_labcomm_generated_encoding test_labcomm +#FIXME: test_labcomm_errors TEST_DIR=test TESTDATA_DIR=$(TEST_DIR)/testdata TEST_GEN_DIR=$(TESTDATA_DIR)/gen @@ -63,6 +64,15 @@ $(TEST_DIR)/%.o: $(TEST_DIR)/%.c $(TEST_DIR)/%: $(TEST_DIR)/%.o liblabcomm.a $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(LDLIBS_TEST) +$(TEST_DIR)/gen: + mkdir -p $@ + +$(TEST_DIR)/gen/%.c $(TEST_DIR)/gen/%.h: $(TEST_DIR)/%.lc | $(TEST_DIR)/gen + java -jar $(LABCOMMC_JAR) \ + --c=$(TEST_DIR)/gen/$*.c \ + --h=$(TEST_DIR)/gen/$*.h \ + $< + $(TEST_GEN_DIR)/%.c $(TEST_GEN_DIR)/%.h: $(TESTDATA_DIR)/%.lc \ $(LABCOMMC_JAR) | $(TEST_GEN_DIR) java -jar $(LABCOMMC_JAR) \ @@ -82,11 +92,14 @@ clean: $(RM) test/*.gch $(RM) test/test_labcomm_errors $(RM) test/testdata/gen/*.[cho] + $(RM) test/gen/*.[cho] $(RM) $(TEST_DIR)/test_labcomm distclean: clean $(RM) liblabcomm.a # Extra dependencies +$(TEST_DIR)/test_labcomm_basic_type_encoding.o: labcomm_private.h +$(TEST_DIR)/test_labcomm_generated_encoding.o : $(TEST_DIR)/gen/generated_encoding.h +$(TEST_DIR)/test_labcomm_generated_encoding : $(TEST_DIR)/gen/generated_encoding.o $(TEST_DIR)/test_labcomm: $(TEST_GEN_DIR)/test_sample.o -$(TEST_DIR)/test_labcomm_private.o: labcomm_private.h diff --git a/lib/c/labcomm.c b/lib/c/labcomm.c index bdcd204edf7e189ecea889664ce80ef66e1c1d9a..c571f168510254adbeef259e749b9bc0c97a021c 100644 --- a/lib/c/labcomm.c +++ b/lib/c/labcomm.c @@ -1,3 +1,23 @@ +/* + labcomm.c -- runtime for handling encoding and decoding of + labcomm samples. + + Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + 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 <http://www.gnu.org/licenses/>. +*/ + #ifdef LABCOMM_COMPAT #include LABCOMM_COMPAT #else @@ -26,9 +46,18 @@ typedef struct labcomm_sample_entry { void *context; } labcomm_sample_entry_t; +#ifndef LABCOMM_ENCODER_LINEAR_SEARCH +extern labcomm_signature_t labcomm_first_signature; +extern labcomm_signature_t labcomm_last_signature; +#endif + typedef struct labcomm_encoder_context { +#ifdef LABCOMM_ENCODER_LINEAR_SEARCH labcomm_sample_entry_t *sample; int index; +#else + labcomm_sample_entry_t *by_section; +#endif } labcomm_encoder_context_t; typedef struct labcomm_decoder_context { @@ -152,7 +181,7 @@ static labcomm_sample_entry_t *get_sample_by_index( #ifdef LABCOMM_ENCODER_LINEAR_SEARCH -static int get_encoder_index( +static int get_encoder_index_by_search( labcomm_encoder_t *e, labcomm_signature_t *s) { @@ -171,14 +200,11 @@ static int get_encoder_index( #else -static int get_encoder_index( +static int get_encoder_index_by_section( labcomm_encoder_t *e, labcomm_signature_t *s) { - int result = 0; - extern labcomm_signature_t labcomm_first_signature; - extern labcomm_signature_t labcomm_last_signature; - + int result = -ENOENT; if (&labcomm_first_signature <= s && s <= &labcomm_last_signature) { //fprintf(stderr, "%d\n", (int)(s - &labcomm_start)); result = s - &labcomm_first_signature + LABCOMM_USER; @@ -187,6 +213,16 @@ static int get_encoder_index( } #endif +static int get_encoder_index( + labcomm_encoder_t *e, + labcomm_signature_t *s) +{ +#ifdef LABCOMM_ENCODER_LINEAR_SEARCH + return get_encoder_index_by_search(e, s); +#else + return get_encoder_index_by_section(e, s); +#endif +} void labcomm_encoder_start(struct labcomm_encoder *e, labcomm_signature_t *s) @@ -225,50 +261,142 @@ void labcomm_encode_signature(struct labcomm_encoder *e, e->writer.write(&e->writer, labcomm_writer_end_signature); } +#ifdef LABCOMM_ENCODER_LINEAR_SEARCH +static int encoder_add_signature_by_search(struct labcomm_encoder *e, + labcomm_signature_t *signature, + labcomm_encode_typecast_t encode) +{ + int result; + labcomm_encoder_context_t *context = e->context; + labcomm_sample_entry_t *sample; + + sample = (labcomm_sample_entry_t*)malloc(sizeof(labcomm_sample_entry_t)); + if (sample == NULL) { + result = -ENOMEM; + } else { + sample->next = context->sample; + sample->index = context->index; + sample->signature = signature; + sample->encode = encode; + context->index++; + context->sample = sample; + result = sample->index; + } + return result; +} +#endif + +#ifndef LABCOMM_ENCODER_LINEAR_SEARCH +static int encoder_add_signature_by_section(struct labcomm_encoder *e, + labcomm_signature_t *s, + labcomm_encode_typecast_t encode) +{ + int result = -ENOENT; + + if (&labcomm_first_signature <= s && s <= &labcomm_last_signature) { + /* Signature is in right linker section */ + labcomm_encoder_context_t *context = e->context; + int index = s - &labcomm_first_signature; + + if (context->by_section == NULL) { + int n = &labcomm_last_signature - &labcomm_first_signature; + context->by_section = malloc(n * sizeof(context->by_section[0])); + } + if (context->by_section == NULL) { + result = -ENOMEM; + goto out; + } + context->by_section[index].next = NULL; + context->by_section[index].index = index + LABCOMM_USER; + context->by_section[index].signature = s; + context->by_section[index].encode = encode; + result = context->by_section[index].index; + } +out: + return result; +} +#endif + +static int encoder_add_signature(struct labcomm_encoder *e, + labcomm_signature_t *signature, + labcomm_encode_typecast_t encode) +{ + int index = -ENOENT; + +#ifdef LABCOMM_ENCODER_LINEAR_SEARCH + index = encoder_add_signature_by_search(e, signature, encode); +#else + index = encoder_add_signature_by_section(e, signature, encode); +#endif + return index; +} + static void do_encoder_register(struct labcomm_encoder *e, labcomm_signature_t *signature, labcomm_encode_typecast_t encode) { if (signature->type == LABCOMM_SAMPLE) { if (get_encoder_index(e, signature) == 0) { - labcomm_encoder_context_t *context = e->context; - labcomm_sample_entry_t *sample = - (labcomm_sample_entry_t*)malloc(sizeof(labcomm_sample_entry_t)); - sample->next = context->sample; - sample->index = context->index; - sample->signature = signature; - sample->encode = encode; - context->index++; - context->sample = sample; - - struct labcomm_ioctl_register_signature ioctl_data; - int err; - - ioctl_data.index = sample->index; - ioctl_data.signature = signature; - err = labcomm_encoder_ioctl(e, LABCOMM_IOCTL_REGISTER_SIGNATURE, - &ioctl_data); - if (err != 0) { - labcomm_encode_signature(e, signature); + int index = encoder_add_signature(e, signature, encode); + + if (index > 0) { + struct labcomm_ioctl_register_signature ioctl_data; + int err; + + ioctl_data.index = index; + ioctl_data.signature = signature; + err = labcomm_encoder_ioctl(e, LABCOMM_IOCTL_REGISTER_SIGNATURE, + &ioctl_data); + if (err != 0) { + labcomm_encode_signature(e, signature); + } } } } } +static labcomm_sample_entry_t *encoder_get_sample_by_signature_address( + labcomm_encoder_t *encoder, + labcomm_signature_t *s) +{ + labcomm_sample_entry_t *result = NULL; + labcomm_encoder_context_t *context = encoder->context; + +#ifndef LABCOMM_ENCODER_LINEAR_SEARCH + if (&labcomm_first_signature <= s && s <= &labcomm_last_signature) { + result = &context->by_section[s - &labcomm_first_signature]; + } +#else + result = get_sample_by_signature_address(context->sample, s); +#endif + return result; +} + static void do_encode( labcomm_encoder_t *encoder, labcomm_signature_t *signature, + labcomm_encode_typecast_t encode, void *value) { - labcomm_encoder_context_t *context = encoder->context; labcomm_sample_entry_t *sample; - sample = get_sample_by_signature_address(context->sample, - signature); + sample = encoder_get_sample_by_signature_address(encoder, signature); + (void)sample; + + labcomm_encoder_start(encoder, signature); + labcomm_encode_type_index(encoder, signature); + encode(encoder, value); + labcomm_encoder_end(encoder, signature); +/* + labcomm_sample_entry_t *sample; + + + sample = encoder_get_sample_by_signature_address(encoder, signature); if (sample && sample->encode) { sample->encode(encoder, value); } else { encoder->on_error(LABCOMM_ERROR_ENC_NO_REG_SIGNATURE, 2, "No registration for %s.\n", signature->name); } +*/ } labcomm_encoder_t *labcomm_encoder_new( @@ -280,8 +408,12 @@ labcomm_encoder_t *labcomm_encoder_new( labcomm_encoder_context_t *context; context = malloc(sizeof(labcomm_encoder_context_t)); +#ifdef LABCOMM_ENCODER_LINEAR_SEARCH context->sample = NULL; context->index = LABCOMM_USER; +#else + context->by_section = NULL; +#endif result->context = context; result->writer.context = writer_context; result->writer.data = 0; @@ -316,11 +448,11 @@ void labcomm_internal_encoder_register( void labcomm_internal_encode( labcomm_encoder_t *e, labcomm_signature_t *signature, + labcomm_encode_typecast_t encode, void *value) { - // Will segfault if e == NULL if (e->do_encode) { - e->do_encode(e, signature, value); + e->do_encode(e, signature, encode, value); } else { e->on_error(LABCOMM_ERROR_ENC_MISSING_DO_ENCODE, 0); } @@ -329,16 +461,19 @@ void labcomm_internal_encode( void labcomm_encoder_free(labcomm_encoder_t* e) { e->writer.write(&e->writer, labcomm_writer_free); - labcomm_encoder_context_t *econtext = (labcomm_encoder_context_t *) e->context; - - labcomm_sample_entry_t *sentry = econtext->sample; - labcomm_sample_entry_t *sentry_next; - while (sentry != NULL) { - sentry_next = sentry->next; - free(sentry); - sentry = sentry_next; - } + labcomm_encoder_context_t *context = (labcomm_encoder_context_t *) e->context; +#ifdef LABCOMM_ENCODER_LINEAR_SEARCH + labcomm_sample_entry_t *entry = context->sample; + labcomm_sample_entry_t *entry_next; + while (entry != NULL) { + entry_next = entry->next; + free(entry); + entry = entry_next; + } +#else + free(context->by_section); +#endif free(e->context); free(e); } diff --git a/lib/c/labcomm_private.h b/lib/c/labcomm_private.h index 4271200ed144b5dc0e1841d797cb6685135d54f5..301f590d2835a6fc6657c7b3f85d40d9b3944977 100644 --- a/lib/c/labcomm_private.h +++ b/lib/c/labcomm_private.h @@ -215,6 +215,7 @@ typedef struct labcomm_encoder { labcomm_encode_typecast_t); void (*do_encode)(struct labcomm_encoder *encoder, labcomm_signature_t *signature, + labcomm_encode_typecast_t encode, void *value); labcomm_error_handler_callback on_error; } labcomm_encoder_t; @@ -227,19 +228,9 @@ void labcomm_internal_encoder_register( void labcomm_internal_encode( labcomm_encoder_t *encoder, labcomm_signature_t *signature, + labcomm_encode_typecast_t encode, void *value); -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( - labcomm_encoder_t *encoder, - labcomm_signature_t *signature); - - - #if __BYTE_ORDER == __LITTLE_ENDIAN #define LABCOMM_ENCODE(name, type) \ @@ -384,6 +375,4 @@ static inline void labcomm_encode_string(labcomm_encoder_t *e, labcomm_write_string(&e->writer, s); } -void labcomm_encode_type_index(labcomm_encoder_t *e, labcomm_signature_t *s); - #endif diff --git a/lib/c/test/generated_encoding.lc b/lib/c/test/generated_encoding.lc new file mode 100644 index 0000000000000000000000000000000000000000..99cc300533e1da1c3ba48a40434e296bcfd708b7 --- /dev/null +++ b/lib/c/test/generated_encoding.lc @@ -0,0 +1,5 @@ +sample void V; +sample byte B; +sample struct { + int i; +} S1; diff --git a/lib/c/test/test_labcomm_generated_encoding.c b/lib/c/test/test_labcomm_generated_encoding.c new file mode 100644 index 0000000000000000000000000000000000000000..17efb239106e1b09a8be68a3720ba5af4bbf985f --- /dev/null +++ b/lib/c/test/test_labcomm_generated_encoding.c @@ -0,0 +1,163 @@ +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include "labcomm_private.h" +#include "labcomm_private.h" +#include "test/gen/generated_encoding.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); +} + +#define IOCTL_WRITER_ASSERT_BYTES 4096 +#define IOCTL_WRITER_RESET 4097 + +static unsigned char buffer[128]; + +static int buffer_writer_ioctl( + struct labcomm_writer *w, int action, va_list arg) +{ + int result = -ENOTSUP; + switch (action) { + case IOCTL_WRITER_ASSERT_BYTES: { + int line = va_arg(arg, int); + int count = va_arg(arg, int); + int *expected = va_arg(arg, int *); + int i, mismatch; + + if (w->pos != count) { + fprintf(stderr, "Invalid length encoded %d != %d (%s:%d)\n", + w->pos, count, __FILE__, line); + mismatch = 1; + } + for (mismatch = 0, i = 0 ; i < count ; i++) { + if (expected[i] >= 0 && expected[i] != buffer[i]) { + mismatch = 1; + } + } + if (mismatch) { + fprintf(stderr, "Encoder mismatch (%s:%d)\n", + __FILE__, line); + + for (i = 0 ; i < w->pos ; i++) { + printf("%2.2x ", w->data[i]); + } + printf("\n"); + for (i = 0 ; i < count ; i++) { + if (expected[i] < 0) { + printf(".. "); + } else { + printf("%2.2x ", expected[i] ); + } + } + printf("\n"); + exit(1); + } + result = 0; + } break; + case IOCTL_WRITER_RESET: { + w->pos = 0; + result = 0; + } + } + return result; +} + +static int buffer_writer( + labcomm_writer_t *w, + labcomm_writer_action_t action, + ...) +{ + switch (action) { + case labcomm_writer_alloc: { + w->data_size = sizeof(buffer); + w->count = w->data_size; + w->data = buffer; + w->pos = 0; + w->ioctl = buffer_writer_ioctl; + } break; + case labcomm_writer_start: + case labcomm_writer_start_signature: { + } break; + case labcomm_writer_continue: + case labcomm_writer_continue_signature: { + fprintf(stderr, "Should not come here %s:%d\n", __FILE__, __LINE__); + exit(1); + } break; + case labcomm_writer_end: + case labcomm_writer_end_signature: { + } break; + case labcomm_writer_free: { + w->data = 0; + w->data_size = 0; + w->count = 0; + w->pos = 0; + } break; + } + return w->error; +} + +void dump_encoder(labcomm_encoder_t *encoder) +{ + int i; + + for (i = 0 ; i < encoder->writer.pos ; i++) { + printf("%2.2x ", encoder->writer.data[i]); + } + printf("\n"); +} + +int main(void) +{ + generated_encoding_V V; + generated_encoding_B B = 1; + + labcomm_encoder_t *encoder = labcomm_encoder_new(buffer_writer, buffer); + + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); + labcomm_encoder_register_generated_encoding_V(encoder); + { + int expected[] = { 0x02, -1, 0x01, 'V', 0x11, 0x00 }; + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES, + __LINE__, + 6, expected); + } + + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); + labcomm_encoder_register_generated_encoding_B(encoder); + { + int expected[] = { 0x02, -1, 0x01, 'B', 0x21 }; + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES, + __LINE__, + 5, expected); + } + + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); + labcomm_encode_generated_encoding_V(encoder, &V); + { + int expected[] = { -1 }; + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES, + __LINE__, + 1, expected); + } + + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_RESET); + labcomm_encode_generated_encoding_B(encoder, &B); + { + int expected[] = { -1, 1 }; + labcomm_encoder_ioctl(encoder, IOCTL_WRITER_ASSERT_BYTES, + __LINE__, + 2, expected); + } + + return 0; +} +