0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-04-26 02:52:28 +00:00
Files
2022-01-04 12:22:53 +02:00

577 lines
18 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "app_cfg.h"
extern md5_context ctx;
extern unsigned char md5sum[16];
extern const unsigned char AES_init_vector[16];
extern T_Boot_record p_boot_rec1;
extern T_Boot_record p_boot_rec2;
extern unsigned char block[HEADER_BLOCK_SZ+10];
static INT32S g_destination; // Индекс записи об образе в массиве информации о принимаемых образах img_file_cbl
// Если 0 - программирование собственной FLASH микроконтроллера,
// Если не 0 - программирование другого микроконтроллера по CAN
static INT32U g_blocks_cnt;
static INT32U g_indx_in_block;
static INT32U g_file_remainder;
static INT32U g_addr;
static INT32U g_programmed_size; // Общее количество данных отправленных в процедуру программирования
static INT32U g_file_size;
static INT32S g_packets_cnt;
static INT32S g_session_begin;
static INT32S g_file_done;
static INT32U g_chank_size;
static INT8U *g_ptr_in_pack_buf;
int boot_encrypted;
static INT8U packet_buf[PACKET_1K_SIZE + PACKET_OVERHEAD];
INT8U file_size_str[FILE_SIZE_LENGTH+1];
INT8U file_name[FILE_NAME_LENGTH+1];
INT8U tmp_file_name[FILE_NAME_LENGTH+3];
extern INT8U chainCipherBlock[16]; // Buffer for Cipher Block
#define RCV_OK 0
#define RCV_ERROR -1
#define RCV_ABORT 1
#define RCV_TIMEOUT 2
#define IS_AF(c) ((c >= 'A') && (c <= 'F'))
#define IS_af(c) ((c >= 'a') && (c <= 'f'))
#define IS_09(c) ((c >= '0') && (c <= '9'))
#define ISVALIDHEX(c) IS_AF(c) || IS_af(c) || IS_09(c)
#define ISVALIDDEC(c) IS_09(c)
#define CONVERTDEC(c) (c - '0')
#define CONVERTHEX_alpha(c) (IS_AF(c) ? (c - 'A'+10) : (c - 'a'+10))
#define CONVERTHEX(c) (IS_09(c) ? (c - '0') : CONVERTHEX_alpha(c))
static INT32S Ymodem_packets_receiving(INT8U *data, INT32S *length, INT32U timeout);
static int Ymodem_packets_processing(INT32S pack_len);
static int Ymodem_pack_prg_to_FLASH(int pack_len);
static int Ymodem_pack_prg_by_CAN(int pack_len);
/*-------------------------------------------------------------------------------------------------------------
Прем пакетов по Y-Modem и программирование из во FLASH микроконтроллера
Состав пакетов Y-modem
[01] или [02] ( 01 - SOH, передача 128 байт пакета ) (02 - STX,передача 1024 байт пакета )
[indx]
[indx ^ 0xFF]
[data]....[data]
[crc hi] - первый байт контрольной суммы CRC16
[crc lo] - второй байт контрольной суммы CRC16
На первый пакет должен быть ответ - [0x06] [0x43] (ACK, CRC)
На последующие - [0x06] (ACK)
Если пакет с ошибкой то в ответ высылаеться - [0x15] (NAK)
Передатчик может отправить сигнал аборта - [0x41] или [0x61] (ABORT1, ABORT2)
В ответ должно быть выслано подтверждение абрта - [0x18] [0x18] (CA, CA)
В конце передачи файла передатчик высылает - [0x04] (EOT)
В ответ должен получить - [0x15] (NAK)
Потом снова высылает - [0x04] (EOT)
В ответ должен получить - [0x06] [0x43] (ACK, CRC)
-------------------------------------------------------------------------------------------------------------*/
INT32S Ymodem_programmator(void)
{
INT32S errors;
INT32S pack_len;
INT32S res;
errors = 0;
g_session_begin = 0;
g_packets_cnt = 0;
g_file_done = 0;
LCD_print_str("SER",0,0);
Send_byte(CRC16);
while (1)
{
switch (Ymodem_packets_receiving(packet_buf, &pack_len, NAK_TIMEOUT))
{
case RCV_OK:
errors = 0;
switch (pack_len)
{
case -1: // Получено два символа CA - сигнал аборта от передатчика
Send_byte(ACK);
return 0;
case 0: // RCV_OK и pack_len=0 означает получение символа EOT
if ( g_file_done == 1 )
{
Send_byte(NAK); // Отправка NAK в ответ на EOT означает окончание программирования файла
g_file_done = 0;
g_packets_cnt = 0;
}
else
{
Send_byte(ACK);
Send_byte(CRC16);
}
break;
default: // Получен нормальный пакет
if ( (packet_buf[PACKET_SEQNO_INDEX] & 0xff) != (g_packets_cnt & 0xff) )
{
Send_byte(NAK);
}
else
{
res = Ymodem_packets_processing(pack_len);
switch (res)
{
case ABORT_SESSION:
g_file_done = 0;
g_packets_cnt = 0;
Send_byte(CA); // Завершаем сессию в случае ошибки
Send_byte(CA);
return 0;
case FIRST_PACKET:
Send_byte(ACK); // Начинаем сессию
Send_byte(CRC16);
g_session_begin = 1;
break;
case NEXT_PACKET:
Send_byte(ACK); // Продолжаем сессию
break;
case SKIP_SESSION:
g_file_done = 0;
g_packets_cnt = 0;
Send_byte(NAK);
Send_byte(CRC16);
break;
}
}
}
break;
case RCV_ABORT:
Send_byte(CA);
Send_byte(CA);
return 0;
case RCV_ERROR:
// Либо произошел таймаут, либо пришел неизвестный символ
if ( g_session_begin > 0 )
{
errors++;
}
if ( errors > MAX_ERRORS )
{
Send_byte(CA);
Send_byte(CA);
return 0;
}
Send_byte(CRC16);
break;
case RCV_TIMEOUT:
Send_byte(CRC16);
break;
} // switch( Wait_Ymodem_packet(packet_data, &packet_length, NAK_TIMEOUT) )
} // while ( 1 )
}
/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void Decrypt_block(INT8U *buf, int len)
{
do
{
aesDecrypt(buf, chainCipherBlock); // Расшифровываем блок
buf += 16;
len -= 16;
}
while (len >= 16);
}
/*-------------------------------------------------------------------------------------------------------------
* Function Name : Str2Int
* Description : Convert a string to an integer
* Input 1 : - inputstr: The string to be converted
* - intnum: The intger value
* Output : None
* Return : 1: Correct
* 0: Error
-------------------------------------------------------------------------------------------------------------*/
INT32U Str2Int(INT8U *inputstr, INT32S *intnum)
{
INT32U i = 0, res = 0;
INT32U val = 0;
if ( inputstr[0] == '0' && (inputstr[1] == 'x' || inputstr[1] == 'X') )
{
if ( inputstr[2] == '\0' )
{
return 0;
}
for (i = 2; i < 11; i++)
{
if ( inputstr[i] == '\0' )
{
*intnum = val;
res = 1; /* return 1; */
break;
}
if ( ISVALIDHEX(inputstr[i]) )
{
val = (val << 4) + CONVERTHEX(inputstr[i]);
}
else
{
/* return 0; Invalid input */
res = 0;
break;
}
}
if ( i >= 11 ) res = 0; /* over 8 digit hex --invalid */
}
else /* max 10-digit decimal input */
{
for (i = 0; i < 11; i++)
{
if ( inputstr[i] == '\0' )
{
*intnum = val;
/* return 1; */
res = 1;
break;
}
else if ( (inputstr[i] == 'k' || inputstr[i] == 'K') && (i > 0) )
{
val = val << 10;
*intnum = val;
res = 1;
break;
}
else if ( (inputstr[i] == 'm' || inputstr[i] == 'M') && (i > 0) )
{
val = val << 20;
*intnum = val;
res = 1;
break;
}
else if ( ISVALIDDEC(inputstr[i]) ) val = val * 10 + CONVERTDEC(inputstr[i]);
else
{
/* return 0; Invalid input */
res = 0;
break;
}
}
if ( i >= 11 ) res = 0; /* Over 10 digit decimal --invalid */
}
return res;
}
/*-------------------------------------------------------------------------------------------------------------
Function Name : Receive_Packet
Description : Receive a packet from sender
Input 1 : - data
Input 2 : - length
Input 3 : - timeout
Output : *length:
0: end of transmission
-1: abort by sender
>0: packet length
Return : 0: normally return
-1: timeout or packet error
1: abort by user
-------------------------------------------------------------------------------------------------------------*/
static INT32S Ymodem_packets_receiving(INT8U *data, INT32S *length, INT32U timeout)
{
INT16U i, packet_size;
INT8U c;
*length = 0;
if ( Wait_byte(&c, timeout) != SUCCESS ) return RCV_TIMEOUT;
switch (c)
{
case SOH:
packet_size = PACKET_128B_SIZE;
break;
case STX:
packet_size = PACKET_1K_SIZE;
break;
case EOT:
return RCV_OK;
case CA:
if ( (Wait_byte(&c, timeout) == SUCCESS) && (c == CA) )
{
*length = -1;
return RCV_OK;
}
else
{
return RCV_ERROR;
}
case ABORT1:
case ABORT2:
return RCV_ABORT;
case 0x1B:
return RCV_ABORT;
default:
return RCV_ERROR;
}
*data = c;
for (i = 1; i < (packet_size + PACKET_OVERHEAD); i++)
{
if ( Wait_byte(data + i, timeout) != SUCCESS )
{
return RCV_ERROR;
}
}
if ( data[PACKET_SEQNO_INDEX] != ((data[PACKET_SEQNO_COMP_INDEX] ^ 0xff) & 0xff) )
{
return RCV_ERROR;
}
*length = packet_size;
return RCV_OK;
}
/*-------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------*/
static int Ymodem_packets_processing(INT32S pack_len)
{
int i;
T_img_file_cbl *p_img_file_cbl;
g_file_size = 0;
// Проверяем является ли это пустым пакетом от протокола Ymodem-а с PC
if ( (packet_buf[0] == SOH) && (packet_buf[1] == 00) && (packet_buf[2] == 0xFF) && (packet_buf[3] == 0x00) && (packet_buf[4] == 0x00) )
{
return ABORT_SESSION;
}
g_ptr_in_pack_buf = packet_buf + PACKET_HEADER;
// Первый пакет всегда содержит имя файла и размер
if ( g_packets_cnt == 0 )
{
// Прием имени файла
for (i = 0; i < FILE_NAME_LENGTH; i++)
{
file_name[i] = tolower(*g_ptr_in_pack_buf++);
if ( file_name[i] == 0 ) break;
}
file_name[i] = '\0';
// Прием размера файла
for (i = 0; i < FILE_SIZE_LENGTH; i++)
{
file_size_str[i] = *g_ptr_in_pack_buf++;
if ( file_size_str[i] == ' ' ) break;
}
file_size_str[i] = '\0';
Str2Int(file_size_str, (INT32S *)&g_file_size);
if ( g_destination == 0 )
{
// Проверить размер файла для записи
if ( g_file_size > (FLASH_AREA_SIZE - BOOTL_IMG_SIZE - sizeof(p_boot_rec1)) )
{
// Прерывание процесса если размер больше допустимого
return ABORT_SESSION;
}
}
g_blocks_cnt = 0;
g_indx_in_block = 0;
g_file_remainder = g_file_size;
g_packets_cnt++;
return FIRST_PACKET;
}
else
{
return Ymodem_pack_prg_to_FLASH(pack_len);
}
}
/*-------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------*/
static int Finish_file_program(void)
{
if ( g_packets_cnt < 2 )
{
return ERROR;
}
// Проверяем хэш записанных данных
md5_starts(&ctx);
md5_update(&ctx, (uint8 *)PROGRAMM_AREA_BEG_ADDR, p_boot_rec1.orig_img_size);
md5_finish(&ctx, md5sum);
if ( memcmp(p_boot_rec1.md5_hash, md5sum, 16) != 0 )
{
return ERROR;
}
// Записываем запись boot
g_addr = FLASH_AREA_ADDR + FLASH_AREA_SIZE - sizeof(p_boot_rec1);
__disable_interrupt();
Flash_ByteProgram(g_addr,(unsigned char *)&p_boot_rec1, sizeof(p_boot_rec1));
__enable_interrupt();
if ( memcmp((void *)g_addr, (void *)&p_boot_rec1, sizeof(p_boot_rec1)) != 0 ) // Проверка
{
LCD_show_programming_end(ERROR);
return ERROR;
}
LCD_show_programming_end(SUCCESS);
return SUCCESS;
}
/*-------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------*/
static int Ymodem_pack_prg_to_FLASH(int pack_len)
{
int i;
// Полученные в пакете данные разбиваем на блоки заданной длины которые программируем
do
{
// Перенос данных из пакета в блок
g_chank_size = HEADER_BLOCK_SZ - g_indx_in_block; // Рассчитываем количество свободного места в блоке
if ( g_chank_size > pack_len ) g_chank_size = pack_len; // Если места в блоке больше чем данных в пакете
if ( g_chank_size > g_file_remainder ) g_chank_size = g_file_remainder;
memcpy(block, g_ptr_in_pack_buf, g_chank_size);
g_indx_in_block += g_chank_size;
g_file_remainder -= g_chank_size;
g_ptr_in_pack_buf += g_chank_size;
// Программируем только когда наберется полный буфер размером HEADER_BLOCK_SZ или когда новых данных уже не поступит
if ( (g_file_remainder == 0) || (g_indx_in_block == HEADER_BLOCK_SZ) )
{
// Записываем блок во FLASH
if ( g_blocks_cnt == 0 )
{
// Проверяем хидер файла
memcpy(chainCipherBlock, (void *)AES_init_vector, 16);
aesInit(); // Init AES algorithm.
// Определяем зашифрован или нет файл
memcpy(&p_boot_rec1, &block[HEADER_BLOCK_SZ - sizeof(p_boot_rec1)], sizeof(p_boot_rec1));
if ( p_boot_rec1.magic_val != MAGIC_TAG )
{
Decrypt_block(block, HEADER_BLOCK_SZ);
memcpy(&p_boot_rec1, &block[HEADER_BLOCK_SZ - sizeof(p_boot_rec1)], sizeof(p_boot_rec1));
// Если не обнаружен в первом блоке MAGIC_TAG и до и после шифрования, то прерываем программирование
if ( p_boot_rec1.magic_val != MAGIC_TAG ) return ABORT_SESSION;
boot_encrypted = 1;
}
// Проверяем допустимость размера файла с образом программирования
if ( p_boot_rec1.orig_img_size > (FLASH_AREA_SIZE - BOOTL_IMG_SIZE - sizeof(p_boot_rec1)) )
{
return ABORT_SESSION; // У образа недопустимо большой размер
}
// Образы с установленны флагом сжатия не принимаються
if ( p_boot_rec1.compress_flag != 0 )
{
return ABORT_SESSION; // Сжатые файлы не обрабатываем
}
// Начинаем запись файлов во Flash
__disable_interrupt();
Flash_Init();
__enable_interrupt();
// Начинаем со стирания последнего сектора
__disable_interrupt();
Flash_SectorErase(FLASH_AREA_ADDR + FLASH_AREA_SIZE - ERASE_SECTOR_SIZE);
__enable_interrupt();
{
unsigned int n = p_boot_rec1.orig_img_size / ERASE_SECTOR_SIZE;
if ( (p_boot_rec1.orig_img_size % ERASE_SECTOR_SIZE) != 0 ) n++;
if ( n >= MAX_SECTOR_NUM ) n = MAX_SECTOR_NUM - 1; // Чтобы не повтороять повтороное стирание последнего сектора
// Стираем все изменяемые сектора
for (i = 0; i < n; i++)
{
__disable_interrupt();
Flash_SectorErase(FLASH_AREA_ADDR + BOOTL_IMG_SIZE + i * ERASE_SECTOR_SIZE);
__enable_interrupt();
}
}
g_programmed_size = 0;
g_addr = FLASH_AREA_ADDR + BOOTL_IMG_SIZE;
}
else
{
// Записываем данные во FLASH
if ( boot_encrypted == 1 )
{
Decrypt_block(block, g_chank_size);
}
__disable_interrupt();
Flash_ByteProgram(g_addr, block, g_chank_size); // Программирование
__enable_interrupt();
if ( memcmp((void *)g_addr, block, g_chank_size) != 0 ) // Проверка
{
return ABORT_SESSION;
}
g_addr += g_chank_size;
g_programmed_size += g_chank_size;
LCD_show_programming_progress(g_addr, g_programmed_size );
}
g_indx_in_block = 0;
g_blocks_cnt++;
}
if ( g_file_remainder == 0 )
{
// Завершаем запись во FLASH
if ( Finish_file_program() == SUCCESS )
{
g_file_done = 1;
return NEXT_PACKET;
}
else
{
return ABORT_SESSION;
}
}
pack_len = pack_len - g_chank_size;
}
while (pack_len != 0);
g_packets_cnt++;
return NEXT_PACKET;
}