/* labcomm_private.h -- semi private declarations for handling encoding and decoding of labcomm samples. Copyright 2006-2013 Anders Blomdell <anders.blomdell@control.lth.se> This file is part of LabComm. LabComm 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. LabComm 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/>. */ #ifndef _LABCOMM_PRIVATE_H_ #define _LABCOMM_PRIVATE_H_ #ifdef LABCOMM_COMPAT #include LABCOMM_COMPAT #else #include <endian.h> #include <stdio.h> #endif #include <stdint.h> //#include <stdlib.h> #include <string.h> #include <unistd.h> #include "labcomm.h" /* * Predeclared aggregate type indices */ #define LABCOMM_TYPEDEF 0x01 #define LABCOMM_SAMPLE 0x02 #define LABCOMM_ARRAY 0x10 #define LABCOMM_STRUCT 0x11 /* * Predeclared primitive type indices */ #define LABCOMM_BOOLEAN 0x20 #define LABCOMM_BYTE 0x21 #define LABCOMM_SHORT 0x22 #define LABCOMM_INT 0x23 #define LABCOMM_LONG 0x24 #define LABCOMM_FLOAT 0x25 #define LABCOMM_DOUBLE 0x26 #define LABCOMM_STRING 0x27 /* * Start index for user defined types */ #define LABCOMM_USER 0x40 /* * */ #define LABCOMM_DECLARE_SIGNATURE(name) \ struct labcomm_signature __attribute__((section("labcomm"),aligned(1))) name /* * Semi private lock declarations */ struct labcomm_lock; struct labcomm_lock_action { int (*free)(struct labcomm_lock *lock); int (*acquire)(struct labcomm_lock *lock); int (*release)(struct labcomm_lock *lock); int (*wait)(struct labcomm_lock *lock, useconds_t usec); int (*notify)(struct labcomm_lock *lock); }; struct labcomm_lock { const struct labcomm_lock_action *action; struct labcomm_memory *memory; void *context; }; /* * Semi private dynamic memory declarations */ struct labcomm_memory { void *(*alloc)(struct labcomm_memory *m, int lifetime, size_t size); void *(*realloc)(struct labcomm_memory *m, int lifetime, void *ptr, size_t size); void (*free)(struct labcomm_memory *m, int lifetime, void *ptr); void *context; }; /* * Semi private decoder declarations */ typedef void (*labcomm_handler_function)(void *value, void *context); typedef void (*labcomm_decoder_function)( struct labcomm_reader *r, labcomm_handler_function handler, void *context); struct labcomm_reader_action_context; struct labcomm_reader_action { /* 'alloc' is called at the first invocation of 'labcomm_decoder_decode_one' on the decoder containing the reader. If 'labcomm_version' != NULL and non-empty the transport layer may use it to ensure that compatible versions are used. Returned value: > 0 Number of bytes allocated for buffering <= 0 Error */ int (*alloc)(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, struct labcomm_decoder *decoder, char *labcomm_version); /* 'free' returns the resources claimed by 'alloc' and might have other reader specific side-effects as well. Returned value: == 0 Success != 0 Error */ int (*free)(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context); /* 'start' is called right after a sample has arrived. In the case of a sample or typedef, 'value' == NULL. */ int (*start)(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, int index, struct labcomm_signature *signature, void *value); int (*end)(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context); int (*fill)(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context); int (*ioctl)(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, int index, struct labcomm_signature *signature, uint32_t ioctl_action, va_list args); }; struct labcomm_reader_action_context { struct labcomm_reader_action_context *next; const struct labcomm_reader_action *action; void *context; }; struct labcomm_reader { struct labcomm_reader_action_context *action_context; struct labcomm_memory *memory; /* The following fields are initialized by labcomm_decoder_new */ struct labcomm_decoder *decoder; unsigned char *data; int data_size; int count; int pos; int error; }; int labcomm_reader_alloc(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, struct labcomm_decoder *decoder, char *labcomm_version); int labcomm_reader_free(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context); int labcomm_reader_start(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, int index, struct labcomm_signature *signature, void *value); int labcomm_reader_end(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context); int labcomm_reader_fill(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context); int labcomm_reader_ioctl(struct labcomm_reader *r, struct labcomm_reader_action_context *action_context, int index, struct labcomm_signature *signature, uint32_t ioctl_action, va_list args); /* * Non typesafe registration function to be called from * generated labcomm_decoder_register_* functions. */ int labcomm_internal_decoder_register( struct labcomm_decoder *d, struct labcomm_signature *s, labcomm_decoder_function decoder, labcomm_handler_function handler, void *context); int labcomm_internal_decoder_ioctl(struct labcomm_decoder *decoder, struct labcomm_signature *signature, uint32_t ioctl_action, va_list args); #if __BYTE_ORDER == __LITTLE_ENDIAN #define LABCOMM_DECODE(name, type) \ static inline type labcomm_read_##name(struct labcomm_reader *r) { \ type result; int i; \ for (i = sizeof(type) - 1 ; i >= 0 ; i--) { \ if (r->pos >= r->count) { \ labcomm_reader_fill(r, r->action_context); \ } \ ((unsigned char*)(&result))[i] = r->data[r->pos]; \ r->pos++; \ } \ return result; \ } #else #define LABCOMM_DECODE(name, type) \ static inline type labcomm_read_##name(struct labcomm_reader *r) { \ type result; int i; \ for (i = 0 ; i < sizeof(type) ; i++) { \ if (r->pos >= r->count) { \ labcomm_reader_fille(r, r->action_context); \ } \ ((unsigned char*)(&result))[i] = r->data[r->pos]; \ r->pos++; \ } \ return result; \ } #endif LABCOMM_DECODE(boolean, unsigned char) LABCOMM_DECODE(byte, unsigned char) LABCOMM_DECODE(short, short) LABCOMM_DECODE(int, int) LABCOMM_DECODE(long, long long) LABCOMM_DECODE(float, float) LABCOMM_DECODE(double, double) static inline unsigned int labcomm_read_packed32(struct labcomm_reader *r) { unsigned int result = 0; while (1) { unsigned char tmp; if (r->pos >= r->count) { labcomm_reader_fill(r, r->action_context); if (r->error != 0) { goto out; } } tmp = r->data[r->pos]; r->pos++; result = (result << 7) | (tmp & 0x7f); if ((tmp & 0x80) == 0) { break; } } out: return result; } static inline char *labcomm_read_string(struct labcomm_reader *r) { char *result; int length, i; length = labcomm_read_packed32(r); result = labcomm_memory_alloc(r->memory, 1, length + 1); for (i = 0 ; i < length ; i++) { if (r->pos >= r->count) { labcomm_reader_fill(r, r->action_context); } result[i] = r->data[r->pos]; r->pos++; } result[length] = 0; return result; } /* * Semi private encoder declarations */ typedef int (*labcomm_encoder_function)( struct labcomm_writer *, void *value); typedef int (*labcomm_encoder_enqueue)( struct labcomm_encoder *encoder, void (*action)(struct labcomm_encoder *encoder, void *context), void *context); struct labcomm_writer_action_context; struct labcomm_writer_action { int (*alloc)(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, struct labcomm_encoder *encoder, char *labcomm_version, labcomm_encoder_enqueue enqueue); int (*free)(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context); /* 'start' is called right before a sample is to be sent. In the case of a sample or typedef, 'value' == NULL. Returned value: == 0 Success -> continue sending the sample == -EALREADY Success -> silently skip sending the sample, 'end' will not be called < 0 Error */ int (*start)(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, int index, struct labcomm_signature *signature, void *value); int (*end)(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context); int (*flush)(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context); int (*ioctl)(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, int index, struct labcomm_signature *signature, uint32_t ioctl_action, va_list args); }; struct labcomm_writer_action_context { struct labcomm_writer_action_context *next; const struct labcomm_writer_action *action; void *context; }; struct labcomm_writer { struct labcomm_writer_action_context *action_context; struct labcomm_memory *memory; /* The following fields are initialized by labcomm_encoder_new */ struct labcomm_encoder *encoder; unsigned char *data; int data_size; int count; int pos; int error; }; int labcomm_writer_alloc(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, struct labcomm_encoder *encoder, char *labcomm_version, labcomm_encoder_enqueue enqueue); int labcomm_writer_free(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context); int labcomm_writer_start(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, int index, struct labcomm_signature *signature, void *value); int labcomm_writer_end(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context); int labcomm_writer_flush(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context); int labcomm_writer_ioctl(struct labcomm_writer *w, struct labcomm_writer_action_context *action_context, int index, struct labcomm_signature *signature, uint32_t ioctl_action, va_list args); int labcomm_internal_encoder_register( struct labcomm_encoder *encoder, struct labcomm_signature *signature, labcomm_encoder_function encode); int labcomm_internal_encode( struct labcomm_encoder *encoder, struct labcomm_signature *signature, labcomm_encoder_function encode, void *value); int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, struct labcomm_signature *signature, uint32_t ioctl_action, va_list args); #if __BYTE_ORDER == __LITTLE_ENDIAN #define LABCOMM_ENCODE(name, type) \ static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \ int i; \ for (i = sizeof(type) - 1 ; i >= 0 ; i--) { \ if (w->pos >= w->count) { /*buffer is full*/ \ int err; \ err = labcomm_writer_flush(w, w->action_context); \ if (err != 0) { return err; } \ } \ w->data[w->pos] = ((unsigned char*)(&data))[i]; \ w->pos++; \ } \ return 0; \ } #else #define LABCOMM_ENCODE(name, type) \ static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \ int i; \ for (i = 0 ; i < sizeof(type) ; i++) { \ if (w->pos >= w->count) { \ int err; \ err = labcomm_writer_flush(w, w->action_context); \ if (err != 0) { return err; } \ } \ w->data[w->pos] = ((unsigned char*)(&data))[i]; \ w->pos++; \ } \ return 0; \ } #endif LABCOMM_ENCODE(boolean, unsigned char) LABCOMM_ENCODE(byte, unsigned char) LABCOMM_ENCODE(short, short) LABCOMM_ENCODE(int, int) LABCOMM_ENCODE(long, long long) LABCOMM_ENCODE(float, float) LABCOMM_ENCODE(double, double) static inline int labcomm_write_packed32(struct labcomm_writer *w, unsigned int data) { unsigned char tmp[5]; int i; for (i = 0 ; i == 0 || data ; i++, data = (data >> 7)) { tmp[i] = data & 0x7f; } for (i = i - 1 ; i >= 0 ; i--) { if (w->pos >= w->count) { int err; err = labcomm_writer_flush(w, w->action_context); if (err != 0) { return err; } } w->data[w->pos++] = tmp[i] | (i?0x80:0x00); } return 0; } static inline int labcomm_write_string(struct labcomm_writer *w, char *s) { int length, i, err; length = strlen((char*)s); err = labcomm_write_packed32(w, length); if (err != 0) { return err; } for (i = 0 ; i < length ; i++) { if (w->pos >= w->count) { int err; err = labcomm_writer_flush(w, w->action_context); if (err != 0) { return err; } } w->data[w->pos] = s[i]; w->pos++; } return 0; } /* * Macros for handling arrays indexed by signature index */ #define LABCOMM_SIGNATURE_ARRAY_DEF(name, kind) \ struct { \ int first; \ int last; \ kind *data; \ } name #define LABCOMM_SIGNATURE_ARRAY_DEF_INIT(name, kind) \ LABCOMM_SIGNATURE_ARRAY_DEF(name, kind) = { 0, 0, NULL } #define LABCOMM_SIGNATURE_ARRAY_INIT(name, kind) \ name.first = 0; name.last = 0; name.data = NULL; \ name.data = (kind *)name.data; /* typechecking no-op */ #define LABCOMM_SIGNATURE_ARRAY_FREE(memory, name, kind) \ if (name.data) { labcomm_memory_free(memory, 0, name.data); } \ name.data = (kind *)NULL; /* typechecking */ void *labcomm_signature_array_ref(struct labcomm_memory * memory, int *first, int *last, void **data, int size, int index); /* * NB: the pointer returned by LABCOMM_SIGNATURE_ARRAY_REF might be * rendered invalid by a subsequent call to LABCOMM_SIGNATURE_ARRAY_REF * on the same SIGNATURE_ARRAY, so make sure not to use the result if * any other code might have made a call to LABCOMM_SIGNATURE_ARRAY_REF * on the same SIGNATURE_ARRAY. */ #define LABCOMM_SIGNATURE_ARRAY_REF(memory, name, kind, index) \ (name.data = (kind *)name.data, /* typechecking no-op */ \ (kind *)(labcomm_signature_array_ref(memory, \ &name.first, &name.last, \ (void **)&name.data, \ sizeof(kind), index))) #define LABCOMM_SIGNATURE_ARRAY_FOREACH(name, kind, var) \ for (name.data = (kind *)name.data, /* typechecking no-op */ \ var = name.first ; var < name.last ; var++) #endif