labcomm_private.h 13.9 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/>.
*/

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

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

33
#include <stdint.h>
Anders Nilsson's avatar
Anders Nilsson committed
34
35
#include <stdlib.h>
#include <string.h>
36
#include <unistd.h>
Anders Nilsson's avatar
Anders Nilsson committed
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#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
 */
62
#define LABCOMM_USER     0x40
Anders Nilsson's avatar
Anders Nilsson committed
63

64
65
66
67
/*
 *
 */
#define LABCOMM_DECLARE_SIGNATURE(name) \
68
  struct labcomm_signature __attribute__((section("labcomm"),aligned(1))) name 
69

70
71
72
/*
 * Semi private lock declarations
 */
73
74
struct labcomm_lock;

75
struct labcomm_lock_action {
76
77
78
79
80
  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);
81
82
};

83
struct labcomm_lock {
84
85
  const struct labcomm_lock_action *action;
  void *context;
86
87
};

Anders Nilsson's avatar
Anders Nilsson committed
88
89
90
/*
 * Semi private decoder declarations
 */
91
typedef void (*labcomm_handler_function)(void *value, void *context);
Anders Nilsson's avatar
Anders Nilsson committed
92

93
typedef void (*labcomm_decoder_function)(
94
  struct labcomm_reader *r,
95
96
  labcomm_handler_function handler,
  void *context);
Anders Nilsson's avatar
Anders Nilsson committed
97

98
99
struct labcomm_reader_action_context;

100
struct labcomm_reader_action {
101
102
103
104
105
106
107
108
109
  /* '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
  */
110
111
  int (*alloc)(struct labcomm_reader *r, 
	       struct labcomm_reader_action_context *action_context, 
112
	       struct labcomm_decoder *decoder, char *labcomm_version);
113
114
115
116
117
118
119
  /* 'free' returns the resources claimed by 'alloc' and might have other
     reader specific side-effects as well.

     Returned value:
       == 0    Success
       != 0    Error
  */
120
121
  int (*free)(struct labcomm_reader *r, 
	      struct labcomm_reader_action_context *action_context);
122
123
124
  /* 'start' is called right after a sample has arrived. In the case of 
     a sample or typedef, 'value' == NULL.
   */
125
  int (*start)(struct labcomm_reader *r, 
126
127
128
	       struct labcomm_reader_action_context *action_context,
	       int index, struct labcomm_signature *signature,
	       void *value);
129
130
131
132
133
134
  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,
135
	       int index, struct labcomm_signature *signature, 
136
	       uint32_t ioctl_action, va_list args);
137
138
};

139
140
struct labcomm_reader_action_context {
  struct labcomm_reader_action_context *next;
141
  const struct labcomm_reader_action *action;
142
143
144
145
146
  void *context;  
};

struct labcomm_reader {
  struct labcomm_reader_action_context *action_context;
147
148
149
150
151
152
153
  unsigned char *data;
  int data_size;
  int count;
  int pos;
  int error;
};

154
155
156
157
158
159
160
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, 
161
162
163
			 struct labcomm_reader_action_context *action_context,
			 int index, struct labcomm_signature *signature,
			 void *value);
164
165
166
167
168
169
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,
170
			 int index, struct labcomm_signature *signature, 
171
			 uint32_t ioctl_action, va_list args);
172

Anders Nilsson's avatar
Anders Nilsson committed
173
174
175
176
/*
 * Non typesafe registration function to be called from
 * generated labcomm_decoder_register_* functions.
 */
177
int labcomm_internal_decoder_register(
178
179
180
181
  struct labcomm_decoder *d, 
  struct labcomm_signature *s, 
  labcomm_decoder_function decoder,
  labcomm_handler_function handler,
Anders Nilsson's avatar
Anders Nilsson committed
182
183
  void *context);

184
int labcomm_internal_decoder_ioctl(struct labcomm_decoder *decoder, 
185
				   struct labcomm_signature *signature,
186
				   uint32_t ioctl_action, va_list args);
187

Anders Nilsson's avatar
Anders Nilsson committed
188
189
190
#if __BYTE_ORDER == __LITTLE_ENDIAN

#define LABCOMM_DECODE(name, type)					\
191
  static inline type labcomm_read_##name(struct labcomm_reader *r) {	\
Anders Nilsson's avatar
Anders Nilsson committed
192
193
194
    type result; int i;							\
    for (i = sizeof(type) - 1 ; i >= 0 ; i--) {				\
      if (r->pos >= r->count) {						\
195
	labcomm_reader_fill(r, r->action_context);			\
Anders Nilsson's avatar
Anders Nilsson committed
196
197
198
199
200
201
202
203
204
205
      }									\
      ((unsigned char*)(&result))[i] = r->data[r->pos];			\
      r->pos++;								\
    }									\
    return result;							\
  }

#else

#define LABCOMM_DECODE(name, type)					\
206
  static inline type labcomm_read_##name(struct labcomm_reader *r) {	\
Anders Nilsson's avatar
Anders Nilsson committed
207
208
209
    type result; int i;							\
    for (i = 0 ; i < sizeof(type) ; i++) {				\
      if (r->pos >= r->count) {						\
210
	labcomm_reader_fille(r, r->action_context);			\
Anders Nilsson's avatar
Anders Nilsson committed
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
      }									\
      ((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)
227

228
static inline unsigned int labcomm_read_packed32(struct labcomm_reader *r)
229
230
231
232
233
234
235
{
  unsigned int result = 0;
  
  while (1) {
    unsigned char tmp;

    if (r->pos >= r->count) {	
236
      labcomm_reader_fill(r, r->action_context);
Anders Blomdell's avatar
Anders Blomdell committed
237
238
239
      if (r->error != 0) {
	goto out;
      }
240
241
242
243
244
245
246
247
    }
    tmp = r->data[r->pos];
    r->pos++;
    result = (result << 7) | (tmp & 0x7f);
    if ((tmp & 0x80) == 0) { 
      break; 
    }
  }
Anders Blomdell's avatar
Anders Blomdell committed
248
out:
249
250
251
  return result;
}
 
252
static inline char *labcomm_read_string(struct labcomm_reader *r)
Anders Nilsson's avatar
Anders Nilsson committed
253
254
255
256
{
  char *result;
  int length, i; 
  
257
  length = labcomm_read_packed32(r);
Anders Nilsson's avatar
Anders Nilsson committed
258
259
260
  result = malloc(length + 1);
  for (i = 0 ; i < length ; i++) {
    if (r->pos >= r->count) {	
261
      labcomm_reader_fill(r, r->action_context);
Anders Nilsson's avatar
Anders Nilsson committed
262
263
264
265
266
267
268
269
270
271
272
    }
    result[i] = r->data[r->pos];
    r->pos++;
  }
  result[length] = 0;
  return result;
}

/*
 * Semi private encoder declarations
 */
273
typedef int (*labcomm_encoder_function)(
274
  struct labcomm_writer *,
Anders Nilsson's avatar
Anders Nilsson committed
275
  void *value);
276
277
278
279
280
typedef int (*labcomm_encoder_enqueue)(
  struct labcomm_encoder *encoder, 
  void (*action)(struct labcomm_encoder *encoder, 
		 void *context),
  void *context);
281
struct labcomm_writer_action_context;
282
283

struct labcomm_writer_action {
284
285
  int (*alloc)(struct labcomm_writer *w, 
	       struct labcomm_writer_action_context *action_context, 
286
287
	       struct labcomm_encoder *encoder, char *labcomm_version,
	       labcomm_encoder_enqueue enqueue);
288
289
  int (*free)(struct labcomm_writer *w, 
	      struct labcomm_writer_action_context *action_context);
290
291
292
293
294
295
296
297
298
  /* '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
   */
299
300
  int (*start)(struct labcomm_writer *w, 
	       struct labcomm_writer_action_context *action_context,
301
302
	       int index, struct labcomm_signature *signature,
	       void *value);
303
304
305
306
307
308
  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, 
309
	       int index, struct labcomm_signature *signature, 
310
	       uint32_t ioctl_action, va_list args);
311
312
};

313
314
struct labcomm_writer_action_context {
  struct labcomm_writer_action_context *next;
315
  const struct labcomm_writer_action *action;
316
317
318
319
320
  void *context;  
};

struct labcomm_writer {
  struct labcomm_writer_action_context *action_context;
321
322
323
324
325
326
327
  unsigned char *data;
  int data_size;
  int count;
  int pos;
  int error;
};

328
329
330
int labcomm_writer_alloc(struct labcomm_writer *w, 
			 struct labcomm_writer_action_context *action_context, 
			 struct labcomm_encoder *encoder, 
331
332
			 char *labcomm_version,
			 labcomm_encoder_enqueue enqueue);
333
334
335
336
337
338
339
340
341
342
343
344
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, 
345
			 int index, struct labcomm_signature *signature, 
346
347
			 uint32_t ioctl_action, va_list args);

348
int labcomm_internal_encoder_register(
349
350
  struct labcomm_encoder *encoder, 
  struct labcomm_signature *signature, 
351
  labcomm_encoder_function encode);
Anders Nilsson's avatar
Anders Nilsson committed
352

353
int labcomm_internal_encode(
354
355
  struct labcomm_encoder *encoder, 
  struct labcomm_signature *signature, 
356
  labcomm_encoder_function encode,
Anders Nilsson's avatar
Anders Nilsson committed
357
358
  void *value);

359
int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, 
360
				   struct labcomm_signature *signature,
361
				   uint32_t ioctl_action, va_list args);
362

Anders Nilsson's avatar
Anders Nilsson committed
363
364
365
#if __BYTE_ORDER == __LITTLE_ENDIAN

#define LABCOMM_ENCODE(name, type)					\
366
  static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \
Anders Nilsson's avatar
Anders Nilsson committed
367
368
    int i;								\
    for (i = sizeof(type) - 1 ; i >= 0 ; i--) {				\
Oscar Olsson's avatar
Oscar Olsson committed
369
      if (w->pos >= w->count) { /*buffer is full*/			\
370
        int err;							\
371
	err = labcomm_writer_flush(w, w->action_context);		\
372
	if (err != 0) { return err; }					\
Anders Nilsson's avatar
Anders Nilsson committed
373
374
375
376
      }									\
      w->data[w->pos] = ((unsigned char*)(&data))[i];			\
      w->pos++;								\
    }									\
377
    return 0;								\
Anders Nilsson's avatar
Anders Nilsson committed
378
379
380
381
382
  }

#else

#define LABCOMM_ENCODE(name, type)					\
383
  static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \
Anders Nilsson's avatar
Anders Nilsson committed
384
385
386
    int i;								\
    for (i = 0 ; i < sizeof(type) ; i++) {				\
      if (w->pos >= w->count) {						\
387
        int err;							\
388
	err = labcomm_writer_flush(w, w->action_context);		\
389
	if (err != 0) { return err; }					\
Anders Nilsson's avatar
Anders Nilsson committed
390
391
392
393
      }									\
      w->data[w->pos] = ((unsigned char*)(&data))[i];			\
      w->pos++;								\
    }									\
394
    return 0;								\
Anders Nilsson's avatar
Anders Nilsson committed
395
396
397
398
399
400
401
402
403
404
405
  }

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

407
static inline int labcomm_write_packed32(struct labcomm_writer *w, 
408
409
410
411
412
413
414
415
416
417
418
					 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;
419
      err = labcomm_writer_flush(w, w->action_context);	
420
421
422
423
424
425
426
      if (err != 0) { return err; }
    }
    w->data[w->pos++] = tmp[i] | (i?0x80:0x00);
  }
  return 0;
}

427
static inline int labcomm_write_string(struct labcomm_writer *w, char *s)
Anders Nilsson's avatar
Anders Nilsson committed
428
{
429
  int length, i, err; 
Anders Nilsson's avatar
Anders Nilsson committed
430
431

  length = strlen((char*)s);
432
433
  err = labcomm_write_packed32(w, length);
  if (err != 0) { return err; }
Anders Nilsson's avatar
Anders Nilsson committed
434
435
  for (i = 0 ; i < length ; i++) {
    if (w->pos >= w->count) {	
436
      int err;
437
      err = labcomm_writer_flush(w, w->action_context);	
438
      if (err != 0) { return err; }
Anders Nilsson's avatar
Anders Nilsson committed
439
440
441
442
    }
    w->data[w->pos] = s[i];
    w->pos++;
  }
443
  return 0;
Anders Nilsson's avatar
Anders Nilsson committed
444
445
}

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
/*
 * 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(name, kind)		\
  if (name.data) { free(name.data); }				\
  name.data = (kind *)NULL; /* typechecking */

#define LABCOMM_SIGNATURE_ARRAY_REF(name, kind, index)			\
  (name.data = (kind *)name.data, /* typechecking no-op */		\
   (kind *)(labcomm_signature_array_ref(&name.first, &name.last,	\
					(void **)&name.data,		\
					sizeof(kind), index)))

void *labcomm_signature_array_ref(int *first, int *last, void **data,
				  int size, int index);


Anders Nilsson's avatar
Anders Nilsson committed
478
#endif