Skip to content
Snippets Groups Projects
Forked from Anders Blomdell / LabComm
420 commits behind the upstream repository.
labcomm.c 7.49 KiB
/*
  labcomm.c -- runtime 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/>.
*/

#ifdef LABCOMM_COMPAT
  #include LABCOMM_COMPAT
#else
  #include <stdio.h>
  #include <strings.h>
#endif

#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h>

#include "labcomm.h"
#include "labcomm_private.h"
#include "labcomm_ioctl.h"
#include "labcomm_dynamic_buffer_writer.h"

#define LABCOMM_VERSION "LabComm2013"

/* Unwrapping reader/writer functions */
#define UNWRAP_ac(rw, ac, ...) ac
#define UNWRAP(func, ...)	     \
  while (1) {								\
    if (UNWRAP_ac(__VA_ARGS__)->action->func) {				\
      return UNWRAP_ac(__VA_ARGS__)->action->func(__VA_ARGS__); }	\
    if (UNWRAP_ac(__VA_ARGS__)->next == NULL) { return -ENOSYS; }	\
    UNWRAP_ac( __VA_ARGS__) = UNWRAP_ac(__VA_ARGS__)->next;		\
  }

int labcomm_reader_alloc(struct labcomm_reader *r, 
                         struct labcomm_reader_action_context *action_context, 
                         char *labcomm_version)
{
  UNWRAP(alloc, r, action_context, labcomm_version);
}

int labcomm_reader_free(struct labcomm_reader *r, 
                        struct labcomm_reader_action_context *action_context)
{
  UNWRAP(free, r, action_context);
}

int labcomm_reader_start(struct labcomm_reader *r, 
                         struct labcomm_reader_action_context *action_context,
			 int local_index, int remote_index,
			 struct labcomm_signature *signature,
			 void *value)
{
  UNWRAP(start, r, action_context, local_index, remote_index, signature, value);
}

int labcomm_reader_end(struct labcomm_reader *r, 
                       struct labcomm_reader_action_context *action_context)
{
  UNWRAP(end, r, action_context);
}

int labcomm_reader_fill(struct labcomm_reader *r, 
                        struct labcomm_reader_action_context *action_context)
{
  UNWRAP(fill, r, action_context);
}

int labcomm_reader_ioctl(struct labcomm_reader *r, 
                         struct labcomm_reader_action_context *action_context,
                         int local_index, int remote_index,
                         struct labcomm_signature *signature, 
                         uint32_t ioctl_action, va_list args)
{
  UNWRAP(ioctl, r, action_context, 
	 local_index, remote_index, signature, ioctl_action, args);
}

int labcomm_writer_alloc(struct labcomm_writer *w, 
                         struct labcomm_writer_action_context *action_context, 
                         char *labcomm_version)
{
  UNWRAP(alloc, w, action_context, labcomm_version);
}

int labcomm_writer_free(struct labcomm_writer *w, 
                        struct labcomm_writer_action_context *action_context)
{
  UNWRAP(free, w, 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)
{
  UNWRAP(start, w, action_context, index, signature, value);
}

int labcomm_writer_end(struct labcomm_writer *w, 
                       struct labcomm_writer_action_context *action_context)
{
  UNWRAP(end, w, action_context);
} 

int labcomm_writer_flush(struct labcomm_writer *w, 
                         struct labcomm_writer_action_context *action_context)
{
  UNWRAP(flush, w, 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)
{
  UNWRAP(ioctl, w, action_context, index, signature, ioctl_action, args);
} 

#undef UNWRAP
#undef UNWRAP_ac



static const char *labcomm_error_string[] = { 
#define LABCOMM_ERROR(name, description) description ,
#include "labcomm_error.h"
#undef LABCOMM_ERROR
};
static const int labcomm_error_string_count = (sizeof(labcomm_error_string) / 
					       sizeof(labcomm_error_string[0]));


const char *labcomm_error_get_str(enum labcomm_error error_id)
{
  const char *error_str = NULL;
  // Check if this is a known error ID.
  if (0 <= error_id && error_id < labcomm_error_string_count) {
    error_str = labcomm_error_string[error_id];
  }
  return error_str;
}

void on_error_fprintf(enum labcomm_error error_id, size_t nbr_va_args, ...)
{
#ifndef LABCOMM_NO_STDIO
  const char *err_msg = labcomm_error_get_str(error_id); // The final string to print.
  if (err_msg == NULL) {
    err_msg = "Error with an unknown error ID occured.";
  }
  fprintf(stderr, "%s\n", err_msg);

 if (nbr_va_args > 0) {
   va_list arg_pointer;
   va_start(arg_pointer, nbr_va_args);

   fprintf(stderr, "%s\n", "Extra info {");
   char *print_format = va_arg(arg_pointer, char *);
   vfprintf(stderr, print_format, arg_pointer);
   fprintf(stderr, "}\n");

   va_end(arg_pointer);
 } 
#else
 ; // If labcomm can't be compiled with stdio the user will have to make an own error callback functionif he/she needs error reporting.
#endif
}



#if 0
static void dump(void *p, int size, int first, int last)
{
  int i, j;

  printf("%d %d (%p): ", first, last, p);
  for (i = first ; i < last ; i++) {
    for (j = 0 ; j < size ; j++) {
      printf("%2.2d", ((char*)p)[(i-first)*size + j]);
    }
    printf(" ");
  }
  printf("\n");
}
#endif

void *labcomm_signature_array_ref(struct labcomm_memory *memory,
				  int *first, int *last, void **data,
				  int size, int index)
{
  if (*first == 0 && *last == 0) {
    *first = index;
    *last = index + 1;
    *data = labcomm_memory_alloc(memory, 0, size);
    if (*data) { 
      memset(*data, 0, size); 
    }
  } else if (index < *first || *last <= index) {
    void *old_data = *data;
    int old_first = *first;
    int old_last = *last;
    int n;
    *first = (index<old_first)?index:old_first;
    *last = (old_last<=index)?index+1:old_last;
    n = (*last - *first);
    *data = labcomm_memory_alloc(memory, 0, n * size);
    if (*data) {
      memset(*data, 0, n * size);
      memcpy(*data + (old_first - *first) * size, 
	     old_data, 
	     (old_last - old_first) * size);
    }
//    dump(old_data, size, old_first, old_last);
    labcomm_memory_free(memory, 0, old_data);
  }
  if (*data) {
//    dump(*data, size, *first, *last);
    return *data + (index - *first) * size;
  } else {
    return NULL;
  }
}

static int local_index = 0x40;

void labcomm_set_local_index(struct labcomm_signature *signature)
{
  if (signature->index != 0) {
    labcomm_error_fatal_global(LABCOMM_ERROR_SIGNATURE_ALREADY_SET,
			       "%s", signature->name);
  }
  signature->index = local_index;
  local_index++;
}

int labcomm_get_local_index(struct labcomm_signature *signature)
{
  if (signature->index == 0) {
    labcomm_error_fatal_global(LABCOMM_ERROR_SIGNATURE_NOT_SET,
			       "%s", signature->name);
  }
  return signature->index;
}