Skip to content
Snippets Groups Projects
Select Git revision
  • bb99f89d25b467a87478b68f9781bd4179f1f995
  • master default
  • labcomm2006
  • typedefs
  • anders.blomdell
  • typeref
  • pragma
  • compiler-refactoring
  • labcomm2013
  • v2014.4
  • v2006.0
  • v2014.3
  • v2014.2
  • v2014.1
  • v2014.0
  • v2013.0
16 results

labcomm_private.h

Blame
  • Forked from Anders Blomdell / LabComm
    148 commits behind the upstream repository.
    labcomm_private.h 16.80 KiB
    /*
      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>
      #include <stdint.h>
      #include <unistd.h>
    #endif
    
    //#include <stdlib.h>
    #include <string.h>
    #include "labcomm.h"
    
    /*
     * Allowed packet tags
     */
    #define LABCOMM_VERSION      0x01
    #define LABCOMM_SAMPLE_DEF   0x02
    #define LABCOMM_SAMPLE_REF   0x03
    #define LABCOMM_TYPE_DEF     0x04
    #define LABCOMM_TYPE_BINDING 0x05
    #define LABCOMM_PRAGMA       0x3f
    #define LABCOMM_USER         0x40 /* ..0xffffffff */
    
    /*
     * Predefined aggregate type indices
     */
    #define LABCOMM_ARRAY        0x10
    #define LABCOMM_STRUCT       0x11
    
    /*
     * Predefined 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
    #define LABCOMM_REF          0x28
    
    /* 
     * other special values
     */
    
    #define LABCOMM_BIND_SELF    0
    
    /*
     * Macro to automagically call constructors in modules compiled 
     * with the labcomm compiler. If __attribute__((constructor)) is
     * not supported, these calls has to be done first in main program.
     */
    #ifndef LABCOMM_CONSTRUCTOR
    #define LABCOMM_CONSTRUCTOR __attribute__((constructor))
    #endif
    
    /*
     * 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.
    
         Returned value:
           >  0    Number of bytes allocated for buffering
           <= 0    Error
      */
      int (*alloc)(struct labcomm_reader *r, 
    	       struct labcomm_reader_action_context *action_context);
      /* '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 at the following instances:
         1. When a sample is registered 
              (local_index != 0, remote_index == 0, value == NULL)
         2. When a sample definition is received 
              (local_index != 0, remote_index != 0, value == NULL)
         3. When a sample is received
              (local_index != 0, remote_index != 0, value != NULL)
       */
      int (*start)(struct labcomm_reader *r, 
    	       struct labcomm_reader_action_context *action_context,
    	       int local_index, int remote_index,
    	       const 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 local_index, int remote_index,
    	       const 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);
    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 local_index, int remote_index,
    			 const 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 local_index, int remote_index,
    			 const 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, 
      const struct labcomm_signature *s, 
      labcomm_decoder_function decoder,
      labcomm_handler_function handler,
      void *context);
    
    int labcomm_internal_decoder_ioctl(struct labcomm_decoder *decoder, 
    				   const struct labcomm_signature *signature,
    				   uint32_t ioctl_action, va_list args);
    
    const struct labcomm_signature *labcomm_internal_decoder_index_to_signature(
      struct labcomm_decoder *decoder, int index);
    
    #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);			\
    	if (r->error < 0) {						\
    	  return 0;							\
    	}								\
          }									\
          ((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);			\
    	if (r->error < 0) {						\
    	  return 0;							\
    	}								\
          }									\
          ((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 = NULL;
      int length, pos; 
      
      length = labcomm_read_packed32(r);
      result = labcomm_memory_alloc(r->memory, 1, length + 1);
      if (!result) {
        labcomm2014_on_error_fprintf(LABCOMM_ERROR_MEMORY, 4, "%d byte at %s:%d",
    		     length+1, __FUNCTION__, __LINE__);
        return NULL;
      }
      for (pos = 0 ; pos < length ; pos++) {
        if (r->pos >= r->count) {	
          labcomm_reader_fill(r, r->action_context);
          if (r->error < 0) {
    	goto out;
          }
        }
        result[pos] = r->data[r->pos];
        r->pos++;
      }
    out:
      result[pos] = 0;
      return result;
    }
    
    /*
     * Semi private encoder declarations
     */
    typedef int (*labcomm_encoder_function)(struct labcomm_writer *,
    					void *value);
    struct labcomm_writer_action_context;
    
    struct labcomm_writer_action {
      int (*alloc)(struct labcomm_writer *w, 
    	       struct labcomm_writer_action_context *action_context);
      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, const 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, const 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);
    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, const 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, const struct labcomm_signature *signature, 
    			 uint32_t ioctl_action, va_list args);
    
    int labcomm_internal_encoder_type_register(
      struct labcomm_encoder *e,
      const struct labcomm_signature *signature);
    
    int labcomm_internal_encoder_type_bind(
      struct labcomm_encoder *e,
      const struct labcomm_signature *signature,
      char has_deps);
    
    int labcomm_internal_encoder_register(
      struct labcomm_encoder *encoder, 
      const struct labcomm_signature *signature, 
      labcomm_encoder_function encode);
    
    int labcomm_internal_encode(
      struct labcomm_encoder *encoder, 
      const struct labcomm_signature *signature, 
      labcomm_encoder_function encode,
      void *value);
    
    int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, 
    				   const struct labcomm_signature *signature,
    				   uint32_t ioctl_action, va_list args);
    
    int labcomm_internal_encoder_signature_to_index(
      struct labcomm_encoder *encoder, const struct labcomm_signature *signature);
    
    int labcomm_internal_sizeof(const struct labcomm_signature *signature,
                                void *v);
    
    
    #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(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;
    }
    
    /* Size of packed32 variable */
    static inline int labcomm_size_packed32(unsigned int data)
    {
      int result = 0;
      int i;
    
      for (i = 0 ; i == 0 || data ; i++, data = (data >> 7)) {
        result++;
      }
      return result;
    
    }
    
    static inline int labcomm_size_string(char *s)
    {
      int length = strlen(s);
      
      return labcomm_size_packed32(length) + length;
    }
    
    /*
     * 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_GET(name, kind, index, nomatch)         \
      (name.data = (kind *)name.data, /* typechecking no-op */		\
       (name.first <= index &&                                              \
        index < name.last) ? name.data[index - name.first] : nomatch)
    
    #define LABCOMM_SIGNATURE_ARRAY_FOREACH(name, kind, var)		\
      for (name.data = (kind *)name.data, /* typechecking no-op */		\
           var = name.first ; var < name.last ; var++)
    
    /* Give signature a free local index, this may not be used concurrently */
    void labcomm_set_local_index(struct labcomm_signature *signature);
    
    /* Get the local index for a signature */
    int labcomm_get_local_index(const struct labcomm_signature *s);
    
    int labcomm_get_local_type_index(const struct labcomm_signature *s);
    
    #endif