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

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

69
70
71
/*
 * Semi private lock declarations
 */
72
73
74
75
76
77
78
79
80
struct labcomm_lock_action {
  int (*alloc)(void *context);
  int (*free)(void *context);
  int (*read_lock)(void *context);
  int (*read_unlock)(void *context);
  int (*write_lock)(void *context);
  int (*write_unlock)(void *context);
};

81
struct labcomm_lock {
82
  const struct labcomm_lock_action action;
83
84
};

Anders Nilsson's avatar
Anders Nilsson committed
85
86
87
/*
 * Semi private decoder declarations
 */
88
typedef void (*labcomm_handler_function)(void *value, void *context);
Anders Nilsson's avatar
Anders Nilsson committed
89

90
typedef void (*labcomm_decoder_function)(
91
  struct labcomm_reader *r,
92
93
  labcomm_handler_function handler,
  void *context);
Anders Nilsson's avatar
Anders Nilsson committed
94

95
96
struct labcomm_reader_action_context;

97
struct labcomm_reader_action {
98
99
  int (*alloc)(struct labcomm_reader *r, 
	       struct labcomm_reader_action_context *action_context, 
100
	       struct labcomm_decoder *decoder, char *labcomm_version);
101
102
103
104
105
106
107
108
109
110
  int (*free)(struct labcomm_reader *r, 
	      struct labcomm_reader_action_context *action_context);
  int (*start)(struct labcomm_reader *r, 
	       struct labcomm_reader_action_context *action_context);
  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,
111
	       int signature_index, struct labcomm_signature *signature, 
112
	       uint32_t ioctl_action, va_list args);
113
114
};

115
116
struct labcomm_reader_action_context {
  struct labcomm_reader_action_context *next;
117
  const struct labcomm_reader_action *action;
118
119
120
121
122
  void *context;  
};

struct labcomm_reader {
  struct labcomm_reader_action_context *action_context;
123
124
125
126
127
128
129
  unsigned char *data;
  int data_size;
  int count;
  int pos;
  int error;
};

130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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, 
			 struct labcomm_reader_action_context *action_context);
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 signature_index, 
			 struct labcomm_signature *signature, 
			 uint32_t ioctl_action, va_list args);
147

Anders Nilsson's avatar
Anders Nilsson committed
148
149
150
151
152
/*
 * Non typesafe registration function to be called from
 * generated labcomm_decoder_register_* functions.
 */
void labcomm_internal_decoder_register(
153
154
155
156
  struct labcomm_decoder *d, 
  struct labcomm_signature *s, 
  labcomm_decoder_function decoder,
  labcomm_handler_function handler,
Anders Nilsson's avatar
Anders Nilsson committed
157
158
  void *context);

159
int labcomm_internal_decoder_ioctl(struct labcomm_decoder *decoder, 
160
				   struct labcomm_signature *signature,
161
				   uint32_t ioctl_action, va_list args);
162

Anders Nilsson's avatar
Anders Nilsson committed
163
164
165
#if __BYTE_ORDER == __LITTLE_ENDIAN

#define LABCOMM_DECODE(name, type)					\
166
  static inline type labcomm_read_##name(struct labcomm_reader *r) {	\
Anders Nilsson's avatar
Anders Nilsson committed
167
168
169
    type result; int i;							\
    for (i = sizeof(type) - 1 ; i >= 0 ; i--) {				\
      if (r->pos >= r->count) {						\
170
	labcomm_reader_fill(r, r->action_context);			\
Anders Nilsson's avatar
Anders Nilsson committed
171
172
173
174
175
176
177
178
179
180
      }									\
      ((unsigned char*)(&result))[i] = r->data[r->pos];			\
      r->pos++;								\
    }									\
    return result;							\
  }

#else

#define LABCOMM_DECODE(name, type)					\
181
  static inline type labcomm_read_##name(struct labcomm_reader *r) {	\
Anders Nilsson's avatar
Anders Nilsson committed
182
183
184
    type result; int i;							\
    for (i = 0 ; i < sizeof(type) ; i++) {				\
      if (r->pos >= r->count) {						\
185
	labcomm_reader_fille(r, r->action_context);			\
Anders Nilsson's avatar
Anders Nilsson committed
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
      }									\
      ((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)
202

203
static inline unsigned int labcomm_read_packed32(struct labcomm_reader *r)
204
205
206
207
208
209
210
{
  unsigned int result = 0;
  
  while (1) {
    unsigned char tmp;

    if (r->pos >= r->count) {	
211
      labcomm_reader_fill(r, r->action_context);
Anders Blomdell's avatar
Anders Blomdell committed
212
213
214
      if (r->error != 0) {
	goto out;
      }
215
216
217
218
219
220
221
222
    }
    tmp = r->data[r->pos];
    r->pos++;
    result = (result << 7) | (tmp & 0x7f);
    if ((tmp & 0x80) == 0) { 
      break; 
    }
  }
Anders Blomdell's avatar
Anders Blomdell committed
223
out:
224
225
226
  return result;
}
 
227
static inline char *labcomm_read_string(struct labcomm_reader *r)
Anders Nilsson's avatar
Anders Nilsson committed
228
229
230
231
{
  char *result;
  int length, i; 
  
232
  length = labcomm_read_packed32(r);
Anders Nilsson's avatar
Anders Nilsson committed
233
234
235
  result = malloc(length + 1);
  for (i = 0 ; i < length ; i++) {
    if (r->pos >= r->count) {	
236
      labcomm_reader_fill(r, r->action_context);
Anders Nilsson's avatar
Anders Nilsson committed
237
238
239
240
241
242
243
244
245
246
247
    }
    result[i] = r->data[r->pos];
    r->pos++;
  }
  result[length] = 0;
  return result;
}

/*
 * Semi private encoder declarations
 */
248
typedef int (*labcomm_encoder_function)(
249
  struct labcomm_writer *,
Anders Nilsson's avatar
Anders Nilsson committed
250
  void *value);
251
struct labcomm_writer_action_context;
252
253

struct labcomm_writer_action {
254
255
  int (*alloc)(struct labcomm_writer *w, 
	       struct labcomm_writer_action_context *action_context, 
256
	       struct labcomm_encoder *encoder, char *labcomm_version);
257
258
259
260
  int (*free)(struct labcomm_writer *w, 
	      struct labcomm_writer_action_context *action_context);
  int (*start)(struct labcomm_writer *w, 
	       struct labcomm_writer_action_context *action_context,
261
262
263
	       struct labcomm_encoder *encoder,
	       int index, struct labcomm_signature *signature,
	       void *value);
264
265
266
267
268
269
  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, 
270
	       int signature_index, struct labcomm_signature *signature, 
271
	       uint32_t ioctl_action, va_list args);
272
273
};

274
275
struct labcomm_writer_action_context {
  struct labcomm_writer_action_context *next;
276
  const struct labcomm_writer_action *action;
277
278
279
280
281
  void *context;  
};

struct labcomm_writer {
  struct labcomm_writer_action_context *action_context;
282
283
284
285
286
287
288
  unsigned char *data;
  int data_size;
  int count;
  int pos;
  int error;
};

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
int labcomm_writer_alloc(struct labcomm_writer *w, 
			 struct labcomm_writer_action_context *action_context, 
			 struct labcomm_encoder *encoder, 
			 char *labcomm_version);
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,
			 struct labcomm_encoder *encoder,
			 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, 
			 int signature_index, 
			 struct labcomm_signature *signature, 
			 uint32_t ioctl_action, va_list args);

Anders Nilsson's avatar
Anders Nilsson committed
310
void labcomm_internal_encoder_register(
311
312
  struct labcomm_encoder *encoder, 
  struct labcomm_signature *signature, 
313
  labcomm_encoder_function encode);
Anders Nilsson's avatar
Anders Nilsson committed
314

315
int labcomm_internal_encode(
316
317
  struct labcomm_encoder *encoder, 
  struct labcomm_signature *signature, 
318
  labcomm_encoder_function encode,
Anders Nilsson's avatar
Anders Nilsson committed
319
320
  void *value);

321

322
int labcomm_internal_encoder_ioctl(struct labcomm_encoder *encoder, 
323
				   struct labcomm_signature *signature,
324
				   uint32_t ioctl_action, va_list args);
325

Anders Nilsson's avatar
Anders Nilsson committed
326
327
328
#if __BYTE_ORDER == __LITTLE_ENDIAN

#define LABCOMM_ENCODE(name, type)					\
329
  static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \
Anders Nilsson's avatar
Anders Nilsson committed
330
331
    int i;								\
    for (i = sizeof(type) - 1 ; i >= 0 ; i--) {				\
Oscar Olsson's avatar
Oscar Olsson committed
332
      if (w->pos >= w->count) { /*buffer is full*/			\
333
        int err;							\
334
	err = labcomm_writer_flush(w, w->action_context);		\
335
	if (err != 0) { return err; }					\
Anders Nilsson's avatar
Anders Nilsson committed
336
337
338
339
      }									\
      w->data[w->pos] = ((unsigned char*)(&data))[i];			\
      w->pos++;								\
    }									\
340
    return 0;								\
Anders Nilsson's avatar
Anders Nilsson committed
341
342
343
344
345
  }

#else

#define LABCOMM_ENCODE(name, type)					\
346
  static inline int labcomm_write_##name(struct labcomm_writer *w, type data) { \
Anders Nilsson's avatar
Anders Nilsson committed
347
348
349
    int i;								\
    for (i = 0 ; i < sizeof(type) ; i++) {				\
      if (w->pos >= w->count) {						\
350
        int err;							\
351
	err = labcomm_writer_flush(w, w->action_context);		\
352
	if (err != 0) { return err; }					\
Anders Nilsson's avatar
Anders Nilsson committed
353
354
355
356
      }									\
      w->data[w->pos] = ((unsigned char*)(&data))[i];			\
      w->pos++;								\
    }									\
357
    return 0;								\
Anders Nilsson's avatar
Anders Nilsson committed
358
359
360
361
362
363
364
365
366
367
368
  }

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

370
static inline int labcomm_write_packed32(struct labcomm_writer *w, 
371
372
373
374
375
376
377
378
379
380
381
					 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;
382
      err = labcomm_writer_flush(w, w->action_context);	
383
384
385
386
387
388
389
      if (err != 0) { return err; }
    }
    w->data[w->pos++] = tmp[i] | (i?0x80:0x00);
  }
  return 0;
}

390
static inline int labcomm_write_string(struct labcomm_writer *w, char *s)
Anders Nilsson's avatar
Anders Nilsson committed
391
{
392
  int length, i, err; 
Anders Nilsson's avatar
Anders Nilsson committed
393
394

  length = strlen((char*)s);
395
396
  err = labcomm_write_packed32(w, length);
  if (err != 0) { return err; }
Anders Nilsson's avatar
Anders Nilsson committed
397
398
  for (i = 0 ; i < length ; i++) {
    if (w->pos >= w->count) {	
399
      int err;
400
      err = labcomm_writer_flush(w, w->action_context);	
401
      if (err != 0) { return err; }
Anders Nilsson's avatar
Anders Nilsson committed
402
403
404
405
    }
    w->data[w->pos] = s[i];
    w->pos++;
  }
406
  return 0;
Anders Nilsson's avatar
Anders Nilsson committed
407
408
}

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/*
 * 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
441
#endif