#ifndef _SETCAN
#define _SETCAN
#include "main.h"
#include "can.h"

#define _DEMO

#define ONLINE 1;
#define OFFLINE 0;

#ifndef YESNO
#define YESNO
#define YES 1
#define NO 0
#endif

#define ISPM NO

#ifndef CURRENT_TYPE_DEVICE
#define CURRENT_TYPE_DEVICE 0b001
#endif

#ifndef CURRENT_ID_DEVICE
#define CURRENT_ID_DEVICE 0b0010
#endif

#define SETCAN_RX_BUFFER_SIZE 128

#define SensorToModbusRegister(SensorType, SensorID) SensorType << 11 | SensorID
#define HighByteOfWord(WORD) (WORD>>8)&0xFF
#define LowByteOfWord(WORD) WORD&0xFF

/**
 * @brief Статус инициализации протокола CAN.
 *
 * Это перечисление описывает возможные статусы после попытки инициализации.
 */
typedef enum
{
  SETCAN_INIT_OK = 0x00U,            /**< Инициализация прошла успешно. */
  SETCAN_INIT_HCAN_ERROR = 0x01U,    /**< Ошибка при инициализации модуля CAN. */
  SETCAN_INIT_HRTC_ERROR = 0x02U,    /**< Ошибка при инициализации модуля RTC. */
  SETCAN_INIT_TIM_ERROR = 0x04U      /**< Ошибка при инициализации таймера. */
} SETCAN_INIT_StatusTypeDef;

/**
 * @brief Статус выполнения операции протокола CAN.
 *
 * Это перечисление описывает возможные результаты выполнения функций протокола.
 */
typedef enum
{
  SETCAN_OK       = 0x00U, /**< Операция прошла успешно. */
  SETCAN_ERROR    = 0x01U, /**< Обнаружена ошибка во время выполнения. */
  SETCAN_BUSY     = 0x02U, /**< Канал занят, выполнение невозможно в данный момент. */
  SETCAN_TIMEOUT  = 0x03U  /**< Истек таймаут ожидания. */
} SETCAN_StatusTypeDef;

/**
 * @brief Уровень приоритета CAN-сообщения.
 *
 * Это перечисление определяет важность и приоритет обработки сообщения.
 */
typedef enum {
	SETCAN_PRIORITY_CRITICAL = 0,   /**< Критический приоритет, рекомендуется обработка без задержек. */
	SETCAN_PRIORITY_STANDARD = 1    /**< Стандартный приоритет, менее важный. */
} SetCanPriorityType;

/**
 * @brief Маршрут CAN-сообщения.
 *
 * Это перечисление задает направление маршрута отправки сообщения.
 */
typedef enum {
	SETCAN_ROUTE_FROM_PM = 0,      /**< Сообщение отправляется от управляющего модуля (PM). */
	SETCAN_ROUTE_FROM_DEVICE = 1   /**< Сообщение отправляется от устройства (Device). */
} SetCanRouteType;

/**
 * @brief Типы сообщений CAN.
 *
 * Перечисление определяет различные типы сообщений, используемые в протоколе.
 */
typedef enum {
	SETCAN_MSGTYPE_BROADCAST = 0b0000,             /**< Широковещательное сообщение. */
	SETCAN_MSGTYPE_DISCRETE = 0b0001,              /**< Дискретное цифровое сообщение. */
	SETCAN_MSGTYPE_ANALOG = 0b0010,                /**< Аналоговое сообщение. */
	SETCAN_MSGTYPE_GENERAL_ADDRESS_SPACE = 0b0011, /**< Сообщение общего адресного пространства. */
	SETCAN_MSGTYPE_MODBUS_COIL = 0b0100,           /**< Сообщение Modbus - Coil. */
	SETCAN_MSGTYPE_MODBUS_DISCRETE = 0b0101,       /**< Сообщение Modbus - Discrete. */
	SETCAN_MSGTYPE_MODBUS_HOLDING = 0b0110,        /**< Сообщение Modbus - Holding. */
	SETCAN_MSGTYPE_MODBUS_INPUT = 0b0111,          /**< Сообщение Modbus - Input. */
	SETCAN_MSGTYPE_ERROR = 0b1000,                 /**< Сообщение об ошибке. */
	SETCAN_MSGTYPE_PULSE = 0b1111,                 /**< Импульсное сообщение. */
} SetCanMsgType;

/**
 * @brief Типы широковещательных сообщений CAN.
 *
 * Перечисление задает различные типы широковещательных команд, используемых в протоколе.
 */
typedef enum {
	SETCAN_BROADCAST_STATUS = 0b000000000000,       /**< Статус устройства. */
	SETCAN_BROADCAST_ONOFF = 0b000000000001,        /**< Включение/выключение устройства. */
	SETCAN_BROADCAST_RESTARTDEVICE = 0b000000000010, /**< Перезагрузка устройства. */
	SETCAN_BROADCAST_RTCSETUP = 0b000000000011,      /**< Настройка RTC (часы реального времени). */
	SETCAN_BROADCAST_END = 0b111111111111          /**< Конец диапазона широковещательных сообщений. */
} SetCanBroadcastType;

/**
 * @brief Структура и представление широковещательного сообщения CAN.
 *
 * Объединение позволяет обращаться к данным сообщения либо как к отдельным полям, либо как к целому 16-битному значению.
 */
typedef union{
    struct msgBody_Broadcast{
        unsigned Body:4; /**< Поле для дополнительных данных или кода задачи (4 бита). */
        SetCanBroadcastType Type:12; /**< Тип широковещательного сообщения (12 бит). */
    } Fields; /**< Структура с разбивкой по полям. */
    unsigned Body; /**< Общее 16-битное представление сообщения. */
} msgBodyBroadcastType;

/**
 * @brief Типы дискретных сообщений CAN.
 *
 * Перечисление задает различные виды дискретных команд или событий.
 */
typedef enum {
	SETCAN_DISCRETE_ACCIDENT = 0b0000,                       /**< Аварийное состояние. */
	SETCAN_DISCRETE_WARNING = 0b0001,                        /**< Предупредительный сигнал. */
	SETCAN_DISCRETE_CONTROL_SIGNALS = 0b0010,                /**< Управляющие сигналы. */
	SETCAN_DISCRETE_FLAGS = 0b0011,                          /**< Флаги состояния. */
	SETCAN_DISCRETE_RESET = 0b0100,                          /**< Сброс устройства. */
	SETCAN_DISCRETE_CHANGE_MODE = 0b0101,                    /**< Смена режима работы. */
	SETCAN_DISCRETE_REQUEST_LIST_OF_PARAMETERS = 0b0110,   /**< Запрос списка параметров. */
	SETCAN_DISCRETE_END = 0b1111                              /**< Конец диапазона дискретных сообщений. */
} SetCanDiscreteType;

/**
 * @brief Структура и представление дискретного сообщения CAN.
 *
 * Объединение позволяет обращаться к данным сообщения как к отдельным полям или как к целому 16-битному значению.
 */
typedef union{
    struct msgBody_Discrete{
        unsigned Body:12; /**< Поле данных или кода (12 бит). */
        SetCanDiscreteType Type:4; /**< Тип дискретного сообщения (4 бита). */
    } Fields; /**< Структура с разбивкой по полям. */
    unsigned Body; /**< Общее 16-битное представление сообщения. */
} msgBodyDiscreteType;

/**
 * @brief Типы аналоговых сообщений CAN.
 *
 * Перечисление определяет различные типы аналоговых данных или команд.
 */
typedef enum {
	SETCAN_ANALOG_UNIVERSAL = 0b0000,    /**< Универсальный тип. */
	SETCAN_ANALOG_SETTINGS = 0b0001,     /**< Настройки. */
	SETCAN_ANALOG_U = 0b0010,            /**< Напряжение (U). */
	SETCAN_ANALOG_I = 0b0011,            /**< Ток (I). */
	SETCAN_ANALOG_T = 0b0100,            /**< Температура (T). */
	SETCAN_ANALOG_END = 0b1111           /**< Конец диапазона типов. */
} SetCanAnalogType;

/**
 * @brief Структура и представление аналогового сообщения CAN.
 *
 * Объединение позволяет обращаться к данным сообщения как к отдельным полям или как к целому 16-битному значению.
 */
typedef union{
    struct msgBody_Analog{
        unsigned SensorID:12; /**< Идентификатор датчика (12 бит). */
        SetCanAnalogType Type:4; /**< Тип аналоговых данных (4 бита). */
    } Fields; /**< Структура с разбивкой по полям. */
    unsigned Body; /**< Общее 16-битное представление сообщения. */
} msgBodyAnalogType;

/**
 * @brief Структура и представление сообщения Modbus CAN.
 *
 * Объединение позволяет обращаться к данным как к отдельным полям или как к целому 16-битному значению.
 */
typedef union{
    struct msgBody_Modbus{
        unsigned RegCount:4; /**< Количество регистров (4 бита). */
        unsigned StrAdr:12;  /**< Адрес строки или регистра (12 бит). */
    } Fields; /**< Поля структуры сообщения Modbus. */
    unsigned Body; /**< Общее 16-битное представление сообщения. */
} msgBodyModbusType;

/**
 * @brief Структура и представление сообщения об ошибке CAN.
 *
 * Объединение позволяет обращаться к данным как к отдельным полям или как к целому 16-битному значению.
 */
typedef union{
    struct msgBody_Error{
        unsigned ErrorCode:8; /**< Код ошибки (8 бит). */
        unsigned Info:8;      /**< Дополнительная информация (8 бит). */
    } Fields; /**< Поля ошибки. */
    unsigned Body; /**< Общее 16-битное представление сообщения об ошибке. */
} msgBodyErrorType;

struct controlflags{
	unsigned IsPulse:1;
	unsigned IsRtrMode:1;
};

/**
 * @brief Поля идентификатора протокола CAN.
 *
 * Объединение позволяет обращаться к различным полям идентификатора, а также как к 29-битному целому числу.
 */
typedef union{
	struct SETCANIdFields{
		unsigned MsgBody:16;                 /**< Поле сообщения (16 бит). */
		SetCanMsgType MsgType:4;           /**< Тип сообщения (4 бита). */
		unsigned DeviceID:4;                 /**< Идентификатор устройства (4 бита). */
		unsigned DeviceType:3;               /**< Тип устройства (3 бита). */
		SetCanRouteType Route:1;           /**< Маршрут (1 бит). */
		SetCanPriorityType Priority:1;     /**< Приоритет (1 бит). */
	} Fields; /**< Структура с разбивкой по полям. */
  unsigned int BitAll:29; /**< Общее представление 29-битного идентификатора. */
} SetCanId_t;

/**
 * @brief Структура для общего адресного пространства CAN.
 *
 * Используется для хранения данных о регистре и его содержимом.
 */
typedef struct{
	struct SetCanCoreData{
		uint16_t Type;
		uint16_t Body;
		uint8_t *Data;
		unsigned DataCount;
	} CoreData;
	struct SetCanGeneralAddressSpaceData{
		uint16_t RegStartAdr; /**< Начальный адрес регистров. */
		uint16_t *Data; /**< Указатель на массив данных. */
		unsigned RegCount; /**< Количество регистров. */
	} GeneralAddressSpaceData;
	struct SetCanModbusData{
		uint16_t StrAdr;
		uint16_t *Data;
		unsigned RegCount:4;
	} ModbusData;
	struct SetCanErrorData{
		uint16_t Info;
		uint16_t Code;
	} ErrorData;
} SetCanData_t;

/**
 * @brief Структура данных устройства CAN.
 *
 * Включает статус, идентификатор, таймер последнего импульса и шаг последнего импульса.
 */
typedef struct{
	unsigned Status:1; /**< Статус устройства (флаг). */
	SetCanId_t Id; /**< Идентификатор CAN. */
	unsigned TimeFromLastPulse; /**< Время с последнего импульса (мс). */
	unsigned LastPulseStep; /**< Шаг последнего импульса. */
} SetCanDevice_t;

/**
 * @brief Структура для хранения сообщения RXCAN.
 */
struct RXMsg {
    /**
     * @brief Структура, содержащая флаги информации.
     */
    struct INFO {
        unsigned EXT : 1; /**< Бит расширенного идентификатора (EXT). */
        unsigned RTR : 1; /**< Бит запроса на передачу (RTR). */
    } info; /**< Информационные флаги сообщения. */
    SetCanId_t eID; /**< Идентификатор CAN-сообщения. */
    uint16_t DLC; /**< Длина данных (Data Length Code). */
    uint8_t Data[8]; /**< Массив данных (до 8 байт). */
};

uint16_t AvailableCanRxMsg(void);

SETCAN_INIT_StatusTypeDef SETCAN_INIT(CAN_HandleTypeDef *tmp_hcan,
																					RTC_HandleTypeDef *tmp_hrtc,
																					TIM_HandleTypeDef *tmp_tim);
void SETCAN_DEINIT(uint8_t stage);
void SETCAN_FILTERS(void);
void SETCAN_LoopProcessRxMsgs(void);
SETCAN_StatusTypeDef SETCAN_ProcessAllRxMsgs(void);
SETCAN_StatusTypeDef SETCAN_ProcessSingleRxMsg(void);
SETCAN_StatusTypeDef SETCAN_SEND(SetCanId_t id, SetCanData_t data);

void SetCanPulseCallback(TIM_HandleTypeDef *htim);
void SetCanRxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan);

SETCAN_StatusTypeDef SETCAN_BroadcastProcessing(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToBroadcastStatus(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToBroadcastOnOff(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToBroadcastRestart(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToBroadcastRtcSetup(struct RXMsg _rxMsg);

SETCAN_StatusTypeDef SETCAN_DiscreticProcessing(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToDiscreteAccident(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToDiscreteWarning(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToDiscreteControlSignals(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToDiscreteFlags(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToDiscreteReset(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToDiscreteChangeMode(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToDiscreteRequestListOfParameters(struct RXMsg _rxMsg);

SETCAN_StatusTypeDef SETCAN_AnalogProcessing(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToAnalogUniversal(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToAnalogSettings(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToAnalogUSens(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToAnalogISens(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToAnalogTSens(struct RXMsg _rxMsg);

SETCAN_StatusTypeDef SetCanMsgToGeneralAddressSpace(struct RXMsg _rxMsg);

SETCAN_StatusTypeDef SETCAN_RequestError(struct RXMsg _rxMsg);

SETCAN_StatusTypeDef SETCAN_ModbusProcessing(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToModbusCoil(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToModbusDiscrete(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToModbusHolding(struct RXMsg _rxMsg);
SETCAN_StatusTypeDef SetCanMsgToModbusInput(struct RXMsg _rxMsg);

void SETCAN_RTC_SYNC(uint8_t *data);

#endif
