/alps/ipecamera

To get this branch, use:
bzr branch http://suren.me/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>
185 by Suren A. Chilingaryan
More fixes to frame separation in multiframe mode; debugging mode
9
#include <sys/stat.h>
10
#include <sys/types.h>
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
11
#include <pthread.h>
12
#include <assert.h>
13
14
#include <ufodecode.h>
15
245 by Suren A. Chilingaryan
First stand-alone ipecamera implementation
16
#include <pcilib.h>
17
#include <pcilib/tools.h>
18
#include <pcilib/error.h>
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
19
162 by Suren A. Chilingaryan
UFO5 size estimation
20
#include "model.h"
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
21
#include "private.h"
22
#include "reader.h"
23
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
24
//#define CHECK_FRAME_MAGIC(buf) \
25
//	memcmp(buf, ((void*)frame_magic) + 1, sizeof(frame_magic) - 1)
26
27
#define CHECK_FRAME_MAGIC(buf) \
28
	memcmp(((ipecamera_payload_t*)(buf)) + 1, &frame_magic[1], sizeof(frame_magic) - sizeof(ipecamera_payload_t))
29
30
static ipecamera_payload_t frame_magic[3] = { 0x51111111, 0x52222222, 0x53333333 };
31
32
33
34
int ipecamera_compute_buffer_size(ipecamera_t *ctx, ipecamera_format_t format, size_t header_size, size_t lines) {
35
//    const size_t header_size = 8 * sizeof(ipecamera_payload_t);
36
    const size_t footer_size = CMOSIS_FRAME_TAIL_SIZE;
37
38
    size_t max_channels;
175 by Suren A. Chilingaryan
Support both UFO4 and UFO5 frame formats
39
    size_t line_size, raw_size, padded_blocks;
40
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
41
    switch (format) {
42
     case IPECAMERA_FORMAT_CMOSIS:
43
	max_channels = CMOSIS_MAX_CHANNELS;
44
	line_size = (1 + CMOSIS_PIXELS_PER_CHANNEL) * 32; 
45
	break;
46
     case IPECAMERA_FORMAT_CMOSIS20:
47
	max_channels = CMOSIS20_MAX_CHANNELS;
48
	line_size = (1 + CMOSIS20_PIXELS_PER_CHANNEL) * 32 / 2;
49
	break;
175 by Suren A. Chilingaryan
Support both UFO4 and UFO5 frame formats
50
     default:
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
51
	pcilib_warning("Unsupported version (%u) of frame format...", format);
52
	return PCILIB_ERROR_NOTSUPPORTED;
53
    }
54
55
    raw_size = lines * line_size;
56
    raw_size *= max_channels / ctx->cmosis_outputs;
57
    raw_size += header_size + footer_size;
248 by Suren A. Chilingaryan
Support CMOSIS bug resulting in missing payload
58
59
#ifdef IPECAMERA_BUG_MISSING_PAYLOAD
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
60
        // As I understand, the first 32-byte packet is missing, so we need to substract 32 (both CMOSIS and CMOSIS20)
61
    raw_size -= 32;
248 by Suren A. Chilingaryan
Support CMOSIS bug resulting in missing payload
62
#endif /* IPECAMERA_BUG_MISSING_PAYLOAD */
168 by Suren A. Chilingaryan
Support 12-bit modes
63
64
    padded_blocks = raw_size / IPECAMERA_DMA_PACKET_LENGTH + ((raw_size % IPECAMERA_DMA_PACKET_LENGTH)?1:0);
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
65
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
66
    ctx->roi_raw_size = raw_size;
67
    ctx->roi_padded_size = padded_blocks * IPECAMERA_DMA_PACKET_LENGTH;
168 by Suren A. Chilingaryan
Support 12-bit modes
68
162 by Suren A. Chilingaryan
UFO5 size estimation
69
    return 0;
70
}
71
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
72
73
static int ipecamera_parse_header(ipecamera_t *ctx, ipecamera_payload_t *buf, size_t buf_size) {
74
    int last = buf[0] & 1;
75
    int version = (buf[0] >> 1) & 7;
76
    size_t size = 0, n_lines;
77
    ipecamera_format_t format = IPECAMERA_FORMAT_CMOSIS;
78
79
    switch (version) {
80
     case 0:
81
	n_lines = ((uint32_t*)buf)[5] & 0x7FF;
82
	ctx->frame[ctx->buffer_pos].event.info.seqnum = buf[6] & 0xFFFFFF;
83
	ctx->frame[ctx->buffer_pos].event.info.offset = (buf[7] & 0xFFFFFF) * 80;
84
	break;
85
     case 1:
86
	n_lines = ((uint32_t*)buf)[5] & 0xFFFF;
87
	if (!n_lines) {
88
	    pcilib_error("The frame header claims 0 lines in the data");
89
	    return 0;
90
	}
91
92
	ctx->frame[ctx->buffer_pos].event.info.seqnum = buf[6] & 0xFFFFFF;
93
	ctx->frame[ctx->buffer_pos].event.info.offset = (buf[7] & 0xFFFFFF) * 80;
94
	format = (buf[6] >> 24)&0x0F;
95
        break;
96
     default:
97
	ipecamera_debug(HARDWARE, "Incorrect version of the frame header, ignoring broken data...");
98
	return 0;
99
    }
100
    gettimeofday(&ctx->frame[ctx->buffer_pos].event.info.timestamp, NULL);
101
102
    ipecamera_debug(FRAME_HEADERS, "frame %lu: %x %x %x %x", ctx->frame[ctx->buffer_pos].event.info.seqnum, buf[0], buf[1], buf[2], buf[3]);
103
    ipecamera_debug(FRAME_HEADERS, "frame %lu: %x %x %x %x", ctx->frame[ctx->buffer_pos].event.info.seqnum, buf[4], buf[5], buf[6], buf[7]);
104
105
    while ((!last)&&((size + CMOSIS_FRAME_HEADER_SIZE) <= buf_size)) {
106
	size += CMOSIS_FRAME_HEADER_SIZE;
107
	last = buf[size] & 1;
108
    }
109
110
    size += CMOSIS_FRAME_HEADER_SIZE;
111
    ipecamera_compute_buffer_size(ctx, format, size, n_lines);
112
113
	// Returns total size of found headers or 0 on the error
114
    return size;
115
}
116
117
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
118
static inline int ipecamera_new_frame(ipecamera_t *ctx) {
119
    ctx->frame[ctx->buffer_pos].event.raw_size = ctx->cur_size;
120
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
121
    if (ctx->cur_size < ctx->roi_raw_size) {
165 by Suren A. Chilingaryan
Minor fix for frame partitioning
122
	ctx->frame[ctx->buffer_pos].event.info.flags |= PCILIB_EVENT_INFO_FLAG_BROKEN;
123
    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
124
    
125
    ctx->buffer_pos = (++ctx->event_id) % ctx->buffer_size;
126
    ctx->cur_size = 0;
127
128
    ctx->frame[ctx->buffer_pos].event.info.type = PCILIB_EVENT0;
129
    ctx->frame[ctx->buffer_pos].event.info.flags = 0;
130
    ctx->frame[ctx->buffer_pos].event.image_ready = 0;
131
132
    if ((ctx->event_id == ctx->autostop.evid)&&(ctx->event_id)) {
133
	ctx->run_reader = 0;
134
	return 1;
135
    }
136
	
245 by Suren A. Chilingaryan
First stand-alone ipecamera implementation
137
    if (pcilib_check_deadline(&ctx->autostop.timestamp, 0)) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
138
	ctx->run_reader = 0;
139
	return 1;
140
    }
141
    
142
    return 0;
143
}
144
145
static int ipecamera_data_callback(void *user, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
146
    int res;
147
    int eof = 0;
251 by Suren A. Chilingaryan
Use pcitool debugging API
148
    
149
    static unsigned long packet_id = 0;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
150
151
#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
143 by Suren A. Chilingaryan
Send padding data to rawdata_callback
152
    size_t real_size;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
153
    size_t extra_data = 0;
154
#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
240 by Suren A. Chilingaryan
Fix frame size computation in ipecamera and few debuging options
155
    
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
156
    ipecamera_t *ctx = (ipecamera_t*)user;
157
184 by Suren A. Chilingaryan
Fix splitting of frames in case of MULTIFRAME_PACKETS camera bug
158
#if defined(IPECAMERA_BUG_INCOMPLETE_PACKETS)||defined(IPECAMERA_BUG_MULTIFRAME_PACKETS)
159
    static  pcilib_event_id_t invalid_frame_id = (pcilib_event_id_t)-1;
160
#endif
185 by Suren A. Chilingaryan
More fixes to frame separation in multiframe mode; debugging mode
161
251 by Suren A. Chilingaryan
Use pcitool debugging API
162
    packet_id++;
163
    ipecamera_debug_buffer(RAW_PACKETS, bufsize, buf, PCILIB_DEBUG_BUFFER_MKDIR, "frame%4lu/frame%9lu", ctx->event_id, packet_id);
164
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
165
    if (!ctx->cur_size) {
267 by Suren A. Chilingaryan
Handle frame headers split between 2 packets
166
#ifdef IPECAMERA_BUG_MULTIFRAME_HEADERS
167
	if (ctx->saved_header_size) {
168
	    void *buf2 = alloca(ctx->saved_header_size + bufsize);
169
	    if (!buf2) {
170
		pcilib_error("Error allocating %zu bytes of memory in stack", ctx->saved_header_size + bufsize);
171
		return -PCILIB_ERROR_MEMORY;
172
	    }
173
	    memcpy(buf2, ctx->saved_header, ctx->saved_header_size);
174
	    memcpy(buf2 + ctx->saved_header_size, buf, bufsize);
175
176
	    buf = buf2;
177
	    bufsize += ctx->saved_header_size;
178
179
	    ctx->saved_header_size = 0;
180
	}
181
#endif /* IPECAMERA_BUG_MULTIFRAME_HEADERS */
182
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
183
#if defined(IPECAMERA_BUG_INCOMPLETE_PACKETS)||defined(IPECAMERA_BUG_MULTIFRAME_PACKETS)
184
	size_t startpos;
267 by Suren A. Chilingaryan
Handle frame headers split between 2 packets
185
	for (startpos = 0; (startpos + CMOSIS_ENTITY_SIZE) <= bufsize; startpos += sizeof(ipecamera_payload_t)) {
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
186
	    if (!CHECK_FRAME_MAGIC(buf + startpos)) break;
182 by Suren A. Chilingaryan
Skip non-informative packets on DMA
187
	}
188
	
267 by Suren A. Chilingaryan
Handle frame headers split between 2 packets
189
	if ((startpos +  CMOSIS_ENTITY_SIZE) > bufsize) {
251 by Suren A. Chilingaryan
Use pcitool debugging API
190
	    ipecamera_debug_buffer(RAW_PACKETS, bufsize, NULL, 0, "frame%4lu/frame%9lu.invalid", ctx->event_id, packet_id);
184 by Suren A. Chilingaryan
Fix splitting of frames in case of MULTIFRAME_PACKETS camera bug
191
	    
192
	    if (invalid_frame_id != ctx->event_id) {
254 by Suren A. Chilingaryan
Report extra padding only if IPECAMERA_DEBUG_HARDWARE is set
193
		ipecamera_debug(HARDWARE, "No frame magic in DMA packet of %u bytes, current event %lu", bufsize, ctx->event_id);
184 by Suren A. Chilingaryan
Fix splitting of frames in case of MULTIFRAME_PACKETS camera bug
194
		invalid_frame_id = ctx->event_id;
195
	    }
196
197
	    return PCILIB_STREAMING_CONTINUE;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
198
	}
199
	
200
	if (startpos) {
143 by Suren A. Chilingaryan
Send padding data to rawdata_callback
201
		// pass padding to rawdata callback
202
	    if (ctx->event.params.rawdata.callback) {
203
		res = ctx->event.params.rawdata.callback(0, NULL, PCILIB_EVENT_FLAG_RAW_DATA_ONLY, startpos, buf, ctx->event.params.rawdata.user);
204
		if (res <= 0) {
205
		    if (res < 0) return res;
206
		    ctx->run_reader = 0;
207
		}
208
	    }
209
210
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
211
	    buf += startpos;
212
	    bufsize -= startpos;
213
	}
214
#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */
215
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
216
	if ((bufsize >= CMOSIS_FRAME_HEADER_SIZE)&&(!CHECK_FRAME_MAGIC(buf))) {
217
		// We should handle the case when multi-header is split between multiple DMA packets
218
	    if (!ipecamera_parse_header(ctx, buf, bufsize))
219
		return PCILIB_STREAMING_CONTINUE;
267 by Suren A. Chilingaryan
Handle frame headers split between 2 packets
220
221
#ifdef IPECAMERA_BUG_MULTIFRAME_HEADERS
222
	} else if ((bufsize >= CMOSIS_ENTITY_SIZE)&&(!CHECK_FRAME_MAGIC(buf))) {
223
	    memcpy(ctx->saved_header, buf, bufsize);
224
	    ctx->saved_header_size = bufsize;
225
	    return PCILIB_STREAMING_REQ_FRAGMENT;
226
#endif /* IPECAMERA_BUG_MULTIFRAME_HEADERS */
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
227
	} else {
267 by Suren A. Chilingaryan
Handle frame headers split between 2 packets
228
	    ipecamera_debug(HARDWARE, "Frame magic is not found in the remaining DMA packet consisting of %u bytes, ignoring broken data...", bufsize);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
229
	    return PCILIB_STREAMING_CONTINUE;
230
	}
231
    }
232
233
#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
143 by Suren A. Chilingaryan
Send padding data to rawdata_callback
234
	// for rawdata_callback with complete padding
235
    real_size = bufsize;
236
    
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
237
    if (ctx->cur_size + bufsize > ctx->roi_raw_size) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
238
        size_t need;
239
	
267 by Suren A. Chilingaryan
Handle frame headers split between 2 packets
240
	for (need = ctx->roi_raw_size - ctx->cur_size; (need + CMOSIS_ENTITY_SIZE) <= bufsize; need += sizeof(uint32_t)) {
261 by Suren A. Chilingaryan
Support for new CMOSIS 20MPix camera
241
	    if (!CHECK_FRAME_MAGIC(buf + need)) break;
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
242
	}
243
	
267 by Suren A. Chilingaryan
Handle frame headers split between 2 packets
244
	if ((need + CMOSIS_ENTITY_SIZE) <= bufsize) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
245
	    extra_data = bufsize - need;
246
	    eof = 1;
247
	}
240 by Suren A. Chilingaryan
Fix frame size computation in ipecamera and few debuging options
248
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
249
	    // just rip of padding
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
250
	bufsize = ctx->roi_raw_size - ctx->cur_size;
251 by Suren A. Chilingaryan
Use pcitool debugging API
251
	ipecamera_debug_buffer(RAW_PACKETS, bufsize, buf, 0, "frame%4lu/frame%9lu.partial", ctx->event_id, packet_id);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
252
    }
253
#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
254
255
    if (ctx->parse_data) {
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
256
	if (ctx->cur_size + bufsize > ctx->padded_size) {
257
    	    pcilib_error("Unexpected event data, we are expecting at maximum (%zu) bytes, but (%zu) already read", ctx->padded_size, ctx->cur_size + bufsize);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
258
	    return -PCILIB_ERROR_TOOBIG;
259
	}
260
263 by Suren A. Chilingaryan
Add handling of a bug when IPECamera producing a dublicate 16 bytes at 4096 offset
261
	if (bufsize) {
262
#ifdef IPECAMERA_BUG_REPEATING_DATA
263
	    if ((bufsize > 16)&&(ctx->cur_size > 16)) {
264
		if (!memcmp(ctx->buffer + ctx->buffer_pos * ctx->padded_size +  ctx->cur_size - 16, buf, 16)) {
265
		    pcilib_warning("Skipping repeating bytes at offset %zu of frame %zu", ctx->cur_size, ctx->event_id);
266
		    buf += 16;
267
		    bufsize -=16;
268
		}
269
	    }
270
#endif /* IPECAMERA_BUG_REPEATING_DATA */
245 by Suren A. Chilingaryan
First stand-alone ipecamera implementation
271
	    memcpy(ctx->buffer + ctx->buffer_pos * ctx->padded_size +  ctx->cur_size, buf, bufsize);
263 by Suren A. Chilingaryan
Add handling of a bug when IPECamera producing a dublicate 16 bytes at 4096 offset
272
	}
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
273
    }
274
275
    ctx->cur_size += bufsize;
276
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
277
    if (ctx->cur_size >= ctx->roi_raw_size) {
239 by Suren A. Chilingaryan
ipecamera hack
278
	eof = 1;
279
    }
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
280
281
    if (ctx->event.params.rawdata.callback) {
282
	res = ctx->event.params.rawdata.callback(ctx->event_id, (pcilib_event_info_t*)(ctx->frame + ctx->buffer_pos), (eof?PCILIB_EVENT_FLAG_EOF:PCILIB_EVENT_FLAGS_DEFAULT), bufsize, buf, ctx->event.params.rawdata.user);
283
	if (res <= 0) {
284
	    if (res < 0) return res;
285
	    ctx->run_reader = 0;
286
	}
287
    }
288
    
289
    if (eof) {
137 by Suren A. Chilingaryan
Stop reader thread on pcilib_stop
290
	if ((ipecamera_new_frame(ctx))||(!ctx->run_reader)) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
291
	    return PCILIB_STREAMING_STOP;
292
	}
293
	
294
#ifdef IPECAMERA_BUG_MULTIFRAME_PACKETS
295
	if (extra_data) {
185 by Suren A. Chilingaryan
More fixes to frame separation in multiframe mode; debugging mode
296
	    return ipecamera_data_callback(user, flags, extra_data, buf + (real_size - extra_data));
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
297
	}
298
#endif /* IPECAMERA_BUG_MULTIFRAME_PACKETS */
299
    }
300
301
    return PCILIB_STREAMING_REQ_FRAGMENT;
302
}
303
304
void *ipecamera_reader_thread(void *user) {
305
    int err;
306
    ipecamera_t *ctx = (ipecamera_t*)user;
307
    
308
    while (ctx->run_reader) {
245 by Suren A. Chilingaryan
First stand-alone ipecamera implementation
309
	err = pcilib_stream_dma(ctx->event.pcilib, ctx->rdma, 0, 0, PCILIB_DMA_FLAG_MULTIPACKET, IPECAMERA_DMA_TIMEOUT, &ipecamera_data_callback, user);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
310
	if (err) {
311
	    if (err == PCILIB_ERROR_TIMEOUT) {
249 by Suren A. Chilingaryan
Simplify size tracking in the reader
312
		if (ctx->cur_size >= ctx->roi_raw_size) ipecamera_new_frame(ctx);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
313
#ifdef IPECAMERA_BUG_INCOMPLETE_PACKETS
314
		else if (ctx->cur_size > 0) ipecamera_new_frame(ctx);
315
#endif /* IPECAMERA_BUG_INCOMPLETE_PACKETS */
245 by Suren A. Chilingaryan
First stand-alone ipecamera implementation
316
		if (pcilib_check_deadline(&ctx->autostop.timestamp, 0)) {
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
317
		    ctx->run_reader = 0;
318
		    break;
319
		}
320
		usleep(IPECAMERA_NOFRAME_SLEEP);
321
	    } else pcilib_error("DMA error while reading IPECamera frames, error: %i", err);
252 by Suren A. Chilingaryan
Cleanup
322
	} 
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
323
    }
324
    
325
    ctx->run_streamer = 0;
326
    
252 by Suren A. Chilingaryan
Cleanup
327
    if (ctx->cur_size)
328
	pcilib_info("partialy read frame after stop signal, %zu bytes in the buffer", ctx->cur_size);
126 by Suren A. Chilingaryan
multithread preprocessing of ipecamera frames and code reorganization
329
330
    return NULL;
331
}