/alps/ipecamera

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/ipecamera
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#ifndef _IPECAMERA_PRIVATE_H
#define _IPECAMERA_PRIVATE_H

#include <pthread.h>
#include <pcilib/model.h>
#include <pcilib/debug.h>
#include <pcilib/locking.h>
#include "base.h"
#include "ipecamera.h"
#include "env.h"

#define IPECAMERA_DEBUG
#ifdef IPECAMERA_DEBUG
//# define IPECAMERA_DEBUG_RAW_FRAMES		//**< Store all raw frames */
# define IPECAMERA_DEBUG_BROKEN_FRAMES		//**< Store broken frames in the specified directory */
# define IPECAMERA_DEBUG_RAW_PACKETS		//**< Store all raw packets read from DMA grouped in frames */
# define IPECAMERA_DEBUG_HARDWARE		//**< Produce various debugging information about ipecamera operation */
# define IPECAMERA_DEBUG_FRAME_HEADERS		//**< Print frame headers & footers */
# define IPECAMERA_DEBUG_API			//**< Debug IPECamera API calls */
#endif /* IPECAMERA_DEBUG */

#define IPECAMERA_BUG_MISSING_PAYLOAD		//**< CMOSIS fails to provide a first payload for each frame, therefore the frame is 32 bit shorter */
#define IPECAMERA_BUG_MULTIFRAME_PACKETS	//**< This is by design, start of packet comes directly after the end of last one in streaming mode */
#define IPECAMERA_BUG_MULTIFRAME_HEADERS	//**< UFO Camera operates with 32-byte entities, but some times there is 16-byte padding before the data which may result in spliting the header between 2 DMA packets. We still need to define a minimal number of bytes which are always in the same DMA packet (CMOSIS_ENTITY_SIZE) */
#define IPECAMERA_BUG_REPEATING_DATA		//**< 16 bytes repeated at frame offset 4096, the problem start/stop happenning on board restart */
//#define IPECAMERA_BUG_STUCKED_BUSY		//**< DMA may stuck in busy. According to Michele, the work-around is to disable triggering and read all data out. Not checked */
//#define IPECAMERA_BUG_INCOMPLETE_PACKETS	//**< Support incomplete packets, i.e. check for frame magic even if full frame size is not reached yet (slow) */
//#define IPECAMERA_ANNOUNCE_READY		//**< Announce new event only after the reconstruction is done */
//#define IPECAMERA_CLEAN_ON_START		//**< Read all the data from DMA before starting of recording */
//#define IPECAMERA_ADJUST_BUFFER_SIZE		//**< Adjust default buffer size based on the hardware capabilities (number of frames stored in the FPGA memory) */

#define IPECAMERA_DEFAULT_BUFFER_SIZE 256  	//**< number of buffers in a ring buffer, should be power of 2 */
#define IPECAMERA_DEFAULT_CMOSIS20_BUFFER_SIZE 64 //*< overrides number of buffers for CMOSIS20 sensor to reduce memory consumption */
#define IPECAMERA_RESERVE_BUFFERS 4		//**< Return Frame is Lost error, if requested frame will be overwritten after specified number of frames

#define IPECAMERA_DMA_TIMEOUT 50000		//**< Default DMA timeout */
#define IPECAMERA_TRIGGER_TIMEOUT 200000	//**< In trigger call allow specified timeout for camera to get out of busy state. Set 0 to fail immideatly */
#define IPECAMERA_CMOSIS_RESET_DELAY 250000 	//**< Michele thinks 250 should be enough, but reset failing in this case */
#define IPECAMERA_CMOSIS_REGISTER_DELAY 250000 	//**< Michele thinks 250 should be enough, but reset failing in this case */
#define IPECAMERA_SPI_REGISTER_DELAY 10000	//**< Delay between consequitive access to the registers */
#define IPECAMERA_NEXT_FRAME_DELAY 1000 	//**< Michele requires 30000 to sync between End Of Readout and next Frame Req */
#define IPECAMERA_TRIGGER_DELAY 0 		//**< Defines how long the trigger bits should be set */
#define IPECAMERA_READ_STATUS_DELAY 1000	//**< According to Uros, 1ms delay needed before consequitive reads from status registers */
#define IPECAMERA_NOFRAME_SLEEP 100		//**< Sleep while polling for a new frame in reader */
#define IPECAMERA_NOFRAME_PREPROC_SLEEP 100	//**< Sleep while polling for a new frame in pre-processor */

#define IPECAMERA_EXPECTED_STATUS_4 0x08409FFFF
#define IPECAMERA_EXPECTED_STATUS 0x08449FFFF

#define IPECAMERA_END_OF_SEQUENCE 0x1F001001


#define CMOSIS_FRAME_HEADER_SIZE	(8 * sizeof(ipecamera_payload_t))
#define CMOSIS_FRAME_TAIL_SIZE		(8 * sizeof(ipecamera_payload_t))
#ifdef IPECAMERA_BUG_MULTIFRAME_HEADERS
# define CMOSIS_ENTITY_SIZE		(4 * sizeof(ipecamera_payload_t))		//**< This normaly should be equal to 32 bytes like header and tail, but in fact is only 16 bytes */
#else /* IPECAMERA_BUG_MULTIFRAME_HEADERS */
# define CMOSIS_ENTITY_SIZE		(8 * sizeof(ipecamera_payload_t))		//**< This normaly should be equal to 32 bytes like header and tail, but in fact is only 16 bytes */
#endif /* IPECAMERA_BUG_MULTIFRAME_HEADERS */

#define CMOSIS_MAX_CHANNELS 16
#define CMOSIS_PIXELS_PER_CHANNEL 128
#define CMOSIS_WIDTH (CMOSIS_MAX_CHANNELS * CMOSIS_PIXELS_PER_CHANNEL)
//#define IPECAMERA_MAX_LINES 1088
#define CMOSIS_MAX_LINES 2048

/*
#define CMOSIS20_MAX_CHANNELS 8
#define CMOSIS20_PIXELS_PER_CHANNEL 640
#define CMOSIS20_WIDTH (CMOSIS20_MAX_CHANNELS * CMOSIS20_PIXELS_PER_CHANNEL)
*/
#define CMOSIS20_PIXELS_PER_CHANNEL 320
#define CMOSIS20_WIDTH (CMOSIS_MAX_CHANNELS * CMOSIS20_PIXELS_PER_CHANNEL)
#define CMOSIS20_MAX_LINES 3840

#define IPECAMERA_FRAME_REQUEST 		0x209 // 0x80000209 // 0x1E9
#define IPECAMERA_IDLE 				0x201 // 0x80000201 // 0x1E1
#define IPECAMERA_START_INTERNAL_STIMULI 	0x1F1

#define IPECAMERA_MODE_16_CHAN_IO		0
#define IPECAMERA_MODE_4_CHAN_IO		2

#define IPECAMERA_MODE_12_BIT_ADC		2
#define IPECAMERA_MODE_11_BIT_ADC		1
#define IPECAMERA_MODE_10_BIT_ADC		0


#ifdef IPECAMERA_DEBUG_RAW_FRAMES
# define IPECAMERA_DEBUG_RAW_FRAMES_MESSAGE(function, ...)  if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_message (#function, __FILE__, __LINE__, __VA_ARGS__); }
# define IPECAMERA_DEBUG_RAW_FRAMES_BUFFER(function, ...)  if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_data_buffer (#function, __VA_ARGS__); }
#else /* IPECAMERA_DEBUG_RAW_FRAMES */
# define IPECAMERA_DEBUG_RAW_FRAMES_MESSAGE(function, ...)
# define IPECAMERA_DEBUG_RAW_FRAMES_BUFFER(function, ...)
#endif /* IPECAMERA_DEBUG_RAW_FRAMES */

#ifdef IPECAMERA_DEBUG_BROKEN_FRAMES
# define IPECAMERA_DEBUG_BROKEN_FRAMES_MESSAGE(function, ...) if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_message (#function, __FILE__, __LINE__, __VA_ARGS__); }
# define IPECAMERA_DEBUG_BROKEN_FRAMES_BUFFER(function, ...) if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_data_buffer (#function, __VA_ARGS__); }
#else /* IPECAMERA_DEBUG_BROKEN_FRAMES */
# define IPECAMERA_DEBUG_BROKEN_FRAMES_MESSAGE(function, ...)
# define IPECAMERA_DEBUG_BROKEN_FRAMES_BUFFER(function, ...)
#endif /* IPECAMERA_DEBUG_BROKEN_FRAMES */

#ifdef IPECAMERA_DEBUG_RAW_PACKETS
# define IPECAMERA_DEBUG_RAW_PACKETS_MESSAGE(function, ...) if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_message (#function, __FILE__, __LINE__, __VA_ARGS__); }
# define IPECAMERA_DEBUG_RAW_PACKETS_BUFFER(function, ...) if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_data_buffer (#function, __VA_ARGS__); }
#else /* IPECAMERA_DEBUG_RAW_PACKETS */
# define IPECAMERA_DEBUG_RAW_PACKETS_MESSAGE(function, ...)
# define IPECAMERA_DEBUG_RAW_PACKETS_BUFFER(function, ...)
#endif /* IPECAMERA_DEBUG_RAW_PACKETS */

#ifdef IPECAMERA_DEBUG_HARDWARE
# define IPECAMERA_DEBUG_HARDWARE_MESSAGE(function, ...) if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_message (#function, __FILE__, __LINE__, __VA_ARGS__); }
# define IPECAMERA_DEBUG_HARDWARE_BUFFER(function, ...) if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_data_buffer (#function, __VA_ARGS__); }
#else /* IPECAMERA_DEBUG_HARDWARE */
# define IPECAMERA_DEBUG_HARDWARE_MESSAGE(function, ...)
# define IPECAMERA_DEBUG_HARDWARE_BUFFER(function, ...)
#endif /* IPECAMERA_DEBUG_HARDWARE */

#ifdef IPECAMERA_DEBUG_FRAME_HEADERS
# define IPECAMERA_DEBUG_FRAME_HEADERS_MESSAGE(function, ...)  if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_message (#function, __FILE__, __LINE__, __VA_ARGS__); }
# define IPECAMERA_DEBUG_FRAME_HEADERS_BUFFER(function, ...)  if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_data_buffer (#function, __VA_ARGS__); }
#else /* IPECAMERA_DEBUG_RAW_FRAMES */
# define IPECAMERA_DEBUG_FRAME_HEADERS_MESSAGE(function, ...)
# define IPECAMERA_DEBUG_FRAME_HEADERS_BUFFER(function, ...)
#endif /* IPECAMERA_DEBUG_RAW_FRAMES */

#ifdef IPECAMERA_DEBUG_API
# define IPECAMERA_DEBUG_API_MESSAGE(function, ...)  if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_message (#function, __FILE__, __LINE__, __VA_ARGS__); }
# define IPECAMERA_DEBUG_API_BUFFER(function, ...)  if (ipecamera_getenv(function##_ENV, #function)) { pcilib_debug_data_buffer (#function, __VA_ARGS__); }
#else /* IPECAMERA_DEBUG_API */
# define IPECAMERA_DEBUG_API_MESSAGE(function, ...)
# define IPECAMERA_DEBUG_API_BUFFER(function, ...)
#endif /* IPECAMERA_DEBUG_API */


#define ipecamera_debug(function, ...) \
    IPECAMERA_DEBUG_##function##_MESSAGE(IPECAMERA_DEBUG_##function, PCILIB_LOG_DEFAULT, __VA_ARGS__)

#define ipecamera_debug_buffer(function, ...) \
    IPECAMERA_DEBUG_##function##_BUFFER(IPECAMERA_DEBUG_##function, __VA_ARGS__)


typedef uint32_t ipecamera_payload_t;

typedef enum {
    IPECAMERA_FIRMWARE_UNKNOWN = 0,
    IPECAMERA_FIRMWARE_UFO5 = 5,
    IPECAMERA_FIRMWARE_CMOSIS20 = 6
} ipecamera_firmware_t;

typedef enum {
    IPECAMERA_FORMAT_CMOSIS = 5,
    IPECAMERA_FORMAT_CMOSIS20 = 6,
    IPECAMERA_FORMAT_POLARIS = 7
} ipecamera_format_t;

typedef struct {
    pcilib_event_id_t evid;
    struct timeval timestamp;
} ipecamera_autostop_t;

typedef struct {
    size_t i;
    pthread_t thread;
    ipecamera_t *ipecamera;
    
    int started;			/**< flag indicating that join & cleanup is required */
} ipecamera_preprocessor_t;


typedef struct {
    ipecamera_event_info_t event;	/**< this structure is overwritten by the reader thread, we need a copy */
    pthread_rwlock_t mutex;		/**< this mutex protects reconstructed buffers only, the raw data, event_info, etc. will be overwritten by reader thread anyway */
} ipecamera_frame_t;

struct ipecamera_s {
    pcilib_context_t event;
    UfoDecoder *ipedec;

    pcilib_lock_t *run_lock;		/**< Lock protecting global camera operation */
    pcilib_lock_t *stream_lock;		/**< Lock protecting stream/next_frame operations */
    pcilib_lock_t *trigger_lock;	/**< Lock protecting stream/next_frame operations */
    int run_locked;			/**< Flag indicating if camera is currently locked */
    int stream_locked;			/**< Flag indicating if camera is currently locked */
    int trigger_locked;			/**< Flag indicating if camera is currently locked */

    char *data;
    ipecamera_pixel_t *image;
    size_t size;

    volatile pcilib_event_id_t event_id;
    volatile pcilib_event_id_t preproc_id;
    pcilib_event_id_t reported_id;

    pcilib_dma_engine_t rdma;

    pcilib_register_t control_reg, status_reg;
    pcilib_register_t status2_reg, status3_reg;
//    pcilib_register_t n_lines_reg;
//    uint16_t line_reg;
//    pcilib_register_t exposure_reg;
//    pcilib_register_t flip_reg;

    pcilib_register_t firmware_version_reg;
    pcilib_register_t adc_resolution_reg;
    pcilib_register_t output_mode_reg;
    
    pcilib_register_t max_frames_reg;
    pcilib_register_t num_frames_reg;

    int started;			/**< Camera is in grabbing mode (start function is called) */
    int streaming;			/**< Camera is in streaming mode (we are within stream call) */
    int parse_data;			/**< Indicates if some processing of the data is required, otherwise only rawdata_callback will be called */

    volatile int run_reader;		/**< Instructs the reader thread to stop processing */
    volatile int run_streamer;		/**< Indicates request to stop streaming events and can be set by reader_thread upon exit or by user request */
    volatile int run_preprocessors;	/**< Instructs preprocessors to exit */
    
    ipecamera_autostop_t autostop;

    struct timeval autostop_time;
    struct timeval next_trigger;	/**< The minimal delay between trigger signals is mandatory, this indicates time when next trigger is possible */

    size_t buffer_size;			/**< How many images to store */
    size_t buffer_pos;			/**< Current image offset in the buffer, due to synchronization reasons should not be used outside of reader_thread */
    size_t cur_size;			/**< Already written part of data in bytes */
    size_t raw_size;			/**< Expected maximum size of raw data in bytes */
    size_t padded_size;			/**< Expected maximum size of buffer for raw data, including additional padding */
    size_t roi_raw_size;		/**< Expected size (for currently configured ROI) of raw data in bytes */
    size_t roi_padded_size;		/**< Expected size (for currently configured ROI) of buffer for raw data, including additional padding */
    
    size_t image_size;			/**< Size of a single image in bytes */
    
    size_t max_frames;			/**< Maximal number of frames what may be buffered in camera DDR memory */
    ipecamera_firmware_t firmware;	/**< Firmware type */
    int cmosis_outputs;			/**< Number of active cmosis outputs: 4 or 16 */
    int width, height;

    
//    void *raw_buffer;
    void *buffer;
    ipecamera_change_mask_t *cmask;
    ipecamera_frame_t *frame;

#ifdef IPECAMERA_BUG_MULTIFRAME_HEADERS
    size_t saved_header_size;				/**< If it happened that the frame header is split between 2 DMA packets, this variable holds the size of the part containing in the first packet */
    char saved_header[CMOSIS_FRAME_HEADER_SIZE];	/**< If it happened that the frame header is split between 2 DMA packets, this variable holds the part containing in the first packet */
#endif /* IPECAMERA_BUG_MULTIFRAME_HEADERS */

    size_t data_line_size;
    ipecamera_image_dimensions_t dim;

    pthread_t rthread;
    
    size_t n_preproc;
    ipecamera_preprocessor_t *preproc;
    pthread_mutex_t preproc_mutex;
    
    int preproc_mutex_destroy;
    int frame_mutex_destroy;
};

#endif /* _IPECAMERA_PRIVATE_H */