Files
Balsam_167/Source/Internal/bios.c

472 lines
16 KiB
C
Raw 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.
/**
* @file bios.c
* @brief Сервисные команды удалённого доступа к памяти и загрузки программы.
*
* Реализует разбор BIOS-команд, формирование ответов, чтение/запись памяти,
* загрузку блоков и запуск кода через транспорт RS-485. Адреса и размеры
* приходят извне, поэтому корректность пакета и CRC должна быть подтверждена
* до вызова обработчиков. Прямой доступ к памяти преднамеренно использует
* volatile и требует адресов из допустимой карты памяти контроллера.
*/
/****************************************************************/
/* TMS320C32 */
/* ====== BIOS, КЛАИН, КЛВСП ====== */
/* ЦНИИ СЭТ (с) 1998-2000 г. */
/****************************************************************
Bios.c
**************************************************************
Основные комманды BIOS *
дла работы с RS232
****************************************************************/
#include "DSP2833x_Device.h" // DSP2833x Headerfile Include File
#include "RS485.h"
#include "bios_dsp.h"
#include "crc16.h"
#include "spise2p.h"
#include "log_to_mem.h"
//#include "flash_tools.h"
//#include "spartan_tools.h"
//#include "big_dsp_module.h"
int flag_DEBUG = false; /* Флаг отладочного режима */
//static unsigned int *RecvPtr;
//static int BS_LoadOK = false; /** Флаг успешности приема блока */
/**********************************************************/
/* Прототипы функций, используемых и определенных в файле */
/**********************************************************/
//static int _getbyte(int *addr, int offs);
/** @brief Читает одно volatile-слово из физического адресного пространства DSP. */
unsigned int read_memory(unsigned long addr)
{
return (*(volatile int *)(addr));
}
/** @brief Записывает одно слово data по физическому адресу addr. */
void write_memory(unsigned long addr, unsigned int data)
{
(*(volatile int *)( addr )) = data;
}
/** Возвращает номер комманды, если есть или -1 если транзакций не было */
/**
* @brief Проверяет и диспетчеризует полностью принятый сервисный кадр.
* @param rs_arr Порт и буфер принятой команды.
* @return Код распознанной команды либо признак ошибки кадра.
* @details Проверяет адрес, длину и CRC, затем вызывает обработчик CMD_*.
*/
int get_command(RS_DATA *rs_arr)
{
int cmd;
unsigned int crc, rcrc;
if(rs_arr->RS_DataReady) // Данные по RS пришли
{
rs_arr->RS_DataReady = false;
cmd = rs_arr->RS_Header[1]; // Прочитали номер команды
// Провераем длину команды дла считываниа CRC
if((RS_Len[cmd]<3) || (RS_Len[cmd]>MAX_RECEIVE_LENGTH))
{
RS_Line_to_receive(rs_arr); // режим приема RS485
RS_SetBitMode(rs_arr,9);
return -1;
}
if(cmd == CMD_LOAD) // Если команда загрузки
{
rs_arr->RS_PrevCmd = cmd;
return cmd; // Нет проверки crc
}
else // Все остальные команды
{
// Считываем crc из посылки
crc = (rs_arr->RS_Header[RS_Len[cmd]-1] << 8) |
(rs_arr->RS_Header[RS_Len[cmd]-2]) ;
}
// Рассчитываем crc из посылки
rcrc = 0xffff;
rcrc = get_crc_16( rcrc, rs_arr->RS_Header, (RS_Len[cmd]-2) );
if(crc == rcrc) // Провераем crc
{
rs_arr->RS_PrevCmd = cmd;
return cmd;
}
else
{
RS_Line_to_receive(rs_arr); // режим приема RS485
RS_SetBitMode(rs_arr,9);
} }
return -1;
}
/** Стандартный ответ, без параметров */
/**
* @brief Добавляет CRC и отправляет n слов ответа через исходный порт.
* @param rs_arr Порт, через который пришёл запрос.
* @param n Число информационных слов до CRC.
*/
void Answer(RS_DATA *rs_arr,int n)
{
int crc;
flag_DEBUG = true; // Флаг отладочного режима
rs_arr->buffer[0] = rs_arr->addr_recive; //CNTRL_ADDR;
rs_arr->buffer[1] = n;
crc = 0xffff;
crc = get_crc_16( crc, rs_arr->buffer, 2);
rs_arr->buffer[2] = LOBYTE(crc);
rs_arr->buffer[3] = HIBYTE(crc);
rs_arr->buffer[4] = 0;
rs_arr->buffer[5] = 0;
RS_Send(rs_arr,rs_arr->buffer, 6);
}
/* Внутреннаа ф-циа */
static char _getbyte(unsigned int *addr, int32 offs)
{
unsigned int *address;
unsigned int byte;
address = addr + offs/2;
byte = *address;
if(offs%2) return LOBYTE(byte);
else return HIBYTE(byte);
}
/* начальные установки (не работает)*/
/** @brief Сбрасывает параметры текущей загрузочной сессии и подтверждает команду. */
void init(RS_DATA *rs_arr)
{
/*
if(rs_arr->RS_Header[2]==3)
{
if (rs_arr->curr_baud!=57600)
{ RS_SetLineSpeed(rs_arr,57600);
rs_arr->curr_baud= 57600;
} }
if(rs_arr->RS_Header[2]==4)
{
if (rs_arr->curr_baud!=115200)
{ RS_SetLineSpeed(rs_arr,115200);
rs_arr->curr_baud= 115200;
} }
Answer(rs_arr,CMD_INIT);
rs_arr->BS_LoadOK = false;
*/
}
/**@name Комманды
* Комманды, вызываемые через последовательный канал
*/
//@{
/** Инициировать загрузку блока.
Настраивает прием блока данных */
/**
* @brief Принимает заголовок нового образа и подготавливает диапазон загрузки.
* @details Из кадра извлекаются начальный адрес, длина и контрольные параметры;
* запись данных разрешается только после успешной проверки заголовка.
*/
void initload(RS_DATA *rs_arr)
{
unsigned long Address;
Address = rs_arr->RS_Header[5] & 0xFF;
Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);
rs_arr->RS_Length = rs_arr->RS_Header[9] & 0xFF;
rs_arr->RS_Length = (rs_arr->RS_Length<<8) | (rs_arr->RS_Header[8] & 0xFF);
rs_arr->RS_Length = (rs_arr->RS_Length<<8) | (rs_arr->RS_Header[7] & 0xFF);
rs_arr->RS_Length = (rs_arr->RS_Length<<8) | (rs_arr->RS_Header[6] & 0xFF);
rs_arr->RS_Length += 2;
rs_arr->pRS_RecvPtr = (unsigned int *)Address; //(unsigned int *)Address;
rs_arr->pRecvPtr = (unsigned int *)Address; //(unsigned int *)Address;
no_write = 1;
Answer(rs_arr,CMD_INITLOAD);
}
/** Загрузка блока.
Вызываетса после загрузки блока через RS */
/**
* @brief Записывает очередную порцию образа по текущему адресу загрузки.
* @post Рабочий адрес и остаток длины продвинуты на принятый блок.
*/
void load(RS_DATA *rs_arr)
{
unsigned int rcrc, crc;
crc = (_getbyte(rs_arr->pRecvPtr, rs_arr->RS_Length-1) << 8) +
_getbyte(rs_arr->pRecvPtr, rs_arr->RS_Length-2);
rs_arr->RS_Header[0] = rs_arr->addr_recive;
// CNTRL_ADDR;
rs_arr->RS_Header[1]=CMD_LOAD;
rcrc = 0xffff;
rcrc = get_crc_16( rcrc, rs_arr->RS_Header, 2);
rcrc = get_crc_16b( rcrc, rs_arr->pRecvPtr, rs_arr->RS_Length-2);
if(rcrc == crc)
{
Answer(rs_arr,CMD_LOAD);
rs_arr->BS_LoadOK = true;
}
else
{
rs_arr->BS_LoadOK = false;
RS_Line_to_receive(rs_arr); // режим приема RS485
RS_SetBitMode(rs_arr,9);
} }
/** Выполнить программу в формате Serial Boot.
@precondition Должна быть произведена загрузка блока
Адрес программы беретса из заголовка и
сравниваетса с переменной RecvPtr, заполнаемой в ф-ции load
@see load */
/** @brief Подтверждает команду и передаёт управление загруженной программе. */
void run (RS_DATA *rs_arr)
{
return;
}
/** Прочитать ачейку памати */
/**
* @brief Возвращает содержимое заданного диапазона памяти.
* @warning Диапазон должен быть предварительно разрешён протокольным уровнем.
*/
void peek(RS_DATA *rs_arr)
{
unsigned long Address;
unsigned int Data, crc;
flag_DEBUG = true; // Флаг отладочного режима
Address = rs_arr->RS_Header[5] & 0xFF;
Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);
if(Address<PROM_LEN)
Seeprom_read(Address,(unsigned int *)&Data,2);
else Data = read_memory(Address);
rs_arr->buffer[0] = rs_arr->addr_recive; //CNTRL_ADDR;
rs_arr->buffer[1] = CMD_PEEK;
rs_arr->buffer[2] = LOBYTE(Data);
rs_arr->buffer[3] = HIBYTE(Data);
rs_arr->buffer[4] = LOBYTE(CpuTimer2.InterruptCount);
rs_arr->buffer[5] = HIBYTE(CpuTimer2.InterruptCount);
crc = 0xffff;
crc = get_crc_16(crc, rs_arr->buffer, 6);
rs_arr->buffer[6] = LOBYTE(crc);
rs_arr->buffer[7] = HIBYTE(crc);
rs_arr->buffer[8] = 0;
rs_arr->buffer[9] = 0;
RS_Send(rs_arr,rs_arr->buffer, 10);
}
/** Записать в ачейку памати */
/** @brief Записывает данные команды в заданную область памяти и отвечает статусом. */
void poke(RS_DATA *rs_arr)
{
unsigned long Address;
unsigned int Data;
Address = rs_arr->RS_Header[5] & 0xFF;
Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);
Data = 0;
Data = (Data<<8) | (rs_arr->RS_Header[7] & 0xFF);
Data = (Data<<8) | (rs_arr->RS_Header[6] & 0xFF);
if(Address<PROM_LEN)
Seeprom_write(Address,(unsigned int *)&Data,2);
else write_memory(Address,Data);
Answer(rs_arr,CMD_POKE);
}
/** Передать блок памати */
/** @brief Передаёт ведущему очередной блок ранее выбранной области памяти. */
void upload(RS_DATA *rs_arr)
{
int32 Address, Length, crc;
no_write = 1; // Флаг отладочного режима
// stopp=1;
Address = rs_arr->RS_Header[5] & 0xFF;
Address = (Address<<8) | (rs_arr->RS_Header[4] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[3] & 0xFF);
Address = (Address<<8) | (rs_arr->RS_Header[2] & 0xFF);
Length = rs_arr->RS_Header[9] & 0xFF;
Length = (Length<<8) | (rs_arr->RS_Header[8] & 0xFF);
Length = (Length<<8) | (rs_arr->RS_Header[7] & 0xFF);
Length = (Length<<8) | (rs_arr->RS_Header[6] & 0xFF);
rs_arr->buffer[0] = rs_arr->addr_recive; //CNTRL_ADDR;
rs_arr->buffer[1] = CMD_UPLOAD;
crc = 0xffff;
crc = get_crc_16( crc, rs_arr->buffer, 2);
crc = get_crc_16b( crc, (unsigned int *)Address, Length);
RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу
rs_arr->buffer[0] = CMD_UPLOAD;
RS_Send(rs_arr,rs_arr->buffer, 1); // <=2 байт по флагу
RS_Wait4OK(rs_arr);
RS_BSend(rs_arr,(unsigned int*)Address, Length);
RS_Wait4OK(rs_arr);
rs_arr->buffer[0] = LOBYTE(crc);
rs_arr->buffer[1] = HIBYTE(crc);
rs_arr->buffer[2] = 0;
rs_arr->buffer[3] = 0;
RS_Send(rs_arr,rs_arr->buffer, 4+2);
}
/** Прошить XILINX.
@precondition Должна быть произведена загрузка блока
Адрес и длина прошивки беретса из заголовка и
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load,
так же смотрит магическое слово в начале прошивки
@see load */
/** @brief Обрабатывает совместимую команду программирования внешней логики. */
void xflash(RS_DATA *rs_arr)
{
return;
}
/** Прошить TMS.
@precondition Должна быть произведена загрузка блока
Адрес и длина прошивки беретса из заголовка и
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
@see load */
/** @brief Обрабатывает команду программирования памяти целевого контроллера. */
void tflash(RS_DATA *rs_arr)
{
// volatile unsigned long Address1,Address2;
// volatile unsigned long Length, LengthW;
/*
if(!rs_arr->BS_LoadOK)
{
RS_Line_to_receive(rs_arr); // режим приема RS485
RS_SetBitMode(rs_arr,9);
return;
}
Address1 = rs_arr->RS_Header[5] & 0xFF;
Address1 = (Address1<<8) | (rs_arr->RS_Header[4] & 0xFF);
Address1 = (Address1<<8) | (rs_arr->RS_Header[3] & 0xFF);
Address1 = (Address1<<8) | (rs_arr->RS_Header[2] & 0xFF);
Address2 = rs_arr->RS_Header[9] & 0xFF;
Address2 = (Address2<<8) | (rs_arr->RS_Header[8] & 0xFF);
Address2 = (Address2<<8) | (rs_arr->RS_Header[7] & 0xFF);
Address2 = (Address2<<8) | (rs_arr->RS_Header[6] & 0xFF);
Length = rs_arr->RS_Header[13] & 0xFF;
Length = (Length<<8) | (rs_arr->RS_Header[12] & 0xFF);
Length = (Length<<8) | (rs_arr->RS_Header[11] & 0xFF);
Length = (Length<<8) | (rs_arr->RS_Header[10] & 0xFF);
LengthW = Length/2;
if (LengthW*2<Length) LengthW++;
if( (Address2 < 0x100000) || (Address2 > 0x180000) || ((Address2+LengthW) > 0x180000) )
{
RS_Line_to_receive(rs_arr); // режим приема RS485
RS_SetBitMode(rs_arr,9);
return;
}
run_flash_data(Address1,Address2, LengthW );
Answer(rs_arr,CMD_TFLASH);
*/
return;
}
/** Прошить TMS.
@precondition Должна быть произведена загрузка блока
Адрес и длина прошивки беретса из заголовка и
сравниваетса с переменными RecvPtr и Length, заполнаемыми в ф-ции load
@see load */
/**
* @brief Выполняет расширенную BIOS-команду, не входящую в базовый набор.
* @details Подкоманда и её аргументы извлекаются из принятого сервисного кадра.
*/
void extendbios(RS_DATA *rs_arr)
{
volatile unsigned long Address1,Address2,Length;
unsigned int code;
Address1 = rs_arr->RS_Header[5] & 0xFF;
Address1 = (Address1<<8) | (rs_arr->RS_Header[4] & 0xFF);
Address1 = (Address1<<8) | (rs_arr->RS_Header[3] & 0xFF);
Address1 = (Address1<<8) | (rs_arr->RS_Header[2] & 0xFF);
Address2 = rs_arr->RS_Header[9] & 0xFF;
Address2 = (Address2<<8) | (rs_arr->RS_Header[8] & 0xFF);
Address2 = (Address2<<8) | (rs_arr->RS_Header[7] & 0xFF);
Address2 = (Address2<<8) | (rs_arr->RS_Header[6] & 0xFF);
Length = rs_arr->RS_Header[13] & 0xFF;
Length = (Length<<8) | (rs_arr->RS_Header[12] & 0xFF);
Length = (Length<<8) | (rs_arr->RS_Header[11] & 0xFF);
Length = (Length<<8) | (rs_arr->RS_Header[10] & 0xFF);
code=rs_arr->RS_Header[14] & 0xFF;
switch ( code )
{
// Прошиваем EPROM Из RAM
case 4: Seeprom_write(Address1,(unsigned int*)Address2,Length);
break;
// Читаем из EPROM в RAM
case 5: Seeprom_read(Address1,(unsigned int*)Address2,Length);
break;
default:
return;
}
Answer(rs_arr,CMD_EXTEND);
return;
}
//@}