/alps/ipecamera

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/ipecamera
277 by Suren A. Chilingaryan
Build RPM
1
#define _DEFAULT_SOURCE
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
2
#define _BSD_SOURCE
3
#define _GNU_SOURCE
4
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <unistd.h>
8
#include <string.h>
9
#include <sys/time.h>
10
#include <pthread.h>
11
#include <assert.h>
12
13
#include <ufodecode.h>
14
245 by Suren A. Chilingaryan
First stand-alone ipecamera implementation
15
#include <pcilib.h>
16
#include <pcilib/tools.h>
17
#include <pcilib/error.h>
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
18
19
#include "private.h"
20
#include "data.h"
21
22
// DS: Currently, on event_id overflow we are assuming the buffer is lost
23
static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) {
24
    pcilib_event_id_t diff;
25
26
    if (evid > ctx->event_id) {
27
	diff = (((pcilib_event_id_t)-1) - ctx->event_id) + evid;
28
	if (diff >= ctx->buffer_size) return -1;
29
    } else {
30
	diff = ctx->event_id - evid;
31
        if (diff >= ctx->buffer_size) return -1;
32
    }
33
    
34
	// DS: Request buffer_size to be power of 2 and replace to shifts (just recompute in set_buffer_size)
35
    return (evid - 1) % ctx->buffer_size;
36
}
37
38
inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
39
    int err = 0;
128 by Suren A. Chilingaryan
Fix handling of return values from frame decoder and event callback
40
    size_t res;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
41
    uint16_t *pixels;
42
    
43
    int buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
44
    if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
45
    
46
    if (ctx->frame[buf_ptr].event.image_ready) return 0;
47
    
48
    if (ctx->frame[buf_ptr].event.info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) {
49
	err = PCILIB_ERROR_INVALID_DATA;
188 by Suren A. Chilingaryan
Handle broken frames in ipecamera
50
	ctx->frame[buf_ptr].event.image_broken = err;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
51
	goto ready;
52
    }
53
	
54
		
55
    pixels = ctx->image + buf_ptr * ctx->image_size;
56
    memset(ctx->cmask + ctx->buffer_pos * ctx->dim.height, 0, ctx->dim.height * sizeof(ipecamera_change_mask_t));
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
57
252 by Suren A. Chilingaryan
Cleanup
58
    ipecamera_debug_buffer(RAW_FRAMES, ctx->frame[buf_ptr].event.raw_size, ctx->buffer + buf_ptr * ctx->padded_size, PCILIB_DEBUG_BUFFER_MKDIR, "raw_frame.%4lu", ctx->event_id);
59
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
60
    res = ufo_decoder_decode_frame(ctx->ipedec, ctx->buffer + buf_ptr * ctx->padded_size, ctx->frame[buf_ptr].event.raw_size, pixels, &ctx->frame[buf_ptr].event.meta);
128 by Suren A. Chilingaryan
Fix handling of return values from frame decoder and event callback
61
    if (!res) {
251 by Suren A. Chilingaryan
Use pcitool debugging API
62
	ipecamera_debug_buffer(BROKEN_FRAMES, ctx->frame[buf_ptr].event.raw_size, ctx->buffer + buf_ptr * ctx->padded_size, PCILIB_DEBUG_BUFFER_MKDIR, "broken_frame.%4lu", ctx->event_id);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
63
        err = PCILIB_ERROR_INVALID_DATA;
188 by Suren A. Chilingaryan
Handle broken frames in ipecamera
64
        ctx->frame[buf_ptr].event.image_broken = err;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
65
	goto ready;
273 by Suren A. Chilingaryan
Fix a bug causing image_broken flag to be checked before it set when preprocessing was enabled
66
    } 
67
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
68
    ctx->frame[buf_ptr].event.image_broken = 0;
69
70
ready:
71
    ctx->frame[buf_ptr].event.image_ready = 1;
72
73
    if (ipecamera_resolve_event_id(ctx, event_id) < 0) {
74
	ctx->frame[buf_ptr].event.image_ready = 0;
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
75
	return PCILIB_ERROR_OVERWRITTEN;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
76
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
77
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
78
    return err;
79
}
80
81
static int ipecamera_get_next_buffer_to_process(ipecamera_t *ctx, pcilib_event_id_t *evid) {
82
    int res;
83
84
    if (ctx->preproc_id == ctx->event_id) return -1;
85
    
86
    if (ctx->preproc) 
87
	pthread_mutex_lock(&ctx->preproc_mutex);
88
	
89
    if (ctx->preproc_id == ctx->event_id) {
90
	if (ctx->preproc)
91
	    pthread_mutex_unlock(&ctx->preproc_mutex);
92
	return -1;
93
    }
94
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
95
    if ((ctx->event_id - ctx->preproc_id) > (ctx->buffer_size - IPECAMERA_RESERVE_BUFFERS)) {
96
	size_t preproc_id = ctx->preproc_id;
97
	ctx->preproc_id = ctx->event_id - (ctx->buffer_size - 1 - IPECAMERA_RESERVE_BUFFERS - 1);
270 by Suren A. Chilingaryan
More lost event debugging
98
	ipecamera_debug(HARDWARE, "Skipping preprocessing of events %zu to %zu as decoding is not fast enough. We are currently %zu buffers beyond, but only %zu buffers are available and safety limit is %zu",
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
99
	    preproc_id, ctx->preproc_id - 1, ctx->event_id - ctx->preproc_id, ctx->buffer_size, IPECAMERA_RESERVE_BUFFERS);
100
    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
101
102
    res = ctx->preproc_id%ctx->buffer_size;
103
104
    if (pthread_rwlock_trywrlock(&ctx->frame[res].mutex)) {
105
	pthread_mutex_unlock(&ctx->preproc_mutex);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
106
	ipecamera_debug(HARDWARE, "Can't lock buffer %i", res);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
107
	return -1;
108
    }
109
    
110
    *evid = ++ctx->preproc_id;
111
112
    if (ctx->preproc)
113
	pthread_mutex_unlock(&ctx->preproc_mutex);
114
115
    return res;
116
}
117
118
119
void *ipecamera_preproc_thread(void *user) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
120
    int err;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
121
    int buf_ptr;
122
    pcilib_event_id_t evid;
123
    
124
    ipecamera_preprocessor_t *preproc = (ipecamera_preprocessor_t*)user;
125
    ipecamera_t *ctx = preproc->ipecamera;
126
    
127
    while (ctx->run_preprocessors) {
128
	buf_ptr = ipecamera_get_next_buffer_to_process(ctx, &evid);
129
	if (buf_ptr < 0) {
130
	    usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
131
	    continue;
132
	}
133
	
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
134
	err = ipecamera_decode_frame(ctx, evid);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
135
	
136
	pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
137
138
#ifdef IPECAMERA_DEBUG_HARDWARE
139
	if (err) {
140
	    switch (err) {
141
	     case PCILIB_ERROR_OVERWRITTEN:
142
		ipecamera_debug(HARDWARE, "The frame (%zu) was overwritten while preprocessing", evid);
143
	     break;
144
	     case PCILIB_ERROR_INVALID_DATA:
145
		ipecamera_debug(HARDWARE, "The frame (%zu) is corrupted, decoding have failed", evid);
146
	     break;
147
	     default:
148
		ipecamera_debug(HARDWARE, "The frame (%zu) is corrupted, decoding have failed", evid);
149
	    }
150
	}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
151
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
152
#endif /* IPECAMERA_DEBUG_HARDWARE */
183 by Suren A. Chilingaryan
Fix re-computation of first processable frame_id
153
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
154
    return NULL;
155
}
156
157
static int ipecamera_get_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
158
    int err;
159
    int buf_ptr = (event_id - 1) % ctx->buffer_size;
273 by Suren A. Chilingaryan
Fix a bug causing image_broken flag to be checked before it set when preprocessing was enabled
160
161
    if (!ctx->preproc) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
162
	pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
163
164
	err = ipecamera_decode_frame(ctx, event_id);
165
166
	if (err) {
167
	    pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
168
	    return err;
169
	}
170
	
171
	return 0;
172
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
173
174
273 by Suren A. Chilingaryan
Fix a bug causing image_broken flag to be checked before it set when preprocessing was enabled
175
    while (!((volatile ipecamera_t*)ctx)->frame[buf_ptr].event.image_ready) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
176
	usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
177
178
	buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
179
	if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
180
    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
181
273 by Suren A. Chilingaryan
Fix a bug causing image_broken flag to be checked before it set when preprocessing was enabled
182
    if (((volatile ipecamera_t*)ctx)->frame[buf_ptr].event.image_broken)
183
	return ctx->frame[buf_ptr].event.image_broken;
184
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
185
    pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
186
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
187
    buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
188
    if ((buf_ptr < 0)||(!ctx->frame[buf_ptr].event.image_ready)) {
189
	pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
190
	return PCILIB_ERROR_OVERWRITTEN;
191
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
192
193
    return 0;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
194
}
195
196
197
/*
198
 We will lock the data for non-raw data to prevent ocasional overwritting. The 
199
 raw data will be overwritten by the reader thread anyway and we can't do 
200
 anything to prevent it for performance reasons.
201
*/
202
int ipecamera_get(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **ret) {
203
    int err;
204
    int buf_ptr;
205
    size_t raw_size;
206
    ipecamera_t *ctx = (ipecamera_t*)vctx;
207
208
    void *data = *ret;
209
210
    if (!ctx) {
211
	pcilib_error("IPECamera imaging is not initialized");
212
	return PCILIB_ERROR_NOTINITIALIZED;
213
    }
183 by Suren A. Chilingaryan
Fix re-computation of first processable frame_id
214
262 by Suren A. Chilingaryan
Introduce API debugging
215
    ipecamera_debug(API, "ipecamera: get (data)");
216
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
217
    buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
268 by Suren A. Chilingaryan
Add few warning about problems with frames
218
    if (buf_ptr < 0) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
219
	ipecamera_debug(HARDWARE, "The data of the requested frame %zu has been meanwhile overwritten", event_id);
268 by Suren A. Chilingaryan
Add few warning about problems with frames
220
	return PCILIB_ERROR_OVERWRITTEN;
221
    }
222
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
223
    switch ((ipecamera_data_type_t)data_type) {
224
	case IPECAMERA_RAW_DATA:
225
	    raw_size = ctx->frame[buf_ptr].event.raw_size;
226
	    if (data) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
227
		if ((!size)||(*size < raw_size)) {
228
		    pcilib_warning("The raw data associated with frame %zu is too big (%zu bytes) for user supplied buffer (%zu bytes)", event_id, raw_size, (size?*size:0));
229
		    return PCILIB_ERROR_TOOBIG;
230
		}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
231
		memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
232
		if (ipecamera_resolve_event_id(ctx, event_id) < 0) {
233
		    ipecamera_debug(HARDWARE, "The data of requested frame %zu was overwritten while copying", event_id);
234
		    return PCILIB_ERROR_OVERWRITTEN;
235
		}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
236
		*size = raw_size;
237
		return 0;
238
	    }
239
	    if (size) *size = raw_size;
240
	    *ret = ctx->buffer + buf_ptr * ctx->padded_size;
241
	    return 0;
242
	case IPECAMERA_IMAGE_DATA:
243
	    err = ipecamera_get_frame(ctx, event_id);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
244
	    if (err) {
245
#ifdef IPECAMERA_DEBUG_HARDWARE
246
		switch (err) {
247
	         case PCILIB_ERROR_OVERWRITTEN:
248
		    ipecamera_debug(HARDWARE, "The requested frame (%zu) was overwritten", event_id);
249
		    break;
250
	         case PCILIB_ERROR_INVALID_DATA:
251
		    ipecamera_debug(HARDWARE, "The requested frame (%zu) is corrupted", event_id);
252
		    break;
253
		 default:
254
		    ipecamera_debug(HARDWARE, "Error getting the data associated with the requested frame (%zu), error %i", event_id, err);
255
		}
256
#endif /* IPECAMERA_DEBUG_HARDWARE */
257
		return err;
258
	    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
259
260
	    if (data) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
261
		if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) {
262
		    pcilib_warning("The image associated with frame %zu is too big (%zu bytes) for user supplied buffer (%zu bytes)", event_id, ctx->image_size * sizeof(ipecamera_pixel_t), (size?*size:0));
263
		    return PCILIB_ERROR_TOOBIG;
264
		}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
265
		memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t));
266
		pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
267
		*size =  ctx->image_size * sizeof(ipecamera_pixel_t);
268
		return 0;
269
	    }
270
	
271
	    if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t);
272
	    *ret = ctx->image + buf_ptr * ctx->image_size;
273
	    return 0;
274
	case IPECAMERA_CHANGE_MASK:
275
	    err = ipecamera_get_frame(ctx, event_id);
276
	    if (err) return err;
277
278
	    if (data) {
279
		if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return PCILIB_ERROR_TOOBIG;
280
		memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t));
281
		pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
282
		*size =  ctx->dim.height * sizeof(ipecamera_change_mask_t);
283
		return 0;
284
	    }
285
286
	    if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t);
287
	    *ret = ctx->cmask + buf_ptr * ctx->dim.height;
288
	    return 0;
289
	case IPECAMERA_DIMENSIONS:
290
	    if (size) *size = sizeof(ipecamera_image_dimensions_t);
291
	    ret = (void*)&ctx->dim;
292
	    return 0;
293
	case IPECAMERA_IMAGE_REGION:
294
	case IPECAMERA_PACKED_IMAGE:
295
	    // Shall we return complete image or only changed parts?
296
	case IPECAMERA_PACKED_LINE:
297
	case IPECAMERA_PACKED_PAYLOAD:
298
	    pcilib_error("Support for data type (%li) is not implemented yet", data_type);
299
	    return PCILIB_ERROR_NOTSUPPORTED;
300
	default:
301
	    pcilib_error("Unknown data type (%li) is requested", data_type);
302
	    return PCILIB_ERROR_INVALID_REQUEST;
303
    }
304
}
305
306
307
/*
308
 We will unlock non-raw data and check if the raw data is not overwritten yet
309
*/
310
int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) {
311
    ipecamera_t *ctx = (ipecamera_t*)vctx;
312
313
    if (!ctx) {
314
	pcilib_error("IPECamera imaging is not initialized");
315
	return PCILIB_ERROR_NOTINITIALIZED;
316
317
    }
318
319
    if ((ipecamera_data_type_t)data_type == IPECAMERA_RAW_DATA) {
320
	if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN;
321
    } else {
322
	int buf_ptr = (event_id - 1) % ctx->buffer_size;
323
	pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
324
    }
325
262 by Suren A. Chilingaryan
Introduce API debugging
326
    ipecamera_debug(API, "ipecamera: return (data)");
327
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
328
    return 0;
329
}