Commit af248eb3 authored by Andrey Filippov's avatar Andrey Filippov

working on histograms code

parent 8697a0d7
/*!********************************************************************************
*! FILE NAME : gamma_tables.c
*! DESCRIPTION: Handles "gamma"tables storage and scaling
*! exposes device driver to manipulate custom "gamma" tables
*! "Gamma" tables are calculated in several steps, leaving the
*! exponent calculation to the application, but handling scaling inside.
*! Scaling (with saturation if >1.0)is used for color balancing.
*! Gamma table calulation involves several intermediate tables:
*! - forward table
*! - reverse table (for histogram corrections)
*! - FPGA format
*! And the driver caches intermediate tables when possible, calculates
*! them when needed.
*! Copyright (C) 2008 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*! $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.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.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.14 2008/10/06 08:31:08 elphel
*! snapshot, first images
*!
*! Revision 1.13 2008/10/05 05:13:33 elphel
*! snapshot003
*!
*! Revision 1.12 2008/10/04 16:10:12 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.9 2008/09/19 04:37:25 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.6 2008/09/11 01:05:32 elphel
*! 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.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.1 2008/06/08 23:46:45 elphel
*! added drivers files for handling quantization tables, gamma tables and the histograms
*!
*!
/***************************************************************************//**
* @file gamma_tables.c
* @brief Handles "gamma"tables storage and scaling
* exposes device driver to manipulate custom "gamma" tables
* "Gamma" tables are calculated in several steps, leaving the
* exponent calculation to the application, but handling scaling inside.
* Scaling (with saturation if >1.0)is used for color balancing.
*
* Gamma table calculation involves several intermediate tables:
* - forward table
* - reverse table (for histogram corrections)
* - FPGA format
* And the driver caches intermediate tables when possible, calculates
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
/*********************************************************************************
* $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.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.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.14 2008/10/06 08:31:08 elphel
* snapshot, first images
*
* Revision 1.13 2008/10/05 05:13:33 elphel
* snapshot003
*
* Revision 1.12 2008/10/04 16:10:12 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.9 2008/09/19 04:37:25 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.6 2008/09/11 01:05:32 elphel
* 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.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.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
......@@ -149,7 +148,9 @@
#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"
/**
* @brief number of different non-scaled tables in cache when it starts to overwrite non-scaled tables rather than scaled
......@@ -158,15 +159,15 @@
#define GAMMA_THRESH (GAMMA_CACHE_NUMBER/16)
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 {
int minor;
unsigned short scale;
unsigned short hash16;
unsigned char mode;
unsigned char color;
/// something else to be added here?
unsigned char color; // Does it need port/sub-channel?
// something else to be added here?
};
int gammas_open (struct inode *inode, struct file *file);
......@@ -192,7 +193,7 @@ inline void remove_from_nonscaled(int index) {
* @param index item index to remove
*/
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].older_scaled].newer_scaled=gammas[index].newer_scaled;
}
......@@ -202,7 +203,7 @@ inline void remove_from_scaled (int index) {
* @brief remove item from the all ("diagonal") chain
* @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].older_all].newer_all=gammas[index].newer_all;
}
......@@ -219,8 +220,8 @@ inline void insert_first_nonscaled(int index) {
gammas[index].newer_non_scaled=0; // 6
gammas[0].non_scaled_length++;
gammas[index].this_non_scaled=0; // none
gammas[index].newest_scaled=index; /// no scaled yet - point to itself
gammas[index].oldest_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
}
......@@ -259,25 +260,25 @@ void init_gammas(void) {
unsigned long flags;
int i;
gammas_p=gammas;
/// empty 2-d chain
// empty 2-d chain
local_irq_save(flags);
gammas[0].oldest_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].newest_all=1;
MDF10(printk("\n"));
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
/// something else?
gammas[i].this_non_scaled=-1; // no parent.FIXME: Where is it used? -1 if never used
// something else?
gammas[i].newer_all=i-1;
gammas[i].older_all= (i==(GAMMA_CACHE_NUMBER-1))? 0: (i+1);
gammas[i].locked=0;
gammas[i].valid=0;
}
gammas[0].non_scaled_length=0;
for (i=1; i < 4;i++) {
gammas[0].locked_color[i]=0;
for (i=1; i < sizeof(gammas[0].locked_chn_color)/sizeof(gammas[0].locked_chn_color[0]);i++) {
gammas[0].locked_chn_color[i]=0;
}
local_irq_restore(flags);
}
......@@ -306,61 +307,68 @@ int is_gamma_valid (unsigned short hash16, unsigned short scale, int index) {
}
/**
* @brief Looks for the hash32 last programmed to the FPGA for the particular color
/** Looks for the hash32 last programmed to the FPGA for the particular color
* @param color
* @return hash32 (combined gamma/black/scale) locked fro a specified color. If none - return 0
* @return hash32 (combined gamma/black/scale) locked for a specified color. If none - return 0
*/
unsigned long get_locked_hash32(int color) {
int index=gammas[0].locked_color[color];
unsigned long get_locked_hash32(int color, ///< color channel 0..3
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;
}
/**
* @brief Lock gamma table for the specified color, save previous locks (if any) so new locks can be applied/canceled
* NOTE: interrupts should be disabled ***
* @param index gamma table index
* @param color
*/
inline void lock_gamma_node (int index, int color) {
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
gammas[tmp_p].locked &= ~(1 << color); /// remove any previous lock on the same color (if any)
}
gammas[0].locked_color[color]= index;
gammas[index].locked |= (1 << color);
}
* @brief 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! */
inline void lock_gamma_node (int index, ///< gamma table index
int color, ///< color channel 0..3
int sensor_port, ///< sensor port number (0..3)
int sensor_subchn) ///< sensor sub-channel (connected to the same port through 10359 mux) (0..3)
{
int tmp_p;
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[tmp_p].locked &= ~(1ULL << cps); // remove any previous lock on the same color (if any)
}
gammas[0].locked_chn_color[cps]= index;
gammas[index].locked |= (1ULL << cps);
}
/**
* @brief Unlock gamma table for the specified color
* NOTE: Not needed anymore
* @param color color index (0..3)
* @return wrong data -1, nothing to unlock - 0, >0 - unlocked index
*/
int unlock_gamma_node (int color) {
/** Unlock gamma table for the specified color/port/subchannel
* NOTE: Not needed anymore */
int unlock_gamma_node (int color, ///< color channel 0..3
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 wrong data -1, nothing to unlock - 0, >0 - unlocked index
{
unsigned long flags;
int index;
int cps = PORT_CHN_COLOR(color,sensor_port,sensor_subchn);
MDF11(printk("color=0x%x\n",color));
if (unlikely((color>= 4) || (color<0))) return -1;
local_irq_save(flags);
index =gammas[0].locked_color[color];
index =gammas[0].locked_chn_color[cps];
if (index) {
gammas[index].locked &= ~(1 << color); /// clear appropriate "locked" bit for this table
gammas[0].locked_color[color]=0;
gammas[index].locked &= ~(1ULL << color); // clear appropriate "locked" bit for this table
gammas[0].locked_chn_color[color]=0;
}
local_irq_restore(flags);
return index;
}
/**
* @brief Find a gamma table in FPGA format to be programmed (table should already be locked for this color)
* @param color color index (0..3) of the table
* @return pointer to a gamma table (or NULL if table does not exist)
*/
unsigned long * get_gamma_fpga(int color) { /// NOTE: Not needed anymore?
/** 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
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 pointer to a gamma table (or NULL if table does not exist)
{ // NOTE: Not needed anymore?
int index;
if (unlikely((color>=4) || (color<0))) return NULL; //
index =gammas[0].locked_color[color];
int cps = PORT_CHN_COLOR(color,sensor_port,sensor_subchn);
// if (unlikely((color>=4) || (color<0))) return NULL; //
index =gammas[0].locked_chn_color[cps];
MDF11(printk(" index=%d(0x%x)\n",index,index));
if (index) return gammas[index].fpga;
else return NULL;
......@@ -376,18 +384,18 @@ unsigned long * get_gamma_fpga(int color) { /// NOTE: Not needed anymore?
*/
int gamma_new_node(void) {
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
/// sacrifice 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
tmp_p=gammas[0].oldest_non_scaled;
remove_from_nonscaled(tmp_p);
} else { /// use oldest scaled
} else { // use oldest scaled
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;
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 "scaled chain"
// remove from "scaled chain"
remove_from_scaled (tmp_p);
}
gammas[tmp_p].valid=0;
......@@ -442,9 +450,9 @@ void gamma_calc_scaled (unsigned short scale,unsigned short * gamma_in, unsigne
* @param gamma_out reversed gamma table (8 bit)
*/
void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * gamma_out) {
unsigned long gcurr=0; /// running value to be compared against direct gamma
int r=0; /// current value of reverse gamma table
int x=0; /// current indedx of reverse gamma table
unsigned long gcurr=0; // running value to be compared against direct gamma
int r=0; // current value of reverse gamma table
int x=0; // current indedx of reverse gamma table
MDF11(printk("\n"));
while ((r<256) && (x<256)) {
gamma_out[x]=r;
......@@ -458,23 +466,25 @@ void gamma_calc_reverse(unsigned short * gamma_in, unsigned char * gamma_out) {
}
}
/**
* @brief calculate gamma table (and requested derivatives), insert new node if needed.
* @param hash16 16-bit unique (non-scaled) gamma table identifier. Can be 1-byte gamma and 1-byte black level shift TODO: make black level fine-grained?
* @param scale gamma table scale (currently 0x400 ~ 1.0) GAMMA_SCLALE_1 = 0x400
* @param gamma_proto 16-bit gamma table prototype (or NULL)
* @param mode bits specify calculation mode:
* - 1 - if set, no interrupts will be enabled between steps, whole operation will be atomic
* - 2 - calculate reverse gamma table
* - 4 - calculate FPGA-format gamma table.
* - 8 - Lock (FPGA) table for specified color
* @param color color index (0..3) to lock table for (if mode bit 4 is set), otherwise color is ignored
* @return index for the specified table or 0 if none exists and prototype was not provided (gamma_proto==NULL)
*/
//#define GAMMA_MODE_LOCK 8 // Lock the table for the specified color (used from irq/tasklet - it is needed because all 4 tables in FPGA have to be overwritten at once)
int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short * gamma_proto, unsigned char mode, int color) {
/** 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
///< TODO: make black level fine-grained?
unsigned short scale, ///< gamma table scale (currently 0x400 ~ 1.0) GAMMA_SCLALE_1 = 0x400
unsigned short * gamma_proto, ///< 16-bit gamma table prototype (or NULL)
unsigned char mode, ///< bits specify calculation mode:
///< - 1 - if set, no interrupts will be enabled between steps, whole operation will be atomic
///<- 2 - calculate reverse gamma table
///<- 4 - calculate FPGA-format gamma table
///< - 8 - Lock (FPGA) table for specified color/port/subchannel
int color, ///< index (0..63) combined with the next two parameters to lock
///< table for (if mode bit 4 is set), otherwise color, sensor_port, sensor_subchn are ignored
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 index for the specified table or 0 if none exists and prototype was not provided (gamma_proto==NULL)
{
D1I(unsigned long flags);
int tmp_p, tmp_p1; //,tmp_p0;
int cps=PORT_CHN_COLOR(color,sensor_port,sensor_subchn);
unsigned short gamma_linear[257]=
{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,
......@@ -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,
0xf000,0xf100,0xf200,0xf300,0xf400,0xf500,0x0600,0xf700,0xf800,0xf900,0xfa00,0xfb00,0xfc00,0xfd00,0xfe00,0xff00,
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)) {
gamma_proto=gamma_linear;
......@@ -503,10 +513,10 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
}
///disable interrupts here
D1I(local_irq_save(flags));
/// look for the matching hash
// look for the matching hash
tmp_p=gammas[0].newest_non_scaled;
/// gammas[0].oldest_all=GAMMA_CACHE_NUMBER-1;
/// gammas[0].newest_all=1;
// gammas[0].oldest_all=GAMMA_CACHE_NUMBER-1;
// gammas[0].newest_all=1;
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
tmp_p=gammas[tmp_p].older_non_scaled;
}
MDF10(printk("tmp_p=0x%x\n", tmp_p)); ///NOTE: 0xff
/// Got right hash?
if (tmp_p == 0) { /// no luck
// Got right hash?
if (tmp_p == 0) { // no luck
MDF10(printk("Need new table\n")); ///NOTE: never
if (!gamma_proto) { //
D1I(local_irq_restore(flags));
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();
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));
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].scale=0;
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].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
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));
MDF10(printk("Interrupts reenabled, tmp_p=0x%x\n", tmp_p));
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))) {
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 (gammas[tmp_p].direct, gamma_proto, 257*2) ; ///copy the provided table (full 16 bits)
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));
insert_first_nonscaled(tmp_p);
/// 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
// 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
MDF10(printk("remove_from_nonscaled (0x%x)\n", tmp_p)); ///NOTE: 0xff
remove_from_nonscaled (tmp_p);
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
MDF10(printk("0x%x\n", tmp_p)); ///NOTE: 0xff
/// now looking for the correct scale.
// now looking for the correct scale.
if (scale==0) {
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;
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
D10(printk(" >>tmp_p1=0x%x)\n", tmp_p1));
tmp_p1=gammas[tmp_p1].older_scaled;
}
/// Got right scale?
// if (tmp_p1 == 0) { /// no luck
if (tmp_p1 == tmp_p) { /// no luck
// Got right scale?
// if (tmp_p1 == 0) { // no luck
if (tmp_p1 == tmp_p) { // no luck
MDF10(printk("create new scaled table\n"));
/// create new scale
// create new scale
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));
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].scale= scale;
/// insert into 2-d
// insert into 2-d
insert_first_scaled (tmp_p, tmp_p1);
/// insert into 1-d (all)
// insert into 1-d (all)
insert_first_all (tmp_p1);
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_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))) {
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"));
/// 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
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);
insert_first_scaled (tmp_p, tmp_p1);
}
///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);
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) {
/// calculate scaled version
// calculate scaled version
gamma_calc_scaled (scale, gammas[tmp_p].direct, gammas[tmp_p1].direct);
gammas[tmp_p1].valid |= GAMMA_VALID_MASK;
}
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) {
gamma_encode_fpga(gammas[tmp_p1].direct, gammas[tmp_p1].fpga);
gammas[tmp_p1].valid |= GAMMA_FPGA_MASK;
}
}
if (mode & GAMMA_MODE_LOCK) {
/// lock the node for the color
lock_gamma_node (tmp_p1, color);
// lock the node for the color/port/channel
lock_gamma_node (tmp_p1, color, sensor_port,sensor_subchn);
}
if (mode & GAMMA_MODE_NEED_REVERSE) {
if ((gammas[tmp_p1].valid & GAMMA_VALID_REVERSE)==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_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))) {
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);
......@@ -658,26 +668,26 @@ int set_gamma_table (unsigned short hash16, unsigned short scale, unsigned short
///======================================
/// File operations:
/// open, release - nop
/// read - none
/// 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
/// 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 1 byte [4] - mode (1 - not_nice, 2 - need reverse, 4 - hardware, 8 - lock)
/// next byte [5] - color only if lock bit in mode is set
/// next 514 bytes [6..519] - 16-bit gamma table
/// can use current file pointer or special indexes (0x****ff01 - set frame number, 0x****ff02 - set latency) that should come before actual parameters
/// file pointer - absolute frame number
/// lseek (SEEK_SET, value) - do nothing, return 0
/// lseek (SEEK_CUR, value) - ignore value, return last write result (and if it is still valid) - used by ftell
/// lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
/// lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer
/// lseek (SEEK_END, 1) - initialize all the gamma data structures
/// lseek (SEEK_END, 2) - check that current hash/scale/index are still current
/// mmap (should be used read only)
// File operations:
// open, release - nop
// read - none
// 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
// 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 1 byte [4] - mode (1 - not_nice, 2 - need reverse, 4 - hardware, 8 - lock)
// next byte [5] - color only if lock bit in mode is set
// next 514 bytes [6..519] - 16-bit gamma table
// can use current file pointer or special indexes (0x****ff01 - set frame number, 0x****ff02 - set latency) that should come before actual parameters
// file pointer - absolute frame number
// lseek (SEEK_SET, value) - do nothing, return 0
// lseek (SEEK_CUR, value) - ignore value, return last write result (and if it is still valid) - used by ftell
// lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
// lseek (SEEK_END, value > 0) - execute commands, do not modify file pointer
// lseek (SEEK_END, 1) - initialize all the gamma data structures
// lseek (SEEK_END, 2) - check that current hash/scale/index are still current
// mmap (should be used read only)
//#define LSEEK_GAMMA_INIT 1 // SEEK_END LSEEK_GAMMA_INIT to initialize all the gamma data structures
//#define LSEEK_GAMMA_ISCURRENT 2 // SEEK_END to check if the selected node(pointed by file pointer) is current - returns 0 if not, otherwise - node index
/**
......@@ -716,7 +726,7 @@ int gammas_open(struct inode *inode, struct file *file) {
privData-> mode= 0;
return 0;
default:
kfree(file->private_data); /// already allocated
kfree(file->private_data); // already allocated
return -EINVAL;
}
file->f_pos = 0;
......@@ -784,7 +794,7 @@ loff_t gammas_lseek (struct file * file, loff_t offset, int orig) {
file->f_pos=0;
break;
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;
break;
default: ///other commands
......@@ -792,44 +802,42 @@ loff_t gammas_lseek (struct file * file, loff_t offset, int orig) {
}
break;
}
default: /// not SEEK_SET/SEEK_CUR/SEEK_END
default: // not SEEK_SET/SEEK_CUR/SEEK_END
return -EINVAL;
} /// switch (orig)
} // switch (orig)
MDF10(printk("file->f_pos=0x%x\n",(int) file->f_pos));
return file->f_pos ;
default: /// other minors
default: // other minors
return -EINVAL;
}
}
/**
* @brief Gammas driver WRITE method
/** 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 method receives data and uses it with \b set_gamma_table()
* - first 2 bytes [0.1] - scale (0..0xffff),
* - 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 [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()
* sets file pointer to gamma cache index (0 - no table exist)
* @param file
* @param buf
* @param count
* @param off
* @return full length passed or 0 if failed
*/
ssize_t gammas_write(struct file * file, const char * buf, size_t count, loff_t *off) {
* sets file pointer to gamma cache index (0 - no table exist) */
ssize_t gammas_write(struct file * file, ///< this file structure
const char * buf, ///< userland buffer
size_t count, ///< number of bytes to write
loff_t *off) ///< updated offset in the buffer
///< @return full length passed or 0 if failed
{
struct gammas_pd * privData = (struct gammas_pd *) file->private_data;
struct {
unsigned short scale;
unsigned short hash16;
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];
} data;
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;
MDF10(printk(" file->f_pos=0x%x, *off=0x%x\n", (int) file->f_pos, (int) *off));
switch (privData->minor) {
......@@ -838,12 +846,13 @@ ssize_t gammas_write(struct file * file, const char * buf, size_t count, loff_t
if(count) {
if(copy_from_user((char *) &data, buf, count)) return -EFAULT;
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;
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) 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;
} else *off=0;
MDF10(printk("file->f_pos=0x%x\n", (int) *off));
......@@ -885,8 +894,8 @@ static int __init gammas_init(void) {
printk ("Starting "X3X3_GAMMAS_DRIVER_NAME" - %d \n",GAMMAS_MAJOR);
init_gammas();
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
/// hash16==0
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
res = register_chrdev(GAMMAS_MAJOR, "gamma_tables_operations", &gammas_fops);
if(res < 0) {
......
......@@ -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_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)
/// return index of the specified hash/scale, insert new table (gamma_proto) if needed
/// If no table is specified (null) - return 0 if no prototype is found
/// if (not_nice) - don't re-enable interrupts between atomic actions (may fail)
/// if "hardware" is non-zero, color/frame pair will be used to lock node to it, fpga-encoded table will be calculated (if not done so earlier)
// return index of the specified hash/scale, insert new table (gamma_proto) if needed
// If no table is specified (null) - return 0 if no prototype is found
// if (not_nice) - don't re-enable interrupts between atomic actions (may fail)
// if "hardware" is non-zero, color/frame pair will be used to lock node to it, fpga-encoded table will be calculated (if not done so earlier)
// #define GAMMA_MODE_NOT_NICE 1 // if set, no interrupts will be enabled between steps, whole operation is atomic
// #define GAMMA_MODE_NEED_REVERSE 2 // reverse gamma table is needed
// #define GAMMA_MODE_HARDWARE 4 // the table is needed to program FPGA: fpga-encoded table will be calculated (if not yet), node will be locked for specified
// 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);
#endif
......@@ -92,10 +92,10 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/autoconf.h>
//#include <linux/autoconf.h>
#include <linux/vmalloc.h>
#include <asm/system.h>
//#include <asm/system.h>
#include <asm/byteorder.h> // endians
#include <asm/io.h>
......@@ -103,14 +103,21 @@
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <asm/elphel/driver_numbers.h>
#include <asm/elphel/c313a.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 <asm/outercache.h>
#include <asm/cacheflush.h>
#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 "x393.h"
#include "histograms.h"
/**
......@@ -118,36 +125,57 @@
*/
#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 ;} }
/// includes tasklets
// includes tasklets
#define MDF22(x) { if (GLOBALPARS(G_DEBUG) & (1 <<22)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
#else
#define MDF21(x)
#define MDF22(x)
#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"
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
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 {
int minor;
unsigned long frame;
int frame_index; /// -1 if invalid
int frame_index; ///< -1 if invalid
int needed;
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)
struct wait_queue *hist_y_wait_queue; /// wait queue for the G1 histogram (used as Y) ///NOTE: not used at all?
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 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 port; ///< selected sensor port (0..3)
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?
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);
......@@ -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_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);
/*
unsigned long gtab_r;
unsigned long gtab_g;
unsigned long gtab_gb;
unsigned long gtab_b;
histograms_dma_ctrl(2);
return 0;
}
*/
/** 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) {
unsigned long flags;
int i;
histograms_p=histograms;
MDF21(printk("\n"));
local_irq_save(flags);
for (i=0; i < HISTOGRAM_CACHE_NUMBER; i++) {
histograms[i].frame=0xffffffff;
histograms[i].valid=0;
}
local_irq_restore(flags);
void init_histograms(int chn_mask) ///< combined subchannels and ports Save mask to global P-variable
{
unsigned long flags;
int p,s,i, sz,pages;
numHistChn = 0; //__builtin_popcount (chn_mask & 0xffff);
if (sz & (PAGE_SIZE-1)) pages++;
for (p=0; p< SENSOR_PORTS; p++) for (s=0;s <MAX_SENSORS;s++) {
i = p * SENSOR_PORTS + s;
if (chn_mask & (1 << i)){
histograms_map = numHistChn++;
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?)
* @param frame absolute frame number (Caller should match it to the hardware frame)
* TODO: should it be one frame behind current?
* @param needed bits specify what histograms (color, type) are requested
* @param gammaHash array of 4 hash32 values to be saved with the histograms
* each group of 4 bits cover 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?)
* @return 0 for now
*/
int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash, unsigned long * framep) {
// unsigned long flags;
//hist_next_index
int i, color_start;
if (histograms[GLOBALPARS(G_HIST_LAST_INDEX)].frame!=frame) {
GLOBALPARS(G_HIST_LAST_INDEX)=(GLOBALPARS(G_HIST_LAST_INDEX)+1) & (HISTOGRAM_CACHE_NUMBER-1);
histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid=0; /// overwrite all
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
if (gammaHash) memcpy (&(histograms[GLOBALPARS(G_HIST_LAST_INDEX)].gtab_r), gammaHash, 16); // copy provided 4 hash32 values
} else {
needed &= ~histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid; /// remove those that are already available from the request
}
for (i=0; i<4; i++) if (needed & ( 1 << i )) {
color_start= i<<8 ;
fpga_hist_read_nice (color_start, 256, (unsigned long *) &histograms[GLOBALPARS(G_HIST_LAST_INDEX)].hist[color_start]);
histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid |= 1 << i;
}
return 0;
* each group of 4 bits cover 4 colors of the same type */
int set_histograms (int sensor_port, ///< sensor port number (0..3)
int sensor_chn, ///< sensor subchannel (0 w/o multiplexer)
unsigned long frame, ///< absolute frame number (Caller should match it to the hardware frame)
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?)
///< - 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 explicitly (can not be read from FPGA later),
///< "needed" for cumul_hist will be added automatically if percentiles are requested
unsigned long * gammaHash,///< array of 4 hash32 values to be saved with the histograms (same gamma for all sub-channels), NULL OK
unsigned long * framep) ///< array of 8 values to copy (frame, gains,expos,vexpos, focus), NULL OK
///< @return 0 OK, -EINVAL unused port/channel
{
int i, color_start, hist_indx, hist_frame;
hist_indx=get_hist_index(sensor_port,sensor_chn);
if (hist_indx <0 ) return -EINVAL;
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);
histograms[hist_indx][GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn)].valid=0; // overwrite all
histograms[hist_indx][GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn)].frame=frame; // add to existent
if (framep) memcpy (&(histograms[GLOBALPARS(sensor_port,G_HIST_LAST_INDEX)].frame), framep, 32); // copy provided frame, gains,expos,vexpos, focus
if (gammaHash) memcpy (&(histograms[GLOBALPARS(sensor_port,G_HIST_LAST_INDEX)].gtab_r), gammaHash, 16); // copy provided 4 hash32 values
} else {
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)
* 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
* @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
int get_histograms (unsigned long frame, int needed) {
// unsigned long flags;
//hist_next_index
int i, color_start;
int index=GLOBALPARS(G_HIST_LAST_INDEX);
int raw_needed=(needed | (needed>>4) | needed>>8) & 0xf;
for (i=0;i<HISTOGRAM_CACHE_NUMBER;i++) {
MDF21(printk("index=%d, needed=0x%x\n",index,needed));
if ((histograms[index].frame <= frame) && ((histograms[index].valid & raw_needed)==raw_needed)) break;
index = (index-1) & (HISTOGRAM_CACHE_NUMBER-1);
}
if (i>=HISTOGRAM_CACHE_NUMBER) {
ELP_KERR(printk("no histograms exist for requested colors (0x%x), requested 0x%x\n",raw_needed,needed));
return -1; /// 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[index].valid;
/// if ((needed >> 4) & (~histograms[index].valid) & 0x0f) return -2 ; /// some needed raw histograms are not available NOTE: now never comes here
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[index].hist[color_start], (unsigned long *) &histograms[index].cumul_hist[color_start] );
histograms[index].valid |= 0x10 << i;
int get_histograms(int sensor_port, ///< sensor port number (0..3)
int sensor_chn, ///< sensor subchannel (0 w/o multiplexer)
unsigned long frame, ///< absolute frame number (Caller should match it to the hardware frame)
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?)
///< - 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 explicitly (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:
///< - -EFAULT not reading FPGA and frame number stored is different from the requested (too late - histogram buffer overrun?)
///< - -EINVAL unused port/channel
{
int i, color_start, index;
int hist_indx=get_hist_index(sensor_port,sensor_chn);
if (hist_indx <0 ) return -EINVAL;
index=GLOBALPARS(sensor_port, G_HIST_LAST_INDEX+sensor_chn);
int raw_needed=(needed | (needed>>4) | needed>>8) & 0xf;
for (i=0;i<HISTOGRAM_CACHE_NUMBER;i++) {
MDF21(printk("index=%d, needed=0x%x\n",index,needed));
if ((histograms[hist_indx][index].frame <= frame) && ((histograms[hist_indx][index].valid & raw_needed)==raw_needed)) break;
index = (index-1) & (HISTOGRAM_CACHE_NUMBER-1);
}
if (i>=HISTOGRAM_CACHE_NUMBER) {
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 )) {
color_start= i<<8 ;
histogram_calc_percentiles ( (unsigned long *) &histograms[index].cumul_hist[color_start], (unsigned char *) &histograms[index].percentile[color_start] );
histograms[index].valid |= 0x100 << i;
if (needed & 0xf00) { // Calculating percentiles
for (i=0; i<4; i++) if (needed & ( 0x100 << i )) {
color_start= i<<8 ;
histogram_calc_percentiles ( (unsigned long *) &histograms[hist_indx][index].cumul_hist[color_start], (unsigned char *) &histograms[hist_indx][index].percentile[color_start] );
histograms[hist_indx][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;
}
/**
* @brief calculate cumulative histogram (one color component) from the corresponding raw histogram
* @param hist input raw histogram array of unsigned long, single color (256)
* @param cumul_hist output cumulative histogram array of unsigned long, single color (256)
*/
inline void histogram_calc_cumul ( unsigned long * hist, unsigned long * cumul_hist ) {
int i;
cumul_hist[0]=hist[0];
for (i=1; i<256;i++) cumul_hist[i]=cumul_hist[i-1]+hist[i];
/** 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)
unsigned long * cumul_hist) ///< output cumulative histogram array of unsigned long, single color (256)
{
int 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:
* 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
......@@ -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
* 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)
* @param cumul_hist
* @param percentile
*/
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 inc_v256=cumul_hist[255]; /// step of v256 increment
int shiftl=8;
while (inc_v256>0xffffff) { /// to protect from unlikely overflow at 16MPix - in the future)
inc_v256 >>= 1;
shiftl--;
}
int p=0; /// current value of percentile
int x=0; /// current percentile index
while ((p<256) && (x<256)) {
percentile[x]=p;
if ((p<255) && ( (cumul_hist[p] << shiftl) <= v256)) {
p++;
} else {
x++;
v256+=inc_v256;
* Current algorithm is limited to 16 MPix/color_component (64 MPix total) */
inline void histogram_calc_percentiles (unsigned long * cumul_hist, ///< [IN] Pointer to the start of u32[256] cumulative histogram array
unsigned char * percentile) ///< [OUT]Pointer to the start of u32[256] calculated percentile array
{
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
int shiftl=8;
while (inc_v256>0xffffff) { // to protect from unlikely overflow at 16MPix - in the future)
inc_v256 >>= 1;
shiftl--;
}
int p=0; // current value of percentile
int x=0; // current percentile index
while ((p<256) && (x<256)) {
percentile[x]=p;
if ((p<255) && ( (cumul_hist[p] << shiftl) <= v256)) {
p++;
} else {
x++;
v256+=inc_v256;
}
}
}
}
///======================================
/// File operations:
/// open, release - nop
/// read - none
/// write - none
/// lseek
/// mmap (should be used read only)
/**
* \def HISTOGRAMS_FILE_SIZE histograms file size (in frames, not bytes)
*/
#define HISTOGRAMS_FILE_SIZE HISTOGRAM_CACHE_NUMBER
// use G_SUBCHANNELS in userspace to re-calculate full histogram index
// File operations:
// open, release - nop
// read - none
// write - none
// lseek
// mmap (should be used read only)
/** HISTOGRAMS_FILE_SIZE histograms file size in frames (total nu,ber in all channels), not bytes) */
#define HISTOGRAMS_FILE_SIZE (HISTOGRAM_CACHE_NUMBER*numHistChn)
static struct file_operations histograms_fops = {
owner: THIS_MODULE,
llseek: histograms_lseek,
......@@ -346,55 +442,53 @@ static struct file_operations histograms_fops = {
release: histograms_release
};
/**
* @brief Histograms driver OPEN method
* @param inode inode
* @param file file pointer
* @return OK - 0, -EINVAL for wrong minor
*/
int histograms_open(struct inode *inode, struct file *file) {
int res;
struct histograms_pd * privData;
privData= (struct histograms_pd *) kmalloc(sizeof(struct histograms_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
file->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
MDF21(printk("minor=0x%x\n",privData-> minor));
switch (privData-> minor) {
case CMOSCAM_MINOR_HISTOGRAMS :
/** Histograms driver OPEN method */
int histograms_open(struct inode *inode, ///< inode
struct file *file) ///< file pointer
///< @return OK - 0, -EINVAL for wrong minor
{
int res;
struct histograms_pd * privData;
privData= (struct histograms_pd *) kmalloc(sizeof(struct histograms_pd),GFP_KERNEL);
if (!privData) return -ENOMEM;
file->private_data = privData;
privData-> minor=MINOR(inode->i_rdev);
MDF21(printk("minor=0x%x\n",privData-> minor));
switch (privData-> minor) {
case CMOSCAM_MINOR_HISTOGRAMS :
inode->i_size = HISTOGRAMS_FILE_SIZE;
privData->frame=0xffffffff;
privData->frame_index=-1;
privData->needed= 0;
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->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->port=0;
privData->subchannel=0;
return 0;
default:
kfree(file->private_data); // already allocated
return -EINVAL;
}
file->f_pos = 0;
return res;
default:
kfree(file->private_data); // already allocated
return -EINVAL;
}
file->f_pos = 0;
return res;
}
/**
* @brief Histograms driver RELEASE method
* @param inode inode
* @param file file pointer
* @return OK - 0, -EINVAL for wrong minor
*/
int histograms_release(struct inode *inode, struct file *file) {
int res=0;
int p = MINOR(inode->i_rdev);
MDF21(printk("minor=0x%x\n",p));
switch ( p ) {
/** Histograms driver RELEASE method */
int histograms_release (struct inode *inode, ///< inode
struct file *file) ///< file pointer
///< @return OK - 0, -EINVAL for wrong minor
{
int res=0;
int p = MINOR(inode->i_rdev);
MDF21(printk("minor=0x%x\n",p));
switch ( p ) {
case CMOSCAM_MINOR_HISTOGRAMS :
break;
default:
return -EINVAL; //! do not need to free anything - "wrong number"
}
kfree(file->private_data);
return res;
kfree(file->private_data);
return res;
}
/**
......@@ -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, 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_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_DIS) - disable histogram request when reading histogram - will read latest available relying it is available
* @param file
......@@ -421,103 +516,124 @@ int histograms_release(struct inode *inode, struct file *file) {
* @param orig SEEK_SET, SEEK_CUR or SEEK_SET END
* @return file position (absolute frame number)
*/
/// 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) {
struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
unsigned long reqAddr,reqFrame;
MDF21(printk("offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
switch (privData->minor) {
case CMOSCAM_MINOR_HISTOGRAMS :
switch(orig) {
case SEEK_CUR: /// ignore offset
offset+=(privData-> wait_mode)?GLOBALPARS(G_HIST_C_FRAME):GLOBALPARS(G_HIST_Y_FRAME);
case SEEK_SET:
privData->frame=offset;
/// Try to make some precautions to avoid waiting forever - if the past frame is requested - request histogram for the current frame,
/// if the "immediate" future (fits into the array of frames) one - request that frame's histogram
/// if in the far future (unsafe) do nothing -NOTE: far future should be avoided if the histograms are set request-only
/// 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 (privData->request_en) {
reqAddr=(privData-> wait_mode)?P_HISTRQ_C:P_HISTRQ_Y;
reqFrame=getThisFrameNumber();
if (offset > reqFrame) {
if (offset > (reqFrame+5)) reqFrame+=5;
else reqFrame=offset;
}
if ((offset < reqFrame) && /// if the requested frame is in the past - try to get it first before requesting a new
(((privData->frame_index = get_histograms (offset, privData->needed))) >=0)) {
file->f_pos=privData->frame_index;
return file->f_pos;
}
/// request histogram(s)
setFramePar(&framepars[reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
/// make sure (harmful) interrupt did not happen since getThisFrameNumber()
if (reqFrame < getThisFrameNumber()) {
setFramePar(&framepars[getThisFrameNumber() & PARS_FRAMES_MASK], reqAddr, 1);
}
}
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);
privData->frame_index = get_histograms (offset, privData->needed);
if (privData->frame_index <0) {
return -EFAULT;
} else {
file->f_pos=privData->frame_index;
return file->f_pos;
}
break; /// just in case
case SEEK_END:
if (offset < 0) {
return -EINVAL;
} else {
if (offset < LSEEK_HIST_NEEDED) {
switch (offset) {
case 0:
break;
case LSEEK_HIST_REQ_EN: /// enable requesting histogram for the specified frame (0 - rely on the available ones)
privData->request_en=1; ///default after open
break;
case LSEEK_HIST_REQ_DIS: /// disable requesting histogram for the specified frame, rely on the available ones
privData->request_en=0;
break;
case LSEEK_HIST_WAIT_Y: /// set histogram waiting for the Y (actually G1) histogram (default after open)
privData-> wait_mode=0;
break;
case LSEEK_HIST_WAIT_C: /// set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too
privData-> wait_mode=1;
break;
default:
switch (offset & ~0x1f) {
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
// 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)
{
int p,s;
struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
unsigned long reqAddr,reqFrame;
MDF21(printk("offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
switch (privData->minor) {
case CMOSCAM_MINOR_HISTOGRAMS :
switch(orig) {
case SEEK_CUR: // ignore offset
offset+=(privData-> wait_mode)?
GLOBALPARS(privData->port,G_HIST_C_FRAME+privData->subchannel):
GLOBALPARS(privData->port,G_HIST_Y_FRAME+privData->subchannel);
//no break (CDT understands this)
case SEEK_SET:
privData->frame=offset;
// Try to make some precautions to avoid waiting forever - if the past frame is requested - request histogram for the current frame,
// if the "immediate" future (fits into the array of frames) one - request that frame's histogram
// if in the far future (unsafe) do nothing -NOTE: far future should be avoided if the histograms are set request-only
// 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 (privData->request_en) {
reqAddr=(privData-> wait_mode)?P_HISTRQ_C:P_HISTRQ_Y;
reqFrame=getThisFrameNumber(privData->port);
if (offset > reqFrame) {
if (offset > (reqFrame+5)) reqFrame+=5; // What is this 5?
else reqFrame=offset;
}
if ((offset < reqFrame) && // if the requested frame is in the past - try to get it first before requesting a new
(((privData->frame_index = get_histograms (offset, privData->needed))) >=0)) {
// 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;
}
// request histogram(s)
// setFramePar(&framepars[reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
setFramePar(&aframepars[privData->port][reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
// make sure (harmful) interrupt did not happen since getThisFrameNumber()
if (reqFrame < getThisFrameNumber(privData->port)) {
// setFramePar(&framepars[getThisFrameNumber() & PARS_FRAMES_MASK], reqAddr, 1);
setFramePar(&aframepars[privData->port][getThisFrameNumber(privData->port) & PARS_FRAMES_MASK], reqAddr, 1);
}
}
if (privData-> wait_mode) wait_event_interruptible (hist_c_wait_queue,GLOBALPARS(privData->port,G_HIST_C_FRAME + privData->subchannel)>=offset);
else wait_event_interruptible (hist_y_wait_queue,GLOBALPARS(privData->port,G_HIST_Y_FRAME + privData->subchannel)>=offset);
privData->frame_index = get_histograms (offset, privData->needed);
if (privData->frame_index <0) {
return -EFAULT;
} else {
// 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;
}
break; // just in case
case SEEK_END:
if (offset < 0) {
return -EINVAL;
} else {
if (offset < LSEEK_HIST_NEEDED) {
//#define LSEEK_HIST_SET_CHN 0x30 ///< ..2F Select channel to wait for (4*port+subchannel)
if ((offset & ~0xf) == LSEEK_HIST_SET_CHN){
p = (offset >> 2) & 3;
s = (offset >> 0) & 3;
if (get_hist_index(p,s)<0)
return -ENXIO; // invalid port/channel combination
privData->port = p;
privData->subchannel = s;
file->f_pos=privData->frame_index + HISTOGRAM_CACHE_NUMBER * get_hist_index(privData->port, privData->subchannel);
} else switch (offset) {
case 0:
break;
case LSEEK_HIST_REQ_EN: // enable requesting histogram for the specified frame (0 - rely on the available ones)
privData->request_en=1; ///default after open
break;
case LSEEK_HIST_REQ_DIS: // disable requesting histogram for the specified frame, rely on the available ones
privData->request_en=0;
break;
case LSEEK_HIST_WAIT_Y: // set histogram waiting for the Y (actually G1) histogram (default after open)
privData-> wait_mode=0;
break;
case LSEEK_HIST_WAIT_C: // set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too
privData-> wait_mode=1;
break;
default:
switch (offset & ~0x1f) {
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;
} /// 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)
......@@ -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 result;
struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
MDF21(printk("minor=0x%x\n",privData-> minor));
switch (privData->minor) {
case CMOSCAM_MINOR_HISTOGRAMS :
result=remap_pfn_range(vma,
vma->vm_start,
((unsigned long) virt_to_phys(histograms_p)) >> PAGE_SHIFT, /// Should be page-aligned
vma->vm_end-vma->vm_start,
vma->vm_page_prot);
MDF21(printk("remap_pfn_range returned=%x\r\n",result));
if (result) return -EAGAIN;
return 0;
default: return -EINVAL;
}
int result;
struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
MDF21(printk("minor=0x%x\n",privData-> minor));
switch (privData->minor) {
case CMOSCAM_MINOR_HISTOGRAMS :
result=remap_pfn_range(vma,
vma->vm_start,
((unsigned long) virt_to_phys(histograms_p)) >> PAGE_SHIFT, // Should be page-aligned
vma->vm_end-vma->vm_start,
vma->vm_page_prot);
MDF21(printk("remap_pfn_range returned=%x\r\n",result));
if (result) return -EAGAIN;
return 0;
default: return -EINVAL;
}
}
/**
......@@ -549,18 +665,19 @@ int histograms_mmap (struct file *file, struct vm_area_struct *vma) {
* @return 0
*/
static int __init histograms_init(void) {
int res;
init_histograms();
res = register_chrdev(HISTOGRAMS_MAJOR, "gamma_tables_operations", &histograms_fops);
if(res < 0) {
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(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color)
printk(X3X3_HISTOGRAMS_DRIVER_NAME"\r\n");
return 0;
int res;
// init_histograms(); // Not now??? Need to have list of channels
// Do it later, from the user space
res = register_chrdev(HISTOGRAMS_MAJOR, "gamma_tables_operations", &histograms_fops);
if(res < 0) {
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(&hist_c_wait_queue); // wait queue for all the other (R,G2,B) histograms (color)
printk(X3X3_HISTOGRAMS_DRIVER_NAME"\r\n");
return 0;
}
......@@ -568,25 +685,3 @@ module_init(histograms_init);
MODULE_LICENSE("GPLv3.0");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(X3X3_HISTOGRAMS_DRIVER_NAME);
......@@ -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_c_wait_queue; /// wait queue for all the other (R,G2,B) histograms (color)
void init_histograms(void);
int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash, unsigned long * framep);
void init_histograms(int chn_mask);
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)
......@@ -15,11 +18,11 @@ int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash,
* TODO: should it be one frame behind current?
* @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:
* 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 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 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
* @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?)
......@@ -27,3 +30,5 @@ int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash,
*/
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 @@
void x313_dma_init(){}
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));
#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
if (get_locked_hash32(color)!=thispars->pars[P_GTAB_R+color]) { // modified for this 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
}
}
......@@ -2011,7 +2016,13 @@ int pgm_gammaload (int sensor_port, ///< sensor port number (0..3
for (color=0; color<4; color++) {
*pgamma32=thispars->pars[P_GTAB_R+color];
// 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
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
......
......@@ -25,46 +25,18 @@
*/
//copied from cxi2c.c - TODO:remove unneeded
//#include <linux/module.h>
#include <linux/sched.h>
//#include <linux/slab.h>
//#include <linux/errno.h>
#include <linux/kernel.h>
//#include <linux/fs.h>
//#include <linux/string.h>
#include <linux/init.h>
//#include <linux/autoconf.h>
#include <linux/interrupt.h>
#include <linux/time.h>
//#include <linux/vmalloc.h>
#include <linux/platform_device.h>
//#include <linux/of.h>
//#include <linux/of_device.h>
#include <asm/outercache.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/c313a.h>
//#include <asm/elphel/fpgaconfa.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 "sensor_common.h"
......@@ -173,6 +145,32 @@ void camseq_set_jpeg_rp(unsigned int chn, int 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?
......@@ -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
struct sensorproc_t * asensorproc = NULL;
//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);
......@@ -205,23 +203,23 @@ struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * co
///
/// initializes structures for the image acquisition parameter
/// initializes hardware i2c controller and the command sequencer (leaves them stopped to ignore any frame syncs)
/// sets some default acquisition parameters
/// Maybe - set up DMA also?
/// TODO: Take care while turning off reset on i2c and cmd_sequencer so there will be no sensor vsync lost
/// (easier to do in FPGA)
/// Done:
// initializes structures for the image acquisition parameter
// initializes hardware i2c controller and the command sequencer (leaves them stopped to ignore any frame syncs)
// sets some default acquisition parameters
// Maybe - set up DMA also?
// TODO: Take care while turning off reset on i2c and cmd_sequencer so there will be no sensor vsync lost
// (easier to do in FPGA)
// Done:
///#define CCAM_VSYNC_ON port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,0)
///#define CCAM_VSYNC_OFF port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,1)
///
int init_acq_sensor(void); // Never used?
//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_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_3, tasklet_fpga_function, 3); /// 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_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_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};
......@@ -239,12 +237,12 @@ static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
phys_addr_t phys_addr;
void *virt_addr;
// 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);
xferred = stat.offset256 - (jptr->fpga_cntr_prev >> 3);
if (xferred == 0)
return 0; /// no advance (compressor was off?)
return 0; // no advance (compressor was off?)
jptr->flags |= SENS_FLAG_IRQ;
jptr->fpga_cntr_prev = jptr->jpeg_wp;
......@@ -414,10 +412,10 @@ inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, struct interframe_params_t*
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;
// 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 * 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.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);
......@@ -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
DIS_INTERRUPTS;
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, ...?
if (updateIRQJPEG_wp()) { ///also fills P_FRAME ahead
updateIRQCircbuf();
updateIRQFocus(); ///NOTE: currently global (latest), not per-frame
struct interframe_params_t* interframe= updateIRQ_interframe(); /// fills jpeg_len, signffff
/// should we use memcpy as before here?
struct interframe_params_t* interframe= updateIRQ_interframe(); // fills jpeg_len, signffff
// should we use memcpy as before here?
// interframe->frame_length=jpeg_len;
// interframe->signffff=0xffff;
updateIRQ_Exif(interframe);
updateFramePars(X3X3_I2C_FRAME, interframe);
wake_up_interruptible(&circbuf_wait_queue); /// only when frame is acquired
wake_up_interruptible(&circbuf_wait_queue); // only when frame is acquired
} else {
updateFramePars(X3X3_I2C_FRAME, NULL);
}
PROFILE_NOW(1);
wake_up_interruptible(&framepars_wait_queue); /// all interrupts, not just frames acquired
tasklet_schedule(&tasklet_fpga); /// trigger software interrupt
wake_up_interruptible(&framepars_wait_queue); // all interrupts, not just frames acquired
tasklet_schedule(&tasklet_fpga); // trigger software interrupt
EN_INTERRUPT(SMART);
......@@ -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
/// if defined 1 - will wakeup each frame, regardless of the availability of the histograms
// HISTOGRAMS_WAKEUP_ALWAYS if 0 will only wakeup processes waiting for histograms when they become available, maybe never if they are disabled
// if defined 1 - will wakeup each frame, regardless of the availability of the histograms
//#define HISTOGRAMS_WAKEUP_ALWAYS 0
void tasklet_fpga_function(unsigned long arg) {
int is_compressor_irq = 1; // TODO: add interrupts from frame sync if compressor is off
int hist_en;
int sensor_port = image_acq_priv.jpeg_ptr[arg].chn_num;
int tasklet_disable=get_globalParam(sensor_port, G_TASKLET_CTL);
unsigned long thisFrameNumber=getThisFrameNumber(sensor_port);
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]);
const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
dma_addr_t phys_addr_start, phys_addr_end;
void *virt_addr_start;
unsigned int sz;
int subchn,hist_indx;
/* 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);
......@@ -626,78 +626,85 @@ void tasklet_fpga_function(unsigned long arg) {
__cpuc_flush_dcache_area(virt_addr_start, sz - CCAM_DMA_SIZE);
}
#ifdef TEST_DISABLE_CODE
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
#endif /* TEST_DISABLE_CODE */
/// Histograms are available for the previous frame (that is already in circbuf if compressor was running)
/// Is Y histogram needed?
// Time is out?
if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port,is_compressor_irq)) & PARS_FRAMES_MASK) return; // already next frame
// Histograms are available for the previous frame (that is already in circbuf if compressor was running)
// Is Y histogram needed?
PROFILE_NOW(2);
switch ((tasklet_disable >> TASKLET_CTL_HISTY_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
case TASKLET_HIST_NEVER: // never calculate
hist_en=0;
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));
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));
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));
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));
break;
case TASKLET_HIST_ALL: /// calculate each frame
default: /// calculate always (safer)
case TASKLET_HIST_ALL: // calculate each frame
default: // calculate always (safer)
hist_en=1;
}
#ifdef TEST_DISABLE_CODE
//#ifdef TEST_DISABLE_CODE
if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, (1 << COLOR_Y_NUMBER), hash32p, framep); /// 0x2 Green1
GLOBALPARS(G_HIST_Y_FRAME)=prevFrameNumber; /// histogram corresponds to previous frame
// after updateFramePars gammaHash are from framepars[this-1]
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,
(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);
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
// Time is out?
// 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
}
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
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 /* TEST_DISABLE_CODE */
/// Process parameters
//#endif /* TEST_DISABLE_CODE */
// Process parameters
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);
}
#ifdef TEST_DISABLE_CODE
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
/// Are C histograms needed?
#endif /* TEST_DISABLE_CODE */
// Time is out?
if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port,is_compressor_irq)) & PARS_FRAMES_MASK) return; // already next frame
// Are C histograms needed?
switch ((tasklet_disable >> TASKLET_CTL_HISTC_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
case TASKLET_HIST_NEVER: // never calculate
hist_en=0;
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));
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));
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));
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));
break;
case TASKLET_HIST_ALL: /// calculate each frame
default: /// calculate always (safer)
case TASKLET_HIST_ALL: // calculate each frame
default: // calculate always (safer)
hist_en=1;
}
/*
......@@ -707,22 +714,35 @@ GLOBALPARS(0x1042)=((thisFrameNumber & 7) ==0);
GLOBALPARS(0x1043)=hist_en;
GLOBALPARS(0x1044)=thisFrameNumber;
*/
#ifdef TEST_DISABLE_CODE
if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, 0xf, hash32p, framep); /// all 4 colors, including Y (it will be skipped)
GLOBALPARS(G_HIST_C_FRAME)=prevFrameNumber; /// histogram corresponds to previous frame
// after updateFramePars gammaHash are from framepars[this-1]
// after updateFramePars gammaHash are from framepars[this-1]
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);
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
// Time is out?
if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port,is_compressor_irq)) & PARS_FRAMES_MASK) return; // already next frame
#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
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 /* TEST_DISABLE_CODE */
}
//#endif /* TEST_DISABLE_CODE */
......@@ -736,10 +756,10 @@ void reset_compressor(unsigned int chn)
local_irq_save(flags);
#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 );
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 */
image_acq_priv.jpeg_ptr[chn].jpeg_wp = 0;
image_acq_priv.jpeg_ptr[chn].jpeg_rp = 0;
......@@ -765,7 +785,7 @@ void camera_interrupts (int on) {
} else {
DIS_INTERRUPTS;
}
/// clear smart interrupt circuitry in any case
// clear smart interrupt circuitry in any case
port_csp0_addr[X313_WA_SMART_IRQ]=0x8000;
reg_intr_vect_rw_mask intr_mask;
......@@ -856,11 +876,11 @@ int image_acq_init(struct platform_device *pdev)
for (i = 0; i < SENSOR_PORTS; i++) {
reset_compressor(i);
}
//reset_compressor(); /// reset compressor and buffer pointers
//reset_compressor(); // reset compressor and buffer pointers
//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"));
//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"));
framepars_init(pdev);
......
......@@ -240,6 +240,7 @@
#define SENSORWIDTH_IBIS51300 1280 ///< FillFactory IBIS51300 width
#define SENSORHEIGHT_IBIS51300 1024 ///< FillFactory IBIS51300 height
//TODO: Update CONST_NAME_ENTRY_* to new P_vars
/// 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)
/* Modified for 393 - using up to 4 sub-sensors (even as 10359 only supports 3 */
......@@ -427,6 +428,8 @@
// The following 4 parameters should have consecutive indexes
// 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.
///< 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)
......@@ -453,6 +456,8 @@
#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
// 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_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")
......@@ -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_HISTC_BIT 8 ///< shift of histogram calculation for C in G_TASKLET_CTL (bits 8,9,10)
#define G_HIST_LAST_INDEX (FRAMEPAR_GLOBALS + 56) ///< last used index in histogram cache
#define G_HIST_Y_FRAME (FRAMEPAR_GLOBALS + 57) ///< last frame for which Y histogram was calcualted
#define G_HIST_C_FRAME (FRAMEPAR_GLOBALS + 58) ///< last frame for which C histograms were calcualted
//#define G_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 calculated
//#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_FTP_NEXT_TIME (FRAMEPAR_GLOBALS + 60) ///< time of the next FTP upload (seconds from epoch)
......@@ -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_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
///< Only first 96 for each color are used
......@@ -1266,6 +1278,7 @@ struct p_names_t {
G_NAME_ENTRY(HIST_LAST_INDEX), \
G_NAME_ENTRY(HIST_Y_FRAME), \
G_NAME_ENTRY(HIST_C_FRAME), \
G_NAME_ENTRY(SUBCHANNELS), \
G_NAME_ENTRY(SKIP_DIFF_FRAME), \
G_NAME_ENTRY(FTP_NEXT_TIME), \
G_NAME_ENTRY(DAEMON_ERR), \
......@@ -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
/// MOST ARE OBSOLETE - WILL REMOVE WHEN UPDATING STREAMERS
#define IO_CCAM_JPEG 0x08 /// JPEG-compressor related commands
#define JPEG_CMD_RESET 0x00 /// Resets pointers - both acquisition and readout
//#define JPEG_CMD_ARM 0x01 /// Prepare compressor to read next frame acquired
#define JPEG_CMD_GET 0x02 /// Read current page (will return empty (and length==0) if not ready
#define JPEG_CMD_FORGET 0x03 /// increment read frame pointer
#define JPEG_CMD_CATCHUP 0x04 /// set read pointer to the last acquired (or acquiring if none is acquired yet)
#define JPEG_CMD_ACQUIRE 0x05 /// acquire and compress one frame
#define JPEG_CMD_SAVE_RP 0x06 /// save read pointer
#define JPEG_CMD_RESTORE_RP 0x07 /// restore read pointer
#define JPEG_CMD_N_DONE 0x08 /// return 1 if no more frames to be acquired (frame number)
#define JPEG_CMD_L_DONE 0x09 /// return 1 if no more frames to be acquired (total length)
#define JPEG_CMD_START 0x0a /// start constant compression mode
#define JPEG_CMD_STOP 0x0b /// stop constant compression mode (may want to wait for CAMSEQ_DONE)
#define JPEG_CMD_FRAMES 0x0c /// returns number of frames in buffer, (re)uilds frames chain
#define JPEG_CMD_JUST_STOP 0x0d /// just stop - don't start cycle if was allready off!
#define JPEG_CMD_DUMP 0x0f /// printk all static data/tables
#define JPEG_CMD_RESET0 0x10 /// same as JPEG_CMD_RESET, but non-zero, to be used from lseek (SEEK_END)
//#define PROGRAM_SENSOR_0 0x11 /// programSensor(0) - to be used from lseek (SEEK_END)
//#define PROGRAM_SENSOR_1 0x12 /// programSensor(1) - to be used from lseek (SEEK_END)
#define IO_CCAM_JPEG 0x08 ///< JPEG-compressor related commands
#define JPEG_CMD_RESET 0x00 ///< Resets pointers - both acquisition and readout
//#define JPEG_CMD_ARM 0x01 ///< Prepare compressor to read next frame acquired
#define JPEG_CMD_GET 0x02 ///< Read current page (will return empty (and length==0) if not ready
#define JPEG_CMD_FORGET 0x03 ///< increment read frame pointer
#define JPEG_CMD_CATCHUP 0x04 ///< set read pointer to the last acquired (or acquiring if none is acquired yet)
#define JPEG_CMD_ACQUIRE 0x05 ///< acquire and compress one frame
#define JPEG_CMD_SAVE_RP 0x06 ///< save read pointer
#define JPEG_CMD_RESTORE_RP 0x07 ///< restore read pointer
#define JPEG_CMD_N_DONE 0x08 ///< return 1 if no more frames to be acquired (frame number)
#define JPEG_CMD_L_DONE 0x09 ///< return 1 if no more frames to be acquired (total length)
#define JPEG_CMD_START 0x0a ///< start constant compression mode
#define JPEG_CMD_STOP 0x0b ///< stop constant compression mode (may want to wait for CAMSEQ_DONE)
#define JPEG_CMD_FRAMES 0x0c ///< returns number of frames in buffer, (re)uilds frames chain
#define JPEG_CMD_JUST_STOP 0x0d ///< just stop - don't start cycle if was allready off!
#define JPEG_CMD_DUMP 0x0f ///< printk all static data/tables
#define JPEG_CMD_RESET0 0x10 ///< same as JPEG_CMD_RESET, but non-zero, to be used from lseek (SEEK_END)
//#define PROGRAM_SENSOR_0 0x11 ///< programSensor(0) - to be used from lseek (SEEK_END)
//#define PROGRAM_SENSOR_1 0x12 ///< programSensor(1) - to be used from lseek (SEEK_END)
/// Compressor state now applies only to particular frame
//#define LSEEK_CAMSEQSTATE 0x13 /// return camSeqState - to be used from lseek (SEEK_END)
//#define LSEEK_CAMSEQSTATE 0x13 ///< return camSeqState - to be used from lseek (SEEK_END)
#define LSEEK_GAMMA_INIT 1 // SEEK_END LSEEK_GAMMA_INIT to initialize all the gamma data structures
#define LSEEK_GAMMA_ISCURRENT 2 // SEEK_END to check if the selected node(pointed by file pointer) is current - returns 0 if not, otherwise - node index
......@@ -1392,47 +1405,48 @@ struct p_names_t {
#define LSEEK_HUFFMAN_FPGACALC 7
#define LSEEK_HUFFMAN_FPGAPGM 8
//#define LSEEK_RESET_SENSOR 0x14 /// reset sensor and FPGA - next time will reprogram it
//#define LSEEK_INIT_SENSOR 0x15 /// initialise SDRAM and sensor if it is not programmed yet (or reset)
//#define LSEEK_RESET_SENSOR 0x14 ///< reset sensor and FPGA - next time will reprogram it
//#define LSEEK_INIT_SENSOR 0x15 ///< initialise SDRAM and sensor if it is not programmed yet (or reset)
#define LSEEK_GET_FPGA_TIME 0x16 /// get FPGA timer to G_SECONDS, G_MICROSECONDS
#define LSEEK_SET_FPGA_TIME 0x17 /// set FPGA timer to G_SECONDS, G_MICROSECONDS
#define LSEEK_GET_FPGA_TIME 0x16 ///< get FPGA timer to G_SECONDS, G_MICROSECONDS
#define LSEEK_SET_FPGA_TIME 0x17 ///< set FPGA timer to G_SECONDS, G_MICROSECONDS
//#define LSEEK_FLUSH_CACHE 0x18 // workaround for Axis mmap cache coherency problems - flush all cache (8KB)
#define LSEEK_AUTOEXP_SET 0x19 /// set autoexposure parameters
#define LSEEK_AUTOEXP_GET 0x1a /// copy window and exposure parameters to autoexp_state
#define LSEEK_TRIGGER_PGM 0x1b /// program trigger parameters
#define LSEEK_I2C_PGM 0x1c /// program hardware i2c speed/bytes
#define LSEEK_IRQ_SMART_PGM 0x1d /// program "smart" irq modes (+1 - wait VACT, +2 - wait dma fifo)
#define LSEEK_EXTERN_TIMESTAMP_PGM 0x1e /// 1 - use external timestamps if available
#define LSEEK_DMA_INIT 0x1f /// (re-) initialize ETRAX DMA for compressor
#define LSEEK_DMA_STOP 0x20 /// STOP ETRAX DMA
#define LSEEK_DMA_START 0x21 /// STARTETRAX DMA
#define LSEEK_COMPRESSOR_RESET 0x22 /// reset compressor and pointers
#define LSEEK_INTERRUPT_OFF 0x23 /// disable camera interrupts
#define LSEEK_INTERRUPT_ON 0x24 /// enable camera interrupts
#define LSEEK_FRAMEPARS_INIT 0x25 /// reset hardware sequencers, init framepars structure
#define LSEEK_SENSORPROC 0x26 /// process modified parameters in frame 0 (to start sensor detection)
#define LSEEK_FRAME_RESET 0x27 /// reset absolute frame number to avoid integer overflow
///Histograms related commands
#define LSEEK_HIST_WAIT_Y 0x28 /// set histogram waiting for the Y (actually G1) histogram (default after open)
#define LSEEK_HIST_WAIT_C 0x29 /// set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too
#define LSEEK_HIST_REQ_EN 0x2a /// enable histogram request when reading histogram (safer, but may be not desirable in HDR mode) - default after opening
#define LSEEK_HIST_REQ_DIS 0x2b /// disable histogram request when reading histogram - will read latest available relying it is available
#define LSEEK_HIST_NEEDED 0x10000 /// set histogram "needed" mask - 0x10000..0x1ffff
//#define LSEEK_HIST_WAIT_AE 0x2a /// wait for autoexposure enabled
#define LSEEK_DAEMON_FRAME 0x80 /// LSEEK_DAEMON_FRAME+B wait for frame interrupt and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_DAEMON_CIRCBUF 0xa0 /// LSEEK_DAEMON_FRAME+B wait for frame compressed interrupt and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_DAEMON_HIST_Y 0xc0 /// LSEEK_DAEMON_FRAME+B wait for histogram Y ready and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_DAEMON_HIST_C 0xe0 /// LSEEK_DAEMON_FRAME+B wait for all histograms ready and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_FRAME_WAIT_REL 0x100 /// LSEEK_WAIT_FRAME_REL+N - skip N frames (0<N<256)
#define LSEEK_FRAME_WAIT_ABS 0x200 /// LSEEK_WAIT_FRAME_ABS+N - wait absolute frame N
#define LSEEK_AUTOEXP_SET 0x19 ///< set autoexposure parameters
#define LSEEK_AUTOEXP_GET 0x1a ///< copy window and exposure parameters to autoexp_state
#define LSEEK_TRIGGER_PGM 0x1b ///< program trigger parameters
#define LSEEK_I2C_PGM 0x1c ///< program hardware i2c speed/bytes
#define LSEEK_IRQ_SMART_PGM 0x1d ///< program "smart" irq modes (+1 - wait VACT, +2 - wait dma fifo)
#define LSEEK_EXTERN_TIMESTAMP_PGM 0x1e ///< 1 - use external timestamps if available
#define LSEEK_DMA_INIT 0x1f ///< (re-) initialize ETRAX DMA for compressor
#define LSEEK_DMA_STOP 0x20 ///< STOP ETRAX DMA
#define LSEEK_DMA_START 0x21 ///< STARTETRAX DMA
#define LSEEK_COMPRESSOR_RESET 0x22 ///< reset compressor and pointers
#define LSEEK_INTERRUPT_OFF 0x23 ///< disable camera interrupts
#define LSEEK_INTERRUPT_ON 0x24 ///< enable camera interrupts
#define LSEEK_FRAMEPARS_INIT 0x25 ///< reset hardware sequencers, init framepars structure
#define LSEEK_SENSORPROC 0x26 ///< process modified parameters in frame 0 (to start sensor detection)
#define LSEEK_FRAME_RESET 0x27 ///< reset absolute frame number to avoid integer overflow
//Histograms related commands
#define LSEEK_HIST_WAIT_Y 0x28 ///< set histogram waiting for the Y (actually G1) histogram (default after open)
#define LSEEK_HIST_WAIT_C 0x29 ///< set histogram waiting for the C (actually R, G2, B) histograms to become available - implies G1 too
#define LSEEK_HIST_REQ_EN 0x2a ///< enable histogram request when reading histogram (safer, but may be not desirable in HDR mode) - default after opening
#define LSEEK_HIST_REQ_DIS 0x2b ///< disable histogram request when reading histogram - will read latest available relying it is available
#define LSEEK_HIST_SET_CHN 0x30 ///< ..2F Select channel to wait for (4*port+subchannel)
#define LSEEK_HIST_NEEDED 0x10000 ///< set histogram "needed" mask - 0x10000..0x1ffff
//#define LSEEK_HIST_WAIT_AE 0x2a ///< wait for autoexposure enabled
#define LSEEK_DAEMON_FRAME 0x80 ///< LSEEK_DAEMON_FRAME+B wait for frame interrupt and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_DAEMON_CIRCBUF 0xa0 ///< LSEEK_DAEMON_FRAME+B wait for frame compressed interrupt and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_DAEMON_HIST_Y 0xc0 ///< LSEEK_DAEMON_FRAME+B wait for histogram Y ready and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_DAEMON_HIST_C 0xe0 ///< LSEEK_DAEMON_FRAME+B wait for all histograms ready and corresponding bit (B) in P_DAEMON_EN is set
#define LSEEK_FRAME_WAIT_REL 0x100 ///< LSEEK_WAIT_FRAME_REL+N - skip N frames (0<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)
......@@ -1569,49 +1583,49 @@ struct p_names_t {
// make this structure common for sensors, add fields as needed
struct sensor_t {
// sensor constants
unsigned long imageWidth; /// nominal image width for final images
unsigned long imageHeight; /// nominal image height for final images
unsigned long clearWidth; /// maximal clear (useful) image width
unsigned long clearHeight; /// maximal clear (useful) image height;
unsigned long clearTop; /// top 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 arrayHeight; /// total image array height (including black and boundary)
unsigned long minWidth; /// minimal WOI width
unsigned long minHeight; /// minimal WOI height
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 maxHorBlank; /// maximal horizontal blanking/Virtual frame width (depends on sensor type)
unsigned long minVertBlank; /// minimal vertical blanking
unsigned long maxVertBlank; /// maximal vertical blanking/Virtual frame height (depends on sensor type)
unsigned long maxShutter; /// Maximal shutter duration (in lines)
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 bayer; /// bayer shift for flips==0
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 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 maxGain256; /// maximal analog gain times 0x100
unsigned long minClockFreq; /// Minimal clock frequency
unsigned long maxClockFreq; /// Maximal clock frequency
unsigned long nomClockFreq; ///nominal clock frequency
unsigned long sensorType; /// sensor type (for Elphel cameras)
unsigned long i2c_addr; /// i2c address
unsigned long i2c_period; /// SCL period in ns, (standard i2c - 2500)
unsigned long i2c_bytes; /// number of bytes/ register
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)
unsigned long needReset; /// bit 0 - need reset after clock frequency change, bit 1 - need reset after phase change
unsigned long imageWidth; ///< nominal image width for final images
unsigned long imageHeight; ///< nominal image height for final images
unsigned long clearWidth; ///< maximal clear (useful) image width
unsigned long clearHeight; ///< maximal clear (useful) image height;
unsigned long clearTop; ///< top 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 arrayHeight; ///< total image array height (including black and boundary)
unsigned long minWidth; ///< minimal WOI width
unsigned long minHeight; ///< minimal WOI height
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 maxHorBlank; ///< maximal horizontal blanking/Virtual frame width (depends on sensor type)
unsigned long minVertBlank; ///< minimal vertical blanking
unsigned long maxVertBlank; ///< maximal vertical blanking/Virtual frame height (depends on sensor type)
unsigned long maxShutter; ///< Maximal shutter duration (in lines)
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 bayer; ///< bayer shift for flips==0
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 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 maxGain256; ///< maximal analog gain times 0x100
unsigned long minClockFreq; ///< Minimal clock frequency
unsigned long maxClockFreq; ///< Maximal clock frequency
unsigned long nomClockFreq; ///<nominal clock frequency
unsigned long sensorType; ///< sensor type (for Elphel cameras)
unsigned long i2c_addr; ///< i2c address
unsigned long i2c_period; ///< SCL period in ns, (standard i2c - 2500)
unsigned long i2c_bytes; ///< number of bytes/ register
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)
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_PHASE 2
struct sensorproc_t {
struct sensor_t sensor;
/// 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
/// by corresponding one with (number-32) if not NULL. Sensor initilaization should set up those functions
// 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
// 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)
struct sensor_t * sensor, ///< pointer to sensor parameters
struct framepars_t * framepars, ///< pointer to structure with array of current frame parameters
......@@ -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
*! 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
......@@ -1628,11 +1642,11 @@ struct sensorproc_t {
*! that goes after the encoded frame, so total is 36 bytes (26+2+8)
!****************************************************************************************************/
// move fram x353.h
#define DEFAULT_COLOR_SATURATION_BLUE 0x90 // 100*realtive saturation blue
#define DEFAULT_COLOR_SATURATION_RED 0xb6 // 100*realtive saturation red
#define DEFAULT_COLOR_SATURATION_BLUE 0x90 ///< 100*realtive saturation blue
#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 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
// 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 {
};
};
};
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; /// 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
union { /// used in head (element 0) and non-scaled chain (not used in scaled)
struct { /// element 0 - heads of the chains
......@@ -1760,10 +1774,12 @@ struct gamma_stuct_t {
};
struct {
// int locked_col_frame[4 * PARS_FRAMES]; //index of the table to load to color/frame (should be locked, until unlocked)
int locked_color[4]; /// NOTE: Changed to just color (locked last written to FPGA - maybe needed again, as the FPGA needs all table to be overwritten - two pages)
int 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+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