/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "lwip.h"
#include "lwip/udp.h"
#include "lwip/debug.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "pribors.h"
#include <FLASH_SECTOR_F4.h>

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim3;

SRAM_HandleTypeDef hsram1;

/* USER CODE BEGIN PV */
// Счётчики которые висят на таймере
uint32_t br_counter = 0;
uint32_t rx_counter = 0;
uint32_t flash_counter = 0;
uint32_t pribor;									// Прибор в котором стоит ячейка
uint32_t pribor_type;								// Тип прибора в котором стоит ячейка
ip_addr_t rx_addr;									// Адрес с которого принят пакет.
// Флаги загрузки ячеек ЭМС/КЭМС
_Bool flag_load_ems_b0 = 0;
_Bool flag_load_ems_b1 = 0;
_Bool flag_load_kems_b = 0;
_Bool flag_load_ems_g = 0;
// Структуры принятого и отправленного сообщения
struct rcv_msg rx_msg;
struct tsm_msg tx_msg;

_Bool need_send_private = 0;						// Флаг, что нужно отправить персональный ответ.
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_FMC_Init(void);
static void MX_TIM3_Init(void);
/* USER CODE BEGIN PFP */
void write_isa(uint16_t addr, uint16_t data);
uint16_t read_isa(uint16_t addr);
void sock_init(struct udp_pcb * pcb);
void udp_echo_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
	    const ip_addr_t *addr, u16_t port);
void rcv_command(void);
uint16_t create_header(void);
void set_pbuf_params(struct pbuf *p, u16_t length);
_Bool load_flash_to_ems(uint32_t base_addr, uint16_t base_port);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  HAL_Delay(100);
  MX_LWIP_Init();
  MX_FMC_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  struct udp_pcb * pcb = udp_new();
  sock_init(pcb);
  memset(tx_msg.tx_buf, 0, sizeof tx_msg.tx_buf);
  struct pbuf *p = pbuf_alloc(0, sizeof tx_msg.tx_buf, PBUF_RAM);
  uint32_t br_addr = ipaddr_addr("10.1.1.255");
  u16_t br_port = 50000U;
  pribor = (((GPIOC->IDR) >> 6) & 0x7) | (((GPIOC->IDR) >> 9) & 0x18);
  // timer start
  if (HAL_TIM_Base_Start_IT(&htim3) != HAL_OK)
  {
    /* Starting Error */
    Error_Handler();
  }
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	MX_LWIP_Process();
	printf("aaa\n");
	if (need_send_private == 1)
	{
		need_send_private = 0;
		set_pbuf_params(p, tx_msg.status_len + tx_msg.cmd_len);
		err_t errok = udp_sendto(pcb, p, &rx_addr, rx_msg.port);
		br_counter = 0;
	}
	if (br_counter > 99)													// Широковещательный всётчик для отправки пакетов 100мс.
	{
		set_pbuf_params(p, create_header() + tx_msg.cmd_len);
		err_t errok = udp_sendto(pcb, p, (ip_addr_t*)&br_addr, br_port);
		br_counter = 0;
	}


	if (rx_msg.con_timeout > 1999)										// Таймаут соединения 2с
	{
		rx_msg.clnt_con = 0;
	}

	if (rx_counter > 30)												// Мигание светодиода на 30мс при приёме команды
	{
		HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);
	}

	if (flash_counter > 100)											// Таймер проверки загрежен ли флеш
	{
		flash_counter = 0;
		switch(pribor_type)
		{
			case PRIBOR_TYPE_UF:
			{
				if (flag_load_kems_b == 0) flag_load_kems_b = load_flash_to_ems(FLASH_BASE_WR, BASE_ADDR_KEMS_B);
				if (flag_load_ems_b0 == 0) flag_load_ems_b0 = load_flash_to_ems(FLASH_BASE_EMS_B0, BASE_ADDR_EMS_B0);
				if (flag_load_ems_b1 == 0) flag_load_ems_b1 = load_flash_to_ems(FLASH_BASE_EMS_B1, BASE_ADDR_EMS_B1);
				break;
			}
		}
	}

  }
  /* USER CODE END WHILE */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 100;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief TIM3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 22;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 2170;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  /* USER CODE END TIM3_Init 2 */

}

/* FMC initialization function */
static void MX_FMC_Init(void)
{

  /* USER CODE BEGIN FMC_Init 0 */

  /* USER CODE END FMC_Init 0 */

  FMC_NORSRAM_TimingTypeDef Timing = {0};

  /* USER CODE BEGIN FMC_Init 1 */

  /* USER CODE END FMC_Init 1 */

  /** Perform the SRAM1 memory initialization sequence
  */
  hsram1.Instance = FMC_NORSRAM_DEVICE;
  hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
  /* hsram1.Init */
  hsram1.Init.NSBank = FMC_NORSRAM_BANK1;
  hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
  hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
  hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16;
  hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
  hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
  hsram1.Init.WrapMode = FMC_WRAP_MODE_DISABLE;
  hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
  hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
  hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
  hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
  hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
  hsram1.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
  hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
  hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
  /* Timing */
  Timing.AddressSetupTime = 10;
  Timing.AddressHoldTime = 10;
  Timing.DataSetupTime = 15;
  Timing.BusTurnAroundDuration = 10;
  Timing.CLKDivision = 10;
  Timing.DataLatency = 10;
  Timing.AccessMode = FMC_ACCESS_MODE_A;


  if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
  {
    Error_Handler( );
  }

  /* USER CODE BEGIN FMC_Init 2 */

  /* USER CODE END FMC_Init 2 */
}

/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOE_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOG_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);

  /*Configure GPIO pins : PC13 PC6 PC7 PC8
                           PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8
                          |GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PC14 */
  GPIO_InitStruct.Pin = GPIO_PIN_14;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

uint16_t create_header(void)
{
	tx_msg.tx_buf[0] = 0;
	tx_msg.tx_buf[1] = 0;
	tx_msg.tx_buf[2] = rx_msg.rx_buf[2];
	tx_msg.tx_buf[3] = rx_msg.rx_buf[3];
	tx_msg.tx_buf[4] = 0;
	tx_msg.tx_buf[5] = 0;
	tx_msg.status_len = set_status(tx_msg.tx_buf, pribor) + 6;
	return tx_msg.status_len;
}

void set_pbuf_params(struct pbuf *p, u16_t length)
{
	p->len = length;
	p->tot_len = p->len;
	memcpy(p->payload, tx_msg.tx_buf, p->tot_len);
}

void sock_init(struct udp_pcb * pcb)
{
	uint32_t ipaddr = get_ip();
	u16_t port = get_port();
	err_t errok = udp_bind(pcb, (ip_addr_t*)&ipaddr, port);
	udp_recv(pcb, udp_echo_recv, NULL);
	rx_msg.port = 0;
	rx_msg.cmd_num = 0;
	rx_msg.cmd_code = 0;
	rx_msg.clnt_con = 0;
	rx_msg.length = 0;
	tx_msg.status_len = 0;
	tx_msg.cmd_len = 0;
	memset(rx_msg.rx_buf, 0, sizeof rx_msg.rx_buf);
	return;
}

void udp_echo_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
	    const ip_addr_t *addr, u16_t port)
{
    if (p != NULL) {
    	if (p->tot_len < sizeof rx_msg.rx_buf)
    	{
    		if (p->tot_len < 6)
			{
    			return;
			}
    		memcpy(rx_msg.rx_buf, p->payload, p->tot_len);
    		if (rx_msg.clnt_con == 1)
    		{
    			if ((memcmp(&rx_addr, addr, sizeof rx_addr)!= 0) || (rx_msg.port != port))
    			{
    				return;
    			}
    			uint16_t cmd_num = rx_msg.rx_buf[2] | (rx_msg.rx_buf[3] << 8);
				if (cmd_num != (rx_msg.cmd_num + 1))
				{
					return;
				}
    		}
    		else
    		{
    	    	memcpy(&rx_addr, addr, sizeof rx_addr);
        		rx_msg.port = port;
    		}
        	rx_msg.con_timeout = 0;
        	rx_msg.clnt_con = 1;
        	rx_msg.length = p->tot_len;
        	rcv_command();
    	}
        /* free the pbuf */
        pbuf_free(p);
    }
}

void rcv_command(void)
{
	uint16_t ports_amount = 0;
	uint16_t bytes_amount = 0;
	uint16_t len_block = 0;
	uint16_t i = 0;
	rx_msg.cmd_num = rx_msg.rx_buf[2] | (rx_msg.rx_buf[3] << 8);
	rx_msg.cmd_code = rx_msg.rx_buf[6];
	tx_msg.status_len = create_header();

	unsigned char *cmd_buf = &tx_msg.tx_buf[tx_msg.status_len];
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
	//tx_msg.tx_buf[5] = 1;
	rx_counter = 0;
	switch(rx_msg.cmd_code)		// код команды
	{
		case 0:
			//-----------------------------------------------------------
			// КОМАНДА №0
			// ЧТЕНИЕ МАССИВА ПОРТОВ
			//-----------------------------------------------------------

			cmd_buf[0] = rx_msg.cmd_code;	// - код команды
			ports_amount = rx_msg.rx_buf[7];

			// Проверка размера принятого буфера
			if( rx_msg.length < (8 + ports_amount * 2))
			{
				// Размер принятого пакета меньше чем долно быть
				// Установить ошибку
				// КОД = 2
				cmd_buf[1] = ERR_SIZE;

				// Установить размер буфера = 2
				tx_msg.cmd_len = 2;

			}
			else
			{
				// Установить ВЫПОЛНЕНО
				cmd_buf[1] = NO_ERROR;
				// Колличество прочитаных портов
				cmd_buf[2] = rx_msg.rx_buf[7];

				uint16_t port_data = 0xFFFF;
				uint16_t port_addr = 0x0000;
				for (i = 0; i<ports_amount; i++)
				{
					port_addr = rx_msg.rx_buf[8 + i * 2] + (rx_msg.rx_buf[9 + i * 2] << 8);
					cmd_buf[3 + (i*4)] = rx_msg.rx_buf[8 + i * 2];
					cmd_buf[4 + (i*4)] = rx_msg.rx_buf[9 + i * 2];
					port_data = read_isa(port_addr);
					cmd_buf[5 + (i*4)] = port_data & 0xFF;
					cmd_buf[6 + (i*4)] = port_data >> 8;
				}
				// Установить размер буфера
				tx_msg.cmd_len = (ports_amount << 2) + 3;
			}
			break;

		case 1:
			//-----------------------------------------------------------
			// КОМАНДА №1
			// ЗАПИСЬ МАССИВА ПОРТОВ
			//-----------------------------------------------------------

			cmd_buf[0] = rx_msg.cmd_code;	// - код команды
			ports_amount = rx_msg.rx_buf[7];

			// Проверка размера принятого буфера
			if( rx_msg.length < (8 + ports_amount * 4))
			{
				// Размер принятого пакета меньше чем долно быть
				// Установить ошибку
				// КОД = 2
				cmd_buf[1] = ERR_SIZE;

				// Установить размер буфера = 2
				tx_msg.cmd_len = 2;

			}
			else
			{
				// Установить ВЫПОЛНЕНО
				cmd_buf[1] = NO_ERROR;
				// Колличество записанных портов
				cmd_buf[2] = rx_msg.rx_buf[7];

				uint16_t port_data;
				uint16_t port_addr;
				for (i = 0; i<ports_amount; i++)
				{
					port_addr = rx_msg.rx_buf[8 + i * 4] + (rx_msg.rx_buf[9 + i * 4] << 8);
					port_data = rx_msg.rx_buf[10 + i * 4] + (rx_msg.rx_buf[11 + i * 4] << 8);
					cmd_buf[3 + (i*4)] = rx_msg.rx_buf[8 + i * 4];
					cmd_buf[4 + (i*4)] = rx_msg.rx_buf[9 + i * 4];
					write_isa(port_addr, port_data);
					port_data = read_isa(port_addr);
					cmd_buf[5 + (i*4)] = port_data & 0xFF;
					cmd_buf[6 + (i*4)] = port_data >> 8;
				}
				// Установить размер буфера
				tx_msg.cmd_len = (ports_amount << 2) + 3;
			}
			break;
		case 55:
			//-----------------------------------------------------------
			// КОМАНДА №55
			// ЗАПИСЬ МАССИВА В FLASH
			//-----------------------------------------------------------

			cmd_buf[0] = rx_msg.cmd_code;	// - код команды
			bytes_amount = rx_msg.rx_buf[10] + (rx_msg.rx_buf[11] << 8);

			// Проверка размера принятого буфера
			if( rx_msg.length < (10 + bytes_amount))
			{
				// Размер принятого пакета меньше чем долно быть
				// Установить ошибку
				// КОД = 2
				cmd_buf[1] = ERR_SIZE;

				// Установить размер буфера = 2
				tx_msg.cmd_len = 2;

			}
			else
			{
				// Установить ВЫПОЛНЕНО
				cmd_buf[1] = NO_ERROR;
				uint32_t sector = FLASH_BASE_WR;
				unsigned char flash_sector = rx_msg.rx_buf[7];
				if (flash_sector == 1) sector = FLASH_BASE_EMS_B0;
				if (flash_sector == 2) sector = FLASH_BASE_EMS_B1;
				uint16_t flash_addr = rx_msg.rx_buf[8] + (rx_msg.rx_buf[9] << 8);
				uint16_t  numofwords = (bytes_amount/4)+((bytes_amount%4)!=0);
				Flash_Write_Data(sector + flash_addr, (uint32_t *)&rx_msg.rx_buf[12], numofwords);
				// Установить размер буфера
				tx_msg.cmd_len = 2;
			}
			break;
		case 56:
			//-----------------------------------------------------------
			// КОМАНДА №56
			// ЧТЕНИЕ МАССИВА ИЗ FLASH
			//-----------------------------------------------------------

			cmd_buf[0] = rx_msg.cmd_code;	// - код команды
			// Проверка размера принятого буфера
			if( rx_msg.length < (8))
			{
				// Размер принятого пакета меньше чем долно быть
				// Установить ошибку
				// КОД = 2
				cmd_buf[1] = ERR_SIZE;

				// Установить размер буфера = 2
				tx_msg.cmd_len = 2;

			}
			else
			{
				uint32_t sector = FLASH_BASE_WR;
				unsigned char flash_sector = rx_msg.rx_buf[7];
				if (flash_sector == 1) sector = FLASH_BASE_EMS_B0;
				if (flash_sector == 2) sector = FLASH_BASE_EMS_B1;
				bytes_amount = rx_msg.rx_buf[10] + (rx_msg.rx_buf[11] << 8);

				// Установить ВЫПОЛНЕНО
				cmd_buf[1] = NO_ERROR;
				// Колличество записаных байт
				cmd_buf[2] = rx_msg.rx_buf[7];
				cmd_buf[3] = rx_msg.rx_buf[8];
				cmd_buf[4] = rx_msg.rx_buf[9];
				cmd_buf[5] = rx_msg.rx_buf[10];
				cmd_buf[6] = rx_msg.rx_buf[11];
				uint16_t flash_addr = rx_msg.rx_buf[8] + (rx_msg.rx_buf[9] << 8);
				uint16_t  numofwords = (bytes_amount/4)+((bytes_amount%4)!=0);
				Flash_Read_Data(sector + flash_addr, (uint32_t *)&cmd_buf[7], numofwords);
				// Установить размер буфера
				tx_msg.cmd_len = 7 + bytes_amount;
			}
			break;
		case 60:
				//-----------------------------------------------------------
				// КОМАНДА №60
				// ЗАПИСЬ МАССИВА В  ПОРТ
				//-----------------------------------------------------------

				cmd_buf[0] = rx_msg.cmd_code;	// - код команды
				len_block = rx_msg.rx_buf[7] + (rx_msg.rx_buf[8] << 8);	// - длинна блока данных в словах

				// Проверка размера принятого буфера
				if( rx_msg.length < (11 + len_block * 2))
				{
					// Размер принятого пакета меньше чем долно быть
					// Установить ошибку
					// КОД = 2
					cmd_buf[1] = ERR_SIZE;

					// Установить размер буфера = 2
					tx_msg.cmd_len = 2;

				}
				else
				{
					// Установить ВЫПОЛНЕНО
					cmd_buf[1] = NO_ERROR;
					// Колличество записанных портов
					cmd_buf[2] = rx_msg.rx_buf[7];
					cmd_buf[3] = rx_msg.rx_buf[8];
					cmd_buf[4] = rx_msg.rx_buf[9];
					cmd_buf[5] = rx_msg.rx_buf[10];

					uint16_t port_data;
					uint16_t port_addr;

					port_addr = rx_msg.rx_buf[9] + (rx_msg.rx_buf[10] << 8);
					for (i = 0; i<len_block; i++)
					{
						port_data = rx_msg.rx_buf[11 + i * 2] + (rx_msg.rx_buf[12 + i * 2] << 8);
						write_isa(port_addr, port_data);
					}
					// Установить размер буфера
					tx_msg.cmd_len = 6;
				}
				break;
		case 61:
				//-----------------------------------------------------------
				// КОМАНДА №61
				// ЧТЕНИЕ МАССИВА ИЗ ПОРТА
				//-----------------------------------------------------------

				cmd_buf[0] = rx_msg.cmd_code;	// - код команды
				len_block = rx_msg.rx_buf[7] + (rx_msg.rx_buf[8] << 8);	// - длинна блока данных в словах

				// Проверка размера принятого буфера
				if( rx_msg.length < 11 )
				{
					// Размер принятого пакета меньше чем долно быть
					// Установить ошибку
					// КОД = 2
					cmd_buf[1] = ERR_SIZE;

					// Установить размер буфера = 2
					tx_msg.cmd_len = 2;

				}
				else
				{
					// Установить ВЫПОЛНЕНО
					cmd_buf[1] = NO_ERROR;
					// Колличество прочитаных портов
					cmd_buf[2] = rx_msg.rx_buf[7];
					cmd_buf[3] = rx_msg.rx_buf[8];
					cmd_buf[4] = rx_msg.rx_buf[9];
					cmd_buf[5] = rx_msg.rx_buf[10];

					uint16_t port_data;
					uint16_t port_addr;

					port_addr = rx_msg.rx_buf[9] + (rx_msg.rx_buf[10] << 8);
					for (i = 0; i<len_block; i++)
					{
						port_data = read_isa(port_addr);
						cmd_buf[6 + (i*2)] = port_data & 0xFF;
						cmd_buf[7 + (i*2)] = port_data >> 8;
					}
					// Установить размер буфера
					tx_msg.cmd_len = 6 + len_block * 2;
				}
				break;
		case 70:
			//-----------------------------------------------------------
			// КОМАНДА №70
			// КОМАНДА ЗАПИСИ ФЛАГА О ОКОНЧАНИИ ЗАГРУЗКИ ЭМС-Г
			//-----------------------------------------------------------

			cmd_buf[0] = rx_msg.cmd_code;	// - код команды

			// Проверка размера принятого буфера
			if( rx_msg.length < (7))
			{
				// Размер принятого пакета меньше чем долно быть
				// Установить ошибку
				// КОД = 2
				cmd_buf[1] = ERR_SIZE;

				// Установить размер буфера = 2
				tx_msg.cmd_len = 2;

			}
			else
			{
				// Установить ВЫПОЛНЕНО
				cmd_buf[1] = NO_ERROR;
				flag_load_ems_g = 1;
				// Установить размер буфера
				tx_msg.cmd_len = 2;
			}
			break;
		default:
				{
					//-----------------------------------------------------------
					// НЕИЗВЕСТНАЯ КОМАНДА
					//-----------------------------------------------------------

					cmd_buf[0] = rx_msg.cmd_code;	// - код команды
					cmd_buf[1] = ERR_UNKNOW_COMMAND;
					tx_msg.cmd_len = 2;
				}
				break;
	}

	need_send_private = 1;

}

uint16_t read_isa(uint16_t addr)
{
    return *(uint16_t*)(ISA_BASE_RD + (addr << 1));
}

void write_isa(uint16_t addr, uint16_t data)
{
    *(uint16_t*)(ISA_BASE_WR + (addr << 1)) = data;
}

_Bool load_flash_to_ems(uint32_t base_addr, uint16_t base_port)
{
	_Bool load_ok = 0;
	uint16_t ports_data = 0, i = 0;
	uint32_t flash_data[2] = {0,0};
	write_isa(base_port + 0x2, 200);
	ports_data = read_isa(base_port + 0x2);
	if (ports_data != 200) return load_ok;
	for (i = 0; i<=WORDS_TO_KEMS; i++)
	{
		Flash_Read_Data(base_addr + i * 10, (uint32_t *)&flash_data, 1);
		write_isa(base_port + 0x2, flash_data[0]);
		Flash_Read_Data(base_addr + i * 10 + 2, (uint32_t *)&flash_data, 1);
		write_isa(base_port + 0x4, flash_data[0]);
		Flash_Read_Data(base_addr + i * 10 + 4, (uint32_t *)&flash_data, 1);
		write_isa(base_port + 0x6, flash_data[0]);
		Flash_Read_Data(base_addr + i * 10 + 6, (uint32_t *)&flash_data, 1);
		write_isa(base_port + 0x8, flash_data[0]);
		Flash_Read_Data(base_addr + i * 10 + 8, (uint32_t *)&flash_data, 1);
		write_isa(base_port + 0xa, flash_data[0]);
	}
	load_ok = 1;
	return load_ok;

}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
