uint8_t       encoder_1or2, encoders_conf;
uint32_t      encoder_mode[2];
int32_t       encoder_val[2];
const int8_t  encoder_deltas[16] =
    { 0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0 };

// the encoders function is called from EXTI_Int 0-3

int
encoders( int bit_enc )
{
  int           PC_b1b0;
  int           PC_b3b2;
  int           delta;
  int           result;

  switch ( encoder_1or2 )
  {
    case 0:
      PC_b1b0 = GPIOC->IDR & 3;
      if( encoders_conf & 1 )
      {
	delta = PC_b1b0 + 4 * encoder_mode[0];
	encoder_mode[0] = PC_b1b0;
	result = encoder_val[0] + encoder_deltas[delta];
	encoder_val[0] = result;
      }
      else
      {
	delta = PC_b1b0 + 4 * encoder_mode[0];
	encoder_mode[0] = PC_b1b0;
	result = encoder_val[0] - encoder_deltas[delta];
	encoder_val[0] = result;
      }
      return result;
    case 1:
      PC_b3b2 = ( GPIOC->IDR >> 2 ) & 3;
      if( encoders_conf & 2 )
      {
	delta = PC_b3b2 + 4 * encoder_mode[1];
	encoder_mode[1] = PC_b3b2;
	result = encoder_val[1] + encoder_deltas[delta];
	encoder_val[1] = result;
      }
      else
      {
	delta = PC_b3b2 + 4 * encoder_mode[1];
	encoder_mode[1] = PC_b3b2;
	result = encoder_val[1] - encoder_deltas[delta];
	encoder_val[1] = result;
      }
      return result;
  }
}

// horrendous coding from now on:
// every 6 SysTick interrupts process_encoders is called
// this is some kind of averaging over the last 4 values

uint32_t encoder_last4[8];
uint32_t encoder_update[2];
uint32_t last_4_pos[2];
int      encoder_sgn_dbl[2];
int      encoder_rem[2];

void
process_encoders( void )
{
  int idx;
  if( encoder_1or2 )
  {
    idx = last_4_pos[1] + 4;
    encoder_sgn_dbl[1] += 2 * encoder_val[1];
    encoder_last4[idx] += abs( encoder_val[1] );
    encoder_update[1]++;
    if( encoder_update[1] )
    {
      encoder_update[1] = 0;
      last_4_pos[1]++;
      last_4_pos[1] &= 3;
      encoder_last4[4 + last_4_pos[1]] = 0;
    }
    encoder_val[1] = 0;
  }
  else
  {
    idx = last_4_pos[0] + 0;
    encoder_sgn_dbl[0] += 2 * encoder_val[0];
    encoder_last4[idx] += abs( encoder_val[0] );
    encoder_update[0]++;
    if( encoder_update[0] )
    {
      encoder_update[0] = 0;
      last_4_pos[0]++;
      last_4_pos[0] &= 3;
      encoder_last4[0 + last_4_pos[0]] = 0;
    }
    encoder_val[0] = 0;
  }
}

int 
i_read_encoders(uint32_t *average, signed int divider, int encoder_nr)
{
  uint32_t *last4; 
  unsigned int v1, v2; 
  int enc; 
  int result; 

  last4 = &encoder_last4[4 * encoder_nr];
  v2 = 0xf00 * (encoder_update[encoder_nr] + 3);
  v1 = 80000 * (*last4 + last4[1] + last4[2] + last4[3]);
  enc = encoder_sgn_dbl[encoder_nr] + encoder_rem[encoder_nr];
  encoder_sgn_dbl[encoder_nr] = 0;
  *average = v1 / v2;
  result = enc / divider;
  encoder_rem[encoder_nr] = enc % divider;
  return result;
}

uint32_t encoder_clicks[10] = { 20, 30, 10, 20, 5, 15, 2, 10, 1, 6 }; 
uint32_t var_is_4 = 4;

// finally when the code wants to read an encoder value it calls read_encoders
 
int
read_encoders(int *clicks, int encoder_nr)
{
  int result; 
  signed int select; 
  uint32_t average; 

  result = i_read_encoders(&average, var_is_4, encoder_nr);
  if ( average > 0x1D )
    select = 0;
  else if ( average > 0x13 )
    select = 1;
  else if ( average > 0xE )
    select = 2;
  else if ( average > 9 )
    select = 3;
  else
  {
    if ( average <= 5 )
    {
      *clicks = 1;
      return result;
    }
    select = 4;
  }
  *clicks = encoder_clicks[2 * select];
  return result;
}

// all of the above to read two encoders ...
 
