/*
* Name: stk500protocol.c
* Project: AVR-Doper
* Author: Christian Starkjohann
* Creation Date: 2006-06-19
* Tabsize: 4
* Copyright: (c) 2006 by Christian Starkjohann, all rights reserved.
* License: Proprietary, see documentation.
* Revision: $Id: stk500protocol.c 242 2006-08-31 13:00:09Z cs $
*/
#include "hardware.h"
#include
#include
#include "oddebug.h"
#include "stk500protocol.h"
#include "utils.h"
#include "isp.h"
#include "hvprog.h"
#include "timer.h"
#include "vreg.h"
#define BUFFER_SIZE 281 /* results in 275 bytes max body size */
#define RX_TIMEOUT 200 /* timeout in milliseconds */
#define STK_TXMSG_START 5
static uchar rxBuffer[BUFFER_SIZE];
static uint rxPos;
static utilWord_t rxLen;
static uchar txBuffer[BUFFER_SIZE];
static uint txPos, txLen;
stkParam_t stkParam = {{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 4, 0, 50, 0, 1, 0x80,
2, 0, 0xaa, 0, 0, 0, 0, 0,
}};
utilDword_t stkAddress;
/* ------------------------------------------------------------------------- */
void stkIncrementAddress(void)
{
stkAddress.dword++;
}
/* ------------------------------------------------------------------------- */
static void stkSetTxMessage(uint len)
{
uchar *p = txBuffer, sum = 0;
*p++ = STK_STX;
*p++ = rxBuffer[1]; /* sequence number */
*p++ = utilHi8(len);
*p++ = len;
*p++ = STK_TOKEN;
txPos = 0;
len += 6;
txLen = len--;
p = txBuffer;
while(len--){
sum ^= *p++;
}
*p = sum;
DBG1(0xe0, txBuffer, txLen);
}
/* ------------------------------------------------------------------------- */
static void setParameter(uchar index, uchar value)
{
if(index == STK_PARAM_OSC_PSCALE){
HW_SET_T2_PRESCALER(value);
}else if(index == STK_PARAM_OSC_CMATCH){
OCR2 = value;
}
index &= 0x1f;
stkParam.bytes[index] = value;
}
static uchar getParameter(uchar index)
{
if(index == STK_PARAM_OSC_PSCALE)
return HW_GET_T2_PRESCALER();
if(index == STK_PARAM_OSC_CMATCH)
return OCR2;
index &= 0x1f;
return stkParam.bytes[index];
}
/* ------------------------------------------------------------------------- */
/* Use defines for the switch statement so that we can choose between an
* if()else if() and a switch/case based implementation. switch() is more
* efficient for a LARGE set of sequential choices, if() is better in all other
* cases.
*/
#if 0
#define SWITCH_START if(0){
#define SWITCH_CASE(value) }else if(cmd == (value)){
#define SWITCH_CASE2(v1,v2) }else if(cmd == (v1) || cmd == (v2)){
#define SWITCH_CASE3(v1,v2,v3) }else if(cmd == (v1) || cmd == (v2) || (cmd == v3)){
#define SWITCH_CASE4(v1,v2,v3,v4) }else if(cmd == (v1) || cmd == (v2) || cmd == (v3) || cmd == (v4)){
#define SWITCH_DEFAULT }else{
#define SWITCH_END }
#else
#define SWITCH_START switch(cmd){{
#define SWITCH_CASE(value) }break; case (value):{
#define SWITCH_CASE2(v1,v2) }break; case (v1): case(v2):{
#define SWITCH_CASE3(v1,v2,v3) }break; case (v1): case(v2): case(v3):{
#define SWITCH_CASE4(v1,v2,v3,v4) }break; case (v1): case(v2): case(v3): case(v4):{
#define SWITCH_DEFAULT }break; default:{
#define SWITCH_END }}
#endif
void stkEvaluateRxMessage(void) /* not static to prevent inlining */
{
uchar i, cmd;
utilWord_t len = {2}; /* defaults to cmd + error code */
void *param;
DBG1(0xf1, rxBuffer, rxLen.bytes[0]);
cmd = rxBuffer[STK_TXMSG_START];
txBuffer[STK_TXMSG_START] = cmd;
txBuffer[STK_TXMSG_START + 1] = STK_STATUS_CMD_OK;
param = &rxBuffer[STK_TXMSG_START + 1];
SWITCH_START
SWITCH_CASE(STK_CMD_SIGN_ON)
static PROGMEM uchar string[] = {8, 'S', 'T', 'K', '5', '0', '0', '_', '2', 0};
uchar *p = &txBuffer[STK_TXMSG_START + 2];
strcpy_P(p, string);
len.bytes[0] = 11;
SWITCH_CASE(STK_CMD_SET_PARAMETER)
setParameter(rxBuffer[STK_TXMSG_START + 1], rxBuffer[STK_TXMSG_START + 2]);
SWITCH_CASE(STK_CMD_GET_PARAMETER)
txBuffer[STK_TXMSG_START + 2] = getParameter(rxBuffer[STK_TXMSG_START + 1]);
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_OSCCAL)
txBuffer[STK_TXMSG_START + 1] = STK_STATUS_CMD_FAILED;
/* not yet implemented */
SWITCH_CASE(STK_CMD_LOAD_ADDRESS)
for(i=0;i<4;i++){
stkAddress.bytes[3-i] = rxBuffer[STK_TXMSG_START + 1 + i];
}
SWITCH_CASE(STK_CMD_SET_CONTROL_STACK)
/* AVR Studio sends:
1b 08 00 21 0e 2d
4c 0c 1c 2c 3c 64 74 66
68 78 68 68 7a 6a 68 78
78 7d 6d 0c 80 40 20 10
11 08 04 02 03 08 04 00
bf
*/
/* dummy: ignore */
SWITCH_CASE(STK_CMD_ENTER_PROGMODE_HVSP)
hvspEnterProgmode(param);
SWITCH_CASE(STK_CMD_LEAVE_PROGMODE_HVSP)
hvspLeaveProgmode(param);
SWITCH_CASE(STK_CMD_CHIP_ERASE_HVSP)
txBuffer[STK_TXMSG_START + 1] = hvspChipErase(param);
SWITCH_CASE(STK_CMD_PROGRAM_FLASH_HVSP)
txBuffer[STK_TXMSG_START + 1] = hvspProgramMemory(param, 0);
SWITCH_CASE(STK_CMD_READ_FLASH_HVSP)
len.word = 1 + hvspReadMemory(param, (void *)&txBuffer[STK_TXMSG_START + 1], 0);
SWITCH_CASE(STK_CMD_PROGRAM_EEPROM_HVSP)
txBuffer[STK_TXMSG_START + 1] = hvspProgramMemory(param, 1);
SWITCH_CASE(STK_CMD_READ_EEPROM_HVSP)
len.word = 1 + hvspReadMemory(param, (void *)&txBuffer[STK_TXMSG_START + 1], 1);
SWITCH_CASE(STK_CMD_PROGRAM_FUSE_HVSP)
txBuffer[STK_TXMSG_START + 1] = hvspProgramFuse(param);
SWITCH_CASE(STK_CMD_READ_FUSE_HVSP)
txBuffer[STK_TXMSG_START + 2] = hvspReadFuse(param);
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_PROGRAM_LOCK_HVSP)
txBuffer[STK_TXMSG_START + 1] = hvspProgramLock(param);
SWITCH_CASE(STK_CMD_READ_LOCK_HVSP)
txBuffer[STK_TXMSG_START + 2] = hvspReadLock();
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_READ_SIGNATURE_HVSP)
txBuffer[STK_TXMSG_START + 2] = hvspReadSignature(param);
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_READ_OSCCAL_HVSP)
txBuffer[STK_TXMSG_START + 2] = hvspReadOsccal();
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_ENTER_PROGMODE_PP)
ppEnterProgmode(param);
SWITCH_CASE(STK_CMD_LEAVE_PROGMODE_PP)
ppLeaveProgmode(param);
SWITCH_CASE(STK_CMD_CHIP_ERASE_PP)
txBuffer[STK_TXMSG_START + 1] = ppChipErase(param);
SWITCH_CASE(STK_CMD_PROGRAM_FLASH_PP)
txBuffer[STK_TXMSG_START + 1] = ppProgramMemory(param, 0);
SWITCH_CASE(STK_CMD_READ_FLASH_PP)
len.word = 1 + ppReadMemory(param, (void *)&txBuffer[STK_TXMSG_START + 1], 0);
SWITCH_CASE(STK_CMD_PROGRAM_EEPROM_PP)
txBuffer[STK_TXMSG_START + 1] = ppProgramMemory(param, 1);
SWITCH_CASE(STK_CMD_READ_EEPROM_PP)
len.word = 1 + ppReadMemory(param, (void *)&txBuffer[STK_TXMSG_START + 1], 1);
SWITCH_CASE(STK_CMD_PROGRAM_FUSE_PP)
txBuffer[STK_TXMSG_START + 1] = ppProgramFuse(param);
SWITCH_CASE(STK_CMD_READ_FUSE_PP)
txBuffer[STK_TXMSG_START + 2] = ppReadFuse(param);
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_PROGRAM_LOCK_PP)
txBuffer[STK_TXMSG_START + 1] = ppProgramLock(param);
SWITCH_CASE(STK_CMD_READ_LOCK_PP)
txBuffer[STK_TXMSG_START + 2] = ppReadLock();
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_READ_SIGNATURE_PP)
txBuffer[STK_TXMSG_START + 2] = ppReadSignature(param);
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_READ_OSCCAL_PP)
txBuffer[STK_TXMSG_START + 2] = ppReadOsccal();
len.bytes[0] = 3;
SWITCH_CASE(STK_CMD_ENTER_PROGMODE_ISP)
txBuffer[STK_TXMSG_START + 1] = ispEnterProgmode(param);
SWITCH_CASE(STK_CMD_LEAVE_PROGMODE_ISP)
ispLeaveProgmode(param);
SWITCH_CASE(STK_CMD_CHIP_ERASE_ISP)
txBuffer[STK_TXMSG_START + 1] = ispChipErase(param);
SWITCH_CASE(STK_CMD_PROGRAM_FLASH_ISP)
txBuffer[STK_TXMSG_START + 1] = ispProgramMemory(param, 0);
SWITCH_CASE(STK_CMD_READ_FLASH_ISP)
len.word = 1 + ispReadMemory(param, (void *)&txBuffer[STK_TXMSG_START + 1], 0);
SWITCH_CASE(STK_CMD_PROGRAM_EEPROM_ISP)
txBuffer[STK_TXMSG_START + 1] = ispProgramMemory(param, 1);
SWITCH_CASE(STK_CMD_READ_EEPROM_ISP)
len.word = 1 + ispReadMemory(param, (void *)&txBuffer[STK_TXMSG_START + 1], 1);
SWITCH_CASE(STK_CMD_PROGRAM_FUSE_ISP)
txBuffer[STK_TXMSG_START + 1] = ispProgramFuse(param);
SWITCH_CASE4(STK_CMD_READ_FUSE_ISP, STK_CMD_READ_LOCK_ISP, STK_CMD_READ_SIGNATURE_ISP, STK_CMD_READ_OSCCAL_ISP)
txBuffer[STK_TXMSG_START + 2] = ispReadFuse(param);
txBuffer[STK_TXMSG_START + 3] = STK_STATUS_CMD_OK;
len.bytes[0] = 4;
SWITCH_CASE(STK_CMD_PROGRAM_LOCK_ISP)
txBuffer[STK_TXMSG_START + 1] = ispProgramFuse(param);
SWITCH_CASE(STK_CMD_SPI_MULTI)
len.word = 1 + ispMulti(param, (void *)&txBuffer[STK_TXMSG_START + 1]);
SWITCH_DEFAULT /* unknown command */
DBG1(0xf8, 0, 0);
txBuffer[STK_TXMSG_START + 1] = STK_STATUS_CMD_FAILED;
SWITCH_END
stkSetTxMessage(len.word);
}
/* ------------------------------------------------------------------------- */
void stkSetRxChar(uchar c)
{
if(timerLongTimeoutOccurred()){
rxPos = 0;
}
if(rxPos == 0){ /* only accept STX as the first character */
if(c == STK_STX)
rxBuffer[rxPos++] = c;
}else{
if(rxPos < BUFFER_SIZE){
rxBuffer[rxPos++] = c;
if(rxPos == 4){ /* do we have length byte? */
rxLen.bytes[0] = rxBuffer[3];
rxLen.bytes[1] = rxBuffer[2];
rxLen.word += 6;
if(rxLen.word > BUFFER_SIZE){ /* illegal length */
rxPos = 0; /* reset state */
}
}else if(rxPos == 5){ /* check whether this is the token byte */
if(c != STK_TOKEN){
rxPos = 0; /* reset state */
}
}else if(rxPos > 4 && rxPos == rxLen.word){ /* message is complete */
uchar sum = 0;
uchar *p = rxBuffer;
while(rxPos){ /* decrement rxPos down to 0 -> reset state */
sum ^= *p++;
rxPos--;
}
if(sum == 0){ /* check sum is correct, evaluate rx message */
stkEvaluateRxMessage();
}else{ /* checksum error */
DBG2(0xf2, rxBuffer, rxLen.word);
txBuffer[STK_TXMSG_START] = STK_ANSWER_CKSUM_ERROR;
txBuffer[STK_TXMSG_START + 1] = STK_ANSWER_CKSUM_ERROR;
stkSetTxMessage(2);
}
}
}else{ /* overflow */
rxPos = 0; /* reset state */
}
}
timerSetupLongTimeout(RX_TIMEOUT);
}
int stkGetTxCount(void)
{
return txLen - txPos;
}
int stkGetTxByte(void)
{
uchar c;
if(txLen == 0){
return -1;
}
c = txBuffer[txPos++];
if(txPos >= txLen){ /* transmit ready */
txPos = txLen = 0;
}
return c;
}
/* ------------------------------------------------------------------------- */