#include "stm32l1xx_hal.h"
#include "core/csect.h"
#include "core/config.h"
#include "core/config_pins.h"
#include "drivers/switchboard_control/switchboard_control.h"
#include "app/control_table/control_table.h"

static bool Table_Init();
static bool Table_Add_Points( uint8_t * val, uint8_t size );
static bool Table_Clear( );
static void Table_Set_Edit_State(bool state);
static bool Table_Get_Edit_State();
static uint16_t Table_Get_Number_Of_Points();
static bool Table_Get_Point(uint8_t point_number, sTableTablePoint_t* point);
static void Table_DeInit();

static void Start_Meas();
static void Stop_Meas();
static void Continue_Meas( );
static uint8_t Mode_Meas( );
static void PortSet(sTableTablePoint_t portCommutation);
static void SetDefaultState( );
static sTableTablePoint_t PortRead();
static void TriggerPolaritySet(uint8_t polarity);
static uint8_t TriggerPolarityGet ();
static uint8_t TriggerCounterGet ();

 const Table_Handle_t TableHandle = {

    Table_Init,
    Table_Add_Points,
    Table_Clear,
    Table_Set_Edit_State,
    Table_Get_Edit_State,
    Table_Get_Number_Of_Points,
    Table_Get_Point,
    Table_DeInit,
 };
 
 const Control_Handle_t ControlHandle = {
    Start_Meas,
    Stop_Meas,
    Continue_Meas,
    Mode_Meas,
    PortSet,
    SetDefaultState,
    PortRead,
    TriggerPolaritySet,
    TriggerPolarityGet,
    TriggerCounterGet,
 };
 
 static uint32_t currentTableAddr = 0; // Текущий адрес в таблице состояний (адрес последней записи)
 static bool isTableEditState = false;
 static bool Table_Init()
 {
   // Инициализация SPI для работы с коммутатором
   SBHandle.Init();
   Table_Get_Edit_State(true);
   currentTableAddr = Table_Get_Number_Of_Points();
   return true;
 }
 
 static void Table_DeInit()
 {
     Table_Set_Edit_State(false);
     currentTableAddr = 0;
 }
 
 static bool Validate_Points(uint8_t * point, uint8_t size)
 {
     if( size % 2 || !size ) return false;
     sTableTablePoint_t TablePoint;
     for(int i = 0; i < size; i += 2)
     {
         TablePoint.port1 = *point++;
         TablePoint.port2 = *point++;
         if( TablePoint.port1 > 16 || TablePoint.port2 > 16 
            || !TablePoint.port1 || !TablePoint.port2 )
         {
             return false;
         }
     }
     return true;
 }

 // Add cell to the end of list
 static bool Table_Add_Points( uint8_t * val, uint8_t size )
 {
   if(!Table_Get_Edit_State()) return false;
   if( NULL == val || !size || ! Validate_Points(val, size) ) return false;
   
   for(int i = 0; i < size; i += 2)
   {
       sTableTablePoint_t TablePoint;
       TablePoint.port1 = *val++;
       TablePoint.port2 = *val++;
       
       SB_command_t tablePointCmd = {
           .cmd = SWB_TABLE_NEW_RECORD,
           .addr = currentTableAddr,
           .responce_2 = TablePoint.port2,
           .responce_1 = TablePoint.port1
       };
       SBHandle.ClrNSS();
       SBHandle.Transmit((uint8_t*)&tablePointCmd, sizeof(tablePointCmd));
       SBHandle.SetNSS();
       currentTableAddr++;
       //if(!SW_ROM_SetDataPoint(eChValues, &TablePoint)) return false;
   }
   return true;
 }

static bool Table_Clear( )
{
    SB_command_t tableClearCmd = {
           .cmd = SWB_TABLE_CLEAR,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&tableClearCmd, sizeof(uint8_t));
    SBHandle.SetNSS();
    currentTableAddr = 0;
    return true;
    //return SW_ROM_Table_Clear();
}

static void Table_Set_Edit_State(bool state)
{
    isTableEditState = state;
}

static bool Table_Get_Edit_State()
{
    return isTableEditState;
}

static uint16_t Table_Get_Number_Of_Points()
{
    if(!Table_Get_Edit_State()) false;
    SB_command_t tableGetPointCountCmd = {
           .cmd = SWB_TABLE_TABLE_COUNT,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&tableGetPointCountCmd, sizeof(uint8_t));
    SBHandle.Receive((uint8_t*)&tableGetPointCountCmd.responce_2, sizeof(uint8_t));
    SBHandle.SetNSS();
    currentTableAddr = tableGetPointCountCmd.responce_2;
    return currentTableAddr;
    //return SW_ROM_GetNumberOfPoints();
}

static bool Table_Get_Point(uint8_t point_number, sTableTablePoint_t* point)
{
    if( point_number >= currentTableAddr)
    {
        return false;
    }
    SB_command_t tableGetPointCmd = {
           .cmd = SWB_TABLE_GET_RECORD,
           .addr = point_number,
           .responce_2 = 0,
           .responce_1 = 0
       };
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&tableGetPointCmd, sizeof(uint16_t));
    if(!SBHandle.Receive((uint8_t*)&tableGetPointCmd.responce_2, sizeof(uint16_t)))
    {
        return false;
    }
    SBHandle.SetNSS();
    point->port2 = tableGetPointCmd.responce_2;
    point->port1 = tableGetPointCmd.responce_1;
    return true;
    //return SW_ROM_GetDataPoint( eChValues, point_number, (uint8_t *)point, sizeof(point) );
}

static void Start_Meas()
{
    SB_command_t controlStartMeasCmd = {
           .cmd = SWB_TABLE_START_MEASURING,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&controlStartMeasCmd, sizeof(uint8_t));
    SBHandle.SetNSS();
}

static void Stop_Meas()
{
    SB_command_t controlStopMeasCmd = {
           .cmd = SWB_TABLE_STOP_MEASURING,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&controlStopMeasCmd, sizeof(uint8_t));
    SBHandle.SetNSS();
}

static void Continue_Meas( )
{
    SB_command_t controlContinueMeasCmd = {
           .cmd = SWB_TABLE_CONTINUE_MEASURING,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&controlContinueMeasCmd, sizeof(uint8_t));
    SBHandle.SetNSS();
}

// Запрос режима измерения прибора
static uint8_t Mode_Meas()
{
    SB_command_t controlModeMeasCmd = {
           .cmd = SWB_CONTROL_MEASURING_MODE,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    bool result = false;
    SBHandle.ClrNSS();
    // 0 - Manual, 1 - Table
    SBHandle.Transmit((uint8_t*)&controlModeMeasCmd.cmd, sizeof(uint8_t));
    result = SBHandle.Receive((uint8_t*)&controlModeMeasCmd.responce_2, sizeof(uint8_t));
    SBHandle.SetNSS();
    return result ? controlModeMeasCmd.responce_2 : ERROR_CODE;
}

static void PortSet(sTableTablePoint_t portCommutation)
{
    struct 
    {
        uint8_t cmd;
        uint8_t responce_2;
        uint8_t responce_1;
    }portSetCmd;
    
    portSetCmd.cmd = SWB_CONTROL_PORT;
    portSetCmd.responce_2 = portCommutation.port2;
    portSetCmd.responce_1 = portCommutation.port1;

    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&portSetCmd, sizeof(portSetCmd));
    SBHandle.SetNSS();
}

static void SetDefaultState( )
{
    struct 
    {
        uint8_t cmd;
        uint8_t responce_2;
        uint8_t responce_1;
    }portSetCmd;
    
    portSetCmd.cmd = SWB_CONTROL_PORT;
    portSetCmd.responce_2 = 0;
    portSetCmd.responce_1 = 0;

    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&portSetCmd, sizeof(portSetCmd));
    SBHandle.SetNSS();
}

static sTableTablePoint_t PortRead()
{
    SB_command_t controlPortReadCmd = {
           .cmd = SWB_CONTROL_READ,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    // Чтение первого порта
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&controlPortReadCmd, sizeof(uint8_t));
    SBHandle.Receive((uint8_t*)&controlPortReadCmd.responce_2, sizeof(uint16_t));
    SBHandle.SetNSS();
    
    sTableTablePoint_t portCommutation;
    portCommutation.port1 = controlPortReadCmd.responce_1;
    portCommutation.port2 = controlPortReadCmd.responce_2;
    return portCommutation;
}

static void TriggerPolaritySet(uint8_t polarity)
{
    struct 
    {
        uint8_t cmd;
        uint8_t responce_2;
    }trigSetCmd;
    
    trigSetCmd.cmd = SWB_CONTROL_SET_TRIGGER_MODE;
    trigSetCmd.responce_2 = polarity;

    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&trigSetCmd, sizeof(trigSetCmd));
    SBHandle.SetNSS();
}

static uint8_t TriggerPolarityGet()
{
    SB_command_t triggerModeCmd = {
           .cmd = SWB_CONTROL_GET_TRIGGER_MODE,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    // Чтение состояния триггера
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&triggerModeCmd, sizeof(uint8_t));
    SBHandle.Receive((uint8_t*)&triggerModeCmd.responce_2, sizeof(uint8_t));
    SBHandle.SetNSS();
    
    return triggerModeCmd.responce_2;
}

static uint8_t TriggerCounterGet()
{
    SB_command_t triggerModeCmd = {
           .cmd = SWB_CONTROL_GET_TRIGGER_COUN,
           .addr = 0,
           .responce_2 = 0,
           .responce_1 = 0
       };
    // Чтение состояния триггера
    SBHandle.ClrNSS();
    SBHandle.Transmit((uint8_t*)&triggerModeCmd.cmd, sizeof(uint8_t));
    SBHandle.Receive((uint8_t*)&triggerModeCmd.responce_2, sizeof(uint8_t));
    SBHandle.SetNSS();
    
    return triggerModeCmd.responce_2;
}