diff --git a/src/drivers/elphel/Makefile b/src/drivers/elphel/Makefile
index 364b00b4d635cc649fd9d6edd8bbd7f6d60bb89f..f71a25f87804f19b8361d4d76eacf1d422964931 100644
--- a/src/drivers/elphel/Makefile
+++ b/src/drivers/elphel/Makefile
@@ -6,3 +6,8 @@ obj-$(CONFIG_ELPHEL393) += elphel393-pwr.o
obj-$(CONFIG_ELPHEL393) += elphel393-mem.o
obj-$(CONFIG_ELPHELDRVONMICROZED) += elphel393-mem.o
obj-$(CONFIG_ELPHEL393_INIT) += elphel393-init.o
+
+obj-$(CONFIG_ELPHEL393) += framepars.o
+obj-$(CONFIG_ELPHEL393) += sensor_common.o
+obj-$(CONFIG_ELPHEL393) += quantization_tables.o
+obj-$(CONFIG_ELPHEL393) += circbuf.o jpeghead.o
\ No newline at end of file
diff --git a/src/drivers/elphel/circbuf.c b/src/drivers/elphel/circbuf.c
new file mode 100644
index 0000000000000000000000000000000000000000..1a6f48eeea3799b9eb67176b57366d528ff4c0d9
--- /dev/null
+++ b/src/drivers/elphel/circbuf.c
@@ -0,0 +1,695 @@
+/*!***************************************************************************
+*! FILE NAME : circbuf.c
+*! DESCRIPTION: drivers to manipulate large circular buffer that holds compressed
+*! images/video. Buffer frame data is filled in by the FPGA, frame pointers and
+*! essential frames metadata filled during servicing of the interruptsl
+*! This code is based on the code from cxdma.c
+*! TODO: Add buffer reset, JPEG header generation here
+*!
+*! Copyright (C) 2002-2007 Elphel, Inc
+*! -----------------------------------------------------------------------------**
+*!
+*! This program is free software: you can redistribute it and/or modify
+*! it under the terms of the GNU General Public License as published by
+*! the Free Software Foundation, either version 3 of the License, or
+*! (at your option) any later version.
+*!
+*! This program is distributed in the hope that it will be useful,
+*! but WITHOUT ANY WARRANTY; without even the implied warranty of
+*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*! GNU General Public License for more details.
+*!
+*! You should have received a copy of the GNU General Public License
+*! along with this program. If not, see .
+*! -----------------------------------------------------------------------------**
+*! $Log: circbuf.c,v $
+*! Revision 1.3 2010/08/08 21:14:04 elphel
+*! 8.0.8.38
+*!
+*! Revision 1.2 2008/11/28 08:17:09 elphel
+*! keeping Doxygen a little happier
+*!
+*! Revision 1.1.1.1 2008/11/27 20:04:00 elphel
+*!
+*!
+*! Revision 1.20 2008/11/20 07:06:24 elphel
+*! started more poll options
+*!
+*! Revision 1.19 2008/11/03 20:51:49 elphel
+*! minor bug fix
+*!
+*! Revision 1.18 2008/10/29 04:18:28 elphel
+*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
+*!
+*! Revision 1.17 2008/10/25 19:59:48 elphel
+*! added lseek() calls to enable/disable daemons at events (compressed frame available, any frame available, histogram-Y and histograms-C available)
+*!
+*! Revision 1.16 2008/10/23 08:01:30 elphel
+*! comments
+*!
+*! Revision 1.15 2008/10/19 06:50:03 elphel
+*! removed couple # if 0
+*!
+*! Revision 1.14 2008/10/13 16:55:53 elphel
+*! removed (some) obsolete P_* parameters, renamed CIRCLSEEK to LSEEK_CIRC constants (same as other similar)
+*!
+*! Revision 1.13 2008/10/12 16:46:22 elphel
+*! snapshot
+*!
+*! Revision 1.12 2008/10/06 08:31:08 elphel
+*! snapshot, first images
+*!
+*! Revision 1.11 2008/09/22 22:55:47 elphel
+*! snapshot
+*!
+*! Revision 1.10 2008/09/20 00:29:49 elphel
+*! moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
+*!
+*! Revision 1.9 2008/09/12 20:40:11 elphel
+*! snapshot
+*!
+*! Revision 1.8 2008/09/12 00:23:58 elphel
+*! removed cc353.c, cc353.h
+*!
+*! Revision 1.7 2008/09/11 01:05:29 elphel
+*! snapshot
+*!
+*! Revision 1.6 2008/09/07 19:48:08 elphel
+*! snapshot
+*!
+*! Revision 1.5 2008/09/05 23:20:26 elphel
+*! just a snapshot
+*!
+*! Revision 1.4 2008/05/26 23:32:59 elphel
+*! Added driver to handle multi-frame parameters
+*!
+*! Revision 1.3 2008/05/24 05:31:02 elphel
+*! removed seek to current hardware write pointer after opening file, so now ftp-ing circbuf file works correctly
+*!
+*! Revision 1.2 2008/05/16 06:06:27 elphel
+*! adjusting drivers to the fpga code (03533020)
+*!
+*! Revision 1.10 2008/04/11 23:16:51 elphel
+*! removed unneeded local_irq_disable() after local_irq_save_flags()
+*!
+*! Revision 1.8 2007/12/03 08:28:46 elphel
+*! Multiple changes, mostly cleanup
+*!
+*! Revision 1.7 2007/11/16 08:56:19 elphel
+*! Added support for 2 additional commands to check circbuf usage
+*!
+*! Revision 1.6 2007/11/05 06:08:25 elphel
+*! fixed "first/second" bug introduced while fixing the previous one
+*!
+*! Revision 1.5 2007/11/05 01:40:51 elphel
+*! fixed wrong count of frames available, "second" frame
+*!
+*! Revision 1.4 2007/11/04 05:46:06 elphel
+*! removed debug, rearranged code to avoid a warning
+*!
+*! Revision 1.3 2007/11/01 18:59:37 elphel
+*! debugging mmap/caching problems
+*!
+*! Revision 1.2 2007/10/27 00:55:32 elphel
+*! untested revision - need to go
+*!
+*! Revision 1.1.1.1 2007/10/02 23:54:58 elphel
+*! This is a fresh tree based on elphel353-2.10
+*!
+*! Revision 1.6 2007/10/02 23:54:58 elphel
+*! LSEEK_CIRC_LAST will now return just write pointer, not an error if there are no frames yet available. Moving to previous will still generate error.
+*!
+*! Revision 1.5 2007/10/02 22:29:38 elphel
+*! made that only 0,SEEK_END can move beyond circbuf, fro SEEK_CUR and SEET_SET it will roll over to 0
+*!
+*! Revision 1.4 2007/10/02 19:35:15 elphel
+*! minor circbuf interface changes, bug fixes
+*!
+*! Revision 1.3 2007/09/30 07:07:08 elphel
+*! minor bug fix, disabled debug output
+*!
+*! Revision 1.2 2007/09/30 03:19:56 elphel
+*! Cleanup, fixed broken acquisition of individual JPEG images into circbuf (in mode 7)
+*!
+*! Revision 1.1 2007/09/29 18:33:29 elphel
+*! Split cxdma.c - /dev/circbuf is now in a separate circbuf.c file. New device driver does not support ioctl, so some curernt applications are updated to use other drivers to control the camera
+*!
+*/
+
+/****************** INCLUDE FILES SECTION ***********************************/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//#include
+//#include
+//#include obsolete
+#include
+
+/*#include
+#include
+#include
+#include
+#include
+*/
+
+#include
+#include
+
+
+#include
+#include
+#include
+#include
+
+#include "framepars.h" // just for ELPHEL_DEBUG bit mask
+
+#include "sensor_common.h"
+#include "jpeghead.h"
+#include "circbuf.h"
+#include "exif.h"
+#if ELPHEL_DEBUG
+ #define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;}
+ #define D19(x) { if (GLOBALPARS(G_DEBUG) & (1 <<19)) {x; } ; }
+ #define MDF19(x) { if (GLOBALPARS(G_DEBUG) & (1 <<19)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
+ #define D20(x) { if (GLOBALPARS(G_DEBUG) & (1 <<20)) {x; } ; }
+ #define MDF20(x) { if (GLOBALPARS(G_DEBUG) & (1 <<20)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
+#else
+ #define MDF(x)
+ #define D19(x)
+ #define MDF19(x)
+ #define D20(x)
+ #define MDF20(x)
+
+#endif
+
+#define MD12(x)
+#define D(x)
+
+//#define MD7(x) printk("%s:%d:",__FILE__,__LINE__);x
+#define MD7(x)
+
+//#define MD10(x) printk("%s:%d:",__FILE__,__LINE__);x
+#define MD10(x)
+//#define MD11(x) printk("%s:%d:",__FILE__,__LINE__);x
+#define MD11(x)
+
+/* really huge static DMA buffer (1288+8)*1032/3=445824 long-s */
+// DMA_SIZE - in 32-bit words, not bytes
+static unsigned long ccam_dma_buf[CCAM_DMA_SIZE + (PAGE_SIZE>>2)] __attribute__ ((aligned (PAGE_SIZE)));
+//!Without "static" system hangs after "Uncompressing Linux...
+unsigned long * ccam_dma_buf_ptr = NULL;
+unsigned long * ccam_dma = NULL; //! still used in autoexposure or something - why is in needed there?
+
+void init_ccam_dma_buf_ptr(void) {
+ ccam_dma_buf_ptr = ccam_dma_buf;
+ ccam_dma = ccam_dma_buf; //&ccam_dma_buf[0]; Use in autoexposure
+}
+extern struct interframe_params_t frame_params; // cc353.c
+/*!======================================================================================
+ *! Wait queue for the processes waiting for a new frame to appear in the circular buffer
+ *!======================================================================================*/
+wait_queue_head_t circbuf_wait_queue;
+/*!=========================================================================================================
+ *! circbuf top level device drivers. Minors are the same as before
+ *! CMOSCAM_MINOR_CIRCBUF, CMOSCAM_MINOR_JPEAGHEAD - just a new major
+ *!========================================================================================================*/
+#define CIRCBUF_DRIVER_NAME "Elphel (R) Model 353 video buffer device driver"
+static struct file_operations circbuf_fops = {
+ owner: THIS_MODULE,
+ llseek: circbuf_all_lseek,
+ read: circbuf_all_read,
+ write: circbuf_all_write,
+ //ioctl: circbuf_all_ioctl,
+ open: circbuf_all_open,
+ mmap: circbuf_all_mmap,
+ poll: circbuf_all_poll,
+ release: circbuf_all_release
+};
+
+// Read/write to circular buffer. Needed to find out what Axis DMA is doing
+// also - jpeg header
+struct circbuf_pd {
+ int minor; /// should be the first, same as in jpeghead_pd
+ int daemon_bit; /// poll() will produce POLLHUP if this bit is >=0 (set through lseek (, LSEEK_DAEMON_CIRCBUF,SEEK_END)
+ /// and the corresponding bit in P_DAEMON_EN goes 0
+ int imageWidth; /// image width to compare to current. G_SKIP_DIFF_FRAME
+ int imageHeight; /// image height to compare to current. G_SKIP_DIFF_FRAME
+ int tolerated; /// number of frames with different size tolerated
+ struct wait_queue *circbuf_wait_queue; ///NOTE: not used at all?
+// something else to be added here?
+};
+// CMOSCAM_MINOR_HUFFMAN // huffman tables R/W
+int circbuf_all_open(struct inode *inode, struct file *filp) {
+ int res;
+ MD10(printk("circbuf_all_open, minor=0x%x\n",MINOR(inode->i_rdev)));
+ switch (MINOR(inode->i_rdev)) {
+ case CMOSCAM_MINOR_CIRCBUF :
+ res=circbuf_open(inode,filp);
+ break;
+ case CMOSCAM_MINOR_JPEAGHEAD :
+ res=jpeghead_open(inode,filp);
+ break;
+ case CMOSCAM_MINOR_HUFFMAN :
+ res=huffman_open(inode,filp);
+ break;
+ default:
+// kfree(filp->private_data); // already allocated
+ return -EINVAL;
+ }
+ return res;
+}
+int circbuf_all_release(struct inode *inode, struct file *filp) {
+ int res=0;
+ int p = MINOR(inode->i_rdev);
+ MD10(printk("circbuf_all_release, minor=0x%x\n",p));
+ switch ( p ) {
+ case CMOSCAM_MINOR_CIRCBUF :
+// res=circbuf_release(inode,filp);
+ break;
+ case CMOSCAM_MINOR_JPEAGHEAD :
+// res=jpeghead_release(inode,filp);
+ break;
+ case CMOSCAM_MINOR_HUFFMAN :
+// res=huffman_release(inode,filp);
+ break;
+ default:
+ return -EINVAL; //! do not need to free anything - "wrong number"
+ }
+ if (filp->private_data) kfree(filp->private_data);
+ return res;
+}
+
+loff_t circbuf_all_lseek(struct file * file, loff_t offset, int orig) {
+ struct circbuf_pd * privData;
+ privData = (struct circbuf_pd *) file->private_data;
+ MD10(printk("circbuf_all_lseek, minor=0x%x\n",privData-> minor));
+ switch (privData->minor) {
+ case CMOSCAM_MINOR_CIRCBUF : return circbuf_lseek (file, offset, orig);
+ case CMOSCAM_MINOR_JPEAGHEAD : return jpeghead_lseek (file, offset, orig);
+ case CMOSCAM_MINOR_HUFFMAN : return huffman_lseek (file, offset, orig);
+ default: return -EINVAL;
+ }
+}
+
+ssize_t circbuf_all_read(struct file * file, char * buf, size_t count, loff_t *off) {
+ struct circbuf_pd * privData;
+ privData = (struct circbuf_pd *) file->private_data;
+ MD10(printk("circbuf_all_read, minor=0x%x\n",privData-> minor));
+ switch (privData->minor) {
+ case CMOSCAM_MINOR_CIRCBUF : return circbuf_read (file, buf, count, off);
+ case CMOSCAM_MINOR_JPEAGHEAD : return jpeghead_read (file, buf, count, off);
+ case CMOSCAM_MINOR_HUFFMAN : return huffman_read (file, buf, count, off);
+ default: return -EINVAL;
+ }
+}
+ssize_t circbuf_all_write(struct file * file, const char * buf, size_t count, loff_t *off) {
+ struct circbuf_pd * privData;
+ privData = (struct circbuf_pd *) file->private_data;
+ MD10(printk("circbuf_all_write, minor=0x%x, count=%d, off=%d\n",privData-> minor, (int) count,(int)*off));
+ switch (privData->minor) {
+ case CMOSCAM_MINOR_CIRCBUF : return circbuf_write (file, buf, count, off);
+// case CMOSCAM_MINOR_JPEAGHEAD : return jpeghead_write (file, buf, count, off); // same as other - write header
+ case CMOSCAM_MINOR_HUFFMAN : return huffman_write (file, buf, count, off);
+ default: return -EINVAL;
+ }
+}
+
+
+int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma) {
+ struct circbuf_pd * privData;
+ privData = (struct circbuf_pd *) file->private_data;
+ MD10(printk("circbuf_all_mmap, minor=0x%x\n",privData-> minor));
+ switch (privData->minor) {
+ case CMOSCAM_MINOR_CIRCBUF : return circbuf_mmap (file, vma);
+ default: return -EINVAL;
+ }
+}
+
+unsigned int circbuf_all_poll (struct file *file, poll_table *wait) {
+ struct circbuf_pd * privData;
+ privData = (struct circbuf_pd *) file->private_data;
+ MD10(printk("circbuf_all_poll, minor=0x%x\n",privData-> minor));
+ switch (privData->minor) {
+ case CMOSCAM_MINOR_CIRCBUF :
+ return circbuf_poll (file, wait);
+ default: return -EINVAL;
+ }
+}
+
+int circbuf_all_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {
+ struct circbuf_pd * privData;
+ privData = (struct circbuf_pd *) filp->private_data;
+ printk("\n========== IOCTL is not implemented in circbuf_all_ioctl, minor=0x%x, cmd=0x%x, _IOC_NR(cmd)=0x%x, arg=0x%x\n",privData-> minor, (int) cmd, _IOC_NR(cmd), (int) arg);
+ return -EINVAL;
+}
+
+
+
+
+int circbuf_open(struct inode *inode, struct file *filp) { // set filesize
+ struct circbuf_pd * privData;
+ privData= (struct circbuf_pd *) kmalloc(sizeof(struct circbuf_pd),GFP_KERNEL);
+ if (!privData) return -ENOMEM;
+ filp->private_data = privData;
+ privData-> minor=MINOR(inode->i_rdev);
+
+ inode->i_size = ((CCAM_DMA_SIZE) << 2);
+ MD10(printk("circbuf_open, inode->i_size=0x%x\n", (int)inode->i_size));
+
+//!should be removed (or else you can not ftp file - it will start from WP)
+// circbuf_lseek(filp, LSEEK_CIRC_LAST, SEEK_END); //! position at last acquired frame, ignore result
+ return 0;
+}
+
+/*!=============================================================================================
+ *! Overloading lseek with additional functionality (to avoid ioctls)
+ *! with orig==SEEK_END lseek will treat (offset>0) as a command
+ *! to manipulate frame pointer(s) or wait for the image to be ready
+ *! using these commands
+ *! LSEEK_CIRC_TORP .- set filepointer to global (shared) read pointer
+ *! LSEEK_CIRC_TOWP - set filepointer to FPGA write pointer (next frame to be acquired)
+ *! LSEEK_CIRC_PREV - move pointer to the previous frame, return -EOVERFLOW if there are none
+ *! LSEEK_CIRC_NEXT - advance pointer to the next frame, return -EOVERFLOW if was already
+ *! at the last
+ *! LSEEK_CIRC_LAST - move pointer to the last acquired frame (default after open)
+ *! (it is combination of 2+3)
+ *! LSEEK_CIRC_FIRST - move pointer to the first acquired frame. It s not safe to rely
+ *! on this pointer if more frames are expected - next incoming frame
+ *! can overwrite this one.
+ *! LSEEK_CIRC_SCND - move pointer to the second oldest acquired frame. A slightly safer
+ *! to use instead of LSEEK_CIRC_FIRST when constant acquisition is on
+ *! and sensor provides new frames - this frame will likely survive longer
+ *! LSEEK_CIRC_SETP - save current pointer to global read pointer
+ *! LSEEK_CIRC_VALID - verify that the frame at current location is valid (not overrun in the buffer)
+ *! Returns file pointer if valid, else - -1
+ *! LSEEK_CIRC_READY - verify frame at current loacation is available (valid and acquired)
+ *! Returns file pointer if ready, else - -1
+ *! LSEEK_CIRC_WAIT - sleep until next frame is acquired
+ *! All commands but (LSEEK_CIRC_TOWP,LSEEK_CIRC_LAST,LSEEK_CIRC_FIRST) will return -EINVAL if read
+ *! pointer is not valid (i.e buffer was overrun and data pointed is lost). if success they return
+ *! the current (byte *) to the start of the frame data (parameters are at
+ *! offsett =-32 from it)
+ *! (0, SEEK_CUR) also verifies that the header is not overwritten. It can be used
+ *! after buffering frame data to verify you got it all correctly
+ *! SEEK_CUR also supports the circular nature of the buffer and rolls over if needed
+ *! Additional commands for SEEK_END (they _DO_ modify the current file pointer !)
+ *! LSEEK_CIRC_FREE - returnes remaining memory in circbuf from the current file pointer,
+ *! or -EINVAL if the pointer is invalid. As this command uses the buffer write pointer
+ *! that is updated only when the complete frame is in the buffer, the actual
+ *! free memory may be less by a whole frame if compressor is running.
+ *! LSEEK_CIRC_USED - returnes memory used in the in circbuf from the current file pointer,
+ *! or -EINVAL if the pointer is invalid
+ *!=============================================================================================*/
+//!returns 0 if rp is a valid read ponter
+//! returns 1 if there is a frame at this address
+//! returns 0 if the pointer is for the frame yet to be acquired
+//! returns -1 if there is no frame at this index
+//! returns -2 if the rp is not 32-bytes aligned
+//!sets *fpp to the frame header, including signature and length
+int circbufValidPointer(int rp, struct interframe_params_t ** fpp) {
+ if (rp & 0x1f) { //!rp is not 32-bytes aligned
+ MD10(printk("circbufValidPointer: misaligned pointer\n"));
+ return -2;
+ }
+ int wp=camSeqGetJPEG_wp();
+ int p= rp >> 2; // index inccam_dma_buf
+ struct interframe_params_t * fp;
+ fp = (struct interframe_params_t *) &ccam_dma_buf[X313_BUFFSUB(p, 8)]; //! 32 bytes before the frame pointer, may roll-over to the end of ccam_dma_buf
+
+ MD10(printk("rp=0x%x (0x%x), offset=0x%x\n",rp,p,(int)&ccam_dma_buf[p]-(int)fp); dumpFrameParams(fp, "in circbufValidPointer:"));
+
+ *fpp=fp;
+ MD11(printk("p=0x%x , wp==0x%x\n",p,wp));
+ if (p == wp) {
+ return 0; // frame not yet acquired, fp - not valid
+ }
+ if (fp->signffff != 0xffff) { //! signature is overwritten
+ MD10(printk("circbufValidPointer: signanure overwritten\n"));
+ return -1;
+ }
+ if ((fp->timestamp_sec) & X313_LENGTH_MASK) {
+ MDF(printk ("Should not get here - fp->timestamp_sec=0x%x\n",(int) fp->timestamp_sec));
+ return 0; //! should not get here - should be caught by (p==wp)
+ }
+ return 1;
+
+}
+
+loff_t circbuf_lseek(struct file * file, loff_t offset, int orig) {
+ // orig 0: position from begning
+ // orig 1: relative from current
+ // orig 2: position from last address
+ int l = (CCAM_DMA_SIZE << 2);
+ int fl=0;// frame length
+ struct interframe_params_t * fp;
+ int fvld=-1;
+ int rp, bp, prev_p, preprev_p; //, p;
+ int nf; //! number of frames;
+ int nz=1; //! number of crossing of start of the circular buffer (counter to prevent looping forever)
+MD12(int dbg_i);
+// int pf; // previous frame
+ MD11(printk("circbuf_lseek, offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
+ switch(orig) {
+ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+ case SEEK_CUR:
+ if (offset) file->f_pos += offset;
+ else if (circbufValidPointer(file->f_pos, &fp) <0 ) return -EINVAL; //!no frames at the specified location or pointer is not 32-byte aligned
+ break;
+ case SEEK_END:
+ if (offset <= 0) {
+ file->f_pos = l + offset;
+ } else { //! New functionality
+//!verify the frame pointer
+ switch (offset) {
+ case LSEEK_CIRC_TORP:
+ file->f_pos=camSeqGetJPEG_rp()<<2; //! set file pointer to global read pointer, and proceed
+ case LSEEK_CIRC_PREV:
+ case LSEEK_CIRC_NEXT:
+ case LSEEK_CIRC_SETP:
+ case LSEEK_CIRC_VALID:
+ case LSEEK_CIRC_READY:
+ case LSEEK_CIRC_FREE:
+ case LSEEK_CIRC_USED:
+ if (((fvld=circbufValidPointer(file->f_pos, &fp))) <0 )
+ return -EINVAL; //!no frames at the specified location
+ }
+ switch (offset) {
+ case LSEEK_CIRC_FREE:
+ bp=(file->f_pos - (camSeqGetJPEG_wp()<<2));
+// return (bp>0)?bp:(bp+l); //!will return full buffer size if current pointer is a write pointer (waiting for the next frame)
+ return (file->f_pos=(bp>0)?bp:(bp+l)); //!Has a side effect of moving a file pointer!
+ case LSEEK_CIRC_USED:
+ bp=((camSeqGetJPEG_wp()<<2) - file->f_pos);
+// return (bp>=0)?bp:(bp+l); //!will return 0 if current pointer is a write pointer (waiting for the next frame)
+ return (file->f_pos=(bp>0)?bp:(bp+l)); //!Has a side effect of moving a file pointer!
+ case LSEEK_CIRC_TORP:
+ break;
+ case LSEEK_CIRC_TOWP:
+ file->f_pos=camSeqGetJPEG_wp()<<2; // no checking if it is valid
+ break;
+ case LSEEK_CIRC_LAST:
+ file->f_pos=camSeqGetJPEG_wp()<<2;
+ fvld=circbufValidPointer(file->f_pos, &fp); //!set fp
+ case LSEEK_CIRC_PREV:
+ rp= file->f_pos >> 2;
+ fl=ccam_dma_buf[X313_BUFFSUB(rp, 9)] ^ X313_LENGTH_MASK;
+ MD11(printk("LSEEK_CIRC_PREV: rp=0x%x, fvld=%d, fl=0x%x\n", rp, fvld,fl));
+ if (fl & X313_LENGTH_MASK) {
+ if (offset==LSEEK_CIRC_LAST) break; // just don't move pointer, leave it at write pointer and return no error
+ return -EOVERFLOW; //! no frames before current
+ }
+ bp = (X313_BUFFSUB(rp, X313_PADDED_FRAME(fl))<<2); // in bytes
+ MD11(printk("LSEEK_CIRC_PREV: bp=0x%x (0x%x), circbufValidPointer=%d\n", bp, bp>>2,circbufValidPointer(rp>>2, &fp)));
+ if (circbufValidPointer(bp, &fp) < 0 ) { //! no valid frames before current
+ if (offset==LSEEK_CIRC_LAST) break; // just don't move pointer, leave it at write pointer and return no error
+ return -EOVERFLOW; //! no frames before current
+ }
+ //! move frame pointer only if there is a valid frame there
+ file->f_pos=bp;
+ break;
+ case LSEEK_CIRC_NEXT:
+ MD11(printk("LSEEK_CIRC_NEXT: rp=0x%x, fvld=%d, fp->timestamp_sec=0x%x\n", file->f_pos >> 2, fvld, fp->timestamp_sec));
+ if (fvld <=0)
+ return -EOVERFLOW; //! no frames after current
+ file->f_pos = X313_BUFFADD(file->f_pos >> 2, X313_PADDED_FRAME(fp->timestamp_sec)) <<2 ;// do it even if the next frame does not yet exist
+ break;
+ case LSEEK_CIRC_FIRST:
+ case LSEEK_CIRC_SCND:
+//! Starting from the write pointer do be able to count all the frames in the buffer
+ rp=camSeqGetJPEG_wp();
+ prev_p=rp;
+ preprev_p=prev_p; // for second
+ nf=0;
+ nz=1;
+ file->f_pos=rp<<2;
+ while ((((fvld=circbufValidPointer(rp<<2, &fp))) >= 0) & (nz>=0)) {
+ nf++;
+// file->f_pos=rp<<2;
+ preprev_p=prev_p; //! second known good (at least first one)
+ prev_p=rp; //!now - current, known good
+ fl=ccam_dma_buf[X313_BUFFSUB(rp, 9)] ^ X313_LENGTH_MASK;
+ MD11(printk("\nf=%d, rp=0x%x, fvld=%d, fl=0x%x\n",nf, rp, fvld, fl));
+ if (fl & X313_LENGTH_MASK) break; //! no frames before rp (==prev_p)
+//! move rp to the previous frame
+ rp= X313_BUFFSUB(rp, X313_PADDED_FRAME(fl));
+ if (rp > prev_p) nz-- ; // rolled through zero - make sure we'll not stuck in this loop forever
+ }
+
+ MD11(printk("after while{}: nf=%d, rp=0x%x, fvld=%d, fl=0x%x\n",nf, rp, fvld, fl));
+ file->f_pos=((offset==LSEEK_CIRC_SCND)?preprev_p:prev_p) << 2;
+ break;
+ case LSEEK_CIRC_SETP:
+ camSeqSetJPEG_rp(file->f_pos>>2);
+ break;
+ case LSEEK_CIRC_VALID:
+ break;
+ case LSEEK_CIRC_READY:
+ if (fvld <=0) return -EINVAL; //! no frame is available better code?
+ break;
+ case LSEEK_CIRC_WAIT:
+ while (((fvld=circbufValidPointer(file->f_pos, &fp)))==0) { //! only while not ready, ready or BAD - return
+ wait_event_interruptible(circbuf_wait_queue,(camSeqGetJPEG_wp()<<2)!=file->f_pos);
+ }
+ if (fvld < 0) return -ESPIPE; //!invalid seek - have better code?
+ return file->f_pos ; //! data already available, return file pointer
+ default:
+ if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) {
+ wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
+ }
+ }
+ return ( file->f_pos ); //! file position >=0
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ // roll-over position
+ while (file->f_pos < 0) file->f_pos+=l;
+ while (file->f_pos > l) file->f_pos-=l;
+ if ((orig !=SEEK_END) && (file->f_pos == l)) file->f_pos=0; //!only for lseek (fd,0,SEEK_END) the result will be file size, others will roll to 0
+ return file->f_pos ;
+}
+
+ssize_t circbuf_write(struct file * file, const char * buf, size_t count, loff_t *off) {
+ unsigned long p;
+ char *char_pb = (char *)ccam_dma_buf;
+ D(printk("circbuf_write\n"));
+/// ************* NOTE: Never use file->f_pos in write() and read() !!!
+ p = *off;
+ if(p >= (CCAM_DMA_SIZE << 2))
+ p = (CCAM_DMA_SIZE << 2);
+ if((p + count) > (CCAM_DMA_SIZE << 2)) { // truncate count
+ count = (CCAM_DMA_SIZE << 2) - p;
+ }
+ if(count) {
+ if(copy_from_user(&char_pb[p], buf, count))
+ return -EFAULT;
+ *off += count;
+ }
+ return count;
+}
+
+ssize_t circbuf_read(struct file * file, char * buf, size_t count, loff_t *off) {
+ unsigned long p;
+ char * char_pb = (char *) ccam_dma_buf;
+ p = *off;
+ D(printk("circbuf_read pos=%d,count=%d, off=%d\r\n",p,count,off ));
+ if (p >= (CCAM_DMA_SIZE<<2)) p = (CCAM_DMA_SIZE<<2);
+ if( (p + count) > (CCAM_DMA_SIZE<<2)) { // truncate count
+ count = (CCAM_DMA_SIZE<<2) - p;
+ }
+ if (count) {
+ if (copy_to_user(buf, &char_pb[p], count)) return -EFAULT;
+// file->f_pos+=count;
+ *off+=count;
+ }
+ return count;
+}
+
+int circbuf_mmap (struct file *file, struct vm_area_struct *vma) {
+
+ int rslt;
+
+ MD7(printk("vm_start=%lx\r\n",vma->vm_start));
+ MD7(printk("vm_end=%lx\r\n",vma->vm_end));
+ MD7(printk("vm_pgoff=%lx\r\n",vma->vm_pgoff));
+ MD7(printk("vm_file=%lx\r\n",(unsigned long) (vma->vm_file)));
+ MD7(printk("ccam_dma_buf=%lx\r\n",(unsigned long) (virt_to_phys (&ccam_dma_buf[0]))));
+ /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
+ rslt=remap_pfn_range(vma,
+ vma->vm_start,
+// ((unsigned long)(&ccam_dma_buf[0])) >> PAGE_SHIFT, // Should be page-aligned
+ ((unsigned long) virt_to_phys(&ccam_dma_buf[0])) >> PAGE_SHIFT, // Should be page-aligned
+ vma->vm_end-vma->vm_start,
+ vma->vm_page_prot);
+
+ MD7(printk("remap_pfn_range returned=%x\r\n",rslt));
+ if (rslt) return -EAGAIN;
+// vma->vm_ops = &simple_remap_vm_ops;
+// simple_vma_open(vma);
+ return 0;
+}
+/*!===========================================================================
+ *! If the current read pointer is invalid, circbuf_poll returns POLLHUP
+ *! as no data will be ever available until file poinetr is reset.
+ *! if it is valid, wait is setup and the blocking condition occurs
+ *! ifthe current file pointer is equal to the FPGA write pointer
+ *!===========================================================================*/
+unsigned int circbuf_poll (struct file *file, poll_table *wait) {
+ struct interframe_params_t * fp;
+ struct circbuf_pd * privData;
+ privData = (struct circbuf_pd *) file->private_data;
+ int rslt; //!result of testing read poinetr
+ MD10(printk("circbuf_poll\n"));
+ rslt= circbufValidPointer(file->f_pos, &fp);
+ if (rslt < 0) { //! not a valid read pointer, probable buffer overrun
+ MD10(printk("circbuf_poll:invalid pointer\n"));
+ return POLLHUP ;
+ } else if (rslt > 0) {
+ return POLLIN | POLLRDNORM; //! there was frame already available
+ } else { //! pointer valid, no frame yet
+ poll_wait(file, &circbuf_wait_queue, wait);
+//! Frame might become available during call to poll_wait so nobody will wake us up.
+//! Let's see if there is stillno frame
+ if ((camSeqGetJPEG_wp()<<2)!=file->f_pos) return POLLIN | POLLRDNORM; //! we are lucky - got it
+ }
+ return 0; // nothing ready
+}
+
+
+static int __init circbuf_all_init(void) {
+ int res;
+ MDF19(printk("\n"));
+ res = register_chrdev(CIRCBUF_MAJOR, "circbuf_operations", &circbuf_fops);
+ if(res < 0) {
+ printk(KERN_ERR "\ncircbuf_all_init: couldn't get a major number %d.\n",CIRCBUF_MAJOR);
+ return res;
+ }
+
+ MDF19(printk("init_waitqueue_head()\n"));
+ init_waitqueue_head(&circbuf_wait_queue);
+ MDF19(printk("jpeg_htable_init()\n"));
+ jpeg_htable_init (); /// set default Huffman table, encode it for the FPGA
+ printk(CIRCBUF_DRIVER_NAME"- %d\n",CIRCBUF_MAJOR);
+ return 0;
+}
+
+
+module_init(circbuf_all_init);
+MODULE_LICENSE("GPLv3.0");
+MODULE_AUTHOR("Andrey Filippov .");
+MODULE_DESCRIPTION(CIRCBUF_DRIVER_NAME);
+
diff --git a/src/drivers/elphel/circbuf.h b/src/drivers/elphel/circbuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..09ec0d72d198818dca2d0a855a05407c66609b3e
--- /dev/null
+++ b/src/drivers/elphel/circbuf.h
@@ -0,0 +1,34 @@
+// FILE NAME : cxsdma.h
+// read/write image and FPN buffers from SDRAM
+
+#ifndef _CIRCBUF_H
+#define _CIRCBUF_H
+
+#include
+
+int circbuf_all_open (struct inode *inode, struct file *filp); // set filesize
+int circbuf_all_release(struct inode *inode, struct file *filp);
+loff_t circbuf_all_lseek (struct file * file, loff_t offset, int orig);
+ssize_t circbuf_all_write (struct file * file, const char * buf, size_t count, loff_t *off);
+ssize_t circbuf_all_read (struct file * file, char * buf, size_t count, loff_t *off);
+int circbuf_all_mmap (struct file *file, struct vm_area_struct *vma);
+unsigned int circbuf_all_poll (struct file *file, poll_table *wait);
+//!just to notify it is not implemented
+int circbuf_all_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+
+
+
+int circbuf_open (struct inode *inode, struct file *filp); // set filesize
+loff_t circbuf_lseek (struct file * file, loff_t offset, int orig);
+ssize_t circbuf_write (struct file * file, const char * buf, size_t count, loff_t *off);
+ssize_t circbuf_read (struct file * file, char * buf, size_t count, loff_t *off);
+int circbuf_mmap (struct file *file, struct vm_area_struct *vma);
+unsigned int circbuf_poll (struct file *file, poll_table *wait);
+
+void init_ccam_dma_buf_ptr(void);
+/*!======================================================================================
+ *! Wait queue for the processes waiting for a new frame to appear in the circular buffer
+ *!======================================================================================*/
+extern wait_queue_head_t circbuf_wait_queue;
+
+#endif /* _CIRCBUF_H */
diff --git a/src/drivers/elphel/exif.h b/src/drivers/elphel/exif.h
new file mode 100644
index 0000000000000000000000000000000000000000..88e477ee828f26413f63c99f6688c5247029660e
--- /dev/null
+++ b/src/drivers/elphel/exif.h
@@ -0,0 +1,45 @@
+#ifndef __F_EXIF__H_
+#define __F_EXIF__H_
+
+extern unsigned char exif_header[];
+int exif_header_length(void);
+
+#define EXIF_OFFSET 4
+
+#define EXIF_FIRMWARE 0xC4
+#define EXIF_FIRMWARE_LEN 27
+
+//#define EXIF_DATE_TIME 0x7A
+#define EXIF_DATE_TIME 0xE0
+#define EXIF_DATE_TIME_LEN 20
+
+//#define EXIF_ARTIST 0x8E
+#define EXIF_ARTIST 0xF4
+#define EXIF_ARTIST_LEN 18
+
+//#define EXIF_DATE_TIME_OR 0xCA
+#define EXIF_DATE_TIME_OR 0x0138
+#define EXIF_DATE_TIME_OR_LEN 20
+
+//#define EXIF_SUBSEC_OR 0xDE
+#define EXIF_SUBSEC_OR 0x014C
+#define EXIF_SUBSEC_OR_LEN 7
+
+//#define EXIF_EXP 0xE6
+#define EXIF_EXP 0x0130
+#define EXIF_EXP_LEN 8
+
+#define EXIF_IMAGE_ID 0x6E
+#define EXIF_IMAGE_ID_LEN 64
+
+struct exif_desc_t {
+ unsigned char date_time[EXIF_DATE_TIME_LEN];
+ unsigned char date_time_or[EXIF_DATE_TIME_OR_LEN];
+ unsigned char subsec[EXIF_SUBSEC_OR_LEN];
+ unsigned char artist[EXIF_ARTIST_LEN];
+ unsigned char firmware[EXIF_FIRMWARE_LEN];
+ unsigned long exp[2];
+};
+extern struct exif_desc_t exif_desc;
+
+#endif //__F_EXIF__H_
diff --git a/src/drivers/elphel/framepars.c b/src/drivers/elphel/framepars.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ea9ce724bb08a5d2d411928e359caceb417c3c5
--- /dev/null
+++ b/src/drivers/elphel/framepars.c
@@ -0,0 +1,1345 @@
+/*!********************************************************************************
+*! FILE NAME : framepars.c
+*! DESCRIPTION: Handling of frame parameters, making use of FPGA i2c
+*! and command sequencer that accepts commands up to 6 frames ahead.
+*! This module includes parameter storage, code called from ISR,
+*! from other kernel drivers as well as from the user space
+*! Copyright (C) 2008 Elphel, Inc.
+*! -----------------------------------------------------------------------------**
+*!
+*! This program is free software: you can redistribute it and/or modify
+*! it under the terms of the GNU General Public License as published by
+*! the Free Software Foundation, either version 3 of the License, or
+*! (at your option) any later version.
+*!
+*! This program is distributed in the hope that it will be useful,
+*! but WITHOUT ANY WARRANTY; without even the implied warranty of
+*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*! GNU General Public License for more details.
+*!senssensor_common.hor_common.h
+*! You should have received a copy of the GNU General Public License
+*! along with this program. If not, see .
+*! -----------------------------------------------------------------------------**
+*! $Log: framepars.c,v $
+*! Revision 1.14 2011/12/22 05:39:07 elphel
+*! catching up after some missed interrupts
+*!
+*! Revision 1.13 2010/08/10 21:10:41 elphel
+*! portrait mode now includes all 4 rotations (2 bits)
+*!
+*! Revision 1.12 2010/08/03 23:37:34 elphel
+*! rev 8.0.8.37, portrait mode support
+*!
+*! Revision 1.11 2010/05/25 00:52:23 elphel
+*! 8.0.8.20, working on multi-sensor
+*!
+*! Revision 1.10 2010/05/21 06:12:16 elphel
+*! continue working on multi-sensor software
+*!
+*! Revision 1.9 2010/05/16 02:03:47 elphel
+*! 8.0.8.4 - driver working with individual/broadcast sensor registers
+*!
+*! Revision 1.8 2010/05/13 03:39:31 elphel
+*! 8.0.8.12 - drivers modified for multi-sensor operation
+*!
+*! Revision 1.7 2010/04/28 02:34:33 elphel
+*! 8.0.6.6 - added support for linescan mode (also useful for high fps small images). 2.5K full line pairs/second with 5MPix sensor
+*!
+*! Revision 1.6 2010/04/06 20:35:42 elphel
+*! 8.0.7.5 - made the fpgaclock driver program 10359 clock in addition to the system one
+*!
+*! Revision 1.5 2010/01/27 22:51:52 elphel
+*! turned off ELPHEL_DEBUG, fixed errors caused by that.
+*!
+*! Revision 1.4 2008/12/02 19:08:54 elphel
+*! Bug fixin setFramePar()
+*!
+*! Revision 1.3 2008/11/30 05:01:03 elphel
+*! Changing gains/scales behavior
+*!
+*! Revision 1.2 2008/11/28 08:17:09 elphel
+*! keeping Doxygen a little happier
+*!
+*! Revision 1.1.1.1 2008/11/27 20:04:00 elphel
+*!
+*!
+*! Revision 1.41 2008/11/17 06:42:37 elphel
+*! added SETFRAMEREL - skipping specified number of frames from current (through lseek)
+*!
+*! Revision 1.40 2008/11/14 07:09:48 elphel
+*! additional test to prevent "JUST_THIS" parameters to be written to the future-most frame (otherwise it can get stuck)
+*!
+*! Revision 1.39 2008/11/13 05:40:45 elphel
+*! 8.0.alpha16 - modified histogram storage, profiling
+*!
+*! Revision 1.38 2008/11/05 02:01:25 elphel
+*! Added bit field manipulation in parameters
+*!
+*! Revision 1.37 2008/11/02 00:31:25 elphel
+*! reduced required initialization steps
+*!
+*! Revision 1.36 2008/10/29 04:18:28 elphel
+*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
+*!
+*! Revision 1.35 2008/10/25 19:59:48 elphel
+*! added lseek() calls to enable/disable daemons at events (compressed frame available, any frame available, histogram-Y and histograms-C available)
+*!
+*! Revision 1.34 2008/10/23 18:25:40 elphel
+*! removed unneeded test condition before calling wait_event_interruptible()
+*!
+*! Revision 1.33 2008/10/23 08:03:38 elphel
+*! cleanup
+*!
+*! Revision 1.32 2008/10/21 21:28:26 elphel
+*! minor bug fix
+*!
+*! Revision 1.31 2008/10/20 18:46:36 elphel
+*! all the functions for the same target frame are processed in the order regardless of latencies
+*!
+*! Revision 1.30 2008/10/19 06:51:51 elphel
+*! rearranged initialization, added frame number reset (to avoid unlikely integer overflow)
+*!
+*! Revision 1.29 2008/10/17 05:44:48 elphel
+*! fixing latencies
+*!
+*! Revision 1.28 2008/10/15 22:28:56 elphel
+*! snapshot 8.0.alpha2
+*!
+*! Revision 1.27 2008/10/12 06:13:10 elphel
+*! snapshot
+*!
+*! Revision 1.26 2008/10/11 18:46:07 elphel
+*! snapshot
+*!
+*! Revision 1.25 2008/10/10 17:06:59 elphel
+*! just a snapshot
+*!
+*! Revision 1.24 2008/10/08 21:26:25 elphel
+*! snapsot 7.2.0.pre4 - first images (actually - second)
+*!
+*! Revision 1.23 2008/10/06 08:31:08 elphel
+*! snapshot, first images
+*!
+*! Revision 1.22 2008/10/05 05:13:33 elphel
+*! snapshot003
+*!
+*! Revision 1.21 2008/10/04 16:10:12 elphel
+*! snapshot
+*!
+*! Revision 1.20 2008/09/28 00:31:57 elphel
+*! snapshot
+*!
+*! Revision 1.19 2008/09/25 00:58:11 elphel
+*! snapshot
+*!
+*! Revision 1.18 2008/09/20 00:29:50 elphel
+*! moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
+*!
+*! Revision 1.17 2008/09/19 04:37:25 elphel
+*! snapshot
+*!
+*! Revision 1.16 2008/09/16 00:49:31 elphel
+*! snapshot
+*!
+*! Revision 1.15 2008/09/12 20:40:11 elphel
+*! snapshot
+*!
+*! Revision 1.14 2008/09/12 00:28:54 elphel
+*! typo fixed
+*!
+*! Revision 1.13 2008/09/12 00:23:59 elphel
+*! removed cc353.c, cc353.h
+*!
+*! Revision 1.12 2008/09/07 19:48:08 elphel
+*! snapshot
+*!
+*! Revision 1.11 2008/09/05 23:20:26 elphel
+*! just a snapshot
+*!
+*! Revision 1.10 2008/09/04 17:37:13 elphel
+*! documenting
+*!
+*! Revision 1.9 2008/09/02 21:01:06 elphel
+*! just next...
+*!
+*! Revision 1.8 2008/07/27 04:27:49 elphel
+*! next snapshot
+*!
+*! Revision 1.7 2008/06/24 00:43:44 elphel
+*! just a snapshot
+*!
+*! Revision 1.6 2008/06/20 03:54:19 elphel
+*! another snapshot
+*!
+*! Revision 1.5 2008/06/19 02:17:36 elphel
+*! continuing work - just a snapshot
+*!
+*! Revision 1.4 2008/06/16 06:51:21 elphel
+*! work in progress, intermediate commit
+*!
+*! Revision 1.3 2008/06/10 00:03:14 elphel
+*! storing past frame data - subset of the frame parameters
+*!
+*! Revision 1.2 2008/06/08 23:48:39 elphel
+*! minor cleanup
+*!
+*! Revision 1.1 2008/05/26 23:33:00 elphel
+*! Added driver to handle multi-frame parameters
+*!
+*!
+*/
+
+//copied from cxi2c.c - TODO:remove unneeded
+
+
+#include /// div for 64
+#include /// div for 64
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+//#include
+#include
+
+//#include
+#include // endians
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+//#include "fpgactrl.h" // defines port_csp0_adsensor_common.hdr, port_csp4_addr
+//#include "cc3x3.h"
+//#include "x3x3.h" // hardware definitions
+
+
+#include "sensor_common.h"
+#include "framepars.h"
+#include "param_depend.h" // specifies what functions should be called for different parameters changed
+/// needed for lseek commands
+//#include "cxdma.h" // x313_dma_init
+//#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on'
+
+
+/**
+ * \def MDF1(x) optional debug output
+ */
+
+#if ELPHEL_DEBUG
+ #define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;}
+ #define MDF2(x) { if (GLOBALPARS(G_DEBUG) & (1 <<2)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
+/// setFrameParsAtomic
+ #define MDF5(x) { if (GLOBALPARS(G_DEBUG) & (1 <<5)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
+ #define D5(x) { if (GLOBALPARS(G_DEBUG) & (1 <<5)) {x ;} }
+/// processPars
+ #define MDF6(x) { if (GLOBALPARS(G_DEBUG) & (1 <<6)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
+ #define D6(x) { if (GLOBALPARS(G_DEBUG) & (1 <<6)) {x ;} }
+///update FramePars
+ #define MDF7(x) { if (GLOBALPARS(G_DEBUG) & (1 <<7)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
+ #define D7(x) { if (GLOBALPARS(G_DEBUG) & (1 <<7)) {x ;} }
+/// setFramePar[s]
+ #define MDF8(x) { if (GLOBALPARS(G_DEBUG) & (1 <<8)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
+ #define D8(x) { if (GLOBALPARS(G_DEBUG) & (1 <<8)) {x ;} }
+ #define ELPHEL_DEBUG_THIS 0
+// #define ELPHEL_DEBUG_THIS 1
+#else
+ #define MDF(x)
+ #define MDF2(x)
+ #define MDF5(x)
+ #define D5(x)
+ #define MDF6(x)
+ #define D6(x)
+ #define MDF7(x)
+ #define D7(x)
+ #define MDF8(x)
+ #define D8(x)
+ #define ELPHEL_DEBUG_THIS 0
+#endif
+
+
+#if ELPHEL_DEBUG_THIS
+ #define MDD1(x) printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__); x ; udelay (ELPHEL_DEBUG_DELAY)
+ #define MDF1(x) printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__); x
+ #define D1(x) x
+ #define D1I(x)
+
+#else
+ #define MDD1(x)
+ #define MDF1(x)
+ #define D1(x)
+ #define D1I(x) x
+#endif
+//#define ELP_KERR(x) printk("%s:%d:%s: ERROR ",__FILE__,__LINE__,__FUNCTION__); x
+
+/**
+ * \def X3X3_FRAMEPARS_DRIVER_NAME driver name to display
+ */
+
+#define X3X3_FRAMEPARS_DRIVER_NAME "Elphel (R) Model 353 Frame Parameters device driver"
+
+static struct framepars_all_t sFrameParsAll __attribute__ ((aligned (PAGE_SIZE))); ///< Sensor Parameters, currently 8 pages all and 2048 pages some, static struct
+unsigned long frameParsInitialized; /// set to 0 at startup, 1 after initialization that is triggered by setParsAtomic()
+#define thisFrameNumber GLOBALPARS(G_THIS_FRAME) // Current frame number (may lag from the hardware)
+#define THISFRAMENUMBER GLOBALPARS(G_THIS_FRAME) // Current frame number (may lag from the hardware)
+
+struct framepars_all_t *frameparsall=NULL; /// - will be mmap-ed
+struct framepars_t *framepars= NULL; ///< getting rid of static to be able to use extern
+struct framepars_past_t *pastpars= NULL; ///< getting rid of static to be able to use extern
+unsigned long *funcs2call= NULL; /// sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used
+unsigned long *globalPars= NULL; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
+unsigned long *multiSensIndex= NULL; /// index for per-sensor alternatives
+unsigned long *multiSensRvrsIndex=NULL; /// reverse index (to parent) for the multiSensIndex
+wait_queue_head_t framepars_wait_queue; /// used to wait for the frame to be acquired
+
+
+/**
+ * @brief file private data
+ */
+struct framepars_pd {
+ int minor; ///< file minor value
+ struct wait_queue *framepars_wait_queue; ///< wait queue (waiting for file number to increase) ///NOTE: not used at all?
+// something else to be added here?
+};
+
+
+
+/**
+ * @brief assign non-static pointers to static data to be used as extern
+ */
+void init_framepars_ptr(void) {
+ frameparsall= &sFrameParsAll; /// - will be mmap-ed
+ framepars = sFrameParsAll.framePars;
+ pastpars = sFrameParsAll.pastPars;
+ funcs2call = sFrameParsAll.func2call.pars; /// each parameter has a 32-bit mask of what pgm_function to call - other fields not used
+ globalPars = sFrameParsAll.globalPars; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
+ multiSensIndex= sFrameParsAll.multiSensIndex; /// indexes of individual sensor register shadows (first of 3) - now for all parameters, not just sensor ones
+ multiSensRvrsIndex= sFrameParsAll.multiSensRvrsIndex; /// reverse index (to parent) for the multiSensIndex
+
+}
+
+int framepars_open (struct inode *inode, struct file *filp);
+int framepars_release(struct inode *inode, struct file *filp);
+loff_t framepars_lseek (struct file * file, loff_t offset, int orig);
+ssize_t framepars_write (struct file * file, const char * buf, size_t count, loff_t *off);
+int framepars_mmap (struct file *file, struct vm_area_struct *vma);
+static int __init framepars_init(void);
+
+/**
+ * @brief Reset hardware sequencers (i2c, command) and initialize framepars structure
+ */
+void initSequencers(void) {
+ unsigned long flags;
+ MDF2(printk ("\n"));
+ printk ("initSequencers:resetting both sequencers\n");
+#ifdef TEST_DISABLE_CODE
+ local_irq_save(flags);
+ X3X3_SEQ_RESET;
+ i2c_reset_wait();
+ local_irq_restore(flags);
+ initFramePars();
+#endif
+}
+
+/**
+ * @brief reset absolute frame number \b thisFrameNumber to \b frame8
+ */
+void resetFrameNumber(void) {
+ int i;
+#ifdef TEST_DISABLE_CODE
+ thisFrameNumber= X3X3_I2C_FRAME;
+#endif
+ MDF2(printk (" thisFrameNumber=0x%lx\n",thisFrameNumber));
+// write absolute frame numbers
+ for (i=thisFrameNumber; i<(thisFrameNumber+PARS_FRAMES); i++) framepars[i & PARS_FRAMES_MASK].pars[P_FRAME]=i;
+/// initialize frameParsDeps.pars masks:
+}
+
+/**
+ * @brief initialize all parameters, set \b thisFrameNumber to \b frame number read from hardware hardware ( 0 after resetting i2c and cmd_seq)
+ */
+void initFramePars(void) {
+ int i;
+ memset(framepars, 0, sizeof(framepars));
+ resetFrameNumber();
+/// initialize frameParsDeps.pars masks:
+ for (i=0; i < (sizeof(param_depend_tab)/8); i++) {
+ funcs2call[param_depend_tab[2*i] & 0xffff]=param_depend_tab[2*i+1]; /// remove possible flags
+ MDF2(printk("funcs2call[0x%lx]=0x%08lx\n",param_depend_tab[2*i] & 0xffff,param_depend_tab[2*i+1]));
+ }
+ for (i=0; i < P_SENSOR_NUMREGS; i++) funcs2call[P_SENSOR_REGS+i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
+/// Same for 10359 registers - will not change anything if there is no 10359 - these registers will not be chnaged, and if will be it wil cause no action
+ for (i=0; i < P_M10359_NUMREGS; i++) funcs2call[P_M10359_REGS+i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
+
+ initMultiPars(); /// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
+ frameParsInitialized=1;
+}
+
+/**
+ * @brief reset all global parameters, set default for debug mask (if ELPHEL_DEBUG)
+ */
+void initGlobalPars(void) {
+ memset(&globalPars[GLOBALS_PRESERVE], 0, sizeof(globalPars)-GLOBALS_PRESERVE*sizeof(globalPars[0]));
+/// MDF(GLOBALPARS(G_DEBUG) = ELPHEL_DEBUG_STARTUP;// removed - add write to fpga init script
+ MDF(printk("GLOBALPARS(G_DEBUG)=%lx\n",GLOBALPARS(G_DEBUG)));
+}
+
+/**
+ * @brief initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
+ * @return number of multi-regs
+ */
+int initMultiPars(void) {
+ int i,j,n;
+ int ireg=P_MULTI_REGS; /// multi-reg shadows start index
+ unsigned long m;
+ memset(multiSensIndex, 0, sizeof(multiSensIndex));
+ memset(multiSensRvrsIndex, 0, sizeof(multiSensRvrsIndex));
+ GLOBALPARS(G_MULTI_NUM)=0;
+ for (i=0;i<8;i++) {
+ m=GLOBALPARS(G_MULTI_REGSM+i); /// 1 bit per register that need individual shadows
+// MDF(printk("i=%d, m=0x%lx\n",i,m));
+ for (j= P_SENSOR_REGS +(i<<5); m && (GLOBALPARS(G_MULTI_NUM)>= 1) {
+ if (m & 1) {
+ multiSensIndex[j]=ireg;
+// MDF(printk("j=0x%x ireg=0x%x\n",j,ireg));
+ for (n=0;nheight= framepars[findex_this].pars[P_ACTUAL_HEIGHT]; /// NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy
+ interframe_pars->color= framepars[findex_this].pars[P_COLOR];
+ interframe_pars->byrshift=framepars[findex_this].pars[P_COMPMOD_BYRSH];
+ interframe_pars->quality2 |= (framepars[findex_this].pars[P_PORTRAIT] & 1) << 7;
+ }
+/// copy parameters from findex_future (old "fartherst in the future") to findex_prev (new "fartherst in the future") if it was changed since
+ if ((bmask32=framepars[findex_prev].modsince32)) {
+ MDF7(printk("framepars[%d].modsince32=0x%lx\n",findex_prev,bmask32));
+ for (index32=0; bmask32; index32++, bmask32 >>= 1) {
+ if (bmask32 & 1) {
+ for (index=(index32<<5),bmask=framepars[findex_prev].modsince[index32]; bmask; index++, bmask >>= 1)
+ if (bmask & 1) {
+ framepars[findex_prev].pars[index] = framepars[findex_future].pars[index];
+ MDF7(printk("hw=%d framepars[%d].pars[%d]=framepars[%d].pars[%d]=0x%lx\n",frame8, findex_prev,index,findex_future,index,framepars[findex_future].pars[index]));
+ }
+ framepars[findex_prev].modsince[index32]=0; /// mark as not "modified since" (yet)
+ }
+ }
+ framepars[findex_prev].modsince32=0;/// mark as not "modified since" super index
+ }
+/// clear "modified" and flags on the brand new future frame
+ if (framepars[findex_prev].mod32) memset(framepars[findex_prev].mod, 0, 32*4); /// .mod[0]-.mod[30], .mod32
+ framepars[findex_prev].functions=0; /// No functions yet needed on the brand new frame
+ framepars[findex_prev].pars[P_FRAME]=thisFrameNumber+7; /// that will be the full frame number
+/// NOTE: Handle past due - copy functions, and mod if functions were non-zero
+ if (framepars[findex_this].functions) { /// Some functions were not yet processed (past due)
+ if (!(get_globalParam(G_TASKLET_CTL) & (1 << TASKLET_CTL_IGNPAST))) {
+ framepars[findex_next].functions |= framepars[findex_this].functions;
+ if ((bmask32=framepars[findex_this].mod32)) {
+ for (index32=0; bmask32; index32++, bmask32 >>= 1) {
+ if (bmask32 & 1) {
+ framepars[findex_next].mod[index32] |= framepars[findex_this].mod[index32];
+ }
+ framepars[findex_next].mod32 |= framepars[findex_this].mod32;
+ }
+ }
+ MDF7(printk ("resubmitting past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber,findex_this));
+ } else {
+ MDF(printk ("Ignored past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber,findex_this));
+ }
+ }
+ thisFrameNumber++;
+ }
+}
+
+
+/**
+ * @brief process parameters that are overdue or due in ASAP mode (not through the sequencer)
+ * Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?)
+ * @param sensorproc
+ * @param frame8
+ */
+inline void processParsASAP (struct sensorproc_t * sensorproc, int frame8) {
+ unsigned long todo, mask , remain;
+ int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8
+ int frame_proc; /// current frame for which parameters are considered
+ struct framepars_t * procpars;
+ struct framepars_t * prevpars ; /// maybe - drop calculation for each function, move it to pgm_* where needed?
+ unsigned long * p_nasap=& GLOBALPARS(G_CALLNASAP);
+ int i;
+ int rslt;
+#if ELPHEL_DEBUG
+ unsigned long allfunctions=framepars[0].functions | framepars[1].functions | framepars[2].functions | framepars[3].functions |
+ framepars[4].functions | framepars[5].functions | framepars[6].functions | framepars[7].functions;
+ if (allfunctions) MDF6(printk("frame8=%d, functions: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", frame8, framepars[0].functions,framepars[1].functions,framepars[2].functions,framepars[3].functions,framepars[4].functions,framepars[5].functions,framepars[6].functions,framepars[7].functions));
+
+#endif
+/// do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
+/// Now try overdue functions with latencies >=1 and try them in ASAP mode
+ for (pars_ahead=0; pars_ahead <= 4; pars_ahead++ ) {
+ frame_proc=(frame8 + pars_ahead) & PARS_FRAMES_MASK;
+ procpars = &framepars[frame_proc];
+ prevpars = &framepars[(frame_proc-1) & PARS_FRAMES_MASK];
+ i=0;
+ mask=1;
+ remain=0xffffffff;
+ while ((todo=(pars_ahead)?
+ (p_nasap[pars_ahead] & (procpars->functions) & remain):
+ (procpars->functions & remain) )) { ///none, *1, *2,*3,*4
+
+ while (!(todo & mask)) { /// skip zeros - todo will stay current (.functions will not change
+ i++;
+ mask <<=1;
+ remain <<=1;
+ }
+/// now (todo & mask) !=0
+ MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx\n", todo, procpars->functions, frame8,pars_ahead,frame_proc,i,mask));
+
+ MDF6(printk(" %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", framepars[0].functions,framepars[1].functions,framepars[2].functions,framepars[3].functions,framepars[4].functions,framepars[5].functions,framepars[6].functions,framepars[7].functions));
+
+ if (sensorproc->pgm_func[i]) {
+ rslt=sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, -1);
+ } else rslt=0; /// only sensor-specific function, nothing to do common to all sensors
+ if ((rslt >= 0) && (sensorproc->pgm_func[i+32])) { /// sensor - specific functions, called after the main ones
+ rslt=sensorproc->pgm_func[i+32] ( &(sensorproc->sensor), procpars, prevpars, -1);
+ }
+/// Nothing to do with errors here - just report?
+ if (rslt<0) printk("%s:%d:%s - error=%d",__FILE__,__LINE__,__FUNCTION__, rslt);
+ procpars->functions &= ~mask;
+ MDF6(printk(".functions=0x%08lx)\n", procpars->functions));
+ i++;
+ mask <<=1;
+ remain <<=1;
+ }
+ }
+}
+/// Next 5 should go in that sequence
+//#define G_CALLNASAP 119 // bitmask - what functions can be used not only in the current frame (ASAP) mode
+//#define G_CALLNEXT1 120 // bitmask of actions to be one or more frames ahead of the programmed one (OR-ed with G_CALLNEXT2..G_CALLNEXT4)
+//#define G_CALLNEXT2 121 // bitmask of actions to be two or more frames ahead of the programmed one (OR-ed with G_CALLNEXT3..G_CALLNEXT4)
+//#define G_CALLNEXT3 122 // bitmask of actions to be three or more frames ahead of the programmed one (OR-ed with G_CALLNEXT4)
+//#define G_CALLNEXT4 123 // bitmask of actions to be four or more frames ahead of the programmed one
+
+
+inline void processParsSeq (struct sensorproc_t * sensorproc, int frame8, int maxahead) {
+ unsigned long todo, mask , remain;
+ int job_ahead; /// doing job "job_ahead" ahead of needed
+ int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8
+ int frame_proc; /// current frame for which parameters are considered
+ struct framepars_t * procpars;
+ struct framepars_t * prevpars ; /// maybe - drop calculation fpr each function, move it to pgm_* where needed?
+ unsigned long * p_nasap=& GLOBALPARS(G_CALLNASAP);
+ int seq_frame; /// sequencer frame for which pgm_* function should schedule data
+ int i;
+ int rslt;
+ int max_par_ahead;
+ int this_ahead;
+ if (maxahead > (PARS_FRAMES-3)) maxahead = PARS_FRAMES-3; /// use 5 if maxahead >5
+/// commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
+/// Modifying - as soon as found the frame to process with non-zero masked .functions - process all functions for that
+/// frame with appropriate sequencer frame.
+/// For now - scan p_nasap[i] to find latency - improve that later
+ for (job_ahead=0; job_ahead <= maxahead; job_ahead++ ) {
+ max_par_ahead=min(5,(PARS_FRAMES-3) -job_ahead);
+ for (pars_ahead=0; pars_ahead < max_par_ahead; pars_ahead++ ) {
+ frame_proc=(frame8 + job_ahead + pars_ahead +1) & PARS_FRAMES_MASK; ///
+ procpars = &framepars[frame_proc];
+/// Check if at least one function is needed for frame_proc
+ if (procpars->functions &
+ p_nasap[pars_ahead] & ///all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
+ p_nasap[0]) {
+ prevpars = &framepars[(frame_proc-1) & PARS_FRAMES_MASK];
+// seq_frame= (frame8+job_ahead+1) & PARS_FRAMES_MASK;
+ i=0;
+ mask=1;
+ remain=0xffffffff;
+ while ((todo=procpars->functions &
+/// p_nasap[pars_ahead] & ///all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
+ p_nasap[0] & remain)) { /// eliminate ASAP-only function
+ while (!(todo & mask)) { /// skip zeros - todo will stay current (.functions will not change)
+ i++;
+ mask <<=1;
+ remain <<=1;
+ }
+/// now (todo & mask) !=0
+/// find the right latency
+ for (this_ahead=1; (p_nasap[this_ahead] & todo & mask) && (this_ahead <=4); this_ahead++); /// this_ahead==1..5
+// seq_frame= (frame8 + job_ahead + this_ahead) & PARS_FRAMES_MASK;
+ seq_frame= (frame_proc+1-this_ahead) & PARS_FRAMES_MASK;
+
+ MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, frame_proc=%d, seq_frame=%d, i=%d, mask=0x%08lx\n", todo, procpars->functions, frame8,frame_proc,seq_frame,i,mask));
+ MDF6(printk(" %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", framepars[0].functions,framepars[1].functions,framepars[2].functions,framepars[3].functions,framepars[4].functions,framepars[5].functions,framepars[6].functions,framepars[7].functions));
+
+ if (sensorproc->pgm_func[i]) {
+ /// NOTE: Was (frame8+job_ahead +1) & PARS_FRAMES_MASK
+ rslt=sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, seq_frame);
+ } else rslt=0; /// only sensor-specific function, nothing to do common to all sensors
+ if ((rslt >= 0) && (sensorproc->pgm_func[i+32])) { /// sensor - specific functions, called after the main ones
+ rslt=sensorproc->pgm_func[i+32] ( &(sensorproc->sensor), procpars, prevpars, seq_frame);
+ }
+ if (rslt >= 0) {
+ procpars->functions &= ~mask; /// mark it done
+ } else {
+ MDF6(printk("Error - function result was %d\n", rslt));
+ }
+ i++;
+ mask <<=1;
+ remain <<=1;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief Program image acquisition, according to the parameters changed
+ * Called from ISR?
+ * @param sensorproc pointer to sensor static parameters and functions
+ * @param frame8 current hardware frame number
+ * @param maxahead maximal number of frames to program ahead of the current (make it P_* parameter ?)
+ * @return always 0 ?
+ */
+//TODO: "Do it later" should be the only reason not to erase todo bit
+//#define P_CALLASAP 107 // bitmask - what functions work only in the current frame (ASAP) mode
+
+void processPars (struct sensorproc_t * sensorproc, int frame8, int maxahead) {
+ frame8 &= PARS_FRAMES_MASK;
+/// first - do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
+// MDF6(printk("before first processParsASAP\n"));
+ processParsASAP (sensorproc, frame8);
+/// now - the rest commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
+/// for jobahead =0 it is still possible to have some functions in ASAP mode with non-zero latency
+// MDF6(printk("before processParsSeq\n"));
+ processParsSeq (sensorproc, frame8, maxahead);
+/// re-test ASAP tasks - they might appear as a result of other commands executed
+// MDF6(printk("before second processParsASAP\n"));
+ processParsASAP (sensorproc, frame8);
+}
+
+/**
+ * @brief schedule pgm_func to be executed for selected frame (frame8)
+ * @param frame8 frame number (3-bit) to schedule a function for
+ * @param func_num function number to schedule
+ */
+void schedule_pgm_func(int frame8, int func_num) {
+ MDF1(printk(" frame8=%d, func_num=%d\n", frame8, func_num));
+ framepars[frame8 & PARS_FRAMES_MASK].functions |= 1 << func_num;
+}
+
+/**
+ * @brief schedule pgm_func to be executed for this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK
+ * @param this_framepars pointer to frame parameters structure
+ * @param func_num number of function to schedule
+ */
+void schedule_this_pgm_func(struct framepars_t * this_framepars, int func_num) {
+ int frame8=this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK;
+ MDF1(printk(" frame8=%d, func_num=%d\n", frame8, func_num));
+ framepars[frame8].functions |= 1 << func_num;
+}
+
+
+/**
+ * @brief just return current thisFrameNumber
+ * @return current value of thisFrameNumber
+ */
+unsigned long getThisFrameNumber(void) {
+ return thisFrameNumber;
+}
+
+
+/**
+ * @brief Set parameters that will never change (usually after sensor discovery)
+ * @param numPars number of parameters to set
+ * @param pars array of parameters (number/value pairs)
+ * @return always 0
+ */
+int setFrameParsStatic(int numPars, struct frameparspair_t * pars) {
+ int npar,nframe,index;
+ for (npar=0; npar < numPars; npar++) {
+ index=pars[npar].num;
+ if (index > P_MAX_PAR) return -ERR_FRAMEPARS_BADINDEX;
+ for (nframe=0; nframe < PARS_FRAMES; nframe++) {
+ framepars[nframe].pars[index]=pars[npar].val;
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief set parameters for the specified frame (atomic, with interrupts off). Used from applications through driver write
+ * @param frameno absolute (full) frame number parameters should be applied to
+ * @param maxLatency maximal command latency (parameters should be set not less than maxLatency ahead of the current frame)
+ * maxLatency < 0 - don't check latency (i.e.only commands that are not releted to particular frames)
+ * @param numPars number of parameters to set (0 is OK to just test if it is too early/too late)
+ * @param pars array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number
+ * @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE
+ */
+///TODO: Check that writes never to the future or past frame (only 6 of 8 are allowed). Have seen just_this to flood all
+int setFrameParsAtomic(unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars) {
+ unsigned long flags;
+ int npar,nframe;
+ unsigned long val, bmask, bmask32;
+ int index,bindex;
+ if (!frameParsInitialized) {
+ initSequencers(); /// Will call initFramePars(); and initialize functions
+ }
+ int findex_this= thisFrameNumber & PARS_FRAMES_MASK;
+ int findex_prev= (findex_this-1) & PARS_FRAMES_MASK;
+ int findex_future=(findex_this-2) & PARS_FRAMES_MASK; /// actually - fartherst in the future??
+// int frame8= frameno & PARS_FRAMES_MASK;
+ int frame8;
+ MDF2(printk (": frameno=0x%lx, findex_this=%d (0x%lx) maxLatency=%d, numPars=%d\n",frameno, findex_this, thisFrameNumber, maxLatency, numPars));
+ D1I(local_irq_save(flags));
+ PROFILE_NOW(6);
+ if (maxLatency>=0) {
+ if (frameno <= (thisFrameNumber+maxLatency)) {
+ D1I(local_irq_restore(flags));
+ return -ERR_FRAMEPARS_TOOLATE;
+ }
+ else if (frameno >= (thisFrameNumber+ (PARS_FRAMES-1))) {
+ D1I(local_irq_restore(flags));
+ return -ERR_FRAMEPARS_TOOEARLY;
+ }
+ }
+ /// not too late, not too early, go ahead
+ for (npar=0; npar < numPars; npar++) {
+ D5(printk(" --pars[%d].num=0x%lx, pars[%d].val=0x%lx",npar,pars[npar].num, npar, pars[npar].val));
+// frame8= (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno & PARS_FRAMES_MASK);
+ frame8= frameno & PARS_FRAMES_MASK;
+ val=pars[npar].val;
+ index= pars[npar].num & 0xffff;
+ if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) {
+ D1I(local_irq_restore(flags));
+ return -ERR_FRAMEPARS_BADINDEX;
+ }
+ D5(printk(" index=0x%x, val=0x%lx",index, val));
+ if (index >= FRAMEPAR_GLOBALS) { /// ignore frame logic, set "static" parameters to frame 0
+ if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
+ val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(index), val);
+ }
+ GLOBALPARS(index)=val;
+ D5(printk(" set GLOBALPARS(0x%x)=0x%lx\n",index,val));
+ } else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) {
+ funcs2call[index] = val;
+ D5(printk(" set funcs2call[0x%x]=0x%lx\n",index,val));
+// } else if ((frameno !=findex_prev) && (frameno != findex_future)) { /// do not write parameters in the future otherwise
+ } else if ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick
+ if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
+ val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val);
+ }
+//TODO: optimize to use mask several parameters together
+ D5(printk(" frame8=0x%x\n",frame8));
+ if ((framepars[frame8].pars[index]!= val) || (pars[npar].num & FRAMEPAIR_FORCE_NEW)){
+ bmask= 1 << (index & 31);
+ bindex = index >> 5;
+ bmask32= 1 << bindex;
+/// Set this parameter for specified frame
+ framepars[frame8].pars[index] = val;
+ framepars[frame8].mod[bindex] |= bmask;
+ framepars[frame8].mod32 |= bmask32;
+ framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters
+ D5(printk(" bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",bindex, bmask, bmask32, framepars[frame8].functions));
+/// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS)
+ if ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0) {
+ MDF5(printk (": --- setting next frames"));
+ for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
+ framepars[nframe].pars[index] = val;
+ D5(printk (" %d",nframe));
+ }
+ frame8=(frame8-1) & PARS_FRAMES_MASK;/// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
+ D5(printk ("\n"));
+ }
+/// Mark this parameter in all previous frames as "modified since"
+/// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
+ for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here
+ framepars[nframe].modsince[bindex] |= bmask;
+ framepars[nframe].modsince32 |= bmask32;
+ }
+ }
+ } else { /// error - trying to write "just this" to the "future" - that would stick if allowed
+ D1I(local_irq_restore(flags));
+ ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num));
+ return -ERR_FRAMEPARS_TOOEARLY;
+ }
+ }
+/// Try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent
+/// effects of uncertainty of when was it called relative to frame sync
+/// Changed to all (don't care about uncertainty - they will trigger only if it is too late or during sensor detection/initialization)
+ if (!(get_globalParam(G_TASKLET_CTL) & (1<< TASKLET_CTL_NOSAME))) {
+// processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet
+ MDF5(printk ("\n"));
+ processPars (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet
+ }
+ PROFILE_NOW(7);
+ D1I(local_irq_restore(flags));
+ return 0;
+}
+//#define FRAMEPAIR_JUST_THIS 0x40000 // write only to this frame, don't propagate
+ // (like "single frame" - compressor, sensor) first write "stop", then - "single" with FRAMEPAIR_JUST_THIS
+/**
+ * @brief set a single output (calculated) parameter for the frame referenced by this_framepars structure.
+ * Shedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex
+ * @param this_framepars pointer to the current parameters structure
+ * @param mindex parameter number (with optional modifiers in high bits)
+ * @param val parameter value to set
+ * @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
+ */
+int setFramePar(struct framepars_t * this_framepars, unsigned long mindex, unsigned long val) {
+ int frame8= (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
+ unsigned long flags;
+ int nframe;
+ unsigned long bmask, bmask32 , bindex;
+ int findex_this= thisFrameNumber & PARS_FRAMES_MASK;
+ int findex_prev= (findex_this-1) & PARS_FRAMES_MASK;
+ int findex_future=(findex_this-2) & PARS_FRAMES_MASK;
+ int index= mindex & 0xffff;
+ MDF8(printk (": thisFrameNumber=0x%lx frame8=%d index= %d (0x%lx), val=0x%lx\n", thisFrameNumber, frame8, index, mindex, val));
+ D1I(local_irq_save(flags));
+// if (index > P_MAX_PAR) {
+ if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) {
+ D1I(local_irq_restore(flags));
+ return -ERR_FRAMEPARS_BADINDEX;
+ }
+//TODO: optimize to use mask several parameters together
+ if (index >= FRAMEPAR_GLOBALS) { /// ignore frame logic, set "static" parameters to frame 0
+ if (mindex & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
+ val= FRAMEPAIR_FRAME_MASK_NEW(mindex, GLOBALPARS(index), val);
+ }
+ GLOBALPARS(index)=val;
+ } else if (mindex & FRAMEPAIR_FRAME_FUNC) { /// write to func_proc[] instead
+ funcs2call[index] = val;
+// } else {
+
+ } else if ((frame8 != findex_future) || ((mindex & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick
+ if (mindex & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
+ val= FRAMEPAIR_FRAME_MASK_NEW(mindex, framepars[frame8].pars[index], val);
+ }
+ if ((framepars[frame8].pars[index]!= val) || (mindex & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))){
+ bmask= 1 << (index & 31);
+ bindex = index >> 5;
+ bmask32= 1 << bindex;
+/// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
+ framepars[frame8].pars[index] = val;
+ framepars[frame8].mod[bindex] |= bmask;
+ framepars[frame8].mod32 |= bmask32;
+ if (mindex & FRAMEPAIR_FORCE_PROC){
+ framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters
+ }
+ MDF8(printk(" bindex=0x%lx, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",bindex, bmask, bmask32, framepars[frame8].functions));
+/// Write parameter to the next frames up to the one that have the same parameter already modified
+ if ((mindex & FRAMEPAIR_JUST_THIS)==0) {
+ MDF8(printk (": --- setting next frames"));
+// for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[frame8].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
+ for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
+ framepars[nframe].pars[index] = val;
+ D8(printk (" %d",nframe));
+ }
+ frame8=(frame8-1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
+ }
+// MDF1(printk("\n"));
+/// Mark this parameter in all previous frames as "modified since"
+/// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
+ MDF8(printk (": >>> setting modsince"));
+// for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
+ for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here
+ framepars[nframe].modsince[bindex] |= bmask;
+ framepars[nframe].modsince32 |= bmask32;
+ D8(printk (" %d",nframe));
+ }
+ D8(printk ("\n"));
+ }
+ } else { /// error - trying to write "just this" to the "future" - that would stick if allowed
+ D1I(local_irq_restore(flags));
+ ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex));
+ return -ERR_FRAMEPARS_TOOEARLY;
+ }
+ D1I(local_irq_restore(flags));
+ return 0;
+}
+/**
+ * @brief set multiple output (calculated) parameters for the frame referenced by this_framepars structure.
+ * Shedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in the particular parameter index
+ * @param this_framepars pointer to the current parameters structure
+ * @param numPars number of parameters to set
+ * @param pars array of parameters (number/value pairs). Parameter numbers accept modifiers
+ * @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
+ */
+int setFramePars(struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars) {
+ int frame8;
+ unsigned long flags;
+ int npar,nframe;
+ unsigned long val, bmask, bmask32;
+ int index,bindex;
+ int findex_this= thisFrameNumber & PARS_FRAMES_MASK;
+ int findex_prev= (findex_this-1) & PARS_FRAMES_MASK;
+ int findex_future=(findex_this-2) & PARS_FRAMES_MASK;
+ MDF8(printk (": this_framepars=0x%x numPars=%d\n",(int) this_framepars, numPars));
+ D1I(local_irq_save(flags));
+ for (npar=0; npar < numPars; npar++) {
+ frame8= (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
+ val=pars[npar].val;
+ index= pars[npar].num & 0xffff;
+ MDF8(printk (": --- frame8=%d index=%d (0x%x) val=0x%x\n", frame8, index, (int) pars[npar].num, (int) val));
+ if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) {
+ D1I(local_irq_restore(flags));
+ ELP_KERR(printk(" bad index=%d > %d\n", index, P_MAX_PAR));
+ return -ERR_FRAMEPARS_BADINDEX;
+ }
+ if (index >= FRAMEPAR_GLOBALS) { /// ignore frame logic, set "static" parameters to frame 0
+ if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
+ val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(index), val);
+ }
+ GLOBALPARS(index)=val;
+ } else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) {
+ funcs2call[index] = val;
+// } else {
+ } else if ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick
+ if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one
+ val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val);
+ }
+//TODO: optimize to use mask several parameters together
+ if ((framepars[frame8].pars[index]!= val) || (pars[npar].num & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))){
+ bmask= 1 << (index & 31);
+ bindex = index >> 5;
+ bmask32= 1 << bindex;
+/// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
+ framepars[frame8].pars[index] = val;
+ framepars[frame8].mod[bindex] |= bmask;
+ framepars[frame8].mod32 |= bmask32;
+ if (pars[npar].num & FRAMEPAIR_FORCE_PROC){
+ framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters
+ }
+/// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS)
+ if ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0) {
+ MDF8(printk (": --- setting next frames"));
+ for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
+ D8(printk (" %d",nframe));
+ framepars[nframe].pars[index] = val;
+ }
+ frame8=(frame8-1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
+ D8(printk ("\n"));
+ }
+/// Mark this parameter in all previous frames as "modified since"
+/// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
+// for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
+ for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here
+ framepars[nframe].modsince[bindex] |= bmask;
+ framepars[nframe].modsince32 |= bmask32;
+ }
+ }
+ } else { /// error - trying to write "just this" to the "future" - that would stick if allowed
+ D1I(local_irq_restore(flags));
+ ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num));
+ return -ERR_FRAMEPARS_TOOEARLY;
+ }
+ }
+ D1I(local_irq_restore(flags));
+ return 0;
+}
+
+///TODO: make some parameters readonly (prohibited from modification from the userland)
+/// File operations:
+/// open, release - nop
+/// read - none
+/// write -> setFrameParsAtomic (first 4 bytes - absolute frame number, next 4 bytes - latency, then each 8 bytes - index/value)
+/// can use current file pointer or special indexes (0x****ff01 - set frame number, 0x****ff02 - set latency) that should come before actual parameters
+/// file pointer - absolute frame number
+/// lseek (SEEK_SET, value) - set absolute frame number
+/// lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber),
+/// lseek (SEEK_CUR, 0) - (used by ftell()) also modifies file pointer - set it to thisFrameNumber,
+/// lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
+/// lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to)
+/// mmap (should be used read only)
+
+static struct file_operations framepars_fops = {
+ owner: THIS_MODULE,
+ llseek: framepars_lseek,
+ write: framepars_write,
+ open: framepars_open,
+ mmap: framepars_mmap,
+ release: framepars_release
+};
+
+/**
+ * @brief Driver OPEN method
+ * @param inode inode
+ * @param filp file pointer
+ * @return OK - 0, -EINVAL for wrong minor
+ */
+int framepars_open(struct inode *inode, struct file *filp) {
+ int res;
+ struct framepars_pd * privData;
+ privData= (struct framepars_pd *) kmalloc(sizeof(struct framepars_pd),GFP_KERNEL);
+ if (!privData) return -ENOMEM;
+ filp->private_data = privData;
+ privData-> minor=MINOR(inode->i_rdev);
+ MDF1(printk(": minor=0x%x\n",privData-> minor));
+ switch (privData-> minor) {
+ case CMOSCAM_MINOR_FRAMEPARS :
+ inode->i_size = 0; //or return 8 - number of frame pages?
+ return 0;
+ default:
+ kfree(filp->private_data); // already allocated
+ return -EINVAL;
+ }
+ return res;
+}
+
+/**
+ * @brief Driver RELEASE method
+ * @param inode inode
+ * @param filp file pointer
+ * @return OK - 0, -EINVAL for wrong minor
+ */
+int framepars_release(struct inode *inode, struct file *filp) {
+ int res=0;
+ int p = MINOR(inode->i_rdev);
+ MDF1(printk(": minor=0x%x\n",p));
+ switch ( p ) {
+ case CMOSCAM_MINOR_FRAMEPARS :
+ break;
+ default:
+ return -EINVAL; //! do not need to free anything - "wrong number"
+ }
+ kfree(filp->private_data);
+ return res;
+}
+
+/**
+ * @brief Driver LSEEK method (and execute commands)
+ * - lseek (SEEK_SET, value) - set absolute frame number
+ * - lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber),
+ * - lseek (SEEK_CUR, 0) - (used by ftell()) DOES NOT modify file pointer, returns thisFrameNumber,
+ * - lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
+ * - lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to)
+ * - no commands yet
+ * @param file
+ * @param offset
+ * @param orig SEEK_SET, SEEK_CUR or SEEK_SET END
+ * @return file position (absolute frame number)
+ */
+loff_t framepars_lseek (struct file * file, loff_t offset, int orig) {
+ unsigned long target_frame;
+ MDF1(printk(" offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
+ switch(orig) {
+ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+ case SEEK_CUR:
+ if (offset==0) return getThisFrameNumber(); /// do not modify frame number
+ file->f_pos = getThisFrameNumber() + offset; /// modifies frame number, but it is better to use absolute SEEK SET
+ break;
+ case SEEK_END:
+ if (offset <= 0) {
+ break;
+ } else if (offset >= LSEEK_FRAME_WAIT_REL) {
+ if (offset >=LSEEK_FRAME_WAIT_ABS) target_frame=offset-LSEEK_FRAME_WAIT_ABS; /// Wait for absolute frame number
+ else target_frame=getThisFrameNumber()+offset-LSEEK_FRAME_WAIT_REL; /// Skip 0..255 frames
+ wait_event_interruptible (framepars_wait_queue,getThisFrameNumber()>=target_frame);
+// if (getThisFrameNumber()=target_frame);
+ return getThisFrameNumber(); /// Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber()
+ } else { //! Other lseek commands
+ switch (offset & ~0x1f) {
+ case LSEEK_DAEMON_FRAME: /// wait the daemon enabled and a new frame interrupt (sensor frame sync)
+ wait_event_interruptible (framepars_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
+ break;
+ default:
+ switch (offset) {
+ case LSEEK_GET_FPGA_TIME:
+ //X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS), GLOBALPARS(G_MICROSECONDS) );
+ MDF2(printk("X313_GET_FPGA_TIME\n"));
+ break;
+ case LSEEK_SET_FPGA_TIME: /// better to use write, not lseek to set FPGA time
+ //X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
+ MDF2(printk("X313_SET_FPGA_TIME\n"));
+ break;
+ case LSEEK_FRAMEPARS_INIT: /// reset hardware sequencers, init framepars structure
+ MDF2(printk("LSEEK_FRAMEPARS_INIT\n"));
+ initGlobalPars();/// reset all global parameters but the first 32
+ initSequencers();
+ break;
+ case LSEEK_FRAME_RESET: /// reset absoulte frame number to avoid integer frame number overflow
+ MDF2(printk("LSEEK_FRAME_RESET\n"));
+ resetFrameNumber();
+ break;
+ case LSEEK_SENSORPROC: /// process modified parameters in frame 0 (to start sensor detection)
+ MDF2(printk("LSEEK_SENSORPROC: framepars[0].functions=0x%08lx\n",framepars[0].functions));
+ processPars (sensorproc, 0, 8); ///frame0, all 8 frames (maxAhead==8)
+ break;
+ case LSEEK_DMA_INIT: /// initialize ETRAX DMA (normally done in sensor_common.c at driver init
+ MDF2(printk("LSEEK_DMA_INIT\n"));
+ //x313_dma_init();
+ break;
+ case LSEEK_DMA_STOP: /// stop DMA
+ MDF2(printk("LSEEK_DMA_STOP\n"));
+ //x313_dma_stop(); ///
+ break;
+ case LSEEK_DMA_START: /// start DMA
+ MDF2(printk("LSEEK_DMA_START\n"));
+ //x313_dma_start(); ///
+ break;
+ case LSEEK_COMPRESSOR_RESET: /// reset compressor and buffer pointers
+ MDF2(printk("LSEEK_COMPRESSOR_RESET\n"));
+ reset_compressor();
+ break;
+ case LSEEK_INTERRUPT_OFF: /// disable camera interrupts
+ MDF2(printk ("LSEEK_INTERRUPT_OFF\n"));
+ camera_interrupts (0);
+ break;
+ case LSEEK_INTERRUPT_ON: /// enable camera interrupts
+ MDF2(printk ("LSEEK_INTERRUPT_ON\n"));
+ camera_interrupts (1);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return file->f_pos ;
+}
+
+/**
+ * @brief Driver WRITE method
+ * writes all at once, no provisions to continue in the next call
+ * @param file
+ * @param buf
+ * @param count
+ * @param off
+ * @return OK - number of bytes written, negative - errors
+ */
+ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff_t *off) {
+ struct frameparspair_t pars_static[256];/// will be sufficient for most calls
+ struct frameparspair_t * pars = pars_static;
+ struct framepars_pd * privData = (struct framepars_pd *) file->private_data;
+ unsigned long frame=*off; /// ************* NOTE: Never use file->f_pos in write() and read() !!!
+ int latency=-1;
+ int first=0;
+ int last;
+ int result;
+ MDF1(printk(": file->f_pos=0x%x, *off=0x%x, count=0x%x\n", (int) file->f_pos, (int) *off, (int) count));
+ count &= ~7; /// sizeof (struct frameparspair_t)==8
+ switch (privData->minor) {
+ case CMOSCAM_MINOR_FRAMEPARS :
+ if (count>sizeof(pars_static)) /// only allocate if static is not enough
+ pars = (struct frameparspair_t *) kmalloc(count, GFP_KERNEL);
+ if (!pars) return -ENOMEM;
+ count >>=3; /// divide by sizeof(struct frameparspair_t); // 8
+ if(count) {
+ if(copy_from_user((char *) pars, buf, count<<3)) {
+ if (count>sizeof(pars_static)) kfree(pars);
+ return -EFAULT;
+ }
+ while (first sizeof(pars_static)) kfree(pars);
+ return -EFAULT;
+ }
+ first=last;
+ }
+ }
+ if (count>sizeof(pars_static)) kfree(pars);
+ return count<<3; /// *sizeof(struct frameparspair_t);
+ default: return -EINVAL;
+ }
+}
+
+/**
+ * @brief Driver MMAP method (should be used read only)
+ * provides access to both 8-frame parameters (including future ones), frame - 0 - some static ones too and
+ * much longer retained pastparameters - subset of all parameters
+ * @param file
+ * @param vma
+ * @return OK - 0, negative - errors
+ */
+int framepars_mmap (struct file *file, struct vm_area_struct *vma) {
+ int result;
+ struct framepars_pd * privData = (struct framepars_pd *) file->private_data;
+ MDF1(printk(": minor=0x%x\n",privData-> minor));
+ switch (privData->minor) {
+ case CMOSCAM_MINOR_FRAMEPARS :
+ result=remap_pfn_range(vma,
+ vma->vm_start,
+ ((unsigned long) virt_to_phys(frameparsall)) >> PAGE_SHIFT, // Should be page-aligned
+ vma->vm_end-vma->vm_start,
+ vma->vm_page_prot);
+ MDF1(printk("remap_pfn_range returned=%x\r\n",result));
+ if (result) return -EAGAIN;
+ return 0;
+ default: return -EINVAL;
+ }
+}
+
+/**
+ * @brief framepars driver init
+ * @return 0
+ */
+static int __init framepars_init(void) {
+ int res;
+ init_framepars_ptr();
+ initGlobalPars(); /// sets default debug if enabled - not anymore. Add here?
+ initMultiPars(); /// just clear - needs to be called again when sensor is recognized
+ frameParsInitialized=0;
+ res = register_chrdev(FRAMEPARS_MAJOR, "framepars_operations", &framepars_fops);
+ if(res < 0) {
+ printk(KERN_ERR "\nframepars_init: couldn't get a major number %d.\n",FRAMEPARS_MAJOR);
+ return res;
+ }
+ init_waitqueue_head(&framepars_wait_queue);
+ printk(X3X3_FRAMEPARS_DRIVER_NAME" - %d \n",FRAMEPARS_MAJOR);
+ return 0;
+}
+
+
+module_init(framepars_init);
+MODULE_LICENSE("GPLv3.0");
+MODULE_AUTHOR("Andrey Filippov .");
+MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);
diff --git a/src/drivers/elphel/framepars.h b/src/drivers/elphel/framepars.h
new file mode 100644
index 0000000000000000000000000000000000000000..e91d7a8b1605da35c56981fb187ba8631563a8c0
--- /dev/null
+++ b/src/drivers/elphel/framepars.h
@@ -0,0 +1,63 @@
+#ifndef _FRAMEPARS_H
+#define _FRAMEPARS_H
+
+//extern struct framepars_t (*framepars)[PARS_FRAMES];
+extern struct framepars_t *framepars;
+extern struct framepars_past_t *pastpars;
+extern unsigned long *globalPars;
+extern unsigned long *multiSensIndex;
+extern unsigned long *multiSensRvrsIndex;
+
+extern wait_queue_head_t framepars_wait_queue;
+///TODO: init framepars (zero parameters) before initscripts (not when detecting the sensors) - then initscript will be able to overwrite some
+void init_framepars_ptr(void);
+void initSequencers(void); ///Move to sensorcommon? currently it is used through frameparsall file (lseek)
+void initGlobalPars(void); /// resets all global parameters but debug mask (if ELPHEL_DEBUG)
+int initMultiPars(void); /// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called aftre/during sensor detection
+void initFramePars(void); ///initialize all parameters, set thisFrameNumber to frame8 (read from hardware, usually 0 after resetting i2c and cmd_seq)
+void resetFrameNumber(void); /// reset this frame number (called from initFramePars(), also can be used to avoid frame number integer overflow)
+
+unsigned long get_imageParamsThis (int n);
+unsigned long get_imageParamsPrev (int n);
+
+void set_imageParamsThis (int n,unsigned long d);
+unsigned long get_globalParam (int n);
+
+void set_globalParam (int n, unsigned long d);
+void set_imageParamsR_all(int n, unsigned long d);
+void updateFramePars(int frame8, struct interframe_params_t * frame_pars); /// called from ISR - advance thisFrameNumber to match hardware frame8, copy parameters as needed.
+ /// frame8 usually is just next after thisFrameNumber
+ /// frame_pars - pointer to structure (between frames in the frame buffer) to save a pointer to past parameters
+int setFrameParsStatic(int numPars, struct frameparspair_t * pars);
+
+unsigned long getThisFrameNumber(void); /// just return current thisFrameNumber
+/// set parameters for the frame number frameno, knowing that they should be set not less than maxLatency ahead (may be sensor - dependent)
+/// Parameters (numPars of them) will be updated all at once, with interrupts disabled
+/// Return - 0 if OK, -ERR_FRAMEPARS_TOOEARLY or -ERR_FRAMEPARS_TOOLATE if it is too early or too late to set parameters (numPars may be 0 to just test)
+///
+/// NOTE: When writing parameter to P_SENSOR_RUN or P_COMPRESSOR_RUN "*_RUN_SINGLE", first write "*SENSOR_RUN_STOP" (it will propagate to all next frames) and then
+/// write "*_RUN_SINGLE", to (P_*_RUN | FRAMEPAIR_JUST_THIS) - then this *_RUN_SINGLE will not propagate to the next frames (they will stay stopped)
+
+
+/// TODO: Make (an "unlimited") future commands que based on lists and a tree frame index
+
+int setFrameParsAtomic(unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars);
+
+/// set output/calculated parameter and propogate changes - will not trigger any actions
+int setFramePar(struct framepars_t * this_framepars, unsigned long mindex, unsigned long val);
+///same for several pars at once
+int setFramePars(struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars);
+/// schedule pgm_func to be executed for selected frame
+void schedule_pgm_func(int frame8, int func_num);
+/// schedule pgm_func to be executed for the current frame
+void schedule_this_pgm_func(struct framepars_t * this_framepars, int func_num);
+
+/// program acquisition, according to the parameters changed.
+/// maxahead - how many frames ahead of time (start with most urgent, then 1 ahead, ...)
+/// make maxahead - P_* parameter?
+inline void processParsASAP (struct sensorproc_t * sensorproc, int frame8);
+inline void processParsSeq (struct sensorproc_t * sensorproc, int frame8, int maxahead);
+
+void processPars (struct sensorproc_t * sensorproc, int frame8, int maxahead);
+///*** TODO: Add option (flag?) to write "single" (like single compress, single sensor) so it will not make all the next frames "single"
+#endif
diff --git a/src/drivers/elphel/jpeghead.c b/src/drivers/elphel/jpeghead.c
new file mode 100644
index 0000000000000000000000000000000000000000..9d5840319b11e9c4077af72800a89e60cd3a4e4b
--- /dev/null
+++ b/src/drivers/elphel/jpeghead.c
@@ -0,0 +1,758 @@
+/*!***************************************************************************
+*! FILE NAME : jpeghead.c
+*! DESCRIPTION: handleng JPEG file headers
+*!
+*! Copyright (C) 2008 Elphel, Inc
+*! -----------------------------------------------------------------------------**
+*!
+*! This program is free software: you can redistribute it and/or modify
+*! it under the terms of the GNU General Public License as published by
+*! the Free Software Foundation, either version 3 of the License, or
+*! (at your option) any later version.
+*!
+*! This program is distributed in the hope that it will be useful,
+*! but WITHOUT ANY WARRANTY; without even the implied warranty of
+*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*! GNU General Public License for more details.
+*!
+*! You should have received a copy of the GNU General Public License
+*! along with this program. If not, see .
+*! -----------------------------------------------------------------------------**
+*! $Log: jpeghead.c,v $
+*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
+*!
+*!
+*! Revision 1.10 2008/11/03 18:43:18 elphel
+*! 8.0.alpha12 with working apps/astreamer
+*!
+*! Revision 1.9 2008/10/29 04:18:28 elphel
+*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
+*!
+*! Revision 1.8 2008/10/12 16:46:22 elphel
+*! snapshot
+*!
+*! Revision 1.7 2008/10/06 08:31:08 elphel
+*! snapshot, first images
+*!
+*! Revision 1.6 2008/09/22 22:55:48 elphel
+*! snapshot
+*!
+*! Revision 1.5 2008/09/19 04:37:25 elphel
+*! snapshot
+*!
+*! Revision 1.4 2008/09/12 20:40:12 elphel
+*! snapshot
+*!
+*! Revision 1.3 2008/09/12 00:23:59 elphel
+*! removed cc353.c, cc353.h
+*!
+*! Revision 1.2 2008/09/11 01:05:32 elphel
+*! snapshot
+*!
+*! Revision 1.1 2008/09/07 19:48:09 elphel
+*! snapshot
+*!
+*/
+
+/****************** INCLUDE FILES SECTION ***********************************/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+//#include
+#include
+
+//#include
+//#include
+//#include obsolete
+#include
+
+/*#include
+#include
+#include
+#include
+#include
+*/
+
+#include
+#include
+
+
+#include
+#include
+#include
+//#include "fpga_io.h"//fpga_table_write_nice
+#include "jpeghead.h"
+//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
+#include "framepars.h" // extern pastpars
+#include "quantization_tables.h" // get_gtables()
+//#include "x3x3.h"
+//#include "cc3x3.h"
+//#include "cxdma.h"
+#include "circbuf.h"
+#include "sensor_common.h"
+#include "exif.h"
+
+#if ELPHEL_DEBUG
+ #define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;}
+ #define D17(x) { if (GLOBALPARS(G_DEBUG) & (1 <<17)) {x; } ; }
+ #define MDF17(x) { if (GLOBALPARS(G_DEBUG) & (1 <<17)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
+ #define D18(x) { if (GLOBALPARS(G_DEBUG) & (1 <<18)) {x; } ; }
+ #define MDF18(x) { if (GLOBALPARS(G_DEBUG) & (1 <<18)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__ );x ;} }
+ #define ELPHEL_DEBUG_THIS 1
+#else
+ #define MDF(x)
+ #define D17(x)
+ #define MDF17(x)
+ #define D18(x)
+ #define MDF18(x)
+ #define ELPHEL_DEBUG_THIS 0
+#endif
+
+#define JPEG_HEADER_MAX_SIZE 0x300
+static int huffman_fpga_programmed=0;
+/// All huffman tabels data to be read/written from the application
+static struct huff_tables_t {
+ struct huffman_encoded_t header_huffman_tables[4];
+ unsigned long fpga_huffman_table[512];
+ union {
+ unsigned char dht_all[20];
+ struct {
+ unsigned char dht_dc0[5]; /// DHT DC0 header (all constants but the length)
+ unsigned char dht_ac0[5]; /// DHT AC0 header (all constants but the length)
+ unsigned char dht_dc1[5]; /// DHT DC1 header (all constants but the length)
+ unsigned char dht_ac1[5]; /// DHT AC1 header (all constants but the length)
+ };
+ };
+} huff_tables;
+
+#define HEADER_COPY_SOF(x) {buf[bpl]=sizeof( x )+8 ; \
+ buf[bp++]=sizeof( x)/3; \
+ memcpy((void *) &buf[bp], (void *) ( x ), sizeof ( x )); \
+ bp+=sizeof ( x );}
+#define HEADER_COPY_SOS(x) {buf[bp++]=sizeof( x )+6 ; \
+ buf[bp++]=sizeof( x)/2; \
+ memcpy((void *) &buf[bp], (void *) ( x ), sizeof ( x )); \
+ bp+=sizeof ( x );}
+/**
+ * @brief just copy two quantization tables for the current frame (for the RTP streamer)
+ * @param params pointer to an array of parameters stored for the frame
+ * @param buf buffer to put the header to
+ * @return header length if successful, <0 - error
+ */
+int qtables_create(struct interframe_params_t * params, unsigned char * buf) {
+ MDF18(printk("params->quality2=0x%x",params->quality2));
+#ifdef TEST_DISABLE_CODE
+ int rslt=get_qtable(params->quality2, &buf[0], &buf[64]); /// will copy both quantization tables
+ if (rslt <0) return rslt; /// bad quality table
+#endif
+ return 128;
+}
+/**
+ * @brief create JPEG header for the frame acquired earlier
+ * @param params pointer to an array of parameters stored for the frame
+ * @param buf buffer to put the header to
+ * @return header length if successful, <0 - error
+ */
+int jpegheader_create(struct interframe_params_t * params, unsigned char * buf) {
+ int bp=0; ///buffer pointer
+ int bpl; /// pointer to length word in the buffer
+ int rslt;
+ int len;
+ int header_sos; /// start of SOS (varaible)
+ const int header_yqtable= 0x19;
+ const int header_cqtable_hd= 0x59;
+ const int header_cqtable= 0x5e;
+ const int header_sof= 0x9e;
+/// first constant part of the header - 0x19 bytes
+ const unsigned char jfif1[0x19]={0xff, 0xd8, /// SOI start of image
+ 0xff, 0xe0, /// APP0
+ 0x00, 0x10, /// (16 bytes long)
+ 0x4a, 0x46, 0x49, 0x46, 0x00, /// JFIF null terminated
+ 0x01, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00,
+ 0xff, 0xdb, /// DQT (define quantization table)
+ 0x00, 0x43, /// 0x43 bytes long
+ 0x00 }; /// table number + (bytes-1)<<4 (0ne byte - 0, 2 bytes - 0x10)
+/// second constant part of the header (starting from byte 0x59 - 0x5 bytes)
+
+ const unsigned char jfif2[0x5]= {0xff, 0xdb, /// DQT (define quantization table)
+ 0x00, 0x43, /// 0x43 bytes long
+ 0x01 }; /// table number + (bytes-1)<<4 (0ne byte - 0, 2 bytes - 0x10)
+
+ const unsigned char sof_color6[]= {0x01, 0x22, 0x00, /// id , freqx/freqy, q
+ 0x02, 0x11, 0x01,
+ 0x03, 0x11, 0x01};
+ const unsigned char sos_color6[]= {0x01, 0x00, /// id, hufftable_dc/htable_ac
+ 0x02, 0x11,
+ 0x03, 0x11};
+
+ const unsigned char sof_jp46dc[]= {0x01, 0x11, 0x00, /// id , freqx/freqy, q
+ 0x02, 0x11, 0x00,
+ 0x03, 0x11, 0x00,
+ 0x04, 0x11, 0x00,
+ 0x05, 0x11, 0x01,
+ 0x06, 0x11, 0x01};
+ const unsigned char sos_jp46dc[]= {0x01, 0x00, /// id, hufftable_dc/htable_ac
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x00,
+ 0x05, 0x11,
+ 0x06, 0x11};
+
+ const unsigned char sof_mono4[]= {0x01, 0x22, 0x00}; /// id , freqx/freqy, q
+ const unsigned char sos_mono4[]= {0x01, 0x00}; /// id, hufftable_dc/htable_ac
+
+ const unsigned char sof_jp4[]= {0x04, 0x22, 0x00}; /// id , freqx/freqy, q
+ const unsigned char sos_jp4[]= {0x04, 0x00}; /// id, hufftable_dc/htable_ac
+
+ const unsigned char sof_jp4dc[]= {0x04, 0x11, 0x00, /// id , freqx/freqy, q
+ 0x05, 0x11, 0x00,
+ 0x06, 0x11, 0x00,
+ 0x07, 0x11, 0x00};
+ const unsigned char sos_jp4dc[]= {0x04, 0x00, /// id, hufftable_dc/htable_ac
+ 0x05, 0x00,
+ 0x06, 0x00,
+ 0x07, 0x00};
+
+ const unsigned char sof_jp4diff[]={0x04, 0x11, 0x11, /// will be adjusted to bayer shift, same for jp4hdr
+ 0x05, 0x11, 0x11,
+ 0x06, 0x11, 0x11,
+ 0x07, 0x11, 0x11};
+ const unsigned char sos_jp4diff[]={0x04, 0x11, /// id, hufftable_dc/htable_ac
+ 0x05, 0x11,
+ 0x06, 0x11,
+ 0x07, 0x11};
+ if (buf==NULL) return -1; /// buffer is not provided
+ MDF17(printk("\n"));
+ MDF18(unsigned char * p= (char *) params; for (len=0;len<32;len++) {if ((len & 0x0f)==0) printk("\n%03x: ",len); printk(" %02x", (int) p[len]);} printk("\n"););
+
+ memcpy((void *) &buf[0], (void *) jfif1, sizeof (jfif1)); /// including DQT0 header
+ memcpy((void *) &buf[header_cqtable_hd], (void *) jfif2, sizeof (jfif2)); /// DQT1 header
+#ifdef TEST_DISABLE_CODE
+ rslt=get_qtable(params->quality2, &buf[header_yqtable], &buf[header_cqtable]); /// will copy both quantization tables
+ if (rslt <0) return rslt; /// bad quality table
+#endif
+ bp=header_sof;
+ buf[bp++]=0xff; buf[bp++]=0xc0;
+ buf[bp++]=0; /// high byte length - always 0
+ bpl=bp; /// save pointer to length (low byte)
+ bp++;
+ buf[bp++]=0x8; /// 8bpp
+ buf[bp++]=params->height >> 8; buf[bp++]=params->height; /// big endian height
+ buf[bp++]=params->width >> 8; buf[bp++]=params->width; /// big endian width
+/// copy SOF0 (constants combined with bayer shift for jp4diff/jp4hdr)
+ switch (params->color) {
+ case COLORMODE_MONO6: /// monochrome, (4:2:0),
+ case COLORMODE_COLOR: /// color, 4:2:0, 18x18(old)
+ case COLORMODE_COLOR20: /// color, 4:2:0, 20x20, middle of the tile (not yet implemented)
+ case COLORMODE_JP46: /// jp4, original (4:2:0)
+ HEADER_COPY_SOF(sof_color6);
+ break;
+ case COLORMODE_MONO4: /// monochrome, 4 blocks (but still with 2x2 macroblocks)
+ HEADER_COPY_SOF(sof_mono4);
+ break;
+ case COLORMODE_JP4: /// jp4, 4 blocks
+ HEADER_COPY_SOF(sof_jp4);
+ break;
+ case COLORMODE_JP46DC: /// jp4, dc -improved (4:2:0)
+ HEADER_COPY_SOF(sof_jp46dc);
+ break;
+ case COLORMODE_JP4DC: /// jp4, 4 blocks, dc -improved
+ HEADER_COPY_SOF(sof_jp4dc);
+ break;
+ case COLORMODE_JP4DIFF: /// jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
+ case COLORMODE_JP4DIFF2: /// jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
+ HEADER_COPY_SOF(sof_jp4diff);
+//header_sof
+//bshift
+ buf[header_sof+12+3*((4-params->byrshift) & 3)]=0; /// set quantization table 0 for the "base color"
+ break;
+ case COLORMODE_JP4HDR: /// jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
+ case COLORMODE_JP4HDR2: /// jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2)
+ HEADER_COPY_SOF(sof_jp4diff); /// same as for COLORMODE_JP4DIFF
+ buf[header_sof+12+3*((4-params->byrshift) & 3)]=0; /// set quantization table 0 for the "base color"
+ buf[header_sof+12+3*((6-params->byrshift) & 3)]=0; /// set quantization table 0 for the HDR color
+ break;
+ }
+/// Include 4 huffman tables
+ memcpy((void *) &buf[bp], (void *) huff_tables.dht_dc0, 5); /// DHT DC0 header
+ bp+=5;
+ len= (huff_tables.dht_dc0[2]<<8)+huff_tables.dht_dc0[3]-3; /// table length itself, excluding 2 length bytes and type byte
+ memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[0], len);
+ bp+=len;
+
+ memcpy((void *) &buf[bp], (void *) huff_tables.dht_ac0, 5); /// DHT AC0 header
+ bp+=5;
+ len= (huff_tables.dht_ac0[2]<<8)+huff_tables.dht_ac0[3]-3; /// table length itself, excluding 2 length bytes and type byte
+ memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[1], len);
+ bp+=len;
+
+ memcpy((void *) &buf[bp], (void *) huff_tables.dht_dc1, 5); /// DHT DC1 header
+ bp+=5;
+ len= (huff_tables.dht_dc1[2]<<8)+huff_tables.dht_dc1[3]-3; /// table length itself, excluding 2 length bytes and type byte
+ memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[2], len);
+ bp+=len;
+
+ memcpy((void *) &buf[bp], (void *) huff_tables.dht_ac1, 5); /// DHT AC1 header
+ bp+=5;
+ len= (huff_tables.dht_ac1[2]<<8)+huff_tables.dht_ac1[3]-3; /// table length itself, excluding 2 length bytes and type byte
+ memcpy((void *) &buf[bp], (void *) &huff_tables.header_huffman_tables[3], len);
+ bp+=len;
+
+/// copy SOS0 (constants combined with bayer shift for jp4diff/jp4hdr)
+ header_sos=bp;
+ buf[bp++]=0xff; buf[bp++]=0xda; /// SOS tag
+ buf[bp++]=0; /// high byte length - always 0
+ switch (params->color) {
+ case COLORMODE_MONO6: /// monochrome, (4:2:0),
+ case COLORMODE_COLOR: /// color, 4:2:0, 18x18(old)
+ case COLORMODE_COLOR20: /// color, 4:2:0, 20x20, middle of the tile (not yet implemented)
+ case COLORMODE_JP46: /// jp4, original (4:2:0)
+ HEADER_COPY_SOS(sos_color6);
+ break;
+ case COLORMODE_MONO4: /// monochrome, 4 blocks (but still with 2x2 macroblocks)
+ HEADER_COPY_SOS(sos_mono4);
+ break;
+ case COLORMODE_JP4: /// jp4, 4 blocks
+ HEADER_COPY_SOS(sos_jp4);
+ break;
+ case COLORMODE_JP46DC: /// jp4, dc -improved (4:2:0)
+ HEADER_COPY_SOS(sos_jp46dc);
+ break;
+ case COLORMODE_JP4DC: /// jp4, 4 blocks, dc -improved
+ HEADER_COPY_SOS(sos_jp4dc);
+ break;
+ case COLORMODE_JP4DIFF: /// jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
+ case COLORMODE_JP4DIFF2: /// jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
+ HEADER_COPY_SOS(sos_jp4diff);
+ buf[header_sos+6+2*((4-params->byrshift) & 3)]=0; /// set huffman table 0 for the "base color"
+ break;
+ case COLORMODE_JP4HDR: /// jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
+ case COLORMODE_JP4HDR2: /// jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2)
+ HEADER_COPY_SOS(sos_jp4diff); /// same as for COLORMODE_JP4DIFF
+ buf[header_sos+6+2*((4-params->byrshift) & 3)]=0; /// set huffman table 0 for the "base color"
+ buf[header_sos+6+2*((6-params->byrshift) & 3)]=0; /// set huffman table 0 for the HDR color
+ break;
+ }
+ buf[bp++]=0x00; /// Spectral selection start
+ buf[bp++]=0x3f; /// Spectral selection end
+ buf[bp++]=0x00; /// Successive approximation (2 values 0..13)
+ MDF17(printk("JPEG header length=%d\n",bp));
+ MDF18(for (len=0;lenprivate_data = privData;
+ privData-> minor=MINOR(inode->i_rdev);
+ privData-> size=0; ///undefined yet
+ inode->i_size=JPEG_HEADER_MAXSIZE; /// not the actual size
+ return 0;
+}
+
+/*!=================================================================
+ *! Overloading lseek with additional functionality (to avoid ioctls)
+ *! with orig==SEEK_END lseek will treat (offset>0) as a byte pointer
+ *! in (char *)ccam_dma_buf_ptr of a frame pointer and use quality,
+ *! width and height to regenerate header.
+ *! frame pointers are 32-bytes aligned, so adding 1 to offest
+ *! will make sure it is always >0 (as offset=0, orig=SEEK_END
+ *! will just move pointer to the end and return file length.
+ *!
+ *! When called with orig==SEEK_END, offset>0 lseek will position
+ *! file at the very beginning and return 0 if OK, -EINVAL if
+ *! frame header is not found for the specified offset
+ *!================================================================*/
+
+
+loff_t jpeghead_lseek(struct file * file, loff_t offset, int orig){
+
+ int rp;
+ struct jpeghead_pd * privData;
+ struct interframe_params_t * fp;
+ privData = (struct jpeghead_pd *) file->private_data;
+ MDF17(printk("orig=%d, offst=0x%x\n",orig,(int) offset));
+
+ switch (orig)
+ {
+ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+ case SEEK_CUR:
+ file->f_pos += offset;
+ break;
+ case SEEK_END:
+ if (offset <= 0) {
+ file->f_pos = privData->size + offset;
+ } else { //! New functionality
+ file->f_pos=0; // anyway reset it to 0
+ rp= (offset >>2) & (~7); // convert to index to long, align to 32-bytes
+ fp = (struct interframe_params_t *) &ccam_dma_buf_ptr[X313_BUFFSUB(rp, 8)]; //! 32 bytes before the frame pointer, may roll-over to the end of ccam_dma_buf_ptr
+ if ((fp->signffff != 0xffff) || //! signature is overwritten
+ ((fp->timestamp_sec) & X313_LENGTH_MASK)) return -EINVAL; //! acquisition of this frame is not done yet - length word high byte is non-zero
+
+
+
+///FIXME: pp_index=fp->past_index; /// unsigned short
+/// if (pp_index>=PASTPARS_SAVE_ENTRIES) return -EINVAL; /// wrong index
+/// privData->size= jpegheader_create( pastpars[pp_index].past_pars, privData->header);
+ if ((offset & 0x1f)==0x2) privData->size= qtables_create(fp, privData->header); /// just qunatization tables (128 bytes) - for the streamer
+ else privData->size= jpegheader_create(fp, privData->header); /// full JPEG header
+ if (privData->size <0 ) {
+ privData->size=0;
+ return -EINVAL; /// error in header
+ }
+ return ( file->f_pos ); //! it is 0
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ /// truncate position
+ if (file->f_pos < 0) {
+ file->f_pos = 0;
+ return(-EOVERFLOW);
+ }
+
+ if (file->f_pos > privData->size) {
+ file->f_pos = privData->size;
+ }
+ return ( file->f_pos );
+}
+
+ssize_t jpeghead_read(struct file * file, char * buf, size_t count, loff_t *off) {
+ unsigned long p;
+ struct jpeghead_pd * privData;
+ privData = (struct jpeghead_pd *) file->private_data;
+ MDF17(printk("\n"));
+ p = *off;
+ if(p >= privData->size)
+ p = privData->size;
+ if((p + count) > privData->size) { /// truncate count
+ count = privData->size - p;
+ }
+ if(count) {
+ if(copy_to_user(buf, &privData->header[p], count)) return -EFAULT;
+ *off += count;
+ }
+ return count;
+}
+
+
+/**huffman_* file operations
+ * write, read Huffman tables, initialize tables to default ones, program FPGA with the Huffman tables
+ * file structure is the same as the struct huff_tables_t:
+ * - 4 tables of 16+256 elements (16 frequencies followed by symbols)
+ * - 2048 bytes (512 unsigned long) FPGA-encoded data - it is recalculated from the tables above
+ * - 4 bytes - number of symbols in each table (calculated)
+ */
+
+int huffman_open(struct inode *inode, struct file *filp) { // set filesize
+ struct huffman_pd * privData;
+ privData= (struct huffman_pd *) kmalloc(sizeof(struct huffman_pd),GFP_KERNEL);
+ if (!privData) return -ENOMEM;
+ filp->private_data = privData;
+ privData-> minor=MINOR(inode->i_rdev);
+ inode->i_size = sizeof(huff_tables);
+
+ return 0;
+}
+
+/*!=================================================================
+ *! Overloading lseek with additional functionality
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_DC0 - position at Huffman DC0
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_AC0 - position at Huffman DC0
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_DC1 - position at Huffman DC0
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_AC1 - position at Huffman DC0
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_FPGATAB - position at FPGA table
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_DEFAULT - fill in default tables
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_FPGACALC - calculate FPGA table
+ *! with orig==SEEK_END , offset==LSEEK_HUFFMAN_FPGAPGM - program FPGA table
+ *! those commands do not move the file pointer (return current),
+ *! or negative in the case of error (calculate FPGA table)
+ *!================================================================*/
+
+loff_t huffman_lseek(struct file * file, loff_t offset, int orig){
+ // orig 0: position from begning
+ // orig 1: relative from current position
+ // orig 2: position from last address
+
+ switch (orig)
+ {
+ case SEEK_SET:
+ file->f_pos = offset;
+ break;
+ case SEEK_CUR:
+ file->f_pos += offset;
+ break;
+ case SEEK_END:
+ if (offset <= 0) {
+ file->f_pos = sizeof(huff_tables) + offset;
+ } else { //! New functionality
+ switch (offset) {
+ case LSEEK_HUFFMAN_DC0: file->f_pos=0; break;
+ case LSEEK_HUFFMAN_AC0: file->f_pos=1*sizeof(struct huffman_encoded_t);break;
+ case LSEEK_HUFFMAN_DC1: file->f_pos=2*sizeof(struct huffman_encoded_t);break;
+ case LSEEK_HUFFMAN_AC1: file->f_pos=3*sizeof(struct huffman_encoded_t);break;
+ case LSEEK_HUFFMAN_FPGATAB: file->f_pos=4*sizeof(struct huffman_encoded_t);break;
+ case LSEEK_HUFFMAN_DEFAULT: jpeg_htable_init(); break; // no change to file pointer
+ case LSEEK_HUFFMAN_FPGACALC:
+ if (jpeg_htable_fpga_encode () <0) return -EINVAL;
+ break;
+ case LSEEK_HUFFMAN_FPGAPGM: jpeg_htable_fpga_pgm (); break;
+ default: return -EINVAL;
+
+ }
+ return ( file->f_pos );
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ // truncate position
+ if (file->f_pos < 0) {
+ file->f_pos = 0;
+ return(-EOVERFLOW);
+ }
+ if (file->f_pos > sizeof(huff_tables)) file->f_pos = sizeof(huff_tables);
+ return ( file->f_pos );
+}
+
+
+ssize_t huffman_read(struct file * file, char * buf, size_t count, loff_t *off) {
+ unsigned long p;
+ unsigned char * uc_huff_tables= (unsigned char *) &huff_tables;
+ MDF17(printk("\n"));
+ p = *off;
+ if(p >= sizeof(huff_tables)) p = sizeof(huff_tables);
+ if((p + count) > sizeof(huff_tables)) count = sizeof(huff_tables) - p; /// truncate count
+ if(count) {
+ if(copy_to_user(buf, &uc_huff_tables[p], count)) return -EFAULT;
+ *off += count;
+ }
+ return count;
+}
+
+
+ssize_t huffman_write(struct file * file, const char * buf, size_t count, loff_t *off) {
+ unsigned long p;
+ unsigned char * uc_huff_tables= (unsigned char *) &huff_tables;
+ MDF17(printk("\n"));
+ p = *off;
+ if (p >= sizeof(huff_tables)) p = sizeof(huff_tables);
+ if( (p + count) > sizeof(huff_tables)) count = sizeof(huff_tables) - p; /// truncate count
+ if (count) {
+ if (copy_from_user(&uc_huff_tables[p],buf, count)) return -EFAULT;
+ }
+
+ return count;
+}
+
+/**
+ * @brief Initialize Huffman tables with default data
+ */
+void jpeg_htable_init (void) {
+ unsigned char dc0[]={0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///. number of codes of each length 1..16 (12 total)
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /// symbols encoded (12)
+ 0x08, 0x09, 0x0a, 0x0b};
+
+ unsigned char ac0[]={0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, /// - counts of codes of each length - 1..16 - total a2
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, /// symbols encoded (0xa2)
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa};
+
+ unsigned char dc1[]={0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b};
+ unsigned char ac1[]={0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa};
+ MDF17(printk(" started\n"));
+ memset ((void*) &huff_tables,0, sizeof(huff_tables));
+ memcpy ((void*) huff_tables.header_huffman_tables[0].bits,dc0, sizeof(dc0));
+ memcpy ((void*) huff_tables.header_huffman_tables[1].bits,ac0, sizeof(ac0));
+ memcpy ((void*) huff_tables.header_huffman_tables[2].bits,dc1, sizeof(dc1));
+ memcpy ((void*) huff_tables.header_huffman_tables[3].bits,ac1, sizeof(ac1));
+ MDF17(printk("jpeg_htable_fpga_encode ()\n"));
+ jpeg_htable_fpga_encode ();
+}
+
+/**
+ * @brief encode all 4 Huffman tables into FPGA format
+ * additionally calculates number of symbols in each table
+ * @return OK - 0, -1 - too many symbols, -2 bad table, -3 - bad table number
+ */
+
+int jpeg_htable_fpga_encode (void) {
+ int ntab, i, rslt, a, length;
+ const unsigned char dht_headers[20]={ /// length will be inserted later
+ 0xff, 0xc4, 0x00, 0x00, 0x00,
+ 0xff, 0xc4, 0x00, 0x00, 0x10,
+ 0xff, 0xc4, 0x00, 0x00, 0x01,
+ 0xff, 0xc4, 0x00, 0x00, 0x11 };
+ struct huffman_fpga_code_t codes[256];
+ unsigned long * icodes = (unsigned long *) codes;
+ huffman_fpga_programmed=0; /// mark FPGA table as needed to be programmed
+ MDF17(printk(" started\n"));
+/// Fill in the table headers:
+ memcpy ((void*) huff_tables.dht_all, (void*) dht_headers, sizeof(dht_headers)); /// all 4 headers (with zero length)
+ for (ntab=0; ntab<4; ntab++) {
+ MDF17(printk("ntab=%d\n", ntab));
+ memset (codes,0,sizeof(codes));
+ if ((rslt=jpeg_prep_htable (&(huff_tables.header_huffman_tables[ntab]), codes)) < 0 ) return rslt;
+ if (ntab & 1) {
+ a=((ntab & 2)<<7);
+ for (i=0; i<256;i+=16) {
+ memcpy ((void*) &(huff_tables.fpga_huffman_table[a]), (void*) &codes[i], 60); /// all but DC column
+ a+=16;
+ }
+ } else {
+ a=((ntab & 2)<<7)+0x0f; /// in FPGA DC use spare parts of AC table
+ for (i=0; i<16;i++) {
+ huff_tables.fpga_huffman_table[a]= icodes[i];
+ a+=16;
+ }
+ }
+/// Fill in the table headers:
+ length=19; /// 2 length bytes, 1 type byte, 16 lengths bytes
+ for (i=0; i<16; i++) length += huff_tables.header_huffman_tables[ntab].bits[i]; /// first 16 bytes in each table number of symbols
+ huff_tables.dht_all[(5*ntab)+2]=length >> 8; /// high byte (usually 0)
+ huff_tables.dht_all[(5*ntab)+3]=length& 0xff; /// low byte
+ }
+
+ MDF17(printk("\nFPGA Huffman table\n");for (i=0;i<512;i++){printk (" %06x",(int)huff_tables.fpga_huffman_table[i]); if ((i & 0x0f)==0x0f) printk("\n");});
+ return 0;
+}
+
+
+/**
+ * @brief check if the FPGA is programmed to the new Huffman table
+ * @return 1 - programmed, 0 - not programmed
+ */
+int jpeg_htable_is_programmed(void) {
+ return huffman_fpga_programmed;
+}
+
+/**
+ * @brief program FPGA Huffman table (fram static array)
+ */
+void jpeg_htable_fpga_pgm (void) {
+#ifdef TEST_DISABLE_CODE
+ fpga_table_write_nice (CX313_FPGA_TABLES_HUFF, 512, huff_tables.fpga_huffman_table);
+#endif
+ huffman_fpga_programmed=1;
+}
+
+/// Code below is based on jdhuff.c (from libjpeg)
+/**
+ * @brief Calculate huffman table (1 of 4) from the JPEG header to code lengh/value (for FPGA)
+ * @param htable encoded Huffman table - 16 length bytes followed by up to 256 symbols
+ * @param hcodes combined (length<<16) | code table for each symbol
+ * @return OK- 0, -1 - too many symbols, -2 bad table
+ */
+///Does it depend on no missing symbols?
+int jpeg_prep_htable (struct huffman_encoded_t * htable, struct huffman_fpga_code_t * hcodes) {
+ int p, i, l, si, numsymbols;
+ unsigned int code;
+ MDF17(printk(" started\n"));
+ /// Figure C.1: make table of Huffman code length for each symbol
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ i = htable->bits[l-1];
+ if (i < 0 || p + i > 256) {
+ MDF17(printk("protect against table overrun\n"));
+ return -1 ; /// protect against table overrun
+ }
+ while (i--) hcodes[htable->huffval[p++]].length=l;
+ }
+ numsymbols = p;
+ /// Figure C.2: generate the codes themselves
+ /// We also validate that the counts represent a legal Huffman code tree.
+ code = 0;
+ si = hcodes[htable->huffval[0]].length;
+ p = 0;
+///htable->huffval[N] - N-th symbol value
+ while (p < numsymbols) {
+ if ((hcodes[htable->huffval[p]].length < si) || (si>16)) {
+ ELP_KERR(printk("Bad table/bug\n"));
+ return -3; ///Bad table
+ }
+ while (hcodes[htable->huffval[p]].length == si) {
+ hcodes[htable->huffval[p++]].value = code;
+ code++;
+ }
+
+ /** code is now 1 more than the last code used for codelength si; but
+ * it must still fit in si bits, since no code is allowed to be all ones.
+ */
+ if ( code >= (1 << si)) {
+ ELP_KERR(printk("Bad code\n"));
+ return -2; ///Bad code
+ }
+ code <<= 1;
+ si++;
+ }
+ return 0;
+}
+
diff --git a/src/drivers/elphel/jpeghead.h b/src/drivers/elphel/jpeghead.h
new file mode 100644
index 0000000000000000000000000000000000000000..092eba7548191d5c083c63a2ec7019803215fe22
--- /dev/null
+++ b/src/drivers/elphel/jpeghead.h
@@ -0,0 +1,38 @@
+// FILE NAME : jpeghead.h
+///Structure used for FPGA data - lower 16 bits - code value, next 5 - code length (1..16).
+///Actually FPGA only uses 20 bits, length 0 is interpreted as 16
+struct huffman_fpga_code_t {
+ unsigned short value; /// code value
+ unsigned short length; /// code length
+};
+int qtables_create (struct interframe_params_t * params, unsigned char * buf);
+int jpegheader_create(struct interframe_params_t * params, unsigned char * buf);
+int jpeghead_open (struct inode *inode, struct file *filp); // set filesize
+loff_t jpeghead_lseek (struct file * file, loff_t offset, int orig);
+ssize_t jpeghead_read (struct file * file, char * buf, size_t count, loff_t *off);
+
+int huffman_open (struct inode *inode, struct file *filp); // set filesize
+int huffman_release(struct inode *inode, struct file *filp);
+loff_t huffman_lseek (struct file * file, loff_t offset, int orig);
+ssize_t huffman_read (struct file * file, char * buf, size_t count, loff_t *off);
+ssize_t huffman_write (struct file * file, const char * buf, size_t count, loff_t *off);
+
+
+extern unsigned long * ccam_dma_buf_ptr;
+void init_ccam_dma_buf_ptr(void);
+#define JPEG_HEADER_MAXSIZE 0x300
+struct jpeghead_pd {
+ int minor;/// should be the first, same as in circbuf_pd
+ unsigned long size; /// JPEG header size (no Exif)
+ unsigned char header[JPEG_HEADER_MAXSIZE];
+};
+
+struct huffman_pd {
+ int minor;/// should be the first, same as in circbuf_pd
+};
+
+int jpeg_htable_is_programmed(void);
+void jpeg_htable_init (void);
+int jpeg_htable_fpga_encode (void);
+void jpeg_htable_fpga_pgm (void);
+int jpeg_prep_htable (struct huffman_encoded_t * htable, struct huffman_fpga_code_t * hcodes);
diff --git a/src/drivers/elphel/param_depend.h b/src/drivers/elphel/param_depend.h
new file mode 100644
index 0000000000000000000000000000000000000000..ebe79f76a2705132e1fa1f7bf897b3c8cf29d812
--- /dev/null
+++ b/src/drivers/elphel/param_depend.h
@@ -0,0 +1,359 @@
+/*!********************************************************************************
+*! FILE NAME : param_depend.h
+*! DESCRIPTION: Specifies, which actions should be performed when some acquisition
+*! parameters are changed
+*! Copyright (C) 2008 Elphel, Inc.
+*! -----------------------------------------------------------------------------**
+*!
+*! This program is free software: you can redistribute it and/or modify
+*! it under the terms of the GNU General Public License as published by
+*! the Free Software Foundation, either version 3 of the License, or
+*! (at your option) any later version.
+*!
+*! This program is distributed in the hope that it will be useful,
+*! but WITHOUT ANY WARRANTY; without even the implied warranty of
+*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*! GNU General Public License for more details.
+*!
+*! You should have received a copy of the GNU General Public License
+*! along with this program. If not, see .
+*! -----------------------------------------------------------------------------**
+*! $Log: param_depend.h,v $
+*! Revision 1.12 2010/08/03 23:37:34 elphel
+*! rev 8.0.8.37, portrait mode support
+*!
+*! Revision 1.11 2010/08/01 19:29:24 elphel
+*! files updated to support coring function for noise filtering
+*!
+*! Revision 1.10 2010/06/02 16:31:04 elphel
+*! Added P_MULTI_SELECTED parameter
+*!
+*! Revision 1.9 2010/06/01 08:30:36 elphel
+*! support for the FPGA code 03534022 with optional master time stamp over the inter-camera sync line(s)
+*!
+*! Revision 1.8 2010/05/25 00:52:23 elphel
+*! 8.0.8.20, working on multi-sensor
+*!
+*! Revision 1.7 2010/05/21 06:12:16 elphel
+*! continue working on multi-sensor software
+*!
+*! Revision 1.6 2010/05/16 02:03:47 elphel
+*! 8.0.8.4 - driver working with individual/broadcast sensor registers
+*!
+*! Revision 1.5 2010/05/13 03:39:31 elphel
+*! 8.0.8.12 - drivers modified for multi-sensor operation
+*!
+*! Revision 1.4 2010/04/28 16:00:09 elphel
+*! Changing PF_HEIGHT now triggers window recalculation
+*!
+*! Revision 1.3 2008/12/03 17:17:23 elphel
+*! added limitfps function to exposure change - otherwise indicated period/fps was not updated when exposure time was reduced (from above minimal frame period)
+*!
+*! Revision 1.2 2008/11/30 05:01:03 elphel
+*! Changing gains/scales behavior
+*!
+*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
+*!
+*!
+*! Revision 1.20 2008/11/27 09:27:31 elphel
+*! Support fro new parameters (vignetting correction related)
+*!
+*! Revision 1.19 2008/11/13 05:40:45 elphel
+*! 8.0.alpha16 - modified histogram storage, profiling
+*!
+*! Revision 1.18 2008/10/29 04:18:28 elphel
+*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
+*!
+*! Revision 1.17 2008/10/18 06:14:21 elphel
+*! 8.0.alpha4 - removed some obsolete parameters, renumbered others, split P_FLIP into P_FLIPH and P_FLIPV (different latencies because of bad frames), pgm_window-> pgm_window, pgm_window_safe
+*!
+*! Revision 1.16 2008/10/10 17:06:59 elphel
+*! just a snapshot
+*!
+*! Revision 1.15 2008/10/08 21:26:25 elphel
+*! snapsot 7.2.0.pre4 - first images (actually - second)
+*!
+*! Revision 1.14 2008/10/06 08:31:08 elphel
+*! snapshot, first images
+*!
+*! Revision 1.13 2008/10/04 16:10:12 elphel
+*! snapshot
+*!
+*! Revision 1.12 2008/09/28 00:31:57 elphel
+*! snapshot
+*!
+*! Revision 1.11 2008/09/25 00:58:12 elphel
+*! snapshot
+*!
+*! Revision 1.10 2008/09/22 22:55:49 elphel
+*! snapshot
+*!
+*! Revision 1.9 2008/09/16 00:49:32 elphel
+*! snapshot
+*!
+*! Revision 1.8 2008/08/11 19:17:01 elphel
+*! reduced syntax complaints by KDevelop
+*!
+*! Revision 1.7 2008/07/29 01:15:06 elphel
+*! another snapshot
+*!
+*! Revision 1.6 2008/07/27 23:25:07 elphel
+*! next snapshot
+*!
+*! Revision 1.5 2008/07/27 04:27:49 elphel
+*! next snapshot
+*!
+*! Revision 1.4 2008/06/24 00:43:44 elphel
+*! just a snapshot
+*!
+*! Revision 1.3 2008/06/20 03:54:20 elphel
+*! another snapshot
+*!
+*! Revision 1.2 2008/06/19 02:17:36 elphel
+*! continuing work - just a snapshot
+*!
+*! Revision 1.1 2008/06/16 06:51:21 elphel
+*! work in progress, intermediate commit
+*!
+*!
+*/
+#ifndef _PARAM_DEPEND_H
+#define _PARAM_DEPEND_H
+
+#define ONCHANGE_MULTISENS (1 << onchange_multisens ) /// changes related to multiplexed sensors
+#define ONCHANGE_RECALCSEQ (1 << onchange_recalcseq ) /// recalculate sequences/latencies, according to P_SKIP, P_TRIG
+#define ONCHANGE_DETECTSENSOR (1 << onchange_detectsensor ) /// detect sensor type, sets sensor structure (capabilities), function pointers
+#define ONCHANGE_SENSORPHASE (1 << onchange_sensorphase ) /// program sensor clock/phase
+#define ONCHANGE_I2C (1 << onchange_i2c ) /// program i2c speed/bytes
+#define ONCHANGE_INITSENSOR (1 << onchange_initsensor ) /// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
+#define ONCHANGE_AFTERINIT (1 << onchange_afterinit ) /// restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
+#define ONCHANGE_WINDOW (1 << onchange_window ) /// program sensor WOI - with 1 bad frame to be skipped by the compressor
+#define ONCHANGE_WINDOW_SAFE (1 << onchange_window_safe ) /// program sensor WOI - zero bad frames to be skipped by the compressor
+#define ONCHANGE_EXPOSURE (1 << onchange_exposure ) /// program exposure
+#define ONCHANGE_GAINS (1 << onchange_gains ) /// program analog gains
+#define ONCHANGE_TRIGGERMODE (1 << onchange_triggermode ) /// program sensor trigger mode
+#define ONCHANGE_SENSORIN (1 << onchange_sensorin ) /// program sensor input in FPGA (Bayer, 8/16 bits, ??)
+#define ONCHANGE_SENSORSTOP (1 << onchange_sensorstop) /// Stop acquisition from the sensor to the FPGA (start has latency of 2)
+#define ONCHANGE_SENSORRUN (1 << onchange_sensorrun) /// Start/single acquisition from the sensor to the FPGA (stop has latency of 1)
+#define ONCHANGE_GAMMA (1 << onchange_gamma ) /// program gamma table
+#define ONCHANGE_HIST (1 << onchange_hist ) /// program histogram window
+#define ONCHANGE_AEXP (1 << onchange_aexp ) /// program autoexposure mode
+#define ONCHANGE_QUALITY (1 << onchange_quality ) /// program quantization table(s)
+#define ONCHANGE_MEMSENSOR (1 << onchange_memsensor ) /// program memory channels 0 (sensor->memory) and 1 (memory->FPN)
+#define ONCHANGE_MEMCOMPRESSOR (1 << onchange_memcompressor ) /// program memory channel 2 (memory->compressor)
+#define ONCHANGE_LIMITFPS (1 << onchange_limitfps ) /// check compressor will keep up, limit sensor FPS if needed
+#define ONCHANGE_COMPMODE (1 << onchange_compmode ) /// program compressor modes
+#define ONCHANGE_FOCUSMODE (1 << onchange_focusmode ) /// program focus modes
+#define ONCHANGE_TRIGSEQ (1 << onchange_trigseq ) /// program sequencer (int/ext)
+#define ONCHANGE_IRQ (1 << onchange_irq ) /// program smart IRQ mode (needs to be on)
+#define ONCHANGE_COMPRESTART (1 << onchange_comprestart ) /// restart after changing geometry (recognizes ASAP and programs memory channel 2 then)
+#define ONCHANGE_COMPSTOP (1 << onchange_compstop ) /// stop compressor when changing geometry
+#define ONCHANGE_COMPCTL (1 << onchange_compctl ) /// only start/stop/single (after explicitly changed, not when geometry was changed)
+#define ONCHANGE_GAMMALOAD (1 << onchange_gammaload ) /// write gamma tables (should be prepared). Maybe - just last byte, to activate?
+#define ONCHANGE_SENSORREGS (1 << onchange_sensorregs ) /// write sensor registers (only changed from outside the driver as they may have different latencies)?
+#define ONCHANGE_PRESCAL (1 << onchange_prescal ) /// change scales for per-color digital gains, apply vignetting correction
+
+const unsigned long param_depend_tab[]=
+ {
+ P_SENSOR_RUN, ONCHANGE_SENSORSTOP | ONCHANGE_SENSORRUN | ONCHANGE_MEMCOMPRESSOR,
+ P_SENSOR, ONCHANGE_DETECTSENSOR | ONCHANGE_RECALCSEQ | ONCHANGE_INITSENSOR | ONCHANGE_AFTERINIT | ONCHANGE_MULTISENS | \
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+ P_BAYER , ONCHANGE_SENSORIN ,
+ P_CLK_FPGA, ONCHANGE_I2C | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+/// not need ONCHANGE_INITSENSOR | ONCHANGE_AFTERINIT - they will be scheduled by pgm_sensorphase if needed for the sensor
+ P_CLK_SENSOR, ONCHANGE_SENSORPHASE | \
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+ P_SENSOR_PHASE, ONCHANGE_SENSORPHASE | ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+ P_FPGA_XTRA, ONCHANGE_LIMITFPS ,
+ P_TRIG, ONCHANGE_RECALCSEQ | ONCHANGE_TRIGGERMODE | ONCHANGE_TRIGSEQ | ONCHANGE_LIMITFPS | /// Next to call with afterinit
+ ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+// P_VIRT_WIDTH, ONCHANGE_LIMITFPS ,
+ P_VIRT_WIDTH, ONCHANGE_LIMITFPS | ONCHANGE_EXPOSURE , ///after limitFPS
+ P_VIRT_HEIGHT, ONCHANGE_LIMITFPS ,
+ P_WOI_LEFT, ONCHANGE_WINDOW_SAFE ,
+// P_WOI_TOP, ONCHANGE_WINDOW_SAFE ,
+ P_WOI_TOP, ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
+ P_WOI_WIDTH, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
+ P_WOI_HEIGHT, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+///P_WOI_HEIGHT-> number of lines to acquire. Or move it to memsensor so other changes (decimation, binning) will lead to recalc number of lines?
+///FLIP_H is safe, FLIPV produces bad frame
+ P_FLIPH, ONCHANGE_WINDOW_SAFE | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN , /// bit 0 - horizontal (ONCHANGE_SENSORIN for Bayer)
+ P_FLIPV, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART, /// bit 1 - vertical (ONCHANGE_SENSORIN for Bayer)
+ P_FPSFLAGS, ONCHANGE_LIMITFPS ,
+ P_DCM_HOR, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
+/// Multisensor is called without any verification of [P_DCM_VERT] (it is needed to adjust gaps between frames)
+ P_DCM_VERT, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_BIN_HOR, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
+ P_BIN_VERT, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_COLOR, ONCHANGE_COMPMODE | ONCHANGE_LIMITFPS ,
+// P_PF_HEIGHT, ONCHANGE_RECALCSEQ | ONCHANGE_SENSORIN | ONCHANGE_LIMITFPS | ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+ P_PF_HEIGHT, ONCHANGE_RECALCSEQ | ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_BITS, ONCHANGE_SENSORIN | ONCHANGE_LIMITFPS | ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+ P_FPGATEST, ONCHANGE_SENSORIN ,
+ P_FPNS, ONCHANGE_SENSORIN ,
+ P_FPNM, ONCHANGE_SENSORIN ,
+ P_VIRTTRIG, ONCHANGE_SENSORIN ,
+ P_COMPMOD_BYRSH, ONCHANGE_COMPMODE,
+ P_COMPMOD_TILSH, ONCHANGE_COMPMODE,
+ P_COMPMOD_DCSUB, ONCHANGE_COMPMODE,
+ P_COMPMOD_QTAB, ONCHANGE_COMPMODE, // to be written not directly,but by pgm_quality ? (pgm_gamma to be used by pgm_gammaload - wrong)
+
+ P_FP1000SLIM, ONCHANGE_LIMITFPS ,
+ P_COLOR_SATURATION_BLUE, ONCHANGE_COMPMODE ,
+ P_COLOR_SATURATION_RED, ONCHANGE_COMPMODE ,
+ P_CORING_PAGE, ONCHANGE_COMPMODE ,
+ P_AUTOEXP_ON, ONCHANGE_AEXP ,
+ P_HISTWND_RWIDTH, ONCHANGE_HIST | ONCHANGE_AEXP ,
+ P_HISTWND_RHEIGHT, ONCHANGE_HIST | ONCHANGE_AEXP ,
+ P_HISTWND_RLEFT, ONCHANGE_HIST | ONCHANGE_AEXP ,
+ P_HISTWND_RTOP, ONCHANGE_HIST | ONCHANGE_AEXP ,
+ P_AUTOEXP_EXP_MAX, ONCHANGE_AEXP ,
+ P_AUTOEXP_OVEREXP_MAX, ONCHANGE_AEXP ,
+ P_AUTOEXP_S_PERCENT, ONCHANGE_AEXP ,
+ P_AUTOEXP_S_INDEX, ONCHANGE_AEXP ,
+ P_AUTOEXP_SKIP_PMIN, ONCHANGE_AEXP ,
+ P_AUTOEXP_SKIP_PMAX, ONCHANGE_AEXP ,
+ P_AUTOEXP_SKIP_T, ONCHANGE_AEXP ,
+ P_FOCUS_SHOW, ONCHANGE_COMPMODE , /// ONCHANGE_COMPMODE, not ONCHANGE_FOCUSMODE (it only can be done w/o the sequencer)
+ P_FOCUS_SHOW1, ONCHANGE_FOCUSMODE ,
+ P_RFOCUS_LEFT, ONCHANGE_FOCUSMODE ,
+ P_RFOCUS_WIDTH, ONCHANGE_FOCUSMODE ,
+ P_RFOCUS_TOP, ONCHANGE_FOCUSMODE ,
+ P_RFOCUS_HEIGHT, ONCHANGE_FOCUSMODE ,
+ P_FOCUS_FILTER, ONCHANGE_FOCUSMODE ,
+ P_TRIG_CONDITION, ONCHANGE_TRIGSEQ ,
+ P_TRIG_DELAY, ONCHANGE_TRIGSEQ ,
+ P_TRIG_OUT, ONCHANGE_TRIGSEQ ,
+ P_TRIG_PERIOD, ONCHANGE_TRIGSEQ ,
+ P_SKIP_FRAMES, ONCHANGE_RECALCSEQ ,
+ P_I2C_QPERIOD, ONCHANGE_I2C ,
+ P_I2C_BYTES, ONCHANGE_I2C ,
+ P_IRQ_SMART, ONCHANGE_IRQ ,
+ P_EXTERN_TIMESTAMP, ONCHANGE_TRIGSEQ ,
+ P_TRIG_BITLENGTH, ONCHANGE_TRIGSEQ ,
+ P_XMIT_TIMESTAMP, ONCHANGE_TRIGSEQ ,
+ P_OVERSIZE, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+ P_QUALITY, ONCHANGE_QUALITY ,
+ P_PORTRAIT, ONCHANGE_QUALITY ,
+ P_CORING_INDEX, ONCHANGE_QUALITY ,
+
+ P_TESTSENSOR, ONCHANGE_GAINS , /// sensor test mode - now processed together with sensor gains
+ P_GAINR, ONCHANGE_GAINS | ONCHANGE_PRESCAL , /// Set digital gain after adjusting analog gain
+ P_GAING, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_GAINGB, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_RSCALE_ALL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_GSCALE_ALL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_BSCALE_ALL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_GAINB, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_GAIN_CTRL, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_GAIN_MIN, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_GAIN_MAX, ONCHANGE_GAINS | ONCHANGE_PRESCAL ,
+ P_EXPOS, ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS, /// Otherwise it only increase period/decr. indicated FP1000S, but does not chnage when exposure is decreased
+ P_VEXPOS, ONCHANGE_EXPOSURE | ONCHANGE_LIMITFPS, /// Otherwise it only increase period/decr. indicated FP1000S, but does not chnage when exposure is decreased
+ P_GTAB_R, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
+ P_GTAB_G, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
+ P_GTAB_GB, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
+ P_GTAB_B, ONCHANGE_GAMMA | ONCHANGE_GAMMALOAD,
+ P_COMPRESSOR_RUN, ONCHANGE_COMPCTL,
+ P_VIGNET_AX, ONCHANGE_PRESCAL,
+ P_VIGNET_AY, ONCHANGE_PRESCAL,
+ P_VIGNET_BX, ONCHANGE_PRESCAL,
+ P_VIGNET_BY, ONCHANGE_PRESCAL,
+ P_VIGNET_C, ONCHANGE_PRESCAL,
+ P_VIGNET_SHL, ONCHANGE_PRESCAL,
+ P_SCALE_ZERO_IN, ONCHANGE_PRESCAL,
+ P_SCALE_ZERO_OUT, ONCHANGE_PRESCAL,
+ P_DGAINR, ONCHANGE_PRESCAL,
+ P_DGAING, ONCHANGE_PRESCAL,
+ P_DGAINGB, ONCHANGE_PRESCAL,
+ P_DGAINB, ONCHANGE_PRESCAL,
+ P_MULTISENS_EN, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_PHASE_SDRAM, ONCHANGE_SENSORPHASE,
+ P_MULTI_PHASE1, ONCHANGE_SENSORPHASE,
+ P_MULTI_PHASE2, ONCHANGE_SENSORPHASE,
+ P_MULTI_PHASE3, ONCHANGE_SENSORPHASE,
+ P_MULTI_SEQUENCE, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_SELECTED, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_FLIPH, ONCHANGE_WINDOW_SAFE | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN , /// bit 0 - horizontal (ONCHANGE_SENSORIN for Bayer)
+ P_MULTI_FLIPV, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_SENSORIN | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
+ P_MULTI_MODE, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_HBLANK, ONCHANGE_MULTISENS, /// not needed ? Calculated?)
+ P_MULTI_VBLANK, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_HEIGHT1, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_HEIGHT2, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_HEIGHT3, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+/*
+ P_MULTI_CWIDTH, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART ,
+ P_MULTI_CHEIGHT, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_CLEFT, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE ,
+ P_MULTI_CTOP, ONCHANGE_MULTISENS | ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
+*/
+ P_MULTI_VBLANK, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_WIDTH1, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
+ P_MULTI_WIDTH2, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
+ P_MULTI_WIDTH3, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
+ P_MULTI_HEIGHT1, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_HEIGHT2, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_HEIGHT3, ONCHANGE_MULTISENS |
+ ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN ,
+ P_MULTI_LEFT1, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE,
+ P_MULTI_LEFT2, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE,
+ P_MULTI_LEFT3, ONCHANGE_MULTISENS | ONCHANGE_WINDOW_SAFE,
+ P_MULTI_TOP1, ONCHANGE_MULTISENS |ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
+ P_MULTI_TOP2, ONCHANGE_MULTISENS |ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
+ P_MULTI_TOP3, ONCHANGE_MULTISENS |ONCHANGE_WINDOW | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART,
+/// These two below are changed in multisensor
+ P_SENSOR_WIDTH, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN,
+ P_SENSOR_HEIGHT, ONCHANGE_WINDOW | ONCHANGE_EXPOSURE | ONCHANGE_HIST | ONCHANGE_AEXP | ONCHANGE_FOCUSMODE | ONCHANGE_LIMITFPS | ONCHANGE_HIST | \
+ ONCHANGE_MEMSENSOR | ONCHANGE_MEMCOMPRESSOR | ONCHANGE_COMPMODE | ONCHANGE_COMPSTOP | ONCHANGE_COMPRESTART | ONCHANGE_SENSORIN
+ };
+#endif
diff --git a/src/drivers/elphel/quantization_tables.c b/src/drivers/elphel/quantization_tables.c
new file mode 100644
index 0000000000000000000000000000000000000000..f5c741f87cc26888270d387cd1939b86efea5a66
--- /dev/null
+++ b/src/drivers/elphel/quantization_tables.c
@@ -0,0 +1,957 @@
+/*!********************************************************************************
+ *! FILE NAME : quantization_tables.c
+ *! DESCRIPTION: Generation and handling quantization tables:
+ *! - direct - to be included in the JPEG headers and
+ *! - reverse - to go to the FPGA. Reverse are calculated as 0x10000/direct
+ *! Based on standard JPEG quality quantization tables, with the following differences
+ *! - FPGA uses multiplication by 65536/x instead of division by x
+ *! - (to better handle JP4 flavors) it is possible to use Y tables for other components
+ *! possibly with different quality.
+ *!
+ *! Quality is represented by 2-byte value. Each byte uses Y table if the value is Q<128,
+ *! and C table with (Q-128) if it is Q>=128.
+ *! If the High byte is zero, it is treated as Q^0x80 (Q|=(Q^0x80)<<8) for compatibility
+ *! with a standard single-byte Q value
+ *! FPGA table accomodates 8 pairs of quantization coefficients, so software tries
+ *! to reuse loaded tables when possible
+ *!
+ *! Copyright (C) 2008 Elphel, Inc.
+ *! -----------------------------------------------------------------------------**
+ *!
+ *! This program is free software: you can redistribute it and/or modify
+ *! it under the terms of the GNU General Public License as published by
+ *! the Free Software Foundation, either version 3 of the License, or
+ *! (at your option) any later version.
+ *!
+ *! This program is distributed in the hope that it will be useful,
+ *! but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *! GNU General Public License for more details.
+ *! You should have received a copy of the GNU General Public License
+ *! along with this program. If not, see .
+ *! -----------------------------------------------------------------------------**
+ *! $Log: quantization_tables.c,v $
+ *! Revision 1.4 2010/08/03 23:37:34 elphel
+ *! rev 8.0.8.37, portrait mode support
+ *!
+ *! Revision 1.3 2010/08/01 19:29:24 elphel
+ *! files updated to support coring function for noise filtering
+ *!
+ *! Revision 1.2 2010/05/31 21:47:21 elphel
+ *! Fixed old bug that effectively disabled FPGA and file headers quantization tables caching
+ *!
+ *! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
+ *!
+ *!
+ *! Revision 1.8 2008/10/29 04:18:28 elphel
+ *! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
+ *!
+ *! Revision 1.7 2008/10/23 08:08:41 elphel
+ *! reenabled irq in debug mode
+ *!
+ *! Revision 1.6 2008/10/05 05:13:33 elphel
+ *! snapshot003
+ *!
+ *! Revision 1.5 2008/09/12 00:24:00 elphel
+ *! removed cc353.c, cc353.h
+ *!
+ *! Revision 1.4 2008/09/11 01:05:32 elphel
+ *! snapshot
+ *!
+ *! Revision 1.3 2008/09/05 23:20:26 elphel
+ *! just a snapshot
+ *!
+ *! Revision 1.2 2008/07/27 23:25:07 elphel
+ *! next snapshot
+ *!
+ *! Revision 1.1 2008/06/08 23:46:45 elphel
+ *! added drivers files for handling quantization tables, gamma tables and the histograms
+ *!
+ *!
+ */
+
+//copied from cxi2c.c - TODO:remove unneeded
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//#include
+#include // endians
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
+//#include "cc3x3.h"
+//#include "fpga_io.h"
+
+//#include "x3x3.h" // just for FPGA_NQTAB
+
+#include "framepars.h"
+//#include "fpga_io.h"//fpga_table_write_nice
+
+#include "quantization_tables.h"
+
+/**
+ * @brief optional debug output
+ */
+
+#if ELPHEL_DEBUG
+ #define D15(x) { if (GLOBALPARS(G_DEBUG) & (1 <<15)) { x ;} }
+ #define MDF15(x) { if (GLOBALPARS(G_DEBUG) & (1 <<15)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
+ #define D14(x) { if (GLOBALPARS(G_DEBUG) & (1 <<14)) { x ;} }
+ #define MDF14(x) { if (GLOBALPARS(G_DEBUG) & (1 <<14)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
+ #define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;}
+// #define D1I(x)
+ #define D1I(x) x
+#else
+ #define D1I(x) x
+ #define D15(x)
+ #define MDF15(x)
+ #define D14(x)
+ #define MDF14(x)
+ #define MDF(x)
+#endif
+
+
+#define QTABLE_SIZE 64 /// number of elements in quantization table
+#define QTABLE_HEAD_CACHE 8 /// number of quantization pairs in cache (just for generation of JPEG headers)
+ static unsigned int std_quant_tbls[4 * QTABLE_SIZE] = { /// make it possible to modify runtime later?
+
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99,
+
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+
+///transposed for portrait mode
+
+ 16, 12, 14, 14, 18, 24, 49, 72,
+ 11, 12, 13, 17, 22, 35, 64, 92,
+ 10, 14, 16, 22, 37, 55, 78, 95,
+ 16, 19, 24, 29, 56, 64, 87, 98,
+ 24, 26, 40, 51, 68, 81, 103, 112,
+ 40, 58, 57, 87, 109, 104, 121, 100,
+ 51, 60, 69, 80, 103, 113, 120, 103,
+ 61, 55, 56, 62, 77, 92, 101, 99,
+
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+
+ };
+
+/// with a number of programmed tables equal to PARS_FRAMES, and that "this" table is not needed it will always be possible to find an unused table slot
+/// LRU cache for JPEG headers
+static unsigned char qtable_cache [QTABLE_SIZE * 2 * QTABLE_HEAD_CACHE]; ///quantization tables cache
+static int qtable_cache_values [QTABLE_HEAD_CACHE]; /// quality values for the tables in cache
+static int qtable_cache_next[QTABLE_HEAD_CACHE] ; /// index of the next (not used longer than this) slot
+static int qtable_cache_mre; ///index of most recently used slot
+
+#define FPGA_NQTAB 8 /* got from x353.h */
+static int qtable_fpga_values [FPGA_NQTAB]; /// quality values for the tables in FPGA
+static int qtable_fpga_next[FPGA_NQTAB] ; /// index of the next (not used longer than this) slot in FPGA quantization tables
+static int qtable_fpga_mre; ///index of most recently used slot
+
+static int qtable_cache_initialized;
+static int qtable_fpga_initialized;
+// Coring function table, 256 4-bit values per function
+// min=0, max=10, step=0.1
+//static char * coring_tables;
+static unsigned long coring_tables[];
+
+
+
+
+/**
+ * @brief force (re-)initilaization of quantization tables cache and FPGA qunatization table (in FPGA) when next used.
+ */
+void reset_qtables(void) {
+ qtable_cache_initialized=0;
+ qtable_fpga_initialized=0;
+}
+
+
+/**
+ * @brief initialization of quantization tables (direct - JPEG header ones) cache
+ * \n TODO: add \b init_qtable_head_cache to module initialization
+ */
+void init_qtable_head_cache (void) {
+ D1I(unsigned long flags);
+ int i;
+ MDF(printk("\n"));
+ D1I(local_irq_save(flags));
+/// needs to turn off IRQ
+ for (i=0; i < QTABLE_HEAD_CACHE; i++) {
+ qtable_cache_values[i]=-1; /// undefined
+ qtable_cache_next[i]=i+1; /// last value is invalid, but that's OK - it should not be used
+ qtable_cache_mre=0;
+ }
+ qtable_cache_initialized=1;
+ D1I(local_irq_restore(flags));
+}
+
+/**
+ * @brief calculates a pair of direct (JPEG header) tables for the specified quality (2-bytes )
+ * @param quality2 single byte (standard) or a pair of bytes (see file header description)
+ * @param y_tab caller-provided pointer to a 64-byte Y (intensity) quantization table (NULL - don't copy)
+ * @param c_tab caller-provided pointer to a 64-byte C (color) quantization table (NULL - don't copy)
+ * @return 0 - cache hit, 1 - cache miss (recalculated), -1 - invalid quality
+ */
+int get_qtable (int quality2, unsigned char *y_tab, unsigned char *c_tab) {
+ D1I(unsigned long flags);
+ int i,transpose,cache_index,cache_index_prev,q_type,quality,temp,tstart;
+ int rslt=0;
+ unsigned char * tab;
+ const unsigned int zig_zag[QTABLE_SIZE] = {
+ 0, 1, 5, 6,14,15,27,28,
+ 2, 4, 7,13,16,26,29,42,
+ 3, 8,12,17,25,30,41,43,
+ 9,11,18,24,31,40,44,53,
+ 10,19,23,32,39,45,52,54,
+ 20,22,33,38,46,51,55,60,
+ 21,34,37,47,50,56,59,61,
+ 35,36,48,49,57,58,62,63
+ };
+ if (qtable_cache_initialized==0) init_qtable_head_cache();
+
+
+ MDF14(printk("quality2=0x%x\n",quality2));
+ if (quality2<0) return -1;
+// transpose=(quality2>>7) & 1; /// 0 - landscape mode, 1 - portrait mode
+// if (quality2<256) quality2 |= (quality2^0x80)<<8;
+ if (quality2<256) quality2 |= (quality2 & 0x7f)<<8;
+// else (quality
+ MDF14(printk("quality2=0x%x\n",quality2));
+ D1I(local_irq_save(flags));
+/// look if such q value is already in cache
+ cache_index=qtable_cache_mre;
+ cache_index_prev=-1;
+ for (i=0; (i=0); i++) {
+ cache_index_prev=cache_index;
+ cache_index=qtable_cache_next[cache_index];
+ D14(printk(" ---i=%d, cache_index_prev=%d, cache_index=%d\n",i, cache_index_prev, cache_index));
+ }
+/// cache_index is invalid if (i==FPGA_NQTAB), but cache_index_prev is OK
+
+/// End of cache?
+ if (i==QTABLE_HEAD_CACHE) { /// yes, re-use the LRE slot
+ qtable_cache_next[cache_index_prev]=qtable_cache_mre;
+ qtable_cache_mre=cache_index_prev;
+ MDF14(printk("qtable_cache_mre=%d\n",qtable_cache_mre));
+ } else if (cache_index_prev>=0){ /// no, hit or never used so far, and not the first - anyway use this slot
+ qtable_cache_next[cache_index_prev]=qtable_cache_next[cache_index]; /// bypass this
+ qtable_cache_next[cache_index]=qtable_cache_mre; /// this points to the old mre
+ qtable_cache_mre=cache_index; /// this is now mre
+ MDF14(printk("qtable_cache_mre=%d\n",qtable_cache_mre));
+ }
+/// is it a hit or a miss?
+ if (qtable_cache_values[qtable_cache_mre] != quality2) { /// miss, calculate the table and save it to cache first
+ qtable_cache_values[qtable_cache_mre] = quality2; /// this operator was missing !!!
+ rslt=1;
+ transpose=(quality2>>7) & 1; /// 0 - landscape mode, 1 - portrait mode
+ for (q_type=0;q_type<2;q_type++) { //Y/C
+// quality=(quality2>>(q_type?8:0)) & 0xff;
+ quality= q_type?((quality2>>8)^0x80):(quality2 & 0x7f);
+ tstart=((quality & 0x80)?QTABLE_SIZE:0)+(transpose*(QTABLE_SIZE*2));
+ tab = & qtable_cache [QTABLE_SIZE * (2 * qtable_cache_mre + q_type)];
+ quality &= 0x7f;
+ MDF14(printk("transpose=%d tstart=%d, quality=%d\n",transpose,tstart,quality));
+ /// Safety limit on quality factor. Convert 0 to 1 to avoid zero divide.
+ if(quality <= 0)
+ quality = 1;
+ if(quality > 100)
+ quality = 100;
+ /** The basic table is used as-is (scaling 100) for a quality of 50.
+ * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
+ * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
+ * to make all the table entries 1 (hence, minimum quantization loss).
+ * Qualities 1..50 are converted to scaling percentage 5000/Q.
+ */
+ if(quality < 50)
+ quality = 5000 / quality;
+ else
+ quality = 200 - quality * 2;
+ MDF14(printk("q_type=%d, quality=%d\n",q_type,quality));
+ for(i = 0; i < QTABLE_SIZE; i++) {
+ temp = (std_quant_tbls[i+tstart] * quality + 50) / 100;
+ /// limit the values to the valid range
+ if(temp <= 0) temp = 1;
+ if(temp > 255) temp = 255;
+ tab[zig_zag[i]]=temp;
+ }
+ }
+ } /// now table pair is calculated and stored in cache
+/// copy tables to the output
+ if (y_tab) memcpy (y_tab, & qtable_cache [QTABLE_SIZE * (2 * qtable_cache_mre + 0)],QTABLE_SIZE) ;
+ if (c_tab) memcpy (c_tab, & qtable_cache [QTABLE_SIZE * (2 * qtable_cache_mre + 1)],QTABLE_SIZE) ;
+ D1I(local_irq_restore(flags));
+ MDF14(printk("y_tab=0x%x, c_tab=0x%x, rslt=%d\n",(int) y_tab, (int) c_tab, rslt));
+ MDF15(if (y_tab) {printk("y_tab\n"); for (i=0;i<64;i++){if ((i & 7)==0) printk("\n");printk(" %02x",(int) y_tab[i]);} printk("\n");});
+ MDF15(if (c_tab) {printk("c_tab\n"); for (i=0;i<64;i++){if ((i & 7)==0) printk("\n");printk(" %02x",(int) c_tab[i]);} printk("\n");});
+ return rslt;
+}
+
+/**
+ * @brief initialization of quantization tables (reverse, for the FPGA) cache
+ * \n TODO: add \b init_qtable_fpga to module initialization
+ */
+void init_qtable_fpga(void) {
+ D1I(unsigned long flags);
+ int i;
+ MDF14(printk("\n"));
+ D1I(local_irq_save(flags)); /// needs to turn off IRQ
+ for (i=0; i < FPGA_NQTAB; i++) {
+ qtable_fpga_values[i]=-1; // undefined
+ qtable_fpga_next[i]=i+1; // last value is invalid, but that's OK - it should not be used
+ qtable_fpga_mre=0;
+ }
+ qtable_fpga_initialized=1;
+ D1I(local_irq_restore(flags));
+}
+
+/**
+ * @brief Finds an already programmed FPGA page or calculates (and programms FPGA with) a new one
+ * @param quality2 single byte (standard) or a pair of bytes (see file header description)
+ * @return table page number used (0..7) or -1 - invalid q
+ */
+int set_qtable_fpga(int quality2) {
+ D1I(unsigned long flags);
+ int i,transpose,fpga_index,fpga_index_prev,q_type,quality,temp,tstart;
+ unsigned short qtable_fpga[QTABLE_SIZE *2];
+ unsigned short * tab;
+ if (qtable_fpga_initialized==0) init_qtable_fpga();
+ if (quality2<0) return -1;
+// if (quality2<256) quality2 |= (quality2 ^ 0x80)<<8;
+ if (quality2<256) quality2 |= (quality2 & 0x7f)<<8;
+ MDF14(printk("quality2=0x%x\n",quality2)); // d050
+ D1I(local_irq_save(flags));
+/// look if such q value is already in cache
+ fpga_index=qtable_fpga_mre;
+ fpga_index_prev=-1;
+ for (i=0; (i=0); i++) {
+ fpga_index_prev=fpga_index;
+ fpga_index=qtable_fpga_next[fpga_index];
+ D14(printk(" ---i=%d, fpga_index_prev=%d, fpga_index=%d\n",i, fpga_index_prev, fpga_index)); ///NOTE: never - fixed!
+
+ }
+/// fpga_index is invalid if (i==FPGA_NQTAB), but fpga_index_prev is OK
+/// End of cache?
+ if (i==FPGA_NQTAB) { /// yes, re-use the LRE slot
+ qtable_fpga_next[fpga_index_prev]=qtable_fpga_mre;
+ qtable_fpga_mre=fpga_index_prev;
+ MDF14(printk("qtable_fpga_mre=%d\n",qtable_fpga_mre)); ///NOTE: never
+ } else if (fpga_index_prev>=0) { /// no, hit or never used so far, and not the latest - anyway use this slot
+ qtable_fpga_next[fpga_index_prev]=qtable_fpga_next[fpga_index]; /// bypass this
+ qtable_fpga_next[fpga_index]=qtable_fpga_mre; /// this points to the old mre
+ qtable_fpga_mre=fpga_index; /// this is now mre
+ MDF14(printk("qtable_fpga_mre=%d\n",qtable_fpga_mre)); ///NOTE: never
+ }
+/// is it a hit or miss?
+ if (qtable_fpga_values[qtable_fpga_mre] != quality2) { /// miss, calculate the table and send it to the FPGA
+ qtable_fpga_values[qtable_fpga_mre] = quality2;
+ transpose=(quality2>>7) & 1; /// 0 - landscape mode, 1 - portrait mode
+ for (q_type=0;q_type<2;q_type++) { //Y/C
+// quality=(quality2>>(q_type?8:0)) & 0xff;
+ quality= q_type?((quality2>>8)^0x80):(quality2 & 0x7f);
+ MDF14(printk("transpose=%d q_type=%d, quality=%d quality2=0x%x\n",transpose, q_type,quality,quality2));
+ tstart=((quality & 0x80)?QTABLE_SIZE:0)+(transpose*(QTABLE_SIZE*2));
+ tab = &qtable_fpga [QTABLE_SIZE * q_type];
+ quality &= 0x7f;
+ MDF14(printk("tstart=%d, quality=%d\n",tstart,quality)); //0, 1 - both times
+ /// Safety limit on quality factor. Convert 0 to 1 to avoid zero divide.
+ if(quality <= 0)
+ quality = 1;
+ if(quality > 100)
+ quality = 100;
+ /** The basic table is used as-is (scaling 100) for a quality of 50.
+ * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
+ * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
+ * to make all the table entries 1 (hence, minimum quantization loss).
+ * Qualities 1..50 are converted to scaling percentage 5000/Q.
+ */
+ if(quality < 50)
+ quality = 5000 / quality;
+ else
+ quality = 200 - quality * 2;
+ MDF14(printk("q_type=%d, quality=%d\n",q_type,quality));
+ for(i = 0; i < QTABLE_SIZE; i++) {
+ temp = (std_quant_tbls[i+tstart] * quality + 50) / 100;
+ D15(if ((i & 7)==0) printk("\n");if (i==0) printk("\n");printk(" %08x",(int) temp));
+ /// limit the values to the valid range
+ if(temp <= 0) temp = 1;
+ if(temp > 255) temp = 255;
+ temp = ((0x20000/temp) + 1) >> 1;
+ if(temp > 0xffff) temp = 0xffff;
+ tab[i]=temp;
+ }
+ }
+ D15(printk("\n"));
+#ifdef TEST_DISABLE_CODE
+ fpga_table_write_nice (CX313_FPGA_TABLES_QUANT+qtable_fpga_mre*QTABLE_SIZE, QTABLE_SIZE, (unsigned long *) qtable_fpga);
+#endif /* TEST_DISABLE_CODE */
+ MDF15(for (i=0;i<128;i++){if ((i & 7)==0) printk("\n");if ((i & 63)==0) printk("\n");printk(" %04x",(int) qtable_fpga[i]);} printk("\n"));
+ MDF15(for (i=0;i<128;i++){if ((i & 7)==0) printk("\n");if ((i & 63)==0) printk("\n");printk(" %04x",std_quant_tbls[i]);} printk("\n"));
+ } /// now table pair is calculated and stored in cache
+/// copy tables to the FPGA
+ D1I(local_irq_restore(flags));
+ MDF14(printk("qtable_fpga_mre=%d\n",qtable_fpga_mre));
+ return qtable_fpga_mre;
+}
+
+// Coring function table, 256 4-bit values per function
+// min=0, max=10, step=0.1
+// See coring_filter_setup.php to generate this table (with parameter '?C')
+ static unsigned long coring_tables[]= {
+// filter=0
+ 0x00000000, 0x11111111, 0x11111111, 0x22222222, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.1
+ 0x00000000, 0x11111110, 0x11111111, 0x22222222, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.2
+ 0x00000000, 0x11111110, 0x11111111, 0x22222222, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.3
+ 0x00000000, 0x11111110, 0x11111111, 0x22222221, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.4
+ 0x00000000, 0x11111100, 0x11111111, 0x22222221, 0x22222222, 0x33333333, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.5
+ 0x00000000, 0x11111000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.6
+ 0x00000000, 0x11111000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.7
+ 0x00000000, 0x11110000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444444,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.8
+ 0x00000000, 0x11100000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=0.9
+ 0x00000000, 0x11000000, 0x11111111, 0x22222221, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555555, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1
+ 0x00000000, 0x10000000, 0x11111111, 0x22222211, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.1
+ 0x00000000, 0x00000000, 0x11111111, 0x22222111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.2
+ 0x00000000, 0x00000000, 0x11111110, 0x22221111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666666, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.3
+ 0x00000000, 0x00000000, 0x11111110, 0x22211111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.4
+ 0x00000000, 0x00000000, 0x11111100, 0x22211111, 0x22222222, 0x33333332, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.5
+ 0x00000000, 0x00000000, 0x11111000, 0x22111111, 0x22222222, 0x33333322, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.6
+ 0x00000000, 0x00000000, 0x11110000, 0x21111111, 0x22222222, 0x33333322, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777777, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.7
+ 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222222, 0x33333222, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.8
+ 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222221, 0x33332222, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=1.9
+ 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x22222211, 0x33322222, 0x33333333, 0x44444443,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2
+ 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x22222111, 0x33322222, 0x33333333, 0x44444433,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888888,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.1
+ 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x22221111, 0x33222222, 0x33333333, 0x44444433,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.2
+ 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x22211111, 0x32222222, 0x33333333, 0x44444433,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.3
+ 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x22111111, 0x22222222, 0x33333333, 0x44444333,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.4
+ 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x21111111, 0x22222222, 0x33333332, 0x44443333,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.5
+ 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x22222222, 0x33333322, 0x44443333,
+ 0x44444444, 0x55555554, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999999, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.6
+ 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22222221, 0x33333222, 0x44433333,
+ 0x44444444, 0x55555544, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.7
+ 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22222221, 0x33332222, 0x44333333,
+ 0x44444444, 0x55555544, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.8
+ 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222211, 0x33322222, 0x43333333,
+ 0x44444444, 0x55555544, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=2.9
+ 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22222111, 0x33222222, 0x33333333,
+ 0x44444444, 0x55555444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3
+ 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x22221111, 0x32222222, 0x33333333,
+ 0x44444444, 0x55555444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaaa, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.1
+ 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x22211111, 0x22222222, 0x33333333,
+ 0x44444443, 0x55554444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.2
+ 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x22111111, 0x22222222, 0x33333333,
+ 0x44444433, 0x55544444, 0x55555555, 0x66666665, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.3
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x21111111, 0x22222222, 0x33333332,
+ 0x44444333, 0x55544444, 0x55555555, 0x66666655, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x22222222, 0x33333322,
+ 0x44443333, 0x55444444, 0x55555555, 0x66666655, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x22222221, 0x33333222,
+ 0x44433333, 0x54444444, 0x55555555, 0x66666555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x22222211, 0x33332222,
+ 0x44333333, 0x44444444, 0x55555555, 0x66666555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22222111, 0x33322222,
+ 0x43333333, 0x44444444, 0x55555554, 0x66665555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22222111, 0x33222222,
+ 0x33333333, 0x44444444, 0x55555554, 0x66665555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbbb, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=3.9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22221111, 0x32222222,
+ 0x33333333, 0x44444443, 0x55555544, 0x66655555, 0x66666666, 0x77777776, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x22211111, 0x22222222,
+ 0x33333333, 0x44444433, 0x55555444, 0x66655555, 0x66666666, 0x77777766, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.1
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x22111111, 0x22222222,
+ 0x33333332, 0x44444333, 0x55554444, 0x66555555, 0x66666666, 0x77777766, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.2
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x21111111, 0x22222222,
+ 0x33333322, 0x44443333, 0x55544444, 0x65555555, 0x66666666, 0x77777666, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.3
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x11111111, 0x22222222,
+ 0x33333222, 0x44433333, 0x55444444, 0x55555555, 0x66666666, 0x77777666, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x22222221,
+ 0x33332222, 0x44333333, 0x54444444, 0x55555555, 0x66666666, 0x77777666, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x22222211,
+ 0x33322222, 0x43333333, 0x44444444, 0x55555555, 0x66666665, 0x77776666, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x22222111,
+ 0x33222222, 0x33333333, 0x44444444, 0x55555554, 0x66666655, 0x77766666, 0x77777777, 0x88888887,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x22221111,
+ 0x32222222, 0x33333333, 0x44444443, 0x55555544, 0x66666555, 0x77766666, 0x77777777, 0x88888877,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccc,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22211111,
+ 0x22222222, 0x33333333, 0x44444433, 0x55555444, 0x66665555, 0x77666666, 0x77777777, 0x88888877,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=4.9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x22211111,
+ 0x22222222, 0x33333332, 0x44444333, 0x55554444, 0x66655555, 0x77666666, 0x77777777, 0x88888877,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x22111111,
+ 0x22222222, 0x33333322, 0x44443333, 0x55544444, 0x66655555, 0x76666666, 0x77777777, 0x88888777,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.1
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x21111111,
+ 0x22222222, 0x33333222, 0x44433333, 0x55444444, 0x66555555, 0x66666666, 0x77777777, 0x88888777,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.2
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x11111111,
+ 0x22222222, 0x33332222, 0x44333333, 0x55444444, 0x65555555, 0x66666666, 0x77777776, 0x88887777,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.3
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111, 0x11111111,
+ 0x22222221, 0x33322222, 0x43333333, 0x54444444, 0x55555555, 0x66666666, 0x77777776, 0x88887777,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x11111111,
+ 0x22222211, 0x33222222, 0x33333333, 0x44444444, 0x55555555, 0x66666665, 0x77777766, 0x88877777,
+ 0x88888888, 0x99999998, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111,
+ 0x22222111, 0x32222222, 0x33333333, 0x44444443, 0x55555554, 0x66666655, 0x77777666, 0x88877777,
+ 0x88888888, 0x99999988, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111,
+ 0x22221111, 0x22222222, 0x33333333, 0x44444433, 0x55555444, 0x66666555, 0x77776666, 0x88777777,
+ 0x88888888, 0x99999988, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110, 0x11111111,
+ 0x22211111, 0x22222222, 0x33333332, 0x44444333, 0x55554444, 0x66665555, 0x77766666, 0x88777777,
+ 0x88888888, 0x99999988, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100, 0x11111111,
+ 0x22111111, 0x22222222, 0x33333322, 0x44443333, 0x55544444, 0x66655555, 0x77666666, 0x87777777,
+ 0x88888888, 0x99999888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddd, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=5.9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111,
+ 0x21111111, 0x22222222, 0x33333222, 0x44433333, 0x55444444, 0x66555555, 0x77666666, 0x77777777,
+ 0x88888888, 0x99999888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000, 0x11111111,
+ 0x11111111, 0x22222222, 0x33332222, 0x44333333, 0x54444444, 0x65555555, 0x76666666, 0x77777777,
+ 0x88888888, 0x99999888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.1
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000, 0x11111111,
+ 0x11111111, 0x22222221, 0x33322222, 0x43333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777,
+ 0x88888887, 0x99998888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.2
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000, 0x11111111,
+ 0x11111111, 0x22222211, 0x33222222, 0x33333333, 0x44444444, 0x55555554, 0x66666665, 0x77777776,
+ 0x88888877, 0x99998888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.3
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111,
+ 0x11111111, 0x22222111, 0x32222222, 0x33333333, 0x44444443, 0x55555544, 0x66666655, 0x77777766,
+ 0x88888777, 0x99988888, 0x99999999, 0xaaaaaaa9, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000, 0x11111111,
+ 0x11111111, 0x22222111, 0x22222222, 0x33333333, 0x44444433, 0x55555444, 0x66666555, 0x77777666,
+ 0x88887777, 0x99988888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000, 0x11111111,
+ 0x11111111, 0x22221111, 0x22222222, 0x33333332, 0x44444333, 0x55554444, 0x66665555, 0x77776666,
+ 0x88887777, 0x99888888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111111,
+ 0x11111111, 0x22211111, 0x22222222, 0x33333322, 0x44443333, 0x55544444, 0x66655555, 0x77766666,
+ 0x88877777, 0x98888888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111110,
+ 0x11111111, 0x22111111, 0x22222222, 0x33333222, 0x44433333, 0x55444444, 0x66555555, 0x77666666,
+ 0x88777777, 0x98888888, 0x99999999, 0xaaaaaa99, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100,
+ 0x11111111, 0x21111111, 0x22222222, 0x33332222, 0x44333333, 0x54444444, 0x65555555, 0x76666666,
+ 0x87777777, 0x88888888, 0x99999999, 0xaaaaa999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=6.9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111100,
+ 0x11111111, 0x11111111, 0x22222222, 0x33322222, 0x43333333, 0x44444444, 0x55555555, 0x66666666,
+ 0x77777777, 0x88888888, 0x99999998, 0xaaaaa999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11111000,
+ 0x11111111, 0x11111111, 0x22222221, 0x33222222, 0x33333333, 0x44444444, 0x55555554, 0x66666665,
+ 0x77777776, 0x88888887, 0x99999998, 0xaaaa9999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.1
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11110000,
+ 0x11111111, 0x11111111, 0x22222211, 0x32222222, 0x33333333, 0x44444433, 0x55555544, 0x66666655,
+ 0x77777766, 0x88888877, 0x99999988, 0xaaaa9999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.2
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11100000,
+ 0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333332, 0x44444333, 0x55555444, 0x66666555,
+ 0x77777666, 0x88888877, 0x99999888, 0xaaa99999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.3
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000000,
+ 0x11111111, 0x11111111, 0x22221111, 0x22222222, 0x33333322, 0x44443333, 0x55554444, 0x66665555,
+ 0x77776666, 0x88888777, 0x99998888, 0xaaa99999, 0xaaaaaaaa, 0xbbbbbbba, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000,
+ 0x11111111, 0x11111111, 0x22211111, 0x22222222, 0x33333222, 0x44433333, 0x55544444, 0x66655555,
+ 0x77766666, 0x88887777, 0x99998888, 0xaa999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000000,
+ 0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222, 0x44333333, 0x54444444, 0x66555555,
+ 0x77666666, 0x88877777, 0x99988888, 0xaa999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeee, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33322222, 0x43333333, 0x44444444, 0x65555555,
+ 0x76666666, 0x88777777, 0x99888888, 0xa9999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11111110, 0x11111111, 0x11111111, 0x22222222, 0x33222222, 0x33333333, 0x44444444, 0x55555554,
+ 0x66666665, 0x87777777, 0x98888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbbaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11111100, 0x11111111, 0x11111111, 0x22222211, 0x32222222, 0x33333333, 0x44444443, 0x55555544,
+ 0x66666655, 0x77777776, 0x88888888, 0x99999999, 0xaaaaaaaa, 0xbbbbbaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=7.9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11111000, 0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333333, 0x44444433, 0x55555444,
+ 0x66666555, 0x77777766, 0x88888887, 0x99999998, 0xaaaaaaa9, 0xbbbbbaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11110000, 0x11111111, 0x11111111, 0x22221111, 0x22222222, 0x33333332, 0x44443333, 0x55554444,
+ 0x66665555, 0x77777666, 0x88888877, 0x99999998, 0xaaaaaa99, 0xbbbbbaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.1
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11100000, 0x11111111, 0x11111111, 0x22211111, 0x22222222, 0x33333322, 0x44433333, 0x55544444,
+ 0x66655555, 0x77776666, 0x88888777, 0x99999988, 0xaaaaaa99, 0xbbbbaaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.2
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11000000, 0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222, 0x44333333, 0x55444444,
+ 0x66555555, 0x77766666, 0x88887777, 0x99999888, 0xaaaaa999, 0xbbbbaaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.3
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x11000000, 0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33322222, 0x43333333, 0x44444444,
+ 0x65555555, 0x77666666, 0x88877777, 0x99998888, 0xaaaa9999, 0xbbbaaaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x10000000, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x33222222, 0x33333333, 0x44444444,
+ 0x55555554, 0x76666666, 0x88777777, 0x99988888, 0xaaa99999, 0xbbbaaaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x11111111, 0x11111111, 0x11111111, 0x22222221, 0x32222222, 0x33333333, 0x44444443,
+ 0x55555544, 0x66666665, 0x87777777, 0x99888888, 0xaaa99999, 0xbbaaaaaa, 0xbbbbbbbb, 0xcccccccb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x11111110, 0x11111111, 0x11111111, 0x22222211, 0x22222222, 0x33333333, 0x44444333,
+ 0x55555444, 0x66666555, 0x77777776, 0x98888888, 0xaa999999, 0xbaaaaaaa, 0xbbbbbbbb, 0xccccccbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x11111100, 0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333332, 0x44443333,
+ 0x55554444, 0x66665555, 0x77777666, 0x88888887, 0xa9999999, 0xbaaaaaaa, 0xbbbbbbbb, 0xccccccbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x11111000, 0x11111111, 0x11111111, 0x22221111, 0x22222222, 0x33333222, 0x44433333,
+ 0x55544444, 0x66655555, 0x77776666, 0x88888877, 0x99999998, 0xaaaaaaaa, 0xbbbbbbbb, 0xccccccbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=8.9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x11110000, 0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222, 0x44333333,
+ 0x54444444, 0x66555555, 0x77766666, 0x88888777, 0x99999988, 0xaaaaaaa9, 0xbbbbbbba, 0xcccccbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x11100000, 0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33322222, 0x43333333,
+ 0x44444444, 0x65555555, 0x77666666, 0x88887777, 0x99999888, 0xaaaaaa99, 0xbbbbbbba, 0xcccccbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.1
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x11000000, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x33222222, 0x33333333,
+ 0x44444443, 0x55555554, 0x76666666, 0x88877777, 0x99998888, 0xaaaaaa99, 0xbbbbbbaa, 0xcccccbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.2
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x10000000, 0x11111111, 0x11111111, 0x11111111, 0x22222221, 0x32222222, 0x33333333,
+ 0x44444433, 0x55555544, 0x66666655, 0x87777777, 0x99988888, 0xaaaaa999, 0xbbbbbaaa, 0xccccbbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.3
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x11111111, 0x22222211, 0x22222222, 0x33333332,
+ 0x44444333, 0x55555444, 0x66666555, 0x77777776, 0x99888888, 0xaaaa9999, 0xbbbbbaaa, 0xccccbbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.4
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x11111110, 0x11111111, 0x11111111, 0x22222111, 0x22222222, 0x33333322,
+ 0x44443333, 0x55544444, 0x66665555, 0x77777666, 0x98888887, 0xaaa99999, 0xbbbbaaaa, 0xcccbbbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.5
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x11111100, 0x11111111, 0x11111111, 0x22211111, 0x22222222, 0x33333222,
+ 0x44433333, 0x55444444, 0x66655555, 0x77776666, 0x88888877, 0xaa999999, 0xbbbaaaaa, 0xcccbbbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.6
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x11111000, 0x11111111, 0x11111111, 0x22111111, 0x22222222, 0x33332222,
+ 0x43333333, 0x54444444, 0x66555555, 0x77766666, 0x88888777, 0xa9999998, 0xbbaaaaaa, 0xccbbbbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.7
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x11110000, 0x11111111, 0x11111111, 0x21111111, 0x22222222, 0x33222222,
+ 0x33333333, 0x44444444, 0x55555555, 0x77666666, 0x88887777, 0x99999988, 0xbaaaaaaa, 0xccbbbbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xffffffff, 0xffffffff, 0xffffffff,
+// filter=9.8
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x11100000, 0x11111111, 0x11111111, 0x11111111, 0x22222222, 0x32222222,
+ 0x33333333, 0x44444443, 0x55555544, 0x76666665, 0x88877777, 0x99999888, 0xbaaaaaa9, 0xcbbbbbbb,
+ 0xcccccccc, 0xdddddddc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xfffffffe, 0xffffffff, 0xffffffff,
+// filter=9.9
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x10000000, 0x11111111, 0x11111111, 0x11111111, 0x22222211, 0x22222222,
+ 0x33333333, 0x44444333, 0x55555444, 0x66666655, 0x88777777, 0x99998888, 0xaaaaaa99, 0xbbbbbbbb,
+ 0xcccccccc, 0xddddddcc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xfffffffe, 0xffffffff, 0xffffffff,
+// filter=10
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x11111111, 0x11111111, 0x11111111, 0x22222111, 0x22222222,
+ 0x33333332, 0x44443333, 0x55554444, 0x66666555, 0x77777766, 0x99988888, 0xaaaaa999, 0xbbbbbbba,
+ 0xcccccccc, 0xddddddcc, 0xdddddddd, 0xeeeeeeed, 0xeeeeeeee, 0xfffffffe, 0xffffffff, 0xffffffff
+ };
+/**
+ * @brief Temporary function to directly set one of the coring LUTs (currently 100 0.0 to 9.9 with 0.1 step)
+ * to one of 16 FPGA tables (even - for Y,odd - for C)
+ * @param coring_number 0..99 - function number
+ * @param fpga_number 0.. 15 - fpga table number
+ * @return table page number used (0..7) or -1 - invalid q
+ */
+#define CORING_SIZE 32 // longs
+void set_coring_fpga(int coring_number, int fpga_number) {
+ if (coring_number<0) coring_number=0;
+ if (coring_number>=sizeof(coring_tables)/(4*CORING_SIZE)) coring_number=sizeof(coring_tables)/(4*CORING_SIZE);
+ D15(printk("coring_number=0x%x, fpga_number=0x%x\n",coring_number, fpga_number));
+#ifdef TEST_DISABLE_CODE
+ fpga_table_write_nice (CX313_FPGA_TABLES_CORING+(fpga_number *CORING_SIZE) , CORING_SIZE, (unsigned long *) &coring_tables[coring_number*CORING_SIZE]);
+#endif /* TEST_DISABLE_CODE */
+ MDF15(int i; for (i=0;i<32;i++) {if ((i & 7)==0) printk("\n");printk(" %08x",(int) coring_tables[coring_number*CORING_SIZE +i]);} printk("\n"));
+}
diff --git a/src/drivers/elphel/quantization_tables.h b/src/drivers/elphel/quantization_tables.h
new file mode 100644
index 0000000000000000000000000000000000000000..83e712fd20ca92333339f2aa215bc4cc8e0147c3
--- /dev/null
+++ b/src/drivers/elphel/quantization_tables.h
@@ -0,0 +1,41 @@
+/// @file quantization_tables.h
+#ifndef _QUANTIZATION_TABLES_H
+#define _QUANTIZATION_TABLES_H
+/**
+ * @brief initialization of quantization tables (direct - JPEG header ones) cache
+ * \n TODO: add \b init_qtable_head_cache to module initialization
+ */
+void init_qtable_head_cache(void);
+/**
+ * @brief calculates a pair of direct (JPEG header) tables for the specified quality (2-bytes )
+ * @param quality2 single byte (standard) or a pair of bytes (see file header description)
+ * @param y_tab caller-provided pointer to a 64-byte Y (intensity) quantization table (NULL - don't copy)
+ * @param c_tab caller-provided pointer to a 64-byte C (color) quantization table (NULL - don't copy)
+ * @return 0 - cache hit, 1 - cache miss (recalculated), -1 - invalid quality
+ */
+int get_qtable(int quality2, unsigned char *y_tab, unsigned char *c_tab);
+/**
+ * @brief initialization of quantization tables (reverse, for the FPGA) cache
+ * \n TODO: add \b init_qtable_fpga to module initialization
+ */
+void init_qtable_fpga(void);
+/**
+ * @brief Finds an already programmed FPGA page or calculates (an programms FPGA with) a new one
+ * @param quality2 single byte (standard) or a pair of bytes (see file header description)
+ * @return table page number used (0..7) or -1 - invalid q
+ */
+int set_qtable_fpga(int quality2);
+
+/**
+ * @brief Temporary function to directly set one of the coring LUTs (currently 100 0.0 to 9.9 with 0.1 step)
+ * to one of 16 FPGA tables (even - for Y,odd - for C)
+ * @param coring_number 0..99 - function number
+ * @param fpga_number 0.. 15 - fpga table number
+ * @return table page number used (0..7) or -1 - invalid q
+ */
+void set_coring_fpga(int coring_number, int fpga_number);
+
+
+
+void reset_qtables(void);
+#endif
diff --git a/src/drivers/elphel/sensor_common.c b/src/drivers/elphel/sensor_common.c
new file mode 100644
index 0000000000000000000000000000000000000000..b9411f4e2448be7cb5bde547181a2dc90d79fd55
--- /dev/null
+++ b/src/drivers/elphel/sensor_common.c
@@ -0,0 +1,775 @@
+/*!********************************************************************************
+*! FILE NAME : sensor_common.c
+*! DESCRIPTION: Sensor discovery, initialization, programming - common
+*! for all sensors
+*! Now most is moved to other files, here will be
+*! - system initialization
+*! - compressor write (and global read) pointers
+*! - populating 32-byte interframe data
+*! - something for Exif?
+*! - where are histograms? ->histograms.c
+*! - interrupt loop
+*! - tasklets
+*! - device driver that includes waiting for the next frame regardless of compression
+*! - anything else?
+*!
+*!
+*! Copyright (C) 2008 Elphel, Inc.
+*! -----------------------------------------------------------------------------**
+*!
+*! This program is free software: you can redistribute it and/or modify
+*! it under the terms of the GNU General Public License as published by
+*! the Free Software Foundation, either version 3 of the License, or
+*! (at your option) any later version.
+*!
+*! This program is distributed in the hope that it will be useful,
+*! but WITHOUT ANY WARRANTY; without even the implied warranty of
+*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+*! GNU General Public License for more details.
+*!
+*! You should have received a copy of the GNU General Public License
+*! along with this program. If not, see .
+*! -----------------------------------------------------------------------------**
+*! $Log: sensor_common.c,v $
+*! Revision 1.11 2012/04/08 04:09:23 elphel
+*! added temperatures to MakerNote
+*!
+*! Revision 1.10 2010/08/10 21:14:31 elphel
+*! 8.0.8.39 - added EEPROM support for multiplexor and sensor boards, so autocampars.php uses application-specific defaults. Exif Orientation tag support, camera Model reflects application and optional mode (i.e. camera number in Eyesis)
+*!
+*! Revision 1.9 2010/08/03 23:37:34 elphel
+*! rev 8.0.8.37, portrait mode support
+*!
+*! Revision 1.8 2010/08/01 19:29:24 elphel
+*! files updated to support coring function for noise filtering
+*!
+*! Revision 1.7 2010/07/20 20:13:34 elphel
+*! 8.0.8.33 - added MakerNote info for composite images made with multisensor cameras (with 10359 board)
+*!
+*! Revision 1.6 2010/05/16 02:03:47 elphel
+*! 8.0.8.4 - driver working with individual/broadcast sensor registers
+*!
+*! Revision 1.5 2010/05/13 03:39:31 elphel
+*! 8.0.8.12 - drivers modified for multi-sensor operation
+*!
+*! Revision 1.4 2010/03/04 06:41:40 elphel
+*! 8.0.7.3 - more data to makerNote
+*!
+*! Revision 1.3 2009/12/28 06:24:17 elphel
+*! 8.0.6.6 - added MakerNote to Exif, it icludes channels gains and gammas/black levels
+*!
+*! Revision 1.2 2008/11/30 21:56:39 elphel
+*! Added enforcing limit on the overall gains in the color channels, storage of exposure and gains in the histograms cache (to be used with autoexposure/white balance)
+*!
+*! Revision 1.1.1.1 2008/11/27 20:04:00 elphel
+*!
+*!
+*! Revision 1.33 2008/11/20 07:04:47 elphel
+*! made silent when debug is 0
+*!
+*! Revision 1.32 2008/11/14 07:06:54 elphel
+*! fixed wrong timing for servicing histogram requests
+*!
+*! Revision 1.31 2008/11/13 05:40:45 elphel
+*! 8.0.alpha16 - modified histogram storage, profiling
+*!
+*! Revision 1.30 2008/11/10 19:47:46 elphel
+*! added TODO abut reducing CPU load by decimating histogram calculations (not each frame)
+*!
+*! Revision 1.29 2008/10/29 04:18:28 elphel
+*! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
+*!
+*! Revision 1.28 2008/10/26 05:54:45 elphel
+*! changed value of frame counters for histograms to compensate for 1 frame latency of histograms
+*!
+*! Revision 1.27 2008/10/25 19:55:00 elphel
+*! made the histograms calculations relate to previous, not this frame.
+*!
+*! Revision 1.26 2008/10/23 08:09:02 elphel
+*! support for histogram wait queues
+*!
+*! Revision 1.25 2008/10/19 06:56:05 elphel
+*! elphel_wait_frame() now works only for compressed frames, new elphel_skip_frames() and elphel_wait_frame_abs() wait sequencer frames (all sensor frames, even those that are not compressed)
+*!
+*! Revision 1.24 2008/10/15 22:28:56 elphel
+*! snapshot 8.0.alpha2
+*!
+*! Revision 1.23 2008/10/13 16:55:53 elphel
+*! removed (some) obsolete P_* parameters, renamed CIRCLSEEK to LSEEK_CIRC constants (same as other similar)
+*!
+*! Revision 1.22 2008/10/12 16:46:22 elphel
+*! snapshot
+*!
+*! Revision 1.21 2008/10/11 18:46:07 elphel
+*! snapshot
+*!
+*! Revision 1.20 2008/10/10 17:06:59 elphel
+*! just a snapshot
+*!
+*! Revision 1.19 2008/10/08 21:26:25 elphel
+*! snapsot 7.2.0.pre4 - first images (actually - second)
+*!
+*! Revision 1.18 2008/10/05 05:13:33 elphel
+*! snapshot003
+*!
+*! Revision 1.17 2008/10/04 16:10:12 elphel
+*! snapshot
+*!
+*! Revision 1.16 2008/09/28 00:31:57 elphel
+*! snapshot
+*!
+*! Revision 1.15 2008/09/25 00:58:12 elphel
+*! snapshot
+*!
+*! Revision 1.14 2008/09/22 22:55:49 elphel
+*! snapshot
+*!
+*! Revision 1.13 2008/09/20 00:29:50 elphel
+*! moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
+*!
+*! Revision 1.12 2008/09/19 04:37:26 elphel
+*! snapshot
+*!
+*! Revision 1.11 2008/09/16 00:49:32 elphel
+*! snapshot
+*!
+*! Revision 1.10 2008/09/12 00:24:00 elphel
+*! removed cc353.c, cc353.h
+*!
+*! Revision 1.9 2008/09/07 19:48:09 elphel
+*! snapshot
+*!
+*! Revision 1.8 2008/09/05 23:20:26 elphel
+*! just a snapshot
+*!
+*! Revision 1.7 2008/09/02 21:01:07 elphel
+*! just next...
+*!
+*! Revision 1.6 2008/07/29 01:15:07 elphel
+*! another snapshot
+*!
+*! Revision 1.5 2008/07/27 23:25:07 elphel
+*! next snapshot
+*!
+*! Revision 1.4 2008/07/27 04:27:49 elphel
+*! next snapshot
+*!
+*! Revision 1.3 2008/06/24 00:43:44 elphel
+*! just a snapshot
+*!
+*! Revision 1.2 2008/06/20 03:54:21 elphel
+*! another snapshot
+*!
+*! Revision 1.1 2008/06/16 06:51:21 elphel
+*! work in progress, intermediate commit
+*!
+*!
+*/
+
+//copied from cxi2c.c - TODO:remove unneeded
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+//#include
+#include
+#include
+#include
+
+//#include
+#include // endians
+#include
+
+//#include /// ETRAX interrupt registers
+
+#include
+
+#include
+#include
+#include
+#include
+//#include
+#include
+//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
+//#include "fpga_sdram.h" // use a single fpga_initSDRAM(void)
+
+//#include "x3x3.h"
+//#include "cc3x3.h"
+//#include "cxdma.h"
+
+#include "framepars.h"
+#include "sensor_common.h"
+//#include "pgm_functions.h"
+#include "circbuf.h"
+//#include "exif353.h"
+//#include "histograms.h"
+//#include "gamma_tables.h"
+#include "quantization_tables.h"
+
+#if ELPHEL_DEBUG
+ #define ELPHEL_DEBUG_THIS 0
+#else
+ #define ELPHEL_DEBUG_THIS 0
+#endif
+#if ELPHEL_DEBUG_THIS
+ #define MDF2(x) printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__); x
+ #define MDD1(x) printk("%s:%d:",__FILE__,__LINE__); x ; udelay (ELPHEL_DEBUG_DELAY)
+ #define MD1(x) printk("%s:%d:",__FILE__,__LINE__);x
+ //#define MD1(x)
+ #define MD12(x) printk("%s:%d:",__FILE__,__LINE__);x
+ //#define MD12(x)
+ #define MD13(x) printk("%s:%d:",__FILE__,__LINE__);x
+ //#define MD13(x)
+#else
+ #define MDF2(x)
+ #define MD1(x)
+ #define MDD1(x)
+ #define MD12(x)
+ #define MD13(x)
+#endif
+
+
+
+#define X3X3_ELPHEL_DRIVER_NAME "Elphel (R) Model 353 Camera Driver"
+static const char elphel_cam_name[] = "elphelcam353";
+
+static volatile int JPEG_wp;
+static volatile int JPEG_rp;
+static int fpga_counter_prev=0; /// Previous value of the FPGA transfer counter (to find out if it did change)
+ static struct meta_offsets_t { // works like a cache to time save on looking for tags in the directory (forced to recalcualte if does not match)
+ int Image_DateTime; // will have offset of the Exif_Image_DateTime data in meta page (Exif_Photo_SubSecTime should go immediately after in meta page)
+ int Photo_DateTimeOriginal;
+ int Photo_ExposureTime;
+ int Image_FrameNumber;
+ int Image_Orientation;
+ int Photo_MakerNote;
+ } meta_offsets;
+
+
+
+
+
+///Defines/macros moved from the cc353.h
+// #define EN_INTERRUPT(x) port_csp0_addr[X313_WA_IRQ_ENA]= (1<< x )
+// #define DIS_INTERRUPT(x) {port_csp0_addr[X313_WA_IRQ_DIS]= (1<< x ); port_csp0_addr[X313_WA_IRQ_RST]= (1<< x );}
+// #define DIS_INTERRUPTS {port_csp0_addr[X313_WA_IRQ_DIS]= 0xffff; port_csp0_addr[X313_WA_IRQ_RST]= 0xffff;}
+
+
+
+int camSeqGetJPEG_wp(void) {return JPEG_wp;}
+int camSeqGetJPEG_rp(void) {return JPEG_rp;}
+void camSeqSetJPEG_rp(int p) {
+ JPEG_rp=p;
+ set_globalParam(G_CIRCBUFRP, p<< 2);
+ set_globalParam(G_FREECIRCBUF,
+ (((get_globalParam(G_CIRCBUFRP) <= get_globalParam(G_CIRCBUFWP))?
+ get_globalParam(G_CIRCBUFSIZE):0)+ get_globalParam(G_CIRCBUFRP))
+ - get_globalParam(G_CIRCBUFWP));
+ }
+
+/*!
+ End of compressor-related code - TODO: move to a separate file?
+*/
+
+
+#define X3X3_IMAGEACQ_DRIVER_NAME "Elphel (R) Model 353 Image Acquisition device driver"
+static struct sensorproc_t s_sensorproc; // sensor parameters and functions to call
+struct sensorproc_t * sensorproc = NULL;
+//wait_queue_head_t image_acq_wait_queue; /// queue for the sensor frame interrupts
+
+
+struct image_acq_pd {
+ int minor;
+// struct wait_queue *image_acq_wait_queue;
+// something else to be added here?
+};
+
+void tasklet_fpga_function(unsigned long arg);
+
+/**
+ * @brief Copy sensorproc structure, needed for multisensor board to be able to replace some of the functions
+ * @param copy - pointer to a copy structure
+ * @return pointer to a copy structure
+ */
+
+struct sensorproc_t * copy_sensorproc (struct sensorproc_t * copy) {
+ memcpy(copy, sensorproc, sizeof(struct sensorproc_t)); /// copy sensor functions
+ return copy;
+}
+
+#ifdef TEST_DISABLE_CODE
+
+/// When should it be called?
+//int init_sensor(void);
+/// Not yet used??
+/**
+ * @brief Check FPGA version and initialize SDRAM (if not done yet)
+ * TODO: when should it be called?
+ * @return <0 error, 0 - just checked, nothing done,1 - needs sensor initialization
+ */
+int init_FPGA(void) { //will check FPGA version, init SDRAM (if needed) and sensor
+ int i;
+// int f1,f2;
+ // Should be initial
+ if ((fpga_state & FPGA_STATE_LOADED) == 0) return -1; /// fpga is not configured
+
+ if ((i=port_csp0_addr[X313__RA__MODEL]) < X313_MINMODREV) {
+ printk ("too old fpga rev - found %x, software wants >= %x\n",i,X313_MINMODREV);
+ return -1; // too old FPGA
+ }
+ if (i > X313_MAXMODREV) {
+ printk ("too new fpga rev - found %x, software wants <= %x\n",i,X313_MAXMODREV);
+ return -1; // too new FPGA
+ }
+ fpga_state |= FPGA_STATE_INITIALIZED; /// what this initialization really mean?
+
+ if (!X313_IS_SDRAM_ON) fpga_initSDRAM();
+// Was sensor initialized? (What if SDRAM was initialized by some application?)
+ MD1(printk("init_FPGA, fpga_state=0x%x\n",fpga_state));
+ if (X313_CHN0_USED!=0) return 0;
+ return 1;
+}
+
+///
+/// initializes structures for the image acquisition parameter
+/// initializes hardware i2c controller and the command sequencer (leaves them stopped to ignore any frame syncs)
+/// sets some default acquisition parameters
+/// Maybe - set up DMA also?
+/// TODO: Take care while turning off reset on i2c and cmd_sequencer so there will be no sensor vsync lost
+/// (easier to do in FPGA)
+/// Done:
+///#define CCAM_VSYNC_ON port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,0)
+///#define CCAM_VSYNC_OFF port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,1)
+///
+int init_acq_sensor(void);
+
+static int __init image_acq_init(void);
+
+DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); /// 0 - no arguments for now
+
+
+
+/**
+ * @brief reads FPGA transfer pointer to update JPEG_wp
+ * NOTE: should be called before compressor is reset - that would zero out that hardware register
+ * @return 0 if compressor was off (no advance), 1 if write pointer did actually advance
+ */
+inline int updateIRQJPEG_wp(void) {
+ int xferred; /// number of 32-byte chunks transferred since compressor was reset
+ int fpga_cntr= X313_XFERCNTR; /// using macro defined in x353.h that makes a dummy read (reads after writes can be wrong)
+ xferred= fpga_cntr-fpga_counter_prev; /// Transferred since last JPEG_wp update (or counter reset)
+#if 0 /// ELPHEL_DEBUG_THIS- address changed !!!
+ set_globalParam (0x300,get_globalParam (0x300)+1);
+ set_globalParam (0x302,fpga_cntr);
+ if (xferred==0) set_globalParam (0x305,get_globalParam (0x305)+1);
+#endif
+ if (xferred==0) return 0; /// no advance (compressor was off?)
+ fpga_counter_prev= fpga_cntr;
+ if (xferred <0) xferred+= (1 <<24) ; /// Hardware counter is 24 bits - rolled over
+ JPEG_wp+= (xferred << 3); //! counts in 32-byte ( 8 of 32bit words) chunks
+ int circbuf_size=get_globalParam (G_CIRCBUFSIZE)>>2; //G_CIRCBUFSIZE G_CIRCBUFRP
+ if (JPEG_wp > circbuf_size) JPEG_wp-=circbuf_size;
+#if 0 ///ELPHEL_DEBUG_THIS - address changed !!!
+ set_globalParam (0x301,get_globalParam (0x301)+1);
+ set_globalParam (0x303,xferred);
+ set_globalParam (0x304,JPEG_wp);
+#endif
+ return 1;
+}
+/**
+ * @brief Calculate/update CIRCBUF parameters available after compressor interrupt
+ */
+inline void updateIRQCircbuf(void) {
+ set_globalParam (G_CIRCBUFWP, JPEG_wp<<2);
+ set_globalParam (G_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
+ get_globalParam (G_CIRCBUFRP)) - get_globalParam (G_CIRCBUFWP));
+}
+
+/**
+ * @brief Calculate/update focus parameters available after compressor interrupt
+ * NOTE: currently global (latest), not per-frame
+ */
+inline void updateIRQFocus(void) {
+ set_globalParam (G_GFOCUS_VALUE, X313_HIGHFREQ);
+ set_imageParamsThis (P_FOCUS_VALUE, X313_HIGHFREQ);
+}
+
+
+
+/**
+ * @brief Locate area between frames in the circular buffer
+ * @return pointer to interframe parameters structure
+ */
+inline struct interframe_params_t* updateIRQ_interframe(void) {
+ int circbuf_size=get_globalParam (G_CIRCBUFSIZE)>>2;
+ int alen = JPEG_wp-9; if (alen<0) alen+=circbuf_size;
+ int jpeg_len=ccam_dma_buf_ptr[alen] & 0xffffff;
+ set_globalParam(G_FRAME_SIZE,jpeg_len);
+ int aframe_params=(alen & 0xfffffff8)-
+ (((jpeg_len + CCAM_MMAP_META + 3) & 0xffffffe0)>>2) /// multiple of 32-byte chunks to subtract
+ -8; /// size of the storage area to be filled before the frame
+ if(aframe_params < 0) aframe_params += circbuf_size;
+ struct interframe_params_t* interframe= (struct interframe_params_t*) &ccam_dma_buf_ptr[aframe_params];
+/// should we use memcpy as before here?
+ interframe->frame_length=jpeg_len;
+ interframe->signffff=0xffff;
+#if ELPHEL_DEBUG_THIS
+ set_globalParam (0x306,get_globalParam (0x306)+1);
+#endif
+
+ return interframe;
+}
+
+/**
+ * @brief Fill exif data with the current frame data, save pointer to Exif page in the interframe area
+ * @param interframe pointer to interframe parameters structure
+ */
+inline void updateIRQ_Exif(struct interframe_params_t* interframe) {
+ int index_time = JPEG_wp-11; if (index_time<0) index_time+=get_globalParam (G_CIRCBUFSIZE)>>2;
+/// calculates datetime([20] and subsec[7], returns pointer to char[27]
+ char * exif_meta_time_string=encode_time(ccam_dma_buf_ptr[index_time], ccam_dma_buf_ptr[index_time+1]);
+/// may be split in datetime/subsec - now it will not notice missing subseq field in template
+ write_meta_irq(exif_meta_time_string, &meta_offsets.Photo_DateTimeOriginal, Exif_Photo_DateTimeOriginal, 27);
+ write_meta_irq(exif_meta_time_string, &meta_offsets.Image_DateTime, Exif_Image_DateTime, 20); // may use 27 if room is provided
+ putlong_meta_irq(get_imageParamsThis(P_EXPOS), &meta_offsets.Photo_ExposureTime, Exif_Photo_ExposureTime);
+ putlong_meta_irq(get_imageParamsThis(P_FRAME), &meta_offsets.Image_FrameNumber, Exif_Image_FrameNumber);
+//Exif_Photo_MakerNote
+ int global_flips=(get_imageParamsThis(P_FLIPH) & 1) | ((get_imageParamsThis(P_FLIPV)<<1) & 2);
+ int extra_flips=0;
+ if (get_imageParamsThis(P_MULTI_MODE)!=0) {
+ extra_flips=get_imageParamsThis(P_MULTI_MODE_FLIPS);
+ global_flips=extra_flips & 3;
+ }
+/* unsigned char orientations[]={1,6,3,8,
+ 2,7,4,5,
+ 4,5,2,7,
+ 3,8,1,6};
+*/
+ unsigned char orientations[]="1638274545273816";
+
+
+ unsigned char orientation_short[2];
+ orientation_short[0]=0;
+ orientation_short[1]=0xf & orientations[(get_imageParamsThis(P_PORTRAIT)&3) | (global_flips<<2)];
+ write_meta_irq(orientation_short, &meta_offsets.Image_Orientation, Exif_Image_Orientation, 2);
+
+//TODO - use memcpy
+ int maker_offset;
+ maker_offset=putlong_meta_irq(get_imageParamsThis(P_GAINR), &meta_offsets.Photo_MakerNote, Exif_Photo_MakerNote);
+ if (maker_offset>0) {
+ putlong_meta_raw_irq(get_imageParamsThis(P_GAING), maker_offset+4);
+ putlong_meta_raw_irq(get_imageParamsThis(P_GAINGB), maker_offset+8);
+ putlong_meta_raw_irq(get_imageParamsThis(P_GAINB), maker_offset+12);
+ putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_R), maker_offset+16);
+ putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_G), maker_offset+20);
+ putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_GB), maker_offset+24);
+ putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_B), maker_offset+28);
+ putlong_meta_raw_irq(get_imageParamsThis(P_WOI_LEFT) | (get_imageParamsThis(P_WOI_WIDTH)<<16), maker_offset+32);
+ putlong_meta_raw_irq(get_imageParamsThis(P_WOI_TOP) | (get_imageParamsThis(P_WOI_HEIGHT)<<16), maker_offset+36);
+ putlong_meta_raw_irq( global_flips |
+ ((get_imageParamsThis(P_BAYER)<<2) & 0xc) |
+ ((get_imageParamsThis(P_COLOR)<<4) & 0xF0) |
+ ((get_imageParamsThis(P_DCM_HOR)<<8) & 0xF00) |
+ ((get_imageParamsThis(P_DCM_VERT)<<12) & 0xF000) |
+ ((get_imageParamsThis(P_BIN_HOR)<<16) & 0xF0000) |
+ ((get_imageParamsThis(P_BIN_VERT)<<20) & 0xF00000) |
+ (extra_flips <<24) , maker_offset+40);
+ putlong_meta_raw_irq(get_imageParamsThis(P_MULTI_HEIGHT_BLANK1), maker_offset+44);
+ putlong_meta_raw_irq(get_imageParamsThis(P_MULTI_HEIGHT_BLANK2), maker_offset+48);
+// putlong_meta_raw_irq(0x1234567, maker_offset+52); // just testing
+ putlong_meta_raw_irq(get_imageParamsThis(P_QUALITY) | ((get_imageParamsThis(P_PORTRAIT)&1)<<7) | (get_imageParamsThis(P_CORING_INDEX)<<16), maker_offset+52);
+ putlong_meta_raw_irq(get_globalParam(G_TEMPERATURE01), maker_offset+56); // data should be provided by a running daemon
+ putlong_meta_raw_irq(get_globalParam(G_TEMPERATURE23), maker_offset+60);
+//get_globalParam(G_TASKLET_CTL)
+// left 1 long spare (+44)
+ }
+ interframe->meta_index=store_meta();
+}
+
+
+/**
+ * @brief hardware IRQ service
+ * most urgent tasks
+ * @param irq
+ * @param dev_id
+ * @return
+ */
+static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
+ unsigned long irq_state;
+
+ irq_state = X313_IRQSTATE; //!making dummy read - see c353.h
+ DIS_INTERRUPTS;
+ PROFILE_NEXT(0);
+/// read hardware write pointer (will only advance if compression was on)
+///find out if compressor was running and update pointers, exif, ...?
+ if (updateIRQJPEG_wp()) { ///also fills P_FRAME ahead
+ updateIRQCircbuf();
+ updateIRQFocus(); ///NOTE: currently global (latest), not per-frame
+ struct interframe_params_t* interframe= updateIRQ_interframe(); /// fills jpeg_len, signffff
+/// should we use memcpy as before here?
+// interframe->frame_length=jpeg_len;
+// interframe->signffff=0xffff;
+ updateIRQ_Exif(interframe);
+ updateFramePars(X3X3_I2C_FRAME, interframe);
+ wake_up_interruptible(&circbuf_wait_queue); /// only when frame is acquired
+ } else {
+ updateFramePars(X3X3_I2C_FRAME, NULL);
+ }
+ PROFILE_NOW(1);
+ wake_up_interruptible(&framepars_wait_queue); /// all interrupts, not just frames acquired
+ tasklet_schedule(&tasklet_fpga); /// trigger software interrupt
+
+ EN_INTERRUPT(SMART);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * @brief Tasklet - software interrupt
+ * lower priority tasks
+ * try to implement some balancing - if job is not finished - reduce FPS for it (alternate jobs)?
+ * @param arg not used
+ */
+
+/*!TODO:
+
+implement 2 modes of controlling when to calculate histograms:
+1 - add mask to 3 frame number LSB (i.e. - 0/10000000/10001000/10101010/11111111) - 3 contol bits - en/dis and mode
+2 - requested in advance (i.e. by autoexposure when writing new exposure or white balance - when writing balance
+
+mode 1 will provide easy way to display histograms (no need to repetively request them),
+mode 2 - useful for autoexposure
+
+Modify waiting (LSEEK_*) for histogrames so they will only unfreeze if the histogram is available (skipping multiple frames))
+For displaying histograms - try use latest available - not waiting fro a particular frame.
+
+
+*/
+
+/// HISTOGRAMS_WAKEUP_ALWAYS if 0 will only wakeup processes waiting for histograms when they become available, maybe never if they are disabled
+/// if defined 1 - will wakeup each frame, regardless of the availability of the histograms
+//#define HISTOGRAMS_WAKEUP_ALWAYS 0
+void tasklet_fpga_function(unsigned long arg) {
+ int hist_en;
+ int tasklet_disable=get_globalParam(G_TASKLET_CTL);
+ unsigned long thisFrameNumber=getThisFrameNumber();
+ unsigned long prevFrameNumber=thisFrameNumber-1;
+ unsigned long * hash32p=&(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]);
+ unsigned long * framep= &(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
+/// Time is out?
+ if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
+/// Histograms are available for the previous frame (that is already in circbuf if compressor was running)
+/// Is Y histogram needed?
+ PROFILE_NOW(2);
+ switch ((tasklet_disable >> TASKLET_CTL_HISTY_BIT) & 7) {
+ case TASKLET_HIST_NEVER: /// never calculate
+ hist_en=0;
+ break;
+ case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8)
+ hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<> TASKLET_CTL_HISTC_BIT) & 7) {
+ case TASKLET_HIST_NEVER: /// never calculate
+ hist_en=0;
+ break;
+ case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8)
+ hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<.");
+MODULE_DESCRIPTION(X3X3_IMAGEACQ_DRIVER_NAME);
diff --git a/src/drivers/elphel/sensor_common.h b/src/drivers/elphel/sensor_common.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea9c1c04ad03d714cc43b09747e0bdd5ccaf31aa
--- /dev/null
+++ b/src/drivers/elphel/sensor_common.h
@@ -0,0 +1,45 @@
+#ifndef _SENSOR_COMMON_H
+#define _SENSOR_COMMON_H
+
+//extern struct sensor_t sensor; // current sensor (will be copied to by sensor driver), made external for the cc353.c to read/write i2c
+extern struct sensorproc_t * sensorproc;
+/// IRQ-safe "nice" FPGA table write and histogram read functions - they split the data in chunks of fixed size,
+/// disable IRQ, transfer a chunk, then reenable interrupt before proceedg to the next chunk
+#define FPGA_TABLE_CHUNK 64 // up to 64 words to send to the table/from histogram on a single IRQ-off transfer
+//void fpga_table_write_nice (int addr, int len, unsigned long * data);
+//void fpga_hist_read_nice (int addr, int len, unsigned long * data);
+#ifdef CONFIG_ETRAX_ELPHEL_MT9X001
+ #include "mt9x001.h"
+#endif
+//#include "multisensor.h"
+int camSeqGetJPEG_wp(void);
+int camSeqGetJPEG_rp(void);
+void camSeqSetJPEG_rp(int p);
+///CIRCBUF macros
+extern unsigned long * ccam_dma_buf_ptr;
+#define X313_LENGTH_MASK 0xff000000
+#define X313_PADDED_FRAME(x)((((x)+67+CCAM_MMAP_META ) >>2) & 0xfffffff8)
+#define X313_BUFFSUB(x,y) (((x)>=(y))? ((x)-(y)) : ((x)+ (CCAM_DMA_SIZE-(y))))
+#define X313_BUFFADD(x,y) ((((x) + (y))<=CCAM_DMA_SIZE)? ((x) + (y)) : ((x) - (CCAM_DMA_SIZE-(y))))
+
+//int init_FPGA(void); /// can be initialized only after FPGA is configured, not at module init (NOTE was static??)
+///can be verified with if (!X313_IS_SDRAM_ON)
+void reset_compressor(void);
+void camera_interrupts (int on);
+struct sensorproc_t * copy_sensorproc (struct sensorproc_t * copy);
+
+///NOTE: If profiling is enabled (TASKLET_CTL_ENPROF is set in G_TASKLET_CTL) - save current time in 2 of the 32-bit locations that can be read as pastpars (i.e. from PHP)
+#ifdef TEST_DISABLE_CODE
+ #define PROFILE_NOW(x) if (get_globalParam(G_TASKLET_CTL) & (1 << TASKLET_CTL_ENPROF)) \
+ X313_GET_FPGA_TIME((pastpars[getThisFrameNumber() & PASTPARS_SAVE_ENTRIES_MASK].past_pars[(PP_PROFILE_START + 0) + ((x)<<1)]),\
+ (pastpars[getThisFrameNumber() & PASTPARS_SAVE_ENTRIES_MASK].past_pars[(PP_PROFILE_START + 1) + ((x)<<1)]))
+ ///Put this to the next frame's data (before thisFrameNumber was incremented)
+ #define PROFILE_NEXT(x) if (get_globalParam(G_TASKLET_CTL) & (1 << TASKLET_CTL_ENPROF)) \
+ X313_GET_FPGA_TIME((pastpars[(getThisFrameNumber()+1) & PASTPARS_SAVE_ENTRIES_MASK].past_pars[(PP_PROFILE_START + 0) + ((x)<<1)]),\
+ (pastpars[(getThisFrameNumber()+1) & PASTPARS_SAVE_ENTRIES_MASK].past_pars[(PP_PROFILE_START + 1) + ((x)<<1)]))
+#else
+ #define PROFILE_NOW(x) {}
+ #define PROFILE_NEXT(x) {}
+#endif
+
+#endif
diff --git a/src/include/elphel/c313a.h b/src/include/elphel/c313a.h
new file mode 100644
index 0000000000000000000000000000000000000000..32bafcb7e09507897cac5caedc65c537899246cb
--- /dev/null
+++ b/src/include/elphel/c313a.h
@@ -0,0 +1,1930 @@
+/*
+ * 05.03.2002 changing for revA
+ * 03.19.2002 Started support for different sensors
+ */
+
+#ifndef _ASM_CMOSCAM_H
+#define _ASM_CMOSCAM_H
+#define SAFE_CHECK 1 // perform more verification on the paremeters
+//#define ELPHEL_DEBUG 0 //global debug on/off in multiple files
+//#define ELPHEL_DEBUG_STARTUP 000a4c00 ;
+//#define ELPHEL_DEBUG_STARTUP 0 ; // removed - add write to fpga init script
+//#define ELPHEL_DEBUG 0 //global debug on/off in multiple files
+#define ELPHEL_DEBUG 1 //global debug on/off in multiple files
+#define ELPHEL_DEBUG_DELAY 100000 //delay after some printk-s
+#define ELP_KERR(x) printk("%s:%d:%s: ERROR ",__FILE__,__LINE__,__FUNCTION__);x
+#define ELP_FERR(x) fprintf(stderr,"%s:%d:%s: ERROR ",__FILE__,__LINE__,__FUNCTION__);x
+
+#define USELONGLONG 1
+#define ETRAXFS_MMAP_CACHE_BUG y
+
+
+#if ELPHEL_DEBUG
+ #define EDBG(x) x
+#else
+ #define EDBG(x)
+#endif
+
+
+
+// _IOC_TYPE, bits 8 to 15 in ioctl cmd
+
+#define CMOSCAM_IOCTYPE 124
+
+/* new i2c devices */
+// minors (add more later - maybe different minors for different speed - set speed when opening)
+#define X3X3_I2C_CTRL 0 // control/reset i2c
+#define X3X3_I2C_8_AINC 1 // 8bit registers, autoincement while read/write
+#define X3X3_I2C_16_AINC 2 // 16bit registers, autoincement while read/write
+#define X3X3_I2C1_8_AINC 3 // 8bit registers, autoincement while read/write (bus 1)
+#define X3X3_I2C1_16_AINC 4 // 16bit registers, autoincement while read/write (bus 1)
+#define X3X3_I2C_RAW 5 // 8bit registers, no address byte (just slave, then read/write byte(s)
+#define X3X3_I2C1_RAW 6 // 8bit registers, no address byte (just slave, then read/write byte(s)
+#define X3X3_I2C_ENABLE 7 // enable(/protect) different I2C devices for different types of I2C accesses
+#define X3X3_I2C_ENABLE_RD 0 // bit 0 - enable i2c read
+#define X3X3_I2C_ENABLE_WR 1 // bit 1 - enable i2c write
+#define X3X3_I2C_ENABLE_RAW 2 // bit 2 - enable i2c raw (no address byte)
+#define X3X3_I2C_ENABLE_8 3 // bit 3 - enable i2c 8-bit registers access
+#define X3X3_I2C_ENABLE_16 4 // bit 4 - enable i2c 16-bit registers access
+#define X3X3_I2C_MAXMINOR 7 //
+#define X3X3_I2C_CHANNELS 2 // number of i2c channels
+//xi2craw c 134 5
+//xi2craw_aux c 134 6
+//xi2cenable c 134 7
+
+#define FPGA_DCM_STEP 22 // ps/step
+#define FPGA_DCM_RANGE 250 // maximal phase correction (+/-) ?
+/* camera sequencer states */
+
+
+
+///Obsolete
+#define CAMSEQ_OFF 0 // off, not programmed (Video mode off on Zoran sensors)
+#define CAMSEQ_READY 1 // sensor programmed may acquire at will (programSensor sets number of frames to skip (if any)
+#define CAMSEQ_SKIP 2 // skipping specified number of frames, interrupt service routine counts and will start acquisition
+#define CAMSEQ_WAIT_F 3 // set by "start exposure" or interrupt service routine. WAIT_F/WAIT_T/acquire/done differs by hardware register
+#define CAMSEQ_WAIT_T 4 // set by "start exposure" or interrupt service routine. Wait/acquire/done differs by hardware register
+#define CAMSEQ_ACQUIRE 5 // acquisition in progress (camSeqState is still CAMSEQ_WAIT)
+#define CAMSEQ_DONE 6 // acquisition over (camSeqState is still CAMSEQ_WAIT)
+#define CAMSEQ_JPEG 7 // waiting for JPEG done interrupt, acquiring/compressing some frames
+
+#define CAMSEQ_RUN 8 // compressor is constantly running (but if camSeqCount>0 - just skipping "bad" frames)
+#define CAMSEQ_STOP 9 // compressor is constantly running but will stop after next "compressor ready"
+#define CAMSEQ_SINGLE 10 // compressor is constantly running to fill one full buffer
+// For KAI11000 sensor board
+#define sensorcom_W_size 1024
+#define sensorcom_R_size 256
+
+/* MCP definitions */
+
+#define MCP_W_size 1024
+#define MCP_R_size 256
+
+#define MCPOtherBits 0xffa7a7ff
+#define MCPOffReset 0x00101800
+#define MCPReset 0x00001800
+#define MCPNoReset 0x00105800
+#define MCPToggleA 0x00080000
+#define MCPToggleB 0x00001000
+#define MCPctlseq 0x00
+#define MCPsofttg 0x02
+#define MCPeackn 0x03
+#define MCPctlgate 0x04
+#define MCPwstdly 0x06
+#define MCPwrsmsk 0x07
+#define MCPwrsup 0x08
+#define MCPwrmons 0x09
+#define MCPwnom 0x0a
+#define MCPwdenom 0x0b
+#define MCPwoutw 0x0c
+#define MCPwinvctl 0x0d
+#define MCPctlsync 0x0e
+#define MCPwrdlys 0x10
+#define MCPwinv 0x40
+#define MCPwshared 0x80
+#define MCPwrsynctb 0x100
+#define MCPwrseq 0x200
+
+
+/* supported ioctl _IOC_NR's */
+#ifndef I2C_WRITEARG
+ #define I2C_WRITEARG(bus, slave, reg, value) (((bus) << 24) | ((slave) << 16) | ((reg) << 8) | (value))
+ #define I2C_READARG(bus, slave, reg) (((bus) << 24) | ((slave) << 16) | ((reg) << 8))
+
+ #define I2C_ARGBUS(arg) (((arg) >> 24) & 0x1)
+ #define I2C_ARGSLAVE(arg) (((arg) >> 16) & 0xff)
+ #define I2C_ARGREG(arg) (((arg) >> 8) & 0xff)
+ #define I2C_ARGVALUE(arg) ((arg) & 0xff)
+
+ #define I2C_DELAYS 0x0 // read/write bit deleys for I2C
+// return delays, if data==0 - don't change, just read
+// lower (0) byte - SCL high,
+// byte 1 - SCL low
+// byte 2 - slave -> master (from slave driving SDA line to master driving SDA)
+// byte 3 - master -> slave (from master driving SDA line to slave driving SDA)
+
+ #define I2C_WRITEREG 0x1 // write to an i2c register
+ #define I2C_READREG 0x2 // read from an i2c register
+#endif
+
+// new for Micron sensors - 16bit data, always bus 0
+#ifndef I2C_16_WRITEARG
+ #define I2C_16_WRITEREG 0x3 // write 2 bytes to an i2c register
+ #define I2C_16_READREG 0x4 // read 2 bytes from an i2c register
+
+ #define I2C_16_WRITEARG(slave, reg, value) (((slave) << 24) | ((reg) << 16) | (value))
+ #define I2C_16_READARG(slave, reg) (((slave) << 24) | ((reg) << 16))
+
+ #define I2C_16_ARGSLAVE(arg) (((arg) >> 24) & 0xff)
+ #define I2C_16_ARGREG(arg) (((arg) >> 16) & 0xff)
+ #define I2C_16_ARGVALUE(arg) ( (arg) & 0xffff)
+ #define I2C_16_ARGVALUE_H(arg) (((arg) >> 8) & 0xff)
+ #define I2C_16_ARGVALUE_L(arg) ( (arg) & 0xff)
+#endif
+
+
+
+// otherParamsRO[16]
+
+#define _CCCMD(x,y) (_IO(CMOSCAM_IOCTYPE, (x << 6) | (y & 0x3f)))
+
+
+
+#define CCAM_CTRL(x) ((_IOC_NR(x) >> 6) & 0x03)
+#define CCAM_ADDR(x) (_IOC_NR(x) & 0x3f)
+
+//#define CCAM_RWSENSOR 1 /* direct read/write first 32 sensor registers */ // will not use at all
+#define CCAM_RPARS 2 /* read parameters 0..0x3f */
+#define CCAM_WPARS 3 /* write parameters 0..0x3f */
+
+/* New parameters and update logic
+ * Separate read and write set of 64 registers
+ * User may specify:
+ * 0 - do not update
+ * 1 - update at once
+ * 2 - update when appropriate
+ * and read update status:
+ * 0 - will not be updated
+ * 1 - in sync
+ * 2 - waiting to be updated
+ * 3 - update in progress (TODO: - support async)
+ * When updating (validating) parameters and copying them to the read "registers" the I2C registers will be written
+ * only if they are different from the shadows
+ */
+/// parameter indexes will be updated to grouprelated ones into the same groups of 32
+/// NOTE: P_* and G_* should not end with numbers - numbers will be used in PHP constants to add to the constant value (ELPHEL_AAA3 will be treated as ELPHEL_AAA+3)
+#define P_NUMBER 1024 //number of registers (was 64) - NOTE: obsolete?
+#define P_SENSOR 1 /* if set to 0 - will (re)detect sensor. If set to None - won't bother
+ 4 - ZR32112MLC - now there is no way to see color/mono
+ 5 - ZR32112PLC
+ 8 - ZR32212MLC
+ 9 - ZR32112PLC
+ 32 - KAC1310-mono
+ 33 - KAC1310-RGB
+ 34 - KAC1310-CMY
+ 36 - KAC5000
+ 48 - MI1300
+ 49 - MT9M001 (1280x1024,same as MI1300)
+ 50 - MT9M001 (1600x1200)
+ 51 - MT9T001 (2048*1536)
+ 52 - MT9P001 (2592*1944)
+ 64 - IBIS5-1300*/
+
+// leave it here - may be used in user applications
+#define SENSOR_MASK 0xfc
+#define SENSOR_ZR32112 0x04
+#define SENSOR_ZR32212 0x08
+#define SENSOR_KAC1310 0x20
+#define SENSOR_KAC5000 0x24
+#define SENSOR_MI1300 0x30
+#define SENSOR_MT9X001 0x30 // MT9M001 - 31, MT9D001 - 32, MT9T001 - 33, MT9P001 - 34
+#define SENSOR_MT9Y001 0x34 // MT9P001 - 34
+#define SENSOR_IBIS51300 0x40
+#define SENSOR_KAI11000 0x80
+#define SENSOR_NONE 0xfc
+
+// sensor sizes:
+//#define SENSORWIDTH_ZR32112 1288
+//#define SENSORHEIGHT_ZR32112 1032
+#define SENSORWIDTH_ZR32112 1280
+#define SENSORHEIGHT_ZR32112 1024
+//#define SENSORWIDTH_ZR32212 1288
+#define SENSORWIDTH_ZR32212 1280
+#define SENSORHEIGHT_ZR32212 968
+#define SENSORWIDTH_KAC1310 1280
+#define SENSORHEIGHT_KAC1310 1024
+//#define SENSORWIDTH_KAC1310 1296
+//#define SENSORHEIGHT_KAC1310 1046
+#define SENSORWIDTH_MI1300 1280
+#define SENSORHEIGHT_MI1300 1024
+
+#define SENSORWIDTH_MT9M001 1280
+#define SENSORHEIGHT_MT9M001 1024
+#define SENSORWIDTH_MT9D001 1600
+#define SENSORHEIGHT_MT9D001 1200
+#define SENSORWIDTH_MT9T001 2048
+#define SENSORHEIGHT_MT9T001 1536
+#define SENSORWIDTH_MT9P001 2592
+#define SENSORHEIGHT_MT9P001 1944
+
+#define SENSORWIDTH_KAC5000 2592
+#define SENSORHEIGHT_KAC5000 1944
+
+
+#define SENSORWIDTH_IBIS51300 1280
+#define SENSORHEIGHT_IBIS51300 1024
+/// Parameters related to multi-sensor (10359A) setup
+#define MAX_SENSORS 3 // maximal number of sensor attached (modify some hard-wired constants below if this to be changed)
+//! Parameters below are accessed through mmap, because of cache coherency problem it make sense to keep them compact (maybe group by 8 - cache line of 32 bytes)
+#define P_SENSOR_RUN 4 // 0 - stop, 1 - single, 2 - run
+ #define SENSOR_RUN_STOP 0
+ #define SENSOR_RUN_SINGLE 1
+ #define SENSOR_RUN_CONT 2
+#define P_COMPRESSOR_RUN 5 // 0 - stop, 1 - single, 2 - run
+ #define COMPRESSOR_RUN_STOP 0
+ #define COMPRESSOR_RUN_SINGLE 1
+ #define COMPRESSOR_RUN_CONT 2
+
+#define P_BAYER 6 // filter number at (0,0) 0-R, 1-G(R), 2-G(B), 3 - B. Write enabled at first, move to WindowSize later
+#define P_TRIGGERED 7 // when trigger occured - 4 LSBs - pixel in DMA word, higher bits - number of DMA word OBSOLETE
+#define P_PERIOD 8 // Frame period in pixel clocks (read only)
+#define P_FP1000SLIM 9 // FPS limit, frames per 1000 sec
+#define P_FPSFLAGS 10 // FPS limit mode - bit 0 - limit fps (not higher than), bit 1 - maintain fps (not lower than)
+
+#define P_JPEG_WP 11 // Last reported JPEG write pointer in the circular buffer. ** OBSOLETE
+ //! In new code use G_CIRCBUFWP instead!
+#define P_CLK_FPGA 12 // FPGA clock in MHz
+#define P_CLK_SENSOR 13 // Sensor clock in MHz
+#define P_FPGA_XTRA 14 // Extra cycles needed to compressor (probably constant...)
+#define P_TRIG 15 /// External trigger mode
+ /// bit 0 - "old" external mode (0- internal, 1 - external )
+ /// bit 1 - enable(1) or disable(0) external trigger to stop clip
+ /// bit 2 - async (snapshot, ext trigger) mode, 0 - continuous NOTE: Only this bit is used now !
+ /// bit 3 - no overlap, single frames: program - acquire/compress same frame
+#define P_BGFRAME 16 // Background measurement mode - will use 16-bit mode and no FPN correction
+
+#define P_IMGSZMEM 17 // image size in video memory (calculated when channel 0 is programmed)
+
+
+// image page numbers depend on image size/pixel depth, so changing any of them will invalidate all pages
+#define P_PAGE_ACQ 18 // Number of image page buffer to acquire to (0.1?)
+#define P_PAGE_READ 19 // Number of image page buffer to read from to (0.1?)
+
+#define P_OVERLAP 20 // number of EXRA lines to be acquired - probably dead,
+
+#define P_VIRT_KEEP 21 // 0 - recalculate P_VIRT_WIDTH, P_VIRT_HEIGHT when window is changed, 1 - keep those parameters
+#define P_VIRT_WIDTH 22 // Virtual window width
+#define P_VIRT_HEIGHT 23 // Virtual window height
+#define P_WOI_LEFT 24 // WOI left corner (before applying decimation)
+#define P_WOI_TOP 25 // WOI top corner
+#define P_WOI_WIDTH 26 // WOI width
+#define P_WOI_HEIGHT 27 // WOI height
+
+#define P_FLIPH 28 // bit 0 horizontal flip
+#define P_FLIPV 29 // bit 0 vertical flip
+
+#define P_DCM_HOR 30 /* Horizontal decimation (1/2/4/8) */
+#define P_DCM_VERT 31 /* Vertical decimation (1/2/4/8) copied from horizontal for Zoran chips */
+#define P_BIN_HOR 32 /* binning 1/2 - KAC1310 only - now for mt9t001 */
+#define P_BIN_VERT 33 /* not used yet binning 1/2 - KAC1310 only - now for mt9t001*/
+#define P_FPGATEST 34 // FPGA test modes (now - just one)
+
+#define P_FRAMESYNC_DLY 35 /* maybe - temporary - delay of frame sync (vacts) by number of scan lines - for photofinish mode*/
+
+#define P_PF_HEIGHT 36 /*height of each strip in photofinish mode - normally 2 lines */
+ /*also now includes timestamping mode +0x10000 - for normal frames, 0x20000 - for photo-finish */
+
+#define P_BITS 37 /* pixel depth - bits 10/8/4 */
+
+#define P_SHIFTL 38 /* "digital gain" - shift left by 0/1/2 bits (3 ->-1)*/
+#define P_FPNS 39 // FPN correction mode (subtract) 0..3
+ // 0-none, 1 - fine(25%), 2 - 50%, 3 - coarse(100%)
+#define P_FPNM 40 // FPN correction mode (multiply) 0..3
+ // 0-none, 1 - fine(+/-12.5%), 2 - medium (+/-25%), +3 - coarse(+/-50%)
+#define P_TESTSENSOR 41 // sensor test mode(s) 0x10000 - enable, lower bits - test mode
+#define P_VIRTTRIG 42 // Sum of pixels in a line greater than this value - trigger acquisition
+
+#define P_PERIOD_MIN 43 // (readonly) minimal frame period (in pixel clocks) limited by user or compressor
+#define P_PERIOD_MAX 44 // (readonly) frame period (in pixel clocks) limited by user
+#define P_SENSOR_PIXH 45 // (readonly) pixels to be read from the sensor, horizontal (incliding margins, excluding embedded timestamps). In multisesnor applies to the whole frame
+#define P_SENSOR_PIXV 46 // (readonly) pixels to be read from the sensor, vertical (incliding margins)
+#define P_FATZERO 47 // subtract while adding data from to consequitive frames (async trigger)
+
+#define P_COMPMOD_TILSH 48
+#define P_COMPMOD_DCSUB 49
+#define P_COMPMOD_QTAB 50 // to be written not directly, but by pgm_quality ?
+
+#define P_FP1000S 51 // Frames per 1000 sec (fps * 1000)
+#define P_SENSOR_WIDTH 52
+#define P_SENSOR_HEIGHT 53
+#define P_COLOR_SATURATION_BLUE 54 // 100*realtive saturation blue - preserve?
+#define P_COLOR_SATURATION_RED 55 // 100*realtive saturation red
+
+/// Vignetting control, AX*X^2+BX*X+AY*Y^2+BY*Y+C
+#define P_VIGNET_AX 56
+#define P_VIGNET_AY 57
+#define P_VIGNET_BX 58
+#define P_VIGNET_BY 59
+#define P_VIGNET_C 60 /// nominal 0x8000
+#define P_VIGNET_SHL 61 /// shift left color_coeff*vign_correction. 0..7, default=1 (up to 4x color correction* vignetting correction)
+#define P_SCALE_ZERO_IN 62 /// signed 16 bit - subtract from pixel 16-bit data before multiplication
+#define P_SCALE_ZERO_OUT 63 /// signed 16 bit - add after correction
+/// "digital gains" for color correction, 17-bit unsigned data (default 0x8000).
+#define P_DGAINR 64
+#define P_DGAING 65
+#define P_DGAINGB 66
+#define P_DGAINB 67
+
+#define P_RSCALE_ALL 68 /// bits 0..29: Ratio of [P_GAINR]/[P_GAING] or one of special, bit 30 - recalculate(self cleaning), bit 31 - ignore
+#define P_GSCALE_ALL 69
+#define P_BSCALE_ALL 70
+#define CSCALES_WIDTH 28
+#define CSCALES_CTL_BIT 28
+#define CSCALES_CTL_WIDTH 2
+/// commands to be written to P_*SCALE_CTL
+#define CSCALES_CTL_NORMAL 0 /// USE P_*SCALE as is
+#define CSCALES_CTL_RECALC 1 /// Recalculate P_*SCALE from P_GAIN*, P_GAING, then use it (will change to CSCALES_CTL_NORMAL when applied)
+#define CSCALES_CTL_FOLLOW 2 /// Don't apply P_*SCALE to P_GAIN*, but update it from the current P_*SCALE from P_GAIN*/P_GAING
+#define CSCALES_CTL_DISABLE 3 /// Disable P_*SCALE - don't apply P_*SCALE to P_GAIN*, don't update P_*SCALE from P_GAIN*, P_GAING
+
+
+#define P_CORING_PAGE 71 // zero bin + ((rounding add) << 8) 8-bit JPEG quantizer zero bin size, fractional addition to absolute value before truncating
+#define P_HISTRQ 72 // per-frame enabling of histogram calculation - bit 0 - Y (G), bit 2 - C (R,G2,B)
+#define P_TILES 73 // Number of 16x16 (20x20) tiles in a compressed frame
+#define P_SENSOR_PHASE 74 // packed, low 16 bit - signed fine phase, bits [18:17] - 90-degrees shift
+
+#define P_TEMPERATURE_PERIOD 75 // period of temperature measurements, ms (normally - multiple seconds)
+
+#define P_AUTOEXP_ON 76 // unsigned long on;
+
+/// relative histogram (autoexposure) window (changed from % to 1/0x10000)
+#define P_HISTWND_RWIDTH 77 // unsigned long width (%)->relative (0x10000 - 1.0);
+#define P_HISTWND_RHEIGHT 78 //unsigned long height (%);
+#define P_HISTWND_RLEFT 79 // unsigned long left (%);
+#define P_HISTWND_RTOP 80 // unsigned long top (%);
+
+/// Are these used anywhere now? ...P_AUTOEXP_SKIP_T
+#define P_AUTOEXP_EXP_MAX 81 //unsigned long exp_max; /* 100 usec == 1 etc... */
+#define P_AUTOEXP_OVEREXP_MAX 82 // unsigned long overexp_max; /* percentages for overexposured pixels - 1% == 100, 5% == 500, 0.02% == 2 etc... */
+#define P_AUTOEXP_S_PERCENT 83 // unsigned long s_percent;(controlling that % of pixels that should have value greater than S_INDEX - below)
+#define P_AUTOEXP_S_INDEX 84 // unsigned long s_index; Specified number of pixels (S_PERCENT) should have value above S_INDEX
+#define P_AUTOEXP_EXP 85 // unsigned long exp; Current exposure time
+#define P_AUTOEXP_SKIP_PMIN 86 // unsigned long skip_pmin; /* percent of delta for skip changes: 1% == 100 */ - no exposure corrections if the desired change is less than that
+#define P_AUTOEXP_SKIP_PMAX 87 // unsigned long skip_pmax; /* percent of changes for wait one frame before apply changes: 1% == 100 */ - do not apply chnanges if they are to big - wait for the next frame
+#define P_AUTOEXP_SKIP_T 88 // unsigned long skip_t; /* time for skip changes: 100 usec == 1 */ Not quite sure what it is
+
+///same as written to the FPGA for the histogram window
+#define P_HISTWND_WIDTH 89 // autoexposure window width (pixels)
+#define P_HISTWND_HEIGHT 90 // autoexposure window height (pixels)
+#define P_HISTWND_TOP 91 // autoexposure window top (pixels)
+#define P_HISTWND_LEFT 92 // autoexposure window left (pixels)
+
+#define P_FOCUS_SHOW 93 // show focus information instead of/combined with the image:
+ // 0 - regular image, 1 - block focus instead of Y DC (AC=0), 2 - image Y DC combined all frame, 3 combined in WOI
+#define P_FOCUS_SHOW1 94 // Additional parameter that modifies visualization mode. Currently just a single bit (how much to add)
+
+#define P_FOCUS_LEFT 96 // focus WOI left margin, inclusive (3 LSB will be zeroed as it should be multiple of 8x8 block width)
+#define P_FOCUS_WIDTH 97 // focus WOI width (3 LSB will be zeroed as it should be multiple of 8x8 block width)
+#define P_FOCUS_TOP 98 // focus WOI top margin, inclusive (3 LSB will be zeroed as it should be multiple of 8x8 block height)
+#define P_FOCUS_HEIGHT 99 // focus WOI height (3 LSB will be zeroed as it should be multiple of 8x8 block height)
+#define P_FOCUS_TOTWIDTH 100 // (readonly) - total width of the image frame in pixels
+#define P_FOCUS_FILTER 101 // select 8x8 filter used for the focus calculation (same order as quantization coefficients), 0..14
+
+//!timing generator/trigger delay/external trigger control
+
+#define P_TRIG_CONDITION 102 // trigger condition, 0 - internal, else dibits ((use<<1) | level) for each GPIO[11:0] pin
+#define P_TRIG_DELAY 103 // trigger delay, 32 bits in pixel clocks
+#define P_TRIG_OUT 104 // trigger output to GPIO, dibits ((use << 1) | level_when_active). Bit 24 - test mode, when GPIO[11:10] are controlled by other internal signals
+#define P_TRIG_PERIOD 105 // output sync period (32 bits, in pixel clocks). 0- stop. 1..256 - single, >=256 repetitive with specified period.
+#define P_TRIG_BITLENGTH 106 // bit length minus 1 (in pixel clock cycles) when transmitting/receiving timestamps. Legal values 2..255
+
+#define P_TRIG_BITLENGTH_DEFAULT 31 // P_TRIG_BITLENGTH default value
+
+
+#define P_SKIP_FRAMES 107 // number of frames to skip after restarting sensor+compressor - now zero/nonzero?
+#define P_I2C_QPERIOD 108 // number of system clock periods in 1/4 of i2c SCL period to the sensor/sensor board
+#define P_I2C_BYTES 109 // number of bytes in hardware i2c write (after slave addr) -0/1/2
+#define P_IRQ_SMART 110 // "smart" IRQ modes: +1 - wait for VACT in early compressor_done, +2 - wait for dma fifo ready
+ /// Currently bit 0 will be always 1 (needs fix in FPGA)
+#define P_EXTERN_TIMESTAMP 111 // Use external timestamp (received with sync) when availabele, 0 - always use local timestamp
+#define P_OVERSIZE 112 // ignore sensor dimensions, use absolute WOI_LEFT, WOI_TOP
+#define P_XMIT_TIMESTAMP 113 // 0 - transmit just sync pulse, 1 - pulse+timestamp over the sync line
+//#define P_VALID 113 // frame parameters valid (all needed parameters written in time, smth. else)
+//#define P_QTABLE 114 // number of quantization table used (0..7)
+#define P_CORING_INDEX 114 // MSW - color coring index (if 0 - use LSW), LSW - Y coring index. Currently 1 step is 1/10 of the pre-quantized DCT
+ // coefficient, maximum of 10. For the same filtering effect it should be higher for higher JPEG quality
+#define P_RFOCUS_LEFT 115 // relative (0x10000 - 1.0) focus WOI left margin, inclusive (3 LSB will be zeroed as it should be multiple of 8x8 block width)
+#define P_RFOCUS_WIDTH 116 // relative (0x10000 - 1.0)focus WOI width (3 LSB will be zeroed as it should be multiple of 8x8 block width)
+#define P_RFOCUS_TOP 117 // relative (0x10000 - 1.0)focus WOI top margin, inclusive (3 LSB will be zeroed as it should be multiple of 8x8 block height)
+#define P_RFOCUS_HEIGHT 118 // relative (0x10000 - 1.0)focus WOI height (3 LSB will be zeroed as it should be multiple of 8x8 block height)
+
+#define P_SDRAM_CHN20 125 // data to be written to the SDRAM CH2 REG 0 (last moment)
+#define P_SDRAM_CHN21 126 // data to be written to the SDRAM CH2 REG 1
+#define P_SDRAM_CHN22 127 // data to be written to the SDRAM CH2 REG 2
+
+
+/// The following 4 parameters should have consecutive indexes
+/// see FRAMEPAIR_MASK_BYTES to modify just part of the word (i.e. scale, not hash16
+#define P_GTAB_R 128 // combines (P_PIXEL_LOW<<24) | (P_GAMMA <<16) and 16-bit (6.10) scale for gamma tables, individually for each color.
+ // 16Msbs are also "hash16" and do not need to be black level/gamma, just uniquely identify the table for applications
+#define P_GTAB_G 129 // same for the first green (red line)
+#define P_GTAB_GB 130 // same for the second green (blue line)
+#define P_GTAB_B 131 // same for the blue
+#define P_QUALITY 132 //JPEG IMAGE QUALITY (now uses 2 bytes)
+#define P_ACTUAL_WIDTH 133 // RD P_RO_WIDTH 1 pixels/row
+#define P_ACTUAL_HEIGHT 134 // RD P_RO_HEIGHT 2 pixels/column
+#define P_COLOR 135 /// mono - 0, color mode - 1, +0 - normal, 256 - sensor test, 512 - FPGA test
+ #define COLORMODE_MONO6 0 // monochrome, (4:2:0),
+ #define COLORMODE_COLOR 1 // color, 4:2:0, 18x18(old)
+ #define COLORMODE_JP46 2 // jp4, original (4:2:0)
+ #define COLORMODE_JP46DC 3 // jp4, dc -improved (4:2:0)
+ #define COLORMODE_COLOR20 4 // color, 4:2:0, 20x20, middle of the tile (not yet implemented)
+ #define COLORMODE_JP4 5 // jp4, 4 blocks, (legacy)
+ #define COLORMODE_JP4DC 6 // jp4, 4 blocks, dc -improved
+ #define COLORMODE_JP4DIFF 7 // jp4, 4 blocks, differential red := (R-G1), blue:=(B-G1), green=G1, green2 (G2-G1). G1 is defined by Bayer shift, any pixel can be used
+ #define COLORMODE_JP4HDR 8 // jp4, 4 blocks, differential HDR: red := (R-G1), blue:=(B-G1), green=G1, green2 (high gain)=G2) (G1 and G2 - diagonally opposite)
+ #define COLORMODE_JP4DIFF2 9 // jp4, 4 blocks, differential, divide differences by 2: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (G2-G1)/2
+ #define COLORMODE_JP4HDR2 10 // jp4, 4 blocks, differential HDR: red := (R-G1)/2, blue:=(B-G1)/2, green=G1, green2 (high gain)=G2),
+ #define COLORMODE_MONO4 14 // monochrome, 4 blocks (but still with 2x2 macroblocks)
+/// the following 8 values should go in the same sequence as fields in the histogram page
+#define P_FRAME 136 // Frame number (reset with JPEG pointers) -(read only)
+#define P_GAINR 137 // R channel gain 8.16 (0x10000 - 1.0). Combines both analog gain and digital scaling
+#define P_GAING 138 // G channel gain ("red line")
+#define P_GAINGB 139 // G channel gain ("blue line")
+#define P_GAINB 140 // B channel gain
+#define P_EXPOS 141 //P_RW_EXPOS 1 exposure time - now in microseconds?
+#define P_VEXPOS 142 // video exposure (if 0 - use P_RW_EXPOS in ms)
+#define P_FOCUS_VALUE 143 // (readonly) - sum of all blocks focus values inside focus WOI
+
+/// 143 - last to copy
+
+#define P_COMPMOD_BYRSH 160 // Bayer shift in compressor
+#define P_PORTRAIT 161 // Quantization coefficients optimized for verical scan lines
+
+
+///TODO: rearrange, combine with other AUTOEXP
+/// if [G_HIST_DIM_01] is set to 0xffffffff that will force re-calibration (1 dark frame)
+/// The following is a daemons control so the sleeping daemons can be awaken by the drivers when the corresponding bit is set and
+/// one of the following events happen (depending on driver and lseek (SEEK_END) offset:
+/// frame interrupt (any - compressed or not) - through "/dev/frameparsall"
+/// frame compressed interrupt - through "/dev/circbuf"
+/// histogram Y (G1) is ready - through "/dev/histogram_cache"
+/// histogram C (R,G1,G2,B) are ready - through "/dev/histogram_cache"
+
+#define P_DAEMON_EN 165 /// disable all autoexp features AEXP, WB, HDR- make extra sleep for AUTOEXP_EN to become non-zero (normal frame rules)
+#define P_AEXP_FRACPIX 166 /// Fraction of all pixels that should be below P_AEXP_LEVEL (16.16 - 0x10000 - all pixels)
+#define P_AEXP_LEVEL 167 /// Target output level: [P_AEXP_FRACPIX]/0x10000 of all pixels should have value below it (also 16.16 - 0x10000 - full output scale)
+
+#define P_HDR_DUR 168 /// 0 - HDR 0ff, >1 - duration of same exposure (currently 1 or 2 - for free running)
+#define P_HDR_VEXPOS 169 /// if less than 0x10000 - number of lines of exposure, >=10000 - relative to "normal" exposure
+
+#define P_AE_PERIOD 170 /// Autoexposure period (will be increased if below the latency)
+#define P_WB_PERIOD 171 /// White balance period (will be increased if below the latency)
+#define P_WB_CTRL 172 /// bitmask - which colors to correct (1 - correct, 0 - ignore)
+#define P_WB_WHITELEV 173 /// White balance level of white (16.16 - 0x10000 is full scale, 0xfae1 - 98%, default)
+#define P_WB_WHITEFRAC 174 /// White balance fraction (16.16) of all pixels that have level above [P_WB_WHITELEV] for the brightest color
+ /// locally [P_WB_WHITELEV] will be decreased if needed to satisfy [P_WB_WHITELEV]. default is 1% (0x028f)
+#define P_WB_MAXWHITE 175 /// Maximal allowed "white" pixels fraction (16.16) to have level above [P_WB_WHITELEV] for the darkest color
+ /// if this limit is exceeded there will be no correction (waiting for autoexposure to decrease overall brightness)
+
+#define P_WB_SCALE_R 176 /// additional correction for R from calulated by white balance (16.16)
+#define P_WB_SCALE_GB 177 /// additional correction for G2(GB) from calulated by white balance (16.16)
+#define P_WB_SCALE_B 178 /// additional correction for B from calulated by white balance (16.16)
+
+#define P_EXP_AHEAD 179 /// How many frames ahead of the current frame write exposure to the sensor
+#define P_AE_THRESH 180 /// AE error (logariphmic exposures) is integrated between frame and corrections are scaled when error is below thershold (500)
+#define P_WB_THRESH 181 /// same for WB
+
+/// Used by white balancing to control analog gains in addition to gamma tables. Can be limited to narrower range than
+#define P_GAIN_MIN 182 /// minimal sensor analog gain 0x10000 ~1.0
+#define P_GAIN_MAX 183 /// maximal sensor analog gain 0x10000 ~1.0
+#define P_GAIN_CTRL 184 /// minimal correction to be applied to the analog gain (should be set larger that sensor actual gain step to prevent oscillations (0x100 - 1.0, 0x20 - 1/8)
+#define GAIN_BIT_STEP 0 /// start bit of gain step control in P_GAIN_CTRL
+#define GAIN_BIT_ENABLE 16 /// start bit of enabling analog gain controls in white balancing
+
+/// Requests for autocampars daemon
+#define P_AUTOCAMPARS_CTRL 185 /// bits 0..24 - groups to restore, bits 24..27 - page number to save bits 28..30: 1 - restore, 2 - save, 3 - set default 4 save as default 5 - init
+
+/// Parameters for ccamftp.php daemon
+/// (server, account, password, directories,script names are sepaarte)
+#define P_FTP_PERIOD 190 /// FTP image upload period
+#define P_FTP_TIMEOUT 191 /// Maximal time allowed for image uploading
+#define P_FTP_UPDATE 192 /// Maximal time between updates (camera wil re-read remote configuration file)
+
+// streamer parameters
+#define _P_STROP_OFFSET 193
+// multicast/unicast transport
+#define P_STROP_MCAST_EN (_P_STROP_OFFSET + 0) // != 0 for multicast, 0 for unicast
+#define P_STROP_MCAST_IP (_P_STROP_OFFSET + 1) // 0 for camera IP based multicast, other value - for custom IP
+#define P_STROP_MCAST_PORT (_P_STROP_OFFSET + 2) // >= 1024 && <= 65532
+#define P_STROP_MCAST_TTL (_P_STROP_OFFSET + 3) // >= 1 && <= 15
+// audio - support only one ("default") soundcard, if present
+#define P_STROP_AUDIO_EN (_P_STROP_OFFSET + 4) // 0 - disable audio, else - try if soundcard is present
+#define P_STROP_AUDIO_RATE (_P_STROP_OFFSET + 5) // >= 11250 && <= 48000
+#define P_STROP_AUDIO_CHANNEL (_P_STROP_OFFSET + 6) // 1 - mono, 2 - stereo
+#define P_STROP_FRAMES_SKIP (_P_STROP_OFFSET + 7) // 0 - output each frame, 1 - output/skip == 1/1 fomr 2 frames, 2 - output/skip == 1/2 from 3 frames etc
+#define P_AUDIO_CAPTURE_VOLUME (_P_STROP_OFFSET + 8) // for streamer and camogm2: 0 == 0%; 65535 == 100% capture volume, by default 90% == 58981
+
+///parameters related to multi-sensor operation
+#define _P_MULTISENS_OFFSET 208
+#define P_MULTISENS_EN (_P_MULTISENS_OFFSET + 0) // 0 - single sensor, no 10359A, otherwise - bitmask of the sensors enabled (obeys G_SENS_AVAIL that should not be modified at runtime)
+#define P_MULTI_PHASE_SDRAM (_P_MULTISENS_OFFSET + 1) // similar to P_SENSOR_PHASE, but for sensor1, connected to 10359
+#define P_MULTI_PHASE1 (_P_MULTISENS_OFFSET + 2) // similar to P_SENSOR_PHASE, but for sensor1, connected to 10359
+#define P_MULTI_PHASE2 (_P_MULTISENS_OFFSET + 3) // similar to P_SENSOR_PHASE, but for sensor2, connected to 10359
+#define P_MULTI_PHASE3 (_P_MULTISENS_OFFSET + 4) // similar to P_SENSOR_PHASE, but for sensor3, connected to 10359
+#define P_MULTI_SEQUENCE (_P_MULTISENS_OFFSET + 5) // sensor sequence (bits 0,1 - first, 2,3 - second, 4,5 - third). 0 - disable. Will obey G_SENS_AVAIL & P_MULTISENS_EN
+#define P_MULTI_FLIPH (_P_MULTISENS_OFFSET + 6) // additional per-sensor horizontal flip to global P_FLIPH, same bits as in G_SENS_AVAIL
+#define P_MULTI_FLIPV (_P_MULTISENS_OFFSET + 7) // additional per-sensor vertical flip to global P_FLIPV, same bits as in G_SENS_AVAIL
+#define P_MULTI_MODE (_P_MULTISENS_OFFSET + 8) // Mode 0 - single sensor (first in sequence), 1 - composite (only enabled in triggered mode)
+#define P_MULTI_HBLANK (_P_MULTISENS_OFFSET + 9) // Horizontal blanking for buffered frames (2,3) - not needed?
+
+///parameters for adjusting physical sensors WOI inside the composite frame
+#define P_MULTI_CWIDTH (_P_MULTISENS_OFFSET + 10) // Composite frame width (stored while in single-sensor mode, copied to P_WOI_WIDTH)
+#define P_MULTI_CHEIGHT (_P_MULTISENS_OFFSET + 11) // Composite frame height (stored while in single-sensor mode)
+#define P_MULTI_CLEFT (_P_MULTISENS_OFFSET + 12) // Composite frame left margin (stored while in single-sensor mode, copied to P_WOI_LEFT)
+#define P_MULTI_CTOP (_P_MULTISENS_OFFSET + 13) // Composite frame top margin (stored while in single-sensor mode)
+#define P_MULTI_CFLIPH (_P_MULTISENS_OFFSET + 14) // Horizontal flip for composite image (stored while in single-sensor mode)
+#define P_MULTI_CFLIPV (_P_MULTISENS_OFFSET + 15) // Vertical flip for composite image (stored while in single-sensor mode)
+#define P_MULTI_VBLANK (_P_MULTISENS_OFFSET + 16) // Vertical blanking for buffered frames (2,3) BEFORE FRAME, not after
+
+/// should go in that sequence *1,*2,*3 (will be indexed)
+#define P_MULTI_WOI (_P_MULTISENS_OFFSET + 17) // Width of frame 1 (direct) // Same as next
+#define P_MULTI_WIDTH1 ( P_MULTI_WOI+ 0) // Width of frame 1 (direct) // same as P_MULTI_WOI !!!!
+#define P_MULTI_WIDTH2 ( P_MULTI_WOI+ 1) // Width of frame 2 (first buffered)
+#define P_MULTI_WIDTH3 ( P_MULTI_WOI+ 2) // Width of frame 3 (second buffered)
+#define P_MULTI_HEIGHT1 ( P_MULTI_WOI+ 3) // Height of frame 1 (direct)
+#define P_MULTI_HEIGHT2 ( P_MULTI_WOI+ 4) // Height of frame 2 (first buffered)
+#define P_MULTI_HEIGHT3 ( P_MULTI_WOI+ 5) // Height of frame 3 (second buffered)
+#define P_MULTI_LEFT1 ( P_MULTI_WOI+ 6) // Left margin of frame 1 (direct)
+#define P_MULTI_LEFT2 ( P_MULTI_WOI+ 7) // Left margin of frame 2 (first buffered)
+#define P_MULTI_LEFT3 ( P_MULTI_WOI+ 8) // Left margin of frame 3 (second buffered)
+#define P_MULTI_TOP1 ( P_MULTI_WOI+ 9) // Top margin of frame 1 (direct)
+#define P_MULTI_TOP2 ( P_MULTI_WOI+ 10) // Top margin of frame 2 (first buffered)
+#define P_MULTI_TOP3 ( P_MULTI_WOI+ 11) // Top margin of frame 3 (second buffered)
+#define P_MULTI_TOPSENSOR (_P_MULTISENS_OFFSET + 29) // number of sensor channel used in first (direct) frame: 0..2, internal parameter (window->sensorin)
+#define P_MULTI_SELECTED (_P_MULTISENS_OFFSET + 30) // number of sensor channel (1..3, not 0..2) used when composite mode is disabled
+/// parameters for MakerNote, internal
+#define P_MULTI_MODE_FLIPS (_P_MULTISENS_OFFSET + 31) // bit 7 - 0, bit 6 - composite mode, bits 4,5 - flips for frame 3, 2,3 - frame 2, 0,1 - frame 1 (top)
+#define P_MULTI_HEIGHT_BLANK1 (_P_MULTISENS_OFFSET + 32) // height of the first sub-frame plus (vertical blank after the first sub-frame) << 16 (output lines, decimated)
+#define P_MULTI_HEIGHT_BLANK2 (_P_MULTISENS_OFFSET + 33) // height of the second sub-frame plus (vertical blank after the second sub-frame) << 16 (output lines, decimated)
+
+// up to _P_MULTISENS_OFFSET + 256-208-1=47
+
+#define P_SENSOR_REGS 256 /// shadows of the sensor registers (should be multiple of 32)
+#define P_SENSOR_NUMREGS 256 /// number of the sensor registers (should be multiple of 32)
+
+#define P_M10359_REGS (P_SENSOR_REGS + P_SENSOR_NUMREGS) /// shadows of the 10359 registers (should be multiple of 32)
+#define P_M10359_NUMREGS 96 /// shadows of the 10359 registers (should be multiple of 32)
+#define P_M10359_REGS32BIT 0x40 // 10359 registers above 0x40 are 32-bit ones
+
+
+#define P_MULTI_NUMREGS 32 /// up to 32 sensor register may have individual values
+#define P_MULTI_REGS (P_M10359_REGS + P_M10359_NUMREGS) /// 32-words aligned
+
+#define P_MAX_PAR (P_MULTI_REGS + (MAX_SENSORS * P_MULTI_NUMREGS )) /// maximal # of used parameter+1
+#ifdef SAFE_CHECK
+ #define MULTIREG(x,n) ((((n)>=0) && ((n)0) && ((x) < P_MAX_PAR) && (multiSensIndex[x] > 0))? (multiSensIndex[x]+(n)) : 0)
+#else
+ #define MULTIREG(x,n) ((multiSensIndex[x] > 0)? (multiSensIndex[x]+(n)) : 0) // unsafe
+#endif
+#define MULTIRVRSREG(x) (multiSensRvrsIndex[x])
+
+
+//#define P_MAX_PAR 511 /// maximal # of used parameter
+//#define P_MAX_GPAR 1023 // maximal # of global parameter
+#define P_MAX_GPAR 2047 /// maximal # of global parameter - TODO: change name to NUM_GPAR and make it 2048
+
+
+#define PARS_SAVE_FROM 128 /// PARS_SAVE_NUM parameters starting from PARS_SAVE_FROM from "this" frame will be saved in circular buffer, PASTPARS_SAVE_ENTRIES entries
+#define PARS_SAVE_COPY 16 /// number of parameters copied from future (framepars) to the past (pastpars)
+#define PARS_SAVE_NUM 32 /// total size of previous parameter save page
+#define PP_PROFILE_START 16 /// index of the first profile timestamp in pastpars
+#define P_PROFILE (PARS_SAVE_FROM + PP_PROFILE_START) //index to access profiles as pastpars (i.e. from PHP ELPHEL_PROFILE1,PHP ELPHEL_PROFILE2)
+
+
+#define FRAMEPAR_GLOBALS 0x01000 /// start of global (not frame-related) parameters
+
+#define GLOBALS_PRESERVE 0x20 /// number of parameters that are not erased during initGlobalPars
+
+/// First 32 parameter values are not erased with initGlobalPars
+#define GLOBALPARS(x) globalPars[(x)-FRAMEPAR_GLOBALS] // should work in drivers and applications
+
+#define G_DEBUG (FRAMEPAR_GLOBALS + 2) /// Each bit turns on/off some debug outputs
+#define G_TEST_CTL_BITS (FRAMEPAR_GLOBALS + 3) /// turn some features on/off in the drivers for debuggin purposes
+#define G_TEST_CTL_BITS_RESET_DMA_COMPRESSOR 0 /// reset compressor and DMA when detecting sensor, bit number in G_TEST_CTL_BITS
+
+#define G_CABLE_TIM (FRAMEPAR_GLOBALS + 7) /// Extra cable delay, signed ps)
+#define G_FPGA_TIM0 (FRAMEPAR_GLOBALS + 8) /// FPGA timing parameter 0 - difference between DCLK pad and DCM input, signed (ps)
+#define G_FPGA_TIM1 (FRAMEPAR_GLOBALS + 9) /// FPGA timing parameter 1
+
+#define G_SENS_AVAIL (FRAMEPAR_GLOBALS + 10) /// bitmask of the sensor attached to 10359A (0 - no 10359A brd)
+#define G_DLY359_OUT (FRAMEPAR_GLOBALS + 11) /// output delay in 10359 board (clock to out) in ps, signed
+#define G_DLY359_P1 (FRAMEPAR_GLOBALS + 12) /// delay in 10359 board sensor port 1 (clock to sensor - clock to DCM) in ps, signed
+#define G_DLY359_P2 (FRAMEPAR_GLOBALS + 13) /// delay in 10359 board sensor port 2 (clock to sensor - clock to DCM) in ps, signed
+#define G_DLY359_P3 (FRAMEPAR_GLOBALS + 14) /// delay in 10359 board sensor port 3 (clock to sensor - clock to DCM) in ps, signed
+#define G_DLY359_C1 (FRAMEPAR_GLOBALS + 15) /// cable delay in sensor port 1 in ps, signed
+#define G_DLY359_C2 (FRAMEPAR_GLOBALS + 16) /// cable delay in sensor port 2 in ps, signed
+#define G_DLY359_C3 (FRAMEPAR_GLOBALS + 17) /// cable delay in sensor port 3 in ps, signed
+///gap
+#define G_MULTI_CFG (FRAMEPAR_GLOBALS + 23) /// Additional configuration options for 10359 board.
+ #define G_MULTI_CFG_SYSCLK 0 /// Bit 0 - use 10353 system clock, not the local one (as on 10359 rev 0)
+ #define G_MULTI_CFG_DLYI2C 1 /// Bit 1 - delay 10359 i2c commands with respect to sensor ones (in multi_pgm_window)
+ #define G_MULTI_CFG_BEFORE 2 /// Bit 2 - send 10359 i2c commands first (to be sent after frame sync, 0 - sesnor commands first)
+#define G_MULTI_REGSM (FRAMEPAR_GLOBALS + 24) /// 8 words of bitmasks of individual sensor registers, used only at init. Later will be initialized (OR-ed?) by driver
+/// used up to FRAMEPAR_GLOBALS + 31
+
+///First 32 entries will not be erased when sensor init, Move some here
+#define G_FRAME_SIZE (FRAMEPAR_GLOBALS + 33) /// Last compressed frame size in bytes (w/o headers)
+
+#define G_MULTI_NUM (FRAMEPAR_GLOBALS + 34) /// Actual number of parameters that are individual for different channels (limited by P_MULTI_NUMREGS)
+
+#define G_MAXAHEAD (FRAMEPAR_GLOBALS + 35) /// Maximal number of frames ahead of current to be programmed to hardware
+#define G_THIS_FRAME (FRAMEPAR_GLOBALS + 36) /// Current frame number (may lag from the hardwaere)
+#define G_CIRCBUFSIZE (FRAMEPAR_GLOBALS + 37) /// Size of the circular buffer (in bytes)
+//!the following 3 locations should be in the same 32-byte (8 long) cache line
+#define G_FREECIRCBUF (FRAMEPAR_GLOBALS + 38) /// Free space in circbuf (uses global read pointer, in bytes)
+#define G_CIRCBUFWP (FRAMEPAR_GLOBALS + 39) /// circbuf write pointer (in bytes - similar P_JPEG_WP is in long words)
+#define G_CIRCBUFRP (FRAMEPAR_GLOBALS + 40) /// circbuf global read pointer (in bytes )
+
+#define G_SECONDS (FRAMEPAR_GLOBALS + 41) /// seconds (R/W to FPGA timer)
+#define G_MICROSECONDS (FRAMEPAR_GLOBALS + 42) /// microseconds (R/W to FPGA timer)
+
+/// Next 5 should go in that sequence
+#define G_CALLNASAP (FRAMEPAR_GLOBALS + 43) /// bitmask - what functions can be used not only in the current frame (ASAP) mode
+#define G_CALLNEXT (FRAMEPAR_GLOBALS + 43) /// (same as G_CALLNASAP) bitmask of actions to be one or more frames ahead of the programmed one (OR-ed with G_CALLNEXT2..G_CALLNEXT4)
+///Leave 4 locations after for (G_CALLNEXT+1)...(G_CALLNEXT+4)
+//#define G_CALLNEXT1 (FRAMEPAR_GLOBALS + 44) /// bitmask of actions to be one or more frames ahead of the programmed one (OR-ed with G_CALLNEXT2..G_CALLNEXT4)
+//#define G_CALLNEXT2 (FRAMEPAR_GLOBALS + 45) /// bitmask of actions to be two or more frames ahead of the programmed one (OR-ed with G_CALLNEXT3..G_CALLNEXT4)
+//#define G_CALLNEXT3 (FRAMEPAR_GLOBALS + 46) // bitmask of actions to be three or more frames ahead of the programmed one (OR-ed with G_CALLNEXT4)
+//#define G_CALLNEXT4 (FRAMEPAR_GLOBALS + 47) // bitmask of actions to be four or more frames ahead of the programmed one
+
+#define G_NEXT_AE_FRAME (FRAMEPAR_GLOBALS + 48) // Next frame to be processed by autoexposure - written directly from daemon through mmap
+#define G_NEXT_WB_FRAME (FRAMEPAR_GLOBALS + 49) // Next frame to be processed by white balance - written directly from daemon through mmap
+#define G_HIST_DIM_01 (FRAMEPAR_GLOBALS + 50) // Percentile measured for colors 0 (lower 16 bits) and 1 (high 16 bits) for VEXPOS=1
+#define G_HIST_DIM_23 (FRAMEPAR_GLOBALS + 51) // Percentile measured for colors 2 (lower 16 bits) and 3 (high 16 bits) for VEXPOS=1
+/// if [G_HIST_DIM_01] is set to 0xffffffff that will force re-calibration (1 dark frame)
+//#define G_EW_HYSTCNTR (FRAMEPAR_GLOBALS + 52) // autoexposure/white balance hysteresis counters , 1 byte each, (sign and count, Y,R,G2,B)
+#define G_AE_INTEGERR (FRAMEPAR_GLOBALS + 52) // current integrated error in the AE loop
+#define G_WB_INTEGERR (FRAMEPAR_GLOBALS + 53) // current integrated error in WB loop
+
+#define G_TASKLET_CTL (FRAMEPAR_GLOBALS + 54) /// disable individual tasklets (TODO:rename to DEBUG_CTL?)
+#define G_GFOCUS_VALUE (FRAMEPAR_GLOBALS + 55) // (readonly) - sum of all blocks focus values inside focus WOI (global)
+
+ #define TASKLET_CTL_PGM 0 /// disable programming parameters (should not be)
+ #define TASKLET_CTL_IGNPAST 1 /// "ignore overdue" control bit
+ #define TASKLET_CTL_NOSAME 2 /// don't try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent
+ #define TASKLET_CTL_ENPROF 3 /// enable profiling (saving timing of the interrupts/tasklets in pastpars)
+ /// effects of uncertainty of when was it called relative to frame sync
+ #define TASKLET_HIST_ALL 0 /// calculate each frame
+ #define TASKLET_HIST_HALF 1 /// calculate each even (0,2,4,6 frme of 8)
+ #define TASKLET_HIST_QUATER 2 /// calculate twice per 8 (0, 4)
+/// NOTE: It is safer to allow all histograms at least once in 8 frames so applications will not be locked up waiting for the missed histogram
+/// TODO: detect missing histograms and wakeup queue
+ #define TASKLET_HIST_ONCE 3 /// calculate once per 8 (0)
+ #define TASKLET_HIST_RQONLY 4 /// calculate only when specifically requested
+ #define TASKLET_HIST_NEVER 7 /// never calculate
+
+ #define TASKLET_CTL_HISTY_BIT 4 /// shift of histogram calculation for Y in G_TASKLET_CTL (bits 4,5,6)
+ #define TASKLET_CTL_HISTC_BIT 8 /// shift of histogram calculation for C in G_TASKLET_CTL (bits 8,9,10)
+
+#define G_HIST_LAST_INDEX (FRAMEPAR_GLOBALS + 56) // last used index in histogram cache
+#define G_HIST_Y_FRAME (FRAMEPAR_GLOBALS + 57) // last frame for which Y histogram was calcualted
+#define G_HIST_C_FRAME (FRAMEPAR_GLOBALS + 58) // last frame for which C histograms were calcualted
+#define G_SKIP_DIFF_FRAME (FRAMEPAR_GLOBALS + 59) // number of frames with different size to tolerate before producing POLLHUP in poll(circbuf)
+#define G_FTP_NEXT_TIME (FRAMEPAR_GLOBALS + 60) // time of the next FTP upload (seconds from epoch)
+
+#define G_DAEMON_ERR (FRAMEPAR_GLOBALS + 63) // 1 bit per daemon error that needs attention (daemon would put itself to sleep through P_DAEMON_EN)
+#define G_DAEMON_RETCODE (FRAMEPAR_GLOBALS + 64) // return codes (32 32-bit words) for daemons, provided with a corresponding bit in G_DAEMON_ERR set
+///next will be (FRAMEPAR_GLOBALS + 96)
+/// temperature is provided by the daemon, embedded in MakerNote by the driver
+#define G_TEMPERATURE01 (FRAMEPAR_GLOBALS + 96) // temperature on the sensors 0 and 1 (0x1000 - sign, rest 8.4 C) no 10359 - only chn0, with 10359 - only 1,2,3 (no 0)
+#define G_TEMPERATURE23 (FRAMEPAR_GLOBALS + 97) // temperature on the sensors 2 and 3
+
+#define G_SENSOR_CALIB (FRAMEPAR_GLOBALS + 1024) /// 1024 Array of sensor calibration data, sensor dependent.For Micron it is 256*4 actual gains in 8.16 format
+ /// Only first 96 for each color are used
+
+
+
+///Modifies to the parameter numbers/addresses
+#define FRAMEPAIR_FORCE_NEW 0x040000000 // will mark parameter as "modified" even the new==old
+#define FRAMEPAIR_FORCE_PROC 0x080000000 // will mark schedule functions for that parameter even if called from setFramePars/setFramePar (normally it is not)
+#define FRAMEPAIR_FORCE_NEWPROC 0x0c0000000 // combines both
+#define FRAMEPAIR_JUST_THIS 0x10000000 // write only to this frame, don't propagate
+ // (like "single frame" - compressor, sensor) first write "stop", then - "single" with FRAMEPAIR_JUST_THIS
+#define FRAMEPAIR_FRAME_FUNC 0x20000000 // write to func2call instead of the frame parameters
+/// compose bit fields to be OR-ed to the parameter number bit 16..25: b - start bit (0..31), w - width 1..32
+#define FRAMEPAIR_FRAME_BITS(w,b) ((((w) & 0x1f)<<21) | (((b) & 0x1f)<<16))
+/// Shift new data (nd), apply mask and combine with old data (od), taking shift/width information from bits 16..25 of (a)
+#define FRAMEPAIR_FRAME_MASK_NEW(a,od,nd) ((((od) ^ ((nd) << (((a)>>16) & 0x1f))) & (((1 << (((a)>>21) & 0x1f))-1) << (((a)>>16) & 0x1f))) ^ (od))
+
+/// read bit field from the data (d), use bit information encoded in bits 16..25 of the parameter address (a)
+#define FRAMEPAIR_FRAME_FIELD(a,d) (((d) >> (((a)>>16) & 0x1f)) & ((1 << (((a) >> 21) & 0x1f))-1))
+
+#define FRAMEPAIR_MASK_BYTES (FRAMEPAIR_FRAME_BITS(31,31)) /// 0x03ff0000 - if parameter address & FRAMEPAIR_FRAME_MASK is nonzero, chnage only some bits
+
+///NOTE: byte/word masks not to be OR-ed!
+#define FRAMEPAIR_BYTE0 (FRAMEPAIR_FRAME_BITS( 8, 0)) // overwrite only byte0 (LSB) in the paremater
+#define FRAMEPAIR_BYTE1 (FRAMEPAIR_FRAME_BITS( 8, 8)) // overwrite only byte1 in the paremater
+#define FRAMEPAIR_BYTE2 (FRAMEPAIR_FRAME_BITS( 8, 16)) // overwrite only byte2 in the parematerhttp://192.168.0.229
+#define FRAMEPAIR_BYTE3 (FRAMEPAIR_FRAME_BITS( 8, 24)) // overwrite only byte3 (MSB) in the paremater
+#define FRAMEPAIR_WORD0 (FRAMEPAIR_FRAME_BITS(16, 0)) // overwrite only word0 (LSW) in the paremater (i.e. gamma scale)
+#define FRAMEPAIR_WORD1 (FRAMEPAIR_FRAME_BITS(16, 16)) // overwrite only word1 (MSW) in the paremater (i.e. gamma hash16)
+
+//#define P_DAEMON_EN 165 // disable all autoexp features AEXP, WB, HDR- make extra sleep for AUTOEXP_EN to become non-zero (normal frame rules)
+#define DAEMON_BIT_AUTOEXPOSURE 0
+#define DAEMON_BIT_STREAMER 1
+#define DAEMON_BIT_CCAMFTP 2
+#define DAEMON_BIT_CAMOGM 3
+#define DAEMON_BIT_AUTOCAMPARS 4
+#define DAEMON_BIT_TEMPERATURE 5
+// add up to 31
+
+#define P_DAEMON_EN_AUTOEXPOSURE (P_DAEMON_EN | FRAMEPAIR_FRAME_BITS(1, DAEMON_BIT_AUTOEXPOSURE))
+#define P_DAEMON_EN_STREAMER (P_DAEMON_EN | FRAMEPAIR_FRAME_BITS(1, DAEMON_BIT_STREAMER))
+#define P_DAEMON_EN_CCAMFTP (P_DAEMON_EN | FRAMEPAIR_FRAME_BITS(1, DAEMON_BIT_CCAMFTP))
+#define P_DAEMON_EN_CAMOGM (P_DAEMON_EN | FRAMEPAIR_FRAME_BITS(1, DAEMON_BIT_CAMOGM))
+#define P_DAEMON_EN_AUTOCAMPARS (P_DAEMON_EN | FRAMEPAIR_FRAME_BITS(1, DAEMON_BIT_AUTOCAMPARS))
+#define P_DAEMON_EN_TEMPERATURE (P_DAEMON_EN | FRAMEPAIR_FRAME_BITS(1, DAEMON_BIT_TEMPERATURE))
+
+//#define P_GAIN_CTRL 184 // combines GAIN_STEP and ANA_GAIN_ENABLE
+#define P_GAIN_STEP (P_GAIN_CTRL | FRAMEPAIR_FRAME_BITS(16, GAIN_BIT_STEP)) // minimal correction to be applied to the analog gain
+ // (should be set larger that sensor actual gain step to prevent oscillations (0x100 - 1.0, 0x20 - 1/8)
+#define P_ANA_GAIN_ENABLE (P_GAIN_CTRL | FRAMEPAIR_FRAME_BITS(1, GAIN_BIT_ENABLE)) // enable analog gain adjustment in white balance procedure
+
+#define WB_CTRL_BIT_EN 4
+#define P_WB_MASK (P_WB_CTRL | FRAMEPAIR_FRAME_BITS(4, 0)) // Colors adjusted in automatic white balance
+#define P_WB_EN (P_WB_CTRL | FRAMEPAIR_FRAME_BITS(1, WB_CTRL_BIT_EN)) // Enabling/disabling automatic white balance adjustment
+
+#define P_RSCALE (P_RSCALE_ALL | FRAMEPAIR_FRAME_BITS(CSCALES_WIDTH, 0)) // Red-to-Green ratio, 0x10000 ~ 1.0
+#define P_GSCALE (P_GSCALE_ALL | FRAMEPAIR_FRAME_BITS(CSCALES_WIDTH, 0)) // Green2-to-Green ratio, 0x10000 ~ 1.0
+#define P_BSCALE (P_BSCALE_ALL | FRAMEPAIR_FRAME_BITS(CSCALES_WIDTH, 0)) // Blue-to-Green ratio, 0x10000 ~ 1.0
+
+#define P_RSCALE_CTL (P_RSCALE_ALL | FRAMEPAIR_FRAME_BITS(CSCALES_CTL_WIDTH, CSCALES_CTL_BIT)) // Red-to-Green ratio control
+#define P_GSCALE_CTL (P_GSCALE_ALL | FRAMEPAIR_FRAME_BITS(CSCALES_CTL_WIDTH, CSCALES_CTL_BIT)) // Green2-to-Green ratio control
+#define P_BSCALE_CTL (P_BSCALE_ALL | FRAMEPAIR_FRAME_BITS(CSCALES_CTL_WIDTH, CSCALES_CTL_BIT)) // Blue-to-Green ratio control
+
+#define P_SENSOR_SINGLE (P_SENSOR_RUN | FRAMEPAIR_JUST_THIS) // is only good to write SENSOR_RUN_SINGLE there!
+#define P_COMPRESSOR_SINGLE (P_COMPRESSOR_RUN | FRAMEPAIR_JUST_THIS) // is only good to write COMPRESSOR_RUN_SINGLE there!
+
+
+//#define P_HISTRQ 67 // per-frame enabling of histogram calculation - bit 0 - Y (G), bit 2 - C (R,G2,B)
+//#define HISTRQ_BITY 0
+//#define HISTRQ_BITC 1
+#define HISTRQ_BIT_Y 0
+#define HISTRQ_BIT_C 1
+
+#define P_HISTRQ_Y (P_HISTRQ | FRAMEPAIR_FRAME_BITS(1, HISTRQ_BIT_Y) | FRAMEPAIR_JUST_THIS) /// request calculation of the Y-histogram for just this frame
+#define P_HISTRQ_C (P_HISTRQ | FRAMEPAIR_FRAME_BITS(1, HISTRQ_BIT_C) | FRAMEPAIR_JUST_THIS) /// request calculation of the C-histogram for just this frame
+#define P_HISTRQ_YC (P_HISTRQ | FRAMEPAIR_FRAME_BITS(2, HISTRQ_BIT_Y) | FRAMEPAIR_JUST_THIS) /// request calculation of both the Y-histogram and C-histogrames for just this frame
+
+#define G_HISTMODE_Y (G_TASKLET_CTL | FRAMEPAIR_FRAME_BITS(3, TASKLET_CTL_HISTY_BIT)) /// control for histogram calculation Y (see TASKLET_HIST_*)
+#define G_HISTMODE_C (G_TASKLET_CTL | FRAMEPAIR_FRAME_BITS(3, TASKLET_CTL_HISTC_BIT)) /// control for histogram calculation Y (see TASKLET_HIST_*)
+
+#define G_PROFILING_EN (G_TASKLET_CTL | FRAMEPAIR_FRAME_BITS(1, TASKLET_CTL_ENPROF)) /// enable profiling (saving timing of the interrupts/tasklets in pastpars)
+
+
+//#define P_AUTOCAMPARS_CTRL 184 // bits 0..24 - groups to restore, bits 24..27 - page number to save bits 28..30: 1 - restore, 2 - save, 3 - set default 4 save as default 5 - init
+#define P_AUTOCAMPARS_GROUPS (P_AUTOCAMPARS_CTRL | FRAMEPAIR_FRAME_BITS(24, 0))
+#define P_AUTOCAMPARS_PAGE (P_AUTOCAMPARS_CTRL | FRAMEPAIR_FRAME_BITS(4, 24))
+#define P_AUTOCAMPARS_CMD (P_AUTOCAMPARS_CTRL | FRAMEPAIR_FRAME_BITS(3, 28))
+
+///NOTE page 0 is write protected, page 15 (0x0f) is "default" page
+#define AUTOCAMPARS_CMD_RESTORE 1 /// restore specified groups of parameters from the specified page
+#define AUTOCAMPARS_CMD_SAVE 2 /// save all current parameters to the specified group (page 0 is write-protected)
+#define AUTOCAMPARS_CMD_DFLT 3 /// make selected page the default one (used at startup), page 0 OK
+#define AUTOCAMPARS_CMD_SAVEDFLT 4 /// save all current parameters to the specified group (page 0 is write-protected) and make it default (used at startup)
+#define AUTOCAMPARS_CMD_INIT 5 /// reset sensor/sequencers, restore all parameters from the specified page
+
+
+
+/// if defined 1 - will wakeup each frame, regardless of the availability of the histograms
+#define HISTOGRAMS_WAKEUP_ALWAYS 0
+
+
+/// Making use of FPGA queues of i2c and sequencer commands (up to 6 frames ahead)
+/// The P_* parameters will now be stored in 8 pages (previous frame, this frame (+0), next(+1),...(+6)
+/// Top index (0..7) corresponds to hardware frame counter, parameters are copied after the frame sync/compressor done interrupts.
+/// when the 3-bit counter is combined with the software variable to get the full 32-bit frame number
+/// Each parameter page includes 927 parameter registers, as well as 97 bitmasks to speed up updates between frames
+/// So if no parameters are changed - nothing to be copied from page to page
+#define PARS_FRAMES 8 // number of frames handled in buffer
+#define PARS_FRAMES_MASK (PARS_FRAMES-1) // currently 7
+#define PASTPARS_SAVE_ENTRIES (PARS_FRAMES << 8) // 2048
+#define PASTPARS_SAVE_ENTRIES_MASK ((PARS_FRAMES << 8)-1) // 0x7ff
+struct framepars_t {
+ unsigned long pars[927]; // parameter values (indexed by P_* constants)
+ unsigned long functions; // each bit specifies function to be executed (triggered by some parameters change)
+ unsigned long modsince[31]; // parameters modified after this frame - each bit corresponds to one element in in par[960] (bit 31 is not used)
+ unsigned long modsince32; // parameters modified after this frame super index - non-zero elements in in mod[31] (bit 31 is not used)
+ unsigned long mod[31]; // modified parameters - each bit corresponds to one element in in par[960] (bit 31 is not used)
+ unsigned long mod32; // super index - non-zero elements in in mod[31] (bit 31 is not used)
+ unsigned long needproc[31]; /// FIXME: REMOVE parameters "modified and not yet processed" (some do not need any processing)
+ unsigned long needproc32; /// FIXME: REMOVE parameters "modified and not yet processed" frame super index - non-zero elements in in mod[31] (bit 31 is not used)
+};
+///TODO: rearrange onchage_* - functions will be executed in this sequence (from 0 to 31)
+
+/// pgm_memcompressor uses pgm_memsensor
+/// pgm_compctl,pgm_comprestart use pgm_memcompressor
+/// pgm_limitfps uses pgm_memcompressor
+
+/// pgm_memcompressor uses pgm_memsensor
+/// pgm_compctl,pgm_comprestart use pgm_memcompressor
+/// pgm_limitfps uses pgm_memcompressor
+/// pgm_limitfps uses pgm_compmode
+/// pgm_trigseq uses pgm_limitfps
+/// pgm_sensorin (bayer) uses pgm_window (flip)
+/// onchange_i2c should be the first after init sensor (even before onchange_sensorphase)
+
+
+/// phase (common part conditionally triggers init) -> init -> i2c -> sensorregs -> afterinit
+/// reset i2c - only once, when the sensor is reset, it is stopped, by frame numbers go on (and parameters are not erased)
+
+///TODO: onchange_exposure should be after onchange_limitfps
+enum onchange_functions_t {
+ onchange_recalcseq=0, /// recalculate sequences/latencies, according to P_SKIP, P_TRIG
+ onchange_detectsensor, /// detect sensor type, sets sensor structure (capabilities), function pointers
+ onchange_sensorphase, /// program sensor clock/phase (needs to know maximal clock frequency)
+ onchange_i2c, /// program i2c
+ onchange_sensorregs, /// write sensor registers (only changed from outside the driver as they may have different latencies)?
+ onchange_initsensor, /// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
+ onchange_afterinit, /// restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
+ onchange_multisens, /// chnages related to multiplexed sensors
+ onchange_window, /// program sensor WOI and mirroring (flipping)
+ onchange_window_safe, /// program sensor WOI and mirroring (flipping) - lower latency, no bad frames
+// onchange_exposure, /// program exposure
+ onchange_gains, /// program analog gains
+ onchange_triggermode, /// program sensor trigger mode
+ onchange_sensorin, /// program sensor input in FPGA (Bayer, 8/16 bits, ??)
+ onchange_sensorstop, /// Stop acquisition from the sensor to the FPGA (start has latency of 2)
+ onchange_sensorrun, /// Start/single acquisition from the sensor to the FPGA (stop has latency of 1)
+ onchange_gamma, /// program gamma table
+ onchange_hist, /// program histogram window
+ onchange_aexp, /// program autoexposure mode
+ onchange_quality, /// program quantization table(s)
+ onchange_memsensor, /// program memory channels 0 (sensor->memory) and 1 (memory->FPN)
+ onchange_memcompressor, /// program memory channel 2 (memory->compressor)
+ onchange_limitfps, /// check compressor will keep up, limit sensor FPS if needed
+ onchange_exposure, /// program exposure - NOTE: was just after onchange_window
+
+ onchange_compmode, /// program compressor modes (excluding start/stop/single)
+ onchange_focusmode, /// program focus modes
+ onchange_trigseq, /// program sequencer (int/ext)
+ onchange_irq, /// program smart IRQ mode (needs to be on)
+ onchange_comprestart, /// restart after changing geometry (recognizes ASAP and programs memory channel 2 then)
+ onchange_compstop, /// stop compressor when changing geometry
+ onchange_compctl, /// only start/stop/single (after explicitly changed, not when geometry was changed)
+ onchange_gammaload, /// write gamma tables (should be prepared). Maybe - just last byte, to activate?
+ onchange_prescal /// change scales for per-color digital gains, apply vignetting correction
+// onchange_sensorregs /// write sensor registers (only changed from outside the driver as they may have different latencies)?
+/// add others - noe left, all 32 bits used
+};
+
+struct framepars_past_t {
+ unsigned long past_pars[PARS_SAVE_NUM];
+};
+
+struct framepars_all_t {
+ struct framepars_t framePars[PARS_FRAMES];
+ struct framepars_t func2call; /// func2call.pars[] - each parameter has a 32-bit mask of what pgm_function to call - other fields not used
+ unsigned long globalPars[P_MAX_GPAR]; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both R/W
+ struct framepars_past_t pastPars [PASTPARS_SAVE_ENTRIES];
+ unsigned long multiSensIndex[P_MAX_PAR]; /// indexes of individual sensor register shadows (first of 3) - now for all parameters, not just sensor ones
+ unsigned long multiSensRvrsIndex[P_MAX_PAR]; /// reverse index (to parent) for the multiSensIndex in lower 16 bits, high 16 bits - sensor number
+};
+
+struct frameparspair_t {
+ unsigned long num; // parameter index ( as defined by P_* constants) ored with "force new" (0x10000) - parameter value will be considered a new one
+ unsigned long val; // parameter value
+};
+
+
+//framePars errors - change to avoid defined in errno.h?
+#define ERR_FRAMEPARS_TOOEARLY 100
+#define ERR_FRAMEPARS_TOOLATE 101
+#define ERR_FRAMEPARS_BADINDEX 102
+#define ERR_PGM_TRYAGAINLATER 103 /// tried to program too early (gamma, ?)
+
+
+#define FRAMEPARS_SETFRAME 0xff01
+#define FRAMEPARS_SETFRAMEREL 0xff02
+#define FRAMEPARS_SETLATENCY 0xff03
+#define FRAMEPARS_SETFPGATIME 0xff04
+#define FRAMEPARS_GETFPGATIME 0xff05
+
+#define FRAME_DEAFAULT_AHEAD 3 // program current frame+3 if not specified
+
+
+//!for structure mapping:
+#define P_AUTOEXP P_AUTOEXP_ON
+#define P_AEXPWND P_HISTWND_WIDTH
+
+
+struct autoexp_t {
+ unsigned long on;
+ /*
+ * in percents: 1 == 1, 100 == 100
+ */
+ unsigned long width;
+ unsigned long height;
+ unsigned long left;
+ unsigned long top;
+ /*
+ * start exposure time really not needed...
+ */
+ unsigned long exp_max; /* 100 usec == 1 etc... */
+ unsigned long overexp_max; /* percentages for overexposured pixels - 1% == 100, 5% == 500, 0.02% == 2 etc... */
+ /*
+ * changed chema - balance exposition for set percent of pixels in needed index
+ */
+ unsigned long s_percent;
+ unsigned long s_index;
+ /*
+ * return current state
+ */
+ unsigned long exp;
+ /*
+ * "sleep" settings
+ */
+ unsigned long skip_pmin; /* percent of delta for skip changes: 1% == 100 */
+ unsigned long skip_pmax; /* percent of changes for wait one frame before apply changes: 1% == 100 */
+ unsigned long skip_t; /* time for skip changes: 100 usec == 1 */
+};
+struct aexp_window_t {
+ unsigned long width;
+ unsigned long height;
+ unsigned long top;
+ unsigned long left;
+};
+
+
+struct p_names_t {
+ int value;
+ char* name;
+};
+
+#define P_NAME_ENTRY(y) { P_##y, #y }
+#define G_NAME_ENTRY(y) { G_##y, #y }
+#define DEFINE_P_NAMES(x) struct p_names_t x[]= { \
+ P_NAME_ENTRY(NUMBER), \
+ P_NAME_ENTRY(SENSOR), \
+ P_NAME_ENTRY(SENSOR_RUN), \
+ P_NAME_ENTRY(SENSOR_SINGLE), \
+ P_NAME_ENTRY(ACTUAL_WIDTH), \
+ P_NAME_ENTRY(ACTUAL_HEIGHT), \
+ P_NAME_ENTRY(BAYER), \
+ P_NAME_ENTRY(PERIOD), \
+ P_NAME_ENTRY(FP1000SLIM), \
+ P_NAME_ENTRY(FRAME), \
+ P_NAME_ENTRY(CLK_FPGA), \
+ P_NAME_ENTRY(CLK_SENSOR), \
+ P_NAME_ENTRY(FPGA_XTRA), \
+ P_NAME_ENTRY(TRIG), \
+ P_NAME_ENTRY(EXPOS), \
+ P_NAME_ENTRY(BGFRAME), \
+ P_NAME_ENTRY(IMGSZMEM), \
+ P_NAME_ENTRY(PAGE_ACQ), \
+ P_NAME_ENTRY(PAGE_READ), \
+ P_NAME_ENTRY(OVERLAP), \
+ P_NAME_ENTRY(VIRT_KEEP), \
+ P_NAME_ENTRY(VIRT_WIDTH), \
+ P_NAME_ENTRY(VIRT_HEIGHT), \
+ P_NAME_ENTRY(WOI_LEFT), \
+ P_NAME_ENTRY(WOI_TOP), \
+ P_NAME_ENTRY(WOI_WIDTH), \
+ P_NAME_ENTRY(WOI_HEIGHT), \
+ P_NAME_ENTRY(FLIPH), \
+ P_NAME_ENTRY(FLIPV), \
+ P_NAME_ENTRY(FPSFLAGS), \
+ P_NAME_ENTRY(DCM_HOR), \
+ P_NAME_ENTRY(DCM_VERT), \
+ P_NAME_ENTRY(BIN_HOR), \
+ P_NAME_ENTRY(BIN_VERT), \
+ P_NAME_ENTRY(FPGATEST), \
+ P_NAME_ENTRY(TESTSENSOR), \
+ P_NAME_ENTRY(COLOR), \
+ P_NAME_ENTRY(FRAMESYNC_DLY), \
+ P_NAME_ENTRY(PF_HEIGHT), \
+ P_NAME_ENTRY(BITS), \
+ P_NAME_ENTRY(SHIFTL), \
+ P_NAME_ENTRY(FPNS), \
+ P_NAME_ENTRY(FPNM), \
+ P_NAME_ENTRY(VEXPOS), \
+ P_NAME_ENTRY(VIRTTRIG), \
+ P_NAME_ENTRY(PERIOD_MIN), \
+ P_NAME_ENTRY(PERIOD_MAX), \
+ P_NAME_ENTRY(SENSOR_PIXH), \
+ P_NAME_ENTRY(SENSOR_PIXV), \
+ P_NAME_ENTRY(GAINR), \
+ P_NAME_ENTRY(GAING), \
+ P_NAME_ENTRY(GAINB), \
+ P_NAME_ENTRY(GAINGB), \
+ P_NAME_ENTRY(RSCALE_ALL), \
+ P_NAME_ENTRY(GSCALE_ALL), \
+ P_NAME_ENTRY(BSCALE_ALL), \
+ P_NAME_ENTRY(RSCALE), \
+ P_NAME_ENTRY(GSCALE), \
+ P_NAME_ENTRY(BSCALE), \
+ P_NAME_ENTRY(RSCALE_CTL), \
+ P_NAME_ENTRY(GSCALE_CTL), \
+ P_NAME_ENTRY(BSCALE_CTL), \
+ P_NAME_ENTRY(FATZERO), \
+ P_NAME_ENTRY(QUALITY), \
+ P_NAME_ENTRY(PORTRAIT), \
+ P_NAME_ENTRY(FP1000S), \
+ P_NAME_ENTRY(SENSOR_WIDTH), \
+ P_NAME_ENTRY(SENSOR_HEIGHT), \
+ P_NAME_ENTRY(COLOR_SATURATION_BLUE), \
+ P_NAME_ENTRY(COLOR_SATURATION_RED), \
+ P_NAME_ENTRY(VIGNET_AX), \
+ P_NAME_ENTRY(VIGNET_AY), \
+ P_NAME_ENTRY(VIGNET_BX), \
+ P_NAME_ENTRY(VIGNET_BY), \
+ P_NAME_ENTRY(VIGNET_C), \
+ P_NAME_ENTRY(VIGNET_SHL), \
+ P_NAME_ENTRY(SCALE_ZERO_IN), \
+ P_NAME_ENTRY(SCALE_ZERO_OUT), \
+ P_NAME_ENTRY(DGAINR), \
+ P_NAME_ENTRY(DGAING), \
+ P_NAME_ENTRY(DGAINGB), \
+ P_NAME_ENTRY(DGAINB), \
+ P_NAME_ENTRY(CORING_PAGE), \
+ P_NAME_ENTRY(TILES), \
+ P_NAME_ENTRY(SENSOR_PHASE), \
+ P_NAME_ENTRY(TEMPERATURE_PERIOD), \
+ P_NAME_ENTRY(AUTOEXP_ON), \
+ P_NAME_ENTRY(HISTWND_RWIDTH), \
+ P_NAME_ENTRY(HISTWND_RHEIGHT), \
+ P_NAME_ENTRY(HISTWND_RLEFT), \
+ P_NAME_ENTRY(HISTWND_RTOP), \
+ P_NAME_ENTRY(AUTOEXP_EXP_MAX), \
+ P_NAME_ENTRY(AUTOEXP_OVEREXP_MAX), \
+ P_NAME_ENTRY(AUTOEXP_S_PERCENT), \
+ P_NAME_ENTRY(AUTOEXP_S_INDEX), \
+ P_NAME_ENTRY(AUTOEXP_EXP), \
+ P_NAME_ENTRY(AUTOEXP_SKIP_PMIN), \
+ P_NAME_ENTRY(AUTOEXP_SKIP_PMAX), \
+ P_NAME_ENTRY(AUTOEXP_SKIP_T), \
+ P_NAME_ENTRY(HISTWND_WIDTH), \
+ P_NAME_ENTRY(HISTWND_HEIGHT), \
+ P_NAME_ENTRY(HISTWND_TOP), \
+ P_NAME_ENTRY(HISTWND_LEFT), \
+ P_NAME_ENTRY(FOCUS_SHOW), \
+ P_NAME_ENTRY(FOCUS_SHOW1), \
+ P_NAME_ENTRY(FOCUS_LEFT), \
+ P_NAME_ENTRY(FOCUS_WIDTH), \
+ P_NAME_ENTRY(FOCUS_TOP), \
+ P_NAME_ENTRY(FOCUS_HEIGHT), \
+ P_NAME_ENTRY(FOCUS_TOTWIDTH), \
+ P_NAME_ENTRY(FOCUS_FILTER), \
+ P_NAME_ENTRY(TRIG_CONDITION), \
+ P_NAME_ENTRY(TRIG_DELAY), \
+ P_NAME_ENTRY(TRIG_OUT), \
+ P_NAME_ENTRY(TRIG_PERIOD), \
+ P_NAME_ENTRY(TRIG_BITLENGTH), \
+ P_NAME_ENTRY(SKIP_FRAMES), \
+ P_NAME_ENTRY(I2C_QPERIOD), \
+ P_NAME_ENTRY(I2C_BYTES), \
+ P_NAME_ENTRY(IRQ_SMART), \
+ P_NAME_ENTRY(EXTERN_TIMESTAMP), \
+ P_NAME_ENTRY(OVERSIZE), \
+ P_NAME_ENTRY(XMIT_TIMESTAMP), \
+ P_NAME_ENTRY(GTAB_R), \
+ P_NAME_ENTRY(GTAB_G), \
+ P_NAME_ENTRY(GTAB_GB), \
+ P_NAME_ENTRY(GTAB_B), \
+ P_NAME_ENTRY(CORING_INDEX), \
+ P_NAME_ENTRY(RFOCUS_LEFT), \
+ P_NAME_ENTRY(RFOCUS_WIDTH), \
+ P_NAME_ENTRY(RFOCUS_TOP), \
+ P_NAME_ENTRY(RFOCUS_HEIGHT), \
+ P_NAME_ENTRY(SDRAM_CHN20), \
+ P_NAME_ENTRY(SDRAM_CHN21), \
+ P_NAME_ENTRY(SDRAM_CHN22), \
+ P_NAME_ENTRY(COMPRESSOR_RUN), \
+ P_NAME_ENTRY(COMPRESSOR_SINGLE), \
+ P_NAME_ENTRY(COMPMOD_BYRSH), \
+ P_NAME_ENTRY(COMPMOD_TILSH), \
+ P_NAME_ENTRY(COMPMOD_DCSUB), \
+ P_NAME_ENTRY(COMPMOD_QTAB), \
+ P_NAME_ENTRY(SENSOR_REGS), \
+ P_NAME_ENTRY(SENSOR_NUMREGS), \
+ P_NAME_ENTRY(M10359_REGS), \
+ P_NAME_ENTRY(M10359_NUMREGS), \
+ P_NAME_ENTRY(DAEMON_EN), \
+ P_NAME_ENTRY(DAEMON_EN_AUTOEXPOSURE), \
+ P_NAME_ENTRY(DAEMON_EN_STREAMER), \
+ P_NAME_ENTRY(DAEMON_EN_CCAMFTP), \
+ P_NAME_ENTRY(DAEMON_EN_CAMOGM), \
+ P_NAME_ENTRY(DAEMON_EN_AUTOCAMPARS), \
+ P_NAME_ENTRY(DAEMON_EN_TEMPERATURE), \
+ P_NAME_ENTRY(AEXP_FRACPIX), \
+ P_NAME_ENTRY(AEXP_LEVEL), \
+ P_NAME_ENTRY(HDR_DUR), \
+ P_NAME_ENTRY(HDR_VEXPOS), \
+ P_NAME_ENTRY(EXP_AHEAD), \
+ P_NAME_ENTRY(AE_THRESH), \
+ P_NAME_ENTRY(WB_THRESH), \
+ P_NAME_ENTRY(AE_PERIOD), \
+ P_NAME_ENTRY(WB_PERIOD), \
+ P_NAME_ENTRY(WB_CTRL), \
+ P_NAME_ENTRY(WB_MASK), \
+ P_NAME_ENTRY(WB_EN), \
+ P_NAME_ENTRY(WB_WHITELEV), \
+ P_NAME_ENTRY(WB_WHITEFRAC), \
+ P_NAME_ENTRY(WB_MAXWHITE), \
+ P_NAME_ENTRY(WB_SCALE_R), \
+ P_NAME_ENTRY(WB_SCALE_GB), \
+ P_NAME_ENTRY(WB_SCALE_B), \
+ P_NAME_ENTRY(HISTRQ), \
+ P_NAME_ENTRY(HISTRQ_Y), \
+ P_NAME_ENTRY(HISTRQ_C), \
+ P_NAME_ENTRY(HISTRQ_YC), \
+ P_NAME_ENTRY(PROFILE), \
+ P_NAME_ENTRY(GAIN_MIN), \
+ P_NAME_ENTRY(GAIN_MAX), \
+ P_NAME_ENTRY(GAIN_CTRL), \
+ P_NAME_ENTRY(GAIN_STEP), \
+ P_NAME_ENTRY(ANA_GAIN_ENABLE), \
+ P_NAME_ENTRY(AUTOCAMPARS_CTRL), \
+ P_NAME_ENTRY(AUTOCAMPARS_GROUPS), \
+ P_NAME_ENTRY(AUTOCAMPARS_PAGE), \
+ P_NAME_ENTRY(AUTOCAMPARS_CMD), \
+ P_NAME_ENTRY(FTP_PERIOD), \
+ P_NAME_ENTRY(FTP_TIMEOUT), \
+ P_NAME_ENTRY(FTP_UPDATE), \
+ P_NAME_ENTRY(STROP_MCAST_EN), \
+ P_NAME_ENTRY(STROP_MCAST_IP), \
+ P_NAME_ENTRY(STROP_MCAST_PORT), \
+ P_NAME_ENTRY(STROP_MCAST_TTL), \
+ P_NAME_ENTRY(STROP_AUDIO_EN), \
+ P_NAME_ENTRY(STROP_AUDIO_RATE), \
+ P_NAME_ENTRY(STROP_AUDIO_CHANNEL), \
+ P_NAME_ENTRY(STROP_FRAMES_SKIP), \
+ P_NAME_ENTRY(AUDIO_CAPTURE_VOLUME), \
+ P_NAME_ENTRY(MULTISENS_EN), \
+ P_NAME_ENTRY(MULTI_PHASE_SDRAM), \
+ P_NAME_ENTRY(MULTI_PHASE1), \
+ P_NAME_ENTRY(MULTI_PHASE2), \
+ P_NAME_ENTRY(MULTI_PHASE3), \
+ P_NAME_ENTRY(MULTI_SEQUENCE), \
+ P_NAME_ENTRY(MULTI_FLIPH), \
+ P_NAME_ENTRY(MULTI_FLIPV), \
+ P_NAME_ENTRY(MULTI_MODE), \
+ P_NAME_ENTRY(MULTI_HBLANK), \
+ P_NAME_ENTRY(MULTI_VBLANK), \
+ P_NAME_ENTRY(MULTI_CWIDTH), \
+ P_NAME_ENTRY(MULTI_CHEIGHT), \
+ P_NAME_ENTRY(MULTI_CLEFT), \
+ P_NAME_ENTRY(MULTI_CTOP), \
+ P_NAME_ENTRY(MULTI_CFLIPH), \
+ P_NAME_ENTRY(MULTI_CFLIPV), \
+ P_NAME_ENTRY(MULTI_VBLANK), \
+ P_NAME_ENTRY(MULTI_WOI), \
+ P_NAME_ENTRY(MULTI_WIDTH1), \
+ P_NAME_ENTRY(MULTI_WIDTH2), \
+ P_NAME_ENTRY(MULTI_WIDTH3), \
+ P_NAME_ENTRY(MULTI_HEIGHT1), \
+ P_NAME_ENTRY(MULTI_HEIGHT2), \
+ P_NAME_ENTRY(MULTI_HEIGHT3), \
+ P_NAME_ENTRY(MULTI_LEFT1), \
+ P_NAME_ENTRY(MULTI_LEFT2), \
+ P_NAME_ENTRY(MULTI_LEFT3), \
+ P_NAME_ENTRY(MULTI_TOP1), \
+ P_NAME_ENTRY(MULTI_TOP2), \
+ P_NAME_ENTRY(MULTI_TOP3), \
+ P_NAME_ENTRY(MULTI_TOPSENSOR), \
+ P_NAME_ENTRY(MULTI_SELECTED), \
+ P_NAME_ENTRY(MULTI_MODE_FLIPS), \
+ P_NAME_ENTRY(MULTI_HEIGHT_BLANK1), \
+ P_NAME_ENTRY(MULTI_HEIGHT_BLANK2), \
+ G_NAME_ENTRY(DEBUG), \
+ G_NAME_ENTRY(TEST_CTL_BITS), \
+ G_NAME_ENTRY(CABLE_TIM), \
+ G_NAME_ENTRY(FPGA_TIM0), \
+ G_NAME_ENTRY(FPGA_TIM1), \
+ G_NAME_ENTRY(SENS_AVAIL), \
+ G_NAME_ENTRY(DLY359_OUT), \
+ G_NAME_ENTRY(DLY359_P1), \
+ G_NAME_ENTRY(DLY359_P2), \
+ G_NAME_ENTRY(DLY359_P3), \
+ G_NAME_ENTRY(DLY359_C1), \
+ G_NAME_ENTRY(DLY359_C2), \
+ G_NAME_ENTRY(DLY359_C3), \
+ G_NAME_ENTRY(MULTI_CFG), \
+ G_NAME_ENTRY(MULTI_REGSM), \
+ G_NAME_ENTRY(FRAME_SIZE), \
+ G_NAME_ENTRY(MULTI_NUM), \
+ G_NAME_ENTRY(MAXAHEAD), \
+ G_NAME_ENTRY(THIS_FRAME), \
+ G_NAME_ENTRY(CIRCBUFSIZE), \
+ G_NAME_ENTRY(FREECIRCBUF), \
+ G_NAME_ENTRY(CIRCBUFWP), \
+ G_NAME_ENTRY(CIRCBUFRP), \
+ G_NAME_ENTRY(SECONDS), \
+ G_NAME_ENTRY(MICROSECONDS), \
+ G_NAME_ENTRY(CALLNASAP), \
+ G_NAME_ENTRY(CALLNEXT), \
+ G_NAME_ENTRY(NEXT_AE_FRAME), \
+ G_NAME_ENTRY(NEXT_WB_FRAME), \
+ G_NAME_ENTRY(HIST_DIM_01), \
+ G_NAME_ENTRY(HIST_DIM_23), \
+ G_NAME_ENTRY(AE_INTEGERR), \
+ G_NAME_ENTRY(WB_INTEGERR), \
+ G_NAME_ENTRY(TASKLET_CTL), \
+ G_NAME_ENTRY(GFOCUS_VALUE), \
+ G_NAME_ENTRY(HISTMODE_Y), \
+ G_NAME_ENTRY(HISTMODE_C), \
+ G_NAME_ENTRY(HIST_LAST_INDEX), \
+ G_NAME_ENTRY(HIST_Y_FRAME), \
+ G_NAME_ENTRY(HIST_C_FRAME), \
+ G_NAME_ENTRY(SKIP_DIFF_FRAME), \
+ G_NAME_ENTRY(FTP_NEXT_TIME), \
+ G_NAME_ENTRY(DAEMON_ERR), \
+ G_NAME_ENTRY(DAEMON_RETCODE), \
+ G_NAME_ENTRY(PROFILING_EN), \
+ G_NAME_ENTRY(TEMPERATURE01), \
+ G_NAME_ENTRY(TEMPERATURE23), \
+ G_NAME_ENTRY(SENSOR_CALIB) \
+};
+
+#define ONCHANGE_NAME_ENTRY(y) { onchange_##y, #y }
+#define DEFINE_ONCHANGE_NAMES(x) struct p_names_t x[]= { \
+ ONCHANGE_NAME_ENTRY(recalcseq), \
+ ONCHANGE_NAME_ENTRY(detectsensor), \
+ ONCHANGE_NAME_ENTRY(sensorphase), \
+ ONCHANGE_NAME_ENTRY(i2c), \
+ ONCHANGE_NAME_ENTRY(sensorregs), \
+ ONCHANGE_NAME_ENTRY(initsensor), \
+ ONCHANGE_NAME_ENTRY(afterinit), \
+ ONCHANGE_NAME_ENTRY(window), \
+ ONCHANGE_NAME_ENTRY(window_safe), \
+ ONCHANGE_NAME_ENTRY(gains), \
+ ONCHANGE_NAME_ENTRY(triggermode), \
+ ONCHANGE_NAME_ENTRY(sensorin), \
+ ONCHANGE_NAME_ENTRY(sensorstop), \
+ ONCHANGE_NAME_ENTRY(sensorrun), \
+ ONCHANGE_NAME_ENTRY(gamma), \
+ ONCHANGE_NAME_ENTRY(hist), \
+ ONCHANGE_NAME_ENTRY(aexp), \
+ ONCHANGE_NAME_ENTRY(quality), \
+ ONCHANGE_NAME_ENTRY(memsensor), \
+ ONCHANGE_NAME_ENTRY(memcompressor), \
+ ONCHANGE_NAME_ENTRY(limitfps), \
+ ONCHANGE_NAME_ENTRY(exposure), \
+ ONCHANGE_NAME_ENTRY(compmode), \
+ ONCHANGE_NAME_ENTRY(focusmode), \
+ ONCHANGE_NAME_ENTRY(trigseq), \
+ ONCHANGE_NAME_ENTRY(irq), \
+ ONCHANGE_NAME_ENTRY(comprestart), \
+ ONCHANGE_NAME_ENTRY(compstop), \
+ ONCHANGE_NAME_ENTRY(compctl), \
+ ONCHANGE_NAME_ENTRY(gammaload), \
+ ONCHANGE_NAME_ENTRY(prescal), \
+ ONCHANGE_NAME_ENTRY(multisens) \
+};
+
+
+
+/* i2c errors */
+#ifndef ERR_I2C_SCL_ST0
+ #define ERR_I2C_SCL_ST0 1
+ #define ERR_I2C_SDA_ST0 2
+ #define ERR_I2C_SCL_ST1 4
+ #define ERR_I2C_SDA_ST1 8
+ #define ERR_I2C_SCL_NOPULLUP 16
+ #define ERR_I2C_SDA_NOPULLUP 32
+
+/* i2c_diagnose called by i2c_start (?) could not find any problems. Try again start */
+ #define ERR_I2C_NOTDETECTED 64
+ #define ERR_I2C_SHORT 128
+ #define ERR_I2C_BSY 256
+ #define ERR_I2C_NACK 512
+#endif
+
+
+/* supported ioctl _IOC_NR's */
+#define IO_CCAM_SET_EXT_EXPOSURE 0x06
+#define IO_CCAM_MONITOR_SEQ 0x07
+
+//#define IO_CCAM_STOP_DMA 0x08
+//#define IO_CCAM_START_DMA 0x09 // just starts DMA - descriptor list should be set eatlier
+//#define IO_CCAM_START_RAW 0x0a // Programs DMA descriptor list according to current frame size, FPGA registers and starts DMA
+
+/// MOST ARE OBSOLETE - WILL REMOVE WHEN UPDATING STREAMERS
+#define IO_CCAM_JPEG 0x08 /// JPEG-compressor related commands
+
+#define JPEG_CMD_RESET 0x00 /// Resets pointers - both acquisition and readout
+//#define JPEG_CMD_ARM 0x01 /// Prepare compressor to read next frame acquired
+#define JPEG_CMD_GET 0x02 /// Read current page (will return empty (and length==0) if not ready
+#define JPEG_CMD_FORGET 0x03 /// increment read frame pointer
+#define JPEG_CMD_CATCHUP 0x04 /// set read pointer to the last acquired (or acquiring if none is acquired yet)
+#define JPEG_CMD_ACQUIRE 0x05 /// acquire and compress one frame
+#define JPEG_CMD_SAVE_RP 0x06 /// save read pointer
+#define JPEG_CMD_RESTORE_RP 0x07 /// restore read pointer
+#define JPEG_CMD_N_DONE 0x08 /// return 1 if no more frames to be acquired (frame number)
+#define JPEG_CMD_L_DONE 0x09 /// return 1 if no more frames to be acquired (total length)
+#define JPEG_CMD_START 0x0a /// start constant compression mode
+#define JPEG_CMD_STOP 0x0b /// stop constant compression mode (may want to wait for CAMSEQ_DONE)
+#define JPEG_CMD_FRAMES 0x0c /// returns number of frames in buffer, (re)uilds frames chain
+#define JPEG_CMD_JUST_STOP 0x0d /// just stop - don't start cycle if was allready off!
+#define JPEG_CMD_DUMP 0x0f /// printk all static data/tables
+#define JPEG_CMD_RESET0 0x10 /// same as JPEG_CMD_RESET, but non-zero, to be used from lseek (SEEK_END)
+
+//#define PROGRAM_SENSOR_0 0x11 /// programSensor(0) - to be used from lseek (SEEK_END)
+//#define PROGRAM_SENSOR_1 0x12 /// programSensor(1) - to be used from lseek (SEEK_END)
+/// Compressor state now applies only to particular frame
+//#define LSEEK_CAMSEQSTATE 0x13 /// return camSeqState - to be used from lseek (SEEK_END)
+#define LSEEK_GAMMA_INIT 1 // SEEK_END LSEEK_GAMMA_INIT to initialize all the gamma data structures
+#define LSEEK_GAMMA_ISCURRENT 2 // SEEK_END to check if the selected node(pointed by file pointer) is current - returns 0 if not, otherwise - node index
+
+// parameters for lseek circbuf
+#define LSEEK_CIRC_TORP 1
+#define LSEEK_CIRC_TOWP 2
+#define LSEEK_CIRC_PREV 3
+#define LSEEK_CIRC_NEXT 4
+#define LSEEK_CIRC_LAST 5
+#define LSEEK_CIRC_FIRST 6
+#define LSEEK_CIRC_SCND 7
+#define LSEEK_CIRC_SETP 8
+#define LSEEK_CIRC_VALID 9
+#define LSEEK_CIRC_READY 10
+#define LSEEK_CIRC_WAIT 11
+#define LSEEK_CIRC_FREE 12
+#define LSEEK_CIRC_USED 13
+
+#define LSEEK_HUFFMAN_DC0 1
+#define LSEEK_HUFFMAN_AC0 2
+#define LSEEK_HUFFMAN_DC1 3
+#define LSEEK_HUFFMAN_AC1 4
+#define LSEEK_HUFFMAN_FPGATAB 5
+#define LSEEK_HUFFMAN_DEFAULT 6
+#define LSEEK_HUFFMAN_FPGACALC 7
+#define LSEEK_HUFFMAN_FPGAPGM 8
+
+//#define LSEEK_RESET_SENSOR 0x14 /// reset sensor and FPGA - next time will reprogram it
+//#define LSEEK_INIT_SENSOR 0x15 /// initialise SDRAM and sensor if it is not programmed yet (or reset)
+
+#define LSEEK_GET_FPGA_TIME 0x16 /// get FPGA timer to G_SECONDS, G_MICROSECONDS
+#define LSEEK_SET_FPGA_TIME 0x17 /// set FPGA timer to G_SECONDS, G_MICROSECONDS
+
+//#define LSEEK_FLUSH_CACHE 0x18 // workaround for Axis mmap cache coherency problems - flush all cache (8KB)
+#define LSEEK_AUTOEXP_SET 0x19 /// set autoexposure parameters
+#define LSEEK_AUTOEXP_GET 0x1a /// copy window and exposure parameters to autoexp_state
+#define LSEEK_TRIGGER_PGM 0x1b /// program trigger parameters
+#define LSEEK_I2C_PGM 0x1c /// program hardware i2c speed/bytes
+#define LSEEK_IRQ_SMART_PGM 0x1d /// program "smart" irq modes (+1 - wait VACT, +2 - wait dma fifo)
+#define LSEEK_EXTERN_TIMESTAMP_PGM 0x1e /// 1 - use external timestamps if available
+#define LSEEK_DMA_INIT 0x1f /// (re-) initialize ETRAX DMA for compressor
+#define LSEEK_DMA_STOP 0x20 /// STOP ETRAX DMA
+#define LSEEK_DMA_START 0x21 /// STARTETRAX DMA
+#define LSEEK_COMPRESSOR_RESET 0x22 /// reset compressor and pointers
+#define LSEEK_INTERRUPT_OFF 0x23 /// disable camera interrupts
+#define LSEEK_INTERRUPT_ON 0x24 /// enable camera interrupts
+
+#define LSEEK_FRAMEPARS_INIT 0x25 /// reset hardware sequencers, init framepars structure
+#define LSEEK_SENSORPROC 0x26 /// process modified parameters in frame 0 (to start sensor detection)
+
+#define LSEEK_FRAME_RESET 0x27 /// reset absolute frame number to avoid integer overflow
+
+///Histograms related commands
+#define LSEEK_HIST_WAIT_Y 0x28 /// set histogram waiting for the Y (actually G1) histogram (default after open)
+#define LSEEK_HIST_WAIT_C 0x29 /// set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too
+#define LSEEK_HIST_REQ_EN 0x2a /// enable histogram request when reading histogram (safer, but may be not desirable in HDR mode) - default after opening
+#define LSEEK_HIST_REQ_DIS 0x2b /// disable histogram request when reading histogram - will read latest available relying it is available
+#define LSEEK_HIST_NEEDED 0x10000 /// set histogram "needed" mask - 0x10000..0x1ffff
+//#define LSEEK_HIST_WAIT_AE 0x2a /// wait for autoexposure enabled
+
+#define LSEEK_DAEMON_FRAME 0x80 /// LSEEK_DAEMON_FRAME+B wait for frame interrupt and corresponding bit (B) in P_DAEMON_EN is set
+#define LSEEK_DAEMON_CIRCBUF 0xa0 /// LSEEK_DAEMON_FRAME+B wait for frame compressed interrupt and corresponding bit (B) in P_DAEMON_EN is set
+#define LSEEK_DAEMON_HIST_Y 0xc0 /// LSEEK_DAEMON_FRAME+B wait for histogram Y ready and corresponding bit (B) in P_DAEMON_EN is set
+#define LSEEK_DAEMON_HIST_C 0xe0 /// LSEEK_DAEMON_FRAME+B wait for all histograms ready and corresponding bit (B) in P_DAEMON_EN is set
+
+
+#define LSEEK_FRAME_WAIT_REL 0x100 /// LSEEK_WAIT_FRAME_REL+N - skip N frames (0=128.
+ /// If the High byte is zero, it is treated as Q^0x80 (Q|=(Q^0x80)<<8) for compatibility
+ /// with a standard single-byte Q value
+/// updated in 8.0.8.37 - bit 7 in quality2 means "portrait mode"
+ unsigned char color; /// color mode //18
+ unsigned char byrshift; /// bayer shift in compressor //19
+ unsigned short width; /// frame width, pixels 20-21 - NOTE: should be 20-21
+ unsigned short height; /// frame height, pixels 22-23
+
+/*24 *//// unsigned char bindec_hor; //! ((bh-1) << 4) | (dh-1) & 0xf (binning/decimation horizontal, 1..16 for each)
+/*25 *//// unsigned char bindec_vert; //! ((bv-1) << 4) | (dv-1) & 0xf (binning/decimation vertical , 1..16 for each)
+/*24-25*/ unsigned short meta_index; //! index of the linked meta page
+
+/*26-27*/ unsigned short signffff; //! should be 0xffff - it will be a signature that JPEG data was not overwritten,
+ //! JPEG bitstream can not have two 0xff after each other
+ union {
+/*28-31*/ unsigned long timestamp_sec ; //! number of seconds since 1970 till the start of the frame exposure
+/*28-31*/ unsigned long frame_length ; //! JPEG frame length in circular buffer, bytes
+ };
+/*32-35*/ unsigned long timestamp_usec; //! number of microseconds to add
+};
+
+struct i2c_timing_t {
+ unsigned char scl_high; //0x02, //! SCL high:
+ unsigned char scl_low; //0x02, //! SCL low:
+ unsigned char slave2master; //0x01, //! slave -> master
+ unsigned char master2slave; //0x01, //! master -> slave
+ unsigned char filter_sda; //0x07, //! filter SDA read data by testing multiple times - currently just zero/non zero
+ unsigned char filter_scl; //0x07};//! filter SCL read data by testing multiple times - currently just zero/non zero
+};
+
+/// Gamma data for one component, including direct and reverse tables, hash (i.e. black level+gamma) and links for caching
+#define GAMMA_CACHE_NUMBER 256 // number of gamma-tables cached
+#define GAMMA_VALID_MASK 1 // table is calculated, matches given hash/scale
+#define GAMMA_VALID_REVERSE 2 // reverse table is calculated for the given hash/scale
+#define GAMMA_FPGA_MASK 4 // gamma-table encoded for the FPGA is valid
+//#define GAMMA_LOCK_MASK 8 // table is locked until programmed to FPGA - now locked is a separate member
+
+// bits passed in int mode
+#define GAMMA_MODE_NOT_NICE 1 // if set, no interrupts will be enabled between steps, whole operation is atomic
+#define GAMMA_MODE_NEED_REVERSE 2 // reverse gamma table is needed
+#define GAMMA_MODE_HARDWARE 4 // the table is needed to program FPGA: fpga-encoded table will be calculated (if not yet),
+#define GAMMA_MODE_LOCK 8 // Lock the table for the specified color (used from irq/tasklet - it is needed because all 4 tables in FPGA have to be overwritten at once)
+
+#define GAMMA_SCALE_SHIFT 10 // when scaling - shift right by GAMMA_SCALE_SHIFT (treat scale as 6.10)
+#define GAMMA_SCLALE_1 ( 1 << GAMMA_SCALE_SHIFT ) // gamma scale 1.0 - 0x400
+struct gamma_stuct_t {
+ union {
+ unsigned long hash32; /// fully identifies current table
+ struct {
+ unsigned short scale; /// 6.10: 0x400 is 1.0 scale (>=1.0) is applied in the driver, saturating result
+ union {
+ unsigned short hash16; /// scale-independent part of the table (tables themselves are calculated outside of the driver)
+ struct {
+ unsigned char gamma; /// "gamma" in the range 0.0 ... 2.55
+ unsigned char black; /// black level to subtract (scaled to full scale) from the input data
+ };
+ };
+ };
+ };
+ int valid; /// 0 - table invalid, 1 - table valid +2 for table locked (until sent to FPGA)
+// int locked; /// bit frame+ (color<<3) locked for color/frame
+ int locked; /// NOTE: Changed to just color locked for color
+ int this_non_scaled; // 0 for non-scaled, others - (for scaled) - pointer to the corresponding non-scaled
+ union { /// used in head (element 0) and non-scaled chain (not used in scaled)
+ struct { /// element 0 - heads of the chains
+ int oldest_non_scaled; //
+ int newest_non_scaled; //
+ };
+ struct { /// non-scaled (gamma data is full 16-bit)
+ int newer_non_scaled; // table type (non-scaled prototype) used later than this one
+ int older_non_scaled; // table type (non-scaled prototype) used before this one
+ };
+ };
+ union { /// used in head (element 0) and scaled chain (not used in non-scaled) (or maybe it will be used?)
+ struct { /// element 0 - heads of the chains
+ int oldest_all; //
+ int newest_all; //
+ };
+ struct { /// scaled (gamma data is hardware defined 10 bit)
+ int newer_all; /// newer in a single chain of all scaled tables, regardless of the prototype
+ int older_all; /// older in a single chain of all scaled tables, regardless of the prototype
+ /// *_all also includes yet unused nodes (after init)
+ };
+ };
+ union { /// used in non-scaled and scaled, not in the head (element 0)
+ struct { /// non-scaled
+ int oldest_scaled; // oldest derivative of this prototype (scaled)
+ int newest_scaled; // newest derivative of this prototype (scaled)
+ };
+ struct { /// scaled (gamma data is hardware defined 10 bit)
+ int newer_scaled; // table type (non-scaled prototype) used later than this one
+ int older_scaled; // table type (non-scaled prototype) used before this one
+ };
+ struct { /// reuse in the head (element 0) - to make this variable visible through mmap to PHP (for debugging)
+ int non_scaled_length; // current number of different hash values
+ int num_locked; // number of nodes locked (until table sent to FPGA)
+ };
+ };
+ union {
+ struct {
+ unsigned short direct[257]; // "Gamma" table, 16-bit for both non-scaled prototypes and scaled, 0..0xffff range (hardware will use less)
+ unsigned short dummy1; // to have it 32-bit aligned
+// unsigned short reverse[256]; // reverse table to speed-up reversing (still need interpolation).Index - most significant 8 bits, data - largest direct argument...
+ unsigned char reverse[256]; /// reverse table to speed-up reversing. No division, but needs interpolation by the application
+ unsigned long fpga[256]; // data encoded for FPGA "gamma" table (18 bits, "floating point")
+ };
+ struct {
+// int locked_col_frame[4 * PARS_FRAMES]; //index of the table to load to color/frame (should be locked, until unlocked)
+ int locked_color[4]; /// NOTE: Changed to just color (locked last written to FPGA - maybe needed again, as the FPGA needs all table to be overwritten - two pages)
+// int other [129+128+256 -(4 * PARS_FRAMES)];
+// int other [129+64+256 -(4 * PARS_FRAMES)];
+ int other [129+64+256 -4];
+ };
+ };
+};
+
+///histograms related structure
+#define HISTOGRAM_CACHE_NUMBER 8 // number of frames histograms are kept after acquisition (should be 2^n)
+#define COLOR_RED 0
+#define COLOR_GREEN1 1
+#define COLOR_GREEN2 2
+#define COLOR_BLUE 3
+
+
+#define COLOR_Y_NUMBER COLOR_GREEN1 // green1 (index=1) is used as Y color (i.e. for auto exposure). Histogram for is calculated first (or only)
+/*
+/// the following 8 values should go in the same sequence as fields in the histogram page
+#define P_FRAME 136 // Frame number (reset with JPEG pointers) -(read only)
+#define P_GAINR 137 // R channel gain 8.16 (0x10000 - 1.0). Combines both analog gain and digital scaling
+#define P_GAING 138 // G channel gain ("red line")
+#define P_GAINGB 139 // G channel gain ("blue line")
+#define P_GAINB 140 // B channel gain
+#define P_EXPOS 141 //P_RW_EXPOS 1 exposure time - now in microseconds?
+#define P_VEXPOS 142 // video exposure (if 0 - use P_RW_EXPOS in ms)
+#define P_FOCUS_VALUE 143 // (readonly) - sum of all blocks focus values inside focus WOI
+
+*/
+
+#define HISTOGRAM_TABLE_OFFSET 52 /// Histogram tables data starts 44 bytes from the histogram page structure (for PHP raw histogram)
+///TODO: Update when histogram_stuct_t is changed
+struct histogram_stuct_t {
+ unsigned long frame; /// frame number correspoding to the current histogram
+/// Color gains for the frame of the histogram
+ union {
+ unsigned long gains[4];
+ struct {
+ unsigned long gain_r;
+ unsigned long gain_g;
+ unsigned long gain_gb;
+ unsigned long gain_b;
+ };
+ };
+ unsigned long expos; /// Exposure time (usec) for the frame of the histogram
+ unsigned long vexpos; /// number of exposure lines for the frame of the histogram
+ unsigned long focus; /// sum of all blocks focus values inside focus WOI
+ unsigned long valid; /// bit mask of valid arrays (0 - hist_r, ... ,4-cumul_hist_r, ..., 11 - percentile_b)
+
+/// Gamma tables hash values for the frame of the histogram
+ union {
+ unsigned long gtab[4];
+ struct {
+ unsigned long gtab_r;
+ unsigned long gtab_g;
+ unsigned long gtab_gb;
+ unsigned long gtab_b;
+ };
+ };
+/// Direct histograms, loaded from the FPGA
+ union {
+ unsigned long hist[1024] ; /// All 4 histograms
+ struct {
+ unsigned long hist_r [256] ; /// Histogram for the red component
+ unsigned long hist_g [256] ; /// Histogram for the first green component (in the "red" line)
+ unsigned long hist_gb[256] ; /// Histogram for the second green component (in the "blue" line)
+ unsigned long hist_b [256] ; /// Histogram for blue component
+ };
+ };
+/// Direct cumulative histograms, calculated from the loaded from the FPGA
+ union {
+ unsigned long cumul_hist[1024] ; /// All 4 cumulative histograms
+ struct {
+ unsigned long cumul_hist_r [256] ; /// Cumulative histogram for the red component
+ unsigned long cumul_hist_g [256] ; /// Cumulative histogram for the first green component (in the "red" line)
+ unsigned long cumul_hist_gb[256] ; /// Cumulative histogram for the second green component (in the "blue" line)
+ unsigned long cumul_hist_b [256] ; /// Cumulative histogram for blue component
+ };
+ };
+/// Calculated reverse cumulative histograms (~percentiles) - for the given 1 byte input X (0 - 1/256 of all pixels, ..., 255 - all pixels)
+/// returns threshold value P (0..255), so that number of pixels with value less than x is less or equal to (P/256)*total_number_of_pixels,
+/// and number of pixels with value less than (x+1) is greater than (P/256)*total_number_of_pixels,
+/// P(0)=0, P(256)=256 /not included in the table/
+/// percentiles arrays are calculated without division for each element, interpolation (with division) will be done only for the value of interest
+/// on demand, in the user space.
+/// NOTE: - argument is _output_ value (after gamma-correction), reverse gamma table is needed to relate percentiles to amount of light (proportional to exposure)
+ union {
+ unsigned char percentile[1024] ; /// All 4 percentiles
+ struct {
+ unsigned char percentile_r [256] ; /// percentile for the red component
+ unsigned char percentile_g [256] ; /// percentile for the first green component (in the "red" line)
+ unsigned char percentile_gb[256] ; /// percentile for the second green component (in the "blue" line)
+ unsigned char percentile_b [256] ; /// percentile for the blue component
+ };
+ };
+
+};
+
+/// Used to provide encoded huffman tables. Those tables (4 of them) will be used in the output JPEG/JP4 files
+/// and whill be programmed to the FPGA
+struct huffman_encoded_t {
+ unsigned char bits[16]; /// number of symbols with length k+1
+ unsigned char huffval[256]; /// The symbols, in order of incr code length
+};
+
+/// All other integer constants exported to PHP space (C:"CONSTANT" -> PHP:"ELPHEL_CONST_CONSTANT)
+#define CONST_NAME_ENTRY(y) { y, #y }
+#define DEFINE_CONST_NAMES(x) struct p_names_t x[]= { \
+ CONST_NAME_ENTRY(SENSOR_RUN_STOP), \
+ CONST_NAME_ENTRY(SENSOR_RUN_SINGLE), \
+ CONST_NAME_ENTRY(SENSOR_RUN_CONT), \
+ CONST_NAME_ENTRY(COMPRESSOR_RUN_STOP), \
+ CONST_NAME_ENTRY(COMPRESSOR_RUN_SINGLE), \
+ CONST_NAME_ENTRY(COMPRESSOR_RUN_CONT), \
+ CONST_NAME_ENTRY(TASKLET_CTL_PGM), \
+ CONST_NAME_ENTRY(TASKLET_CTL_IGNPAST), \
+ CONST_NAME_ENTRY(TASKLET_CTL_NOSAME), \
+ CONST_NAME_ENTRY(COLORMODE_MONO6), \
+ CONST_NAME_ENTRY(COLORMODE_COLOR), \
+ CONST_NAME_ENTRY(COLORMODE_JP46), \
+ CONST_NAME_ENTRY(COLORMODE_JP46DC), \
+ CONST_NAME_ENTRY(COLORMODE_COLOR20), \
+ CONST_NAME_ENTRY(COLORMODE_JP4), \
+ CONST_NAME_ENTRY(COLORMODE_JP4DC), \
+ CONST_NAME_ENTRY(COLORMODE_JP4DIFF), \
+ CONST_NAME_ENTRY(COLORMODE_JP4HDR), \
+ CONST_NAME_ENTRY(COLORMODE_JP4DIFF2), \
+ CONST_NAME_ENTRY(COLORMODE_JP4HDR2), \
+ CONST_NAME_ENTRY(COLORMODE_MONO4), \
+ CONST_NAME_ENTRY(PARS_FRAMES), \
+ CONST_NAME_ENTRY(PARS_FRAMES_MASK), \
+ CONST_NAME_ENTRY(PASTPARS_SAVE_ENTRIES), \
+ CONST_NAME_ENTRY(PASTPARS_SAVE_ENTRIES_MASK), \
+ CONST_NAME_ENTRY(FRAMEPAIR_FORCE_NEW), \
+ CONST_NAME_ENTRY(FRAMEPAIR_FORCE_PROC), \
+ CONST_NAME_ENTRY(FRAMEPAIR_FORCE_NEWPROC), \
+ CONST_NAME_ENTRY(FRAMEPAIR_JUST_THIS), \
+ CONST_NAME_ENTRY(FRAMEPAR_GLOBALS), \
+ CONST_NAME_ENTRY(FRAMEPAIR_FRAME_FUNC), \
+ CONST_NAME_ENTRY(FRAMEPAIR_MASK_BYTES), \
+ CONST_NAME_ENTRY(FRAMEPAIR_BYTE0), \
+ CONST_NAME_ENTRY(FRAMEPAIR_BYTE1), \
+ CONST_NAME_ENTRY(FRAMEPAIR_BYTE2), \
+ CONST_NAME_ENTRY(FRAMEPAIR_BYTE3), \
+ CONST_NAME_ENTRY(FRAMEPAIR_WORD0), \
+ CONST_NAME_ENTRY(FRAMEPAIR_WORD1), \
+ CONST_NAME_ENTRY(ERR_FRAMEPARS_TOOEARLY), \
+ CONST_NAME_ENTRY(ERR_FRAMEPARS_TOOLATE), \
+ CONST_NAME_ENTRY(ERR_FRAMEPARS_BADINDEX), \
+ CONST_NAME_ENTRY(DAEMON_BIT_AUTOEXPOSURE), \
+ CONST_NAME_ENTRY(DAEMON_BIT_STREAMER), \
+ CONST_NAME_ENTRY(DAEMON_BIT_CCAMFTP), \
+ CONST_NAME_ENTRY(DAEMON_BIT_CAMOGM), \
+ CONST_NAME_ENTRY(DAEMON_BIT_AUTOCAMPARS), \
+ CONST_NAME_ENTRY(ERR_PGM_TRYAGAINLATER), \
+ CONST_NAME_ENTRY(FRAMEPARS_SETFRAME), \
+ CONST_NAME_ENTRY(FRAMEPARS_SETFRAMEREL), \
+ CONST_NAME_ENTRY(FRAMEPARS_SETLATENCY), \
+ CONST_NAME_ENTRY(FRAMEPARS_SETFPGATIME), \
+ CONST_NAME_ENTRY(FRAMEPARS_GETFPGATIME), \
+ CONST_NAME_ENTRY(GAMMA_CACHE_NUMBER), \
+ CONST_NAME_ENTRY(GAMMA_VALID_MASK), \
+ CONST_NAME_ENTRY(GAMMA_VALID_REVERSE), \
+ CONST_NAME_ENTRY(GAMMA_FPGA_MASK), \
+ CONST_NAME_ENTRY(GAMMA_MODE_NOT_NICE), \
+ CONST_NAME_ENTRY(GAMMA_MODE_NEED_REVERSE), \
+ CONST_NAME_ENTRY(GAMMA_MODE_HARDWARE), \
+ CONST_NAME_ENTRY(GAMMA_MODE_LOCK), \
+ CONST_NAME_ENTRY(GAMMA_SCALE_SHIFT), \
+ CONST_NAME_ENTRY(GAMMA_SCLALE_1), \
+ CONST_NAME_ENTRY(HISTOGRAM_CACHE_NUMBER), \
+ CONST_NAME_ENTRY(COLOR_Y_NUMBER), \
+ CONST_NAME_ENTRY(FRAME_DEAFAULT_AHEAD), \
+ CONST_NAME_ENTRY(AUTOCAMPARS_CMD_RESTORE), \
+ CONST_NAME_ENTRY(AUTOCAMPARS_CMD_SAVE), \
+ CONST_NAME_ENTRY(AUTOCAMPARS_CMD_DFLT), \
+ CONST_NAME_ENTRY(AUTOCAMPARS_CMD_SAVEDFLT), \
+ CONST_NAME_ENTRY(AUTOCAMPARS_CMD_INIT), \
+ CONST_NAME_ENTRY(COLOR_RED), \
+ CONST_NAME_ENTRY(COLOR_GREEN1), \
+ CONST_NAME_ENTRY(COLOR_GREEN2), \
+ CONST_NAME_ENTRY(COLOR_BLUE), \
+ CONST_NAME_ENTRY(CSCALES_WIDTH), \
+ CONST_NAME_ENTRY(CSCALES_CTL_BIT), \
+ CONST_NAME_ENTRY(CSCALES_CTL_WIDTH), \
+ CONST_NAME_ENTRY(CSCALES_CTL_NORMAL), \
+ CONST_NAME_ENTRY(CSCALES_CTL_RECALC), \
+ CONST_NAME_ENTRY(CSCALES_CTL_FOLLOW), \
+ CONST_NAME_ENTRY(CSCALES_CTL_DISABLE), \
+ CONST_NAME_ENTRY(HISTOGRAM_TABLE_OFFSET) \
+};
+/*
+///NOTE page 0 is write protected, page 15 (0x0f) is "default" page
+#define AUTOCAMPARS_CMD_RESTORE 1 /// restore specified groups of parameters from the specified page
+#define AUTOCAMPARS_CMD_SAVE 2 /// save all current parameters to the specified group (page 0 is write-protected)
+#define AUTOCAMPARS_CMD_DFLT 3 /// make selected page the default one (used at startup), page 0 OK
+#define AUTOCAMPARS_CMD_SAVEDFLT 4 /// save all current parameters to the specified group (page 0 is write-protected) and make it default (used at startup)
+#define AUTOCAMPARS_CMD_INIT 5 /// reset sensor/sequencers, restore all parameters from the specified page
+
+*/
+
+#endif /* _ASM_CMOSCAM_H */
diff --git a/src/include/elphel/driver_numbers.h b/src/include/elphel/driver_numbers.h
new file mode 100644
index 0000000000000000000000000000000000000000..64b36805f4a649c5a75594ebe14a171fced0155b
--- /dev/null
+++ b/src/include/elphel/driver_numbers.h
@@ -0,0 +1,69 @@
+/// driver_numbers.h
+/// see packages/devices/elphel/Makefile - major numbers should match
+
+//#define CMOSCAM_MAJOR 126
+#define X3X3_EXIF_MAJOR 125
+#define ELPHEL_MAJOR 126
+#define STREAM_MAJOR 127
+#define FPGA_MAJOR 129
+#define FPGA_JTAG_MAJOR 132
+#define FPGA_CLOCK_MAJOR 133
+#define X3X3_I2C_MAJOR 134
+#define CIRCBUF_MAJOR 135
+//#define FRAMEPARS_MAJOR 136
+#define FRAMEPARS_MAJOR 130
+#define GAMMAS_MAJOR 137
+#define HISTOGRAMS_MAJOR 138
+//#define IMAGERAW_MAJOR 139
+#define IMAGERAW_MAJOR 131
+#define IMAGEACQ_MAJOR 140
+#define IMU_MAJOR 141
+
+
+/// MINORS
+#define IMU_MINOR 1
+#define IMU_CTL_MINOR 2
+#define IMAGERAW_MINOR_FRAME 1
+#define IMAGERAW_MINOR_FPN 2
+#define IMAGERAW_MINOR_UNLOCK 3
+
+
+#define CMOSCAM_MINOR_RWTABLES 9
+#define CMOSCAM_MINOR_CIRCBUF 11
+#define CMOSCAM_MINOR_HISTOGRAM 12
+#define CMOSCAM_MINOR_JPEAGHEAD 13
+#define CMOSCAM_MINOR_GAMMA 14
+#define CMOSCAM_MINOR_FRAMEPARS 16
+#define CMOSCAM_MINOR_GAMMAS 17
+#define CMOSCAM_MINOR_HISTOGRAMS 18
+#define CMOSCAM_MINOR_IMAGEACQ 19
+#define CMOSCAM_MINOR_HUFFMAN 20
+
+#define FPGACONF_MINOR_IORW 3 /* direct R/W FPGA registers */
+#define FPGACONF_MINOR_SDRAM 4 /* read/write SDRAM through PIO */
+#define FPGACONF_MINOR_TABLES 6 /// Write FPGA tables directly
+
+
+#define FPGA_CLOCK_MINOR 2
+#define FPGA_CLOCK_MINOR_I2C 2
+#define FPGA_CLOCK_MINOR_CLOCKS 3
+
+
+#define FPGA_JTAG_RESET_MINOR 0 // just close open files
+#define FPGA_JTAG_RAW_MINOR 0 // just close open files
+#define FPGA_JTAG_MINOR 1
+#define FPGA_SJTAG_MINOR 2
+#define FPGA_AJTAG_MINOR 3
+#define FPGA_JTAG_BOUNDARY_MINOR 5 // read/write boundary pins of the main FPGA
+#define FPGA_SJTAG_BOUNDARY_MINOR 6 // read/write boundary pins of the sensor board FPGA
+#define FPGA_AJTAG_BOUNDARY_MINOR 7 // read/write boundary pins of the aux board FPGA
+
+
+#define X3X3_EXIF_EXIF 0 // read encoded Exif data (SEEK_END,
+#define X3X3_EXIF_META 1 // write metadata, concurently opened files. All writes atomic
+// control/setup devices
+#define X3X3_EXIF_TEMPLATE 2 // write Exif template
+#define X3X3_EXIF_METADIR 3 // write metadata to Exif header translation (dir_table[MAX_EXIF_FIELDS])
+// those 2 files will disable exif_enable and exif_valid, truncate file size to file pointer on release.
+#define X3X3_EXIF_TIME 4 // write today/tomorrow date (YYYY:MM:DD) and number of seconds at today/tomorrow
+ // midnight (00:00:00) in seconds from epoch (long, startting from LSB)
diff --git a/src/include/elphel/exifa.h b/src/include/elphel/exifa.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c8e34233871bdbbf7462616722f4d78036cf6a9
--- /dev/null
+++ b/src/include/elphel/exifa.h
@@ -0,0 +1,190 @@
+/*
+ exifa.h
+*/
+#ifndef _ASM_EXIF_H
+#define _ASM_EXIF_H
+
+//Major
+#define X3X3_EXIF 125
+//Minors
+#define X3X3_EXIF_EXIF 0 // read encoded Exif data (SEEK_END,
+#define X3X3_EXIF_META 1 // write metadata, concurently opened files. All writes atomic
+// control/setup devices
+#define X3X3_EXIF_TEMPLATE 2 // write Exif template
+#define X3X3_EXIF_METADIR 3 // write metadata to Exif header translation (dir_table[MAX_EXIF_FIELDS])
+// those 2 files will disable exif_enable and exif_valid, truncate file size to file pointer on release.
+#define X3X3_EXIF_TIME 4 // write today/tomorrow date (YYYY:MM:DD) and number of seconds at today/tomorrow
+ // midnight (00:00:00) in seconds from epoch (long, startting from LSB)
+
+// commands for the overloaded lseek:
+
+//X3X3_EXIF_TIME
+#define EXIF_LSEEK_DISABLE 1 // disable Exif (storing of frame meta, generating Exif)
+#define EXIF_LSEEK_ENABLE 2 // enable Exif (build buffer if needed)
+#define EXIF_LSEEK_INVALIDATE 3 // invalidate (and disable)
+#define EXIF_LSEEK_REBUILD 4 // rebuild buffer
+
+#define EXIF_LSEEK_TOMORROW_DATE 5 // file pointer to YYYY:MM:DD (tomorrow) string
+#define EXIF_LSEEK_TOMORROW_SEC 6 // file pointer to unsigned long (little endian) tomorrow seconds from epoch
+#define EXIF_LSEEK_TODAY_DATE 7 // file pointer to YYYY:MM:DD (today) string
+#define EXIF_LSEEK_TODAY_SEC 8 // file pointer to unsigned long (little endian) today seconds from epoch
+
+
+/*
+Exif data in the images is combined from the "static" structure (template), calculated once at startup, and
+variable data stored in the buffer for individual frames in the "Exif" form - converted to ASCII strings
+or Rational or else. The generated Exif header copies that variable fileds on top of the Exif template.
+
+The compressed data buffer is stored in "meta pages", one per frame
+*/
+struct exif_dir_table_t {
+ union {
+ unsigned long ltag;// tag group and tag combined
+ struct {
+ unsigned short tag_group; // tag group: 0 - IFD0, 1 - Exif, 2 - GPS
+ unsigned short tag; // Exif tag as defined in the standard
+ };
+ };
+ unsigned long len; // Number of bytes to be copied from metadata to Exif
+ unsigned long src; // offset in meta data page
+ unsigned long dst; // offset in output Exif page
+};
+#define MAX_EXIF_FIELDS 256 // number of Exif tags in the header
+#define MAX_EXIF_SIZE 4096 // Exif data size
+//#define MAX_EXIF_FRAMES 512 // number of frames in the buffer
+#define MAX_EXIF_FRAMES 2048 // number of frames in the buffer
+
+//Exif Tags - unsigned long, combining actual Exif tags with tag groups (0 - IFD0, 1 - Exif, 2 - GPS)
+#define Exif_Image_ImageDescription 0x0010e
+#define Exif_Image_Make 0x0010f
+#define Exif_Image_Model 0x00110
+#define Exif_Image_Software 0x00131
+#define Exif_Image_DateTime 0x00132
+#define Exif_Image_Artist 0x0013b
+#define Exif_Image_HostComputer 0x0013c
+#define Exif_Image_Orientation 0x00112
+// hack, reusing field to keep it protected
+#define Exif_Image_IPTCNAA 0x083bb
+#define Exif_Image_FrameNumber 0x083bb
+
+#define Exif_Image_ExifTag 0x08769
+#define Exif_Image_GPSTag 0x08825
+
+//Sub IFD
+#define Exif_Photo_ExposureTime 0x1829a
+#define Exif_Photo_DateTimeOriginal 0x19003
+#define Exif_Photo_MakerNote 0x1927c
+#define Exif_Photo_SubSecTime 0x19290
+#define Exif_Photo_SubSecTimeOriginal 0x19291
+//GPSInfo
+#define Exif_GPSInfo_GPSLatitudeRef 0x20001
+#define Exif_GPSInfo_GPSLatitude 0x20002
+#define Exif_GPSInfo_GPSLongitudeRef 0x20003
+#define Exif_GPSInfo_GPSLongitude 0x20004
+#define Exif_GPSInfo_GPSAltitudeRef 0x20005
+#define Exif_GPSInfo_GPSAltitude 0x20006
+#define Exif_GPSInfo_GPSTimeStamp 0x20007
+#define Exif_GPSInfo_GPSMeasureMode 0x2000a
+#define Exif_GPSInfo_GPSDateStamp 0x2001D
+
+/// used for compass module
+#define Exif_GPSInfo_GPSImgDirectionRef 0x20010
+#define Exif_GPSInfo_GPSImgDirection 0x20011
+#define Exif_GPSInfo_GPSDestLatitudeRef 0x20013
+#define Exif_GPSInfo_GPSDestLatitude 0x20014
+#define Exif_GPSInfo_GPSDestLongitudeRef 0x20015
+#define Exif_GPSInfo_GPSDestLongitude 0x20016
+
+#define Exif_GPSInfo_CompassDirectionRef 0x20010
+#define Exif_GPSInfo_CompassDirection 0x20011
+#define Exif_GPSInfo_CompassPitchRef 0x20013
+#define Exif_GPSInfo_CompassPitch 0x20014
+#define Exif_GPSInfo_CompassRollRef 0x20015
+#define Exif_GPSInfo_CompassRoll 0x20016
+
+// array(0x9003,2,"2001:06:21 12:00:00","len"=> 20), //date/time original time created, always use 20 bytes (19 ."\0")
+// array(0x9291,2,"0 ") //original time sub-second length=10 9 ."\0"
+///move back to interframe_params_t?
+struct frame_exif_t {
+ unsigned short meta_index; //! index of the linked meta page
+ unsigned short signffff; //! should be 0xffff - it will be a signature that JPEG data was not overwritten
+ unsigned long frame_length; //! frame length
+};
+
+struct meta_GPSInfo_t {
+ unsigned char GPSLatitudeRef; //"N"/"S"
+ unsigned long GPSLatitude_deg_nom;
+ unsigned long GPSLatitude_deg_denom;
+ unsigned long GPSLatitude_min_nom;
+ unsigned long GPSLatitude_min_denom;
+ unsigned char GPSLongitudeRef; //"E"/"W"
+ unsigned long GPSLongitude_deg_nom;
+ unsigned long GPSLongitude_deg_denom;
+ unsigned long GPSLongitude_min_nom;
+ unsigned long GPSLongitude_min_denom;
+ unsigned char GPSAltitudeRef; //byte, not ascii 0 - above sea level, 1 - below
+ unsigned long GPSAltitude_nom; //in meters
+ unsigned long GPSAltitude_denom;
+ unsigned long GPSTimeStamp_hrs_nom;
+ unsigned long GPSTimeStamp_hrs_denom;
+ unsigned long GPSTimeStamp_min_nom;
+ unsigned long GPSTimeStamp_min_denom;
+ unsigned long GPSTimeStamp_sec_nom;
+ unsigned long GPSTimeStamp_sec_denom;
+ unsigned char GPSDateStamp[11]; //includes '\0'
+ unsigned char GPSMeasureMode;
+};
+//hack - use
+struct meta_CompassInfo_t {
+// unsigned char GPSImgDirectionRef; //"M"/"T" //0x10
+ unsigned long CompassDirection_nom; //0x11
+ unsigned long CompassDirection_denom;
+ unsigned char CompassPitchRef; //"N"/"S"
+ unsigned long CompassPitch_nom;
+ unsigned long CompassPitch_denom;
+ unsigned char CompassRollRef; //"E"/"W"
+ unsigned long CompassRoll_nom;
+ unsigned long CompassRoll_denom;
+};
+
+
+#define EXIF_GPS_MIN_DENOM 10000
+#define EXIF_GPS_METERS_DENOM 10
+#define EXIF_GPS_TIMESEC_DENOM 1000
+#define EXIF_GPS_COMPASS_DENOM 10
+///hack!
+#define EXIF_COMPASS_PITCH_ASCII "NS" // use for pitch +/-
+#define EXIF_COMPASS_ROLL_ASCII "EW" // use for roll +/-
+
+/// Exif data (variable, stored with each frame) used for KML (not only)
+#define Exif_Image_ImageDescription_Index 0x00
+#define Exif_Photo_DateTimeOriginal_Index 0x01
+#define Exif_Photo_SubSecTimeOriginal_Index 0x02
+#define Exif_Photo_ExposureTime_Index 0x03
+#define Exif_GPSInfo_GPSLatitudeRef_Index 0x04
+#define Exif_GPSInfo_GPSLatitude_Index 0x05
+#define Exif_GPSInfo_GPSLongitudeRef_Index 0x06
+#define Exif_GPSInfo_GPSLongitude_Index 0x07
+#define Exif_GPSInfo_GPSAltitudeRef_Index 0x08
+#define Exif_GPSInfo_GPSAltitude_Index 0x09
+#define Exif_GPSInfo_GPSTimeStamp_Index 0x0a
+#define Exif_GPSInfo_GPSDateStamp_Index 0x0b
+#define Exif_GPSInfo_GPSMeasureMode_Index 0x0c
+#define Exif_GPSInfo_CompassDirectionRef_Index 0x0d
+#define Exif_GPSInfo_CompassDirection_Index 0x0e
+#define Exif_GPSInfo_CompassPitchRef_Index 0x0f
+#define Exif_GPSInfo_CompassPitch_Index 0x10
+#define Exif_GPSInfo_CompassRollRef_Index 0x11
+#define Exif_GPSInfo_CompassRoll_Index 0x12
+#define Exif_Image_FrameNumber_Index 0x13
+#define Exif_Image_Orientation_Index 0x14
+#define Exif_Photo_MakerNote_Index 0x15
+/// update ExifKmlNumber to be total number of *_Index entries
+#define ExifKmlNumber Exif_Photo_MakerNote_Index+1
+
+
+#define EXIF_DEV_NAME "/dev/exif_exif"
+#define EXIFDIR_DEV_NAME "/dev/exif_metadir"
+#define EXIFMETA_DEV_NAME "/dev/exif_meta"
+
+#endif