Commit e82469d0 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev

sensor-individual ahead tabs (latencies)

parent ccb9697d
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "x393.h" #include "x393.h"
#include <uapi/elphel/x393_devices.h> #include <uapi/elphel/x393_devices.h>
#include <uapi/elphel/c313a.h> #include <uapi/elphel/c313a.h>
#include "latency.h"
#include "mt9x001.h" #include "mt9x001.h"
#include "mt9f002.h" #include "mt9f002.h"
#include "multi10359.h" #include "multi10359.h"
...@@ -191,7 +192,13 @@ sens_iface_t get_port_interface(int port) ///< Sensor port number (0..3) ...@@ -191,7 +192,13 @@ sens_iface_t get_port_interface(int port) ///< Sensor port number (0..3)
return port_iface[port]; return port_iface[port];
} }
/** init port and subchn with default ahead_tab from latency.h */
int init_port_ahead_table(int port,
int sub_chn)
{
sensorPortConfig[port & 3].ahead_tab[sub_chn] = ahead_tab;
return 0;
}
/** Set sensor port multiplexer type */ /** Set sensor port multiplexer type */
int set_detected_mux_code(int port, ///< Sensor port number (0..3) int set_detected_mux_code(int port, ///< Sensor port number (0..3)
...@@ -391,6 +398,7 @@ static int elphel393_detect_sensors_sysfs_register(struct platform_device *pdev) ...@@ -391,6 +398,7 @@ static int elphel393_detect_sensors_sysfs_register(struct platform_device *pdev)
for (sub_chn = 0; sub_chn < num_sub; sub_chn++){ for (sub_chn = 0; sub_chn < num_sub; sub_chn++){
pr_info ("Setting sensor %d:%d '%s' (0x%x)\n",port, sub_chn, names[sub_chn], get_code_by_name(names[sub_chn], DETECT_SENSOR)); pr_info ("Setting sensor %d:%d '%s' (0x%x)\n",port, sub_chn, names[sub_chn], get_code_by_name(names[sub_chn], DETECT_SENSOR));
set_detected_sensor_code(port, sub_chn, get_code_by_name(names[sub_chn], DETECT_SENSOR)); set_detected_sensor_code(port, sub_chn, get_code_by_name(names[sub_chn], DETECT_SENSOR));
init_port_ahead_table(port,sub_chn);
} }
} }
} }
...@@ -440,6 +448,7 @@ int detect_sensors_par2addr_init(int port,int sub_chn){ ...@@ -440,6 +448,7 @@ int detect_sensors_par2addr_init(int port,int sub_chn){
const unsigned short *par2addr; const unsigned short *par2addr;
const unsigned short *pages; const unsigned short *pages;
const unsigned short *atab;
/* /*
struct sensor_port_config_t { struct sensor_port_config_t {
...@@ -453,13 +462,15 @@ int detect_sensors_par2addr_init(int port,int sub_chn){ ...@@ -453,13 +462,15 @@ int detect_sensors_par2addr_init(int port,int sub_chn){
switch (sensorPortConfig[port].sensor[sub_chn]) { switch (sensorPortConfig[port].sensor[sub_chn]) {
case SENSOR_MT9P006: case SENSOR_MT9P006:
// get sensor table // get sensor table
par2addr = mt9x001_par2addr; par2addr = mt9x001_par2addr;
pages = mt9x001_pages; pages = mt9x001_pages;
atab = mt9x001_ahead_tab;
break; break;
case SENSOR_MT9F002: case SENSOR_MT9F002:
// get sensor table // get sensor table
par2addr = mt9f002_par2addr; par2addr = mt9f002_par2addr;
pages = mt9f002_pages; pages = mt9f002_pages;
atab = mt9f002_ahead_tab;
break; break;
} }
if (par2addr){ if (par2addr){
...@@ -468,6 +479,9 @@ int detect_sensors_par2addr_init(int port,int sub_chn){ ...@@ -468,6 +479,9 @@ int detect_sensors_par2addr_init(int port,int sub_chn){
// save pointer to static LUT // save pointer to static LUT
sensorPortConfig[port].pages_ptr[sub_chn] = pages; sensorPortConfig[port].pages_ptr[sub_chn] = pages;
} }
if(atab){
sensorPortConfig[port].ahead_tab[sub_chn] = atab;
}
/* /*
// all .mux and .sensor are already filled out // all .mux and .sensor are already filled out
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define MAX_FPGA_RECS 256 #define MAX_FPGA_RECS 256
#define MUX_BROADCAST_INDEX 3 #define MUX_BROADCAST_INDEX 3
#define AHEAD_TAB_FUNCS_COUNT 32*7
struct sensor_port_config_t { struct sensor_port_config_t {
u32 mux; ///< Sensor multiplexer, currently 0 (SENSOR_DETECT, SENSOR_MUX_10359 or SENSOR_NONE) u32 mux; ///< Sensor multiplexer, currently 0 (SENSOR_DETECT, SENSOR_MUX_10359 or SENSOR_NONE)
...@@ -37,7 +38,9 @@ struct sensor_port_config_t { ...@@ -37,7 +38,9 @@ struct sensor_port_config_t {
//u8 haddr2rec[MAX_SENSORS][MAX_FPGA_RECS]; ///< Big LUT (but almost empty). Sensor's page address (haddr of reg addr) to fpga i2c record number (fpga line#) //u8 haddr2rec[MAX_SENSORS][MAX_FPGA_RECS]; ///< Big LUT (but almost empty). Sensor's page address (haddr of reg addr) to fpga i2c record number (fpga line#)
// u32 is for error handling // u32 is for error handling
u32 haddr2rec[MAX_SENSORS][MAX_FPGA_RECS]; ///< Big LUT (but almost empty). Sensor's page address (haddr of reg addr) to fpga i2c record number (fpga line#) u32 haddr2rec[MAX_SENSORS][MAX_FPGA_RECS]; ///< Big LUT (but almost empty). Sensor's page address (haddr of reg addr) to fpga i2c record number (fpga line#)
unsigned short *pages_ptr[MAX_SENSORS]; const unsigned short *pages_ptr[MAX_SENSORS];
// original table is const unsigned long, 32 functions is MAX
const unsigned short *ahead_tab[MAX_SENSORS];
}; };
extern struct sensor_port_config_t *pSensorPortConfig; extern struct sensor_port_config_t *pSensorPortConfig;
......
...@@ -86,7 +86,9 @@ ...@@ -86,7 +86,9 @@
#ifndef _LATENCY_H #ifndef _LATENCY_H
#define _LATENCY_H #define _LATENCY_H
///TODO: not used yet, but it is possible to specify a function with non-zero latency that does not work with the sequencer - only in ASAP mode ///TODO: not used yet, but it is possible to specify a function with non-zero latency that does not work with the sequencer - only in ASAP mode
const unsigned long ahead_tab[]= //const unsigned long ahead_tab[]=
// changed to short which is more than enough
const unsigned short ahead_tab[] =
{ /// ASAP C,S C,NS, A,S A,NS NOL { /// ASAP C,S C,NS, A,S A,NS NOL
#if 0 #if 0
onchange_recalcseq, 0, 0, 0, 0, 0, 0, /// recalculate sequences/latencies, according to P_SKIP, P_TRIG onchange_recalcseq, 0, 0, 0, 0, 0, 0, /// recalculate sequences/latencies, according to P_SKIP, P_TRIG
......
...@@ -121,6 +121,57 @@ const unsigned short mt9f002_pages[] = { ...@@ -121,6 +121,57 @@ const unsigned short mt9f002_pages[] = {
0xffff // END indicator 0xffff // END indicator
}; };
/**
* pgm_functions latencies tab
*/
// ASAP - ASAP
// C,S - continuous/safe TRIG&4=0 SAFE=0 (visa versa?)
// C,NS - continuous/no skip TRIG&4=0 SAFE=1
// A,S - async/safe TRIG&4=4 SAFE=0 (visa versa?)
// A,NS - async/no skip TRIG&4=4 SAFE=1
// NOL - nooverlap TRIG&8=8
// array size is AHEAD_TAB_FUNCS_COUNT
const unsigned short mt9f002_ahead_tab[] =
{ /// function ASAP C,S C,NS, A,S A,NS NOL
onchange_recalcseq, 0, 0, 0, 0, 0, 0, /// recalculate sequences/latencies, according to P_SKIP, P_TRIG
onchange_detectsensor, 1, 0, 0, 0, 0, 0, /// detect sensor type, sets sensor structure (capabilities), function pointers
onchange_sensorphase, 1, 0, 0, 0, 0, 0, /// program sensor clock/phase (do immediately)
onchange_i2c, 0, 0, 0, 0, 0, 0, /// program i2c
onchange_initsensor, 1, 0, 0, 0, 0, 0, /// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
onchange_afterinit, 0, 0, 0, 0, 0, 0, /// restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
onchange_multisens, 0, 2, 1, 1, 1, 0, /// chnages related to multiplexed sensors
onchange_window, 0, 2, 1, 1, 1, 0, /// program sensor WOI and mirroring (flipping) - NOTE: 1 bad frame to skip
onchange_window_safe, 0, 1, 1, 1, 1, 0, /// program sensor WOI and mirroring (flipping) - NOTE: no bad frames
onchange_exposure, 0, 2, 1, 2, 1, 0, /// program exposure
onchange_gains, 0, 1, 1, 1, 1, 0, /// program analog gains
onchange_triggermode, 0, 2, 1, 1, 1, 0, /// program sensor trigger mode TODO: does it have any sense here?
onchange_sensorin, 0, 0, 0, 0, 0, 0, /// program sensor input in FPGA (Bayer, 8/16 bits, ??), stop sensor (if needed)
onchange_sensorstop, 0, 0, 0, 0, 0, 0, /// Stop acquisition from the sensor to the FPGA (start has latency of 2)
onchange_sensorrun, 0, 1, 1, 1, 1, 0, /// Start/single acquisition from the sensor to the FPGA (stop has latency of 1)
onchange_gamma, 0, 1, 1, 1, 1, 0, /// program gamma table - make sure table is calculated, maybe send all but last word)
onchange_hist, 0, 0, 0, 0, 0, 0, /// program histogram window TODO: fix FPGA - (now pos_top will be read too early - will use previous ) and add latency
onchange_aexp, 0, 0, 0, 0, 0, 0, /// program autoexposure mode TODO: look what exactly is changed here
onchange_quality, 0, 0, 0, 0, 0, 0, /// program quantization table(s)
onchange_memsensor, 0, 0, 0, 0, 0, 0, /// program memory channels 0 (sensor->memory) and 1 (memory->FPN)
onchange_memcompressor, 0, 0, 0, 0, 0, 0, /// program memory channel 2 (memory->compressor) (delays programming until onchange_comprestart if needed)
/// For Micron sensors limitfps should have the same latency as changing window height, otherwise when WOI_HEIGHT 0x3c0->0x790 and next frame VBLANK 0x13e->0x284
/// sensor waits till the counter overflows (>10 seconds) without any frame sync pulses
onchange_limitfps, 0, 2, 1, 1, 1, 0, /// check compressor will keep up, limit sensor FPS if needed
onchange_compmode, 0, 0, 0, 0, 0, 0, /// program compressor modes
onchange_focusmode, 1, 0, 0, 0, 0, 0, /// program focus modes (through writing the tables, so no sequencer)
onchange_trigseq, 0, 2, 1, 1, 1, 0, /// NC393: OK to program through the sequencer (full 32 bits)
onchange_irq, 0, 0, 0, 0, 0, 0, /// program smart IRQ mode
onchange_comprestart, 0, 0, 0, 0, 0, 0, /// restart after changing geometry (recognizes ASAP and programs memory channel 2 then)
// onchange_compstop should have the same latency as onchange_window
// NC393 - triggered mode wants onchange_compstop==2, while onchange_window == 1?
// TODO: NC393 now comstop is used when changing color modes does not need two cycles - just 1
onchange_compstop, 0, 2, 2, 2, 2, 0, /// stop compressor when changing geometry
onchange_compctl, 0, 0, 1, 1, 1, 0, /// only start/stop/single (after explicitly changed, not when geometry was changed)
onchange_gammaload, 1, 1, 1, 1, 1, 0, /// write gamma tables (should be prepared). Maybe - just last byte, to activate?
onchange_sensorregs, 0, 1, 1, 1, 1, 0, /// write sensor registers (only changed from outside the driver as they may have different latencies)?
onchange_prescal, 0, 0, 0, 0, 0, 0 /// change scales for per-color digital gains, apply vignetting correction
};
static struct device *g_dev_ptr=NULL; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions static struct device *g_dev_ptr=NULL; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions
void mt9f002_set_device(struct device *dev) // do nothing, now it has it's own device void mt9f002_set_device(struct device *dev) // do nothing, now it has it's own device
{ {
......
...@@ -663,6 +663,7 @@ LUT to map SENSOR_REGSxxx to internal sensor register addresses ...@@ -663,6 +663,7 @@ LUT to map SENSOR_REGSxxx to internal sensor register addresses
*/ */
extern const unsigned short mt9f002_par2addr[]; extern const unsigned short mt9f002_par2addr[];
extern const unsigned short mt9f002_pages[]; extern const unsigned short mt9f002_pages[];
extern const unsigned short mt9f002_ahead_tab[];
/** Detect one of Micron/Aptina/On Semiconductor sensors MT9M*, MT9D*,MT9T*, andMT9P* with parallel interface */ /** Detect one of Micron/Aptina/On Semiconductor sensors MT9M*, MT9D*,MT9T*, andMT9P* with parallel interface */
int mt9f002_pgm_detectsensor (int sensor_port, ///< sensor port number (0..3) int mt9f002_pgm_detectsensor (int sensor_port, ///< sensor port number (0..3)
......
...@@ -453,6 +453,57 @@ const unsigned short mt9x001_pages[] = { ...@@ -453,6 +453,57 @@ const unsigned short mt9x001_pages[] = {
0xffff // END indicator 0xffff // END indicator
}; };
/**
* pgm_functions latencies table
*/
// ASAP - ASAP
// C,S - continuous/safe TRIG&4=0 SAFE=0 (visa versa?)
// C,NS - continuous/no skip TRIG&4=0 SAFE=1
// A,S - async/safe TRIG&4=4 SAFE=0 (visa versa?)
// A,NS - async/no skip TRIG&4=4 SAFE=1
// NOL - nooverlap TRIG&8=8
// array size is AHEAD_TAB_FUNCS_COUNT
const unsigned short mt9x001_ahead_tab[] =
{ /// function ASAP C,S C,NS, A,S A,NS NOL
onchange_recalcseq, 0, 0, 0, 0, 0, 0, /// recalculate sequences/latencies, according to P_SKIP, P_TRIG
onchange_detectsensor, 1, 0, 0, 0, 0, 0, /// detect sensor type, sets sensor structure (capabilities), function pointers
onchange_sensorphase, 1, 0, 0, 0, 0, 0, /// program sensor clock/phase (do immediately)
onchange_i2c, 0, 0, 0, 0, 0, 0, /// program i2c
onchange_initsensor, 1, 0, 0, 0, 0, 0, /// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
onchange_afterinit, 0, 0, 0, 0, 0, 0, /// restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
onchange_multisens, 0, 2, 1, 1, 1, 0, /// chnages related to multiplexed sensors
onchange_window, 0, 2, 1, 1, 1, 0, /// program sensor WOI and mirroring (flipping) - NOTE: 1 bad frame to skip
onchange_window_safe, 0, 1, 1, 1, 1, 0, /// program sensor WOI and mirroring (flipping) - NOTE: no bad frames
onchange_exposure, 0, 2, 1, 1, 1, 0, /// program exposure
onchange_gains, 0, 1, 1, 1, 1, 0, /// program analog gains
onchange_triggermode, 0, 2, 1, 1, 1, 0, /// program sensor trigger mode TODO: does it have any sense here?
onchange_sensorin, 0, 0, 0, 0, 0, 0, /// program sensor input in FPGA (Bayer, 8/16 bits, ??), stop sensor (if needed)
onchange_sensorstop, 0, 0, 0, 0, 0, 0, /// Stop acquisition from the sensor to the FPGA (start has latency of 2)
onchange_sensorrun, 0, 1, 1, 1, 1, 0, /// Start/single acquisition from the sensor to the FPGA (stop has latency of 1)
onchange_gamma, 0, 1, 1, 1, 1, 0, /// program gamma table - make sure table is calculated, maybe send all but last word)
onchange_hist, 0, 0, 0, 0, 0, 0, /// program histogram window TODO: fix FPGA - (now pos_top will be read too early - will use previous ) and add latency
onchange_aexp, 0, 0, 0, 0, 0, 0, /// program autoexposure mode TODO: look what exactly is changed here
onchange_quality, 0, 0, 0, 0, 0, 0, /// program quantization table(s)
onchange_memsensor, 0, 0, 0, 0, 0, 0, /// program memory channels 0 (sensor->memory) and 1 (memory->FPN)
onchange_memcompressor, 0, 0, 0, 0, 0, 0, /// program memory channel 2 (memory->compressor) (delays programming until onchange_comprestart if needed)
/// For Micron sensors limitfps should have the same latency as changing window height, otherwise when WOI_HEIGHT 0x3c0->0x790 and next frame VBLANK 0x13e->0x284
/// sensor waits till the counter overflows (>10 seconds) without any frame sync pulses
onchange_limitfps, 0, 2, 1, 1, 1, 0, /// check compressor will keep up, limit sensor FPS if needed
onchange_compmode, 0, 0, 0, 0, 0, 0, /// program compressor modes
onchange_focusmode, 1, 0, 0, 0, 0, 0, /// program focus modes (through writing the tables, so no sequencer)
onchange_trigseq, 0, 2, 1, 1, 1, 0, /// NC393: OK to program through the sequencer (full 32 bits)
onchange_irq, 0, 0, 0, 0, 0, 0, /// program smart IRQ mode
onchange_comprestart, 0, 0, 0, 0, 0, 0, /// restart after changing geometry (recognizes ASAP and programs memory channel 2 then)
// onchange_compstop should have the same latency as onchange_window
// NC393 - triggered mode wants onchange_compstop==2, while onchange_window == 1?
// TODO: NC393 now comstop is used when changing color modes does not need two cycles - just 1
onchange_compstop, 0, 2, 2, 2, 2, 0, /// stop compressor when changing geometry
onchange_compctl, 0, 0, 1, 1, 1, 0, /// only start/stop/single (after explicitly changed, not when geometry was changed)
onchange_gammaload, 1, 1, 1, 1, 1, 0, /// write gamma tables (should be prepared). Maybe - just last byte, to activate?
onchange_sensorregs, 0, 1, 1, 1, 1, 0, /// write sensor registers (only changed from outside the driver as they may have different latencies)?
onchange_prescal, 0, 0, 0, 0, 0, 0 /// change scales for per-color digital gains, apply vignetting correction
};
static struct device *g_dev_ptr=NULL; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions static struct device *g_dev_ptr=NULL; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions
void mt9x001_set_device(struct device *dev) // do nothing, now it has it's own device void mt9x001_set_device(struct device *dev) // do nothing, now it has it's own device
{ {
......
...@@ -202,6 +202,7 @@ LUT to map SENSOR_REGSxxx to internal sensor register addresses ...@@ -202,6 +202,7 @@ LUT to map SENSOR_REGSxxx to internal sensor register addresses
*/ */
extern const unsigned short mt9x001_par2addr[]; extern const unsigned short mt9x001_par2addr[];
extern const unsigned short mt9x001_pages[]; extern const unsigned short mt9x001_pages[];
extern const unsigned short mt9x001_ahead_tab[];
int mt9x001_pgm_detectsensor (int sensor_port, ///< sensor port number (0..3) int mt9x001_pgm_detectsensor (int sensor_port, ///< sensor port number (0..3)
struct sensor_t * sensor, ///< sensor static parameters (capabilities) struct sensor_t * sensor, ///< sensor static parameters (capabilities)
......
...@@ -210,7 +210,7 @@ ...@@ -210,7 +210,7 @@
#include "mt9f002.h" #include "mt9f002.h"
#include "gamma_tables.h" #include "gamma_tables.h"
#include "quantization_tables.h" #include "quantization_tables.h"
#include "latency.h" //#include "latency.h"
#include "pgm_functions.h" #include "pgm_functions.h"
#include "jpeghead.h" // to program FPGA Huffman tables #include "jpeghead.h" // to program FPGA Huffman tables
#include "x393.h" #include "x393.h"
...@@ -2810,24 +2810,44 @@ int pgm_recalcseq (int sensor_port, ///< sensor port number (0..3 ...@@ -2810,24 +2810,44 @@ int pgm_recalcseq (int sensor_port, ///< sensor port number (0..3
int async=(thispars->pars[P_TRIG] & 4)?1:0; int async=(thispars->pars[P_TRIG] & 4)?1:0;
int nooverlap=(thispars->pars[P_TRIG] & 8)?1:0; int nooverlap=(thispars->pars[P_TRIG] & 8)?1:0;
int i,b,d; int i,b,d;
//const unsigned long *port_ahead_tab = ahead_tab;//pSensorPortConfig[sensor_port].ahead_tab[ba];
// will it work for mux?
int ba = pSensorPortConfig[sensor_port].broadcast_addr;
const unsigned short *port_ahead_tab = pSensorPortConfig[sensor_port].ahead_tab[ba];
struct frameparspair_t pars[5]= { struct frameparspair_t pars[5]= {
{G_CALLNEXT+1,0}, {G_CALLNEXT+1,0},
{G_CALLNEXT+2,0}, {G_CALLNEXT+2,0},
{G_CALLNEXT+3,0}, {G_CALLNEXT+3,0},
{G_CALLNEXT+4,0}, {G_CALLNEXT+4,0},
{G_CALLNASAP,0}}; {G_CALLNASAP,0}};
dev_dbg(g_dev_ptr,"{%d} frame16=%d, safe=%d, async=%d, nooverlap=%d\n",sensor_port,frame16, safe, async, nooverlap); dev_dbg(g_dev_ptr,"{%d} frame16=%d, safe=%d, async=%d, nooverlap=%d\n",sensor_port,frame16, safe, async, nooverlap);
MDP(DBGB_PSFN, sensor_port,"frame16=%d\n",frame16) MDP(DBGB_PSFN, sensor_port,"frame16=%d\n",frame16)
for (i=0; i < (sizeof(ahead_tab)/sizeof(ahead_tab[0])); i+=7) {
b=ahead_tab[i]; port_ahead_tab = pSensorPortConfig[sensor_port].ahead_tab[ba];
d=ahead_tab[i+1+(nooverlap?5:(1+((async?2:0)+(safe?1:0))))]; ///continuous/safe - 1, continuous/no skip - 2, async/safe - 3, async/no skip - 4, nooverlap - 5 // init at an earlier stages and remove this check
if (!port_ahead_tab){
dev_warn(g_dev_ptr,"prm_recalcseq: port_ahead_tab is NULL\n");
return 0;
}
//pr_info("pat pgm_exposure values: %d %d %d %d %d %d\n",pat[64],pat[65],pat[66],pat[67],pat[68],pat[69]);
//pr_info("ahd pgm_exposure values: %d %d %d %d %d %d\n",ahead_tab[64],ahead_tab[65],ahead_tab[66],ahead_tab[67],ahead_tab[68],ahead_tab[69]);
//for (i=0; i < (sizeof(port_ahead_tab)/sizeof(port_ahead_tab[0])); i+=7) {
for (i=0; i < AHEAD_TAB_FUNCS_COUNT; i+=7) {
b = port_ahead_tab[i];
///continuous/safe - 1, continuous/no skip - 2, async/safe - 3, async/no skip - 4, nooverlap - 5
d = port_ahead_tab[i+1+(nooverlap?5:(1+((async?2:0)+(safe?1:0))))];
if ((d>0) && (d <=4 )) { if ((d>0) && (d <=4 )) {
pars[d-1].val |= (1<<b); pars[d-1].val |= (1<<b);
} }
if (!ahead_tab[i+1]) { // not the ASAP only mode if (!port_ahead_tab[i+1]) { // not the ASAP only mode
pars[4].val |= (1<<b); pars[4].val |= (1<<b);
} }
} }
for (i=2; i>=0; i--) { for (i=2; i>=0; i--) {
......
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