Commit af248eb3 authored by Andrey Filippov's avatar Andrey Filippov

working on histograms code

parent 8697a0d7
/*!******************************************************************************** /***************************************************************************//**
*! FILE NAME : gamma_tables.c * @file gamma_tables.c
*! DESCRIPTION: Handles "gamma"tables storage and scaling * @brief Handles "gamma"tables storage and scaling
*! exposes device driver to manipulate custom "gamma" tables * exposes device driver to manipulate custom "gamma" tables
*! "Gamma" tables are calculated in several steps, leaving the * "Gamma" tables are calculated in several steps, leaving the
*! exponent calculation to the application, but handling scaling inside. * exponent calculation to the application, but handling scaling inside.
*! Scaling (with saturation if >1.0)is used for color balancing. * Scaling (with saturation if >1.0)is used for color balancing.
*! Gamma table calulation involves several intermediate tables: *
*! - forward table * Gamma table calculation involves several intermediate tables:
*! - reverse table (for histogram corrections) * - forward table
*! - FPGA format * - reverse table (for histogram corrections)
*! And the driver caches intermediate tables when possible, calculates * - FPGA format
*! them when needed. * And the driver caches intermediate tables when possible, calculates
*! Copyright (C) 2008 Elphel, Inc. * them when needed.
*! -----------------------------------------------------------------------------** * @copyright Copyright 2008-2016 (C) Elphel, Inc.
*! * @par <b>License</b>
*! This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 2 of the License, or
*! (at your option) any later version. * (at your option) any later version.
*! * This program is distributed in the hope that it will be useful,
*! This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of
*! but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details.
*! 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 <http://www.gnu.org/licenses/>.
*! You should have received a copy of the GNU General Public License *******************************************************************************/
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*! $Log: gamma_tables.c,v $ /*********************************************************************************
*! Revision 1.1.1.1 2008/11/27 20:04:01 elphel * $Log: gamma_tables.c,v $
*! * Revision 1.1.1.1 2008/11/27 20:04:01 elphel
*! *
*! Revision 1.19 2008/11/13 05:40:45 elphel *
*! 8.0.alpha16 - modified histogram storage, profiling * 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.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:51:06 elphel *
*! Changed word order in writes to gamma tables driver * Revision 1.17 2008/10/25 19:51:06 elphel
*! * Changed word order in writes to gamma tables driver
*! Revision 1.16 2008/10/23 08:04:19 elphel *
*! reenabling IRQ in debug mode * Revision 1.16 2008/10/23 08:04:19 elphel
*! * reenabling IRQ in debug mode
*! Revision 1.15 2008/10/12 16:46:22 elphel *
*! snapshot * Revision 1.15 2008/10/12 16:46:22 elphel
*! * snapshot
*! Revision 1.14 2008/10/06 08:31:08 elphel *
*! snapshot, first images * Revision 1.14 2008/10/06 08:31:08 elphel
*! * snapshot, first images
*! Revision 1.13 2008/10/05 05:13:33 elphel *
*! snapshot003 * Revision 1.13 2008/10/05 05:13:33 elphel
*! * snapshot003
*! Revision 1.12 2008/10/04 16:10:12 elphel *
*! snapshot * Revision 1.12 2008/10/04 16:10:12 elphel
*! * snapshot
*! Revision 1.11 2008/09/22 22:55:48 elphel *
*! snapshot * Revision 1.11 2008/09/22 22:55:48 elphel
*! * snapshot
*! Revision 1.10 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.10 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.9 2008/09/19 04:37:25 elphel *
*! snapshot * Revision 1.9 2008/09/19 04:37:25 elphel
*! * snapshot
*! Revision 1.8 2008/09/16 00:49:32 elphel *
*! snapshot * Revision 1.8 2008/09/16 00:49:32 elphel
*! * snapshot
*! Revision 1.7 2008/09/12 00:23:59 elphel *
*! removed cc353.c, cc353.h * Revision 1.7 2008/09/12 00:23:59 elphel
*! * removed cc353.c, cc353.h
*! Revision 1.6 2008/09/11 01:05:32 elphel *
*! snapshot * Revision 1.6 2008/09/11 01:05:32 elphel
*! * snapshot
*! Revision 1.5 2008/09/05 23:20:26 elphel *
*! just a snapshot * Revision 1.5 2008/09/05 23:20:26 elphel
*! * just a snapshot
*! Revision 1.4 2008/07/27 04:27:49 elphel *
*! next snapshot * Revision 1.4 2008/07/27 04:27:49 elphel
*! * next snapshot
*! Revision 1.3 2008/06/16 06:51:21 elphel *
*! work in progress, intermediate commit * Revision 1.3 2008/06/16 06:51:21 elphel
*! * work in progress, intermediate commit
*! Revision 1.2 2008/06/10 00:02:42 elphel *
*! fast calculation of 8-bit reverse functions for "gamma" tables and histograms * Revision 1.2 2008/06/10 00:02:42 elphel
*! * fast calculation of 8-bit reverse functions for "gamma" tables and histograms
*! Revision 1.1 2008/06/08 23:46:45 elphel *
*! added drivers files for handling quantization tables, gamma tables and the histograms * 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 //copied from cxi2c.c - TODO:remove unneeded
...@@ -149,7 +148,9 @@ ...@@ -149,7 +148,9 @@
#endif #endif
/** Combine color, sensor port and sub-channel into a single index
* It is still possible to use "color" parameter in the range of 0..63 with port and channel set to 0 */
#define PORT_CHN_COLOR(color,port,chn) (((color) & 0x3f) | ((((port) & 3 ) << 4)) | ((((chn) & 3 ) << 2)))
#define X3X3_GAMMAS_DRIVER_NAME "Elphel (R) Model 353 Gamma Tables device driver" #define X3X3_GAMMAS_DRIVER_NAME "Elphel (R) Model 353 Gamma Tables device driver"
/** /**
* @brief number of different non-scaled tables in cache when it starts to overwrite non-scaled tables rather than scaled * @brief number of different non-scaled tables in cache when it starts to overwrite non-scaled tables rather than scaled
...@@ -158,15 +159,15 @@ ...@@ -158,15 +159,15 @@
#define GAMMA_THRESH (GAMMA_CACHE_NUMBER/16) #define GAMMA_THRESH (GAMMA_CACHE_NUMBER/16)
static struct gamma_stuct_t gammas[GAMMA_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE))); static struct gamma_stuct_t gammas[GAMMA_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE)));
struct gamma_stuct_t * gammas_p; /// to use with mmap struct gamma_stuct_t * gammas_p; // to use with mmap
struct gammas_pd { struct gammas_pd {
int minor; int minor;
unsigned short scale; unsigned short scale;
unsigned short hash16; unsigned short hash16;
unsigned char mode; unsigned char mode;
unsigned char color; unsigned char color; // Does it need port/sub-channel?
/// something else to be added here? // something else to be added here?
}; };
int gammas_open (struct inode *inode, struct file *file); int gammas_open (struct inode *inode, struct file *file);
...@@ -192,7 +193,7 @@ inline void remove_from_nonscaled(int index) { ...@@ -192,7 +193,7 @@ inline void remove_from_nonscaled(int index) {
* @param index item index to remove * @param index item index to remove
*/ */
inline void remove_from_scaled (int index) { inline void remove_from_scaled (int index) {
if (likely(gammas[index].newer_scaled)) { /// will skip first, untill the cache is all used if (likely(gammas[index].newer_scaled)) { // will skip first, untill the cache is all used
gammas[gammas[index].newer_scaled].older_scaled=gammas[index].older_scaled; gammas[gammas[index].newer_scaled].older_scaled=gammas[index].older_scaled;
gammas[gammas[index].older_scaled].newer_scaled=gammas[index].newer_scaled; gammas[gammas[index].older_scaled].newer_scaled=gammas[index].newer_scaled;
} }
...@@ -202,7 +203,7 @@ inline void remove_from_scaled (int index) { ...@@ -202,7 +203,7 @@ inline void remove_from_scaled (int index) {
* @brief remove item from the all ("diagonal") chain * @brief remove item from the all ("diagonal") chain
* @param index item index to remove * @param index item index to remove
*/ */
inline void remove_from_all (int index) { /// always - in that chain - after init inline void remove_from_all (int index) { // always - in that chain - after init
gammas[gammas[index].newer_all].older_all=gammas[index].older_all; gammas[gammas[index].newer_all].older_all=gammas[index].older_all;
gammas[gammas[index].older_all].newer_all=gammas[index].newer_all; gammas[gammas[index].older_all].newer_all=gammas[index].newer_all;
} }
...@@ -219,8 +220,8 @@ inline void insert_first_nonscaled(int index) { ...@@ -219,8 +220,8 @@ inline void insert_first_nonscaled(int index) {
gammas[index].newer_non_scaled=0; // 6 gammas[index].newer_non_scaled=0; // 6
gammas[0].non_scaled_length++; gammas[0].non_scaled_length++;
gammas[index].this_non_scaled=0; // none gammas[index].this_non_scaled=0; // none
gammas[index].newest_scaled=index; /// no scaled yet - point to itself gammas[index].newest_scaled=index; // no scaled yet - point to itself
gammas[index].oldest_scaled=index; /// no scaled yet - point to itself gammas[index].oldest_scaled=index; // no scaled yet - point to itself
} }
...@@ -259,25 +260,25 @@ void init_gammas(void) { ...@@ -259,25 +260,25 @@ void init_gammas(void) {
unsigned long flags; unsigned long flags;
int i; int i;
gammas_p=gammas; gammas_p=gammas;
/// empty 2-d chain // empty 2-d chain
local_irq_save(flags); local_irq_save(flags);
gammas[0].oldest_non_scaled=0; gammas[0].oldest_non_scaled=0;
gammas[0].newest_non_scaled=0; gammas[0].newest_non_scaled=0;
/// all entries in a same // all entries in a same
gammas[0].oldest_all=GAMMA_CACHE_NUMBER-1; gammas[0].oldest_all=GAMMA_CACHE_NUMBER-1;
gammas[0].newest_all=1; gammas[0].newest_all=1;
MDF10(printk("\n")); MDF10(printk("\n"));
for (i=1; i < GAMMA_CACHE_NUMBER;i++) { for (i=1; i < GAMMA_CACHE_NUMBER;i++) {
gammas[i].this_non_scaled=-1; /// no parent.FIXME: Where is it used? -1 if never used gammas[i].this_non_scaled=-1; // no parent.FIXME: Where is it used? -1 if never used
/// something else? // something else?
gammas[i].newer_all=i-1; gammas[i].newer_all=i-1;
gammas[i].older_all= (i==(GAMMA_CACHE_NUMBER-1))? 0: (i+1); gammas[i].older_all= (i==(GAMMA_CACHE_NUMBER-1))? 0: (i+1);
gammas[i].locked=0; gammas[i].locked=0;
gammas[i].valid=0; gammas[i].valid=0;
} }
gammas[0].non_scaled_length=0; gammas[0].non_scaled_length=0;
for (i=1; i < 4;i++) { for (i=1; i < sizeof(gammas[0].locked_chn_color)/sizeof(gammas[0].locked_chn_color[0]);i++) {
gammas[0].locked_color[i]=0; gammas[0].locked_chn_color[i]=0;
} }
local_irq_restore(flags); local_irq_restore(flags);
} }
...@@ -306,61 +307,68 @@ int is_gamma_valid (unsigned short hash16, unsigned short scale, int index) { ...@@ -306,61 +307,68 @@ int is_gamma_valid (unsigned short hash16, unsigned short scale, int index) {
} }
/** /** Looks for the hash32 last programmed to the FPGA for the particular color
* @brief Looks for the hash32 last programmed to the FPGA for the particular color
* @param color * @param color
* @return hash32 (combined gamma/black/scale) locked fro a specified color. If none - return 0 * @return hash32 (combined gamma/black/scale) locked for a specified color. If none - return 0
*/ */
unsigned long get_locked_hash32(int color) { unsigned long get_locked_hash32(int color, ///< color channel 0..3
int index=gammas[0].locked_color[color]; int sensor_port, ///< sensor port number (0..3)
int sensor_subchn) ///< sensor sub-channel (connected to the same port through 10359 mux) (0..3)
///< @return hash32 (combined gamma/black/scale) locked for a specified color,
///< port, sub-channel
{
int index=gammas[0].locked_chn_color[PORT_CHN_COLOR(color,sensor_port,sensor_subchn)];
return index?gammas[index].hash32:0; return index?gammas[index].hash32:0;
} }
/** /**
* @brief Lock gamma table for the specified color, save previous locks (if any) so new locks can be applied/canceled * @brief Lock gamma table for the specified color/port/subchannel, save previous locks (if any) so new locks can be applied/canceled
* NOTE: interrupts should be disabled *** * NOTE: interrupts should be disabled! */
* @param index gamma table index inline void lock_gamma_node (int index, ///< gamma table index
* @param color int color, ///< color channel 0..3
*/ int sensor_port, ///< sensor port number (0..3)
inline void lock_gamma_node (int index, int color) { int sensor_subchn) ///< sensor sub-channel (connected to the same port through 10359 mux) (0..3)
int tmp_p;
if (likely((color<4) && (color >=0))) { /// valid color {
if (((tmp_p=gammas[0].locked_color[color]))!=0) { ///new gamma to the same color int tmp_p;
gammas[tmp_p].locked &= ~(1 << color); /// remove any previous lock on the same color (if any) int cps = PORT_CHN_COLOR(color,sensor_port,sensor_subchn);
} if (((tmp_p=gammas[0].locked_chn_color[cps]))!=0) { ///new gamma to the same color
gammas[0].locked_color[color]= index; gammas[tmp_p].locked &= ~(1ULL << cps); // remove any previous lock on the same color (if any)
gammas[index].locked |= (1 << color); }
} gammas[0].locked_chn_color[cps]= index;
gammas[index].locked |= (1ULL << cps);
} }
/** /** Unlock gamma table for the specified color/port/subchannel
* @brief Unlock gamma table for the specified color * NOTE: Not needed anymore */
* NOTE: Not needed anymore int unlock_gamma_node (int color, ///< color channel 0..3
* @param color color index (0..3) int sensor_port, ///< sensor port number (0..3)
* @return wrong data -1, nothing to unlock - 0, >0 - unlocked index int sensor_subchn) ///< sensor sub-channel (connected to the same port through 10359 mux) (0..3)
*/ ///< @return wrong data -1, nothing to unlock - 0, >0 - unlocked index
int unlock_gamma_node (int color) { {
unsigned long flags; unsigned long flags;
int index; int index;
int cps = PORT_CHN_COLOR(color,sensor_port,sensor_subchn);
MDF11(printk("color=0x%x\n",color)); MDF11(printk("color=0x%x\n",color));
if (unlikely((color>= 4) || (color<0))) return -1;
local_irq_save(flags); local_irq_save(flags);
index =gammas[0].locked_color[color]; index =gammas[0].locked_chn_color[cps];
if (index) { if (index) {
gammas[index].locked &= ~(1 << color); /// clear appropriate "locked" bit for this table gammas[index].locked &= ~(1ULL << color); // clear appropriate "locked" bit for this table
gammas[0].locked_color[color]=0; gammas[0].locked_chn_color[color]=0;
} }
local_irq_restore(flags); local_irq_restore(flags);
return index; return index;
} }
/** /** Find a gamma table in FPGA format to be programmed (table should already be locked for this color) */
* @brief Find a gamma table in FPGA format to be programmed (table should already be locked for this color) unsigned long * get_gamma_fpga (int color, ///< color channel 0..3
* @param color color index (0..3) of the table int sensor_port, ///< sensor port number (0..3)
* @return pointer to a gamma table (or NULL if table does not exist) int sensor_subchn) ///< sensor sub-channel (connected to the same port through 10359 mux) (0..3)
*/ ///< @return pointer to a gamma table (or NULL if table does not exist)
unsigned long * get_gamma_fpga(int color) { /// NOTE: Not needed anymore?
{ // NOTE: Not needed anymore?
int index; int index;
if (unlikely((color>=4) || (color<0))) return NULL; // int cps = PORT_CHN_COLOR(color,sensor_port,sensor_subchn);
index =gammas[0].locked_color[color]; // if (unlikely((color>=4) || (color<0))) return NULL; //
index =gammas[0].locked_chn_color[cps];
MDF11(printk(" index=%d(0x%x)\n",index,index)); MDF11(printk(" index=%d(0x%x)\n",index,index));
if (index) return gammas[index].fpga; if (index) return gammas[index].fpga;
else return NULL; else return NULL;
...@@ -376,18 +384,18 @@ unsigned long * get_gamma_fpga(int color) { /// NOTE: Not needed anymore? ...@@ -376,18 +384,18 @@ unsigned long * get_gamma_fpga(int color) { /// NOTE: Not needed anymore?
*/ */
int gamma_new_node(void) { int gamma_new_node(void) {
int tmp_p; int tmp_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 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 // sacrifice oldest hash
tmp_p=gammas[0].oldest_non_scaled; tmp_p=gammas[0].oldest_non_scaled;
remove_from_nonscaled(tmp_p); remove_from_nonscaled(tmp_p);
} else { /// use oldest scaled } else { // use oldest scaled
tmp_p=gammas[0].oldest_all; tmp_p=gammas[0].oldest_all;
/// skip locked if any (should be unlikely to get any locked) // skip locked if any (should be unlikely to get any locked)
while ((tmp_p!=0) && gammas[tmp_p].locked) tmp_p=gammas[tmp_p].newer_all; while ((tmp_p!=0) && gammas[tmp_p].locked) tmp_p=gammas[tmp_p].newer_all;
if (tmp_p==0) return 0; // none (unlocked) nodes are found if (tmp_p==0) return 0; // none (unlocked) nodes are found
/// remove from "all" chain (should work for tmp_p being oldest or not // remove from "all" chain (should work for tmp_p being oldest or not
remove_from_all (tmp_p); remove_from_all (tmp_p);
/// remove from "scaled chain" // remove from "scaled chain"
remove_from_scaled (tmp_p); remove_from_scaled (tmp_p);
} }
gammas[tmp_p].valid=0; gammas[tmp_p].valid=0;
...@@ -442,9 +450,9 @@ void gamma_calc_scaled (unsigned short scale,unsigned short * gamma_in, unsigne ...@@ -442,9 +450,9 @@ void gamma_calc_scaled (unsigned short scale,unsigned short * gamma_in, unsigne
* @param gamma_out reversed gamma table (8 bit) * @param gamma_out reversed gamma table (8 bit)
*/ */
void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * gamma_out) { void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * gamma_out) {
unsigned long gcurr=0; /// running value to be compared against direct gamma unsigned long gcurr=0; // running value to be compared against direct gamma
int r=0; /// current value of reverse gamma table int r=0; // current value of reverse gamma table
int x=0; /// current indedx of reverse gamma table int x=0; // current indedx of reverse gamma table
MDF11(printk("\n")); MDF11(printk("\n"));
while ((r<256) && (x<256)) { while ((r<256) && (x<256)) {
gamma_out[x]=r; gamma_out[x]=r;
...@@ -458,23 +466,25 @@ void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * gamma_out) { ...@@ -458,23 +466,25 @@ void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * gamma_out) {
} }
} }
/** /** Calculate gamma table (and requested derivatives), insert new node if needed. */
* @brief calculate gamma table (and requested derivatives), insert new node if needed. int set_gamma_table (unsigned short hash16, ///< 16-bit unique (non-scaled) gamma table identifier. Can be 1-byte gamma and 1-byte black level shift
* @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? ///< TODO: make black level fine-grained?
* @param scale gamma table scale (currently 0x400 ~ 1.0) GAMMA_SCLALE_1 = 0x400 unsigned short scale, ///< gamma table scale (currently 0x400 ~ 1.0) GAMMA_SCLALE_1 = 0x400
* @param gamma_proto 16-bit gamma table prototype (or NULL) unsigned short * gamma_proto, ///< 16-bit gamma table prototype (or NULL)
* @param mode bits specify calculation mode: unsigned char mode, ///< bits specify calculation mode:
* - 1 - if set, no interrupts will be enabled between steps, whole operation will be atomic ///< - 1 - if set, no interrupts will be enabled between steps, whole operation will be atomic
* - 2 - calculate reverse gamma table ///<- 2 - calculate reverse gamma table
* - 4 - calculate FPGA-format gamma table. ///<- 4 - calculate FPGA-format gamma table
* - 8 - Lock (FPGA) table for specified color ///< - 8 - Lock (FPGA) table for specified color/port/subchannel
* @param color color index (0..3) to lock table for (if mode bit 4 is set), otherwise color is ignored int color, ///< index (0..63) combined with the next two parameters to lock
* @return index for the specified table or 0 if none exists and prototype was not provided (gamma_proto==NULL) ///< table for (if mode bit 4 is set), otherwise color, sensor_port, sensor_subchn are ignored
*/ int sensor_port, ///< sensor port number (0..3)
//#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) int sensor_subchn) ///< sensor sub-channel (connected to the same port through 10359 mux) (0..3)
int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short * gamma_proto, unsigned char mode, int color) { ///< @return index for the specified table or 0 if none exists and prototype was not provided (gamma_proto==NULL)
{
D1I(unsigned long flags); D1I(unsigned long flags);
int tmp_p, tmp_p1; //,tmp_p0; int tmp_p, tmp_p1; //,tmp_p0;
int cps=PORT_CHN_COLOR(color,sensor_port,sensor_subchn);
unsigned short gamma_linear[257]= unsigned short gamma_linear[257]=
{0x0000,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700,0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00,0x0e00,0x0f00, {0x0000,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700,0x0800,0x0900,0x0a00,0x0b00,0x0c00,0x0d00,0x0e00,0x0f00,
0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x0600,0x1700,0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x0600,0x1700,0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00,
...@@ -493,7 +503,7 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short ...@@ -493,7 +503,7 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
0xe000,0xe100,0xe200,0xe300,0xe400,0xe500,0x0600,0xe700,0xe800,0xe900,0xea00,0xeb00,0xec00,0xed00,0xee00,0xef00, 0xe000,0xe100,0xe200,0xe300,0xe400,0xe500,0x0600,0xe700,0xe800,0xe900,0xea00,0xeb00,0xec00,0xed00,0xee00,0xef00,
0xf000,0xf100,0xf200,0xf300,0xf400,0xf500,0x0600,0xf700,0xf800,0xf900,0xfa00,0xfb00,0xfc00,0xfd00,0xfe00,0xff00, 0xf000,0xf100,0xf200,0xf300,0xf400,0xf500,0x0600,0xf700,0xf800,0xf900,0xfa00,0xfb00,0xfc00,0xfd00,0xfe00,0xff00,
0xffff}; 0xffff};
MDF10(printk("hash16=0x%x scale=0x%x gamma_proto=0x%x mode =0x%x color=%x\n", (int) hash16, (int) scale, (int) gamma_proto, (int) mode, color)); MDF10(printk("hash16=0x%x scale=0x%x gamma_proto=0x%x mode =0x%x port/channel/color=%x\n", (int) hash16, (int) scale, (int) gamma_proto, (int) mode, cps));
if (!gamma_proto & (hash16==0)) { if (!gamma_proto & (hash16==0)) {
gamma_proto=gamma_linear; gamma_proto=gamma_linear;
...@@ -503,10 +513,10 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short ...@@ -503,10 +513,10 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
} }
///disable interrupts here ///disable interrupts here
D1I(local_irq_save(flags)); D1I(local_irq_save(flags));
/// look for the matching hash // look for the matching hash
tmp_p=gammas[0].newest_non_scaled; tmp_p=gammas[0].newest_non_scaled;
/// gammas[0].oldest_all=GAMMA_CACHE_NUMBER-1; // gammas[0].oldest_all=GAMMA_CACHE_NUMBER-1;
/// gammas[0].newest_all=1; // gammas[0].newest_all=1;
MDF10(printk("gammas[0].oldest_all=%d\n", gammas[0].oldest_all)); ///NOTE: 253 MDF10(printk("gammas[0].oldest_all=%d\n", gammas[0].oldest_all)); ///NOTE: 253
...@@ -517,46 +527,46 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short ...@@ -517,46 +527,46 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
tmp_p=gammas[tmp_p].older_non_scaled; tmp_p=gammas[tmp_p].older_non_scaled;
} }
MDF10(printk("tmp_p=0x%x\n", tmp_p)); ///NOTE: 0xff MDF10(printk("tmp_p=0x%x\n", tmp_p)); ///NOTE: 0xff
/// Got right hash? // Got right hash?
if (tmp_p == 0) { /// no luck if (tmp_p == 0) { // no luck
MDF10(printk("Need new table\n")); ///NOTE: never MDF10(printk("Need new table\n")); ///NOTE: never
if (!gamma_proto) { // if (!gamma_proto) { //
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
MDF10(printk("matching hash not found, new table is not provided\n")); ///NOTE: never MDF10(printk("matching hash not found, new table is not provided\n")); ///NOTE: never
return 0; /// matching hash not found, new table is not provided - return 0; return 0; // matching hash not found, new table is not provided - return 0;
} }
/// Create new proto table // Create new proto table
tmp_p=gamma_new_node(); tmp_p=gamma_new_node();
MDF10(printk("tmp_p=0x%x\n gamma_proto= 0x%x 0x%x 0x%x 0x%x\n", tmp_p, (int) gamma_proto[0], (int) gamma_proto[1], (int) gamma_proto[2], (int) gamma_proto[3])); MDF10(printk("tmp_p=0x%x\n gamma_proto= 0x%x 0x%x 0x%x 0x%x\n", tmp_p, (int) gamma_proto[0], (int) gamma_proto[1], (int) gamma_proto[2], (int) gamma_proto[3]));
if (unlikely(!tmp_p)) { /// could not allocate node if (unlikely(!tmp_p)) { // could not allocate node
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
return 0; /// failure: could not allocate node - return 0; return 0; // failure: could not allocate node - return 0;
} }
/// fill it: // fill it:
gammas[tmp_p].hash16=hash16; gammas[tmp_p].hash16=hash16;
gammas[tmp_p].scale=0; gammas[tmp_p].scale=0;
gammas[tmp_p].oldest_scaled=tmp_p; /// points to itself - no scaled versions yet gammas[tmp_p].oldest_scaled=tmp_p; // points to itself - no scaled versions yet
gammas[tmp_p].newest_scaled=tmp_p; /// points to itself - no scaled versions yet gammas[tmp_p].newest_scaled=tmp_p; // points to itself - no scaled versions yet
if ((mode & GAMMA_MODE_NOT_NICE)==0) { if ((mode & GAMMA_MODE_NOT_NICE)==0) {
/// let interrupts to take place, and disable again // let interrupts to take place, and disable again
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
MDF10(printk("Interrupts reenabled, tmp_p=0x%x\n", tmp_p)); MDF10(printk("Interrupts reenabled, tmp_p=0x%x\n", tmp_p));
D1I(local_irq_save(flags)); D1I(local_irq_save(flags));
/// check if it is still there (likely so, but allow it to fail). // check if it is still there (likely so, but allow it to fail).
if (unlikely(!is_gamma_current (hash16, 0, tmp_p))) { if (unlikely(!is_gamma_current (hash16, 0, tmp_p))) {
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
return 0; /// failure: other code used this node - return 0; (try not_nice next time?) return 0; // failure: other code used this node - return 0; (try not_nice next time?)
} }
} }
// memcpy ((void *)... // memcpy ((void *)...
memcpy (gammas[tmp_p].direct, gamma_proto, 257*2) ; ///copy the provided table (full 16 bits) memcpy (gammas[tmp_p].direct, gamma_proto, 257*2) ; ///copy the provided table (full 16 bits)
gammas[tmp_p].valid |= GAMMA_VALID_MASK; gammas[tmp_p].valid |= GAMMA_VALID_MASK;
/// add it to the chain // add it to the chain
MDF10(printk("insert_first_nonscaled(0x%x)\n", tmp_p)); MDF10(printk("insert_first_nonscaled(0x%x)\n", tmp_p));
insert_first_nonscaled(tmp_p); insert_first_nonscaled(tmp_p);
/// matching hash found,make it newest (remove from the chain + add to the chain) // matching hash found,make it newest (remove from the chain + add to the chain)
} else if (gammas[tmp_p].newer_non_scaled !=0) { /// if 0 - it is already the newest } else if (gammas[tmp_p].newer_non_scaled !=0) { // if 0 - it is already the newest
MDF10(printk("remove_from_nonscaled (0x%x)\n", tmp_p)); ///NOTE: 0xff MDF10(printk("remove_from_nonscaled (0x%x)\n", tmp_p)); ///NOTE: 0xff
remove_from_nonscaled (tmp_p); remove_from_nonscaled (tmp_p);
MDF10(printk("insert_first_nonscaled (0x%x)\n", tmp_p));///NOTE: 0xff MDF10(printk("insert_first_nonscaled (0x%x)\n", tmp_p));///NOTE: 0xff
...@@ -565,10 +575,10 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short ...@@ -565,10 +575,10 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
MDF10(printk("0x%x\n", tmp_p)); ///NOTE: 0xff MDF10(printk("0x%x\n", tmp_p)); ///NOTE: 0xff
/// now looking for the correct scale. // now looking for the correct scale.
if (scale==0) { if (scale==0) {
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
return tmp_p; /// wanted non-scaled, got it ///NOTE: returns here return tmp_p; // wanted non-scaled, got it ///NOTE: returns here
} }
tmp_p1=gammas[tmp_p].newest_scaled; tmp_p1=gammas[tmp_p].newest_scaled;
MDF10(printk("tmp_p1=0x%x\n", tmp_p1)); ///FIXME: 0xff MDF10(printk("tmp_p1=0x%x\n", tmp_p1)); ///FIXME: 0xff
...@@ -577,74 +587,74 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short ...@@ -577,74 +587,74 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
D10(printk(" >>tmp_p1=0x%x)\n", tmp_p1)); D10(printk(" >>tmp_p1=0x%x)\n", tmp_p1));
tmp_p1=gammas[tmp_p1].older_scaled; tmp_p1=gammas[tmp_p1].older_scaled;
} }
/// Got right scale? // Got right scale?
// if (tmp_p1 == 0) { /// no luck // if (tmp_p1 == 0) { // no luck
if (tmp_p1 == tmp_p) { /// no luck if (tmp_p1 == tmp_p) { // no luck
MDF10(printk("create new scaled table\n")); MDF10(printk("create new scaled table\n"));
/// create new scale // create new scale
tmp_p1=gamma_new_node(); tmp_p1=gamma_new_node();
if (unlikely(!tmp_p1)) { /// could not allocate node if (unlikely(!tmp_p1)) { // could not allocate node
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
return 0; /// failure: could not allocate node - return 0; return 0; // failure: could not allocate node - return 0;
} }
/// fill it // fill it
gammas[tmp_p1].hash16=hash16; gammas[tmp_p1].hash16=hash16;
gammas[tmp_p1].scale= scale; gammas[tmp_p1].scale= scale;
/// insert into 2-d // insert into 2-d
insert_first_scaled (tmp_p, tmp_p1); insert_first_scaled (tmp_p, tmp_p1);
/// insert into 1-d (all) // insert into 1-d (all)
insert_first_all (tmp_p1); insert_first_all (tmp_p1);
if ((mode & GAMMA_MODE_NOT_NICE)==0) { if ((mode & GAMMA_MODE_NOT_NICE)==0) {
/// let interrupts to take place, and disable again // let interrupts to take place, and disable again
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
D1I(local_irq_save(flags)); D1I(local_irq_save(flags));
/// check if it is still there (likely so, but allow it to fail). // check if it is still there (likely so, but allow it to fail).
if (unlikely(!is_gamma_current (hash16, scale, tmp_p1))) { if (unlikely(!is_gamma_current (hash16, scale, tmp_p1))) {
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
return 0; /// failure: other code used this node - return 0; (try not_nice next time?) return 0; // failure: other code used this node - return 0; (try not_nice next time?)
} }
} }
} else { /// scaled table already exists, make it first in 2 chains: } else { // scaled table already exists, make it first in 2 chains:
MDF10(printk("reuse scaled table\n")); MDF10(printk("reuse scaled table\n"));
/// found right scale, make it newest in two chain (2d - hash/scale and 1-d - all scaled together, regardless of the hash // found right scale, make it newest in two chain (2d - hash/scale and 1-d - all scaled together, regardless of the hash
///2-d chain ///2-d chain
if (gammas[tmp_p1].newer_scaled != tmp_p) { /// not already the newest of scales for the same hash if (gammas[tmp_p1].newer_scaled != tmp_p) { // not already the newest of scales for the same hash
remove_from_scaled (tmp_p1); remove_from_scaled (tmp_p1);
insert_first_scaled (tmp_p, tmp_p1); insert_first_scaled (tmp_p, tmp_p1);
} }
///1-d chain ///1-d chain
if (gammas[tmp_p1].newer_all != 0) { /// not already the newest from all scaled if (gammas[tmp_p1].newer_all != 0) { // not already the newest from all scaled
remove_from_all (tmp_p1); remove_from_all (tmp_p1);
insert_first_all (tmp_p1); insert_first_all (tmp_p1);
} }
} }
/// is the scaled version already calculated? // is the scaled version already calculated?
if ((gammas[tmp_p1].valid & GAMMA_VALID_MASK) == 0) { if ((gammas[tmp_p1].valid & GAMMA_VALID_MASK) == 0) {
/// calculate scaled version // calculate scaled version
gamma_calc_scaled (scale, gammas[tmp_p].direct, gammas[tmp_p1].direct); gamma_calc_scaled (scale, gammas[tmp_p].direct, gammas[tmp_p1].direct);
gammas[tmp_p1].valid |= GAMMA_VALID_MASK; gammas[tmp_p1].valid |= GAMMA_VALID_MASK;
} }
if (mode & GAMMA_MODE_HARDWARE) { if (mode & GAMMA_MODE_HARDWARE) {
/// is hardware-encoded array already calculated (do it if not)? // is hardware-encoded array already calculated (do it if not)?
if ((gammas[tmp_p1].valid & GAMMA_FPGA_MASK)==0) { if ((gammas[tmp_p1].valid & GAMMA_FPGA_MASK)==0) {
gamma_encode_fpga(gammas[tmp_p1].direct, gammas[tmp_p1].fpga); gamma_encode_fpga(gammas[tmp_p1].direct, gammas[tmp_p1].fpga);
gammas[tmp_p1].valid |= GAMMA_FPGA_MASK; gammas[tmp_p1].valid |= GAMMA_FPGA_MASK;
} }
} }
if (mode & GAMMA_MODE_LOCK) { if (mode & GAMMA_MODE_LOCK) {
/// lock the node for the color // lock the node for the color/port/channel
lock_gamma_node (tmp_p1, color); lock_gamma_node (tmp_p1, color, sensor_port,sensor_subchn);
} }
if (mode & GAMMA_MODE_NEED_REVERSE) { if (mode & GAMMA_MODE_NEED_REVERSE) {
if ((gammas[tmp_p1].valid & GAMMA_VALID_REVERSE)==0) { if ((gammas[tmp_p1].valid & GAMMA_VALID_REVERSE)==0) {
if ((mode & GAMMA_MODE_NOT_NICE)==0) { if ((mode & GAMMA_MODE_NOT_NICE)==0) {
/// let interrupts to take place, and disable again // let interrupts to take place, and disable again
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
D1I(local_irq_save(flags)); D1I(local_irq_save(flags));
/// check if it is still there (likely so, but allow it to fail). // check if it is still there (likely so, but allow it to fail).
if (unlikely(!is_gamma_current (hash16, 0, tmp_p))) { if (unlikely(!is_gamma_current (hash16, 0, tmp_p))) {
D1I(local_irq_restore(flags)); D1I(local_irq_restore(flags));
return 0; /// failure: other code used this node - return 0; (try not_nice next time?) return 0; // failure: other code used this node - return 0; (try not_nice next time?)
} }
} }
gamma_calc_reverse(gammas[tmp_p1].direct, gammas[tmp_p1].reverse); gamma_calc_reverse(gammas[tmp_p1].direct, gammas[tmp_p1].reverse);
...@@ -658,26 +668,26 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short ...@@ -658,26 +668,26 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
///====================================== ///======================================
/// File operations: // File operations:
/// open, release - nop // open, release - nop
/// read - none // read - none
/// write should be a single call (with or without actual table), file pointer after write is result node index (0 - failure) // write should be a single call (with or without actual table), file pointer after write is result node index (0 - failure)
/// returns - full length passed or 0 if failed // returns - full length passed or 0 if failed
/// write -> set_gamma_table: first 2 bytes [0.1] - table hash - (i.e. gamma | (black << 8)), // write -> set_gamma_table: first 2 bytes [0.1] - table hash - (i.e. gamma | (black << 8)),
/// next 2 bytes [2.3] - scale (0..0xffff), // next 2 bytes [2.3] - scale (0..0xffff),
/// next 1 byte [4] - mode (1 - not_nice, 2 - need reverse, 4 - hardware, 8 - lock) // 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 byte [5] - color only if lock bit in mode is set
/// next 514 bytes [6..519] - 16-bit gamma table // 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 // 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 // file pointer - absolute frame number
/// lseek (SEEK_SET, value) - do nothing, return 0 // 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_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) - do nothing?, do not modify file pointer
/// lseek (SEEK_END, value > 0) - execute commands, 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, 1) - initialize all the gamma data structures
/// lseek (SEEK_END, 2) - check that current hash/scale/index are still current // lseek (SEEK_END, 2) - check that current hash/scale/index are still current
/// mmap (should be used read only) // 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_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 //#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
/** /**
...@@ -716,7 +726,7 @@ int gammas_open(struct inode *inode, struct file *file) { ...@@ -716,7 +726,7 @@ int gammas_open(struct inode *inode, struct file *file) {
privData-> mode= 0; privData-> mode= 0;
return 0; return 0;
default: default:
kfree(file->private_data); /// already allocated kfree(file->private_data); // already allocated
return -EINVAL; return -EINVAL;
} }
file->f_pos = 0; file->f_pos = 0;
...@@ -784,7 +794,7 @@ loff_t gammas_lseek (struct file * file, loff_t offset, int orig) { ...@@ -784,7 +794,7 @@ loff_t gammas_lseek (struct file * file, loff_t offset, int orig) {
file->f_pos=0; file->f_pos=0;
break; break;
case LSEEK_GAMMA_ISCURRENT: case LSEEK_GAMMA_ISCURRENT:
if (file->f_pos==0) break; /// wrong index if (file->f_pos==0) break; // wrong index
if (!is_gamma_current (privData->hash16, privData->scale, (int) file->f_pos)) file->f_pos=0; if (!is_gamma_current (privData->hash16, privData->scale, (int) file->f_pos)) file->f_pos=0;
break; break;
default: ///other commands default: ///other commands
...@@ -792,44 +802,42 @@ loff_t gammas_lseek (struct file * file, loff_t offset, int orig) { ...@@ -792,44 +802,42 @@ loff_t gammas_lseek (struct file * file, loff_t offset, int orig) {
} }
break; break;
} }
default: /// not SEEK_SET/SEEK_CUR/SEEK_END default: // not SEEK_SET/SEEK_CUR/SEEK_END
return -EINVAL; return -EINVAL;
} /// switch (orig) } // switch (orig)
MDF10(printk("file->f_pos=0x%x\n",(int) file->f_pos)); MDF10(printk("file->f_pos=0x%x\n",(int) file->f_pos));
return file->f_pos ; return file->f_pos ;
default: /// other minors default: // other minors
return -EINVAL; return -EINVAL;
} }
} }
/** /** Gammas driver WRITE method
* @brief Gammas driver WRITE method
* write should be a single call (with or without actual table), file pointer after write is result node index (0 - failure) * write should be a single call (with or without actual table), file pointer after write is result node index (0 - failure)
* write method receives data and uses it with \b set_gamma_table() * write method receives data and uses it with \b set_gamma_table()
* - first 2 bytes [0.1] - scale (0..0xffff), * - first 2 bytes [0.1] - scale (0..0xffff),
* - next 2 bytes [2.3] - table hash - (i.e. gamma | (black << 8)), * - next 2 bytes [2.3] - table hash - (i.e. gamma | (black << 8)),
* - next 1 byte [4] - mode (1 - not_nice, 2 - need reverse, 4 - hardware, 8 - lock) * - next 1 byte [4] - mode (1 - not_nice, 2 - need reverse, 4 - hardware, 8 - lock)
* - next 1 byte [5] - color only if lock bit in mode is set * - next 1 byte [5] - color only if lock bit in mode is set. Note: could not find why it was >>3 - error?, seems never used. In 393 it holds {port[1:0],chn[1:0],color[1:0]}
* - next 514 bytes [6..519] - 16-bit gamma table (if less than 514 bytes NULL will be passed to \b set_gamma_table() * - next 514 bytes [6..519] - 16-bit gamma table (if less than 514 bytes NULL will be passed to \b set_gamma_table()
* sets file pointer to gamma cache index (0 - no table exist) * sets file pointer to gamma cache index (0 - no table exist) */
* @param file ssize_t gammas_write(struct file * file, ///< this file structure
* @param buf const char * buf, ///< userland buffer
* @param count size_t count, ///< number of bytes to write
* @param off loff_t *off) ///< updated offset in the buffer
* @return full length passed or 0 if failed ///< @return full length passed or 0 if failed
*/ {
ssize_t gammas_write(struct file * file, const char * buf, size_t count, loff_t *off) {
struct gammas_pd * privData = (struct gammas_pd *) file->private_data; struct gammas_pd * privData = (struct gammas_pd *) file->private_data;
struct { struct {
unsigned short scale; unsigned short scale;
unsigned short hash16; unsigned short hash16;
unsigned char mode; unsigned char mode;
unsigned char color; unsigned char color; // 393: it is now combination of color, port and channel. Could not find what are the 3 LSBs ((privData->color >> 3) &3) below
unsigned short gamma[257]; unsigned short gamma[257];
} data; } data;
int head, result; int head, result;
/// ************* NOTE: Never use file->f_pos in write() and read() !!! // ************* NOTE: Never use file->f_pos in write() and read() !!!
unsigned short * gamma= data.gamma; unsigned short * gamma= data.gamma;
MDF10(printk(" file->f_pos=0x%x, *off=0x%x\n", (int) file->f_pos, (int) *off)); MDF10(printk(" file->f_pos=0x%x, *off=0x%x\n", (int) file->f_pos, (int) *off));
switch (privData->minor) { switch (privData->minor) {
...@@ -838,12 +846,13 @@ ssize_t gammas_write(struct file * file, const char * buf, size_t count, loff_t ...@@ -838,12 +846,13 @@ ssize_t gammas_write(struct file * file, const char * buf, size_t count, loff_t
if(count) { if(count) {
if(copy_from_user((char *) &data, buf, count)) return -EFAULT; if(copy_from_user((char *) &data, buf, count)) return -EFAULT;
head=6; head=6;
if ((count-head) < (2 * 257)) gamma=NULL; /// complete gamma table is not available if ((count-head) < (2 * 257)) gamma=NULL; // complete gamma table is not available
if (head>count) head=count; if (head>count) head=count;
memcpy (&(privData->scale),&(data.scale),head); memcpy (&(privData->scale),&(data.scale),head);
MDF10(printk("count=%d, head=%d, hash16=0x%x scale=0x%x mode=0x%x color=%x\n", count, head, (int) data.hash16, (int) data.scale, (int) data.mode, (int) data.color)); MDF10(printk("count=%d, head=%d, hash16=0x%x scale=0x%x mode=0x%x color=%x\n", count, head, (int) data.hash16, (int) data.scale, (int) data.mode, (int) data.color));
MDF10(printk("count=%d, head=%d, hash16=0x%x scale=0x%x mode=0x%x color=%x\n", count, head, (int) privData->hash16, (int) privData->scale, (int) privData->mode, (int) privData->color)); MDF10(printk("count=%d, head=%d, hash16=0x%x scale=0x%x mode=0x%x color=%x\n", count, head, (int) privData->hash16, (int) privData->scale, (int) privData->mode, (int) privData->color));
result=set_gamma_table (privData->hash16, privData->scale, gamma, privData->mode, ( privData->color >> 3) & 3); // result=set_gamma_table (privData->hash16, privData->scale, gamma, privData->mode, ( privData->color >> 3) & 3);
result=set_gamma_table (privData->hash16, privData->scale, gamma, privData->mode, ( privData->color >> 0) & 3, ( privData->color >> 4) & 3, ( privData->color >> 2) & 3);
*off= (result>0)?result:0; *off= (result>0)?result:0;
} else *off=0; } else *off=0;
MDF10(printk("file->f_pos=0x%x\n", (int) *off)); MDF10(printk("file->f_pos=0x%x\n", (int) *off));
...@@ -885,8 +894,8 @@ static int __init gammas_init(void) { ...@@ -885,8 +894,8 @@ static int __init gammas_init(void) {
printk ("Starting "X3X3_GAMMAS_DRIVER_NAME" - %d \n",GAMMAS_MAJOR); printk ("Starting "X3X3_GAMMAS_DRIVER_NAME" - %d \n",GAMMAS_MAJOR);
init_gammas(); init_gammas();
MDF10(printk("set_gamma_table (0, GAMMA_SCLALE_1, NULL, 0, 0)\n"); udelay (ELPHEL_DEBUG_DELAY)); MDF10(printk("set_gamma_table (0, GAMMA_SCLALE_1, NULL, 0, 0)\n"); udelay (ELPHEL_DEBUG_DELAY));
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 set_gamma_table (0, GAMMA_SCLALE_1, NULL, 0, 0, 0, 0); // maybe not needed to put linear to cache - it can be calculated as soon FPGA will be tried to be programmed with
/// hash16==0 // hash16==0
res = register_chrdev(GAMMAS_MAJOR, "gamma_tables_operations", &gammas_fops); res = register_chrdev(GAMMAS_MAJOR, "gamma_tables_operations", &gammas_fops);
if(res < 0) { if(res < 0) {
......
...@@ -18,14 +18,14 @@ void gamma_encode_fpga(unsigned short * gamma_in, unsigned long * gamma_out);/// ...@@ -18,14 +18,14 @@ void gamma_encode_fpga(unsigned short * gamma_in, unsigned long * gamma_out);///
void gamma_calc_scaled (unsigned short scale,unsigned short * gamma_in, unsigned short * gamma_out);/// scale gamma table by (scale>>GAMMA_SCALE_SHIFT), saturate to 0..0xffff void gamma_calc_scaled (unsigned short scale,unsigned short * gamma_in, unsigned short * 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) //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)
void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * 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) void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * 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 // 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 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 (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) // 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_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_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 // #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
// color/frame pair // color/frame pair
int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short * gamma_proto, unsigned char mode, int color); int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short * gamma_proto, unsigned char mode, int color, int sensor_port, int sensor_subchn);
unsigned long get_locked_hash32(int color); unsigned long get_locked_hash32(int color);
#endif #endif
...@@ -92,10 +92,10 @@ ...@@ -92,10 +92,10 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/autoconf.h> //#include <linux/autoconf.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <asm/system.h> //#include <asm/system.h>
#include <asm/byteorder.h> // endians #include <asm/byteorder.h> // endians
#include <asm/io.h> #include <asm/io.h>
...@@ -103,14 +103,21 @@ ...@@ -103,14 +103,21 @@
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/elphel/driver_numbers.h> #include <asm/outercache.h>
#include <asm/elphel/c313a.h> #include <asm/cacheflush.h>
#include <asm/elphel/exifa.h>
#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
#include "fpga_io.h"//fpga_table_write_nice
#include "framepars.h" // for debug mask
#include <elphel/driver_numbers.h>
#include <elphel/c313a.h>
#include <elphel/exifa.h>
//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
//#include "fpga_io.h"//fpga_table_write_nice
#include "framepars.h" // for debug mask
#include <elphel/elphel393-mem.h>
#include "legacy_defines.h" // temporarily
//#include "cc3x3.h" //#include "cc3x3.h"
#include "x393.h"
#include "histograms.h" #include "histograms.h"
/** /**
...@@ -118,36 +125,57 @@ ...@@ -118,36 +125,57 @@
*/ */
#if ELPHEL_DEBUG #if ELPHEL_DEBUG
/// only when commands are issued // only when commands are issued
#define MDF21(x) { if (GLOBALPARS(G_DEBUG) & (1 <<21)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} } #define MDF21(x) { if (GLOBALPARS(G_DEBUG) & (1 <<21)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
/// includes tasklets // includes tasklets
#define MDF22(x) { if (GLOBALPARS(G_DEBUG) & (1 <<22)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} } #define MDF22(x) { if (GLOBALPARS(G_DEBUG) & (1 <<22)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#else #else
#define MDF21(x) #define MDF21(x)
#define MDF22(x) #define MDF22(x)
#endif #endif
//[SENSOR_PORTS]
u32 (*fpga_hist_data)[SENSOR_PORTS][MAX_SENSORS][PARS_FRAMES][4][256];
dma_addr_t fpga_hist_phys; // physical address of the start of the received histogram data
//dma_buf_ptr = pElphel_buf->vaddr;
//dma_handle = pElphel_buf->paddr;
#define X3X3_HISTOGRAMS_DRIVER_NAME "Elphel (R) Model 353 Histograms device driver" #define X3X3_HISTOGRAMS_DRIVER_NAME "Elphel (R) Model 353 Histograms device driver"
static struct histogram_stuct_t histograms[HISTOGRAM_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE))); ///* for each port and possible sensor subchannel provides index in combine histogram data
int histograms_map[SENSOR_PORTS][MAX_SENSORS];
static int numHistChn = 0;
/** Variable-length array (length is the total number of active sensors <=16), each being the same as in 353:
* consisting of SENSOR_PORTS histogram_stuct_t structures */
struct histogram_stuct_t (*histograms)[HISTOGRAM_CACHE_NUMBER];
dma_addr_t histograms_phys; ///< likely not needed
struct histogram_stuct_t * histograms_p; // to use with mmap
/*
static struct histogram_stuct_t histograms[HISTOGRAM_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE)));
struct histogram_stuct_t * histograms_p; // to use with mmap struct histogram_stuct_t * histograms_p; // to use with mmap
wait_queue_head_t hist_y_wait_queue; /// wait queue for the G1 histogram (used as Y) */
wait_queue_head_t hist_c_wait_queue; /// wait queue for all the other (R,G2,B) histograms (color)
wait_queue_head_t hist_y_wait_queue; // wait queue for the G1 histogram (used as Y)
wait_queue_head_t hist_c_wait_queue; // wait queue for all the other (R,G2,B) histograms (color)
struct histograms_pd { struct histograms_pd {
int minor; int minor;
unsigned long frame; unsigned long frame;
int frame_index; /// -1 if invalid int frame_index; ///< -1 if invalid
int needed; int needed;
int wait_mode; /// 0 - wait just for G1 histogram, 1 - wait for all histograms int wait_mode; ///< 0 - wait just for G1 histogram, 1 - wait for all histograms
int request_en; /// enable requesting histogram for the specified frame (0 - rely on the available ones) int request_en; ///< enable requesting histogram for the specified frame (0 - rely on the available ones)
struct wait_queue *hist_y_wait_queue; /// wait queue for the G1 histogram (used as Y) ///NOTE: not used at all? int port; ///< selected sensor port (0..3)
struct wait_queue *hist_c_wait_queue; /// wait queue for all the other (R,G2,B) histograms (color) ///NOTE: not used at all? int subchannel; ///< selected sensor sub_channel(0..3)
struct wait_queue *hist_y_wait_queue; ///< wait queue for the G1 histogram (used as Y) ///NOTE: not used at all?
/// something else to be added here? struct wait_queue *hist_c_wait_queue; ///< wait queue for all the other (R,G2,B) histograms (color) ///NOTE: not used at all?
// something else to be added here?
}; };
int histograms_open (struct inode *inode, struct file *file); int histograms_open (struct inode *inode, struct file *file);
...@@ -160,134 +188,204 @@ static int __init histograms_init(void); ...@@ -160,134 +188,204 @@ static int __init histograms_init(void);
inline void histogram_calc_cumul ( unsigned long * hist, unsigned long * cumul_hist ); inline void histogram_calc_cumul ( unsigned long * hist, unsigned long * cumul_hist );
inline void histogram_calc_percentiles ( unsigned long * cumul_hist, unsigned char * percentile); inline void histogram_calc_percentiles ( unsigned long * cumul_hist, unsigned char * percentile);
/** Initialize FPGA DMA engine for histograms. Obviously requires bitstream to be loaded.
* Histograms will be initialized for all possible ports/channels, only some will be enabled */
int histograms_init_hardware(void)
{
int port, chn;
x393_hist_saxi_addr_t saxi_addr;
fpga_hist_data = (u32 [SENSOR_PORTS][MAX_SENSORS][PARS_FRAMES][4][256]) pElphel_buf->d2h_vaddr; // must be page-aligned!
fpga_hist_phys = pElphel_buf->d2h_paddr;
for (port=0; port<SENSOR_PORTS; port++) for (chn=0; chn < MAX_SENSORS; chn++) {
saxi_addr.page=(fpga_hist_phys >> PAGE_SHIFT)+ PARS_FRAMES * (chn + MAX_SENSORS *port);// table for 4 colors is exactly 1 page;
set_x393_hist_saxi_addr (saxi_addr, chn); // Histogram DMA addresses (in 4096 byte pages)
}
// Hand all data to device
dma_sync_single_for_device(NULL, fpga_hist_phys, SENSOR_PORTS*MAX_SENSORS*PARS_FRAMES*4*256*4, DMA_FROM_DEVICE);
/* histograms_dma_ctrl(2);
unsigned long gtab_r; return 0;
unsigned long gtab_g; }
unsigned long gtab_gb;
unsigned long gtab_b;
*/ /** Reset/Enable/disable histograms DMA engine */
void histograms_dma_ctrl(int mode) ///< 0 - reset, 1 - disable, 2 - enable
{
x393_hist_saxi_mode_t saxi_mode;
saxi_mode.d32= 0;
saxi_mode.cache= 3;
saxi_mode.confirm=1;
saxi_mode.nrst= (mode)? 1:0;
saxi_mode.en= (mode>1)?1:0;
set_x393_hist_saxi_mode(saxi_mode);
}
/**
* @brief Initialize histgograms data structures (called at module init) /** Initialize histograms data structures, should be called when active subchannels are known (maybe use DT)?
*/ */
void init_histograms(void) { void init_histograms(int chn_mask) ///< combined subchannels and ports Save mask to global P-variable
unsigned long flags; {
int i; unsigned long flags;
histograms_p=histograms; int p,s,i, sz,pages;
MDF21(printk("\n")); numHistChn = 0; //__builtin_popcount (chn_mask & 0xffff);
local_irq_save(flags); if (sz & (PAGE_SIZE-1)) pages++;
for (i=0; i < HISTOGRAM_CACHE_NUMBER; i++) { for (p=0; p< SENSOR_PORTS; p++) for (s=0;s <MAX_SENSORS;s++) {
histograms[i].frame=0xffffffff; i = p * SENSOR_PORTS + s;
histograms[i].valid=0; if (chn_mask & (1 << i)){
} histograms_map = numHistChn++;
local_irq_restore(flags); GLOBALPARS(p, G_HIST_LAST_INDEX + s) =0; // mark as valid
GLOBALPARS(p, G_SUBCHANNELS) |= 1 << s;
} else {
histograms_map = -1;
GLOBALPARS(p, G_HIST_LAST_INDEX + s) =0xffffffff; // mark as invalid
GLOBALPARS(p, G_SUBCHANNELS) &= ~(1 << s);
}
}
//G_SUBCHANNELS
sz = numHistChn * HISTOGRAM_CACHE_NUMBER * sizeof(struct histogram_stuct_t);
pages = sz >> PAGE_SHIFT;
// When device == NULL, dma_alloc_coherent just allocates notmal memory, page aligned, CMA if available
histograms = (struct histogram_stuct_t*[HISTOGRAM_CACHE_NUMBER]) dma_alloc_coherent(NULL,(sz * PAGE_SIZE),&histograms_phys,GFP_KERNEL);
BUG_ON(!histograms);
histograms_p=histograms;
MDF21(printk("\n"));
local_irq_save(flags);
for (s=0; s<numHistChn; s++) {
for (i=0; i < HISTOGRAM_CACHE_NUMBER; i++) {
histograms[s][i].frame=0xffffffff;
histograms[s][i].valid=0;
}
}
local_irq_restore(flags);
}
/** Get histogram index for sensor port/channel, skipping unused ones */
int get_hist_index (int sensor_port, ///< sensor port number (0..3)
int sensor_chn) ///< sensor subchannel (0 w/o multiplexer)
///< @return index of used (active) histogram set (just skipping unused ports/subchannels
{
return histograms_map[sensor_port][sensor_chn];
} }
/** /**
* @brief Get histograms from the FPGA (called as tasklet?) * @brief Get histograms from the FPGA (called as tasklet?)
* @param frame absolute frame number (Caller should match it to the hardware frame)
* TODO: should it be one frame behind current? * TODO: should it be one frame behind current?
* @param needed bits specify what histograms (color, type) are requested * each group of 4 bits cover 4 colors of the same type */
* @param gammaHash array of 4 hash32 values to be saved with the histograms int set_histograms (int sensor_port, ///< sensor port number (0..3)
* each group of 4 bits cover 4 colors of the same type: int sensor_chn, ///< sensor subchannel (0 w/o multiplexer)
* - bits 0..3 - read raw histograms from the FPGA - normally called from IRQ/tasklet (use just 1 color for autoexposure to speed up?) unsigned long frame, ///< absolute frame number (Caller should match it to the hardware frame)
* @return 0 for now int needed, ///< bits specify what histograms (color, type) are requested
*/ ///< each group of 4 bits covers 4 colors of the same type:
///< - bits 0..3 - read raw histograms from the FPGA - normally called from IRQ/tasklet (use just 1 color for autoexposure to speed up?)
int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash, unsigned long * framep) { ///< - bits 4..7 - calculate cumulative histograms (sum of raw ones) - normally called from applications
// unsigned long flags; ///< - bits 8..11 - calculate percentiles (reverse cumulative histograms) - normally called from applications
//hist_next_index ///< "needed" for raw histograms should be specified explicitly (can not be read from FPGA later),
int i, color_start; ///< "needed" for cumul_hist will be added automatically if percentiles are requested
if (histograms[GLOBALPARS(G_HIST_LAST_INDEX)].frame!=frame) { unsigned long * gammaHash,///< array of 4 hash32 values to be saved with the histograms (same gamma for all sub-channels), NULL OK
GLOBALPARS(G_HIST_LAST_INDEX)=(GLOBALPARS(G_HIST_LAST_INDEX)+1) & (HISTOGRAM_CACHE_NUMBER-1); unsigned long * framep) ///< array of 8 values to copy (frame, gains,expos,vexpos, focus), NULL OK
histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid=0; /// overwrite all ///< @return 0 OK, -EINVAL unused port/channel
histograms[GLOBALPARS(G_HIST_LAST_INDEX)].frame=frame; /// add to existent {
if (framep) memcpy (&(histograms[GLOBALPARS(G_HIST_LAST_INDEX)].frame), framep, 32); // copy provided frame, gains,expos,vexpos, focus int i, color_start, hist_indx, hist_frame;
if (gammaHash) memcpy (&(histograms[GLOBALPARS(G_HIST_LAST_INDEX)].gtab_r), gammaHash, 16); // copy provided 4 hash32 values hist_indx=get_hist_index(sensor_port,sensor_chn);
} else { if (hist_indx <0 ) return -EINVAL;
needed &= ~histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid; /// remove those that are already available from the request if (histograms[GLOBALPARS(sensor_port,G_HIST_LAST_INDEX+sensor_chn)].frame!=frame) {
} GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn)=(GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn)+1) & (HISTOGRAM_CACHE_NUMBER-1);
for (i=0; i<4; i++) if (needed & ( 1 << i )) { histograms[hist_indx][GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn)].valid=0; // overwrite all
color_start= i<<8 ; histograms[hist_indx][GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn)].frame=frame; // add to existent
fpga_hist_read_nice (color_start, 256, (unsigned long *) &histograms[GLOBALPARS(G_HIST_LAST_INDEX)].hist[color_start]); if (framep) memcpy (&(histograms[GLOBALPARS(sensor_port,G_HIST_LAST_INDEX)].frame), framep, 32); // copy provided frame, gains,expos,vexpos, focus
histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid |= 1 << i; if (gammaHash) memcpy (&(histograms[GLOBALPARS(sensor_port,G_HIST_LAST_INDEX)].gtab_r), gammaHash, 16); // copy provided 4 hash32 values
} } else {
return 0; needed &= ~histograms[hist_indx][GLOBALPARS(sensor_port,G_HIST_LAST_INDEX)].valid; // remove those that are already available from the request
}
// TODO: handle valid and needed for multichannel?
if (!(needed & 0xf)) // nothing to do with FPGA
return 0;
// Copying received data to histograms structure, maybe later we can skip that step and use data in place
// hist_frame=(frame-1) & PARS_FRAMES_MASK; // TODO: Verify
hist_frame=frame & PARS_FRAMES_MASK; // TODO: Verify
for (i=0; i<4; i++) if (needed & ( 1 << i )) {
u32 phys_addr= fpga_hist_phys + PAGE_SIZE*(hist_frame + PARS_FRAMES * (sensor_chn + MAX_SENSORS *sensor_port)) + i*256*sizeof(u32); // start of selected color
u32 * dma_data = &fpga_hist_data[sensor_port][sensor_chn][hist_frame][i][0];
// invalidate both caches
outer_inv_range(phys_addr, phys_addr + (256*sizeof(u32) - 1));
__cpuc_flush_dcache_area(dma_data, 256*sizeof(u32));
color_start= i<<8 ;
memcpy(&histograms[hist_indx][GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn)],
dma_data, 256*sizeof(u32));
// old in 353: fpga_hist_read_nice (color_start, 256, (unsigned long *) &histograms[GLOBALPARS(G_HIST_LAST_INDEX)].hist[color_start]);
histograms[hist_indx][ GLOBALPARS(sensor_port,G_HIST_LAST_INDEX+sensor_chn)].valid |= 1 << i;
}
return 0;
} }
/** /**
* @brief Get derivative histograms (raw FPGA should be already there read by a tasklet needed) * @brief Get derivative histograms (raw FPGA should be already there read by a tasklet needed)
* Will look for requested (or earlier) frame that has the "needed" raw histograms * Will look for requested (or earlier) frame that has the "needed" raw histograms
* @param frame absolute frame number (Caller should match it to the hardware frame).
* TODO: should it be one frame behind current? - yes, exactly * TODO: should it be one frame behind current? - yes, exactly
* @param needed bits specify what histograms (color, type) are requested
* TODO: Add P_* parameter - what to read from tasklet, turn colors it off for high FPS/small window
* each group of 4 bits cover 4 colors of the same type:
* - bits 0..3 - ignored here (used for raw FPGA tables)
* - bits 4..7 - calculate cumulative histograms (sum of raw ones) - normally called from applications
* - bits 8..11 - calculate percentiles (reverse cumulative histograms) - normally called from applications
* "needed" for raw histograms should be specified explicitely (can not be read from FPGA later),
* "needed" for cumul_hist will be added automatically if percentiles are requested
* @return index of the histogram (>=0) if OK, otherwise:
* - -1 not reading FPGA and frame number stored is different from the requested (too late - histogram buffer overrun?)
*/ */
///TODO: Make color (rare) histograms survive longer? - Challenge - Y goes first, we do not know if it will be followed by color ///TODO: Make color (rare) histograms survive longer? - Challenge - Y goes first, we do not know if it will be followed by color
int get_histograms (unsigned long frame, int needed) { int get_histograms(int sensor_port, ///< sensor port number (0..3)
// unsigned long flags; int sensor_chn, ///< sensor subchannel (0 w/o multiplexer)
//hist_next_index unsigned long frame, ///< absolute frame number (Caller should match it to the hardware frame)
int i, color_start; int needed) ///< bits specify what histograms (color, type) are requested
int index=GLOBALPARS(G_HIST_LAST_INDEX); ///< each group of 4 bits covers 4 colors of the same type:
int raw_needed=(needed | (needed>>4) | needed>>8) & 0xf; ///< - bits 0..3 - read raw histograms from the FPGA - normally called from IRQ/tasklet (use just 1 color for autoexposure to speed up?)
for (i=0;i<HISTOGRAM_CACHE_NUMBER;i++) { ///< - bits 4..7 - calculate cumulative histograms (sum of raw ones) - normally called from applications
MDF21(printk("index=%d, needed=0x%x\n",index,needed)); ///< - bits 8..11 - calculate percentiles (reverse cumulative histograms) - normally called from applications
if ((histograms[index].frame <= frame) && ((histograms[index].valid & raw_needed)==raw_needed)) break; ///< "needed" for raw histograms should be specified explicitly (can not be read from FPGA later),
index = (index-1) & (HISTOGRAM_CACHE_NUMBER-1); ///< "needed" for cumul_hist will be added automatically if percentiles are requested
} ///< @return index of the histogram (>=0) if OK, otherwise:
if (i>=HISTOGRAM_CACHE_NUMBER) { ///< - -EFAULT not reading FPGA and frame number stored is different from the requested (too late - histogram buffer overrun?)
ELP_KERR(printk("no histograms exist for requested colors (0x%x), requested 0x%x\n",raw_needed,needed)); ///< - -EINVAL unused port/channel
return -1; /// if Y - never calculated, if C - maybe all the cache is used by Y {
} int i, color_start, index;
needed &= ~0x0f; /// mask out FPGA read requests -= they are not handled here anymore (use set_histograms()) int hist_indx=get_hist_index(sensor_port,sensor_chn);
MDF22(printk("needed=0x%x\n",needed)); if (hist_indx <0 ) return -EINVAL;
needed |= ((needed >>4) & 0xf0); /// cumulative histograms are needed for percentile calculations index=GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn);
needed &= ~histograms[index].valid; int raw_needed=(needed | (needed>>4) | needed>>8) & 0xf;
/// if ((needed >> 4) & (~histograms[index].valid) & 0x0f) return -2 ; /// some needed raw histograms are not available NOTE: now never comes here for (i=0;i<HISTOGRAM_CACHE_NUMBER;i++) {
MDF22(printk("needed=0x%x\n",needed)); MDF21(printk("index=%d, needed=0x%x\n",index,needed));
if (needed & 0xf0) { /// Calculating cumulative histograms if ((histograms[hist_indx][index].frame <= frame) && ((histograms[hist_indx][index].valid & raw_needed)==raw_needed)) break;
for (i=0; i<4; i++) if (needed & ( 0x10 << i )) { index = (index-1) & (HISTOGRAM_CACHE_NUMBER-1);
color_start= i<<8 ; }
histogram_calc_cumul ( (unsigned long *) &histograms[index].hist[color_start], (unsigned long *) &histograms[index].cumul_hist[color_start] ); if (i>=HISTOGRAM_CACHE_NUMBER) {
histograms[index].valid |= 0x10 << i; ELP_KERR(printk("no histograms exist for requested colors (0x%x), requested 0x%x\n",raw_needed,needed));
return -EFAULT; // if Y - never calculated, if C - maybe all the cache is used by Y
}
needed &= ~0x0f; // mask out FPGA read requests -= they are not handled here anymore (use set_histograms())
MDF22(printk("needed=0x%x\n",needed));
needed |= ((needed >>4) & 0xf0); // cumulative histograms are needed for percentile calculations
needed &= ~histograms[hist_indx][index].valid;
MDF22(printk("needed=0x%x\n",needed));
if (needed & 0xf0) { // Calculating cumulative histograms
for (i=0; i<4; i++) if (needed & ( 0x10 << i )) {
color_start= i<<8 ;
histogram_calc_cumul ( (unsigned long *) &histograms[hist_indx][index].hist[color_start], (unsigned long *) &histograms[hist_indx][index].cumul_hist[color_start] );
histograms[hist_indx][index].valid |= 0x10 << i;
}
MDF21(printk("needed=0x%x, valid=0x%lx\n",needed,histograms[hist_indx][index].valid));
} }
MDF21(printk("needed=0x%x, valid=0x%lx\n",needed,histograms[index].valid)); if (needed & 0xf00) { // Calculating percentiles
} for (i=0; i<4; i++) if (needed & ( 0x100 << i )) {
if (needed & 0xf00) { /// Calculating percentiles color_start= i<<8 ;
for (i=0; i<4; i++) if (needed & ( 0x100 << i )) { histogram_calc_percentiles ( (unsigned long *) &histograms[hist_indx][index].cumul_hist[color_start], (unsigned char *) &histograms[hist_indx][index].percentile[color_start] );
color_start= i<<8 ; histograms[hist_indx][index].valid |= 0x100 << i;
histogram_calc_percentiles ( (unsigned long *) &histograms[index].cumul_hist[color_start], (unsigned char *) &histograms[index].percentile[color_start] ); }
histograms[index].valid |= 0x100 << i; MDF21(printk("needed=0x%x, valid=0x%lx\n",needed, histograms[hist_indx][index].valid));
} }
MDF21(printk("needed=0x%x, valid=0x%lx\n",needed, histograms[index].valid)); return index;
}
return index;
} }
/** /** Calculate cumulative histogram (one color component) from the corresponding raw histogram */
* @brief calculate cumulative histogram (one color component) from the corresponding raw histogram inline void histogram_calc_cumul ( unsigned long * hist, ///< input raw histogram array of unsigned long, single color (256)
* @param hist input raw histogram array of unsigned long, single color (256) unsigned long * cumul_hist) ///< output cumulative histogram array of unsigned long, single color (256)
* @param cumul_hist output cumulative histogram array of unsigned long, single color (256) {
*/ int i;
inline void histogram_calc_cumul ( unsigned long * hist, unsigned long * cumul_hist ) { cumul_hist[0]=hist[0];
int i; for (i=1; i<256;i++) cumul_hist[i]=cumul_hist[i-1]+hist[i];
cumul_hist[0]=hist[0];
for (i=1; i<256;i++) cumul_hist[i]=cumul_hist[i-1]+hist[i];
} }
/** /**
* @brief Calculate reverse cumulative histograms (~percentiles) * Calculate reverse cumulative histograms (~percentiles)
* The reverse cumulative histogram (~percentiles) works as the following: * The reverse cumulative histogram (~percentiles) works as the following:
* for the given 1 byte input X (0 - 1/256 of all pixels, * ..., 255 - all pixels) * for the given 1 byte input X (0 - 1/256 of all pixels, * ..., 255 - all pixels)
* it returns threshold value P (0..255), so that number of pixels with value less than x is * it returns threshold value P (0..255), so that number of pixels with value less than x is
...@@ -300,44 +398,42 @@ inline void histogram_calc_cumul ( unsigned long * hist, unsigned ...@@ -300,44 +398,42 @@ inline void histogram_calc_cumul ( unsigned long * hist, unsigned
* NOTE: - argument is FPGA pixel output-to-videoRAM value (after gamma-correction), reverse gamma table * NOTE: - argument is FPGA pixel output-to-videoRAM value (after gamma-correction), reverse gamma table
* is needed to relate percentiles to amount of light (proportional to exposure) * is needed to relate percentiles to amount of light (proportional to exposure)
* *
* Current algorithm will work up to 16 MPix/color_component (64 MPix total) * Current algorithm is limited to 16 MPix/color_component (64 MPix total) */
* @param cumul_hist inline void histogram_calc_percentiles (unsigned long * cumul_hist, ///< [IN] Pointer to the start of u32[256] cumulative histogram array
* @param percentile unsigned char * percentile) ///< [OUT]Pointer to the start of u32[256] calculated percentile array
*/ {
inline void histogram_calc_percentiles ( unsigned long * cumul_hist, unsigned char * percentile) { unsigned long v256=0; // running value to be compared against cumulative histogram (it is 256 larger than cumul_hist)
unsigned long v256=0; /// running value to be compared against cumulative histogram (it is 256 larger than cumul_hist) unsigned long inc_v256=cumul_hist[255]; // step of v256 increment
unsigned long inc_v256=cumul_hist[255]; /// step of v256 increment int shiftl=8;
int shiftl=8; while (inc_v256>0xffffff) { // to protect from unlikely overflow at 16MPix - in the future)
while (inc_v256>0xffffff) { /// to protect from unlikely overflow at 16MPix - in the future) inc_v256 >>= 1;
inc_v256 >>= 1; shiftl--;
shiftl--; }
} int p=0; // current value of percentile
int p=0; /// current value of percentile int x=0; // current percentile index
int x=0; /// current percentile index while ((p<256) && (x<256)) {
while ((p<256) && (x<256)) { percentile[x]=p;
percentile[x]=p; if ((p<255) && ( (cumul_hist[p] << shiftl) <= v256)) {
if ((p<255) && ( (cumul_hist[p] << shiftl) <= v256)) { p++;
p++; } else {
} else { x++;
x++; v256+=inc_v256;
v256+=inc_v256; }
} }
}
} }
///====================================== ///======================================
/// File operations: // use G_SUBCHANNELS in userspace to re-calculate full histogram index
/// open, release - nop // File operations:
/// read - none // open, release - nop
/// write - none // read - none
/// lseek // write - none
/// mmap (should be used read only) // lseek
// mmap (should be used read only)
/**
* \def HISTOGRAMS_FILE_SIZE histograms file size (in frames, not bytes) /** HISTOGRAMS_FILE_SIZE histograms file size in frames (total nu,ber in all channels), not bytes) */
*/ #define HISTOGRAMS_FILE_SIZE (HISTOGRAM_CACHE_NUMBER*numHistChn)
#define HISTOGRAMS_FILE_SIZE HISTOGRAM_CACHE_NUMBER
static struct file_operations histograms_fops = { static struct file_operations histograms_fops = {
owner: THIS_MODULE, owner: THIS_MODULE,
llseek: histograms_lseek, llseek: histograms_lseek,
...@@ -346,55 +442,53 @@ static struct file_operations histograms_fops = { ...@@ -346,55 +442,53 @@ static struct file_operations histograms_fops = {
release: histograms_release release: histograms_release
}; };
/** /** Histograms driver OPEN method */
* @brief Histograms driver OPEN method int histograms_open(struct inode *inode, ///< inode
* @param inode inode struct file *file) ///< file pointer
* @param file file pointer ///< @return OK - 0, -EINVAL for wrong minor
* @return OK - 0, -EINVAL for wrong minor {
*/ int res;
int histograms_open(struct inode *inode, struct file *file) { struct histograms_pd * privData;
int res; privData= (struct histograms_pd *) kmalloc(sizeof(struct histograms_pd),GFP_KERNEL);
struct histograms_pd * privData; if (!privData) return -ENOMEM;
privData= (struct histograms_pd *) kmalloc(sizeof(struct histograms_pd),GFP_KERNEL); file->private_data = privData;
if (!privData) return -ENOMEM; privData-> minor=MINOR(inode->i_rdev);
file->private_data = privData; MDF21(printk("minor=0x%x\n",privData-> minor));
privData-> minor=MINOR(inode->i_rdev); switch (privData-> minor) {
MDF21(printk("minor=0x%x\n",privData-> minor)); case CMOSCAM_MINOR_HISTOGRAMS :
switch (privData-> minor) {
case CMOSCAM_MINOR_HISTOGRAMS :
inode->i_size = HISTOGRAMS_FILE_SIZE; inode->i_size = HISTOGRAMS_FILE_SIZE;
privData->frame=0xffffffff; privData->frame=0xffffffff;
privData->frame_index=-1; privData->frame_index=-1;
privData->needed= 0; privData->needed= 0;
privData->wait_mode=0; /// 0 - wait just for G1 histogram, 1 - wait for all histograms privData->wait_mode=0; // 0 - wait just for G1 histogram, 1 - wait for all histograms
privData->request_en=1; /// enable requesting histogram for the specified frame (0 - rely on the available ones) privData->request_en=1; // enable requesting histogram for the specified frame (0 - rely on the available ones)
privData->port=0;
privData->subchannel=0;
return 0; return 0;
default: default:
kfree(file->private_data); // already allocated kfree(file->private_data); // already allocated
return -EINVAL; return -EINVAL;
} }
file->f_pos = 0; file->f_pos = 0;
return res; return res;
} }
/** /** Histograms driver RELEASE method */
* @brief Histograms driver RELEASE method int histograms_release (struct inode *inode, ///< inode
* @param inode inode struct file *file) ///< file pointer
* @param file file pointer ///< @return OK - 0, -EINVAL for wrong minor
* @return OK - 0, -EINVAL for wrong minor {
*/ int res=0;
int histograms_release(struct inode *inode, struct file *file) { int p = MINOR(inode->i_rdev);
int res=0; MDF21(printk("minor=0x%x\n",p));
int p = MINOR(inode->i_rdev); switch ( p ) {
MDF21(printk("minor=0x%x\n",p));
switch ( p ) {
case CMOSCAM_MINOR_HISTOGRAMS : case CMOSCAM_MINOR_HISTOGRAMS :
break; break;
default: default:
return -EINVAL; //! do not need to free anything - "wrong number" return -EINVAL; //! do not need to free anything - "wrong number"
} }
kfree(file->private_data); kfree(file->private_data);
return res; return res;
} }
/** /**
...@@ -413,7 +507,8 @@ int histograms_release(struct inode *inode, struct file *file) { ...@@ -413,7 +507,8 @@ int histograms_release(struct inode *inode, struct file *file) {
* lseek (SEEK_END, value = 0) - return HISTOGRAMS_FILE_SIZE * lseek (SEEK_END, value = 0) - return HISTOGRAMS_FILE_SIZE
* lseek (SEEK_END, LSEEK_HIST_WAIT_Y) - set histogram waiting for the Y (actually G1) histogram (default after open) * lseek (SEEK_END, LSEEK_HIST_WAIT_Y) - set histogram waiting for the Y (actually G1) histogram (default after open)
* lseek (SEEK_END, LSEEK_HIST_WAIT_C) - set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too * lseek (SEEK_END, LSEEK_HIST_WAIT_C) - set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too
* lseek (SEEK_END, LSEEK_HIST_NEEDED) /// LSEEK_HIST_NEEDED | (0..0xffff) set histogram "needed" bits * ENXIO
* lseek (SEEK_END, LSEEK_HIST_NEEDED) // LSEEK_HIST_NEEDED | (0..0xffff) set histogram "needed" bits
* lseek (SEEK_END, LSEEK_HIST_REQ_EN) - (default)enable histogram request when reading histogram (safer, but may be not desirable in HDR mode) - default after opening * lseek (SEEK_END, LSEEK_HIST_REQ_EN) - (default)enable histogram request when reading histogram (safer, but may be not desirable in HDR mode) - default after opening
* lseek (SEEK_END, LSEEK_HIST_REQ_DIS) - disable histogram request when reading histogram - will read latest available relying it is available * lseek (SEEK_END, LSEEK_HIST_REQ_DIS) - disable histogram request when reading histogram - will read latest available relying it is available
* @param file * @param file
...@@ -421,103 +516,124 @@ int histograms_release(struct inode *inode, struct file *file) { ...@@ -421,103 +516,124 @@ int histograms_release(struct inode *inode, struct file *file) {
* @param orig SEEK_SET, SEEK_CUR or SEEK_SET END * @param orig SEEK_SET, SEEK_CUR or SEEK_SET END
* @return file position (absolute frame number) * @return file position (absolute frame number)
*/ */
/// TODO: add flag that will allow driver to wakeup processes before the specified frame comes ? // TODO: add flag that will allow driver to wakeup processes before the specified frame comes ?
loff_t histograms_lseek (struct file * file, loff_t offset, int orig) { loff_t histograms_lseek (struct file * file,
struct histograms_pd * privData = (struct histograms_pd *) file->private_data; loff_t offset,
unsigned long reqAddr,reqFrame; int orig)
{
MDF21(printk("offset=0x%x, orig=0x%x\n",(int) offset, (int) orig)); int p,s;
switch (privData->minor) { struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
case CMOSCAM_MINOR_HISTOGRAMS : unsigned long reqAddr,reqFrame;
switch(orig) {
case SEEK_CUR: /// ignore offset MDF21(printk("offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
offset+=(privData-> wait_mode)?GLOBALPARS(G_HIST_C_FRAME):GLOBALPARS(G_HIST_Y_FRAME); switch (privData->minor) {
case SEEK_SET: case CMOSCAM_MINOR_HISTOGRAMS :
privData->frame=offset; switch(orig) {
/// Try to make some precautions to avoid waiting forever - if the past frame is requested - request histogram for the current frame, case SEEK_CUR: // ignore offset
/// if the "immediate" future (fits into the array of frames) one - request that frame's histogram offset+=(privData-> wait_mode)?
/// if in the far future (unsafe) do nothing -NOTE: far future should be avoided if the histograms are set request-only GLOBALPARS(privData->port,G_HIST_C_FRAME+privData->subchannel):
/// NOTE: there could be another wrong condition - request written w/o "JUST_THIS" modifier - then it will turn to always on until cleared. GLOBALPARS(privData->port,G_HIST_Y_FRAME+privData->subchannel);
/// TODO: Save time on always enabled histograms? Don't request them additionally? //no break (CDT understands this)
if (privData->request_en) { case SEEK_SET:
reqAddr=(privData-> wait_mode)?P_HISTRQ_C:P_HISTRQ_Y; privData->frame=offset;
reqFrame=getThisFrameNumber(); // Try to make some precautions to avoid waiting forever - if the past frame is requested - request histogram for the current frame,
if (offset > reqFrame) { // if the "immediate" future (fits into the array of frames) one - request that frame's histogram
if (offset > (reqFrame+5)) reqFrame+=5; // if in the far future (unsafe) do nothing -NOTE: far future should be avoided if the histograms are set request-only
else reqFrame=offset; // NOTE: there could be another wrong condition - request written w/o "JUST_THIS" modifier - then it will turn to always on until cleared.
} // TODO: Save time on always enabled histograms? Don't request them additionally?
if ((offset < reqFrame) && /// if the requested frame is in the past - try to get it first before requesting a new if (privData->request_en) {
(((privData->frame_index = get_histograms (offset, privData->needed))) >=0)) { reqAddr=(privData-> wait_mode)?P_HISTRQ_C:P_HISTRQ_Y;
file->f_pos=privData->frame_index; reqFrame=getThisFrameNumber(privData->port);
return file->f_pos; if (offset > reqFrame) {
} if (offset > (reqFrame+5)) reqFrame+=5; // What is this 5?
/// request histogram(s) else reqFrame=offset;
setFramePar(&framepars[reqFrame & PARS_FRAMES_MASK], reqAddr, 1); }
/// make sure (harmful) interrupt did not happen since getThisFrameNumber() if ((offset < reqFrame) && // if the requested frame is in the past - try to get it first before requesting a new
if (reqFrame < getThisFrameNumber()) { (((privData->frame_index = get_histograms (offset, privData->needed))) >=0)) {
setFramePar(&framepars[getThisFrameNumber() & PARS_FRAMES_MASK], reqAddr, 1); // file->f_pos=privData->frame_index;
} file->f_pos=privData->frame_index + HISTOGRAM_CACHE_NUMBER * get_hist_index(privData->port, privData->subchannel);
} return file->f_pos;
if (privData-> wait_mode) wait_event_interruptible (hist_c_wait_queue,GLOBALPARS(G_HIST_C_FRAME)>=offset); }
else wait_event_interruptible (hist_y_wait_queue,GLOBALPARS(G_HIST_Y_FRAME)>=offset); // request histogram(s)
privData->frame_index = get_histograms (offset, privData->needed); // setFramePar(&framepars[reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
if (privData->frame_index <0) { setFramePar(&aframepars[privData->port][reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
return -EFAULT; // make sure (harmful) interrupt did not happen since getThisFrameNumber()
} else { if (reqFrame < getThisFrameNumber(privData->port)) {
file->f_pos=privData->frame_index; // setFramePar(&framepars[getThisFrameNumber() & PARS_FRAMES_MASK], reqAddr, 1);
return file->f_pos; setFramePar(&aframepars[privData->port][getThisFrameNumber(privData->port) & PARS_FRAMES_MASK], reqAddr, 1);
}
break; /// just in case }
case SEEK_END: }
if (offset < 0) { if (privData-> wait_mode) wait_event_interruptible (hist_c_wait_queue,GLOBALPARS(privData->port,G_HIST_C_FRAME + privData->subchannel)>=offset);
return -EINVAL; else wait_event_interruptible (hist_y_wait_queue,GLOBALPARS(privData->port,G_HIST_Y_FRAME + privData->subchannel)>=offset);
} else { privData->frame_index = get_histograms (offset, privData->needed);
if (offset < LSEEK_HIST_NEEDED) { if (privData->frame_index <0) {
switch (offset) { return -EFAULT;
case 0: } else {
break; // file->f_pos=privData->frame_index;
case LSEEK_HIST_REQ_EN: /// enable requesting histogram for the specified frame (0 - rely on the available ones) file->f_pos=privData->frame_index + HISTOGRAM_CACHE_NUMBER * get_hist_index(privData->port, privData->subchannel);
privData->request_en=1; ///default after open return file->f_pos;
break; }
case LSEEK_HIST_REQ_DIS: /// disable requesting histogram for the specified frame, rely on the available ones break; // just in case
privData->request_en=0; case SEEK_END:
break; if (offset < 0) {
case LSEEK_HIST_WAIT_Y: /// set histogram waiting for the Y (actually G1) histogram (default after open) return -EINVAL;
privData-> wait_mode=0; } else {
break; if (offset < LSEEK_HIST_NEEDED) {
case LSEEK_HIST_WAIT_C: /// set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too //#define LSEEK_HIST_SET_CHN 0x30 ///< ..2F Select channel to wait for (4*port+subchannel)
privData-> wait_mode=1; if ((offset & ~0xf) == LSEEK_HIST_SET_CHN){
break; p = (offset >> 2) & 3;
default: s = (offset >> 0) & 3;
switch (offset & ~0x1f) { if (get_hist_index(p,s)<0)
case LSEEK_DAEMON_HIST_Y: /// wait for daemon enabled and histograms Y ready return -ENXIO; // invalid port/channel combination
MDF21(printk("wait_event_interruptible (hist_y_wait_queue,0x%x & 0x%x)\n",(int) get_imageParamsThis(P_DAEMON_EN), (int) (1<<(offset & 0x1f)))); privData->port = p;
wait_event_interruptible (hist_y_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f))); privData->subchannel = s;
break; file->f_pos=privData->frame_index + HISTOGRAM_CACHE_NUMBER * get_hist_index(privData->port, privData->subchannel);
case LSEEK_DAEMON_HIST_C: /// wait for daemon enabled and histograms Y ready } else switch (offset) {
MDF21(printk("wait_event_interruptible (hist_c_wait_queue,0x%x & 0x%x)\n",(int) get_imageParamsThis(P_DAEMON_EN), (int) (1<<(offset & 0x1f)))); case 0:
wait_event_interruptible (hist_c_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f))); break;
break; case LSEEK_HIST_REQ_EN: // enable requesting histogram for the specified frame (0 - rely on the available ones)
default: privData->request_en=1; ///default after open
return -EINVAL; break;
} case LSEEK_HIST_REQ_DIS: // disable requesting histogram for the specified frame, rely on the available ones
} privData->request_en=0;
} else if (offset < (LSEEK_HIST_NEEDED + 0x10000)) { break;
privData->needed= (offset & 0xffff); case LSEEK_HIST_WAIT_Y: // set histogram waiting for the Y (actually G1) histogram (default after open)
} else { privData-> wait_mode=0;
return -EINVAL; break;
} case LSEEK_HIST_WAIT_C: // set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too
file->f_pos= HISTOGRAMS_FILE_SIZE; privData-> wait_mode=1;
return file->f_pos; break;
} default:
break; switch (offset & ~0x1f) {
default: /// not SEEK_SET/SEEK_CUR/SEEK_END case LSEEK_DAEMON_HIST_Y: // wait for daemon enabled and histograms Y ready
MDF21(printk("wait_event_interruptible (hist_y_wait_queue,0x%x & 0x%x)\n",(int) get_imageParamsThis(P_DAEMON_EN), (int) (1<<(offset & 0x1f))));
wait_event_interruptible (hist_y_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
break;
case LSEEK_DAEMON_HIST_C: // wait for daemon enabled and histograms Y ready
MDF21(printk("wait_event_interruptible (hist_c_wait_queue,0x%x & 0x%x)\n",(int) get_imageParamsThis(P_DAEMON_EN), (int) (1<<(offset & 0x1f))));
wait_event_interruptible (hist_c_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
break;
default:
return -EINVAL;
}
}
} else if (offset < (LSEEK_HIST_NEEDED + 0x10000)) {
privData->needed= (offset & 0xffff);
} else {
return -EINVAL;
}
file->f_pos= HISTOGRAMS_FILE_SIZE;
return file->f_pos;
}
break;
default: // not SEEK_SET/SEEK_CUR/SEEK_END
return -EINVAL;
} // switch (orig)
return file->f_pos ;
default: // other minors
return -EINVAL; return -EINVAL;
} /// switch (orig) }
return file->f_pos ;
default: /// other minors
return -EINVAL;
}
} }
/** /**
* @brief Histograms driver MMAP method to read out the histogram data (raw and calculated) * @brief Histograms driver MMAP method to read out the histogram data (raw and calculated)
...@@ -527,21 +643,21 @@ loff_t histograms_lseek (struct file * file, loff_t offset, int orig) { ...@@ -527,21 +643,21 @@ loff_t histograms_lseek (struct file * file, loff_t offset, int orig) {
*/ */
int histograms_mmap (struct file *file, struct vm_area_struct *vma) { int histograms_mmap (struct file *file, struct vm_area_struct *vma) {
int result; int result;
struct histograms_pd * privData = (struct histograms_pd *) file->private_data; struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
MDF21(printk("minor=0x%x\n",privData-> minor)); MDF21(printk("minor=0x%x\n",privData-> minor));
switch (privData->minor) { switch (privData->minor) {
case CMOSCAM_MINOR_HISTOGRAMS : case CMOSCAM_MINOR_HISTOGRAMS :
result=remap_pfn_range(vma, result=remap_pfn_range(vma,
vma->vm_start, vma->vm_start,
((unsigned long) virt_to_phys(histograms_p)) >> PAGE_SHIFT, /// Should be page-aligned ((unsigned long) virt_to_phys(histograms_p)) >> PAGE_SHIFT, // Should be page-aligned
vma->vm_end-vma->vm_start, vma->vm_end-vma->vm_start,
vma->vm_page_prot); vma->vm_page_prot);
MDF21(printk("remap_pfn_range returned=%x\r\n",result)); MDF21(printk("remap_pfn_range returned=%x\r\n",result));
if (result) return -EAGAIN; if (result) return -EAGAIN;
return 0; return 0;
default: return -EINVAL; default: return -EINVAL;
} }
} }
/** /**
...@@ -549,18 +665,19 @@ int histograms_mmap (struct file *file, struct vm_area_struct *vma) { ...@@ -549,18 +665,19 @@ int histograms_mmap (struct file *file, struct vm_area_struct *vma) {
* @return 0 * @return 0
*/ */
static int __init histograms_init(void) { static int __init histograms_init(void) {
int res; int res;
init_histograms(); // init_histograms(); // Not now??? Need to have list of channels
res = register_chrdev(HISTOGRAMS_MAJOR, "gamma_tables_operations", &histograms_fops); // Do it later, from the user space
if(res < 0) { res = register_chrdev(HISTOGRAMS_MAJOR, "gamma_tables_operations", &histograms_fops);
printk(KERN_ERR "histograms_init: couldn't get a major number %d.\n",HISTOGRAMS_MAJOR); if(res < 0) {
return res; printk(KERN_ERR "histograms_init: couldn't get a major number %d.\n",HISTOGRAMS_MAJOR);
} return res;
// init_waitqueue_head(&histograms_wait_queue); }
init_waitqueue_head(&hist_y_wait_queue); /// wait queue for the G1 histogram (used as Y) // init_waitqueue_head(&histograms_wait_queue);
init_waitqueue_head(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color) init_waitqueue_head(&hist_y_wait_queue); // wait queue for the G1 histogram (used as Y)
printk(X3X3_HISTOGRAMS_DRIVER_NAME"\r\n"); init_waitqueue_head(&hist_c_wait_queue); // wait queue for all the other (R,G2,B) histograms (color)
return 0; printk(X3X3_HISTOGRAMS_DRIVER_NAME"\r\n");
return 0;
} }
...@@ -568,25 +685,3 @@ module_init(histograms_init); ...@@ -568,25 +685,3 @@ module_init(histograms_init);
MODULE_LICENSE("GPLv3.0"); MODULE_LICENSE("GPLv3.0");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>."); MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(X3X3_HISTOGRAMS_DRIVER_NAME); MODULE_DESCRIPTION(X3X3_HISTOGRAMS_DRIVER_NAME);
...@@ -6,8 +6,11 @@ ...@@ -6,8 +6,11 @@
extern wait_queue_head_t hist_y_wait_queue; /// wait queue for the G1 histogram (used as Y) extern wait_queue_head_t hist_y_wait_queue; /// wait queue for the G1 histogram (used as Y)
extern wait_queue_head_t hist_c_wait_queue; /// wait queue for all the other (R,G2,B) histograms (color) extern wait_queue_head_t hist_c_wait_queue; /// wait queue for all the other (R,G2,B) histograms (color)
void init_histograms(void); void init_histograms(int chn_mask);
int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash, unsigned long * framep);
int get_hist_index (int sensor_port, int sensor_chn);
int set_histograms (int sensor_port, int sensor_chn, unsigned long frame, int needed, unsigned long * gammaHash, unsigned long * framep);
/** /**
* @brief Get histograms from the FPGA (called as tasklet?) and/or calculate derivatives (if needed) * @brief Get histograms from the FPGA (called as tasklet?) and/or calculate derivatives (if needed)
...@@ -15,11 +18,11 @@ int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash, ...@@ -15,11 +18,11 @@ int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash,
* TODO: should it be one frame behind current? * TODO: should it be one frame behind current?
* @param needed bits specify what histograms (color, type) are requested * @param needed bits specify what histograms (color, type) are requested
* TODO: Add P_* parameter - what to read from tasklet, turn colors it off for high FPS/small window * TODO: Add P_* parameter - what to read from tasklet, turn colors it off for high FPS/small window
* each group of 4 bits cover 4 colors of the same type: * each group of 4 bits covers 4 colors of the same type:
* - bits 0..3 - read raw histograms from the FPGA - normally called from IRQ/tasklet (use just 1 color for autoexposure to speed up?) * - bits 0..3 - read raw histograms from the FPGA - normally called from IRQ/tasklet (use just 1 color for autoexposure to speed up?)
* - bits 4..7 - calculate cumulative histograms (sum of raw ones) - normally called from applications * - bits 4..7 - calculate cumulative histograms (sum of raw ones) - normally called from applications
* - bits 8..11 - calculate percentiles (reverse cumulative histograms) - normally called from applications * - bits 8..11 - calculate percentiles (reverse cumulative histograms) - normally called from applications
* "needed" for raw histograms should be specified explicitely (can not be read from FPGA later), * "needed" for raw histograms should be specified explicitly (can not be read from FPGA later),
* "needed" for cumul_hist will be added automatically if percentiles are requested * "needed" for cumul_hist will be added automatically if percentiles are requested
* @return index of the histogram (>=0) if OK, otherwise: * @return index of the histogram (>=0) if OK, otherwise:
* - -1 not reading FPGA and frame number stored is different from the requested (too late - histogram buffer overrun?) * - -1 not reading FPGA and frame number stored is different from the requested (too late - histogram buffer overrun?)
...@@ -27,3 +30,5 @@ int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash, ...@@ -27,3 +30,5 @@ int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash,
*/ */
int get_histograms (unsigned long frame, int needed); int get_histograms (unsigned long frame, int needed);
int histograms_init_hardware(void);
void histograms_dma_ctrl(int mode); // 0 - reset, 1 - disable, 2 - enable
...@@ -74,7 +74,53 @@ ...@@ -74,7 +74,53 @@
void x313_dma_init(){} void x313_dma_init(){}
void reset_compressor(){} void reset_compressor(){}
// if ((gtable= get_gamma_fpga(color))) fpga_table_write_nice (CX313_FPGA_TABLES_GAMMA + (color * 256), 256, gtable);
// X3X3_SEQ_SEND1(frame16, X313_WA_DCR0, X353_DCR0(SENSTRIGEN,async)); // X3X3_SEQ_SEND1(frame16, X313_WA_DCR0, X353_DCR0(SENSTRIGEN,async));
#ifdef NC353
/// 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) {
unsigned long flags;
int l,i;
MDF12(printk("addr=0x%x, len=0x%x, data=0x%08lx 0x%08lx 0x%08lx 0x%08lx...\n", addr, len, data[0], data[1], data[2], data[3]));
while (len>0) {
l=(len < FPGA_TABLE_CHUNK)?len:FPGA_TABLE_CHUNK;
local_irq_save(flags);
port_csp0_addr[X313_WA_COMP_TA]=addr; // open fpga for writing table(s)
for (i=0; i<l; i++) port_csp0_addr[X313_WA_COMP_TD]=data[i]; /// will autoincrement FPGA table address
local_irq_restore(flags);
len -=l;
addr +=l;
data +=l;
}
}
///
/// reading histograms really does not need disabling IRQs - they only could interfere with other process, reading histograms
///
void fpga_hist_read_nice (int addr, int len, unsigned long * data) {
unsigned long flags;
int l,i;
MDF13(printk("addr=0x%x, len=0x%x, ",addr, len));
while (len>0) {
l=(len < FPGA_TABLE_CHUNK)?len:FPGA_TABLE_CHUNK;
local_irq_save(flags);
// #define X313_WA_HIST_ADDR 0x44
// #define X313_RA_HIST_DATA 0x45 /// use CSP4 with wait cycles to have a pulse
port_csp0_addr[X313_WA_HIST_ADDR]=addr; /// Write start address, read first word from the memory to the output buffer (will be read out during next read)
X3X3_AFTERWRITE ; //! needed before reading from FPGA after writing to it (for the writes that influence reads only)
for (i=0; i<l; i++) data[i]=port_csp4_addr[X313_RA_HIST_DATA]; /// will autoincrement FPGA table address)
local_irq_restore(flags);
len -=l;
addr +=l;
data +=l;
}
D13(printk("data=0x%08lx 0x%08lx 0x%08lx 0x%08lx...\n", data[0], data[1], data[2], data[3]));
}
#endif
...@@ -1250,7 +1250,12 @@ get_locked_hash32(0),get_locked_hash32(1),get_locked_hash32(2),get_locked_hash32 ...@@ -1250,7 +1250,12 @@ get_locked_hash32(0),get_locked_hash32(1),get_locked_hash32(2),get_locked_hash32
if (get_locked_hash32(color)!=thispars->pars[P_GTAB_R+color]) { // modified for this color if (get_locked_hash32(color)!=thispars->pars[P_GTAB_R+color]) { // modified for this color
*pgamma32=thispars->pars[P_GTAB_R+color]; *pgamma32=thispars->pars[P_GTAB_R+color];
rslt=set_gamma_table (gamma32.hash16, gamma32.scale, NULL, GAMMA_MODE_HARDWARE, color); // frame16 - one ahead of the current do not lock yet rslt=set_gamma_table (gamma32.hash16,
gamma32.scale, NULL,
GAMMA_MODE_HARDWARE,
color,
sensor_port,
0); // frame16 - one ahead of the current do not lock yet TODO 393 multisensor - split gamma tables to subchannels
if (rslt<=0) SETFRAMEPARS_SET(P_GTAB_R+color, get_locked_hash32(color)); // increases nupdate if (rslt<=0) SETFRAMEPARS_SET(P_GTAB_R+color, get_locked_hash32(color)); // increases nupdate
} }
} }
...@@ -2011,7 +2016,13 @@ int pgm_gammaload (int sensor_port, ///< sensor port number (0..3 ...@@ -2011,7 +2016,13 @@ int pgm_gammaload (int sensor_port, ///< sensor port number (0..3
for (color=0; color<4; color++) { for (color=0; color<4; color++) {
*pgamma32=thispars->pars[P_GTAB_R+color]; *pgamma32=thispars->pars[P_GTAB_R+color];
// Normally, nothing will be calculated in the next set_gamma_table() call // Normally, nothing will be calculated in the next set_gamma_table() call
rslt=set_gamma_table (gamma32.hash16, gamma32.scale, NULL, GAMMA_MODE_HARDWARE | GAMMA_MODE_LOCK, color); // frame16 - one ahead of the current rslt=set_gamma_table (gamma32.hash16,
gamma32.scale,
NULL,
GAMMA_MODE_HARDWARE | GAMMA_MODE_LOCK,
color,
sensor_port,
0); // frame16 - one ahead of the current TODO 393 multisensor - split gamma tables to subchannels
// now gtable will be old one if result <=0 get_gamma_fpga(color) can return 0 only if nothing yet was programmed // now gtable will be old one if result <=0 get_gamma_fpga(color) can return 0 only if nothing yet was programmed
if ((gtable= get_gamma_fpga(color))) fpga_table_write_nice (CX313_FPGA_TABLES_GAMMA + (color * 256), 256, gtable); if ((gtable= get_gamma_fpga(color))) fpga_table_write_nice (CX313_FPGA_TABLES_GAMMA + (color * 256), 256, gtable);
if (rslt <= 0) SETFRAMEPARS_SET(P_GTAB_R+color, get_locked_hash32(color)); // restore to the locked table if (rslt <= 0) SETFRAMEPARS_SET(P_GTAB_R+color, get_locked_hash32(color)); // restore to the locked table
......
...@@ -25,46 +25,18 @@ ...@@ -25,46 +25,18 @@
*/ */
//copied from cxi2c.c - TODO:remove unneeded //copied from cxi2c.c - TODO:remove unneeded
//#include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
//#include <linux/slab.h>
//#include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
//#include <linux/fs.h>
//#include <linux/string.h>
#include <linux/init.h> #include <linux/init.h>
//#include <linux/autoconf.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/time.h> #include <linux/time.h>
//#include <linux/vmalloc.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
//#include <linux/of.h>
//#include <linux/of_device.h>
#include <asm/outercache.h> #include <asm/outercache.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
//#include <asm/system.h>
//#include <asm/byteorder.h> // endians
//#include <asm/io.h>
//#include <asm/arch/hwregs/intr_vect_defs.h> /// ETRAX interrupt registers
//#include <asm/irq.h>
//#include <asm/delay.h>
//#include <asm/uaccess.h>
#include <elphel/driver_numbers.h> #include <elphel/driver_numbers.h>
#include <elphel/c313a.h> #include <elphel/c313a.h>
//#include <asm/elphel/fpgaconfa.h>
#include <elphel/exifa.h> #include <elphel/exifa.h>
//#include <elphel/x393_types.h>
//#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 "framepars.h"
#include "sensor_common.h" #include "sensor_common.h"
...@@ -173,6 +145,32 @@ void camseq_set_jpeg_rp(unsigned int chn, int ptr) ...@@ -173,6 +145,32 @@ void camseq_set_jpeg_rp(unsigned int chn, int ptr)
image_acq_priv.jpeg_ptr[chn].jpeg_rp = ptr; image_acq_priv.jpeg_ptr[chn].jpeg_rp = ptr;
} }
} }
/** Return current frame number, if it was from the compressor interrupt
* get the compressed frame number (updated when compression is over,
* can happen even later than start of the next frame.
* Otherwise use command sequencer (switching at frame sync (start of frame)
* TODO: at each frame interrupt check how far is compressor behind,
* take over if >=2 ? */
int getHardFrameNumber(int sensor_port, ///< Sensor port number
int use_compressor) ///< 1 - use compressor frame number, 0 - use sequencer frame number
///< @return hardware frame number (4 bit currently, mod PARS_FRAMES )
{
x393_cmprs_status_t cmprs_status;
x393_cmdseqmux_status_t cmdseqmux_status;
if (use_compressor) {
cmprs_status = x393_cmprs_status(sensor_port);
return cmprs_status.frame;
} else {
cmdseqmux_status = x393_cmdseqmux_status();
switch(sensor_port){
case 0: return cmdseqmux_status.frame_num0;
case 1: return cmdseqmux_status.frame_num1;
case 2: return cmdseqmux_status.frame_num2;
default: return cmdseqmux_status.frame_num3;
}
}
}
/*! /*!
End of compressor-related code - TODO: move to a separate file? End of compressor-related code - TODO: move to a separate file?
...@@ -182,7 +180,7 @@ static const struct of_device_id elphel393_sensor_of_match[]; ...@@ -182,7 +180,7 @@ static const struct of_device_id elphel393_sensor_of_match[];
static struct sensorproc_t as_sensorproc[SENSOR_PORTS]; // sensor parameters and functions to call static struct sensorproc_t as_sensorproc[SENSOR_PORTS]; // sensor parameters and functions to call
struct sensorproc_t * asensorproc = NULL; struct sensorproc_t * asensorproc = NULL;
//EXPORT_SYMBOL_GPL(sensorproc); //EXPORT_SYMBOL_GPL(sensorproc);
//wait_queue_head_t image_acq_wait_queue; /// queue for the sensor frame interrupts //wait_queue_head_t image_acq_wait_queue; // queue for the sensor frame interrupts
void tasklet_fpga_function(unsigned long arg); void tasklet_fpga_function(unsigned long arg);
...@@ -205,23 +203,23 @@ struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * co ...@@ -205,23 +203,23 @@ struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * co
/// ///
/// initializes structures for the image acquisition parameter // initializes structures for the image acquisition parameter
/// initializes hardware i2c controller and the command sequencer (leaves them stopped to ignore any frame syncs) // initializes hardware i2c controller and the command sequencer (leaves them stopped to ignore any frame syncs)
/// sets some default acquisition parameters // sets some default acquisition parameters
/// Maybe - set up DMA also? // 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 // 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) // (easier to do in FPGA)
/// Done: // Done:
///#define CCAM_VSYNC_ON port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,0) ///#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) ///#define CCAM_VSYNC_OFF port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,1)
/// ///
int init_acq_sensor(void); // Never used? int init_acq_sensor(void); // Never used?
//DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); /// 0 - no arguments for now //DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_0, tasklet_fpga_function, 0); /// 0 - no arguments for now DECLARE_TASKLET(tasklet_fpga_0, tasklet_fpga_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_1, tasklet_fpga_function, 1); /// 0 - no arguments for now DECLARE_TASKLET(tasklet_fpga_1, tasklet_fpga_function, 1); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_2, tasklet_fpga_function, 2); /// 0 - no arguments for now DECLARE_TASKLET(tasklet_fpga_2, tasklet_fpga_function, 2); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_3, tasklet_fpga_function, 3); /// 0 - no arguments for now DECLARE_TASKLET(tasklet_fpga_3, tasklet_fpga_function, 3); // 0 - no arguments for now
static struct tasklet_struct *tasklets[SENSOR_PORTS] = {&tasklet_fpga_0, &tasklet_fpga_1, &tasklet_fpga_2, &tasklet_fpga_3}; static struct tasklet_struct *tasklets[SENSOR_PORTS] = {&tasklet_fpga_0, &tasklet_fpga_1, &tasklet_fpga_2, &tasklet_fpga_3};
...@@ -239,12 +237,12 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr) ...@@ -239,12 +237,12 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
phys_addr_t phys_addr; phys_addr_t phys_addr;
void *virt_addr; void *virt_addr;
// int prev_dword; // int prev_dword;
int xferred; /// number of 32-byte chunks transferred since compressor was reset int xferred; // number of 32-byte chunks transferred since compressor was reset
x393_afimux_status_t stat = x393_afimux0_status(jptr->chn_num); x393_afimux_status_t stat = x393_afimux0_status(jptr->chn_num);
xferred = stat.offset256 - (jptr->fpga_cntr_prev >> 3); xferred = stat.offset256 - (jptr->fpga_cntr_prev >> 3);
if (xferred == 0) if (xferred == 0)
return 0; /// no advance (compressor was off?) return 0; // no advance (compressor was off?)
jptr->flags |= SENS_FLAG_IRQ; jptr->flags |= SENS_FLAG_IRQ;
jptr->fpga_cntr_prev = jptr->jpeg_wp; jptr->fpga_cntr_prev = jptr->jpeg_wp;
...@@ -414,10 +412,10 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, struct interframe_params_t* ...@@ -414,10 +412,10 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, struct interframe_params_t*
unsigned int sensor_port = jptr->chn_num; unsigned int sensor_port = jptr->chn_num;
int index_time = jptr->jpeg_wp - 11; if (index_time<0) index_time+=get_globalParam (sensor_port, G_CIRCBUFSIZE)>>2; int index_time = jptr->jpeg_wp - 11; if (index_time<0) index_time+=get_globalParam (sensor_port, G_CIRCBUFSIZE)>>2;
// struct exif_datetime_t // struct exif_datetime_t
/// calculates datetime([20] and subsec[7], returns pointer to char[27] // calculates datetime([20] and subsec[7], returns pointer to char[27]
char time_buff[27]; char time_buff[27];
char * exif_meta_time_string=encode_time(time_buff, ccam_dma_buf_ptr[sensor_port][index_time], ccam_dma_buf_ptr[sensor_port][index_time+1]); char * exif_meta_time_string=encode_time(time_buff, ccam_dma_buf_ptr[sensor_port][index_time], ccam_dma_buf_ptr[sensor_port][index_time+1]);
/// may be split in datetime/subsec - now it will not notice missing subseq field in template // may be split in datetime/subsec - now it will not notice missing subseq field in template
write_meta_irq(sensor_port, exif_meta_time_string, &meta_offsets.Photo_DateTimeOriginal, Exif_Photo_DateTimeOriginal, 27); write_meta_irq(sensor_port, exif_meta_time_string, &meta_offsets.Photo_DateTimeOriginal, Exif_Photo_DateTimeOriginal, 27);
write_meta_irq(sensor_port, exif_meta_time_string, &meta_offsets.Image_DateTime, Exif_Image_DateTime, 20); // may use 27 if room is provided write_meta_irq(sensor_port, exif_meta_time_string, &meta_offsets.Image_DateTime, Exif_Image_DateTime, 20); // may use 27 if room is provided
putlong_meta_irq(sensor_port, get_imageParamsThis(sensor_port, P_EXPOS), &meta_offsets.Photo_ExposureTime, Exif_Photo_ExposureTime); putlong_meta_irq(sensor_port, get_imageParamsThis(sensor_port, P_EXPOS), &meta_offsets.Photo_ExposureTime, Exif_Photo_ExposureTime);
...@@ -490,24 +488,24 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, struct interframe_params_t* ...@@ -490,24 +488,24 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, struct interframe_params_t*
irq_state = X313_IRQSTATE; //!making dummy read - see c353.h irq_state = X313_IRQSTATE; //!making dummy read - see c353.h
DIS_INTERRUPTS; DIS_INTERRUPTS;
PROFILE_NEXT(0); PROFILE_NEXT(0);
/// read hardware write pointer (will only advance if compression was on) // read hardware write pointer (will only advance if compression was on)
///find out if compressor was running and update pointers, exif, ...? ///find out if compressor was running and update pointers, exif, ...?
if (updateIRQJPEG_wp()) { ///also fills P_FRAME ahead if (updateIRQJPEG_wp()) { ///also fills P_FRAME ahead
updateIRQCircbuf(); updateIRQCircbuf();
updateIRQFocus(); ///NOTE: currently global (latest), not per-frame updateIRQFocus(); ///NOTE: currently global (latest), not per-frame
struct interframe_params_t* interframe= updateIRQ_interframe(); /// fills jpeg_len, signffff struct interframe_params_t* interframe= updateIRQ_interframe(); // fills jpeg_len, signffff
/// should we use memcpy as before here? // should we use memcpy as before here?
// interframe->frame_length=jpeg_len; // interframe->frame_length=jpeg_len;
// interframe->signffff=0xffff; // interframe->signffff=0xffff;
updateIRQ_Exif(interframe); updateIRQ_Exif(interframe);
updateFramePars(X3X3_I2C_FRAME, interframe); updateFramePars(X3X3_I2C_FRAME, interframe);
wake_up_interruptible(&circbuf_wait_queue); /// only when frame is acquired wake_up_interruptible(&circbuf_wait_queue); // only when frame is acquired
} else { } else {
updateFramePars(X3X3_I2C_FRAME, NULL); updateFramePars(X3X3_I2C_FRAME, NULL);
} }
PROFILE_NOW(1); PROFILE_NOW(1);
wake_up_interruptible(&framepars_wait_queue); /// all interrupts, not just frames acquired wake_up_interruptible(&framepars_wait_queue); // all interrupts, not just frames acquired
tasklet_schedule(&tasklet_fpga); /// trigger software interrupt tasklet_schedule(&tasklet_fpga); // trigger software interrupt
EN_INTERRUPT(SMART); EN_INTERRUPT(SMART);
...@@ -590,21 +588,23 @@ For displaying histograms - try use latest available - not waiting fro a particu ...@@ -590,21 +588,23 @@ For displaying histograms - try use latest available - not waiting fro a particu
*/ */
/// HISTOGRAMS_WAKEUP_ALWAYS if 0 will only wakeup processes waiting for histograms when they become available, maybe never if they are disabled // 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 // if defined 1 - will wakeup each frame, regardless of the availability of the histograms
//#define HISTOGRAMS_WAKEUP_ALWAYS 0 //#define HISTOGRAMS_WAKEUP_ALWAYS 0
void tasklet_fpga_function(unsigned long arg) { void tasklet_fpga_function(unsigned long arg) {
int is_compressor_irq = 1; // TODO: add interrupts from frame sync if compressor is off
int hist_en; int hist_en;
int sensor_port = image_acq_priv.jpeg_ptr[arg].chn_num; int sensor_port = image_acq_priv.jpeg_ptr[arg].chn_num;
int tasklet_disable=get_globalParam(sensor_port, G_TASKLET_CTL); int tasklet_disable=get_globalParam(sensor_port, G_TASKLET_CTL);
unsigned long thisFrameNumber=getThisFrameNumber(sensor_port); unsigned long thisFrameNumber=getThisFrameNumber(sensor_port);
unsigned long prevFrameNumber=thisFrameNumber-1; unsigned long prevFrameNumber=thisFrameNumber-1;
unsigned long * hash32p=&(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]); unsigned long * hash32p=&(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]); // same gamma for all sub-channels
unsigned long * framep= &(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]); unsigned long * framep= &(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg]; const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
dma_addr_t phys_addr_start, phys_addr_end; dma_addr_t phys_addr_start, phys_addr_end;
void *virt_addr_start; void *virt_addr_start;
unsigned int sz; unsigned int sz;
int subchn,hist_indx;
/* invalidate L2 cache lines in the beginning of current frame */ /* invalidate L2 cache lines in the beginning of current frame */
phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->fpga_cntr_prev); phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->fpga_cntr_prev);
...@@ -626,78 +626,85 @@ void tasklet_fpga_function(unsigned long arg) { ...@@ -626,78 +626,85 @@ void tasklet_fpga_function(unsigned long arg) {
__cpuc_flush_dcache_area(virt_addr_start, sz - CCAM_DMA_SIZE); __cpuc_flush_dcache_area(virt_addr_start, sz - CCAM_DMA_SIZE);
} }
// Time is out?
#ifdef TEST_DISABLE_CODE if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port,is_compressor_irq)) & PARS_FRAMES_MASK) return; // already next frame
/// Time is out? // Histograms are available for the previous frame (that is already in circbuf if compressor was running)
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame // Is Y histogram needed?
#endif /* TEST_DISABLE_CODE */
/// Histograms are available for the previous frame (that is already in circbuf if compressor was running)
/// Is Y histogram needed?
PROFILE_NOW(2); PROFILE_NOW(2);
switch ((tasklet_disable >> TASKLET_CTL_HISTY_BIT) & 7) { switch ((tasklet_disable >> TASKLET_CTL_HISTY_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate case TASKLET_HIST_NEVER: // never calculate
hist_en=0; hist_en=0;
break; break;
case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8) case TASKLET_HIST_HALF: // calculate each even (0,2,4,6 frme of 8)
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y)); hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break; break;
case TASKLET_HIST_QUATER: /// calculate twice per 8 (0, 4) case TASKLET_HIST_QUATER: // calculate twice per 8 (0, 4)
hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y)); hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break; break;
case TASKLET_HIST_ONCE: /// calculate once per 8 (0) case TASKLET_HIST_ONCE: // calculate once per 8 (0)
hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y)); hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break; break;
case TASKLET_HIST_RQONLY: /// calculate only when specifically requested case TASKLET_HIST_RQONLY: // calculate only when specifically requested
hist_en= (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y)); hist_en= (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break; break;
case TASKLET_HIST_ALL: /// calculate each frame case TASKLET_HIST_ALL: // calculate each frame
default: /// calculate always (safer) default: // calculate always (safer)
hist_en=1; hist_en=1;
} }
#ifdef TEST_DISABLE_CODE //#ifdef TEST_DISABLE_CODE
if (hist_en) { if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1] // after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, (1 << COLOR_Y_NUMBER), hash32p, framep); /// 0x2 Green1 for (subchn=0;subchn<MAX_SENSORS;subchn++) if (((hist_indx=get_hist_index(sensor_port,subchn)))>=0){
GLOBALPARS(G_HIST_Y_FRAME)=prevFrameNumber; /// histogram corresponds to previous frame if (PER_CHANNEL393) {
set_histograms (sensor_port,
subchn,
prevFrameNumber,
(1 << COLOR_Y_NUMBER),
hash32p+hist_indx*16*(sizeof u32),
framep+hist_indx*32*(sizeof u32)); // 0x2 Green1
} else {
set_histograms (sensor_port, subchn, prevFrameNumber, (1 << COLOR_Y_NUMBER), hash32p, framep); // 0x2 Green1
}
GLOBALPARS(sensor_port, G_HIST_Y_FRAME + subchn) = prevFrameNumber; // histogram corresponds to previous frame
}
PROFILE_NOW(3); PROFILE_NOW(3);
/// Time is out? // Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame // Old 353 if ((getThisFrameNumber(sensor_port) ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; // already next frame
if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port,is_compressor_irq)) & PARS_FRAMES_MASK) return; // already next frame
#if HISTOGRAMS_WAKEUP_ALWAYS #if HISTOGRAMS_WAKEUP_ALWAYS
} }
wake_up_interruptible(&hist_y_wait_queue); /// wait queue for the G1 histogram (used as Y) wake_up_interruptible(&hist_y_wait_queue); // wait queue for the G1 histogram (used as Y)
#else #else
wake_up_interruptible(&hist_y_wait_queue); /// wait queue for the G1 histogram (used as Y) wake_up_interruptible(&hist_y_wait_queue); // wait queue for the G1 histogram (used as Y)
} }
#endif #endif
#endif /* TEST_DISABLE_CODE */ //#endif /* TEST_DISABLE_CODE */
/// Process parameters // Process parameters
if ((tasklet_disable & (1 << TASKLET_CTL_PGM)) == 0) { if ((tasklet_disable & (1 << TASKLET_CTL_PGM)) == 0) {
processPars (sensor_port, sensorproc, getThisFrameNumber(sensor_port), get_globalParam(sensor_port, G_MAXAHEAD)); /// program parameters processPars (sensor_port, sensorproc, getThisFrameNumber(sensor_port), get_globalParam(sensor_port, G_MAXAHEAD)); // program parameters
PROFILE_NOW(4); PROFILE_NOW(4);
} }
#ifdef TEST_DISABLE_CODE // Time is out?
/// Time is out? if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port,is_compressor_irq)) & PARS_FRAMES_MASK) return; // already next frame
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame // Are C histograms needed?
/// Are C histograms needed?
#endif /* TEST_DISABLE_CODE */
switch ((tasklet_disable >> TASKLET_CTL_HISTC_BIT) & 7) { switch ((tasklet_disable >> TASKLET_CTL_HISTC_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate case TASKLET_HIST_NEVER: // never calculate
hist_en=0; hist_en=0;
break; break;
case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8) case TASKLET_HIST_HALF: // calculate each even (0,2,4,6 frme of 8)
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C)); hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break; break;
case TASKLET_HIST_QUATER: /// calculate twice per 8 (0, 4) case TASKLET_HIST_QUATER: // calculate twice per 8 (0, 4)
hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C)); hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break; break;
case TASKLET_HIST_ONCE: /// calculate once per 8 (0) case TASKLET_HIST_ONCE: // calculate once per 8 (0)
hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C)); hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break; break;
case TASKLET_HIST_RQONLY: /// calculate only when specifically requested case TASKLET_HIST_RQONLY: // calculate only when specifically requested
hist_en= (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C)); hist_en= (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break; break;
case TASKLET_HIST_ALL: /// calculate each frame case TASKLET_HIST_ALL: // calculate each frame
default: /// calculate always (safer) default: // calculate always (safer)
hist_en=1; hist_en=1;
} }
/* /*
...@@ -707,22 +714,35 @@ GLOBALPARS(0x1042)=((thisFrameNumber & 7) ==0); ...@@ -707,22 +714,35 @@ GLOBALPARS(0x1042)=((thisFrameNumber & 7) ==0);
GLOBALPARS(0x1043)=hist_en; GLOBALPARS(0x1043)=hist_en;
GLOBALPARS(0x1044)=thisFrameNumber; GLOBALPARS(0x1044)=thisFrameNumber;
*/ */
#ifdef TEST_DISABLE_CODE
if (hist_en) { if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1] // after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, 0xf, hash32p, framep); /// all 4 colors, including Y (it will be skipped) // after updateFramePars gammaHash are from framepars[this-1]
GLOBALPARS(G_HIST_C_FRAME)=prevFrameNumber; /// histogram corresponds to previous frame for (subchn=0;subchn<MAX_SENSORS;subchn++) if (((hist_indx=get_hist_index(sensor_port,subchn)))>=0){
if (PER_CHANNEL393) {
set_histograms (sensor_port,
subchn,
prevFrameNumber,
0xf, // all colors
hash32p+hist_indx*16*(sizeof u32),
framep+hist_indx*32*(sizeof u32)); // 0x2 Green1
} else {
set_histograms (sensor_port, subchn, prevFrameNumber, 0xf, hash32p, framep); // 0x2 Green1
}
GLOBALPARS(sensor_port, G_HIST_C_FRAME + subchn) = prevFrameNumber; // histogram corresponds to previous frame
}
PROFILE_NOW(5); PROFILE_NOW(5);
/// Time is out? // Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port,is_compressor_irq)) & PARS_FRAMES_MASK) return; // already next frame
#if HISTOGRAMS_WAKEUP_ALWAYS #if HISTOGRAMS_WAKEUP_ALWAYS
} }
wake_up_interruptible(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color) wake_up_interruptible(&hist_c_wait_queue); // wait queue for all the other (R,G2,B) histograms (color)
#else #else
wake_up_interruptible(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color) wake_up_interruptible(&hist_c_wait_queue); // wait queue for all the other (R,G2,B) histograms (color)
} }
#endif #endif
#endif /* TEST_DISABLE_CODE */
} }
//#endif /* TEST_DISABLE_CODE */ //#endif /* TEST_DISABLE_CODE */
...@@ -736,10 +756,10 @@ void reset_compressor(unsigned int chn) ...@@ -736,10 +756,10 @@ void reset_compressor(unsigned int chn)
local_irq_save(flags); local_irq_save(flags);
#ifdef TEST_DISABLE_CODE #ifdef TEST_DISABLE_CODE
port_csp0_addr[X313_WA_COMP_CMD]= COMPCMD_RESET; /// bypasses command sequencer port_csp0_addr[X313_WA_COMP_CMD]= COMPCMD_RESET; // bypasses command sequencer
if (framepars) set_imageParamsR_all( P_COMPRESSOR_RUN, COMPRESSOR_RUN_STOP ); if (framepars) set_imageParamsR_all( P_COMPRESSOR_RUN, COMPRESSOR_RUN_STOP );
else printk ("framepars is not initialized\n"); else printk ("framepars is not initialized\n");
/// TODO: There still is a possibility, that there are compressor commands in the hardware que. Should we stop the hardware sequencer here (and restart it later)? // TODO: There still is a possibility, that there are compressor commands in the hardware que. Should we stop the hardware sequencer here (and restart it later)?
#endif /* TEST_DISABLE_CODE */ #endif /* TEST_DISABLE_CODE */
image_acq_priv.jpeg_ptr[chn].jpeg_wp = 0; image_acq_priv.jpeg_ptr[chn].jpeg_wp = 0;
image_acq_priv.jpeg_ptr[chn].jpeg_rp = 0; image_acq_priv.jpeg_ptr[chn].jpeg_rp = 0;
...@@ -765,7 +785,7 @@ void camera_interrupts (int on) { ...@@ -765,7 +785,7 @@ void camera_interrupts (int on) {
} else { } else {
DIS_INTERRUPTS; DIS_INTERRUPTS;
} }
/// clear smart interrupt circuitry in any case // clear smart interrupt circuitry in any case
port_csp0_addr[X313_WA_SMART_IRQ]=0x8000; port_csp0_addr[X313_WA_SMART_IRQ]=0x8000;
reg_intr_vect_rw_mask intr_mask; reg_intr_vect_rw_mask intr_mask;
...@@ -856,11 +876,11 @@ int image_acq_init(struct platform_device *pdev) ...@@ -856,11 +876,11 @@ int image_acq_init(struct platform_device *pdev)
for (i = 0; i < SENSOR_PORTS; i++) { for (i = 0; i < SENSOR_PORTS; i++) {
reset_compressor(i); reset_compressor(i);
} }
//reset_compressor(); /// reset compressor and buffer pointers //reset_compressor(); // reset compressor and buffer pointers
//MDD1(printk("x313_dma_init()\n")); //MDD1(printk("x313_dma_init()\n"));
//x313_dma_init(); /// initialize ETRAX FS DMA //x313_dma_init(); // initialize ETRAX FS DMA
//MDD1(printk("init_pgm_proc ()\n")); //MDD1(printk("init_pgm_proc ()\n"));
//init_pgm_proc (); /// setup pointers to functions (not sensor-specific) //init_pgm_proc (); // setup pointers to functions (not sensor-specific)
//MDD1(printk("reset_qtables()\n")); //MDD1(printk("reset_qtables()\n"));
framepars_init(pdev); framepars_init(pdev);
......
...@@ -240,6 +240,7 @@ ...@@ -240,6 +240,7 @@
#define SENSORWIDTH_IBIS51300 1280 ///< FillFactory IBIS51300 width #define SENSORWIDTH_IBIS51300 1280 ///< FillFactory IBIS51300 width
#define SENSORHEIGHT_IBIS51300 1024 ///< FillFactory IBIS51300 height #define SENSORHEIGHT_IBIS51300 1024 ///< FillFactory IBIS51300 height
//TODO: Update CONST_NAME_ENTRY_* to new P_vars
/// Parameters related to multi-sensor (10359A) setup /// 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) //#define MAX_SENSORS 3 // maximal number of sensor attached (modify some hard-wired constants below if this to be changed)
/* Modified for 393 - using up to 4 sub-sensors (even as 10359 only supports 3 */ /* Modified for 393 - using up to 4 sub-sensors (even as 10359 only supports 3 */
...@@ -427,6 +428,8 @@ ...@@ -427,6 +428,8 @@
// The following 4 parameters should have consecutive indexes // The following 4 parameters should have consecutive indexes
// see FRAMEPAIR_MASK_BYTES to modify just part of the word (i.e. scale, not hash16 // see FRAMEPAIR_MASK_BYTES to modify just part of the word (i.e. scale, not hash16
// //
// Will need to have them per-subchannel (4x)
#define PER_CHANNEL393 0 ///< set to 1 when ready with per-channel for 393, meanwhile will overwrite each other in histograms.c
#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. #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 ///< 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_G 129 ///< same for the first green (red line)
...@@ -453,6 +456,8 @@ ...@@ -453,6 +456,8 @@
#define COLORMODE_MONO4 14 ///< monochrome, 4 blocks (but still with 2x2 macroblocks) #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 // the following 8 values should go in the same sequence as fields in the histogram page
// 393: per sub-channel // 393: per sub-channel
//// Will need to have them per-subchannel (4x)
#define P_FRAME 136 ///< Frame number (reset with JPEG pointers) -(read only) #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_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_GAING 138 ///< G channel gain ("red line")
...@@ -706,9 +711,10 @@ ...@@ -706,9 +711,10 @@
#define TASKLET_CTL_HISTY_BIT 4 ///< shift of histogram calculation for Y in G_TASKLET_CTL (bits 4,5,6) #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 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_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_Y_FRAME (FRAMEPAR_GLOBALS + 57) // /< last frame for which Y histogram was calculated
#define G_HIST_C_FRAME (FRAMEPAR_GLOBALS + 58) ///< last frame for which C histograms were calcualted //#define G_HIST_C_FRAME (FRAMEPAR_GLOBALS + 58) // /< last frame for which C histograms were calculated
#define G_SUBCHANNELS (FRAMEPAR_GLOBALS + 56) ///< subchannels used on this sensor port (bitmask)
#define G_SKIP_DIFF_FRAME (FRAMEPAR_GLOBALS + 59) ///< number of frames with different size to tolerate before producing POLLHUP in poll(circbuf) #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_FTP_NEXT_TIME (FRAMEPAR_GLOBALS + 60) ///< time of the next FTP upload (seconds from epoch)
...@@ -719,6 +725,12 @@ ...@@ -719,6 +725,12 @@
#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_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_TEMPERATURE23 (FRAMEPAR_GLOBALS + 97) ///< temperature on the sensors 2 and 3
// Moving here as there can be multiple histograms per port
#define G_HIST_LAST_INDEX (FRAMEPAR_GLOBALS + 98) ///< last used index in histogram cache (uses 4 locations), set to !=0 to activate, 0 will skip
#define G_HIST_Y_FRAME (FRAMEPAR_GLOBALS + 102) ///< last frame for which Y histogram was calculated (uses 4 locations)
#define G_HIST_C_FRAME (FRAMEPAR_GLOBALS + 106) ///< last frame for which C histograms were calculated (uses 4 locations)
#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 #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 ///< Only first 96 for each color are used
...@@ -1266,6 +1278,7 @@ struct p_names_t { ...@@ -1266,6 +1278,7 @@ struct p_names_t {
G_NAME_ENTRY(HIST_LAST_INDEX), \ G_NAME_ENTRY(HIST_LAST_INDEX), \
G_NAME_ENTRY(HIST_Y_FRAME), \ G_NAME_ENTRY(HIST_Y_FRAME), \
G_NAME_ENTRY(HIST_C_FRAME), \ G_NAME_ENTRY(HIST_C_FRAME), \
G_NAME_ENTRY(SUBCHANNELS), \
G_NAME_ENTRY(SKIP_DIFF_FRAME), \ G_NAME_ENTRY(SKIP_DIFF_FRAME), \
G_NAME_ENTRY(FTP_NEXT_TIME), \ G_NAME_ENTRY(FTP_NEXT_TIME), \
G_NAME_ENTRY(DAEMON_ERR), \ G_NAME_ENTRY(DAEMON_ERR), \
...@@ -1340,29 +1353,29 @@ struct p_names_t { ...@@ -1340,29 +1353,29 @@ struct p_names_t {
//#define IO_CCAM_START_RAW 0x0a // Programs DMA descriptor list according to current frame size, FPGA registers and starts DMA //#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 /// MOST ARE OBSOLETE - WILL REMOVE WHEN UPDATING STREAMERS
#define IO_CCAM_JPEG 0x08 /// JPEG-compressor related commands #define IO_CCAM_JPEG 0x08 ///< JPEG-compressor related commands
#define JPEG_CMD_RESET 0x00 /// Resets pointers - both acquisition and readout #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_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_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_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_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_ACQUIRE 0x05 ///< acquire and compress one frame
#define JPEG_CMD_SAVE_RP 0x06 /// save read pointer #define JPEG_CMD_SAVE_RP 0x06 ///< save read pointer
#define JPEG_CMD_RESTORE_RP 0x07 /// restore 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_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_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_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_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_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_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_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 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_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) //#define PROGRAM_SENSOR_1 0x12 ///< programSensor(1) - to be used from lseek (SEEK_END)
/// Compressor state now applies only to particular frame /// Compressor state now applies only to particular frame
//#define LSEEK_CAMSEQSTATE 0x13 /// return camSeqState - to be used from lseek (SEEK_END) //#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_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 #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
...@@ -1392,47 +1405,48 @@ struct p_names_t { ...@@ -1392,47 +1405,48 @@ struct p_names_t {
#define LSEEK_HUFFMAN_FPGACALC 7 #define LSEEK_HUFFMAN_FPGACALC 7
#define LSEEK_HUFFMAN_FPGAPGM 8 #define LSEEK_HUFFMAN_FPGAPGM 8
//#define LSEEK_RESET_SENSOR 0x14 /// reset sensor and FPGA - next time will reprogram it //#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_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_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_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_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_SET 0x19 ///< set autoexposure parameters
#define LSEEK_AUTOEXP_GET 0x1a /// copy window and exposure parameters to autoexp_state #define LSEEK_AUTOEXP_GET 0x1a ///< copy window and exposure parameters to autoexp_state
#define LSEEK_TRIGGER_PGM 0x1b /// program trigger parameters #define LSEEK_TRIGGER_PGM 0x1b ///< program trigger parameters
#define LSEEK_I2C_PGM 0x1c /// program hardware i2c speed/bytes #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_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_EXTERN_TIMESTAMP_PGM 0x1e ///< 1 - use external timestamps if available
#define LSEEK_DMA_INIT 0x1f /// (re-) initialize ETRAX DMA for compressor #define LSEEK_DMA_INIT 0x1f ///< (re-) initialize ETRAX DMA for compressor
#define LSEEK_DMA_STOP 0x20 /// STOP ETRAX DMA #define LSEEK_DMA_STOP 0x20 ///< STOP ETRAX DMA
#define LSEEK_DMA_START 0x21 /// STARTETRAX DMA #define LSEEK_DMA_START 0x21 ///< STARTETRAX DMA
#define LSEEK_COMPRESSOR_RESET 0x22 /// reset compressor and pointers #define LSEEK_COMPRESSOR_RESET 0x22 ///< reset compressor and pointers
#define LSEEK_INTERRUPT_OFF 0x23 /// disable camera interrupts #define LSEEK_INTERRUPT_OFF 0x23 ///< disable camera interrupts
#define LSEEK_INTERRUPT_ON 0x24 /// enable camera interrupts #define LSEEK_INTERRUPT_ON 0x24 ///< enable camera interrupts
#define LSEEK_FRAMEPARS_INIT 0x25 /// reset hardware sequencers, init framepars structure #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_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 #define LSEEK_FRAME_RESET 0x27 ///< reset absolute frame number to avoid integer overflow
///Histograms related commands //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_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_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_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_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_SET_CHN 0x30 ///< ..2F Select channel to wait for (4*port+subchannel)
//#define LSEEK_HIST_WAIT_AE 0x2a /// wait for autoexposure enabled #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_FRAME 0x80 ///< LSEEK_DAEMON_FRAME+B wait for frame 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_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_C 0xe0 /// LSEEK_DAEMON_FRAME+B wait for all histograms ready 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<N<256)
#define LSEEK_FRAME_WAIT_ABS 0x200 /// LSEEK_WAIT_FRAME_ABS+N - wait absolute frame N #define LSEEK_FRAME_WAIT_REL 0x100 ///< LSEEK_WAIT_FRAME_REL+N - skip N frames (0<N<256)
#define LSEEK_FRAME_WAIT_ABS 0x200 ///< LSEEK_WAIT_FRAME_ABS+N - wait absolute frame N
#define LSEEK_FSDRAM_RESET 0x01 // re-program FSDRAM (to be programmed again when accessed) #define LSEEK_FSDRAM_RESET 0x01 // re-program FSDRAM (to be programmed again when accessed)
...@@ -1569,49 +1583,49 @@ struct p_names_t { ...@@ -1569,49 +1583,49 @@ struct p_names_t {
// make this structure common for sensors, add fields as needed // make this structure common for sensors, add fields as needed
struct sensor_t { struct sensor_t {
// sensor constants // sensor constants
unsigned long imageWidth; /// nominal image width for final images unsigned long imageWidth; ///< nominal image width for final images
unsigned long imageHeight; /// nominal image height for final images unsigned long imageHeight; ///< nominal image height for final images
unsigned long clearWidth; /// maximal clear (useful) image width unsigned long clearWidth; ///< maximal clear (useful) image width
unsigned long clearHeight; /// maximal clear (useful) image height; unsigned long clearHeight; ///< maximal clear (useful) image height;
unsigned long clearTop; /// top margin to the first clear pixel unsigned long clearTop; ///< top margin to the first clear pixel
unsigned long clearLeft; /// left margin to the first clear pixel unsigned long clearLeft; ///< left margin to the first clear pixel
unsigned long arrayWidth; /// total image array width (including black and boundary) unsigned long arrayWidth; ///< total image array width (including black and boundary)
unsigned long arrayHeight; /// total image array height (including black and boundary) unsigned long arrayHeight; ///< total image array height (including black and boundary)
unsigned long minWidth; /// minimal WOI width unsigned long minWidth; ///< minimal WOI width
unsigned long minHeight; /// minimal WOI height unsigned long minHeight; ///< minimal WOI height
unsigned long minHorBlank; /// minimal horizontal blanking, in pixels in no-decimation, no-binning mode. unsigned long minHorBlank; ///< minimal horizontal blanking, in pixels in no-decimation, no-binning mode.
unsigned long minLineDur; /// minimal total line duration, in pixels in no-decimation, no-binning mode. unsigned long minLineDur; ///< minimal total line duration, in pixels in no-decimation, no-binning mode.
unsigned long maxHorBlank; /// maximal horizontal blanking/Virtual frame width (depends on sensor type) unsigned long maxHorBlank; ///< maximal horizontal blanking/Virtual frame width (depends on sensor type)
unsigned long minVertBlank; /// minimal vertical blanking unsigned long minVertBlank; ///< minimal vertical blanking
unsigned long maxVertBlank; /// maximal vertical blanking/Virtual frame height (depends on sensor type) unsigned long maxVertBlank; ///< maximal vertical blanking/Virtual frame height (depends on sensor type)
unsigned long maxShutter; /// Maximal shutter duration (in lines) unsigned long maxShutter; ///< Maximal shutter duration (in lines)
unsigned long flips; /// capabilities: bit mask bit 0 - flipX, 1 - flipY unsigned long flips; ///< capabilities: bit mask bit 0 - flipX, 1 - flipY
unsigned long init_flips; /// normal orientation flips bit mask bit 0 - flipX, 1 - flipY. will be XOR-ed with [P_FLIP] to get sensor flip unsigned long init_flips; ///< normal orientation flips bit mask bit 0 - flipX, 1 - flipY. will be XOR-ed with [P_FLIP] to get sensor flip
unsigned long bayer; /// bayer shift for flips==0 unsigned long bayer; ///< bayer shift for flips==0
unsigned long dcmHor; /// bit mask bit 0 - 1:1, bit 31 - by 32 unsigned long dcmHor; ///< bit mask bit 0 - 1:1, bit 31 - by 32
unsigned long dcmVert; /// bit mask bit 0 - 1:1, bit 31 - by 32 unsigned long dcmVert; ///< bit mask bit 0 - 1:1, bit 31 - by 32
unsigned long binHor; /// bit mask bit 0 - 1:1, bit 31 - by 32 unsigned long binHor; ///< bit mask bit 0 - 1:1, bit 31 - by 32
unsigned long binVert; /// bit mask bit 0 - 1:1, bit 31 - by 32 unsigned long binVert; ///< bit mask bit 0 - 1:1, bit 31 - by 32
unsigned long maxGain256; /// maximal analog gain times 0x100 unsigned long maxGain256; ///< maximal analog gain times 0x100
unsigned long minClockFreq; /// Minimal clock frequency unsigned long minClockFreq; ///< Minimal clock frequency
unsigned long maxClockFreq; /// Maximal clock frequency unsigned long maxClockFreq; ///< Maximal clock frequency
unsigned long nomClockFreq; ///nominal clock frequency unsigned long nomClockFreq; ///<nominal clock frequency
unsigned long sensorType; /// sensor type (for Elphel cameras) unsigned long sensorType; ///< sensor type (for Elphel cameras)
unsigned long i2c_addr; /// i2c address unsigned long i2c_addr; ///< i2c address
unsigned long i2c_period; /// SCL period in ns, (standard i2c - 2500) unsigned long i2c_period; ///< SCL period in ns, (standard i2c - 2500)
unsigned long i2c_bytes; /// number of bytes/ register unsigned long i2c_bytes; ///< number of bytes/ register
short hact_delay; /// hact delay (in ps) from data short hact_delay; ///< hact delay (in ps) from data
short sensorDelay; /// Delay from sensor clock at FPGA output to pixel data transition (FPGA input), short cable (ps) short sensorDelay; ///< Delay from sensor clock at FPGA output to pixel data transition (FPGA input), short cable (ps)
unsigned long needReset; /// bit 0 - need reset after clock frequency change, bit 1 - need reset after phase change unsigned long needReset; ///< bit 0 - need reset after clock frequency change, bit 1 - need reset after phase change
}; };
#define SENSOR_NEED_RESET_CLK 1 #define SENSOR_NEED_RESET_CLK 1
#define SENSOR_NEED_RESET_PHASE 2 #define SENSOR_NEED_RESET_PHASE 2
struct sensorproc_t { struct sensorproc_t {
struct sensor_t sensor; struct sensor_t sensor;
/// functions return <0 on error (and do nothing) // functions return <0 on error (and do nothing)
/// first 32 functions are called directly when appropriate bit is set, next 32 - sensor specific that are called // first 32 functions are called directly when appropriate bit is set, next 32 - sensor specific that are called
/// by corresponding one with (number-32) if not NULL. Sensor initilaization should set up those functions // by corresponding one with (number-32) if not NULL. Sensor initilaization should set up those functions
int (*pgm_func[64]) (int sensor_port, ///< sensor port number (0..3) int (*pgm_func[64]) (int sensor_port, ///< sensor port number (0..3)
struct sensor_t * sensor, ///< pointer to sensor parameters struct sensor_t * sensor, ///< pointer to sensor parameters
struct framepars_t * framepars, ///< pointer to structure with array of current frame parameters struct framepars_t * framepars, ///< pointer to structure with array of current frame parameters
...@@ -1620,7 +1634,7 @@ struct sensorproc_t { ...@@ -1620,7 +1634,7 @@ struct sensorproc_t {
}; };
/*!*************************************************************************************************** /****************************************************************************************************
*! This is essential data related to the last frame aquired to be stored in the circular buffer before *! This is essential data related to the last frame aquired to be stored in the circular buffer before
*! each frame received from the FPGA - place where FPGA data is padded by 32 bytes of 0. *! each frame received from the FPGA - place where FPGA data is padded by 32 bytes of 0.
*! 6 bytes are already used by next frame pointer signature, so only 26 bytes are left *! 6 bytes are already used by next frame pointer signature, so only 26 bytes are left
...@@ -1628,11 +1642,11 @@ struct sensorproc_t { ...@@ -1628,11 +1642,11 @@ struct sensorproc_t {
*! that goes after the encoded frame, so total is 36 bytes (26+2+8) *! that goes after the encoded frame, so total is 36 bytes (26+2+8)
!****************************************************************************************************/ !****************************************************************************************************/
// move fram x353.h // move fram x353.h
#define DEFAULT_COLOR_SATURATION_BLUE 0x90 // 100*realtive saturation blue #define DEFAULT_COLOR_SATURATION_BLUE 0x90 ///< 100*realtive saturation blue
#define DEFAULT_COLOR_SATURATION_RED 0xb6 // 100*realtive saturation red #define DEFAULT_COLOR_SATURATION_RED 0xb6 ///< 100*realtive saturation red
//#define EXPOSURE_UNIT 100 // to move to finer exposure settings - current unit in microseconds. TODO: Propagate it to drivers... //#define EXPOSURE_UNIT 100 // to move to finer exposure settings - current unit in microseconds. TODO: Propagate it to drivers...
#define EXPOSURE_UNIT 1 // to move to finer exposure settings - current unit in microseconds. TODO: Propagate it to drivers... #define EXPOSURE_UNIT 1 ///< to move to finer exposure settings - current unit in microseconds. TODO: Propagate it to drivers...
/// width,height, quality are still needed even with new Exif - it is used to rebuild JPEG header /// width,height, quality are still needed even with new Exif - it is used to rebuild JPEG header
// most parameters are moved out, but width, height, quality are needed for JPEG header, so currently the following are used: // most parameters are moved out, but width, height, quality are needed for JPEG header, so currently the following are used:
...@@ -1711,9 +1725,9 @@ struct gamma_stuct_t { ...@@ -1711,9 +1725,9 @@ struct gamma_stuct_t {
}; };
}; };
}; };
int valid; /// 0 - table invalid, 1 - table valid +2 for table locked (until sent to FPGA) u64 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; /// bit frame+ (color<<3) locked for color/frame
int locked; /// NOTE: Changed to just color locked for color u64 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 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) union { /// used in head (element 0) and non-scaled chain (not used in scaled)
struct { /// element 0 - heads of the chains struct { /// element 0 - heads of the chains
...@@ -1760,10 +1774,12 @@ struct gamma_stuct_t { ...@@ -1760,10 +1774,12 @@ struct gamma_stuct_t {
}; };
struct { struct {
// int locked_col_frame[4 * PARS_FRAMES]; //index of the table to load to color/frame (should be locked, until unlocked) // 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 locked_chn_color[4*MAX_SENSORS*SENSOR_PORTS]; /// NOTE: Changed to just color (locked last written to FPGA - maybe needed again, as the FPGA needs all table to be overwritten - two pages)
// For NC393 - using 64 entries - individual for each channel/subchannel, color is in 2 lower bits
// int other [129+128+256 -(4 * PARS_FRAMES)]; // int other [129+128+256 -(4 * PARS_FRAMES)];
// int other [129+64+256 -(4 * PARS_FRAMES)]; // int other [129+64+256 -(4 * PARS_FRAMES)];
int other [129+64+256 -4]; int other [129+64+256 -4*MAX_SENSORS*SENSOR_PORTS];
}; };
}; };
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment