6880a47b46
git-svn-id: file:///srv/dev-disk-by-uuid-17e88007-4d0c-45e0-8757-cacfcc458630/repositories/svn/Diplomarbeit@111 9fe90eed-be63-e94b-8204-d34ff4c2ff93
621 lines
15 KiB
C
621 lines
15 KiB
C
/* ---------------------------------------------------------------------------
|
|
* IspProtocol.c - v0.1 (c) 2008 Micro-key bv
|
|
* ---------------------------------------------------------------------------
|
|
* Micro-key bv
|
|
* Industrieweg 28, 9804 TG Noordhorn
|
|
* Postbus 92, 9800 AB Zuidhorn
|
|
* The Netherlands
|
|
* Tel: +31 594 503020
|
|
* Fax: +31 594 505825
|
|
* Email: support@microkey.nl
|
|
* Web: www.microkey.nl
|
|
* ---------------------------------------------------------------------------
|
|
* Description:
|
|
* ---------------------------------------------------------------------------
|
|
* Version(s): 0.1, Feb 13, 2008, FSc
|
|
* Creation.
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* System include files
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Application include files
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
#include "types.h"
|
|
#include "IspProtocol.h"
|
|
#include "InternalFlash.h"
|
|
#include "Crc.h"
|
|
#include "Leds.h"
|
|
#include "appImage.h"
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Local constant and macro definitions
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
#define MAX_ADMINS (4)
|
|
#define START_BYTE (0xAA)
|
|
#define MAX_PAYLOAD_SIZE (80)
|
|
|
|
#define MSGID_ACKNOWLEDGE (0x01)
|
|
#define MSGID_UNLOCK (0x02)
|
|
#define MSGID_ERASEBLOCK (0x03)
|
|
#define MSGID_PROGRAMFLASH (0x04)
|
|
#define MSGID_VERIFYFLASH (0x05)
|
|
#define MSGID_FINISHPROGRAMMING (0x06)
|
|
#define MSGID_STARTPROGRAM (0x07)
|
|
|
|
#define APP_FLASH_START_ADDR (0x00005000)
|
|
#define APP_FLASH_END_ADDR (0x0007DFFF)
|
|
#define APP_FLASH_START_SECTOR (5)
|
|
#define APP_FLASH_END_SECTOR (27)
|
|
#define APP_IMAGE_LENGTH_OFFS 0x0008
|
|
#define APP_IMAGE_CRC_OFFS 0x000C
|
|
|
|
#define PROGRAM_BLOCK_SIZE (256)
|
|
#define INVALID_ADDRESS (0xFFFFFFFF)
|
|
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Global variable definitions
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Local variable definitions
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
typedef enum
|
|
{
|
|
IDLE,
|
|
MESSAGE_ID,
|
|
PAYLOAD_SIZE,
|
|
PAYLOAD,
|
|
CRC
|
|
} t_isp_decodestatus;
|
|
|
|
typedef struct t_ISP_MESSAGE {
|
|
UINT8 messageId;
|
|
UINT8 payloadSize;
|
|
UINT8 payload[MAX_PAYLOAD_SIZE];
|
|
UINT16 crc;
|
|
} t_isp_message;
|
|
|
|
typedef struct t_ISP_ADMIN {
|
|
t_isp_decodestatus status;
|
|
UINT8 rxIndex;
|
|
UINT16 rxCrc;
|
|
t_isp_message rxMessage;
|
|
t_isp_ack_callback ackCallback;
|
|
} t_isp_admin;
|
|
|
|
static t_isp_admin ispAdmins[MAX_ADMINS];
|
|
static UINT8 lastReservedAdmin = 0;
|
|
static UINT32 maxProgrammedAddress = 0;
|
|
static UINT32 startAddress = INVALID_ADDRESS;
|
|
static UINT8 verifyBlock[PROGRAM_BLOCK_SIZE] __attribute__((aligned(PROGRAM_BLOCK_SIZE)));
|
|
static UINT8 programBlock[PROGRAM_BLOCK_SIZE] __attribute__((aligned(PROGRAM_BLOCK_SIZE)));
|
|
static UINT8 programFirstBlock[PROGRAM_BLOCK_SIZE] __attribute__((aligned(PROGRAM_BLOCK_SIZE)));
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
* Local function definitions
|
|
* ---------------------------------------------------------------------------
|
|
*/
|
|
void sendAcknowledge(t_isp_admin *handle, t_isp_responses response);
|
|
BOOLEAN ValidMessageId( UINT8 messageId);
|
|
void handleMessage(t_isp_admin *admin);
|
|
void handleUnlockMessage(t_isp_admin *admin);
|
|
void handleEraseBlockMessage(t_isp_admin *admin);
|
|
void handleStartProgram(t_isp_admin *admin);
|
|
void handleFinishProgramming(t_isp_admin *admin);
|
|
void handleVerifyFlashMessage(t_isp_admin *admin);
|
|
void handleProgramFlashMessage(t_isp_admin *admin);
|
|
iflashresult fillProgramBlock( UINT32 address, UINT8 size, UINT8 *data);
|
|
iflashresult programFlash();
|
|
void resetRamBlock( UINT32 address );
|
|
iflashresult StoreCrcAndLength( UINT32 imageSize );
|
|
|
|
|
|
|
|
/** \brief Initialises a instance of the ISP-protocol handler.
|
|
*
|
|
* For each communication port, one ISP-protocol handler must be initialised.
|
|
*
|
|
* \param ackCallback Callback-function used for parent to send acknowledge
|
|
* \returns handle Handle for this ISP-protocol handler.
|
|
*/
|
|
int ispInitProtocol(t_isp_ack_callback ackCallback )
|
|
{
|
|
int result;
|
|
if (lastReservedAdmin < MAX_ADMINS)
|
|
{
|
|
ispAdmins[lastReservedAdmin].status = IDLE;
|
|
ispAdmins[lastReservedAdmin].ackCallback = ackCallback;
|
|
|
|
result = lastReservedAdmin;
|
|
lastReservedAdmin++;
|
|
}
|
|
else
|
|
{
|
|
result = -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/** \brief Does the protocol handling by parsing each byte received on the communication port.
|
|
*
|
|
* \param handle Handle for the ISP-protocol handler
|
|
* \param byte The received byte on the communication port
|
|
*/
|
|
void ispHandleRxByte( int handle, UINT8 byte )
|
|
{
|
|
t_isp_admin *admin = &(ispAdmins[handle]);
|
|
|
|
switch( admin->status )
|
|
{
|
|
case(IDLE):
|
|
if (byte == START_BYTE)
|
|
{
|
|
admin->status = MESSAGE_ID;
|
|
}
|
|
break;
|
|
case(MESSAGE_ID):
|
|
if (ValidMessageId(byte) == TRUE )
|
|
{
|
|
// Determine Payload-size
|
|
admin->rxCrc = crcCalc(&byte, 1, 0);
|
|
admin->rxMessage.messageId = byte;
|
|
admin->status = PAYLOAD_SIZE;
|
|
}
|
|
else
|
|
{
|
|
sendAcknowledge( admin, ISP_INVALID_MESSAGE_ID );
|
|
admin->status = IDLE;
|
|
}
|
|
break;
|
|
case(PAYLOAD_SIZE):
|
|
// Determine Payload-size
|
|
if (byte <=MAX_PAYLOAD_SIZE)
|
|
{
|
|
admin->rxMessage.payloadSize = byte;
|
|
admin->rxCrc = crcCalc(&byte, 1, admin->rxCrc);
|
|
admin->rxIndex = 0;
|
|
if (byte > 0)
|
|
{
|
|
admin->status = PAYLOAD;
|
|
}
|
|
else
|
|
{
|
|
admin->status = CRC;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sendAcknowledge( admin, ISP_PAYLOAD_TOO_LARGE );
|
|
admin->status = IDLE;
|
|
}
|
|
break;
|
|
case(PAYLOAD):
|
|
admin->rxMessage.payload[ admin->rxIndex ] = byte;
|
|
admin->rxCrc = crcCalc(&byte, 1, admin->rxCrc);
|
|
admin->rxIndex++;
|
|
|
|
if (admin->rxIndex >= admin->rxMessage.payloadSize)
|
|
{
|
|
admin->rxIndex = 0;
|
|
admin->status = CRC;
|
|
}
|
|
break;
|
|
case(CRC):
|
|
// Receive and check CRC
|
|
if (admin->rxIndex == 0)
|
|
{
|
|
admin->rxMessage.crc = (byte << 8);
|
|
}
|
|
else
|
|
{
|
|
admin->rxMessage.crc |= (byte & 0x00FF);
|
|
}
|
|
|
|
admin->rxIndex++;
|
|
|
|
if (admin->rxIndex >= 2)
|
|
{
|
|
if (admin->rxCrc == admin->rxMessage.crc)
|
|
{
|
|
/* Crc was succesfully checked */
|
|
handleMessage(admin);
|
|
}
|
|
else
|
|
{
|
|
sendAcknowledge( admin, ISP_RECV_BAD_CRC );
|
|
}
|
|
admin->status = IDLE;
|
|
}
|
|
break;
|
|
default:
|
|
admin->status = IDLE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void handleMessage(t_isp_admin *admin)
|
|
{
|
|
switch( admin->rxMessage.messageId )
|
|
{
|
|
case(MSGID_UNLOCK):
|
|
//sendAcknowledge( admin, ISP_CMD_SUCCESS);
|
|
handleUnlockMessage( admin );
|
|
break;
|
|
case(MSGID_ERASEBLOCK):
|
|
handleEraseBlockMessage( admin );
|
|
break;
|
|
case(MSGID_PROGRAMFLASH):
|
|
handleProgramFlashMessage( admin );
|
|
break;
|
|
case(MSGID_VERIFYFLASH):
|
|
handleVerifyFlashMessage( admin );
|
|
break;
|
|
case(MSGID_FINISHPROGRAMMING):
|
|
handleFinishProgramming( admin );
|
|
break;
|
|
case(MSGID_STARTPROGRAM):
|
|
handleStartProgram( admin );
|
|
break;
|
|
default:
|
|
sendAcknowledge( admin, ISP_INVALID_MESSAGE_ID);
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOLEAN ValidMessageId( UINT8 messageId)
|
|
{
|
|
if ((messageId >= 0x01) && (messageId <= 0x07))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
void sendAcknowledge(t_isp_admin *handle, t_isp_responses response)
|
|
{
|
|
handle->ackCallback( response );
|
|
}
|
|
|
|
|
|
void handleUnlockMessage(t_isp_admin *admin)
|
|
{
|
|
iflashresult unlockResult = ISP_CMD_SUCCESS;
|
|
|
|
maxProgrammedAddress = 0;
|
|
unlockResult =iflashPrepare( APP_FLASH_START_SECTOR, APP_FLASH_END_SECTOR);
|
|
|
|
admin->ackCallback( (t_isp_responses)unlockResult );
|
|
}
|
|
|
|
void handleEraseBlockMessage(t_isp_admin *admin)
|
|
{
|
|
iflashresult result;
|
|
UINT8 blockNr;
|
|
|
|
// Extract block nr from message
|
|
blockNr = admin->rxMessage.payload[0];
|
|
|
|
if ( ( blockNr >= APP_FLASH_START_SECTOR)
|
|
&& ( blockNr <= APP_FLASH_END_SECTOR))
|
|
{
|
|
result = iflashErase( blockNr );
|
|
}
|
|
else
|
|
{
|
|
result = ISP_INVALID_SECTOR;
|
|
}
|
|
|
|
admin->ackCallback( (t_isp_responses)result );
|
|
}
|
|
|
|
void handleProgramFlashMessage(t_isp_admin *admin)
|
|
{
|
|
iflashresult result;
|
|
UINT32 address;
|
|
UINT8 size;
|
|
UINT8 *data;
|
|
UINT8 index = 0;
|
|
|
|
// Extract address, datalength & data from message
|
|
address = ispGet32bit(admin->rxMessage.payload, &index);
|
|
size = ispGet8bit(admin->rxMessage.payload, &index);
|
|
data = &(admin->rxMessage.payload[index]);
|
|
|
|
if (maxProgrammedAddress < address) maxProgrammedAddress = address;
|
|
|
|
if ( (address >= APP_FLASH_START_ADDR)
|
|
&& (address <= APP_FLASH_END_ADDR)
|
|
)
|
|
{
|
|
result = fillProgramBlock(address, size, data );
|
|
}
|
|
else
|
|
{
|
|
result = ISP_DST_ADDR_ERROR;
|
|
}
|
|
|
|
admin->ackCallback( (t_isp_responses)result );
|
|
}
|
|
|
|
void handleVerifyFlashMessage(t_isp_admin *admin)
|
|
{
|
|
iflashresult result;
|
|
UINT32 address;
|
|
UINT8 size;
|
|
UINT8 index = 0;
|
|
UINT8 bufferIdx;
|
|
|
|
// Extract address, datalength & data from message
|
|
address = ispGet32bit(admin->rxMessage.payload, &index);
|
|
size = ispGet8bit(admin->rxMessage.payload, &index);
|
|
for (bufferIdx = 0; bufferIdx < size; bufferIdx++)
|
|
{
|
|
verifyBlock[bufferIdx] = ispGet8bit(admin->rxMessage.payload, &index);
|
|
}
|
|
|
|
// Make size dividable by 4
|
|
size = size - (size % 4);
|
|
|
|
if ((size >= 4) && (address != APP_FLASH_START_ADDR))
|
|
{
|
|
result = iflashVerify( address, size, verifyBlock );
|
|
}
|
|
else
|
|
{
|
|
result = ISP_CMD_SUCCESS;
|
|
}
|
|
|
|
admin->ackCallback( (t_isp_responses)result );
|
|
}
|
|
|
|
void handleFinishProgramming(t_isp_admin *admin)
|
|
{
|
|
iflashresult result;
|
|
UINT32 imageSize;
|
|
|
|
// Program remaining block on flash
|
|
fillProgramBlock(0, 0, 0 );
|
|
|
|
// Calculate image length
|
|
imageSize = maxProgrammedAddress - APP_FLASH_START_ADDR;
|
|
|
|
// Calculate and store Crc & imageSize on flash
|
|
result = StoreCrcAndLength( imageSize );
|
|
|
|
admin->ackCallback( (t_isp_responses)result );
|
|
}
|
|
|
|
void handleStartProgram(t_isp_admin *admin)
|
|
{
|
|
//if (appiValidAppImageAvail() == TRUE)
|
|
{
|
|
ledSet( LED1, 0 );
|
|
ledSet( LED0, 0 );
|
|
|
|
appiJumpToAppImage();
|
|
}
|
|
//else
|
|
//{
|
|
// admin->ackCallback( ISP_BUSY );
|
|
//}
|
|
}
|
|
|
|
|
|
void ispAdd16bit(UINT8 *payloadlocation, UINT16 data)
|
|
{
|
|
UINT8 index = 0;
|
|
|
|
payloadlocation[index] = (UINT8)(data >> 8);
|
|
index++;
|
|
payloadlocation[index] = (UINT8)(data & 0x00FF);
|
|
}
|
|
|
|
|
|
void ispAdd32bit(UINT8 *payloadlocation, UINT32 data)
|
|
{
|
|
UINT8 index = 0;
|
|
|
|
payloadlocation[index] = (UINT8)(data >> 24);
|
|
index++;
|
|
payloadlocation[index] = (UINT8)(data >> 16);
|
|
index++;
|
|
payloadlocation[index] = (UINT8)(data >> 8);
|
|
index++;
|
|
payloadlocation[index] = (UINT8)(data & 0xFF);
|
|
|
|
}
|
|
|
|
UINT8 ispGet8bit(UINT8 *payload, UINT8 *payloadIndex)
|
|
{
|
|
UINT8 result;
|
|
|
|
result = (UINT8)payload[*payloadIndex];
|
|
(*payloadIndex)++;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
UINT16 ispGet16bit(UINT8 *payload, UINT8 *payloadIndex)
|
|
{
|
|
UINT16 result;
|
|
|
|
result = ((UINT16)payload[*payloadIndex]) << 8;
|
|
(*payloadIndex)++;
|
|
result += ((UINT16)payload[*payloadIndex] & 0x00FF);
|
|
(*payloadIndex)++;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
UINT32 ispGet32bit(UINT8 *payload, UINT8 *payloadIndex)
|
|
{
|
|
UINT32 result;
|
|
|
|
result = ((UINT32)payload[*payloadIndex]) << 24;
|
|
(*payloadIndex)++;
|
|
result += ((UINT32)payload[*payloadIndex]) << 16;
|
|
(*payloadIndex)++;
|
|
result += ((UINT32)payload[*payloadIndex]) << 8;
|
|
(*payloadIndex)++;
|
|
result += ((UINT32)payload[*payloadIndex] & 0x000000FF);
|
|
(*payloadIndex)++;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
iflashresult fillProgramBlock( UINT32 address, UINT8 size, UINT8 *data)
|
|
{
|
|
UINT32 programIndex;
|
|
UINT32 beginIndex;
|
|
UINT32 dataIndex;
|
|
UINT32 endIndex;
|
|
iflashresult result = ISP_CMD_SUCCESS;
|
|
|
|
if (data == 0)
|
|
{
|
|
// finish sending last block
|
|
if (startAddress > 0)
|
|
{
|
|
result = programFlash();
|
|
}
|
|
else
|
|
{
|
|
result = ISP_CMD_SUCCESS;
|
|
}
|
|
startAddress = INVALID_ADDRESS;
|
|
return result;
|
|
}
|
|
|
|
// Determine startAddress.
|
|
if (startAddress == INVALID_ADDRESS)
|
|
{
|
|
// Make sure address is alligned to 256
|
|
resetRamBlock(address - (address % PROGRAM_BLOCK_SIZE));
|
|
}
|
|
else
|
|
{
|
|
if (address > (startAddress + PROGRAM_BLOCK_SIZE))
|
|
{
|
|
result = programFlash();
|
|
resetRamBlock( address );
|
|
}
|
|
}
|
|
|
|
// Determine endIndex;
|
|
if ( (startAddress + PROGRAM_BLOCK_SIZE) > (address + size) )
|
|
{
|
|
endIndex = (address - startAddress) + size;
|
|
}
|
|
else
|
|
{
|
|
endIndex = PROGRAM_BLOCK_SIZE;
|
|
}
|
|
|
|
// Copy data into programblock
|
|
dataIndex = 0;
|
|
beginIndex = address - startAddress;
|
|
for (programIndex = beginIndex; programIndex < endIndex; programIndex++)
|
|
{
|
|
programBlock[programIndex] = data[dataIndex];
|
|
dataIndex++;
|
|
}
|
|
|
|
// if program block is full, program it
|
|
if (dataIndex < size)
|
|
{
|
|
result = programFlash();
|
|
resetRamBlock( startAddress + PROGRAM_BLOCK_SIZE );
|
|
|
|
// Copy rest in new block
|
|
endIndex = size - dataIndex;
|
|
for (programIndex = 0; programIndex < endIndex; programIndex++)
|
|
{
|
|
programBlock[programIndex] = data[dataIndex];
|
|
dataIndex++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((startAddress + PROGRAM_BLOCK_SIZE) == (address + size))
|
|
{
|
|
result = programFlash();
|
|
resetRamBlock( INVALID_ADDRESS );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void resetRamBlock( UINT32 address )
|
|
{
|
|
UINT32 programIndex;
|
|
|
|
startAddress = address;
|
|
for (programIndex = 0; programIndex < PROGRAM_BLOCK_SIZE; programIndex++)
|
|
{
|
|
programBlock[programIndex] = 0x00;
|
|
}
|
|
}
|
|
|
|
iflashresult programFlash()
|
|
{
|
|
UINT16 index;
|
|
|
|
if (startAddress != APP_FLASH_START_ADDR)
|
|
{
|
|
iflashPrepare( APP_FLASH_START_SECTOR, APP_FLASH_END_SECTOR);
|
|
return iflashProgram( startAddress, PROGRAM_BLOCK_SIZE, programBlock );
|
|
}
|
|
else
|
|
{
|
|
// keep copy of first block, programmed later at FinishedProgramming
|
|
for (index = 0; index < PROGRAM_BLOCK_SIZE; index++)
|
|
{
|
|
programFirstBlock[index] = programBlock[index];
|
|
}
|
|
|
|
return ISP_CMD_SUCCESS;
|
|
}
|
|
}
|
|
|
|
iflashresult StoreCrcAndLength( UINT32 imageSize )
|
|
{
|
|
static UINT16 crc = 0;
|
|
static UINT8 *image = 0;
|
|
|
|
// Calculate Crc over part before Length & CRC
|
|
crc = crcCalc(programFirstBlock, APP_IMAGE_LENGTH_OFFS, crc);
|
|
|
|
// Calculate Crc over part after Length & CRC in first program block
|
|
image = (UINT8 *)(programFirstBlock + APP_IMAGE_CRC_OFFS + 4);
|
|
crc = crcCalc(image, PROGRAM_BLOCK_SIZE - (APP_IMAGE_CRC_OFFS + 4), crc);
|
|
|
|
// Calculate Crc over rest of image already programmed
|
|
image = (UINT8 *)(APP_FLASH_START_ADDR + PROGRAM_BLOCK_SIZE);
|
|
crc = crcCalc(image, imageSize - PROGRAM_BLOCK_SIZE, crc);
|
|
|
|
// Fill in Length & CRC
|
|
ispAdd32bit(programFirstBlock + APP_IMAGE_LENGTH_OFFS, imageSize);
|
|
ispAdd16bit(programFirstBlock + APP_IMAGE_CRC_OFFS, crc);
|
|
|
|
// Program first block on flash
|
|
iflashPrepare( APP_FLASH_START_SECTOR, APP_FLASH_START_SECTOR);
|
|
return iflashProgram( APP_FLASH_START_ADDR, PROGRAM_BLOCK_SIZE, programFirstBlock );
|
|
}
|