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