#ifndef MYSTEPPERDRIVER_H
  #define MYSTEPPERDRIVER_H
  // *******************************************************************************************************************
  // * Arduino UNO and MEGA2560 Interrupt Driven (non-blocking) Stepper Motor Driver using the Arduino Motor Shield V3 *
  // *                                                                                                                 *
  // * Project files:                                                                                                  *
  // * 1. myStepperDriver.cpp     Stepper Motor Interrupt Controlled Source Code.                                      *
  // * 2. myStepperDriver.h       This header file.                                                                    *
  // * 3. stepMotorDriver.ino     Arduino template file how to use the driver.                                         *
  // * 4. Documentation.xlsx      Explains the motor driver use.                                                       *
  // * 5. Depending on the Arduino used, the HW Timer can be selected:                                                 *
  // *    +--------+-------------------+--------------------+                                                          *
  // *    | Timer  |    Arduino Uno    |    Arduino Mega    |                                                          *
  // *    +--------+-------------------+--------------------+                                                          *
  // *    | Timer0 | Reserved by Arduino time/millis etc.   | (*) On Arduino Uno, the only suitable timer available    *
  // *    | Timer1 | Mandatory Use (*) |  Option #1 (*)     |     is Timer 1. On Arduino Mega, one may select below    *
  // *    | Timer2 |           Not usable (8bit)            |     options MOTOR_TIMER1 up to 5 to select any of the    *
  // *    | Timer3 | Not available     |  Option #2 (*)     |     suitable timers.                                     *
  // *    | Timer4 | Not available     |  Option #3 (*)     |                                                          *
  // *    | Timer5 | Not available     |  Option #4 (*)     |                                                          *
  // *    +--------+-------------------+--------------------+                                                          *
  // * The GNU GPL applies to all provided files. Use at own risk but free of any charge.                              *
  // * Contact: egi1965@gmail.com                                                                                      *
  // * Note the source is prepared for use with doxygen, but this is not finally tested at this time, not guaranteed.  *
  // *******************************************************************************************************************

  //  \ingroup LowLevel
  #if defined (__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
    #define _ARDUINO_UNO_
    #define MOTOR_TIMER1                                                //Default Timer used on Uno.
  #endif
  #if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__)
    #define _ARDUINO_MEGA_
  //#define MOTOR_TIMER1                                                //Default Timer used on Uno.
  //#define MOTOR_TIMER3                                                //(ONLY) ONE IS ALLOWED TO BE DEFINED AT ANY TIME.
    #define MOTOR_TIMER4
  //#define MOTOR_TIMER5
  #endif

  #if !defined (_ARDUINO_UNO_) && !defined (_ARDUINO_MEGA_)
    #error Board not supported
  #endif

  #define ARDUINO_MOTOR_SHIELD                                          //Uncomment for use with Arduino Motor Shield.

  #ifndef ARDUINO_MOTOR_SHIELD
    #define MOTOR_IOPORT_L                                              //This can be *_A ... *_L (any port that has sufficient outputs available).
    #define MOTOR_PATTERN0        (B00001001)                           //These patterns are applied in sequence.
    #define MOTOR_PATTERN1        (B00000011)
    #define MOTOR_PATTERN2        (B00000110)
    #define MOTOR_PATTERN3        (B00001100)
    #define MOTOR_OUTPUTS         (B00001111)                           //Set all the bits that are output for the motor driver.
  #endif

  #define MOTOR_CTRL_DIRECTION            (B00000001)
  #define MOTOR_CTRL_FASTER               (B00000010)                   //Use this to make the motor spin faster (SUB from timer).
  #define MOTOR_CTRL_SLOWER               (B00000000)                   //Default is CTRL_SLOWER. If one wants to use in control feel free (has no real effect).
  #define MOTOR_CTRL_ENDPOINT_MILLIS      (B00000100)                   //Endpoint is ms instead of steps.
  #define MOTOR_CTRL_VARIABLE_PWR         (B00010000)                   //Shifts the correction factor left (SLOWER) or right (FASTER). Limits usable modCounts to ~31.
  #define MOTOR_CTRL_SPEED_VARIABLE       (B00100000)                   //Variable speed ADD/SUB a user parameter to the virtual 32bit timer.
  #define MOTOR_CTRL_IRQ_TIMING           (B01000000)                   //User does NOT call motorTimerUpdateCheck from own code.
  #define MOTOR_CTRL_DRV_EN               (B10000000)                   //Enable the L298 Driver outputs.
  #define MOTOR_CTRL_IRQ_TIMING_VARIABLE  (B01100000)                   //Combines IRQ_TIMING & SPEED_VARIABLE.

  #define MOTOR_STAT_REACHED              (B00000001)                   //Motor has reached last set target conditions.
  #define MOTOR_STAT_REACH_CALLED         (B00000010)                   //The "Reached Position" callback has been executed once.
  #define MOTOR_STAT_SPINNING             (B00000100)                   //Steps are sent to the motor at this time.
  #define MOTOR_STAT_SPIN_FIXED           (B00001000)                   //Motor RPM is no longer changed (in case it was initialized variable).
  #define MOTOR_STAT_TIMER_DIV_CALLED     (B00010000)                   //Motor divider (32bit virtual timer TOP value) does not fit - error callback executed.
  #define MOTOR_STAT_TIMER_DIV_ERROR      (B00100000)                   //Motor divider (32bit virtual timer TOP value) does not fit in the timer hardware.
  #define MOTOR_STAT_FAULT_CALLED         (B01000000)                   //The fault callback has been executed.
  #define MOTOR_STAT_FAULT                (B10000000)                   //Motor fault condition is detected (ex. exceeding 25kHz stepping frequency).

  #define MOTOR_ENABLE_A                  ( 3)                          //Arduino Digital pin for Motor Enable 1st coil.
  #define MOTOR_BREAK_B                   ( 8)                          //Arduino Digital pin for Motor Enable 2nd coil.
  #define MOTOR_BREAK_A                   ( 9)                          //Arduino Digital pin to drive the L298 2nd input inverter (must be kept LOW) of 1st driver block.
  #define MOTOR_ENABLE_B                  (11)                          //Arduino Digital pin to drive the L298 2nd input inverter (must be kept LOW) of 2nd driver block.
  #define MOTOR_DIR_A                     (12)                          //Arduino Digital pin to drive the L298 1st input of 2nd driver block.
  #define MOTOR_DIR_B                     (13)                          //Arduino Digital pin to drive the L298 1st input of 2nd driver block.

//#define DEBUG_BAUDRATE              (115200)                          //Undefine to disable debug messages.
  #ifdef    DEBUG_BAUDRATE
  //#define DEBUG_LOW
    void    serDbgPrint (const char* formatString, ...);
    void    debugDump (bool only_if_speed_variable = false);
    #define DEBUGPRINT(a) serDbgPrint a
    #define DEBUGPRINTLL(a) //serDbgPrint a
  #else
    #define DEBUGPRINT(a)
    #define DEBUGPRINTLL(a)
  #endif


  uint32_t                                                              //Timer TOP virtual 32-bit value.
  motorTimerCalcPerSecond (uint16_t motorPulses);                       //Amount of stepper pulses to the motor per second.


  uint32_t                                                              //Returns the amount of I/O clocks per second.
  motorTimerGetIOclocksPerSecond ();                                    //Can be used to calculate the timer divider (= virtual 32bit TOP register).


  int8_t
  motorSetSpeed (uint8_t  control = 0,                                  //MOTOR_CTRL parameters.
                 uint32_t timerTop32virtual = 0UL,                      //Virtual 32-bit timer TOP to apply motor steps; 0 = STOP motor.
                 uint32_t stepCountLimit = 0,                           //MOTOR_CTRL_ENDPOINT_MILLIS == '0': Stop after this amount of steps (0 = no limit).
                                                                        //MOTOR_CTRL_ENDPOINT_MILLIS == '1': Stop after this amount of millis since the start.
                 uint32_t timerModification = 0,                        //Virtual 32-bit correction on timerTop32Virtual.
                 uint16_t timerUpd_ms = 0,                              //Every xx ms, the correction is applied.
                 uint16_t modCounts = 0);                               //After this amount of mods has been reached, mod stops.


  void                                                                  //The user can define "void positionReached ()" function.
  motorCallBackPositionReached (void (*userFunction) ());               //This function gets called when the targetted motor position is reached AND.
                                                                        //the MOTOR_CTR_IRQ_TIMING bit is NOT set (user calls motorTimerUpdateCheck regularly).
                                                                        //User function should not be blocking, but return asap.


  void                                                                  //The user can define "void motorFault ()" function.
  motorCallBackFault (void (*userFunction) ());                         //This function gets called when a motor fault / controlling error is encountered AND
                                                                        //the MOTOR_CTR_IRQ_TIMING bit is NOT set (user calls motorTimerUpdateCheck regularly).
                                                                        //User function should not be blocking, but return asap.

  void
  motorShieldInit ();


  void                                                                  //The user must call this function every 1-10 ms (every 1ms is best). However, if this cannot
  motorTimerUpdateCheck ();                                             //be guaranteed and the IRQ service routine execution may be slower, one can set MOTOR_CTRL_IRQ_TIMING.
                                                                        //The motor driver than performs the check on its own.


  uint8_t
  motorReadStatus ();                                                   //Reads motor status (any MOTOR_STAT* combination may be returned).

#endif