* @brief Looks for the hash32 last programmed to the FPGA for the particular color
* @param color
* @return hash32 (combined gamma/black/scale) locked fro a specified color. If none - return 0
*/
unsignedlongget_locked_hash32(intcolor){
intindex=gammas[0].locked_color[color];
returnindex?gammas[index].hash32:0;
}
/**
* @brief Lock gamma table for the specified color, save previous locks (if any) so new locks can be applied/canceled
* NOTE: interrupts should be disabled ***
* @param index gamma table index
* @param color
*/
inlinevoidlock_gamma_node(intindex,intcolor){
inttmp_p;
if(likely((color<4)&&(color>=0))){/// valid color
if(((tmp_p=gammas[0].locked_color[color]))!=0){///new gamma to the same color
gammas[tmp_p].locked&=~(1<<color);/// remove any previous lock on the same color (if any)
}
gammas[0].locked_color[color]=index;
gammas[index].locked|=(1<<color);
}
}
/**
* @brief Unlock gamma table for the specified color
* NOTE: Not needed anymore
* @param color color index (0..3)
* @return wrong data -1, nothing to unlock - 0, >0 - unlocked index
*/
intunlock_gamma_node(intcolor){
unsignedlongflags;
intindex;
MDF11(printk("color=0x%x\n",color));
if(unlikely((color>=4)||(color<0)))return-1;
local_irq_save(flags);
index=gammas[0].locked_color[color];
if(index){
gammas[index].locked&=~(1<<color);/// clear appropriate "locked" bit for this table
gammas[0].locked_color[color]=0;
}
local_irq_restore(flags);
returnindex;
}
/**
* @brief Find a gamma table in FPGA format to be programmed (table should already be locked for this color)
* @param color color index (0..3) of the table
* @return pointer to a gamma table (or NULL if table does not exist)
*/
unsignedlong*get_gamma_fpga(intcolor){/// NOTE: Not needed anymore?
intindex;
if(unlikely((color>=4)||(color<0)))returnNULL;//
index=gammas[0].locked_color[color];
MDF11(printk(" index=%d(0x%x)\n",index,index));
if(index)returngammas[index].fpga;
elsereturnNULL;
}
/**
* @brief Get a new node for gamma tables
* Find least recently used node (balancing between non-scaled and scaled), remove it from current chains and return
* pointers in the returned node are not initialized, "valid" bit is cleared
* NOTE: interrupts should be disabled ***
* @return Node index or 0 if none (unlocked) nodes are found
*/
intgamma_new_node(void){
inttmp_p;
if((gammas[0].non_scaled_length>GAMMA_THRESH)&&(gammas[gammas[0].oldest_non_scaled].newest_scaled==gammas[0].oldest_non_scaled)){/// no scaled for the oldest hash
/// sacrifice oldest hash
tmp_p=gammas[0].oldest_non_scaled;
remove_from_nonscaled(tmp_p);
}else{/// use oldest scaled
tmp_p=gammas[0].oldest_all;
/// skip locked if any (should be unlikely to get any locked)
unsignedlonggcurr=0;/// running value to be compared against direct gamma
intr=0;/// current value of reverse gamma table
intx=0;/// current indedx of reverse gamma table
MDF11(printk("\n"));
while((r<256)&&(x<256)){
gamma_out[x]=r;
// if ((r<255) && (( gamma_in[r]<<8) <= gcurr)) {
if((r<255)&&(gamma_in[r]<=gcurr)){
r++;
}else{
x++;
gcurr+=256;
}
}
}
/**
* @brief calculate gamma table (and requested derivatives), insert new node if needed.
* @param hash16 16-bit unique (non-scaled) gamma table identifier. Can be 1-byte gamma and 1-byte black level shift TODO: make black level fine-grained?
* - 1 - if set, no interrupts will be enabled between steps, whole operation will be atomic
* - 2 - calculate reverse gamma table
* - 4 - calculate FPGA-format gamma table.
* - 8 - Lock (FPGA) table for specified color
* @param color color index (0..3) to lock table for (if mode bit 4 is set), otherwise color is ignored
* @return index for the specified table or 0 if none exists and prototype was not provided (gamma_proto==NULL)
*/
//#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)
/// next 1 byte [4] - mode (1 - not_nice, 2 - need reverse, 4 - hardware, 8 - lock)
/// next byte [5] - color only if lock bit in mode is set
/// next 514 bytes [6..519] - 16-bit gamma table
/// 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) - do nothing, return 0
/// lseek (SEEK_CUR, value) - ignore value, return last write result (and if it is still valid) - used by ftell
/// lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
/// lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer
/// lseek (SEEK_END, 1) - initialize all the gamma data structures
/// lseek (SEEK_END, 2) - check that current hash/scale/index are still current
/// mmap (should be used read only)
//#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
/**
* @brief File size reported by gamma device driver
set_gamma_table(0,GAMMA_SCLALE_1,NULL,0,0);/// maybe not needed to put linear to cache - it can be calculated as soon FPGA will be tried to be programmed with
intunlock_gamma_node(intcolor);/// NOTE: Not needed anymore
///
/// return a pointer to the gamma table (single color) encoded in FPGA format (NULL if there is to table ready)
///
unsignedlong*get_gamma_fpga(intcolor);
intgamma_new_node(void);
voidgamma_encode_fpga(unsignedshort*gamma_in,unsignedlong*gamma_out);///Hardware-dependent encoding of the FPGA "gamma" table. Converts unsigned short array of 257 16-bit values (only 10 msb-s are used) to 256 unsigned long words to be written to FPGA
voidgamma_calc_scaled(unsignedshortscale,unsignedshort*gamma_in,unsignedshort*gamma_out);/// scale gamma table by (scale>>GAMMA_SCALE_SHIFT), saturate to 0..0xffff
//void gamma_calc_reverse(unsigned short * gamma_in, unsigned short * gamma_out);/// calculate reverse gamma table (16-bit output) that matches 1-byte gamma-converted data to the input data (in the 0..ffff range)
voidgamma_calc_reverse(unsignedshort*gamma_in,unsignedchar*gamma_out);/// calculate reverse gamma table (8-bit output) that matches 1-byte gamma-converted data to the input data (in the 0..ffff range)
/// return index of the specified hash/scale, insert new table (gamma_proto) if needed
/// If no table is specified (null) - return 0 if no prototype is found
/// if (not_nice) - don't re-enable interrupts between atomic actions (may fail)
/// if "hardware" is non-zero, color/frame pair will be used to lock node to it, fpga-encoded table will be calculated (if not done so earlier)
// #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), node will be locked for specified
*! Table that specifies what frame should "onchange" function be programmed to, relative to the frame for which parameters are specified
*! 1 - same frame (programmed at least 1 frame earlier), will happen immediately after VACT start for that frame (usually before the interrupt for that frame)
*! 2 - previous frame (programmed at least 2 frames earlier)
*! 3 - pre-previous frame (programmed at least 3 frames earlier)
*! 4 - pre-pre-previous frame (programmed at least 4 frames earlier)
*! 0 - ASAP (programmed after that frame interrupt - when compression of the previous frame is finished)
*! each group consists of 6 numbers:
*! "onchange" index (0..31), then 5 values for:
*! 1 - continuous run , safe mode (skipping frame when geometry is modified)
*! 2 - continuous run , no skipping frame when geometry is modified, trying to save all frames
*! 3 - async mode (external trigger/timer) , safe mode (skipping frame when geometry is modified)
*! 4 - async mode (external trigger/timer) , no skipping frame when geometry is modified, trying to save all frames
*! 5 - async, non-overlap (program - acquire/compress - program next - acquire/compress next (i.e.10347 with CCD)
*! modified trigseq latencies so to to prevent sequencer stop when changing simultaneously trigger mode and starting generator
*!
*! Revision 1.3 2010/05/21 06:12:16 elphel
*! continue working on multi-sensor software
*!
*! Revision 1.2 2010/05/13 03:39:31 elphel
*! 8.0.8.12 - drivers modified for multi-sensor operation
*!
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*!
*!
*! Revision 1.12 2008/11/27 09:27:31 elphel
*! Support fro new parameters (vignetting correction related)
*!
*! Revision 1.11 2008/10/25 19:53:49 elphel
*! increased latency for gamma/gamma_load to fix a bug
*!
*! Revision 1.10 2008/10/23 08:06:40 elphel
*! set latencies for async modes
*!
*! Revision 1.9 2008/10/22 05:29:03 elphel
*! Rev. 8.0.alpha5 - working on external trigger mode - moved programming away from the sequencer that can only pass 24 data bits
*!
*! Revision 1.8 2008/10/22 03:44:50 elphel
*! increased limitfps latency to the same as the one for window to prevent sensor from missing counter rollover
*!
*! Revision 1.7 2008/10/21 04:22:26 elphel
*! changed latency for exposure to 2 (was 3)
*!
*! Revision 1.6 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.5 2008/10/17 05:44:48 elphel
*! fixing latencies
*!
*! Revision 1.4 2008/10/08 21:26:25 elphel
*! snapsot 7.2.0.pre4 - first images (actually - second)
*!
*! Revision 1.3 2008/09/25 00:58:11 elphel
*! snapshot
*!
*! Revision 1.2 2008/08/11 19:17:01 elphel
*! reduced syntax complaints by KDevelop
*!
*! Revision 1.1 2008/07/29 01:15:06 elphel
*! another snapshot
*!
*!
*/
#ifndef _LATENCY_H
#define _LATENCY_H
///TODO: not used yet, but it is possible to specify a function with non-zero latency that does not work with the sequencer - only in ASAP mode
constunsignedlongahead_tab[]=
{/// ASAP C,S C,NS, A,S A,NS NOL
#if 0
onchange_recalcseq, 0, 0, 0, 0, 0, 0, /// recalculate sequences/latencies, according to P_SKIP, P_TRIG
onchange_afterinit, 0, 0, 0, 0, 0, 0, /// restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
onchange_window, 0, 3, 2, 2, 2, 0, /// program sensor WOI and mirroring (flipping)
onchange_exposure, 0, 3, 3, 2, 2, 0, /// program exposure
onchange_gains, 0, 2, 2, 2, 2, 0, /// program analog gains
onchange_triggermode, 0, 3, 2, 2, 2, 0, /// program sensor trigger mode TODO: does it have any sense here?
onchange_sensorstop, 0, 1, 1, 1, 1, 0, /// Stop acquisition from the sensor to the FPGA (start has latency of 2)
onchange_sensorrun, 0, 2, 2, 2, 2, 0, /// Start/single acquisition from the sensor to the FPGA (stop has latency of 1)
onchange_gamma, 0, 1, 1, 1, 1, 0, /// program gamma table - make sure table is calculated, maybe send all but last word)
onchange_hist, 0, 1, 1, 1, 1, 0, /// program histogram window TODO: fix FPGA - (now pos_top will be read too early - will use previous ) and add latency
onchange_aexp, 0, 1, 1, 1, 1, 0, /// program autoexposure mode TODO: look what exactly is changed here
onchange_compctl, 0, 1, 1, 1, 1, 0, /// only start/stop/single (after explicitly changed, not when geometry was changed)
// onchange_gammaload, 1, 0, 0, 0, 0, 0, /// write gamma tables (should be prepared). Maybe - just last byte, to activate?
onchange_gammaload, 1, 1, 1, 1, 1, 0, /// write gamma tables (should be prepared). Maybe - just last byte, to activate?
onchange_sensorregs, 0, 2, 2, 2, 2, 0 /// write sensor registers (only changed from outside the driver as they may have different latencies)?
// 29 - 3 left
#endif
/// (regular - "C,S" column) latencies decreased by 1
onchange_recalcseq,0,0,0,0,0,0,/// recalculate sequences/latencies, according to P_SKIP, P_TRIG
onchange_detectsensor,1,0,0,0,0,0,/// detect sensor type, sets sensor structure (capabilities), function pointers
onchange_sensorphase,1,0,0,0,0,0,/// program sensor clock/phase (do immediately)
onchange_i2c,0,0,0,0,0,0,/// program i2c
onchange_initsensor,1,0,0,0,0,0,/// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
onchange_afterinit,0,0,0,0,0,0,/// restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
onchange_multisens,0,2,1,1,1,0,/// chnages related to multiplexed sensors
onchange_window,0,2,1,1,1,0,/// program sensor WOI and mirroring (flipping) - NOTE: 1 bad frame to skip
onchange_window_safe,0,1,1,1,1,0,/// program sensor WOI and mirroring (flipping) - NOTE: no bad frames
onchange_exposure,0,2,1,1,1,0,/// program exposure
onchange_gains,0,1,1,1,1,0,/// program analog gains
onchange_triggermode,0,2,1,1,1,0,/// program sensor trigger mode TODO: does it have any sense here?
onchange_sensorin,0,0,0,0,0,0,/// program sensor input in FPGA (Bayer, 8/16 bits, ??), stop sensor (if needed)
onchange_sensorstop,0,0,0,0,0,0,/// Stop acquisition from the sensor to the FPGA (start has latency of 2)
onchange_sensorrun,0,1,1,1,1,0,/// Start/single acquisition from the sensor to the FPGA (stop has latency of 1)
onchange_gamma,0,1,1,1,1,0,/// program gamma table - make sure table is calculated, maybe send all but last word)
onchange_hist,0,0,0,0,0,0,/// program histogram window TODO: fix FPGA - (now pos_top will be read too early - will use previous ) and add latency
onchange_aexp,0,0,0,0,0,0,/// program autoexposure mode TODO: look what exactly is changed here
onchange_quality,0,0,0,0,0,0,/// program quantization table(s)
onchange_memsensor,0,0,0,0,0,0,/// program memory channels 0 (sensor->memory) and 1 (memory->FPN)
onchange_memcompressor,0,0,0,0,0,0,/// program memory channel 2 (memory->compressor) (delays programming until onchange_comprestart if needed)
// onchange_limitfps, 0, 1, 2, 2, 2, 0, /// check compressor will keep up, limit sensor FPS if needed
/// For Micron sensors limitfps should have the same latency as changing window height, otherwise when WOI_HEIGHT 0x3c0->0x790 and next frame VBLANK 0x13e->0x284
/// sensor waits till the counter overflows (>10 seconds) without any frame sync pulses
onchange_limitfps,0,2,1,1,1,0,/// check compressor will keep up, limit sensor FPS if needed
onchange_compmode,0,0,1,1,1,0,/// program compressor modes
onchange_focusmode,1,0,0,0,0,0,/// program focus modes (through writing the tables, so no sequencer)
// onchange_trigseq, 1, 0, 0, 0, 0, 0, /// program sequencer (int/ext) NOTE:needs >24 bit data, too much for sequencer
onchange_trigseq,1,2,1,1,1,0,/// program sequencer (int/ext) NOTE:needs >24 bit data, too much for sequencer. Should be not later than onchange_triggermode and limitfps
onchange_irq,0,0,0,0,0,0,/// program smart IRQ mode
onchange_comprestart,0,0,0,0,0,0,/// restart after changing geometry (recognizes ASAP and programs memory channel 2 then)
/// onchange_compstop should have the same latency as onchange_window