#ifndef MISSION_DEVICES_GYROADIS16507HANDLER_H_
#define MISSION_DEVICES_GYROADIS16507HANDLER_H_

#include "OBSWConfig.h"
#include "FSFWConfig.h"
#include "devicedefinitions/GyroADIS16507Definitions.h"

#include "fsfw/globalfunctions/PeriodicOperationDivider.h"
#include "fsfw/devicehandlers/DeviceHandlerBase.h"

#if OBSW_ADIS16507_LINUX_COM_IF == 1
class SpiComIF;
class SpiCookie;
#endif

/**
 * @brief   Device handle for the ADIS16507 Gyroscope by Analog Devices
 * @details
 * Flight manual:
 * https://egit.irs.uni-stuttgart.de/redmine/projects/eive-flight-manual/wiki/ADIS16507_Gyro
 */
class GyroADIS16507Handler: public DeviceHandlerBase {
public:
    GyroADIS16507Handler(object_id_t objectId, object_id_t deviceCommunication,
            CookieIF * comCookie);

    /* DeviceHandlerBase abstract function implementation */
    void doStartUp() override;
    void doShutDown() override;
    ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t * id) override;
    ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t * id) override;
    ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand,
            const uint8_t * commandData, size_t commandDataLen) override;
    void fillCommandAndReplyMap() override;
    ReturnValue_t scanForReply(const uint8_t *start, size_t remainingSize,
            DeviceCommandId_t *foundId, size_t *foundLen) override;
    ReturnValue_t interpretDeviceReply(DeviceCommandId_t id,
            const uint8_t *packet) override;
    uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
    ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
            LocalDataPoolManager &poolManager) override;

private:
    std::array<uint8_t, 32> commandBuffer;

    AdisGyroPrimaryDataset primaryDataset;
    AdisGyroConfigDataset configDataset;

    enum class InternalState {
        STARTUP,
        CONFIG,
        IDLE
    };

    enum class BurstModes {
        BURST_16_BURST_SEL_0,
        BURST_16_BURST_SEL_1,
        BURST_32_BURST_SEL_0,
        BURST_32_BURST_SEL_1
    };

    InternalState internalState = InternalState::STARTUP;
    bool commandExecuted = false;

    void prepareReadCommand(uint8_t* regList, size_t len);

    BurstModes getBurstMode();

#if OBSW_ADIS16507_LINUX_COM_IF == 1
    static ReturnValue_t spiSendCallback(SpiComIF* comIf, SpiCookie *cookie,
            const uint8_t *sendData, size_t sendLen, void* args);
#endif

#if FSFW_HAL_ADIS16507_GYRO_DEBUG == 1
    PeriodicOperationDivider* debugDivider;
#endif
    Countdown breakCountdown;
    void prepareWriteCommand(uint8_t startReg, uint8_t valueOne, uint8_t valueTwo);

    ReturnValue_t handleSensorData(const uint8_t* packet);
};



#endif /* MISSION_DEVICES_GYROADIS16507HANDLER_H_ */