/*********************************************************\
*  AVR MegaSquirt - 2003                                  *
*  (C) 2003 [Michael Kristensen, mik@caffrey.dk]          *
***********************************************************
*  -- History --                                          *
*    release 0.1 - 06-03-2003                             *
*            http://caffrey.dk/megasquirt                 *
*    initial Motorola version by Bowling & Grippo (2002)  *
*            http://www.bgsoflex.com/megasquirt.html      *
\*********************************************************/

// Type declarations global to everything

#ifndef GLOBAL_H
#define GLOBAL_H

#include <inttypes.h>
#include <avr/pgmspace.h>

// EXTERN will diminish in vems.c and used as extern in other files
#define EXTERN extern
typedef uint16_t psize_t;

/* special hardware is defined in my_make (see doc/)
*/
#ifdef GENBOARDv3
#define KNOCK_8101  // knock: yes, please
#define MCP3208

#ifndef BOOSTCONTROL_LINES
// default is to compile with BOOSTCONTROL unless BOOSTCONTROL_LINES=0 is in my_make
// actually "one-gear" boostcontrol:
#define BOOSTCONTROL_LINES 1
#endif

#if(BOOSTCONTROL_LINES > 0)
#define BOOSTCONTROL // convenience define, use this to check if BOOSTCONTROL is needed
#endif

#define HWMAP
#include "hwdef_v3.h"
#else

#ifndef BOOSTCONTROL_LINES
// default is to compile with BOOSTCONTROL unless BOOSTCONTROL_LINES=0 is in my_make
// actually "one-gear" boostcontrol:
#define BOOSTCONTROL_LINES 1
#endif

#if(BOOSTCONTROL_LINES > 0)
#define BOOSTCONTROL // convenience define, use this to check if BOOSTCONTROL is needed
#endif

#define HWMAP
#include "hwdef_v2.h"
#endif

#ifndef true 
#define true 1
#endif

#ifndef false
#define false 0
#endif

#include "ve.h"

/***********************************************************************/
//flags
// #define tenth_second 0
#define second       1

// the high resolution now and now_upper (16+16 bits) is in eventqueue
struct time_t {
// these are clocked from handler2k:
//  uint8_t iac_clk;
  uint8_t adc_clk;	
//  uint8_t tsec_clk; // 100 ms clock
//  uint16_t h2k;   // h2khandler counter (800 usec) is in benchstats. Move here if you need it.
// these are clocked from userspace:
  uint8_t tsec;  // seconds /10
  uint16_t sec;  // seconds
// written from both userspace(use cli-sei!) and interrupt.
  uint8_t flags; 
};

// rtc is not volatile any longer. Some fields are only set and beeing watched
// from userspace (like flags and most); adc_clk only from handler2k()
extern struct time_t rtc;
/***********************************************************************/

#define enabled   0 // squirt
#define scheduled 1 // sched
#define firing    2 // firing

struct squirt_t {
	uint16_t pwcalc;    // pulsewidth in 4 usec resolution
#ifndef GENBOARDv3
	uint8_t pwm_dc;    // pwm duty cycle (injpwm)
#endif
	uint16_t pwm_delay;	// delay (4 usec) before going to pwm-mode (injpwmt) SHOULD depend on Vbatt
	uint16_t stopat;	// when to stop (4 usec time)
};

// volatile dropped, interrupt will reload the values anyway
#ifdef GENBOARDv3
#define INJECTORS 8
#else
#define INJECTORS 2
#endif

// this should move to somewhere to config
#ifdef INJECTOR_STAGING
#ifndef SECONDARY_INJ_CHANNELS_NUM
#define SECONDARY_INJ_CHANNELS_NUM 4 // Default quantity of second-stage injectors
#endif
#endif

#ifdef SOFTRPM
#ifdef NOIGN
#error "Soft RPM limiters need to use ignition, please undefine NOIGN"
#endif
#define IGNCUTLVL_MAX 16
#endif


extern struct squirt_t inj_port[INJECTORS];

/***********************************************************************/

//status
#define running 0  // engine running
#define crank   1  // cranking
#define startw  2  // start warmup enrichment
#define warmup  3  // warmup
#define tpsaen  4  // tps acceleration
#define tpsden  5  // tps deceleration
//#define mapaen  6  // map acceleration
#define idle    7  // idle mode

//status_ext
#define new_rpm          0  // need for recalculation of rpm
#define baro_problem     1  // somehow the barometric pressure is way off
#define o2_not_ready     2  // this is set for the first 30 seconds
#define o2_closed_loop   3  // enabled when o2 sensor is active
#define crank_enable     4  // allowed to enter crank mode
#define als_active	     5  // antilagsystem is active
#define launch_active    6  // launch control is active
#define individual_allowed 7 // MegaTune flags to allow individual power recalc

#define is_als_active() (engine.status_ext & _BV( als_active ))

//status_trig
#define engine_in_sync   0
// #define wheel_in_sync    1  // check etime.tooth_cnt
#define DWELL_SCHEDULED  1

#define wheel_error      2  // error during wheel decoding
#define cam_sync         3	// for timing.c cam_trigger_sync()
#define cam_sync2		 4	// for dispatcher.c disp_igndeact()
#define ign_evnt_drp	 5  // signal that one event has been dropped
#define cam_sync3	 6	// for multitooth.c
#define SPARK_SCHEDULED  7

#define cam_sync_mask  ( _BV(cam_sync) | _BV(cam_sync2)  | _BV(cam_sync3) )

struct engine_t {
  uint8_t status;      // uses the defines above
  uint8_t status_ext;  // uses the defines below the above! TODO: changed from interrupt too ??
  uint8_t status_trig; // trigger status
  uint8_t batt;			// current battery voltage
  uint16_t kpa250;		// MAP value in units of 250Pa (note: the "k" in kpa is historical) 
  uint8_t coolant;     // Coolant temperature in Degrees F plus 40 (allows -40 degress to fit in integer)
  uint8_t mat;         // manifold air temperature
  uint16_t egt;			// Exhaust gas temperature
  uint8_t tps;         // throttle posision (0..255)
  uint8_t last_tok;    // same as tps, or MAP value in units of KPa, last reading
  uint32_t rpm_period; // rpm period (in 4 usec resolution)
  uint8_t rpm;         // computed engine rpm/100 (stupid origins in motorola megasquirt, comm compatibility likes this)
  uint8_t kpa_tps_blend; // engine_kpa_tps_blend8 result for SD/AlphaN mode 
  uint16_t rpm_vhr;		// computed very high res RPM (real RPM, like 8000)
  uint8_t alien_ignadv;  // measured ignition advance (toothwheel + coil trigger)
  uint8_t alien_dwell;  // measured ignition dwell
  uint16_t sparkat;	// absolute time when (appr) spark will come. Set at ign_act(). [4usuc]
#ifdef ALS
  uint8_t als_countdown; // countdown every sec. ALS disabled when reaches 0
#endif
#ifndef NOIGN
  uint16_t ignadv;	// ignition advance + IGN_BALANCE (0.25 crankdeg)
  uint32_t cam_period; // cam period (in 4 usec resolution)
	uint8_t ignum;	// http://tiki.vems.hu/tiki/tiki-index.php?page=IgnitionTiming
	uint16_t dwell;		// in 4 usec resolution. (This could be 64 usec resolution and uint8_t?)
	uint16_t trig2spark;	// time from trigger to spark [4 usec] (NOT rpm_period * trig2spark / 4096 !)
	uint16_t proposed_trig2spark; // 4 usec (not angle "factor" like earlier)
	uint8_t spark_phase;	// actually toothcnt relative to the reference tooth for given cyl
	uint8_t proposed_spark_phase;
	uint8_t dwell_phase;
	uint8_t proposed_dwell_phase;
	uint16_t trig2dwell;	// time from trigger to dwell [4 usec]
	uint16_t proposed_trig2dwell;  // 4 usec
//  uint16_t trig2inject;	// time from trigger to injection start = rpm_period * trig2inject / 4096
#ifdef SOFTRPM
  uint8_t randomseed;	// random seed for soft rpm limiter
  uint8_t sparkcutlvl;  // spark cut level 0..16
#endif  
#endif
  uint8_t injector_bitmask; // bitmask used when firing all injectors simultaneously
  uint8_t shiftcut_state;	// only changed from userspace;
  // lower 2 bit is state; bit7:2 are flags. See below.

#ifdef BOOSTCONTROL
	uint16_t boost_stopat;	// store the time of boostcontrol actuation event
	uint16_t boost_ref_dc;       // (0 .. 255) << 3 means 0 to 100%
 // linear interpolated (according to RPM), but not downscaled according to tps:
	uint8_t boostmax_target;
	uint8_t boost_command_duty; // 0 .. 255 means 0 to 100%
#endif
	uint8_t strig_count;	// incremented by SECONDARY_TRIGGER
	uint8_t individual_power; // filled by flag_rpm();
};

// engine.shiftcut_state bit1:0 state definitions
// (don't change these unless you review all usage of shiftcut_state)
#define SHIFTCUT_STATE_NEGLECTNOISE 0
#define SHIFTCUT_STATE_INACTIVE 1
#define SHIFTCUT_STATE_ACTIVE 2
#define SHIFTCUT_STATE_ARMED 3

// engine.shiftcut_state bit7:2 bits:
#define FUELCUT_SHIFTCUT 7
// if any of these bits are set (by independent sources), we need fuelcut:
#define FUELCUT_MASK 0x80

// above shiftcut RPM threshold we set this to 1:
#define ABOVE_SHIFTCUTRPM_THRESH 6
#define IGNCUT_SHIFTCUT 2
#define IGNCUT_REVCUT 3
// if any of these bits are set (by independent sources), we need igncut:
#define IGNCUT_MASK 0x0c

extern volatile struct engine_t engine;

// I know these should be elsewhere ... feel free to cleanup
static inline void updateDwellPhaseFromProposal(void)
{
	engine.dwell_phase = engine.proposed_dwell_phase;
	engine.trig2dwell = engine.proposed_trig2dwell;
}

static inline void updateSparkPhaseFromProposal(void)
{
	engine.spark_phase = engine.proposed_spark_phase;
	engine.trig2spark = engine.proposed_trig2spark;
}


#define INVALID_TRIGGER_TOOTH 0x80
    /**
     * @return index of next coil to be fired (ignum upper bits)
     */
static inline uint8_t get_ignumsc(void){
        return  (engine.ignum>>4);
}
    
static inline uint8_t get_ignumdc(void){
        return (engine.ignum & 0xF);
}
    
static inline void set_ignumsc(uint8_t newval){
        engine.ignum = (engine.ignum & 0xF ) | (newval << 4 );
}
    
static inline void set_ignumdc(uint8_t newval){
	engine.ignum = (engine.ignum & 0xF0) | newval;   
}
    
// reset both set_ignumdc() and set_ignumsc()
static inline void reset_ignum(uint8_t newval){
	// TODO: should we check if isCoilActive() ?
	engine.ignum = (newval << 4)| newval;   
}
    
static inline uint8_t isCoilActive(void)
{     
        return (get_ignumsc() == get_ignumdc()) ? 0 : 1;        
}
// if( ! isCoilActive() ) ... engine.ignum = 0;
static inline void reset_ignum_if_inactive( void )
{
	uint8_t ei, t8;

	ei = engine.ignum;
	t8 = ei >> 4;
	ei &= 0x0F;
	ei ^= t8; // check with XOR if upper and lower nibble matches
	if( ei == 0 ){ // they matched => isCoilActive() == false
		engine.ignum = 0;
	}
}

#define AUDITRIGGER_NEVER_THISHIGH 0x8F
static inline uint8_t add_modulo(uint8_t a, uint8_t b, uint8_t total_tooth)
{
        uint8_t ret = a + b;
		/*
        if( ret >= AUDITRIGGER_NEVER_THISHIGH ){
		// >143: negative because of underflow;
		// note that up to 135 (or even 142) is perfect with AUDITRIGGER 
		ret += total_tooth;	
		return ret;
        }*/
		
        if( ret >= total_tooth ){
        	ret -= total_tooth;
        }
        return ret;
}

    /**
     * True, if toothcnt is same as searchedtooth, or just follows, like
     * toothcnt == searchedtooth +1
	* examples:
     * searchedtooth toothcnt 
     * 0    1
     * 1    2
     * ...
     * 12   13
     * 13   15 YES, must be allowed, and possible
     * 15   16
     * 28    0  toothcount overflow, allowed
	* 57	 60 when total_tooth==120
	* 57	0
     * 14   15 Special, missing tooth14 should have been avoided !
     * @param allowedtooth
     * @param toothcnt
     * @return true if allowedtooth == toothcnt

	TODO: WHY THE FUCK WOULD WE NEED to allow toothcnt one later than searchedtooth?
	From multitooth.c, a condition for exact match is better
     
static inline uint8_t appr_same(uint8_t searchedtooth, uint8_t toothcnt, uint8_t total_tooth)
{
	int8_t allowedtooth = searchedtooth - toothcnt;
        if( allowedtooth <= 0 ){ // nice, there it is
            if( allowedtooth >= -3 ){ // -2 for N-1; -3 for 60-2
                return 1;
            }
        }
        
        // toothcnt overflowed to 0: like 57 - 0
	// TODO: review. With 15-1 and searchedtooth=27 (or 28), toothcnt=0 will fire FAKE !
	// This might not be a problem, since it already fired at 27 (or 28),
	// (at very worst we get a latefire anyway) and did step_ignumsc() step_ignumdc()
        if( allowedtooth >= (total_tooth - 3)){
                return 1;
        }
        return 0;
}
*/

// prefer access via macros for future flexibility
#define engine_tps255() engine.tps

// max value of engine.rpm_trigger_reenable

#define engine_rpm8() engine.rpm

#define engine_tps8() engine.tps


#define engine_rpm8() engine.rpm

#define engine_tps8() engine.tps

#define TRIGGER_REENABLE_MAX 5000   // 5000*4us = 20.0 ms

/***********************************************************************/

// define the adc sampling period [divisor from 1250Hz]
// THIS SHOULD MATCH H2KDIVIDE in eventqueue.h (maybe make it automatic?)
#define ADC_PERIOD  6

// TIMER3 TOP=1023. TIMER1 could use the same TOP value,
// but a little different value might be nice on the supply.
// The same frequency and artificial offset between TCNT3 and TCNT1 might be the best?
// PWM_FREQUENCY = 16MHz / 15.984kHz - 1
#define PWM_FREQUENCY   1000

// n-1 seconds after leaving crankmode we can't reenter (unless rpm drops to 0)
#define CRANK_TIMEOUT 11

// tps threshold
#define FLOOD_CLEAR 155

// these should teoretically make it harder to make stupid bugs!
#define COLD_TEMP 0     // -40 F == -40 C
#define WARM_TEMP 205   // 165 F == 74 C (assume the engine is warm at this temperature)


// calculation from battcal calibrated 'real' vbat ( batADC = vbat / 30 * 255 )
#define BATT_6V 51
#define BATT_7V 60
#define BATT_14V 119
#define BATT_19V 162


/***********************************************************************/
/* Configuration variables */
/***********************************************************************/

// DO NOT PUT IFDEFS here unless you teach stru.pl to parse my_make
// Otherwise magicstr will be offsetted, and you will have a bad day. You have been warned.
struct config_t {
  // F1
  uint8_t primep;               // Priming pulse at -40 F [100 usec]
  uint8_t primep_temp_scaling;  // Priming pulse scaling at 170 F (80=half, ff=same as cold)

  uint8_t cwl;            // Cranking pulsewidth [100 usec] at -40 F
  uint8_t cwh;            // Cranking pulsewidth [100 usec] at 170 F
  uint8_t cranking_thres; // Cranking threshold [100 rpm]

  uint8_t awev;         // Afterstart warmup enrichment (percent, added value)
  uint8_t awev_temp_scaling; // Afterstart warmup scaling at 170F (80=half, ff=same as cold)
  uint8_t awec;          // Afterstart time (6 crankrev)

  // F2
  uint8_t warmup_clt_range[10];  // Warmup temperature range of bins (+40 F offset)
  uint8_t warmup_clt[10];        // Warmup enrichment bins(fn temp), biased at 100
  uint8_t warmup_rpm_scale;	// Warmup enrichment scaler at highest rpm bin: FF=rpm independent

  // F3
  uint8_t req_fuel;     // Fuel constant (req_fuel)
  uint8_t divider;      // IRQ divide factor for pulse
  uint8_t alternate;    // Alternate injector drivers, bit4 1:batch fire when cranking
  uint8_t injopen;      // Injector open time at 13.2V [16 usec]
  uint8_t battfac;      // Battery gamma factor [16 usec based]
  uint8_t kpafac;	// MAP range [2kPa] 0: use A/B lookup table
  uint8_t kpaoffs;	// MAP signal offset eg.0xA8 -32..+32kPa [250Pa]
  uint8_t injocfuel;    // injector opening effective rampup time [24 usec]
  uint8_t injrampup_battfac; // injector rampup slope battery dependence (FF)
  uint8_t injpwm;       // Injector PWM duty cycle (when current limiting is active)
  uint8_t injpwmt;      // Injector PWM time at which to activate pwm [100 usec]
  uint8_t als_launch_input;	// ALS and launch activation input channel

  uint8_t rpmk[2];      // Constant for calculating, rpm = 12,000/ncyl (0: high byte)

  // F4
  uint8_t tpsdot_kpadot_conf;  // 0: TPSDOT, 1: MAPDOT acceleration enrichment
  uint8_t tpsdotrate[4];  // TPS/MAPDOT acceleration bins, dv/dt
  uint8_t tpsaq[4];       // TPS/MAPDOT acceleration amount (fn TPSDOT) [100 usec]
  
  uint8_t als_cut_mintps;   // ALS cut mintps
  uint8_t tpsasync;     // Acceleration duration [0.1 sec]
  uint8_t acmult;       // Acceleration cold multiplication factor, biased at 100
  uint8_t tpsacold;     // Cold acceleration added amount (at -40 F degrees) [100 usec]
  
  uint8_t launch_enrich;   // launch, fuel enrichment [0.4%]
  uint8_t launch_retard;  // launch, fixed ign. retard [1/4 crankdeg]

  uint8_t overrun_fuelcut;        // Overrun fuelcut, injectors disabled above this [100 rpm]
  uint8_t overrun_fuelresume;     // Overrun fuelresume, injectors reenabled below this [100 rpm]

  uint8_t rev_limit;      // Rev limit (hard) [100 rpm]

  // F5
  uint8_t airden_ignore;  // Fake airdensity low limit (low rpm only), 0==disable

  uint8_t config11;     // c11, bit7-4:ncyl-1 
  uint8_t config12;     // not used
  uint8_t config13;     // c13, bit3:baro bit2:no load multiplication for fuel strategy bit1:WBO2 bit0:oddfire

  uint8_t batt_cal;	// VBatt calibration appr.BC=default
  uint8_t fastidle;     // Fastidle valve off above this Temp[..F-40]

  uint8_t als_max_cut;    // ALS max cut
  uint8_t dbaro;          // max difference in barometric pressure

  uint8_t tps_low;        // tps, min adc-count
  uint8_t tps_high;       // tps, max adc-count

  uint8_t fan_temp;       // coolant fan, start temperature
  uint8_t fan_hyst;       // coolant fan, hysteresis
  uint8_t fan_channel;	  // coolant fan, output selection
  
  // IAC stuff F6
  uint8_t iac_step_seq;        // iac, stepping sequence (define iac wiring)
  uint8_t iac_conf;            // iac, bit7:softidle bit6:asym bit5:dualsol bit4=1:ignadv ON, bit3:preciseidle bit2:stepper(0=pwm) bit1:tps_follow bit0:power_iac_only_when_move
  uint8_t iac_max_steps;       // iac, max steps to extend
  uint8_t iac_tps_thres;       // iac, engine.tps value for idle threshold
  uint8_t iac_cold_idle_temp;  // iac, max temperature for cold idle speed
  uint8_t iac_warm_idle_temp;  // iac, min temperature for warm idle speed
  uint8_t iac_cold_rpm;        // iac, idle rpm (cold) [10 rpm]
  uint8_t iac_warm_rpm;        // iac, idle rpm (warm) [10 rpm]
  uint8_t iac_cold_start_pos;  // iac, crank position at -40 F
  uint8_t iac_warm_start_pos;  // iac, crank position at 170 F
  uint8_t iac_afterstart_rpm;  // iac, afterstart rpm [10 rpm], added to idle rpm
  uint8_t iac_afterstart_duration; // iac, duration of afterstart rpm [0.1 sec]
  uint8_t iac_speed; 		// iac, actuator 1/frequency [msec] (pwm/stepper:+4/+1)
  uint8_t iac_kp;              // iac, P-term
  uint8_t iac_ki;              // iac, I-term
  uint8_t iac_kd;              // iac, D-term
  uint8_t launch_rpm;  // Launch RPM [100 RPM]
  uint8_t iac_integral_limit_dec;  // iac, integral decrease limit
  uint8_t iac_integral_limit_inc;  // iac, integral increase limit
  uint8_t iac_integral_deadband; // iac, integral deadband [1 rpm] (being tested for usefulness)
  uint8_t iac_deadband;        // iac, deadband [1 rpm]
  uint8_t als_cut_maxtps;        // iac, cut maxtps
  uint8_t iac_overclose_interval;  // iac, seconds between overclosing
  uint8_t iac_ref_pos[10];     // iac, reference position (fn temp)
  uint8_t iac_sol_channel;	// iac output channel
  uint8_t iac_ign_slope; // iac, ignition advance [0.25deg/256rpm]
  uint8_t softrpm_range;  // Ignition SoftRPM range [4 RPM]
  uint8_t iac_ign_advance_limit;  // iac, ignition advance limit [0.25deg] 
  uint8_t iac_ign_retard_limit;   // iac, ignition retard limit [0.25deg]
  uint8_t iac_ign_threshold;      // iac, threshold for activating air control [0.25deg]

  // ego controller F7
  uint8_t ego_conf;        // ego, bit5:NBO2_adc7 bit0:PID  

  uint8_t ego_lag;         // ego, timeconstant (engine cycles) for changing correction factor
  uint8_t ego_coolant;     // ego, min coolant temperature for ego enabling[F]
  uint8_t ego_maxtps;      // ego, max tps position for ego correction
  uint8_t ego_maxmap;      // ego, max map for O2 correction[kPa]
  uint8_t ego_minrpm;      // ego, min rpm for ego enabling [100rpm]
  uint8_t ego_maxrpm;      // ego, max rpm for O2 correction [100rpm]
  uint8_t ego_warmup;      // ego, warmup time [sec]
  uint8_t ego_lean_limit;  // ego, max percent to lean afr[0.4%](in SINGLE_TARGET mode rich too)
  uint8_t ego_rich_limit;  // ego, max percent to rich afr[0.4%]

	// note that NBO2 EGO PID reuses all the 5 values below
  uint8_t ego_pid_kp;      // ego, incredible speed limit (or pid kp)
  uint8_t als_enrich;	// ALS enrichment
  uint8_t ego_delta;       // ego, step size (percent) [0.4%]
  uint8_t ego_target;      // ego, target voltage (NBO2)
  uint8_t ego_pid_window;  // ego, minimum window for pid to react

  // WBO2 F8
  // heater:
  uint8_t wbo2_warmup_ramp;     // wbo2, warmup ramp speed [3f=0.2V/sec]
  uint8_t als_react_tps;   // ALS tps threshold
  uint8_t wbo2_abs_limit;	// wbo2, heater absolute limit [2a=12V ff=30V]
  uint8_t wbo2_limit_maxt;     // wbo2, max time spent at abs_limit [262msec]
  uint8_t wbo2_fallback;     // wbo2, fallback V after maxt [1c=10V ff=30V]
  uint8_t wbo2_retry_t;     // wbo2, retry control after [4sec]

  uint8_t als_retard_rpm1;	// ALS, retard RPM1 [100 rpm] 
  uint8_t als_retard_rpm2;	// ALS, retard RPM2 [100 rpm]
  uint8_t wbo2_ri_target;	// wbo2, target Ri (pulse amplitude:C3)[5V/4096]
  uint8_t wbo2_nernstdc_target; // wbo2, target nernstDC [5V/256]
  uint8_t wbo2_pump_pw_zero;    // wbo2, pump zero dutycycle (default: 66) [5V/256]
  uint8_t wbo2_calibration;     // wbo2, calibration constant
  uint8_t wbo2_heater_pid_kp;   // wbo2, heater pid kp
  uint8_t wbo2_heater_pid_ki;   // wbo2, heater pid ki
  uint8_t wbo2_heater_pid_kd;   // wbo2, heater pid kd
  uint8_t wbo2_heater_pid_ilimit;   // wbo2, heater pid integral limit

  uint8_t wbo2_pump_pid_kp;   // wbo2, pump pid kp
  uint8_t wbo2_pump_pid_ki;   // wbo2, pump pid ki
  uint8_t wbo2_pump_pid_kd;   // wbo2, pump pid kd
  uint8_t wbo2_pump_pid_ilimit;   // wbo2, pump pid integral limit

  uint8_t wbo2_ri_confidence_scale;  // wbo2, Ri confidence scaling factor (s^2 < 255/scale)

  // Knock sampling F9
  uint8_t knock_chan;		// knock channel for each cyl; F0=disable
  uint8_t knock_sampling_window;   // knock, sampling window [4 degree] length:start(ATDC)

  uint8_t knock1_frequency;    // knock1, bandpass center frequency
  uint8_t knock1_gain;        // knock1, gain
  uint8_t knock1_integrator;  // knock1, integration time constant

  uint8_t knock2_frequency;    // knock2, bandpass center frequency
  uint8_t knock2_gain;        // knock2, gain
  uint8_t knock2_integrator;  // knock2, integration time constant

  // Knock action
  uint8_t knock_threshold;       // knock, threshold
  uint8_t knock_noise_scale;     // knock, noise scale factor
  uint8_t knock_max_retard;      // knock, max ignition retard [1/4 degree]
  uint8_t knock_default_retard;  // knock, default ignition retard [1/4 degree]
  uint8_t knock_retard_step;     // knock, ignition retard step [1/4 degree]
  uint8_t knock_retard_delay;    // knock, ignition retard delay [15ms]
  uint8_t knock_advance_step;    // knock, ignition advance step [1/4 degree]
  uint8_t knock_advance_delay;   // knock, ignition advance delay [15ms]
  uint8_t knock_minrpm;          // knock, min rpm [100rpm]
  uint8_t knock_maxrpm;          // knock, max rpm [100rpm]

  // VE learning stuff F10
  uint8_t ve_learn_coolant;      // VE learn, min coolant for auto modification of VE entries
  uint8_t ve_learn_max_power;    // VE learn, auto modification of VE entry only below power=map*rpm/256
  uint8_t ve_learn_rpm_scale;    // VE learn, rpm scaling factor (s^2 < 255/scale)
  uint8_t ve_learn_kpa_scale;    // VE learn, kpa scaling factor (s^2 < 255/scale)
  uint8_t ve_learn_ego_scale;    // VE learn, ego scaling factor (s^2 < 255/scale)
  uint8_t ve_learn_min_weight;   // VE learn, minimum weight for modifying VE entry
  uint8_t ve_learn_speed;        // VE learn, speed of changes to the VE table
  uint8_t ve_learn_limit;        // VE learn, max deviation (+/- [0.4%]) from reference VE table
  uint8_t ve_learn_conf;         // VE learn, config, bit0:enable bit1:simulate bit2: 2x2box

  uint8_t lcd_c0;		 // LCD flags 5: sw brightness 4: pwm brightness 3:reinit 1:lcd_easygoto 0:busypolled 
  uint8_t lcd_delay;		 // LCD-cablelength delays Higherhalf:beforeENable LowerHalf:ENable
  uint8_t lcd_backlight;	 // LCD backlight: FF is fully on
  
  uint8_t kpa_conf;		 // bit7-4: kpafac_unit, bit3-0: kpa_config_resolution
  uint8_t als_igncut_rpm2;	 // ALS igncut RPM2 [100 rpm]
  uint8_t als_retard_mintps;	// ALS retard mintps[0.4%]
  uint8_t als_retard_maxtps;	// ALS retard maxtps[0.4%]

  uint8_t lcd_default_view;      // LCD, default runtime view
  
  // F11
  uint8_t primary_trigger;      // trigger1, bit0 0:falling/1:rising, bit1 0:missingtooth/1:coil, bit2=1:filtering, bit3:advanced multitooth, bit4:missing N-1, bit5:FiatStilo, bit6:AudiTrigger135+ bit7:audionly 0=divideby3, 1=divideby2
  uint8_t secondary_trigger;    // trigger2, bit0 0:falling/1:rising, bit1 0:enable/1:disable, bit2 1:filtering, bit3 0:toothwheel/1:coil, bit4 0:alien advance/1:cam sync, bit5 1:both edge at cranking bit6:fiatstilo

  uint8_t tooth_wheel;          // tooth wheel, number of teeth on the wheel
  uint8_t trigger_tooth;        // tooth wheel, active trigger tooth (00:missing tooth)
  uint8_t another_trigger_tooth; // tooth wheel, define another trigger tooth
  uint8_t crank_minper;		// Cranktigger period minimum (*16 usec)

  uint8_t tooth_wheel_twidth1;         // toothwidth [0.25 crankdeg], lower byte
  uint8_t tooth_wheel_twidth2;         // toothwidth [0.25 crankdeg], upper byte

  uint8_t cam_sync_r_edge_phase;      // cam sync, rising edge, engine phase at next primary trigger
  uint8_t cam_sync_f_edge_phase;      // cam sync, falling edge, engine phase at next primary trigger

  uint8_t reset_engphase_after; // not used

  uint8_t ign_tdcdelay;		// TDC after the trigger(0.5crankdeg)
  uint8_t ign_dwell14;		// dwell above 14V (64usec)
  uint8_t ign_dwell6;		// added dwell time at 6V (27usec)
  uint8_t ign_crank_advance;    // ignition advance at cranking [0.25crankdeg]
  // developer bit-definition of ign_out:
  // 7:disable, 6:EDIS/dummy, 5:after/before, 4:ref_to_trigger/ref_to_spark 3:multispark 1: ign_dual_out
  // EDIS bits will be	0000...?
  // dummy-ign bits are:0111...?
  // disable ign:		1111....
  uint8_t ign_out;	// EDIS:0x0? dummy: 0x7? disable:0xff bit1: ign_dual_out bit0: invertout
  uint8_t ignchmax;  // h[2] maxindex for ignition channel lookup

  // Fuelpump section:
  uint8_t engine_off_delay;		// turn off fuelpump after inactivity time [262msec]
  uint8_t pump_on_mintime;		// minimum time to leave fuelpump on at startup [262msec]
  uint8_t fuelpump_channel;		// fuelpump output channel
  
  // Injector staging section F12
  uint8_t inj_stage2_rate;		// secondary injectors rate to calculated pw [0.4%]
  uint8_t inj_stage2_start_tps;		// secondary injectors open above given throttle
  uint8_t inj_stage2_start_map;		// secondary injectors open above given manifold pressure
  
  // AntiLagSystem section
  uint8_t als_igncut_rpm1;		// als igncut RPM1 [100 rpm]
  uint8_t als_deact_time;		// als,switchoff time [sec]
  uint8_t als_deact_egt;		// als,switchoff egt [5 deg celsius]
  uint8_t als_retard;			// als,max ign. retard [1/2 crankdeg]
  uint8_t als_rev_limit;        // Rev limit when ALS active [100 rpm]
  
  // Misc power outputs
  uint8_t misc1out_minrpm;		// misc1out,minimum rpm [100 rpm]
  uint8_t misc1out_maxrpm;		// misc1out,maximum rpm [100 rpm]
  uint8_t misc1out_mintps;		// misc1out,minimum tps position
  uint8_t misc1out_maxtps;		// misc1out,maximum tps position
  uint8_t misc1out_minmap;		// misc1out,minimum manifold pressure
  uint8_t misc1out_maxmap;		// misc1out,maximum manifold pressure
  uint8_t misc1out_channel;		// misc1out,output channel selector

  // Misc power outputs
  uint8_t misc2out_minrpm;		// misc2out,minimum rpm [100 rpm]
  uint8_t misc2out_maxrpm;		// misc2out,maximum rpm [100 rpm]
  uint8_t misc2out_mintps;		// misc2out,minimum tps position
  uint8_t misc2out_maxtps;		// misc2out,maximum tps position
  uint8_t misc2out_minmap;		// misc2out,minimum manifold pressure
  uint8_t misc2out_maxmap;		// misc2out,maximum manifold pressure
  uint8_t misc2out_channel;		// misc2out,output channel selector

  uint8_t act_wot_rpm;		// WOT switch RPM threshold (FF=disable)
  uint8_t act_wot_channel;	// WOT switch output channel
  uint8_t act_rpm_rpm;		// RPM switch RPM threshold (FF=disable)
  uint8_t act_rpm_channel;	// RPM switch output channel
  uint8_t egt1_cal;			// EGT calibration multiplier
  uint8_t als_tks_channel;		// ALS TKS output channel 
  uint8_t boost_conf;	// boostcontrol bit7:4 PWM period [8msec]; bit3:2 refpos; bit1:SIMPLE, bit0 0:boosttarget,1:MAPtarget; 00=disabled
  uint8_t boost_targetoffs;	// boostcontrol target offset applied after b[RPM]*t[TPS]
  uint8_t boost_minpressure;	// actuator OFF below this pressure
  uint8_t boost_pid_kp;   // boostcontrol pid kp
  uint8_t boost_pid_ki;   // boostcontrol pid ki
  uint8_t boost_pid_kd;   // boostcontrol pid kd; reused by simpleboost; see booscontrol.h
  uint8_t boost_pid_ilimit;   // boostcontrol pid integral limit
  
  uint8_t boost_channel;	// boostcontrol solenoid output channel

  // water pump control
  uint8_t water_pump_temp;	// water pump, start temperature
   
  uint8_t hybrid_rpm_a;		// VE mode:alpha-n (TPS) below [*100] RPM 
  uint8_t hybrid_rpm_m;		// VE mode:speed density (MAP) above [*100] RPM 
  uint8_t water_pump_hyst;	// water pump, hysteresis
  uint8_t water_pump_channel;	// water pump, output channel

  uint8_t toothrel_normal;	// Nn: tg_prev * n/16 <= tg <= tg_prev * (1+N/16)
  uint8_t toothrel_missing;	// Mm: tg_prev * (1.25 + m/8) <= tg <= tg_prev * (2.5 + M/8)

  // fuelcuts
  uint8_t fuelcut_min_kpa;	// fuelcut below this MAP (00:disable; 10 recommended)
  uint8_t fuelcut_max_kpa;	// cut the fuel if the engine kpa exceeds this value 0xFF=disable (even if selecting alpha-n)

  // tach output control
  uint8_t tach_channel;         // tach signal output channel FF=disabled
  uint8_t tach_div;      	// divide the tach freq by X/32; use FF if not using
  
  // full power shift cut variables
  uint8_t shiftcut_conf;		// bit4:shiftcut fuel, bit1:shiftcut spark bit0:revcut spark
  uint8_t shiftcut_channel;		// shiftcut mcp3208 channel, disable:FF
  uint8_t shiftcut_time; 		// igncut time after inputpulse [4 msec]
  uint8_t softrpm_rpm;		// Ign Softrpm RPM [100 RPM]
};

extern struct config_t config;

#ifndef KPA_CONFIG_RESOLUTION
#define KPA_CONFIG_RESOLUTION (config.kpa_conf & 0x0F)
#endif

#ifndef KPAFAC_UNIT
#define KPAFAC_UNIT ((config.kpa_conf & 0xF0) >> 4)
#endif

// k: pressure [0.25 kPa] (400 at 100kPa)
static inline uint8_t engine_kpa8_of(uint16_t k)
{
	uint8_t ret;
	if(KPA_CONFIG_RESOLUTION==2){
		// high-boost (50 at 100kPa)
		ret = ( k >= 255*8 ) ? 255 : k>>3;
	} else { // standard, low-boost: KPA_CONFIG_RESOLUTION==1
		// (100 at 100kPa)
		ret = ( k >= 255*4 ) ? 255 : k>>2;
	}
	return ret;
}

/* returns MAP in [1 or 2 kPa] unit, railed to max 255 */
static inline uint8_t engine_kpa8(void)
{
	return engine_kpa8_of( engine.kpa250 );
}

#ifndef IGN_BALANCE
#ifdef ALS
// 0.25 crankdeg resolution: 64 degree is fine
#define IGN_BALANCE 256
#else
#define IGN_BALANCE 0
#endif
#endif

#define config_iac_ignsoftidle() (config.iac_conf & _BV(7))
#define config_iac_pid_asymetric() (config.iac_conf & _BV(6))

// freeing config.baro:
#define config_baro() (100)

#define config_egt1_offs() (0)

// Reusing config variables
#ifdef ALS
#define RV_als_enrich			config.als_enrich	// als,fuel enrichment [0.4%]
#define RV_als_retard_mintps	config.als_retard_mintps	// als,min TPS for delay spark
#define RV_als_retard_maxtps	config.als_retard_maxtps	// als,max TPS for delay spark
#define RV_als_cut_mintps		config.als_cut_mintps 	// als,min TPS for cut spark
#define RV_als_cut_maxtps		config.als_cut_maxtps	// als,max TPS for cut spark
#define RV_als_react_tps		config.als_react_tps	// als,reactivate TPS
#define RV_als_tks_output		config.als_tks_channel	// als,throttle kicker output channel
#define RV_als_max_cut			config.als_max_cut // als,maximum cut strength [0..16]

#define CONF_ALS_RETARD_RPM1 config.als_retard_rpm1
#define CONF_ALS_RETARD_RPM2 config.als_retard_rpm2
#define CONF_ALS_IGNCUT_RPM1 config.als_igncut_rpm1
#define CONF_ALS_IGNCUT_RPM2 config.als_igncut_rpm2

#endif

#ifdef SOFTIDLE
#ifndef SOFTRPM
#error "Define SOFTRPM to use softrpm based idle control!"
#endif
// Idle control by variable spark cut
// config.iac_conf bit 7 to enable
#define RV_softrpm_idle_tps		config.iac_tps_thres // idle,sparkcut,TPS treshold
#define RV_softrpm_idle_rpm		iac.target_rpm // idle RPM target [10 RPM]
// #define RV_softrpm_idle_range	50 // * 4 RPM = 200 RPM idle,sparkcut,RPM control range
#endif // SOFTIDLE

#ifdef SOFTREDLINE
// Soft rpm limiter (redline)
#ifndef SOFTRPM
#error "Define SOFTRPM to use softrpm based redline!"
#endif
#define RV_softrpm_rpm			config.softrpm_rpm  // redline,sparkcut,RPM treshold [100 RPM]
#define RV_softrpm_range		config.softrpm_range // redline,sparkcut,RPM range [4 RPM]
#endif // SOFTREDLINE

#ifdef SOFTLAUNCH
// Launch control by spark cut
#ifndef SOFTRPM
#error "Define SOFTRPM to use launch control!"
#endif
#define RV_launch_rpm			config.launch_rpm	// launch,sparkcut,RPM treshold [100 RPM]
#ifndef SOFTREDLINE
// Using redline's softrpm range, but can be used together
#define RV_softrpm_range		config.softrpm_range	// launch,sparkcut,RPM range [4 RPM]
#endif	// SOFTREDLINE
#endif  // SOFTLAUNCH


/***********************************************************************/
// config.shiftcut_conf
// 7..4 are fuelcut flags
// 0..3 are igncut flags
#define CUT_SPARK_REV 0
#define CUT_SPARK_SHIFT 1
#define CUT_FUEL_SHIFT 4 


//tpsdot_kpadot_conf
#define tps_or_kpa		0  // 0:tpsdot, 1:mapdot

/***********************************************************************/
// alternate
#define BATCH_FIRE_CRANKING 4 // 1:1:batch fire when cranking

/***********************************************************************/
//config11
//bit 7-4 =  number of cylinders-1
#define NCYL_1 ((config.config11 & 0xF0) >> 4);  // ncyl -1
#define NCYL ((config.config11 & 0xF0) >> 4) + 1;  // ncyl

/***********************************************************************/

//config12
// not used

/***********************************************************************/

//config13
#define ODDFIRE               0 // 0:normal, 1:odd-fire
#define O2_WB_SENSOR          1 // 0:narrowband, 1:diy-wb
#define CONTROL_STRATEGY      2 // 0:use the MAP or tps map blend for fuel calcs 1:do not use any multipliers
#define BARO_CORRECTION       3 // 0:off, 1:on
#define MAT_RETARD            4 // 0:on, 1:off
//bit 7-5 unused

#define WBO2_SENSOR_CONFIGURED (config.config13 & _BV(O2_WB_SENSOR))
/***********************************************************************/
// master_debug
#define mat2map        0    // reroute the mat sensor value to the map sensor value

/***********************************************************************/
// ve_conf
#define ve_learn_on    0   // enable the VE learning
#define ve_learn_sim   1   // only simulate VE learning
#define ve_learn_2x2   2   // modify all four elements

/***********************************************************************/
// lcd_c0
#define lcd_busypolled	0	// if 1, the busy flag is polled
#define lcd_easygoto	1 	// if 0, we force goto after each data
#define pwmbrightness	3	// if 1 then the lcd uses PWM to control brightness
#define swbrightness	4	// if 1 then the lcd allows software brightness commands (Noritake VFD)
/***********************************************************************/
// trigger1 primary_trigger
#define trigger_edge   0       // if 1, then rising edge
#define ptrig_coil     1       // if 1, then use coil to trigger instead of toothwheel
#define trigger_filter 2       // if 1, then filtering is enabled
#define trigger_multitooth_hairy 3	// if 1, then noise starts a new resync sequence
#define trigger_multitooth_Nminus1 4	// if 1, then N-1 wheel (0: N-2)
#define trigger_fiatstilo 5	// if 1, then Fiat Stilo style 60/90/30 degree trigger assumed
#define trigger_auditrigger 6	// if 1, then Audi 135+ tooth trigger style assumed
#define trigger_diveby2 7	// 0=divideby3, 1=divideby2

// trigger2
//#define trigger_edge   0       // if 1, then rising edge
#define strig_disable    1       // if 1, then secondary trigger is disabled
//#define trigger_filter 2       // if 1, then filtering is enabled
#define strig_coil       3       // if 1, then use coil to trigger instead of toothwheel
#define strig_cam_sync   4       // if 1, then enable cam sync, else measure alien ignition advance
#define strig_both_edges 5       // if 1, then cam sync on both edges during cranking
#define strig_fiatstilo  6       // if 1, then use fiatstilo camwheel

/***********************************************************************/
// knock_conf WAS: (now changed)
// #define knock_enable   0   // if 1, then enabled
// #define knock_chan     1   // if 1, then channel 1 else channel 0

/***********************************************************************/

// ign_out definitions:
#define IGN_DISABLE		(7)
#define IGN_DUMMYDWELL	(6)
// bit5=0 for CDI
#define IGN_BEFORE		(5)
#define IGN_REFSPARK	(4)
#define IGN_MULTISPARK	(3)
#define IGN_DUAL_OUT	(1)
#define IGN_INVERTOUT	(0)
// used combinations of upper nibble (7..4) bits:
#define IGNTYPE_EDIS	(0x00)
#define IGNTYPE_DUMMY	(0x70)
// the rest 14 combinations are off, but:
#define IGNTYPE_NONE	(0xF0)

// boost_conf definitions:
#define BOOSTTARGET	(0)
#define BOOSTSIMPLE (1)
#define boostsimple_configured  (config.boost_conf & _BV( BOOSTSIMPLE ))

#ifndef KPAFAC_UNIT
// 2 kPa is default
#define KPAFAC_UNIT (2)
#endif

// These two shouln't be _here_
void setleds(void);
extern volatile uint8_t ledstate;       // interrupt sets this, not port directly. port is written from userspace 

// should be in <avr/pgmspace.h> but it's missing from older avrlibc:

#ifndef pgm_read_byte
#define pgm_read_byte(a) (PRG_RDB((unsigned char*)(a)))
#endif

#ifndef PRG_RDB
#define PRG_RDB(x) pgm_read_byte(x)
#endif

#ifndef pgm_read_word
// TODO: this assumes little-endian: make it endian-safe
#define pgm_read_word(a) ((PRG_RDB((unsigned char*)(a)) & 0x00FF) | ((PRG_RDB((unsigned char*)(a)+1))<<8))
#endif

#ifndef pgm_read_word_near
#define pgm_read_word_near(a) pgm_read_word(a)
#endif

#ifndef pgm_read_addr
#define pgm_read_addr(a) pgm_read_word(a)
#endif

// deprecated. Use the ones from above:
#ifndef PRG_RDW 
#define PRG_RDW(x)  pgm_read_word(x)
#endif


#ifndef pointer_to_upper8_16
// hack, only suits little endian. TODO: avr-libc solution
#define pointer_to_upper8_16(x) ((uint8_t*)(x) + 1)
#define pointer_to_lower8_16(x) ((uint8_t*)(x))
#endif

extern const uint8_t BV_rev_arr[];

// similar to BV macro but reverse bitorder (0 => 0x80)
// extern uint8_t BV_rev_arr[] PROGMEM ; // = {0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1};
#define BV_rev(a) (pgm_read_byte(&BV_rev_arr[a]))
#define BV_rev_l(a) (pgm_read_byte(&BV_rev_arr[a&7]))

// macro for putting the code/variables into defined sections
#define SECTION(_sect) __attribute__((section(_sect)))

extern uint8_t individual_power[HWMAP_SIZE];

/**
 * Steps down, except after 0: than step back to ignchmax
 * @param ic
 * @return
 */
static inline uint8_t next_igncount(uint8_t i) {
	if( i == 0 ){
		return config.ignchmax;			
	} 
	return i - 1;
}

static inline void step_ignumsc(void){
        uint8_t idx = get_ignumsc();
        set_ignumsc( next_igncount(idx) );
	if( engine.status_ext & _BV(individual_allowed) ){
		individual_power[idx]= engine.individual_power;
	}
}
static inline void step_ignumdc(void){
        uint8_t idx = get_ignumdc();
	set_ignumdc( next_igncount(idx) );
}

/**
 returns the number of teeth, together with the missing.
 multiplied by 2 if camsync is used.
 15 - 1 with camsync : 30
 60 - 2 with camsync: 120
 60 - 2 without camsync: 60
 When ptrig_coil then it is understood that we have a reset on the secondary
 trigger and config.tooth_wheel is understood to be the number of teeth
 between resets (normally taken from the cam) in this case we don't need *2
 In the future, config.tooth_wheel will need to be set for coiltype as well ?
 TODO: rethink for AUDITRIGGER: 
 	135 * 2 modulo 256 ?
	or 142 * 2 modulo 256 (volvo 142 wheel) ?
*/
static inline uint8_t get_total_tooth(void)
{
	uint8_t cpt, t8 = config.tooth_wheel;
	cpt = config.primary_trigger;
	if( cpt & _BV(ptrig_coil) ) {
		// no <<= 1 (even with camsync!)
		return t8;
	}

	if( cpt & _BV(trigger_multitooth_Nminus1) ) {
		// N-1:
		t8 ++;
	} else { // N-2
		t8 += 2;
	}

	if ( config.secondary_trigger & _BV(strig_cam_sync) ){
		// camsync configured, so *2: t8 <<= 1; t8 += t8;
		t8 <<= 1;
	}

	return t8;
}

#endif	// GLOBAL_H


