//
#include "Define.h"
//
#include "StepperDRV8825.h"
//
CStepperDRV8825::CStepperDRV8825(int pinstep, int pindirection,
                                 int pinm0, int pinm1, int pinm2,
                                 int pinenablen)
{
    FPinStep = pinstep;
    FPinDirection = pindirection;
    FPinM0 = pinm0;
    FPinM1 = pinm1;
    FPinM2 = pinm2;
    FPinEnableN = pinenablen;
    Disable();
    SetStateStep(ssIdle);
}
//
void CStepperDRV8825::SetStateStep(EStateStep statestep)
{
    FStateStep = statestep;
    switch (FStateStep)
    {
        case ssStepLow:
            digitalWrite(PIN_LEDSYSTEM, LOW);
            digitalWrite(PIN_MOTOR_STEP, LOW);
            Enable();
            break;
        case ssStepHigh:
            digitalWrite(PIN_LEDSYSTEM, HIGH);
            digitalWrite(PIN_MOTOR_STEP, HIGH);
            Enable();
            break;
        default: // ssIdle
            Disable();
            break;
    }
}
//
void CStepperDRV8825::SetStepDirection(EStepDirection stepdirection)
{
    switch (stepdirection)
    {
        case sdNegative:
            digitalWrite(PIN_MOTOR_DIRECTION, LOW);  
            break;
        default: // sdPositive
            digitalWrite(PIN_MOTOR_DIRECTION, HIGH);  
            break;
    }
}
//
void CStepperDRV8825::SetStepResolution(EStepResolution stepresolution)
{    
    switch (stepresolution)
    {        
        case srHalf:
            digitalWrite(PIN_MOTOR_PRECISIONM2, LOW);
            digitalWrite(PIN_MOTOR_PRECISIONM1, LOW);
            digitalWrite(PIN_MOTOR_PRECISIONM0, HIGH);
            break;
        case srQuarter:
            digitalWrite(PIN_MOTOR_PRECISIONM2, LOW);
            digitalWrite(PIN_MOTOR_PRECISIONM1, HIGH);
            digitalWrite(PIN_MOTOR_PRECISIONM0, LOW);
            break;
        case srEight:
            digitalWrite(PIN_MOTOR_PRECISIONM2, LOW);
            digitalWrite(PIN_MOTOR_PRECISIONM1, HIGH);
            digitalWrite(PIN_MOTOR_PRECISIONM0, HIGH);
            break;
        case srSixteen:
            digitalWrite(PIN_MOTOR_PRECISIONM2, HIGH);
            digitalWrite(PIN_MOTOR_PRECISIONM1, LOW);
            digitalWrite(PIN_MOTOR_PRECISIONM0, LOW);
            break;
        case srThirtyTwo:
            digitalWrite(PIN_MOTOR_PRECISIONM2, HIGH);
            digitalWrite(PIN_MOTOR_PRECISIONM1, HIGH);
            digitalWrite(PIN_MOTOR_PRECISIONM0, HIGH);
            break;
        default: // srFull
            digitalWrite(PIN_MOTOR_PRECISIONM2, LOW);
            digitalWrite(PIN_MOTOR_PRECISIONM1, LOW);
            digitalWrite(PIN_MOTOR_PRECISIONM0, LOW);
            break;
    }
}
//
void CStepperDRV8825::Enable(void)
{
    digitalWrite(PIN_MOTOR_ENABLEN, LOW);
}
void CStepperDRV8825::Disable(void)
{
    digitalWrite(PIN_MOTOR_ENABLEN, HIGH);
}
//
bool CStepperDRV8825::Open(void)
{
    pinMode(PIN_LEDSYSTEM, OUTPUT);
    pinMode(PIN_MOTOR_STEP, OUTPUT);
    pinMode(PIN_MOTOR_DIRECTION, OUTPUT);
    pinMode(PIN_MOTOR_PRECISIONM0, OUTPUT);
    pinMode(PIN_MOTOR_PRECISIONM1, OUTPUT);
    pinMode(PIN_MOTOR_PRECISIONM2, OUTPUT);
    pinMode(PIN_MOTOR_ENABLEN, OUTPUT);
    SetStateStep(ssIdle);
    SetStepResolution(srFull);
    SetStepDirection(sdPositive);
    return true;
}
bool CStepperDRV8825::Close(void)
{
    SetStateStep(ssIdle);
    SetStepResolution(srFull);
    SetStepDirection(sdPositive);
    pinMode(PIN_LEDSYSTEM, INPUT);
    pinMode(PIN_MOTOR_STEP, INPUT);
    pinMode(PIN_MOTOR_DIRECTION, INPUT);
    pinMode(PIN_MOTOR_PRECISIONM0, INPUT);
    pinMode(PIN_MOTOR_PRECISIONM1, INPUT);
    pinMode(PIN_MOTOR_PRECISIONM2, INPUT);
    pinMode(PIN_MOTOR_ENABLEN, INPUT);
    return true;
}
//
bool CStepperDRV8825::Move(EStepDirection stepdirection,
                           EStepResolution stepresolution,
                           long unsigned stepperiod,
                           long unsigned stepcount)
{
    SetStepResolution(stepresolution);
    SetStepDirection(stepdirection);
    FMicrosPeriod = stepperiod;
    FStepCount = stepcount;
    if (0 < FStepCount)
    {
        FStepCount--;
        SetStateStep(ssStepHigh);
        FMicrosPreset = micros();
    }
    return true;
}
bool CStepperDRV8825::Halt(void)
{
    SetStateStep(ssIdle);
    return true;
}    
//
void CStepperDRV8825::Execute(void)
{
    switch (FStateStep)
    {
        case ssStepHigh:
            if ((FMicrosPeriod / 2) <= (micros() - FMicrosPreset))
            {
                FMicrosPreset = micros();
                SetStateStep(ssStepLow);
            }
            break;
        case ssStepLow:
            if ((FMicrosPeriod / 2) <= (micros() - FMicrosPreset))
            {
                if (0 < FStepCount)
                {
                    FStepCount--;
                    FMicrosPreset = micros();
                    SetStateStep(ssStepHigh);
                }
                else
                {
                    SetStateStep(ssIdle);
                }
            }
            break;
        default: // sdsIdle
          // nothing
          SetStateStep(ssIdle);
          break;
    }
}
//