/*
 * Hardware Timer as an Encoder interface. 
 * 
 * The STM32 Timers have the possibility of being used as an encoder interface. 
 * This can be both a quadrature encoder (mode 3) or pulse encoder with a signal to give direction (modes 1 and 2). 
 * The default behavior is for quadrature encoder. 
 * 
 * To avoid overflowing the encoder (which may or may not happen (although with 16 bits, it's likely), the following code 
 * will interrupt every time the number of pulses that each revolution gives to increment/decrement a variable (ints). 
 * 
 * This means that the total number of pulses given by the encoder will be (ints * PPR) + timer.getCount()
 * 
 * Attached is also a bit of code to simulate a quadrature encoder. 
 * To test this library, make the connections as below: 
 * 
 * TIMER2 inputs -> Digital Pins used to simulate.
 * D2 -> D4
 * D3 -> D5
 * 
 * COUNTING DIRECTION: 
 * 0 means that it is upcounting, meaning that Channel A is leading Channel B
 * 
 * EDGE COUNTING: 
 * 
 * mode 1 - only counts pulses on channel B
 * mode 2 - only counts pulses on Channel A
 * mode 3 - counts on both channels. 
 * 
*/



#include "HardwareTimer.h"

//Encoder simulation stuff
//NOT NEEDED WHEN CONNECTING A REAL ENCODER
unsigned char mode = 0;  //to issue steps...
unsigned char dir = 'F'; // direction of movement of the encoder.

unsigned int freq = 100; //update frequency.
unsigned long time = 0;        //time variable for millis()
unsigned char states[4];       //because I'm lazy...


//Encoder stuff

//Pulses per revolution
#define PPR   1024

HardwareTimer timer(2);

unsigned long ints = 0;

void func(){
if (timer.getDirection()){
  ints--;
} else{
  ints++;
}
}


void setup() {
  //define the Timer channels as inputs. 
  pinMode(D2, INPUT_PULLUP);  //channel A
  pinMode(D3, INPUT_PULLUP);  //channel B

//configure timer as encoder
  timer.setMode(1, TIMER_ENCODER); //set mode, the channel is not used when in this mode (but it must be [1..4]). 
  timer.pause(); //stop... 
  timer.setPrescaleFactor(1); //normal for encoder to have the lowest or no prescaler. 
  timer.setOverflow(PPR);    //use this to match the number of pulse per revolution of the encoder. Most industrial use 1024 single channel steps. 
  timer.setCount(0);          //reset the counter. 
  timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER3); //or TIMER_SMCR_SMS_ENCODER1 or TIMER_SMCR_SMS_ENCODER2. This uses both channels to count and ascertain direction. 
  timer.attachInterrupt(0, func); //channel must be 0 here 
  timer.resume();                 //start the encoder... 
  
//Setup encoder simulator  
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);

  digitalWrite(5, HIGH); 
  digitalWrite(4, LOW);
  states[0] = 0; //00
  states[1] = 1; //01
  states[2] = 3; //11
  states[3] = 2; //10


}

//Support variables.
unsigned long interval=0; //variable for status updates... 
char received = 0;

void loop() {
  //encoder code
  if (millis() - interval >= 1000) { 
     Serial.print(timer.getCount()); 
     Serial.println(" counts");
     Serial.print("direction ");
     Serial.println(timer.getDirection());
     Serial.print("Full Revs: ");
     Serial.println(ints);
     interval = millis(); //update interval for user. 
  }
  
  
  
/*
EENCODER SIMULATION PART. 


*/  
/*
 * 
 * Protocol... 
 * 
 * if received F - Move forward. 
 * if received B - Move BackWard
 * if received 1 - Mode 1 (Channel B counts)
 * if received 2 - Mode 2 (Channel A counts)
 * if received 3 - Mode 3 (Counts on both channels)
 * if received 4 - Change prescaler to 4
 * if received 0 - change prescaler to 1
 * if received - - Increase Speed
 * if received + - Decrease Speed
*/

//take care of comms...
  if (Serial.available() > 0) {
    received = Serial.read();
    if (received == 'F' || received == 'R') dir = received; //direction. Forward or Reverse.
    if (received == '1') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER1); //count only the pulses from input 1
    if (received == '2') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER2); //count only the pulses from input 2
    if (received == '3') timer.setEdgeCounting(TIMER_SMCR_SMS_ENCODER3); //count on both channels (default of the lib).
    if (received == '4') timer.setPrescaleFactor(4); //only updates on overflow, so you need to wait for an overflow. Not really used...  
    if (received == '0') timer.setPrescaleFactor(1); //only updates on overflow, so you need to wait for an overflow. 
    if (received == '-') freq+=50; //increase speed.
    if (received == '+') {
      freq-=50;
      if (freq <= 0) freq = 100; //smallest is 10 ms. 
    }
  }
  
//simulate encoder pulses.   
  if ( millis() - time >= freq) { 
    time = millis(); //prepare next
    
    if (dir == 'F')  mode++;
    if (dir == 'R')  mode --;
    
    digitalWrite(4, (states[mode%4] & 0x01));
    digitalWrite(5, (states[mode%4] >> 1));
  }

}
