/*
 * splitflap.h
 *
 *  Created on: 29.09.2022
 *      Author: jonas
 */

#ifndef SPLITFLAP_H_
#define SPLITFLAP_H_

#include <stdbool.h>
#include "McuULN2003.h"
#include "McuGPIO.h"
#include "McuRTOS.h"
#include "lib/dict.h"
#include <string.h>

/****** SETTINGS ******/
#define SPLITFLAP_CONFIG_USE_FREERTOS_HEAP 	0
#define SPLITFLAP_STEPS_ONE_ROUND 			512
#define SPLITFLAP_AMOUNT_OF_SEGMENTS		(sizeof(SF_Letters)/sizeof(SF_Letters[0]))
#define SPLITFLAP_STEPS_PER_SEGMENT			((float)SPLITFLAP_STEPS_ONE_ROUND/(float)SPLITFLAP_AMOUNT_OF_SEGMENTS)


/****** TYPES ******/
/* define splitflap handle type. SF_Handle_t points to SF_t */
typedef void* SF_Handle_t;

/* descriptor to identify the flap */
typedef char Flap_t;

/* descriptor to identify the hardware */
typedef uint8_t HardwareIdentifier_t;

/* descriptor to identify the instance in the setup */
typedef uint8_t SetupIdentifier_t;

/* state of the splitflap instance */
typedef enum{
	/* splitflap is in initial state, after creation, not initialized */
    SF_STATE_NOT_READY,
	/* splitflap is waiting to be or currently being initialized */
	SF_STATE_INITIALIZATION,
	/* splitflap is ready to move to another flap */
	SF_STATE_READY,
	/* splitflap is currently moving to another flap */
	SF_STATE_MOVING
} SF_State;

typedef struct {
  SetupIdentifier_t id;
  HardwareIdentifier_t hwId;
  McuULN2003_Handle_t motor;
  McuGPIO_Handle_t magSensor;
  SemaphoreHandle_t ongoingMoveMutex;
  QueueHandle_t flapQueue;
  SF_State state;
} SF_t;

typedef struct {
  McuULN2003_Config_t motorConfig;
  McuGPIO_Config_t magSensorConfig;
  HardwareIdentifier_t hardwareIdentifier;
  SetupIdentifier_t setupIdentifier;
} SF_Config_t;

/****** HELPER MACROS **/
#define SF_IS_RDY_TO_MOVE(sf)	(((SF_t*)sf)->state == SF_STATE_READY)
#define SF_IS_MOVING(sf)		(((SF_t*)sf)->state == SF_STATE_MOVING)
#define SF_IS_INITIALIZING(sf)	(((SF_t*)sf)->state == SF_STATE_INITIALIZATION)

/****** FUNCTIONS ******/
/* initializes dictonary with splitflap flaps position */
//void SF_InitConfig(void);

/* free splitflap flaps dictionary */
//void SF_DeInitConfig(void);

/* instantiate new split flap
 * only pass configured types, they do not need to be initialized.
 * Initialization will be made inside the SF_Init method */
SF_Handle_t SF_Init(SF_Config_t* instance);

/* kill instance of splitflap,
 * free memory etc. */
void SF_Deinit(SF_Handle_t instance);

/* Moves split flap slowly to zero position.
 * returns true if the move was successful, false if not
 * (depending on if the sensor was hit before one round)
 * After moving to zero position, the current position of the motor is set to 0 */
bool SF_MoveMotorToZeroPosition(SF_Handle_t instance);

/* Moves split flap slowly to zero position.
 * returns true if the move was successful, false if not
 * (depending on if the sensor was hit before one round)
 * After moving to zero position, the current position of the motor is set to 0 */
void SF_MoveMotorToZeroPositionAsync(SF_Handle_t instance);

/* split flap moves number of steps (uint, since only forward moves are allowed) */
void SF_MoveSteps(SF_Handle_t instance, uint32_t steps);

/* get mag sensor state. returns true if sensor is at zero position, otherwise false */
bool SF_GetMagSensorAtZeroPosition(SF_Handle_t instance);

/* move to specific flap */
void SF_MoveToFlap(SF_Handle_t instance, Flap_t flap);

/* move to specific flap asynchronously (RTOS task) */
void SF_MoveToFlapAsync(SF_Handle_t instance, Flap_t flap);

/* sets the hardware identifier of the split flap.
 * on re-init the new hardware identifier is used to determine offset steps */
void SF_SetHardwareIdentifier(SF_Handle_t instance, HardwareIdentifier_t identifier);

/* get current position of motor */
int32_t SF_GetMotorPosition(SF_Handle_t instance);

/* get current state of the split flap */
SF_State SF_GetCurrentState(SF_Handle_t instance);



#endif /* SPLITFLAP_H_ */
