/alps/ipecamera

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/ipecamera
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
1
#define _BSD_SOURCE
2
#define _GNU_SOURCE
3
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <unistd.h>
7
#include <string.h>
8
#include <sys/time.h>
9
#include <pthread.h>
10
#include <assert.h>
11
12
#include <ufodecode.h>
13
245 by Suren A. Chilingaryan
First stand-alone ipecamera implementation
14
#include <pcilib.h>
15
#include <pcilib/tools.h>
16
#include <pcilib/error.h>
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
17
18
#include "private.h"
19
#include "data.h"
20
21
// DS: Currently, on event_id overflow we are assuming the buffer is lost
22
static int ipecamera_resolve_event_id(ipecamera_t *ctx, pcilib_event_id_t evid) {
23
    pcilib_event_id_t diff;
24
25
    if (evid > ctx->event_id) {
26
	diff = (((pcilib_event_id_t)-1) - ctx->event_id) + evid;
27
	if (diff >= ctx->buffer_size) return -1;
28
    } else {
29
	diff = ctx->event_id - evid;
30
        if (diff >= ctx->buffer_size) return -1;
31
    }
32
    
33
	// DS: Request buffer_size to be power of 2 and replace to shifts (just recompute in set_buffer_size)
34
    return (evid - 1) % ctx->buffer_size;
35
}
36
37
inline static int ipecamera_decode_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
38
    int err = 0;
128 by Suren A. Chilingaryan
Fix handling of return values from frame decoder and event callback
39
    size_t res;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
40
    uint16_t *pixels;
41
    
42
    int buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
43
    if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
44
    
45
    if (ctx->frame[buf_ptr].event.image_ready) return 0;
46
    
47
    if (ctx->frame[buf_ptr].event.info.flags&PCILIB_EVENT_INFO_FLAG_BROKEN) {
48
	err = PCILIB_ERROR_INVALID_DATA;
188 by Suren A. Chilingaryan
Handle broken frames in ipecamera
49
	ctx->frame[buf_ptr].event.image_broken = err;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
50
	goto ready;
51
    }
52
	
53
		
54
    pixels = ctx->image + buf_ptr * ctx->image_size;
55
    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
56
252 by Suren A. Chilingaryan
Cleanup
57
    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);
58
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
59
    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
60
    if (!res) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
61
	ipecamera_debug(HARDWARE, "Decoding of frame %u has failed, ufodecode returns error %i", ctx->event_id, 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;
66
    }
67
	    
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;
160
    
188 by Suren A. Chilingaryan
Handle broken frames in ipecamera
161
    if (ctx->preproc) {	
162
	if (ctx->frame[buf_ptr].event.image_broken)
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
163
	    return ctx->frame[buf_ptr].event.image_broken;
188 by Suren A. Chilingaryan
Handle broken frames in ipecamera
164
    } else {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
165
	pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
166
167
	err = ipecamera_decode_frame(ctx, event_id);
168
169
	if (err) {
170
	    pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
171
	    return err;
172
	}
173
	
174
	return 0;
175
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
176
177
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
178
    while (!ctx->frame[buf_ptr].event.image_ready) {
179
	usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
180
181
	buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
182
	if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
183
    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
184
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
}