/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) {
280 by Suren A. Chilingaryan
Fix minor error in rarely used path
82
    int err, res;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
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
280 by Suren A. Chilingaryan
Fix minor error in rarely used path
104
    if ((err = pthread_rwlock_trywrlock(&ctx->frame[res].mutex)) != 0) {
105
	if (ctx->preproc)
106
	    pthread_mutex_unlock(&ctx->preproc_mutex);
107
	ipecamera_debug(HARDWARE, "Can't lock buffer %i, errno %i", res, err);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
108
	return -1;
109
    }
110
    
111
    *evid = ++ctx->preproc_id;
112
113
    if (ctx->preproc)
114
	pthread_mutex_unlock(&ctx->preproc_mutex);
115
116
    return res;
117
}
118
119
120
void *ipecamera_preproc_thread(void *user) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
121
    int err;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
122
    int buf_ptr;
123
    pcilib_event_id_t evid;
124
    
125
    ipecamera_preprocessor_t *preproc = (ipecamera_preprocessor_t*)user;
126
    ipecamera_t *ctx = preproc->ipecamera;
127
    
128
    while (ctx->run_preprocessors) {
129
	buf_ptr = ipecamera_get_next_buffer_to_process(ctx, &evid);
130
	if (buf_ptr < 0) {
131
	    usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
132
	    continue;
133
	}
134
	
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
135
	err = ipecamera_decode_frame(ctx, evid);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
136
	
137
	pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
138
139
#ifdef IPECAMERA_DEBUG_HARDWARE
140
	if (err) {
141
	    switch (err) {
142
	     case PCILIB_ERROR_OVERWRITTEN:
143
		ipecamera_debug(HARDWARE, "The frame (%zu) was overwritten while preprocessing", evid);
144
	     break;
145
	     case PCILIB_ERROR_INVALID_DATA:
146
		ipecamera_debug(HARDWARE, "The frame (%zu) is corrupted, decoding have failed", evid);
147
	     break;
148
	     default:
149
		ipecamera_debug(HARDWARE, "The frame (%zu) is corrupted, decoding have failed", evid);
150
	    }
151
	}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
152
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
153
#endif /* IPECAMERA_DEBUG_HARDWARE */
183 by Suren A. Chilingaryan
Fix re-computation of first processable frame_id
154
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
155
    return NULL;
156
}
157
158
static int ipecamera_get_frame(ipecamera_t *ctx, pcilib_event_id_t event_id) {
159
    int err;
160
    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
161
162
    if (!ctx->preproc) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
163
	pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
164
165
	err = ipecamera_decode_frame(ctx, event_id);
166
167
	if (err) {
168
	    pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
169
	    return err;
170
	}
171
	
172
	return 0;
173
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
174
175
273 by Suren A. Chilingaryan
Fix a bug causing image_broken flag to be checked before it set when preprocessing was enabled
176
    while (!((volatile ipecamera_t*)ctx)->frame[buf_ptr].event.image_ready) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
177
	usleep(IPECAMERA_NOFRAME_PREPROC_SLEEP);
178
179
	buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
180
	if (buf_ptr < 0) return PCILIB_ERROR_OVERWRITTEN;
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
181
    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
182
273 by Suren A. Chilingaryan
Fix a bug causing image_broken flag to be checked before it set when preprocessing was enabled
183
    if (((volatile ipecamera_t*)ctx)->frame[buf_ptr].event.image_broken)
184
	return ctx->frame[buf_ptr].event.image_broken;
185
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
186
    pthread_rwlock_rdlock(&ctx->frame[buf_ptr].mutex);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
187
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
188
    buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
189
    if ((buf_ptr < 0)||(!ctx->frame[buf_ptr].event.image_ready)) {
190
	pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
191
	return PCILIB_ERROR_OVERWRITTEN;
192
    }
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
193
194
    return 0;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
195
}
196
197
198
/*
199
 We will lock the data for non-raw data to prevent ocasional overwritting. The 
200
 raw data will be overwritten by the reader thread anyway and we can't do 
201
 anything to prevent it for performance reasons.
202
*/
203
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) {
204
    int err;
205
    int buf_ptr;
206
    size_t raw_size;
207
    ipecamera_t *ctx = (ipecamera_t*)vctx;
208
209
    void *data = *ret;
210
211
    if (!ctx) {
212
	pcilib_error("IPECamera imaging is not initialized");
213
	return PCILIB_ERROR_NOTINITIALIZED;
214
    }
183 by Suren A. Chilingaryan
Fix re-computation of first processable frame_id
215
262 by Suren A. Chilingaryan
Introduce API debugging
216
    ipecamera_debug(API, "ipecamera: get (data)");
217
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
218
    buf_ptr = ipecamera_resolve_event_id(ctx, event_id);
268 by Suren A. Chilingaryan
Add few warning about problems with frames
219
    if (buf_ptr < 0) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
220
	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
221
	return PCILIB_ERROR_OVERWRITTEN;
222
    }
223
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
224
    switch ((ipecamera_data_type_t)data_type) {
225
	case IPECAMERA_RAW_DATA:
226
	    raw_size = ctx->frame[buf_ptr].event.raw_size;
227
	    if (data) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
228
		if ((!size)||(*size < raw_size)) {
229
		    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));
230
		    return PCILIB_ERROR_TOOBIG;
231
		}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
232
		memcpy(data, ctx->buffer + buf_ptr * ctx->padded_size, raw_size);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
233
		if (ipecamera_resolve_event_id(ctx, event_id) < 0) {
234
		    ipecamera_debug(HARDWARE, "The data of requested frame %zu was overwritten while copying", event_id);
235
		    return PCILIB_ERROR_OVERWRITTEN;
236
		}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
237
		*size = raw_size;
238
		return 0;
239
	    }
240
	    if (size) *size = raw_size;
241
	    *ret = ctx->buffer + buf_ptr * ctx->padded_size;
242
	    return 0;
243
	case IPECAMERA_IMAGE_DATA:
244
	    err = ipecamera_get_frame(ctx, event_id);
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
245
	    if (err) {
246
#ifdef IPECAMERA_DEBUG_HARDWARE
247
		switch (err) {
248
	         case PCILIB_ERROR_OVERWRITTEN:
249
		    ipecamera_debug(HARDWARE, "The requested frame (%zu) was overwritten", event_id);
250
		    break;
251
	         case PCILIB_ERROR_INVALID_DATA:
252
		    ipecamera_debug(HARDWARE, "The requested frame (%zu) is corrupted", event_id);
253
		    break;
254
		 default:
255
		    ipecamera_debug(HARDWARE, "Error getting the data associated with the requested frame (%zu), error %i", event_id, err);
256
		}
257
#endif /* IPECAMERA_DEBUG_HARDWARE */
258
		return err;
259
	    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
260
261
	    if (data) {
269 by Suren A. Chilingaryan
Improve debugging of dropped frames
262
		if ((!size)||(*size < ctx->image_size * sizeof(ipecamera_pixel_t))) {
263
		    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));
264
		    return PCILIB_ERROR_TOOBIG;
265
		}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
266
		memcpy(data, ctx->image + buf_ptr * ctx->image_size, ctx->image_size * sizeof(ipecamera_pixel_t));
267
		pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
268
		*size =  ctx->image_size * sizeof(ipecamera_pixel_t);
269
		return 0;
270
	    }
271
	
272
	    if (size) *size = ctx->image_size * sizeof(ipecamera_pixel_t);
273
	    *ret = ctx->image + buf_ptr * ctx->image_size;
274
	    return 0;
275
	case IPECAMERA_CHANGE_MASK:
276
	    err = ipecamera_get_frame(ctx, event_id);
277
	    if (err) return err;
278
279
	    if (data) {
280
		if ((!size)||(*size < ctx->dim.height * sizeof(ipecamera_change_mask_t))) return PCILIB_ERROR_TOOBIG;
281
		memcpy(data, ctx->image + buf_ptr * ctx->dim.height, ctx->dim.height * sizeof(ipecamera_change_mask_t));
282
		pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
283
		*size =  ctx->dim.height * sizeof(ipecamera_change_mask_t);
284
		return 0;
285
	    }
286
287
	    if (size) *size = ctx->dim.height * sizeof(ipecamera_change_mask_t);
288
	    *ret = ctx->cmask + buf_ptr * ctx->dim.height;
289
	    return 0;
290
	case IPECAMERA_DIMENSIONS:
291
	    if (size) *size = sizeof(ipecamera_image_dimensions_t);
292
	    ret = (void*)&ctx->dim;
293
	    return 0;
294
	case IPECAMERA_IMAGE_REGION:
295
	case IPECAMERA_PACKED_IMAGE:
296
	    // Shall we return complete image or only changed parts?
297
	case IPECAMERA_PACKED_LINE:
298
	case IPECAMERA_PACKED_PAYLOAD:
299
	    pcilib_error("Support for data type (%li) is not implemented yet", data_type);
300
	    return PCILIB_ERROR_NOTSUPPORTED;
301
	default:
302
	    pcilib_error("Unknown data type (%li) is requested", data_type);
303
	    return PCILIB_ERROR_INVALID_REQUEST;
304
    }
305
}
306
307
308
/*
309
 We will unlock non-raw data and check if the raw data is not overwritten yet
310
*/
311
int ipecamera_return(pcilib_context_t *vctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) {
312
    ipecamera_t *ctx = (ipecamera_t*)vctx;
313
314
    if (!ctx) {
315
	pcilib_error("IPECamera imaging is not initialized");
316
	return PCILIB_ERROR_NOTINITIALIZED;
317
318
    }
319
320
    if ((ipecamera_data_type_t)data_type == IPECAMERA_RAW_DATA) {
321
	if (ipecamera_resolve_event_id(ctx, event_id) < 0) return PCILIB_ERROR_OVERWRITTEN;
322
    } else {
323
	int buf_ptr = (event_id - 1) % ctx->buffer_size;
324
	pthread_rwlock_unlock(&ctx->frame[buf_ptr].mutex);
325
    }
326
262 by Suren A. Chilingaryan
Introduce API debugging
327
    ipecamera_debug(API, "ipecamera: return (data)");
328
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
329
    return 0;
330
}