diff --git a/compiler/C_CodeGen.jrag b/compiler/C_CodeGen.jrag index caf57e950ccc978ea6207f9155df013d814ae2a8..1efc0a385b45b216302a9705853b255e3932bae9 100644 --- a/compiler/C_CodeGen.jrag +++ b/compiler/C_CodeGen.jrag @@ -496,7 +496,8 @@ aspect C_Decoder { } public void VariableSize.C_emitDecoderDecodeLimit(C_env env, int i) { - env.println(env.qualid + ".n_" + i + " = labcomm_decode_int(d);"); + //env.println(env.qualid + ".n_" + i + " = labcomm_decode_int(d);"); + env.println(env.qualid + ".n_" + i + " = labcomm_decode_packed32(d);"); } public void ArrayType.C_emitDecoderDecodeLimit(C_env env) { @@ -721,7 +722,8 @@ aspect C_Encoder { } public void VariableSize.C_emitEncoderEncodeLimit(C_env env, int i) { - env.println("labcomm_encode_int(e, " + env.qualid + ".n_" + i + ");"); + //env.println("labcomm_encode_int(e, " + env.qualid + ".n_" + i + ");"); + env.println("labcomm_encode_packed32(e, " + env.qualid + ".n_" + i + ");"); } public void ArrayType.C_emitEncoderEncodeLimit(C_env env) { diff --git a/compiler/Java_CodeGen.jrag b/compiler/Java_CodeGen.jrag index 40c0e1b26c42550424a5dfdf07b715b5a04b5e53..3331299b0ac6e80e8b513cffbc4dca1ec2fe5518 100644 --- a/compiler/Java_CodeGen.jrag +++ b/compiler/Java_CodeGen.jrag @@ -578,7 +578,7 @@ aspect Java_Class { } public void VariableSize.Java_emitDecoder(Java_env env) { - env.print("d.decodeInt()"); + env.print("d.decodePacked32()"); } public void StructType.Java_emitDecoder(Java_env env, String name) { diff --git a/compiler/Signature.jrag b/compiler/Signature.jrag index fb65987c267994ea994bb00c294729519ce5001f..6d5f16e8aa7881be0a61627cb74bddbc8a55a7af 100644 --- a/compiler/Signature.jrag +++ b/compiler/Signature.jrag @@ -38,11 +38,27 @@ aspect Signature { } public void addInt(int value, String comment) { - byte[] data = new byte[4]; - for (int i = 0 ; i < 4 ; i++) { - data[3 - i] = (byte)((value >> (8 * i)) & 0xff); - } - add(data, comment); + byte[] packed = new byte[5]; + +// System.out.println("addInt: "+value); + int tmp = value; + int len = 0; + + while( tmp >= 0x80 ) { + packed[len] = (byte) ((tmp & 0x7f) | 0x80 ) ; + tmp >>>= 7; + len++; + } + packed[len] = (byte) (tmp & 0x7f); +// System.out.println("packed: "+packed[len]+ "len = "+len); + + add(java.util.Arrays.copyOf(packed, len+1), comment); + +// byte[] data = new byte[4]; +// for (int i = 0 ; i < 4 ; i++) { +// data[3 - i] = (byte)((value >> (8 * i)) & 0xff); +// } +// add(data, comment); } public void addString(String value, String comment) { @@ -196,4 +212,4 @@ aspect Signature { return "_"; } -} \ No newline at end of file +} diff --git a/examples/simple/Decoder.java b/examples/simple/Decoder.java index 278c5aa8b293678ac34e6f8d99d1a5ee0322f6d0..c059df247e3822aa78f92b68c5620d3e82de275b 100644 --- a/examples/simple/Decoder.java +++ b/examples/simple/Decoder.java @@ -5,7 +5,7 @@ import java.io.InputStream; import se.lth.control.labcomm.LabCommDecoderChannel; public class Decoder - implements TwoInts.Handler, IntString.Handler + implements TwoInts.Handler, IntString.Handler, TwoArrays.Handler { LabCommDecoderChannel decoder; @@ -16,6 +16,7 @@ public class Decoder decoder = new LabCommDecoderChannel(in); TwoInts.register(decoder, this); IntString.register(decoder, this); + TwoArrays.register(decoder, this); try { System.out.println("Running decoder."); @@ -33,6 +34,18 @@ public class Decoder System.out.println("Got IntString, x="+d.x+", s="+d.s); } + public void handle_TwoArrays(TwoArrays d) throws java.io.IOException { + System.out.println("Got TwoArrays:"); + for(int i=0; i<d.fixed.length; i++) { + System.out.print(d.fixed[i]+" "); + } + System.out.println(); + for(int i=0; i<d.variable[0].length; i++) { + System.out.print(d.variable[0][i]+" "); + System.out.print(d.variable[1][i]+" "); + } + System.out.println(); + } public static void main(String[] arg) throws Exception { Decoder example = new Decoder( diff --git a/examples/simple/example_decoder.c b/examples/simple/example_decoder.c index bfe8430ab604e71a652b499dd8b80f3fe112aa59..9aa6b40ab1317820b1bc1f6233de10917b796522 100644 --- a/examples/simple/example_decoder.c +++ b/examples/simple/example_decoder.c @@ -12,6 +12,20 @@ static void handle_simple_IntString(simple_IntString *v,void *context) { printf("Got IntString. x=%d, s=%s\n", v->x, v->s); } +static void handle_simple_TwoArrays(simple_TwoArrays *d,void *context) { + printf("Got TwoArrays:"); + int i; + for(i=0; i<2; i++) { + printf("%d ",d->fixed.a[i]); + } + printf("\n"); + for(i=0; i<d->variable.n_1; i++) { + printf("%d ",d->variable.a[0+2*i]); + printf("%d ",d->variable.a[1+2*i]); + } + printf("\n"); +} + int main(int argc, char *argv[]) { int fd; struct labcomm_decoder *decoder; @@ -29,6 +43,7 @@ int main(int argc, char *argv[]) { labcomm_decoder_register_simple_TwoInts(decoder, handle_simple_TwoInts, context); labcomm_decoder_register_simple_IntString(decoder, handle_simple_IntString, context); + labcomm_decoder_register_simple_TwoArrays(decoder, handle_simple_TwoArrays, context); printf("Decoding:\n"); labcomm_decoder_run(decoder); diff --git a/examples/simple/example_encoder.c b/examples/simple/example_encoder.c index c62058833d8736bb17dd781f7997041dc903f506..70a38c8756e91945d01e6543cf3ad7636e29116f 100644 --- a/examples/simple/example_encoder.c +++ b/examples/simple/example_encoder.c @@ -15,6 +15,7 @@ int main(int argc, char *argv[]) { encoder = labcomm_encoder_new(labcomm_fd_writer, &fd); labcomm_encoder_register_simple_TwoInts(encoder); labcomm_encoder_register_simple_IntString(encoder); + labcomm_encoder_register_simple_TwoArrays(encoder); simple_IntString is; is.x = 24; is.s = "Hello, LabComm!"; @@ -26,4 +27,27 @@ int main(int argc, char *argv[]) { ti.b = 37; printf("Encoding TwoInts, a=%d, b=%d\n", ti.a, ti.b); labcomm_encode_simple_TwoInts(encoder, &ti); + + int foo[20]; + + simple_TwoArrays ta; + ta.fixed.a[0] = 17; + ta.fixed.a[1] = 42; + ta.variable.n_1 = 10; + ta.variable.a = foo; + + int k; + for(k=0; k<20; k++) { + foo[k] = k; + } + + printf("Encoding TwoArrays...\n"); + labcomm_encode_simple_TwoArrays(encoder, &ta); + + ti.a = 23; + ti.b = 47; + printf("Encoding TwoInts, a=%d, b=%d\n", ti.a, ti.b); + labcomm_encode_simple_TwoInts(encoder, &ti); + + } diff --git a/examples/simple/simple.lc b/examples/simple/simple.lc index 2da6c48ee0842a6206372d6f733745db0b332d4a..2adfb2e44714bd17a0bd2d3ce4a4b53311996081 100644 --- a/examples/simple/simple.lc +++ b/examples/simple/simple.lc @@ -12,3 +12,8 @@ sample struct { double x; double y; } TwoDoubles; + +sample struct { + int fixed[2]; + int variable[2,_]; +} TwoArrays; diff --git a/lib/c/experimental/labcomm_parser.c b/lib/c/experimental/labcomm_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..fa24f48c248505c7271dccf1317ea75be25671f2 --- /dev/null +++ b/lib/c/experimental/labcomm_parser.c @@ -0,0 +1,677 @@ +/* labcomm_parser.c: + * an example parser for labcomm signatures, illustrating how to skip samples + * based on their signature. Intended as an embryo for introducing this + * functionality into the lib to allow a channel to survive types with no + * registered handler. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define DEBUG + +#define FALSE 0 +#define TRUE 1 + +#define USER_ID_BASE 0x00000080 + +typedef enum{ + TYPE_DECL = 0x00000001, + SAMPLE_DECL = 0x00000002, + + ARRAY_DECL = 0x00000010, + STRUCT_DECL = 0x00000011, + + TYPE_BOOLEAN = 0x00000020, + TYPE_BYTE = 0x00000021, + TYPE_SHORT = 0x00000022, + TYPE_INTEGER = 0x00000023, + TYPE_LONG = 0x00000024, + TYPE_FLOAT = 0x00000025, + TYPE_DOUBLE = 0x00000026, + TYPE_STRING = 0x00000027 +} labcomm_type ; + +void error(char *s) { + fprintf(stderr, "%s", s); + fprintf(stderr, "\nexiting\n"); + exit(1); +} + +#define BUF_SIZE 1024 +#define STACK_SIZE 16 + +/* internal type: stack for the parser */ +typedef struct { + unsigned char* c; + unsigned int size; + unsigned int capacity; + unsigned int idx; + unsigned int* stack; + unsigned int top; +} buffer; + +/* aux method for reading a big endian uint32 from a char* (i.e. ntohl but for explicit char*) */ +static int unpack32(unsigned char *c, unsigned int idx) { + unsigned int b0=(c[idx]) << 3 ; + unsigned int b1=(c[idx+1]) << 2 ; + unsigned int b2=(c[idx+2]) << 1 ; + unsigned int b3=c[idx+3]; + + return b0 | b1 | b2 | b3; +} + +void dumpStack(buffer *b) { +#ifdef DEBUG + int i; + printf("=== stack: "); + for(i=0; i<STACK_SIZE; i++) { //HERE BE DRAGONS + printf("%2.2x ", b->stack[i]); + } + printf(" top==%d\n", b->top); +#endif +} + +void push(buffer *b, unsigned int e) { + b->stack[b->top]=e; + b->top=b->top-1; + dumpStack(b); +} +unsigned int pop(buffer *b) { + b->top=b->top+1; + return b->stack[b->top]; +} + +int init_buffer(buffer *b, size_t size, size_t stacksize) { + b->c = malloc(size); + b->capacity = size; + b->idx = 0; + + b->stack = calloc(stacksize, sizeof(b->stack)); + b->top = stacksize-1; + + return b->c == NULL || b->stack == NULL; +} + +int more(buffer *b) +{ + return b->idx < b->size; +} + +unsigned char get(buffer *b) { + return b->c[b->idx++]; +} + +unsigned char peek(buffer *b) { + return b->c[b->idx]; +} + +void advance(buffer *b) { + b->idx++; +} + +void advancen(buffer *b, size_t n) { + b->idx+=n; +} + +unsigned int peek32(buffer *b) { + return unpack32(b->c, b->idx); +} + +void advance32(buffer *b) { + b->idx+=4; +} + +unsigned int get32(buffer *b) { + unsigned int res = peek32(b); + advance32(b); + return res; +} + +void getStr(buffer *b, char *dest, size_t size) { + int rem = b->size - b->idx; + if( size > rem ) + size = rem; + strncpy(dest, &b->c[b->idx], size); + b->idx += size; +} + +//XXX experimental +#define MAX_SIGNATURES 10 +#define MAX_NAME_LEN 32 +#define MAX_SIG_LEN 128 +unsigned int signatures_length[MAX_SIGNATURES]; +unsigned char signatures_name[MAX_SIGNATURES][MAX_NAME_LEN]; //HERE BE DRAGONS: add range checks +unsigned char signatures[MAX_SIGNATURES][MAX_SIG_LEN]; + +unsigned int get_signature_len(unsigned int uid){ + return signatures_length[uid-USER_ID_BASE]; +} +unsigned char* get_signature_name(unsigned int uid){ + return &signatures_name[uid-USER_ID_BASE][1]; +} +unsigned char* get_signature(unsigned int uid){ + return signatures[uid-USER_ID_BASE]; +} + +void dump_signature(unsigned int uid){ + int i; + unsigned int len = get_signature_len(uid); + printf("signature for uid %x : %s (len=%d):\n", uid, get_signature_name(uid), len); + unsigned char* sig = get_signature(uid); + for(i=0; i<len; i++) { + printf("%2.2x ",sig[i]); + if( (i+1)%8==0 ) printf("\n"); + } + printf("\n"); +} + +int labcomm_sizeof(unsigned int type) +{ + switch(type) { + case TYPE_BOOLEAN : + case TYPE_BYTE : + return 1; + case TYPE_SHORT : + return 2; + case TYPE_INTEGER : + case TYPE_FLOAT : + return 4; + case TYPE_LONG : + case TYPE_DOUBLE : + return 8; + default: + printf("labcomm_sizeof(%x)\n", type); + error("labcomm_sizeof should only be called for primitive types"); + } +} + +int accept_packet(buffer *d); +int accept_type_decl(buffer *d); +int accept_sample_decl(buffer *d); +int accept_user_id(buffer *d); +int accept_string(buffer *d); +int accept_string_length(buffer *d); +int accept_char(buffer *d); +int accept_type(buffer *d); +int accept_basic_type(buffer *d); +int accept_boolean_type(buffer *d); +int accept_byte_type(buffer *d); +int accept_short_type(buffer *d); +int accept_integer_type(buffer *d); +int accept_long_type(buffer *d); +int accept_float_type(buffer *d); +int accept_long_type(buffer *d); +int accept_string_type(buffer *d); +int accept_array_decl(buffer *d); +int accept_number_of_indices(buffer *d); +int accept_indices(buffer *d); +int accept_variable_index(buffer *d); +int accept_fixed_index(buffer *d); +int accept_struct_decl(buffer *d); +int accept_number_of_fields(buffer *d); +int accept_field(buffer *d); +int accept_sample_data(buffer *d); +int accept_packed_sample_data(buffer *d); + +int read_file(FILE *f, buffer *b) { + int s = fread(b->c, sizeof(char), b->capacity, f); + b->size = s; + b->idx=0; + return s; +} + +void test_read(buffer *buf) { + int r = read_file(stdin, buf); + printf("read %d bytes:\n\n", r); + int i; + for(i=0; i<r; i++) { + printf("%x ", buf->c[i]); + if(i%8 == 7) printf("\n"); + } + printf("\n"); +} +int main() { + buffer buf; + + if( init_buffer(&buf, BUF_SIZE, STACK_SIZE) ) { + printf("failed to init buffer\n"); + exit(1); + } + test_read(&buf); + do{ + printf("trying to read another packet\n"); + } while(more(&buf) && accept_packet(&buf)); + printf("done\n"); +} + + +int accept_packet(buffer *d) { + if(accept_type_decl(d)) { + printf("*** got type decl\n"); + } else if(accept_sample_decl(d)) { + printf("*** got sample decl\n"); + } else if(accept_sample_data(d)) { + printf("*** got sample data\n"); + } else { +// error("unexpected %x, expecting packet", d->c[d->idx]); + error("packet"); + } +} +int accept_type_decl(buffer *d){ + unsigned int type = peek32(d) ; + if(type == TYPE_DECL ) { + advance32(d); + accept_user_id(d); + unsigned int uid = pop(d); + accept_string(d); + // ignore, for now. This should do something as + // char *name = (char*) pop(d); + // store or print name + // free(name) + accept_type(d); + unsigned int type = pop(d); + + //push(d, type); + return TRUE; + }else { + return FALSE; + } +} + +int accept_sample_decl(buffer *d){ + unsigned int type = peek32(d) ; + if (type == SAMPLE_DECL) { + advance32(d); + accept_user_id(d); + unsigned int nstart = d->idx; + unsigned int uid = pop(d); + accept_string(d); + unsigned int start = d->idx; + unsigned int nlen = pop(d); + accept_type(d); + unsigned int dt = pop(d); + unsigned int end = d->idx; + unsigned int len = end-start; + if(len <= MAX_SIG_LEN) { + signatures_length[uid-USER_ID_BASE] = len; + memcpy(signatures_name[uid-USER_ID_BASE], &d->c[nstart+3], nlen+1); + } else { + error("sig longer than max length (this ought to be dynamic...)"); + } + if(nlen < MAX_NAME_LEN) { // reserve space for terminating NULL + signatures_name[uid-USER_ID_BASE][nlen+1]=0; + memcpy(signatures[uid-USER_ID_BASE], &d->c[start], len); + } else { + error("sig name longer than max length (this ought to be dynamic..."); + } + printf("signature for uid %x: %s (start=%x,end=%x, nlen=%d,len=%d)\n", uid, get_signature_name(uid), start,end, nlen, len); + return TRUE; + } else { + return FALSE; + } +} + +int accept_user_id(buffer *d){ + unsigned int uid = peek32(d); + if(uid >= USER_ID_BASE) { + push(d, uid); + advance32(d); + //printf("uid = %x\n", uid); + return TRUE; + } else { + return FALSE; + } +} + +int accept_string(buffer *d){ + unsigned int len = get32(d); + push(d, len); + char *str=malloc(len); + getStr(d, str, len); + printf("%s\n", str); +#ifdef RETURN_STRINGS + push(d, str); +#else + free(str); +#endif + return TRUE; +} +// included above +// int accept_string_length(buffer *d){ +// unsigned int uid = get32(d); +// return TRUE; +//} +//int accept_char(buffer *d){ +//} + +int accept_type(buffer *d){ + if(accept_basic_type(d)) { + } else if(accept_user_id(d)) { + //printf("user_id \n"); + } else if(accept_array_decl(d)) { + //printf("array_decl \n"); + } else if(accept_struct_decl(d)) { + //printf("struct_decl \n"); + } else { + return FALSE; + } +} +int accept_basic_type(buffer *d){ + unsigned int type = peek32(d); + switch(type) { + case TYPE_BOOLEAN : + //printf("boolean \n"); + break; + case TYPE_BYTE : + //printf("byte \n"); + break; + case TYPE_SHORT : + //printf("short \n"); + break; + case TYPE_INTEGER : + //printf("integer \n"); + break; + case TYPE_LONG : + //printf("long \n"); + break; + case TYPE_FLOAT : + //printf("float \n"); + break; + case TYPE_DOUBLE : + //printf("double \n"); + break; + case TYPE_STRING : + //printf("string \n"); + break; + default : + return FALSE; + } + advance32(d); + push(d,type); + return TRUE; +} +#if 0 // handle all basic types above +int accept_boolean_type(buffer *d){ +} +int accept_byte_type(buffer *d){ +} +int accept_short_type(buffer *d){ +} +int accept_integer_type(buffer *d){ +} +int accept_long_type(buffer *d){ +} +int accept_float_type(buffer *d){ +} +int accept_string_type(buffer *d){ +} +#endif +int accept_array_decl(buffer *d){ + unsigned int tid = peek32(d); + if(tid == ARRAY_DECL) { + advance32(d); + unsigned int nidx = get32(d); + printf("%d dim array: ", nidx); + int i; + unsigned int numVar=0; + unsigned int size=1; + for(i=0; i<nidx; i++) { + unsigned int idx = get32(d); + if(idx == 0) { + numVar++; + printf("variable index (numVar=%d), ",numVar); + } else { + printf("fixed index: %d, ", idx); + size*=idx; + } + printf("\n"); + } + unsigned int et=accept_type(d); + printf("array element type: %x\n", et); + pop(d); + //push(d,tid); + return TRUE; + } else { + return FALSE; + } +} +#if 0 +int accept_number_of_indices(buffer *d){ +} +int accept_indices(buffer *d){ +} +int accept_variable_index(buffer *d){ +} +int accept_fixed_index(buffer *d){ +} +#endif +int accept_struct_decl(buffer *d){ + unsigned int tid = peek32(d); + if(tid == STRUCT_DECL) { + advance32(d); + unsigned int nf = get32(d); + printf("%d field struct: ", nf); + int i; + int numVar=0; + int size=0; + for(i=0; i<nf; i++) { + accept_field(d); + } + push(d,tid); + return TRUE; + } else { + return FALSE; + } +} +#if 0 +int accept_number_of_fields(buffer *d){ +} +#endif +int accept_field(buffer *d){ + accept_string(d); + // ignore, for now + accept_type(d); + unsigned int type = pop(d); + printf("field: %x \n", type); +} +int accept_sample_data(buffer *d){ + accept_user_id(d); + unsigned int uid = pop(d); + printf("sample data... %x\n", uid); +#ifdef DEBUG + dump_signature(uid); +#endif + unsigned int siglen = get_signature_len(uid); + unsigned char *sig = get_signature(uid); + skip_packed_sample_data(d, sig, siglen); + return TRUE; +} +//int accept_packed_sample_data(buffer *d){ + +int skip_type(unsigned int,buffer*,unsigned char*,unsigned int,unsigned int*) ; + +int skip_array(buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { + unsigned int skip = 0; + unsigned int tot_nbr_elem_tmp = 1; + unsigned int nIdx = unpack32(sig, *pos); + printf("skip_array: nIdx = %d\n", nIdx); + *pos +=4; + unsigned int idx[nIdx]; + unsigned int nVar=0; + + unsigned int i; + + for(i=0; i<nIdx; i++) { + idx[i] = unpack32(sig, *pos); + *pos += 4; + printf("skip_array: idx[%d]=%d\n", i, idx[i]); + if(idx[i] == 0) { + nVar++; + } else { + tot_nbr_elem_tmp *= idx[i]; + } + } + unsigned int var[nVar]; + + for(i=0; i<nVar; i++) { + var[i] = get32(d); + printf("skip_array: var[%d]=%d\n", i, var[i]); + } + + unsigned int type = unpack32(sig, *pos); + *pos+=4; + + unsigned int elemSize = labcomm_sizeof(type); + + skip = elemSize * tot_nbr_elem_tmp; + + printf("skip_array: skip: %d * %d = %d\n", elemSize, tot_nbr_elem_tmp, skip); + + advancen(d, skip); + + skip += nVar; + + return skip; +} + +int skip_struct(buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { + unsigned int nFields = unpack32(sig,*pos); + *pos += 4; + unsigned int i; + unsigned int skipped=0; + printf("skip_struct (%d fields)\n", nFields); + for(i=0; i<nFields; i++) { + //skip name + unsigned int namelen = unpack32(sig, *pos); + *pos += (4+namelen); // 32bit len + actual string +#ifdef DEBUG + printf("namelen==%d \n",namelen); +#endif + unsigned int type = unpack32(sig, *pos); + *pos += 4; +#ifdef DEBUG + printf("type == %x\n", type); +#endif + skipped += skip_type(type, d, sig, len, pos); + } + return skipped; +} +#ifndef QUIET +/* print and skip */ +int skip_type(unsigned int type, buffer *d, + unsigned char *sig, unsigned int len, unsigned int *pos) +{ + int skipped=0; + printf("skip_type %x:", type); + switch(type) { + case TYPE_BOOLEAN : + printf("boolean [%d]\n", get(d)); + skipped++; + break; + case TYPE_BYTE : + printf("byte [%d]\n", get(d)); + skipped++; + break; + case TYPE_SHORT : + //XXX not supported + advancen(d,2); + skipped+=2; + break; + case TYPE_INTEGER : + printf("integer [%d]\n", get32(d)); + skipped +=4; + break; + case TYPE_FLOAT : + //XXX not supported + advancen(d,4); + skipped+=4; + break; + case TYPE_LONG : + case TYPE_DOUBLE : + //XXX not supported + advancen(d,8); + skipped+=8; + break; + case TYPE_STRING : + {unsigned int len = get32(d); + //advancen(d,len); + int i; + printf("string ["); + for(i=0; i<len; i++) + printf("%c", get(d)); + printf("]\n"); + skipped+=len+4; + break;} + case ARRAY_DECL : + printf("array\n"); + skipped += skip_array(d, sig, len, pos); + case STRUCT_DECL : + printf("struct\n"); + skipped += skip_struct(d, sig, len, pos); + break; + default: + printf("ERROR: skip_type: type = %x\n", type); + exit(1); + } + return skipped; +} +#else +int skip_type(unsigned int type, buffer *d, + unsigned char *sig, unsigned int len, unsigned int *pos) +{ + int skipped=0; + printf("skip_type %x\n", type); + switch(type) { + case TYPE_BOOLEAN : + case TYPE_BYTE : + advancen(d,1); + skipped++; + break; + case TYPE_SHORT : + advancen(d,2); + skipped+=2; + break; + case TYPE_INTEGER : + case TYPE_FLOAT : + advancen(d,4); + skipped+=4; + break; + case TYPE_LONG : + case TYPE_DOUBLE : + advancen(d,8); + skipped+=8; + break; + case TYPE_STRING : + {unsigned int len = get32(d); + advancen(d,len); + skipped+=len+4; + break;} + case ARRAY_DECL : + printf("array\n"); + skipped += skip_array(d, sig, len, pos); + case STRUCT_DECL : + skipped += skip_struct(d, sig, len, pos); + break; + default: + printf("ERROR: skip_type: type = %x\n", type); + exit(1); + } + return skipped; +} +#endif + +/* parse signature and skip the corresponding bytes in the buffer + */ +int skip_packed_sample_data(buffer *d, unsigned char *sig, unsigned int siglen) { + unsigned int pos = 0; //current position in signature + unsigned int skipped = 0; //skipped byte counter + while(pos < siglen) { + unsigned int type = unpack32(sig,pos); + pos+=4; + skipped += skip_type(type, d, sig, siglen, &pos); + } + printf("skipped %d bytes\n", skipped); + return TRUE; +} diff --git a/lib/c/experimental/labcomm_sig_parser.c b/lib/c/experimental/labcomm_sig_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..b56c0be9d8006a07892567e7cf0192703306d1b1 --- /dev/null +++ b/lib/c/experimental/labcomm_sig_parser.c @@ -0,0 +1,658 @@ +/* labcomm_parser.c: + * an example parser for labcomm signatures, illustrating how to skip samples + * based on their signature. Intended as an embryo for introducing this + * functionality into the lib to allow a channel to survive types with no + * registered handler. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define DEBUG +#undef DEBUG_STACK +#undef DEBUG_READ + +#undef EXIT_WHEN_RECEIVING_DATA //arrays (at least varsize not working) + +#define FALSE 0 +#define TRUE 1 + +#define USER_ID_BASE 0x00000080 + +typedef enum{ + TYPE_DECL = 0x00000001, + SAMPLE_DECL = 0x00000002, + + ARRAY_DECL = 0x00000010, + STRUCT_DECL = 0x00000011, + + TYPE_BOOLEAN = 0x00000020, + TYPE_BYTE = 0x00000021, + TYPE_SHORT = 0x00000022, + TYPE_INTEGER = 0x00000023, + TYPE_LONG = 0x00000024, + TYPE_FLOAT = 0x00000025, + TYPE_DOUBLE = 0x00000026, + TYPE_STRING = 0x00000027 +} labcomm_type ; + +void error(char *s) { + fprintf(stderr, "%s", s); + fprintf(stderr, "\nexiting\n"); + exit(1); +} + +#define BUF_SIZE 1024 +#define STACK_SIZE 16 + +/* internal type: stack for the parser */ +typedef struct { + unsigned char* c; + unsigned int size; + unsigned int capacity; + unsigned int idx; + unsigned int* stack; + unsigned int top; +} buffer; + +/* aux method for reading a big endian uint32 from a char* (i.e. ntohl but for explicit char*) */ +static int unpack32(unsigned char *c, unsigned int idx) { + unsigned int b0=(c[idx]) << 3 ; + unsigned int b1=(c[idx+1]) << 2 ; + unsigned int b2=(c[idx+2]) << 1 ; + unsigned int b3=c[idx+3]; + + return b0 | b1 | b2 | b3; +} + +void dumpStack(buffer *b) { +#ifdef DEBUG_STACK + int i; + printf("=== stack: "); + for(i=0; i<STACK_SIZE; i++) { //HERE BE DRAGONS + printf("%2.2x ", b->stack[i]); + } + printf(" top==%d\n", b->top); +#endif +} + +void push(buffer *b, unsigned int e) { + b->stack[b->top]=e; + b->top=b->top-1; + dumpStack(b); +} +unsigned int pop(buffer *b) { + b->top=b->top+1; + return b->stack[b->top]; +} + +int init_buffer(buffer *b, size_t size, size_t stacksize) { + b->c = malloc(size); + b->capacity = size; + b->idx = 0; + + b->stack = calloc(stacksize, sizeof(b->stack)); + b->top = stacksize-1; + + return b->c == NULL || b->stack == NULL; +} + +int more(buffer *b) +{ + return b->idx < b->size; +} + +unsigned char get(buffer *b) { + return b->c[b->idx++]; +} + +unsigned char peek(buffer *b) { + return b->c[b->idx]; +} + +void advance(buffer *b) { + b->idx++; +} + +void advancen(buffer *b, size_t n) { + b->idx+=n; +} + +unsigned int peek32(buffer *b) { + return unpack32(b->c, b->idx); +} + +void advance32(buffer *b) { + b->idx+=4; +} + +unsigned int get32(buffer *b) { + unsigned int res = peek32(b); + advance32(b); + return res; +} + +void getStr(buffer *b, char *dest, size_t size) { + int rem = b->size - b->idx; + if( size > rem ) + size = rem; + strncpy(dest, &b->c[b->idx], size); + b->idx += size; +} + +//XXX experimental +#define MAX_SIGNATURES 10 +#define MAX_NAME_LEN 32 +#define MAX_SIG_LEN 128 +unsigned int signatures_length[MAX_SIGNATURES]; +unsigned char signatures_name[MAX_SIGNATURES][MAX_NAME_LEN]; //HERE BE DRAGONS: add range checks +unsigned char signatures[MAX_SIGNATURES][MAX_SIG_LEN]; + +unsigned int get_signature_len(unsigned int uid){ + return signatures_length[uid-USER_ID_BASE]; +} +unsigned char* get_signature_name(unsigned int uid){ + return &signatures_name[uid-USER_ID_BASE][1]; +} +unsigned char* get_signature(unsigned int uid){ + return signatures[uid-USER_ID_BASE]; +} + +void dump_signature(unsigned int uid){ + int i; + unsigned int len = get_signature_len(uid); + printf("signature for uid %x : %s (len=%d):\n", uid, get_signature_name(uid), len); + unsigned char* sig = get_signature(uid); + for(i=0; i<len; i++) { + printf("%2.2x ",sig[i]); + if( (i+1)%8==0 ) printf("\n"); + } + printf("\n"); +} + +int labcomm_sizeof(unsigned int type) +{ + switch(type) { + case TYPE_BOOLEAN : + case TYPE_BYTE : + return 1; + case TYPE_SHORT : + return 2; + case TYPE_INTEGER : + case TYPE_FLOAT : + return 4; + case TYPE_LONG : + case TYPE_DOUBLE : + return 8; + default: + printf("labcomm_sizeof(%x)\n", type); + error("labcomm_sizeof should only be called for primitive types"); + } +} + +int accept_packet(buffer *d); +int accept_type_decl(buffer *d); +int accept_sample_decl(buffer *d); +int accept_user_id(buffer *d); +int accept_string(buffer *d); +int accept_string_length(buffer *d); +int accept_char(buffer *d); +int accept_type(buffer *d); +int accept_boolean_type(buffer *d); +int accept_byte_type(buffer *d); +int accept_short_type(buffer *d); +int accept_integer_type(buffer *d); +int accept_long_type(buffer *d); +int accept_float_type(buffer *d); +int accept_long_type(buffer *d); +int accept_string_type(buffer *d); +int accept_array_decl(buffer *d); +int accept_number_of_indices(buffer *d); +int accept_indices(buffer *d); +int accept_variable_index(buffer *d); +int accept_fixed_index(buffer *d); +int accept_struct_decl(buffer *d); +int accept_number_of_fields(buffer *d); +int accept_field(buffer *d); +int accept_sample_data(buffer *d); +int accept_packed_sample_data(buffer *d); + +int do_parse(buffer *d) { + unsigned int type = peek32(d) ; + if(type == TYPE_DECL ) { + advance32(d); + accept_user_id(d); + unsigned int uid = pop(d); + printf(", name = "); + accept_string(d); + pop(d); // ignore, for now. This should do something as + // char *name = (char*) pop(d); + // store or print name + // free(name) + printf(" : "); + accept_type(d); + unsigned int type = pop(d); + + //push(d, type); + printf("\n"); + return TRUE; + } else if (type == SAMPLE_DECL) { + advance32(d); + printf("sample_decl "); + accept_user_id(d); + unsigned int nstart = d->idx; + unsigned int uid = pop(d); + printf(", name = "); + accept_string(d); + unsigned int start = d->idx; + unsigned int nlen = pop(d); + accept_type(d); + //printf(" : "); + //unsigned int dt = pop(d); + unsigned int end = d->idx; + unsigned int len = end-start; + + if(len <= MAX_SIG_LEN) { + signatures_length[uid-USER_ID_BASE] = len; + memcpy(signatures[uid-USER_ID_BASE], &d->c[start], len); + } else { + error("sig longer than max length (this ought to be dynamic...)"); + } + + if(nlen < MAX_NAME_LEN) { // leave 1 byte for terminating NULL + signatures_name[uid-USER_ID_BASE][0] = nlen; + memcpy(signatures_name[uid-USER_ID_BASE], &d->c[nstart+3], nlen); + signatures_name[uid-USER_ID_BASE][nlen+1]=0; + } else { + error("sig name longer than max length (this ought to be dynamic..."); + } + //printf("signature for uid %x: %s (start=%x,end=%x, nlen=%d,len=%d)\n", uid, get_signature_name(uid), start,end, nlen, len); + } else { +#ifdef EXIT_WHEN_RECEIVING_DATA + printf("*** got sample data, exiting\n"); + exit(0); +#else + accept_sample_data(d); +#endif + } +} + +int accept_user_id(buffer *d){ + unsigned int uid = peek32(d); + if(uid >= USER_ID_BASE) { + advance32(d); + printf("uid = %x ", uid); + push(d, uid); + return TRUE; + } else { + return FALSE; + } +} + +int accept_string(buffer *d){ + unsigned int len = get32(d); + push(d, len); + char *str=malloc(len); + getStr(d, str, len); + printf("%s", str); +#ifdef RETURN_STRINGS + push(d, str); +#else + free(str); +#endif + return TRUE; +} +// included above +// int accept_string_length(buffer *d){ +// unsigned int uid = get32(d); +// return TRUE; +//} +//int accept_char(buffer *d){ +//} + +int accept_type(buffer *d){ + unsigned int type = peek32(d); + switch(type) { + case TYPE_BOOLEAN : + printf("boolean"); + advance32(d); + break; + case TYPE_BYTE : + printf("byte"); + advance32(d); + break; + case TYPE_SHORT : + printf("short"); + advance32(d); + break; + case TYPE_INTEGER : + printf("integer"); + advance32(d); + break; + case TYPE_LONG : + printf("long"); + advance32(d); + break; + case TYPE_FLOAT : + printf("float"); + advance32(d); + break; + case TYPE_DOUBLE : + printf("double"); + advance32(d); + break; + case TYPE_STRING : + printf("string"); + advance32(d); + break; + case ARRAY_DECL : + accept_array_decl(d); + break; + case STRUCT_DECL : + accept_struct_decl(d); + break; + default : + printf("accept_basic_type default (type==%x) should not happen\n", type); + return FALSE; + } + //push(d,type); + return TRUE; +} + +int accept_array_decl(buffer *d){ + unsigned int tid = peek32(d); + if(tid == ARRAY_DECL) { + advance32(d); + unsigned int nidx = get32(d); + printf("%d dim array", nidx); + int i; + unsigned int numVar=0; + unsigned int size=1; + for(i=0; i<nidx; i++) { + unsigned int idx = get32(d); + if(idx == 0) { + numVar++; + printf("[_] "); + } else { + printf("[%d] ", idx); + size*=idx; + } + } + printf(" of "); + unsigned int et=accept_type(d); + //pop(d); + //push(d,tid); + return TRUE; + } else { + printf("accept_array_decl: type=%x, should not happen\n",tid); + return FALSE; + } +} +int accept_struct_decl(buffer *d){ + unsigned int tid = peek32(d); + if(tid == STRUCT_DECL) { + advance32(d); + unsigned int nf = get32(d); + printf(", %d field struct:\n", nf); + int i; + int numVar=0; + int size=0; + for(i=0; i<nf; i++) { + printf("\t"); + accept_field(d); + } +// push(d,tid); + return TRUE; + } else { + printf("accept_struct_decl: type=%x, should not happen\n",tid); + return FALSE; + } +} +int accept_field(buffer *d){ + printf("field "); + accept_string(d); + pop(d); // ignore, for now + printf(" : "); + accept_type(d); + printf("\n"); +} +int accept_sample_data(buffer *d){ + accept_user_id(d); + unsigned int uid = pop(d); + printf("sample data... %x\n", uid); +#ifdef DEBUG + dump_signature(uid); +#endif + unsigned int siglen = get_signature_len(uid); + unsigned char *sig = get_signature(uid); + skip_packed_sample_data(d, sig, siglen); + return TRUE; +} +//int accept_packed_sample_data(buffer *d){ + +int skip_type(unsigned int,buffer*,unsigned char*,unsigned int,unsigned int*) ; + +int skip_array(buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { + unsigned int skip = 0; + unsigned int tot_nbr_elem_tmp = 1; + unsigned int nIdx = unpack32(sig, *pos); + printf("skip_array: nIdx = %d (from sig)\n", nIdx); + *pos +=4; + unsigned int idx[nIdx]; + unsigned int nVar=0; + + unsigned int i; + + for(i=0; i<nIdx; i++) { + idx[i] = unpack32(sig, *pos); + *pos += 4; + printf("skip_array: idx[%d]=%d (from sig)\n", i, idx[i]); + if(idx[i] == 0) { + nVar++; + } else { + tot_nbr_elem_tmp *= idx[i]; + } + } + unsigned int var[nVar]; + + for(i=0; i<nVar; i++) { + var[i] = get32(d); + printf("skip_array: var[%d]=%d (from sample)\n", i, var[i]); + tot_nbr_elem_tmp *= var[i]; + } + + unsigned int type = unpack32(sig, *pos); + *pos+=4; + + unsigned int elemSize = labcomm_sizeof(type); + + skip = elemSize * tot_nbr_elem_tmp; + + printf("skip_array: skip: %d * %d = %d\n", tot_nbr_elem_tmp, elemSize ,skip); + + advancen(d, skip); + + return skip + 4*nVar; +} + +int skip_struct(buffer *d, unsigned char *sig, unsigned int len, unsigned int *pos) { + unsigned int nFields = unpack32(sig,*pos); + *pos += 4; + unsigned int i; + unsigned int skipped=0; + printf("skip_struct (%d fields)\n", nFields); + for(i=0; i<nFields; i++) { + //skip name + unsigned int namelen = unpack32(sig, *pos); +#ifdef DEBUG + printf("namelen==%d",namelen); + char name[namelen+1]; + name[namelen]=0; + strncpy(name, sig+*pos+4, namelen); + printf(", name = %s",name); +#endif + *pos += (4+namelen); // 32bit len + actual string + + unsigned int type = unpack32(sig, *pos); + *pos += 4; +#ifdef DEBUG + printf(": type == %x\n", type); +#endif + skipped += skip_type(type, d, sig, len, pos); + } + return skipped; +} +#ifndef QUIET +/* print and skip */ +int skip_type(unsigned int type, buffer *d, + unsigned char *sig, unsigned int len, unsigned int *pos) +{ + int skipped=0; + printf("skip_type %x:", type); + switch(type) { + case TYPE_BOOLEAN : + printf("boolean [%d]\n", get(d)); + skipped++; + break; + case TYPE_BYTE : + printf("byte [%d]\n", get(d)); + skipped++; + break; + case TYPE_SHORT : + //XXX not supported + advancen(d,2); + skipped+=2; + break; + case TYPE_INTEGER : + printf("integer [%d]\n", get32(d)); + skipped +=4; + break; + case TYPE_FLOAT : + //XXX not supported + advancen(d,4); + skipped+=4; + break; + case TYPE_LONG : + case TYPE_DOUBLE : + //XXX not supported + advancen(d,8); + skipped+=8; + break; + case TYPE_STRING : + {unsigned int len = get32(d); + //advancen(d,len); + int i; + printf("string ["); + for(i=0; i<len; i++) + printf("%c", get(d)); + printf("]\n"); + skipped+=len+4; + break;} + case ARRAY_DECL : + printf("array\n"); + skipped += skip_array(d, sig, len, pos); + break; + case STRUCT_DECL : + printf("struct\n"); + skipped += skip_struct(d, sig, len, pos); + break; + default: + printf("ERROR: skip_type: type = %x\n", type); + exit(1); + } + return skipped; +} +#else +int skip_type(unsigned int type, buffer *d, + unsigned char *sig, unsigned int len, unsigned int *pos) +{ + int skipped=0; + printf("skip_type %x\n", type); + switch(type) { + case TYPE_BOOLEAN : + case TYPE_BYTE : + advancen(d,1); + skipped++; + break; + case TYPE_SHORT : + advancen(d,2); + skipped+=2; + break; + case TYPE_INTEGER : + case TYPE_FLOAT : + advancen(d,4); + skipped+=4; + break; + case TYPE_LONG : + case TYPE_DOUBLE : + advancen(d,8); + skipped+=8; + break; + case TYPE_STRING : + {unsigned int len = get32(d); + advancen(d,len); + skipped+=len+4; + break;} + case ARRAY_DECL : + skipped += skip_array(d, sig, len, pos); + break; + case STRUCT_DECL : + skipped += skip_struct(d, sig, len, pos); + break; + default: + printf("ERROR: skip_type: type = %x\n", type); + exit(1); + } + return skipped; +} +#endif + +/* parse signature and skip the corresponding bytes in the buffer + */ +int skip_packed_sample_data(buffer *d, unsigned char *sig, unsigned int siglen) { + unsigned int pos = 0; //current position in signature + unsigned int skipped = 0; //skipped byte counter + while(pos < siglen) { + unsigned int type = unpack32(sig,pos); + pos+=4; + skipped += skip_type(type, d, sig, siglen, &pos); + } + printf("skipped %d bytes\n", skipped); + return TRUE; +} + +int read_file(FILE *f, buffer *b) { + int s = fread(b->c, sizeof(char), b->capacity, f); + b->size = s; + b->idx=0; + return s; +} + +void test_read(buffer *buf) { + int r = read_file(stdin, buf); +#ifdef DEBUG_READ + printf("read %d bytes:\n\n", r); + int i; + for(i=0; i<r; i++) { + printf("%x ", buf->c[i]); + if(i%8 == 7) printf("\n"); + } + printf("\n"); +#endif +} +int main() { + buffer buf; + + if( init_buffer(&buf, BUF_SIZE, STACK_SIZE) ) { + printf("failed to init buffer\n"); + exit(1); + } + test_read(&buf); + do{ + printf("------------\n"); + } while(more(&buf) && do_parse(&buf)); + printf("done\n"); +} + + diff --git a/lib/c/experimental/pack.c b/lib/c/experimental/pack.c new file mode 100644 index 0000000000000000000000000000000000000000..06636e399bbb1b036aa4f26c5d6b41425f7cf314 --- /dev/null +++ b/lib/c/experimental/pack.c @@ -0,0 +1,76 @@ +#include <stdio.h> + +typedef unsigned int number; + +unsigned char do_pack(unsigned char *buf, number i) +{ + printf("do_pack %lu == %lx\n", i, i); + + number tmp = i; + unsigned char res = 0; + + while ( tmp >= 0x80 ) { + buf[res] = (tmp & 0x7f) | 0x80; + tmp >>= 7; + res++; + } + buf[res] = tmp; + return res+1; +} + +number do_unpack(unsigned char *buf) +{ + number res=0; + unsigned char i=0; + unsigned char cont=1; + do { + unsigned char c = buf[i]; + res |= (c & 0x7f) << 7*i; + cont = c & 0x80; + i++; + } while(cont); + + return res; +} + +void print_packed(unsigned char *buf, unsigned char len) +{ + int i; + + for(i=0; i<len;i++) { + printf("%2x ", buf[i]); + } + printf("\n"); +} + +int main() +{ + unsigned char buf[10]; + unsigned char len; + + len = do_pack(buf, 10); + print_packed(buf, len); + printf("... unpacks to %u\n\n", do_unpack(buf)); + + len = do_pack(buf, 100); + print_packed(buf, len); + printf("... unpacks to %u\n\n", do_unpack(buf)); + + len = do_pack(buf, 1000); + print_packed(buf, len); + printf("... unpacks to %u\n\n", do_unpack(buf)); + + len = do_pack(buf, 100000); + print_packed(buf, len); + printf("... unpacks to %u\n\n", do_unpack(buf)); + + len = do_pack(buf, 2345678901); + print_packed(buf, len); + printf("... unpacks to %u\n\n", do_unpack(buf)); + + len = do_pack(buf, 0xffffffff); + print_packed(buf, len); + printf("... unpacks to %lx\n", do_unpack(buf)); + + return 0; +} diff --git a/lib/c/experimental/throttlenet/throttlenet.lc b/lib/c/experimental/throttlenet/throttlenet.lc new file mode 100644 index 0000000000000000000000000000000000000000..e747d074120dabb29379b8e5d734a939df8d2923 --- /dev/null +++ b/lib/c/experimental/throttlenet/throttlenet.lc @@ -0,0 +1,75 @@ +typedef long number_t; // placeholder for protocol buffers like encoding +typedef byte eth_addr[6]; + +// *** Service registration, lookup, and channel allocation + +typedef struct { + string creatorId; + string svcId; + int version; //unique + string versionName; //human readable +} serviceID; // Should probably be a PalCom[_]like struct + +typedef struct { + string key; + byte value[_]; +} property_t; // used for type info, grounding, etc. + +typedef struct { + string name; + property_t properties[_]; +} param_t; + +typedef struct { + string name; + property_t properties[_]; + param_t params[_]; +} command_t; + +typedef struct { + serviceID svcID; + string name; + command_t commands[_]; + byte data_description[_]; +} serviceDescription; // d:o PalCom + +typedef struct { + eth_addr device; // or more generic, as in PalCom? + serviceID svcID; + number_t instanceID; + string instance_name; +} service_instance; + +sample struct { + service_instance svc; + number_t chnID; // the channel to use for connecting to the service +} service_register; + +sample boolean ack; + +sample struct { + short dummy; +} services_query; + +sample struct { + service_instance svcs[_]; +} services_list; + +sample struct { + service_instance svc; + number_t bytes_per_period; + number_t period_time; //microseconds + // importance? +} service_allocate_channel; // client [_]> GlobeThrottle to request connection + +sample struct { + number_t chnId; + eth_addr remote_device; + number_t remote_chnId; +} service_channel_open; // sent as response to service_allocate_channel (sent to both sides) + +sample struct { + short max_utilization; // in percent + // min period? +} service_channel_NACK; + diff --git a/lib/c/labcomm.c b/lib/c/labcomm.c index 76324dad45aa9b27d2fbafac51d704efaf510062..ac8cf561b5df02c2b9003b763d03ac5a36d805f8 100644 --- a/lib/c/labcomm.c +++ b/lib/c/labcomm.c @@ -199,7 +199,7 @@ static void do_encoder_register(struct labcomm_encoder *e, context->sample = sample; e->writer.write(&e->writer, labcomm_writer_start); - labcomm_encode_int(e, signature->type); + labcomm_encode_packed32(e, signature->type); labcomm_encode_type_index(e, signature); labcomm_encode_string(e, signature->name); for (i = 0 ; i < signature->size ; i++) { @@ -309,7 +309,7 @@ void labcomm_encoder_free(labcomm_encoder_t* e) void labcomm_encode_type_index(labcomm_encoder_t *e, labcomm_signature_t *s) { int index = get_encoder_index(e, s); - labcomm_encode_int(e, index); + labcomm_encode_packed32(e, index); } static int signature_writer( @@ -354,27 +354,33 @@ static void collect_flat_signature( labcomm_decoder_t *decoder, labcomm_encoder_t *signature_writer) { - int type = labcomm_decode_int(decoder); + //int type = labcomm_decode_int(decoder); + int type = labcomm_decode_packed32(decoder); +// printf("%s: type=%x\n", __FUNCTION__, type); if (type >= LABCOMM_USER) { - decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 2, "Implement %s\n", __FUNCTION__); + decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 3, + "Implement %s ... (1) for type 0x%x\n", __FUNCTION__, type); } else { - labcomm_encode_int(signature_writer, type); + //labcomm_encode_int(signature_writer, type); + labcomm_encode_packed32(signature_writer, type); switch (type) { case LABCOMM_ARRAY: { int dimensions, i; - dimensions = labcomm_decode_int(decoder); - labcomm_encode_int(signature_writer, dimensions); + dimensions = labcomm_decode_packed32(decoder); //labcomm_decode_int(decoder); //unpack32 + labcomm_encode_packed32(signature_writer, dimensions); //pack32 for (i = 0 ; i < dimensions ; i++) { - int n = labcomm_decode_int(decoder); - labcomm_encode_int(signature_writer, n); + int n = labcomm_decode_packed32(decoder); //labcomm_decode_int(decoder); + labcomm_encode_packed32(signature_writer, n); // labcomm_encode_int(signature_writer, n); } collect_flat_signature(decoder, signature_writer); } break; case LABCOMM_STRUCT: { int fields, i; - fields = labcomm_decode_int(decoder); - labcomm_encode_int(signature_writer, fields); + //fields = labcomm_decode_int(decoder); + //labcomm_encode_int(signature_writer, fields); + fields = labcomm_decode_packed32(decoder); + labcomm_encode_packed32(signature_writer, fields); for (i = 0 ; i < fields ; i++) { char *name = labcomm_decode_string(decoder); labcomm_encode_string(signature_writer, name); @@ -392,7 +398,8 @@ static void collect_flat_signature( case LABCOMM_STRING: { } break; default: { - decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 2, "Implement %s\n", __FUNCTION__); + decoder->on_error(LABCOMM_ERROR_UNIMPLEMENTED_FUNC, 3, + "Implement %s (2) for type 0x%x...\n", __FUNCTION__, type); } break; } } @@ -431,7 +438,9 @@ static int do_decode_one(labcomm_decoder_t *d) if (result > 0) { labcomm_decoder_context_t *context = d->context; - result = labcomm_decode_int(d); +// printf("do_decode_one: result = %x\n", result); + result = labcomm_decode_packed32(d); +// printf("do_decode_one: result(2) = %x\n", result); if (result == LABCOMM_TYPEDEF || result == LABCOMM_SAMPLE) { labcomm_encoder_t *e = labcomm_encoder_new(signature_writer, 0); labcomm_signature_t signature; @@ -440,8 +449,9 @@ static int do_decode_one(labcomm_decoder_t *d) e->writer.write(&e->writer, labcomm_writer_start); signature.type = result; - index = labcomm_decode_int(d); + index = labcomm_decode_packed32(d); //int signature.name = labcomm_decode_string(d); +// printf("do_decode_one: result = %x, index = %x, name=%s\n", result, index, signature.name); collect_flat_signature(d, e); signature.size = e->writer.pos; signature.signature = e->writer.data; diff --git a/lib/c/labcomm_private.h b/lib/c/labcomm_private.h index bd5dcfa237f178921a1705ae40cbb9a73ce9aa81..57239ff07134227aa24b5b09f6430e118cf4f0f7 100644 --- a/lib/c/labcomm_private.h +++ b/lib/c/labcomm_private.h @@ -39,7 +39,7 @@ /* * Start index for user defined types */ -#define LABCOMM_USER 0x80 +#define LABCOMM_USER 0x60 /* * Semi private decoder declarations @@ -120,12 +120,45 @@ LABCOMM_DECODE(int, int) LABCOMM_DECODE(long, long long) LABCOMM_DECODE(float, float) LABCOMM_DECODE(double, double) + +static inline unsigned int labcomm_unpack32(labcomm_reader_t *r) +{ + unsigned int res=0; + unsigned char i=0; + unsigned char cont=1; + do { + 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]); + } +#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++; + r->pos++; + } while(cont); + return res; +} + +static inline unsigned int labcomm_decode_packed32(labcomm_decoder_t *d) +{ + return labcomm_unpack32(&d->reader); +} + static inline char *labcomm_read_string(labcomm_reader_t *r) { char *result; int length, i; - length = labcomm_read_int(r); + length = labcomm_unpack32(r); result = malloc(length + 1); for (i = 0 ; i < length ; i++) { if (r->pos >= r->count) { @@ -247,12 +280,43 @@ LABCOMM_ENCODE(int, int) LABCOMM_ENCODE(long, long long) 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. + * + * The chunks are sent "little endian": each 7 bit chunk is more significant than + * the previous. + */ +static inline void labcomm_pack32(labcomm_writer_t *w, unsigned int data) +{ + unsigned int tmp, i; + + tmp = data; + + while (tmp >= 0x80) { + if (w->pos >= w->count) { + w->write(w, labcomm_writer_continue); + } + w->data[w->pos] = (tmp & 0x7f) | 0x80; + w->pos++; + tmp >>= 7; + } + w->data[w->pos] = tmp; + w->pos++; +} + +static inline void labcomm_encode_packed32(labcomm_encoder_t *e, unsigned int data) +{ + labcomm_pack32(&e->writer, data); +} + static inline void labcomm_write_string(labcomm_writer_t *w, char *s) { int length, i; length = strlen((char*)s); - labcomm_write_int(w, length); + labcomm_pack32(w, length); for (i = 0 ; i < length ; i++) { if (w->pos >= w->count) { w->write(w, labcomm_writer_continue); diff --git a/lib/csharp/se/lth/control/labcomm/LabComm.cs b/lib/csharp/se/lth/control/labcomm/LabComm.cs index 2354b50ea6ae9e52300869dacaaff376362dc16c..d37db36d05850c7bbdfe1d236306d1c93f530ee5 100644 --- a/lib/csharp/se/lth/control/labcomm/LabComm.cs +++ b/lib/csharp/se/lth/control/labcomm/LabComm.cs @@ -25,7 +25,7 @@ namespace se.lth.control.labcomm { /* * start of user defined types */ - public const int FIRST_USER_INDEX = 0x80; + public const int FIRST_USER_INDEX = 0x60; } diff --git a/lib/csharp/se/lth/control/labcomm/LabCommDecoderChannel.cs b/lib/csharp/se/lth/control/labcomm/LabCommDecoderChannel.cs index 3255371840e1bd77bef2c83ffa084321a778bec1..08b365c457f6c9900a02185e30f73db3faa19da1 100644 --- a/lib/csharp/se/lth/control/labcomm/LabCommDecoderChannel.cs +++ b/lib/csharp/se/lth/control/labcomm/LabCommDecoderChannel.cs @@ -18,11 +18,11 @@ namespace se.lth.control.labcomm { public void runOne() { bool done = false; while (!done) { - int tag = decodeInt(); + int tag = decodePacked32(); switch (tag) { case LabComm.TYPEDEF: case LabComm.SAMPLE: { - int index = decodeInt(); + int index = decodePacked32(); String name = decodeString(); MemoryStream signature = new MemoryStream(); collectFlatSignature(new LabCommEncoderChannel(signature)); @@ -55,19 +55,19 @@ namespace se.lth.control.labcomm { } private void collectFlatSignature(LabCommEncoder e) { - int type = decodeInt(); - e.encodeInt(type); + int type = decodePacked32(); + e.encodePacked32(type); switch (type) { case LabComm.ARRAY: { - int dimensions = decodeInt(); - e.encodeInt(dimensions); + int dimensions = decodePacked32(); + e.encodePacked32(dimensions); for (int i = 0 ; i < dimensions ; i++) { - e.encodeInt(decodeInt()); + e.encodePacked32(decodePacked32()); } collectFlatSignature(e); } break; case LabComm.STRUCT: { - int fields = decodeInt(); + int fields = decodePacked32(); e.encodeInt(fields); for (int i = 0 ; i < fields ; i++) { e.encodeString(decodeString()); @@ -155,12 +155,26 @@ namespace se.lth.control.labcomm { } public String decodeString() { - int length = (int)ReadInt(4); + //int length = (int)ReadInt(4); + int length = decodePacked32(); byte[] buf = new byte[length]; ReadBytes(buf, length); return Encoding.UTF8.GetString(buf); } - } + public int decodePacked32() { + Int64 res = 0; + byte i = 0; + bool cont = true; + + do { + byte c = decodeByte(); + res |= (uint) ((c & 0x7f) << 7*i); + cont = (c & 0x80) != 0; + i++; + } while(cont); + return (int) (res & 0xffffffff); + } + } } diff --git a/lib/csharp/se/lth/control/labcomm/LabCommEncoder.cs b/lib/csharp/se/lth/control/labcomm/LabCommEncoder.cs index 87008c80243a26c318734c8050c9b0d8895f1135..1ddadd260ec2abfdf2dd69ae2b14d9376d1ddc79 100644 --- a/lib/csharp/se/lth/control/labcomm/LabCommEncoder.cs +++ b/lib/csharp/se/lth/control/labcomm/LabCommEncoder.cs @@ -15,6 +15,7 @@ namespace se.lth.control.labcomm { void encodeFloat(float value); void encodeDouble(double value); void encodeString(String value); + void encodePacked32(Int64 value); } diff --git a/lib/csharp/se/lth/control/labcomm/LabCommEncoderChannel.cs b/lib/csharp/se/lth/control/labcomm/LabCommEncoderChannel.cs index 27cc8cbb650bf960bd919f40527168b1f64ae705..73ee9047b49569f37f81355d2a4c619aac719023 100644 --- a/lib/csharp/se/lth/control/labcomm/LabCommEncoderChannel.cs +++ b/lib/csharp/se/lth/control/labcomm/LabCommEncoderChannel.cs @@ -18,8 +18,8 @@ namespace se.lth.control.labcomm { public void register(LabCommDispatcher dispatcher) { int index = registry.add(dispatcher); - encodeInt(LabComm.SAMPLE); - encodeInt(index); + encodePacked32(LabComm.SAMPLE); + encodePacked32(index); encodeString(dispatcher.getName()); byte[] signature = dispatcher.getSignature(); for (int i = 0 ; i < signature.Length ; i++) { @@ -29,7 +29,7 @@ namespace se.lth.control.labcomm { } public void begin(Type c) { - encodeInt(registry.getTag(c)); + encodePacked32(registry.getTag(c)); } public void end(Type c) { @@ -84,9 +84,18 @@ namespace se.lth.control.labcomm { public void encodeString(String value) { byte[] buf = Encoding.UTF8.GetBytes(value); - WriteInt(buf.Length, 4); + encodePacked32(buf.Length); bytes.Write(buf, 0, buf.Length); } + public void encodePacked32(Int64 value) { + Int64 tmp = value; + + while(tmp >= 0x80) { + encodeByte( (byte) ((tmp & 0x7f) | 0x80 ) ); + tmp >>= 7; + } + encodeByte( (byte) (tmp & 0x7f) ); + } } -} \ No newline at end of file +} diff --git a/lib/java/se/lth/control/labcomm/LabComm.java b/lib/java/se/lth/control/labcomm/LabComm.java index bb69df857a2028efe7c5b906e8fc58d835fa80be..7a82e76657809760a1485f9589adfc8316a33e5b 100644 --- a/lib/java/se/lth/control/labcomm/LabComm.java +++ b/lib/java/se/lth/control/labcomm/LabComm.java @@ -25,6 +25,6 @@ public class LabComm { /* * Start of */ - public static final int FIRST_USER_INDEX = 0x80; + public static final int FIRST_USER_INDEX = 0x60; -} \ No newline at end of file +} diff --git a/lib/java/se/lth/control/labcomm/LabCommDecoder.java b/lib/java/se/lth/control/labcomm/LabCommDecoder.java index e8f6b8f1e8c36e567fedda50d61be210ca31e86a..a40fb8531f43c8b064835ca2de4b904325b838ca 100644 --- a/lib/java/se/lth/control/labcomm/LabCommDecoder.java +++ b/lib/java/se/lth/control/labcomm/LabCommDecoder.java @@ -14,5 +14,6 @@ public interface LabCommDecoder { public float decodeFloat() throws IOException; public double decodeDouble() throws IOException; public String decodeString() throws IOException; + public int decodePacked32() throws IOException; -} \ No newline at end of file +} diff --git a/lib/java/se/lth/control/labcomm/LabCommDecoderChannel.java b/lib/java/se/lth/control/labcomm/LabCommDecoderChannel.java index 4096d47abd9245a142d3c3391c2831418d50f386..d783bd32048a948f275015de91cbee7ff3c2fc57 100644 --- a/lib/java/se/lth/control/labcomm/LabCommDecoderChannel.java +++ b/lib/java/se/lth/control/labcomm/LabCommDecoderChannel.java @@ -18,11 +18,11 @@ public class LabCommDecoderChannel implements LabCommDecoder { public void runOne() throws Exception { boolean done = false; while (!done) { - int tag = decodeInt(); + int tag = decodePacked32(); switch (tag) { case LabComm.TYPEDEF: case LabComm.SAMPLE: { - int index = decodeInt(); + int index = decodePacked32(); String name = decodeString(); ByteArrayOutputStream signature = new ByteArrayOutputStream(); collectFlatSignature(new LabCommEncoderChannel(signature)); @@ -55,20 +55,20 @@ public class LabCommDecoderChannel implements LabCommDecoder { } private void collectFlatSignature(LabCommEncoder out) throws IOException { - int type = decodeInt(); - out.encodeInt(type); + int type = decodePacked32(); + out.encodePacked32(type); switch (type) { case LabComm.ARRAY: { - int dimensions = decodeInt(); - out.encodeInt(dimensions); + int dimensions = decodePacked32(); + out.encodePacked32(dimensions); for (int i = 0 ; i < dimensions ; i++) { - out.encodeInt(decodeInt()); + out.encodePacked32(decodePacked32()); } collectFlatSignature(out); } break; case LabComm.STRUCT: { - int fields = decodeInt(); - out.encodeInt(fields); + int fields = decodePacked32(); + out.encodePacked32(fields); for (int i = 0 ; i < fields ; i++) { out.encodeString(decodeString()); collectFlatSignature(out); @@ -124,9 +124,29 @@ public class LabCommDecoderChannel implements LabCommDecoder { } public String decodeString() throws IOException { - in.readShort(); // HACK - return in.readUTF(); + //in.readShort(); // HACK + //return in.readUTF(); + int len = decodePacked32() & 0xffffffff; + byte[] chars = new byte[len]; + for(int i=0; i<len; i++) { + chars[i] = in.readByte(); + } + return new String(chars); } + public int decodePacked32() throws IOException { + long res=0; + byte i=0; + boolean cont=true; + + do { + byte c = in.readByte(); + res |= (c & 0x7f) << 7*i; + cont = (c & 0x80) != 0; + i++; + } while(cont); + + return (int) (res & 0xffffffff); + } } diff --git a/lib/java/se/lth/control/labcomm/LabCommEncoder.java b/lib/java/se/lth/control/labcomm/LabCommEncoder.java index 66584db4f6379db4d713d8e020dd348105b79861..f332d78784cf6281befe30a1eb099fdaea7c175c 100644 --- a/lib/java/se/lth/control/labcomm/LabCommEncoder.java +++ b/lib/java/se/lth/control/labcomm/LabCommEncoder.java @@ -15,5 +15,6 @@ public interface LabCommEncoder { public void encodeFloat(float value) throws IOException; public void encodeDouble(double value) throws IOException; public void encodeString(String value) throws IOException; + public void encodePacked32(long value) throws IOException; -} \ No newline at end of file +} diff --git a/lib/java/se/lth/control/labcomm/LabCommEncoderChannel.java b/lib/java/se/lth/control/labcomm/LabCommEncoderChannel.java index b339c9f44d9250366ebc0b9efc0ab5f3731d76ec..cbb4bd78311755119c78519ef27fe698105e9435 100644 --- a/lib/java/se/lth/control/labcomm/LabCommEncoderChannel.java +++ b/lib/java/se/lth/control/labcomm/LabCommEncoderChannel.java @@ -21,8 +21,8 @@ public class LabCommEncoderChannel implements LabCommEncoder { public void register(LabCommDispatcher dispatcher) throws IOException { int index = registry.add(dispatcher); - encodeInt(LabComm.SAMPLE); - encodeInt(index); + encodePacked32(LabComm.SAMPLE); + encodePacked32(index); encodeString(dispatcher.getName()); byte[] signature = dispatcher.getSignature(); for (int i = 0 ; i < signature.length ; i++) { @@ -32,7 +32,7 @@ public class LabCommEncoderChannel implements LabCommEncoder { } public void begin(Class<? extends LabCommSample> c) throws IOException { - encodeInt(registry.getTag(c)); + encodePacked32(registry.getTag(c)); } public void end(Class<? extends LabCommSample> c) throws IOException { @@ -70,9 +70,31 @@ public class LabCommEncoderChannel implements LabCommEncoder { } public void encodeString(String value) throws IOException { - data.writeShort(0); // HACK... - data.writeUTF(value); + //data.writeShort(0); // HACK... + //data.writeUTF(value); + + //kludge, to replace above hack with packed length + ByteArrayOutputStream tmpb = new ByteArrayOutputStream(); + DataOutputStream tmps = new DataOutputStream(tmpb); + + tmps.writeUTF(value); + tmps.flush(); + byte[] tmp = tmpb.toByteArray(); + + encodePacked32(tmp.length-2); + for (int i = 2 ; i < tmp.length ; i++) { + encodeByte(tmp[i]); + } } + public void encodePacked32(long value) throws IOException { + long tmp = value; + + while( tmp >= 0x80 ) { + encodeByte( (byte) ((tmp & 0x7f) | 0x80 ) ); + tmp >>>= 7; + } + encodeByte( (byte) (tmp & 0x7f) ); + } } diff --git a/lib/python/labcomm/LabComm.py b/lib/python/labcomm/LabComm.py index dada9ecd55218129d3a44c79a35c8a2fd365cd9c..24a757c0ddc28985bea0dc689eb16181f0a2fbef 100644 --- a/lib/python/labcomm/LabComm.py +++ b/lib/python/labcomm/LabComm.py @@ -44,7 +44,7 @@ # User data: # # +----+----+----+----+ -# | id >= 0x00000080 | +# | id >= 0x00000060 | # +----+----+----+----+ # | user data # | ... @@ -89,6 +89,12 @@ #?? +----+----+----+----+ # # +# type numbers and lengths do not have a fixed lenght, but are packed into sequences +# of 7 bit chunks, represented in bytes with the high bit meaning that more data +# is to come. +# +# The chunks are sent "little endian": each 7 bit chunk is more significant than +# the previous. See encode_packed32 and decode_packed32 in in Codec classes below. import struct as packer @@ -107,7 +113,7 @@ i_FLOAT = 0x25 i_DOUBLE = 0x26 i_STRING = 0x27 -i_USER = 0x80 +i_USER = 0x60 def indent(i, s): return ("\n%s" % (" " * i)).join(s.split("\n")) @@ -306,9 +312,9 @@ class array(object): def encode_decl(self, encoder): encoder.encode_type(i_ARRAY) - encoder.encode_int(len(self.indices)) + encoder.encode_packed32(len(self.indices)) for i in self.indices: - encoder.encode_int(i) + encoder.encode_packed32(i) encoder.encode_type_number(self.decl) def min_max_shape(self, l, depth=0, shape=[]): @@ -344,7 +350,7 @@ class array(object): (shape, self.indices)) for i in range(len(self.indices)): if self.indices[i] == 0: - encoder.encode_int(shape[i]) + encoder.encode_packed32(shape[i]) elif self.indices[i] != shape[i]: raise Exception("Actual dimension %d in %s differs from %s" % (i, shape, self.indices)) @@ -362,10 +368,10 @@ class array(object): self.encode_value(encoder, value, depth) def decode_decl(self, decoder): - n_indices = decoder.decode_int() + n_indices = decoder.decode_packed32() indices = [] for i in range(n_indices): - index = decoder.decode_int() + index = decoder.decode_packed32() indices.append(index) elem_decl = decoder.decode_decl() return array(indices, elem_decl) @@ -383,7 +389,7 @@ class array(object): indices = [] for i in self.indices: if i == 0: - i = decoder.decode_int() + i = decoder.decode_packed32() indices.append(i) return self.decode_value(decoder, indices) @@ -400,7 +406,7 @@ class array(object): indices = [] for i in self.indices: if i == 0: - i = decoder.decode_int() + i = decoder.decode_packed32() indices.append(i) return self.new_instance_value(indices) @@ -414,7 +420,7 @@ class struct: def encode_decl(self, encoder): encoder.encode_type(i_STRUCT) - encoder.encode_int(len(self.field)) + encoder.encode_packed32(len(self.field)) for (name, decl) in self.field: encoder.encode_string(name) encoder.encode_type_number(decl) @@ -429,7 +435,7 @@ class struct: decl.encode(encoder, obj.__getattribute__(name)) def decode_decl(self, decoder): - n_field = decoder.decode_int() + n_field = decoder.decode_packed32() field = [] for i in range(n_field): name = decoder.decode_string() @@ -540,7 +546,7 @@ class Codec(object): index.sort() for i in index: e = self.index_to_decl[i] - if i >= 0x80 and isinstance(e, sample): + if i >= i_USER and isinstance(e, sample): result.append(e) return result @@ -573,8 +579,17 @@ class Encoder(Codec): except KeyError: decl.encode_decl(self) + def encode_packed32(self, v): + tmp = v & 0xffffffff; + + while(tmp >= 0x80 ): + self.encode_byte( (tmp & 0x7f) | 0x80 ) + tmp >>= 7 + self.encode_byte(tmp & 0x7f) + def encode_type(self, index): - self.pack("!i", index) + self.encode_packed32(index) +# self.pack("!i", index) def encode_boolean(self, v): if v: @@ -602,7 +617,9 @@ class Encoder(Codec): def encode_string(self, v): s = v.encode("utf8") - self.pack("!i%ds" % len(s), len(s), s) + self.encode_packed32(len(s)); + self.pack("%ds" % len(s),s) +# self.pack("!i%ds" % len(s), len(s), s) class Decoder(Codec): def __init__(self, reader): @@ -648,8 +665,18 @@ class Decoder(Codec): return result + def decode_packed32(self): + res = 0 + i = 0 + cont = True + while (cont): + c = self.decode_byte() + res |= (c & 0x7f) << 7*i + cont = (c & 0x80) != 0; + return res + def decode_type_number(self): - return self.unpack("!i") + return self.decode_packed32() def decode_boolean(self): return self.unpack("!b") != 0 @@ -673,7 +700,7 @@ class Decoder(Codec): return self.unpack("!d") def decode_string(self): - length = self.unpack("!i") + length = self.decode_packed32() return self.unpack("!%ds" % length).decode("utf8")