labcomm_encoder.c 9.86 KB
Newer Older
Anders Blomdell's avatar
Anders Blomdell committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
  labcomm_encoder.c -- handling encoding 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/>.
*/
21
#define CURRENT_VERSION "LabComm2014"
Anders Blomdell's avatar
Anders Blomdell committed
22 23 24 25 26 27

#include <errno.h>
#include "labcomm.h"
#include "labcomm_private.h"
#include "labcomm_ioctl.h"

28 29 30 31 32
#ifndef WITHOUT_PRAGMA
#include "labcomm_dynamic_buffer_writer.h"
#include "labcomm_bytearray_reader.h"
#endif

Anders Blomdell's avatar
Anders Blomdell committed
33 34 35 36 37 38
struct labcomm_encoder {
  struct labcomm_writer *writer;
  struct labcomm_error_handler *error;
  struct labcomm_memory *memory;
  struct labcomm_scheduler *scheduler;
  LABCOMM_SIGNATURE_ARRAY_DEF(registered, int);
39 40
  int context_type; //type tag for context. Currently only LABCOMM_PRAGMA
  void *context; // for, e.g. parent of pragma packet builder 
Anders Blomdell's avatar
Anders Blomdell committed
41 42 43 44 45 46 47 48 49 50 51 52
};

struct labcomm_encoder *labcomm_encoder_new(
  struct labcomm_writer *writer,
  struct labcomm_error_handler *error,
  struct labcomm_memory *memory,
  struct labcomm_scheduler *scheduler)
{
  struct labcomm_encoder *result;

  result = labcomm_memory_alloc(memory, 0, sizeof(*result));
  if (result) {
53 54
    int length;

Anders Blomdell's avatar
Anders Blomdell committed
55 56 57 58 59 60 61 62 63 64 65
    result->writer = writer;
    result->writer->encoder = result;
    result->writer->data = NULL;
    result->writer->data_size = 0;
    result->writer->count = 0;
    result->writer->pos = 0;
    result->writer->error = 0;
    result->error = error;
    result->memory = memory;
    result->scheduler = scheduler;
    LABCOMM_SIGNATURE_ARRAY_INIT(result->registered, int);
66
    labcomm_writer_alloc(result->writer,
67 68 69 70 71 72 73 74 75 76
			 result->writer->action_context);
    labcomm_writer_start(result->writer, 
                         result->writer->action_context, 
                         LABCOMM_VERSION, NULL, CURRENT_VERSION);
    labcomm_write_packed32(result->writer, LABCOMM_VERSION);
    length = (labcomm_size_packed32(LABCOMM_VERSION) +
              labcomm_size_string(CURRENT_VERSION));
    labcomm_write_packed32(result->writer, length);
    labcomm_write_string(result->writer, CURRENT_VERSION);
    labcomm_writer_end(result->writer, result->writer->action_context);
Anders Blomdell's avatar
Anders Blomdell committed
77 78 79 80 81 82 83 84 85 86 87 88 89
  }
  return result;
}

void labcomm_encoder_free(struct labcomm_encoder* e)
{
  struct labcomm_memory *memory = e->memory;

  labcomm_writer_free(e->writer, e->writer->action_context);
  LABCOMM_SIGNATURE_ARRAY_FREE(e->memory, e->registered, int);
  labcomm_memory_free(memory, 0, e);
}

90 91 92 93 94 95 96 97 98 99
#undef WITHOUT_PRAGMA
#ifndef WITHOUT_PRAGMA

struct pragma_packet_builder {
	char * pragma_type;
	struct labcomm_encoder* parent;
};

struct labcomm_encoder *labcomm_pragma_builder_new(
                                   struct labcomm_encoder *e,
100 101
				   char * pragma_type) 
{
102 103
        struct labcomm_writer *dyn_writer = labcomm_dynamic_buffer_writer_new(
                                                 e->memory);
104
	struct labcomm_encoder *pb = labcomm_encoder_new(dyn_writer,
105 106 107
                                                          e->error,
                                                          e->memory,
                                                          e->scheduler);
108 109 110 111 112 113 114 115 116
	size_t tlen = 1+strlen(pragma_type);
	char* ptype = labcomm_memory_alloc(
					e->memory,
					1,
					tlen);
	if(ptype) {
          strncpy(ptype, pragma_type, tlen);		
	} //XXX TODO: and else?
					
117 118 119 120 121 122
	struct pragma_packet_builder* ctxt = labcomm_memory_alloc(
					e->memory,
					1,
					sizeof(struct pragma_packet_builder));
					
	if(ctxt){
123
		ctxt->pragma_type=ptype;
124 125
		ctxt->parent=e;
	}
126 127 128
	pb->context_type = LABCOMM_PRAGMA;
	pb->context = ctxt;
	return pb;
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
}

//HERE BE DRAGONS! Copied from decoder.c
//Should this be moved to private_h?
static int writer_ioctl(struct labcomm_writer *writer,
			uint32_t action,
			...)
{
  int result;
  va_list va;

  if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) {
    result = -EINVAL;
    goto out;
  }

  va_start(va, action);
  result = labcomm_writer_ioctl(writer, writer->action_context,
				0, NULL, action, va);
  va_end(va);
out:
  return result;
}
int labcomm_pragma_send(struct labcomm_encoder* e)
{
//HERE BE DRAGONS!
//We assume that the writer is a dynamic_buffer_writer
  if(e->context_type != LABCOMM_PRAGMA) {
	  printf("context type != PRAGMA, bailing out\n");
	  return 1;
  }
  if(!e->context) {
	  printf("context == NULL, bailing out\n");
	  return 2;
  }
  struct pragma_packet_builder* ctx = e->context;	
  struct labcomm_encoder *p = ctx->parent;
  char * pragma_type = ctx->pragma_type;
  char*  pragma_data;
  int err,len;
  labcomm_writer_end(e->writer, e->writer->action_context);
  err = writer_ioctl(e->writer,
		     LABCOMM_IOCTL_WRITER_GET_BYTES_WRITTEN,
		     &len);
  if (err < 0) {

// HERE BE DRAGONS! 
// What is the difference between error_handler (where is it defined?)
// and error_handler_callback. And why is the latter only in 
// the decoder struct?
//
//    e->on_error(LABCOMM_ERROR_BAD_WRITER, 2,
//		"Failed to get size: %s\n", strerror(-err));
    fprintf(stderr, "BAD WRITER, Failed to get size> %s\n", strerror(-err));
    err = -ENOENT;
    goto free_encoder;
  }
  err = writer_ioctl(e->writer,
        	     LABCOMM_IOCTL_WRITER_GET_BYTE_POINTER,
        	     &pragma_data);
  if (err < 0) {
//    e->on_error(LABCOMM_ERROR_BAD_WRITER, 2,
//        	"Failed to get pointer: %s\n", strerror(-err));
    fprintf(stderr, "BAD WRITER, Failed to get pointer> %s\n", strerror(-err));
    err = -ENOENT;
    goto free_encoder;
  }
  { 
	  int data_len =  labcomm_size_string(pragma_type) + len;
	  int i;
	  labcomm_write_packed32(p->writer, LABCOMM_PRAGMA);
	  labcomm_write_packed32(p->writer, data_len);
	  labcomm_write_string(p->writer, pragma_type);
	  for(i=0; i<len;i++){
		  labcomm_write_byte(p->writer, pragma_data[i]);
	  }
	  labcomm_writer_end(p->writer, p->writer->action_context);
	  err = p->writer->error;
  }
free_encoder:
209 210
  //XXX are these needed, or is that done in encoder_free?
  labcomm_memory_free(e->memory, 1, ctx->pragma_type);  
211 212 213 214 215 216 217 218
  labcomm_memory_free(e->memory, 1, ctx);  
  labcomm_encoder_free(e);
  return err;
}

#endif


219
static int labcomm_internal_encoder_reg_type(
Anders Blomdell's avatar
Anders Blomdell committed
220 221 222 223 224
  struct labcomm_encoder *e,
  struct labcomm_signature *signature,
  labcomm_encoder_function encode)
{
  int result = -EINVAL;
225
  int index, *done, err, i, length;
Anders Blomdell's avatar
Anders Blomdell committed
226

227
  index = labcomm_get_local_index(signature);
Anders Blomdell's avatar
Anders Blomdell committed
228 229 230 231 232 233 234 235 236
  labcomm_scheduler_writer_lock(e->scheduler);
  if (index <= 0) { goto out; }
  done = LABCOMM_SIGNATURE_ARRAY_REF(e->memory, e->registered, int, index);
  if (*done) { goto out; }
  *done = 1;	
  err = labcomm_writer_start(e->writer, e->writer->action_context, 
			     index, signature, NULL);
  if (err == -EALREADY) { result = 0; goto out; }
  if (err != 0) { result = err; goto out; }
Sven Gestegård Robertz's avatar
Sven Gestegård Robertz committed
237
  labcomm_write_packed32(e->writer, LABCOMM_SAMPLE_DEF);
238 239 240 241 242
  length = (labcomm_size_packed32(index) +
            labcomm_size_string(signature->name) +
            labcomm_size_packed32(signature->size) +
            signature->size);
  labcomm_write_packed32(e->writer, length);
Anders Blomdell's avatar
Anders Blomdell committed
243 244
  labcomm_write_packed32(e->writer, index);
  labcomm_write_string(e->writer, signature->name);
245
  labcomm_write_packed32(e->writer, signature->size);
Anders Blomdell's avatar
Anders Blomdell committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259
  for (i = 0 ; i < signature->size ; i++) {
    if (e->writer->pos >= e->writer->count) {
      labcomm_writer_flush(e->writer, e->writer->action_context);
    }
    e->writer->data[e->writer->pos] = signature->signature[i];
    e->writer->pos++;
  }
  labcomm_writer_end(e->writer, e->writer->action_context);
  result = e->writer->error;
out:
  labcomm_scheduler_writer_unlock(e->scheduler);
  return result;
}

260 261 262 263 264 265 266 267 268 269 270 271
int labcomm_internal_encoder_register(
  struct labcomm_encoder *e,
  struct labcomm_signature *signature,
  labcomm_encoder_function encode)
{
  if(e->context_type == LABCOMM_PRAGMA && e->context){
	            e=((struct pragma_packet_builder *)e->context)->parent;
		      }
  return labcomm_internal_encoder_reg_type(
		      e, signature, encode);
}  

Anders Blomdell's avatar
Anders Blomdell committed
272 273 274 275 276 277
int labcomm_internal_encode(
  struct labcomm_encoder *e,
  struct labcomm_signature *signature,
  labcomm_encoder_function encode,
  void *value)
{
278
  int result, index, length;
Anders Blomdell's avatar
Anders Blomdell committed
279

280
  index = labcomm_get_local_index(signature);
281
  length = (signature->encoded_size(value));
Anders Blomdell's avatar
Anders Blomdell committed
282 283 284 285 286 287
  labcomm_scheduler_writer_lock(e->scheduler);
  result = labcomm_writer_start(e->writer, e->writer->action_context, 
				index, signature, value);
  if (result == -EALREADY) { result = 0; goto no_end; }
  if (result != 0) { goto out; }
  result = labcomm_write_packed32(e->writer, index);
288
  result = labcomm_write_packed32(e->writer, length);
Anders Blomdell's avatar
Anders Blomdell committed
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
  if (result != 0) { goto out; }
  result = encode(e->writer, value);
out:
  labcomm_writer_end(e->writer, e->writer->action_context);
no_end:
  labcomm_scheduler_writer_unlock(e->scheduler);
  return result;
}

int labcomm_encoder_ioctl(struct labcomm_encoder *encoder, 
			  uint32_t action,
			  ...)
{
  int result;
  va_list va;
  
  if (LABCOMM_IOC_SIG(action) != LABCOMM_IOC_NOSIG) {
    result = -EINVAL;
    goto out;
  }
  
  va_start(va, action);
  result = labcomm_writer_ioctl(encoder->writer, 
			       encoder->writer->action_context,
			       0, NULL, action, va);
  va_end(va);

out:
  return result;
}

int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, 
				   struct labcomm_signature *signature,
				   uint32_t action, va_list va)
{
  int result = -ENOTSUP;
325 326
  int index;

327
  index = labcomm_get_local_index(signature);
Anders Blomdell's avatar
Anders Blomdell committed
328 329
  result = labcomm_writer_ioctl(encoder->writer, 
				encoder->writer->action_context, 
330
				index, signature, action, va);
Anders Blomdell's avatar
Anders Blomdell committed
331 332
  return result;
}