labcomm_encoder.c 9.5 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 "LabComm20141009"
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
100
101
102
#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,
				   char * pragma_type) {
        struct labcomm_writer *dyn_writer = labcomm_dynamic_buffer_writer_new(
                                                 e->memory);
103
	struct labcomm_encoder *pb = labcomm_encoder_new(dyn_writer,
104
105
106
                                                          e->error,
                                                          e->memory,
                                                          e->scheduler);
107
108
109
110
111
112
113
114
115
	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?
					
116
117
118
119
120
121
	struct pragma_packet_builder* ctxt = labcomm_memory_alloc(
					e->memory,
					1,
					sizeof(struct pragma_packet_builder));
					
	if(ctxt){
122
		ctxt->pragma_type=ptype;
123
124
		ctxt->parent=e;
	}
125
126
127
	pb->context_type = LABCOMM_PRAGMA;
	pb->context = ctxt;
	return pb;
128
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
}

//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:
208
209
  //XXX are these needed, or is that done in encoder_free?
  labcomm_memory_free(e->memory, 1, ctx->pragma_type);  
210
211
212
213
214
215
216
217
  labcomm_memory_free(e->memory, 1, ctx);  
  labcomm_encoder_free(e);
  return err;
}

#endif


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

226
  index = labcomm_get_local_index(signature);
Anders Blomdell's avatar
Anders Blomdell committed
227
228
229
230
231
232
233
234
235
  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
236
  labcomm_write_packed32(e->writer, LABCOMM_SAMPLE_DEF);
237
238
239
240
241
  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
242
243
  labcomm_write_packed32(e->writer, index);
  labcomm_write_string(e->writer, signature->name);
244
  labcomm_write_packed32(e->writer, signature->size);
Anders Blomdell's avatar
Anders Blomdell committed
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  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;
}

int labcomm_internal_encode(
  struct labcomm_encoder *e,
  struct labcomm_signature *signature,
  labcomm_encoder_function encode,
  void *value)
{
265
  int result, index, length;
Anders Blomdell's avatar
Anders Blomdell committed
266

267
  index = labcomm_get_local_index(signature);
268
  length = (signature->encoded_size(value));
Anders Blomdell's avatar
Anders Blomdell committed
269
270
271
272
273
274
  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);
275
  result = labcomm_write_packed32(e->writer, length);
Anders Blomdell's avatar
Anders Blomdell committed
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  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;
312
313
  int index;

314
  index = labcomm_get_local_index(signature);
Anders Blomdell's avatar
Anders Blomdell committed
315
316
  result = labcomm_writer_ioctl(encoder->writer, 
				encoder->writer->action_context, 
317
				index, signature, action, va);
Anders Blomdell's avatar
Anders Blomdell committed
318
319
  return result;
}