labcomm_private.h 16.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
  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/>.
*/

23
24
#ifndef __LABCOMM_PRIVATE_H__
#define __LABCOMM_PRIVATE_H__
Anders Nilsson's avatar
Anders Nilsson committed
25

26
27
#ifdef LABCOMM_COMPAT
  #include LABCOMM_COMPAT
Oscar Olsson's avatar
Oscar Olsson committed
28
29
30
#else
  #include <endian.h>
  #include <stdio.h>
31
32
  #include <stdint.h>
  #include <unistd.h>
Oscar Olsson's avatar
Oscar Olsson committed
33
34
#endif

35
//#include <stdlib.h>
Anders Nilsson's avatar
Anders Nilsson committed
36
37
38
39
#include <string.h>
#include "labcomm.h"

/*
40
 * Allowed packet tags
Anders Nilsson's avatar
Anders Nilsson committed
41
 */
42
43
44
#define LABCOMM_VERSION      0x01
#define LABCOMM_SAMPLE_DEF   0x02
#define LABCOMM_SAMPLE_REF   0x03
45
46
#define LABCOMM_TYPE_DEF     0x04
#define LABCOMM_TYPE_BINDING 0x05
47
48
#define LABCOMM_PRAGMA       0x3f
#define LABCOMM_USER         0x40 /* ..0xffffffff */
49
50
51
52

/*
 * Predefined aggregate type indices
 */
53
54
#define LABCOMM_ARRAY        0x10
#define LABCOMM_STRUCT       0x11
Anders Nilsson's avatar
Anders Nilsson committed
55
56

/*
57
 * Predefined primitive type indices
Anders Nilsson's avatar
Anders Nilsson committed
58
 */
59
60
61
62
63
64
65
66
#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
67
#define LABCOMM_REF          0x28
Anders Nilsson's avatar
Anders Nilsson committed
68

69
70
71
72
73
/* 
 * other special values
 */

#define LABCOMM_BIND_SELF    0
Anders Nilsson's avatar
Anders Nilsson committed
74

75
/*
76
77
78
 * 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.
79
 */
80
81
#ifndef LABCOMM_CONSTRUCTOR
#define LABCOMM_CONSTRUCTOR __attribute__((constructor))
82
#endif
83

84
85
86
87
88
89
90
91
92
/*
 * 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);
93
  void *context;
94
95
};

Anders Nilsson's avatar
Anders Nilsson committed
96
97
98
/*
 * Semi private decoder declarations
 */
99
typedef void (*labcomm_handler_function)(void *value, void *context);
Anders Nilsson's avatar
Anders Nilsson committed
100

101
typedef void (*labcomm_decoder_function)(
102
  struct labcomm_reader *r,
103
104
  labcomm_handler_function handler,
  void *context);
Anders Nilsson's avatar
Anders Nilsson committed
105

106
107
struct labcomm_reader_action_context;

108
struct labcomm_reader_action {
109
  /* 'alloc' is called at the first invocation of 'labcomm_decoder_decode_one' 
110
     on the decoder containing the reader.
111
112
113
114
115

     Returned value:
       >  0    Number of bytes allocated for buffering
       <= 0    Error
  */
116
  int (*alloc)(struct labcomm_reader *r, 
117
	       struct labcomm_reader_action_context *action_context);
118
119
120
121
122
123
124
  /* 'free' returns the resources claimed by 'alloc' and might have other
     reader specific side-effects as well.

     Returned value:
       == 0    Success
       != 0    Error
  */
125
126
  int (*free)(struct labcomm_reader *r, 
	      struct labcomm_reader_action_context *action_context);
127
128
129
130
131
132
133
  /* '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)
134
   */
135
  int (*start)(struct labcomm_reader *r, 
136
	       struct labcomm_reader_action_context *action_context,
Anders Blomdell's avatar
Anders Blomdell committed
137
	       int local_index, int remote_index,
138
	       const struct labcomm_signature *signature,
139
	       void *value);
140
141
142
143
144
145
  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,
146
	       int local_index, int remote_index,
147
	       const struct labcomm_signature *signature, 
148
	       uint32_t ioctl_action, va_list args);
149
150
};

151
152
struct labcomm_reader_action_context {
  struct labcomm_reader_action_context *next;
153
  const struct labcomm_reader_action *action;
154
155
156
157
158
  void *context;  
};

struct labcomm_reader {
  struct labcomm_reader_action_context *action_context;
159
160
161
  struct labcomm_memory *memory;
  /* The following fields are initialized by labcomm_decoder_new */
  struct labcomm_decoder *decoder;
162
163
164
165
166
167
168
  unsigned char *data;
  int data_size;
  int count;
  int pos;
  int error;
};

169
int labcomm_reader_alloc(struct labcomm_reader *r, 
170
			 struct labcomm_reader_action_context *action_context);
171
172
173
int labcomm_reader_free(struct labcomm_reader *r, 
			struct labcomm_reader_action_context *action_context);
int labcomm_reader_start(struct labcomm_reader *r, 
174
			 struct labcomm_reader_action_context *action_context,
Anders Blomdell's avatar
Anders Blomdell committed
175
			 int local_index, int remote_index,
176
			 const struct labcomm_signature *signature,
177
			 void *value);
178
179
180
181
182
183
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,
184
			 int local_index, int remote_index,
185
			 const struct labcomm_signature *signature, 
186
			 uint32_t ioctl_action, va_list args);
187

Anders Nilsson's avatar
Anders Nilsson committed
188
189
190
191
/*
 * Non typesafe registration function to be called from
 * generated labcomm_decoder_register_* functions.
 */
192
int labcomm_internal_decoder_register(
193
  struct labcomm_decoder *d, 
194
  const struct labcomm_signature *s, 
195
196
  labcomm_decoder_function decoder,
  labcomm_handler_function handler,
Anders Nilsson's avatar
Anders Nilsson committed
197
198
  void *context);

199
int labcomm_internal_decoder_ioctl(struct labcomm_decoder *decoder, 
200
				   const struct labcomm_signature *signature,
201
				   uint32_t ioctl_action, va_list args);
202

203
204
205
const struct labcomm_signature *labcomm_internal_decoder_index_to_signature(
  struct labcomm_decoder *decoder, int index);

Anders Nilsson's avatar
Anders Nilsson committed
206
207
208
#if __BYTE_ORDER == __LITTLE_ENDIAN

#define LABCOMM_DECODE(name, type)					\
209
  static inline type labcomm_read_##name(struct labcomm_reader *r) {	\
Anders Nilsson's avatar
Anders Nilsson committed
210
211
212
    type result; int i;							\
    for (i = sizeof(type) - 1 ; i >= 0 ; i--) {				\
      if (r->pos >= r->count) {						\
213
	labcomm_reader_fill(r, r->action_context);			\
214
215
216
	if (r->error < 0) {						\
	  return 0;							\
	}								\
Anders Nilsson's avatar
Anders Nilsson committed
217
218
219
220
221
222
223
224
225
226
      }									\
      ((unsigned char*)(&result))[i] = r->data[r->pos];			\
      r->pos++;								\
    }									\
    return result;							\
  }

#else

#define LABCOMM_DECODE(name, type)					\
227
  static inline type labcomm_read_##name(struct labcomm_reader *r) {	\
Anders Nilsson's avatar
Anders Nilsson committed
228
229
230
    type result; int i;							\
    for (i = 0 ; i < sizeof(type) ; i++) {				\
      if (r->pos >= r->count) {						\
231
	labcomm_reader_fille(r, r->action_context);			\
232
233
234
	if (r->error < 0) {						\
	  return 0;							\
	}								\
Anders Nilsson's avatar
Anders Nilsson committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
      }									\
      ((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)
251

252
static inline unsigned int labcomm_read_packed32(struct labcomm_reader *r)
253
254
255
256
257
258
259
{
  unsigned int result = 0;
  
  while (1) {
    unsigned char tmp;

    if (r->pos >= r->count) {	
260
      labcomm_reader_fill(r, r->action_context);
Anders Blomdell's avatar
Anders Blomdell committed
261
262
263
      if (r->error != 0) {
	goto out;
      }
264
265
266
267
268
269
270
271
    }
    tmp = r->data[r->pos];
    r->pos++;
    result = (result << 7) | (tmp & 0x7f);
    if ((tmp & 0x80) == 0) { 
      break; 
    }
  }
Anders Blomdell's avatar
Anders Blomdell committed
272
out:
273
274
275
  return result;
}
 
276
static inline char *labcomm_read_string(struct labcomm_reader *r)
Anders Nilsson's avatar
Anders Nilsson committed
277
{
278
279
  char *result = NULL;
  int length, pos; 
Anders Nilsson's avatar
Anders Nilsson committed
280
  
281
  length = labcomm_read_packed32(r);
282
  result = labcomm_memory_alloc(r->memory, 1, length + 1);
283
  if (!result) {
Anders Blomdell's avatar
Anders Blomdell committed
284
    labcomm2014_on_error_fprintf(LABCOMM_ERROR_MEMORY, 4, "%d byte at %s:%d",
285
286
287
		     length+1, __FUNCTION__, __LINE__);
    return NULL;
  }
288
  for (pos = 0 ; pos < length ; pos++) {
Anders Nilsson's avatar
Anders Nilsson committed
289
    if (r->pos >= r->count) {	
290
      labcomm_reader_fill(r, r->action_context);
291
292
293
      if (r->error < 0) {
	goto out;
      }
Anders Nilsson's avatar
Anders Nilsson committed
294
    }
295
    result[pos] = r->data[r->pos];
Anders Nilsson's avatar
Anders Nilsson committed
296
297
    r->pos++;
  }
298
299
out:
  result[pos] = 0;
Anders Nilsson's avatar
Anders Nilsson committed
300
301
302
303
304
305
  return result;
}

/*
 * Semi private encoder declarations
 */
Anders Blomdell's avatar
Anders Blomdell committed
306
307
typedef int (*labcomm_encoder_function)(struct labcomm_writer *,
					void *value);
308
struct labcomm_writer_action_context;
309
310

struct labcomm_writer_action {
311
  int (*alloc)(struct labcomm_writer *w, 
312
	       struct labcomm_writer_action_context *action_context);
313
314
  int (*free)(struct labcomm_writer *w, 
	      struct labcomm_writer_action_context *action_context);
315
316
317
318
319
320
321
322
323
  /* '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
   */
324
325
  int (*start)(struct labcomm_writer *w, 
	       struct labcomm_writer_action_context *action_context,
326
	       int index, const struct labcomm_signature *signature,
327
	       void *value);
328
329
330
331
332
333
  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, 
334
	       int index, const struct labcomm_signature *signature, 
335
	       uint32_t ioctl_action, va_list args);
336
337
};

338
339
struct labcomm_writer_action_context {
  struct labcomm_writer_action_context *next;
340
  const struct labcomm_writer_action *action;
341
342
343
344
345
  void *context;  
};

struct labcomm_writer {
  struct labcomm_writer_action_context *action_context;
346
347
348
  struct labcomm_memory *memory;
  /* The following fields are initialized by labcomm_encoder_new */
  struct labcomm_encoder *encoder;
349
350
351
352
353
354
355
  unsigned char *data;
  int data_size;
  int count;
  int pos;
  int error;
};

356
int labcomm_writer_alloc(struct labcomm_writer *w, 
357
			 struct labcomm_writer_action_context *action_context);
358
359
360
361
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,
362
			 int index, const struct labcomm_signature *signature,
363
364
365
366
367
368
369
			 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, 
370
			 int index, const struct labcomm_signature *signature, 
371
372
			 uint32_t ioctl_action, va_list args);

373
374
375
376
377
378
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,
379
380
  const struct labcomm_signature *signature,
  char has_deps);
381

382
int labcomm_internal_encoder_register(
383
  struct labcomm_encoder *encoder, 
384
  const struct labcomm_signature *signature, 
385
  labcomm_encoder_function encode);
Anders Nilsson's avatar
Anders Nilsson committed
386

387
int labcomm_internal_encode(
388
  struct labcomm_encoder *encoder, 
389
  const struct labcomm_signature *signature, 
390
  labcomm_encoder_function encode,
Anders Nilsson's avatar
Anders Nilsson committed
391
392
  void *value);

393
int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, 
394
				   const struct labcomm_signature *signature,
395
				   uint32_t ioctl_action, va_list args);
396

397
398
399
400
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,
401
402
                            void *v);

403

Anders Nilsson's avatar
Anders Nilsson committed
404
405
406
#if __BYTE_ORDER == __LITTLE_ENDIAN

#define LABCOMM_ENCODE(name, type)					\
407
  static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \
Anders Nilsson's avatar
Anders Nilsson committed
408
409
    int i;								\
    for (i = sizeof(type) - 1 ; i >= 0 ; i--) {				\
Oscar Olsson's avatar
Oscar Olsson committed
410
      if (w->pos >= w->count) { /*buffer is full*/			\
411
        int err;							\
412
	err = labcomm_writer_flush(w, w->action_context);		\
413
	if (err != 0) { return err; }					\
Anders Nilsson's avatar
Anders Nilsson committed
414
415
416
417
      }									\
      w->data[w->pos] = ((unsigned char*)(&data))[i];			\
      w->pos++;								\
    }									\
418
    return 0;								\
Anders Nilsson's avatar
Anders Nilsson committed
419
420
421
422
423
  }

#else

#define LABCOMM_ENCODE(name, type)					\
424
  static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \
Anders Nilsson's avatar
Anders Nilsson committed
425
426
427
    int i;								\
    for (i = 0 ; i < sizeof(type) ; i++) {				\
      if (w->pos >= w->count) {						\
428
        int err;							\
429
	err = labcomm_writer_flush(w, w->action_context);		\
430
	if (err != 0) { return err; }					\
Anders Nilsson's avatar
Anders Nilsson committed
431
432
433
434
      }									\
      w->data[w->pos] = ((unsigned char*)(&data))[i];			\
      w->pos++;								\
    }									\
435
    return 0;								\
Anders Nilsson's avatar
Anders Nilsson committed
436
437
438
439
440
441
442
443
444
445
446
  }

#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)
447

448
static inline int labcomm_write_packed32(struct labcomm_writer *w, 
449
450
451
452
453
454
455
456
457
458
459
					 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;
460
      err = labcomm_writer_flush(w, w->action_context);	
461
462
463
464
465
466
467
      if (err != 0) { return err; }
    }
    w->data[w->pos++] = tmp[i] | (i?0x80:0x00);
  }
  return 0;
}

468
static inline int labcomm_write_string(struct labcomm_writer *w, char *s)
Anders Nilsson's avatar
Anders Nilsson committed
469
{
470
  int length, i, err; 
Anders Nilsson's avatar
Anders Nilsson committed
471

472
  length = strlen(s);
473
474
  err = labcomm_write_packed32(w, length);
  if (err != 0) { return err; }
Anders Nilsson's avatar
Anders Nilsson committed
475
476
  for (i = 0 ; i < length ; i++) {
    if (w->pos >= w->count) {	
477
      int err;
478
      err = labcomm_writer_flush(w, w->action_context);	
479
      if (err != 0) { return err; }
Anders Nilsson's avatar
Anders Nilsson committed
480
481
482
483
    }
    w->data[w->pos] = s[i];
    w->pos++;
  }
484
  return 0;
Anders Nilsson's avatar
Anders Nilsson committed
485
486
}

Anders Blomdell's avatar
Anders Blomdell committed
487
488
489
490
491
492
493
494
495
496
497
498
499
/* 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;

}

500
501
502
503
504
505
506
static inline int labcomm_size_string(char *s)
{
  int length = strlen(s);
  
  return labcomm_size_packed32(length) + length;
}

507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
/*
 * 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 */

525
526
#define LABCOMM_SIGNATURE_ARRAY_FREE(memory, name, kind)	\
  if (name.data) { labcomm_memory_free(memory, 0, name.data); }	\
527
528
  name.data = (kind *)NULL; /* typechecking */

529
530
531
532
533
534
535
536
537
538
539
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)		\
540
  (name.data = (kind *)name.data, /* typechecking no-op */		\
541
542
   (kind *)(labcomm_signature_array_ref(memory,				\
					&name.first, &name.last,	\
543
544
545
					(void **)&name.data,		\
					sizeof(kind), index)))

546
547
548
549
550
#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)

551
552
553
#define LABCOMM_SIGNATURE_ARRAY_FOREACH(name, kind, var)		\
  for (name.data = (kind *)name.data, /* typechecking no-op */		\
       var = name.first ; var < name.last ; var++)
554

555
556
557
558
/* 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 */
559
int labcomm_get_local_index(const struct labcomm_signature *s);
560

561
562
int labcomm_get_local_type_index(const struct labcomm_signature *s);

Anders Nilsson's avatar
Anders Nilsson committed
563
#endif