在线情况
楼主
  • 头像
  • 级别
  • 门派
  • 职务总版主
  • 声望+9
  • 财富5
  • 积分3065
  • 经验390701
  • 文章6744
  • 注册2006-03-07
MSP430F149在TCP/IP上的扩展
作者:richardL
摘自:佐格

应佐格公司FFT先生邀请,谈谈在F149的TCP/IP功能上的增强,实际上我接触430的时间很短(FFT,moom知道,只有半年多),只是天天跟CaptureCIS+Allegro,IAR Compiler, CodeWright, VisualC++, cvs, gcc打交道,方方面面都要做(谁叫我在小公司打工呢),上手快些而已.就如FFT所说,希望在不触及(或自己不觉得影响到)商业/工业秘密的时候,各位同行多多交流交流,互促进步. 程序以TI网站上原码为最初原型(其实当初我最早想移植uIP的,后来看到时间紧,放弃了)

1.文件结构调整
  当我一看到TI的范例,就对其结构不已为然,通篇项目只有一个C,其他都是关联近来的,这完全不时一个标准C/C++程序员的风格嘛,对功能扩展,错误跟踪分析不利,所以我第一件事就改了文件结构划分.
使各个C文件单独编译,最后连接,其他应用程序当然是单独的文件了, 免得在调试和分析的时候在整个项目到处乱翻编量和代码实现.
  另外由于Socket的应用显然包括网络的两端,因此单独列出一两个H文件,方便和其他系统C的编译连接(如port定义,各个socket命令参数,格式等),由于平台的相关性,强烈建议采用uIP等的数据类型定义方式,以免以后与32位系统socket联调时麻烦.

2.FLASH区域的详细划分:
  主要代码区
  应用数据区
  系统升级代码及永久数据区(永久数据包括MAC地址等,注意IP地址并不在此内,其实IP,Gateway,等参数随时可能改变)
  网络信息区(IP地址,SubNetMask,别名等等)
  系统版本区(软硬件版本信息,只有系统在线自升级才修改,保留信息结构的一致性,要有扩充余地,方便高端程序对该设备基本软硬件信息的访问)
  中断向量区(系统固定,但软件在线升级时要更改, 因为很可能你的产品安装后要在线升级软件版本,而你的新的软件版本改变了中断方式和中断数量!!!)
 
 
3.编译器连接器的设定
  配合FLASH的划分,设定相关的连接参数: 我的如下XXXX代表应用层)

-cMSP430
-Z(DATA)UDATA0,IDATA0,ECSTR=0200-09FF
-Z(DATA)CSTACK#0200-0A00 //keep 300b+(12c) for stack!!! (check map file)
-Z(CODE)INFO=1000-10FF
//  Main memory (FLASH)
//map of msp430f149
//1000-107f Segment B  (system mode)                             (128   bytes) Segment B
//1080-10ff Segment A  (node-net info)                           (128   bytes) Segment A
//1100-11ff NOT USED ..............!!!!!!!!!!..................  (256   bytes) Segment 119# //special for F149!!! see slas272d.pdf P12
//1200-91ff xxxx-zone                                            (32k   bytes) Segment 55# - 118#
//9200-f9ff general code,const -- changed under system upgraded  (26k   bytes) Segment 3# - 54# (512B/seg)
//fa00-fbff chip info --maybe changed under system upgraded      (512   bytes) Segment 2#
//fc00-fdff mac address         --never change!!!                       (512   bytes) Segment 1#
//fe00-ffff interrupt vectors        -- maybe changed                   (512   bytes) Segment 0# -w/Interrupt Vectors

-Z(CODE)SYS_MODE_TABLE=1000-107F
-Z(CODE)NODE_INFO_TABLE=1080-10FF
-Z(CODE)xxxx_ZONE=1200-91FF
-Z(CODE)CODE,CONST,CSTR,CDATA0,CCSTR=9200-f9ff
-Z(CODE)CHIP_INFO=fa00-fbff
-Z(CODE)MAC_TABLE=fc00-Fdff
-Z(CODE)INTVEC=FFE0-FFFF

4.变量和代码的优化
TCP/IP协议中用了很多全局/局部变量,我更改了一些简单变量为结构模式,有些直接放在响应的FLASH区,从而提高代码的效率和节约了内存.有些函数的参数尽量减少到2个以内(或分开列出),而有些函数根本不必要单独列出,用宏来代替就可以了(效率),以下范例:

a. 合并两个重复的代码:
//#define SwapBytes(Data) ((u16_t)((Data >> 8) | (Data << 8)))
#define SWAPB(Word)          ((u16_t)((Word) << 8) | ((Word) >> 8))

b. TxTCPBuffer 和 RxTCPBuffer 的直接访问(不用多次拷贝----浪费内寸和时间!!!)
extern u8_t RxTCPBuffer[MSP_MAX_TCP_RX_DATA_SIZE]; // space for incoming TCP-data
//pointer of RX_BUFFER
#define TCP_REQ_PTR_KEY      ((u8_t *)TCP_RX_BUF)
#define TCP_REQ_PTR_ORDER    ((u8_t *)TCP_REQ_PTR_KEY     +sizeof(u32_t))
#define TCP_REQ_PTR_LEN      ((u8_t *)TCP_REQ_PTR_ORDER  +sizeof(u16_t))
#define TCP_REQ_PTR_DATA     ((u8_t *)TCP_REQ_PTR_LEN    +sizeof(u16_t))
#define TCP_REQ_KEY          ((u32_t)*((u32_t *)TCP_REQ_PTR_KEY))
#define TCP_REQ_ORDER        ((u16_t)*((u16_t *)TCP_REQ_PTR_ORDER))
#define TCP_REQ_LEN          ((u16_t)*((u16_t *)TCP_REQ_PTR_LEN))
#define TCP_REQ_DATA_U8      ((u8_t)*((u8_t *)TCP_REQ_PTR_DATA))
#define TCP_REQ_DATA_U16     ((u16_t)*((u16_t *)TCP_REQ_PTR_DATA))
#define TCP_REQ_DATA_U32     ((u32_t)*((u32_t *)TCP_REQ_PTR_DATA))
#define TCP_REQ_DATA_U16A    TCP_REQ_DATA_U16 //first 16bit
#define TCP_REQ_DATA_U16B    ((u16_t)*((u16_t *)(TCP_REQ_PTR_DATA+2)))

c. 定义通用head file
#ifdef PLATFORM_MSP  //special for MSP 16bit
typedef unsigned   char    u8_t;
typedef signed     char    s8_t;
typedef unsigned   int     u16_t;
typedef signed     int     s16_t;
typedef unsigned   long    u32_t;
typedef signed     long    s32_t;
#else //Win32 Linux Unix ---Client 32bit-platform
typedef unsigned   char    u8_t;
typedef signed     char    s8_t;
typedef unsigned   short   u16_t;
typedef signed     short   s16_t;
typedef unsigned   int     u32_t;
typedef signed     int     s32_t;
#endif

//packet id define for client/MSP
#define PKTID_GENERAL             'G0'
#define PKTID_CHANGE_MODE         (PKTID_GENERAL+0 ) //change mode between (XXXXserver/ SYSburnserver/ HTTPserver)
#define PKTID_DUMP_FLASH          (PKTID_GENERAL+1 ) //download ANY datas from any positon in flash-mem Data-Zone
....
typedef struct struReqHead_XXX{
u32_t key;   // key for security
u16_t order; // same as order_code (see above) = PKTID_...
u16_t len;
}struReqHead;

typedef struct struNetInfo_XXX{
u16_t MyIP[2];
u16_t MasterIP[2];
u16_t SubnetMask[2];
u16_t GatewayIP[2];
}struNetInfo;

//for protocal_support;
#define PROTOCAL_SUPPORT   0x0001
#define PROTOCOL_ICMP      (PROTOCAL_SUPPORT<<0)
#define PROTOCOL_BROADCAST (PROTOCAL_SUPPORT<<1)
#define PROTOCAL_FULL_SUPPORT   (PROTOCOL_ICMP|PROTOCOL_BROADCAST)

#define TCP_PORT_XXX      4112  
#define TCP_PORT_MASTER   5001  

d. 几个优化:
#define SendFrame1()  {CopyToFrame8900(&TxFrame1, TxFrame1Size);}
#define SendFrame2()  {CopyToFrame8900(&TxFrame2, TxFrame2Size);}
#define TCPRestartTimer() {TCPTimer = 0;}
#define TCPStopTimer() {TCPFlags &= ~TCP_TIMER_RUNNING;}
将CalcChecksum()划分成两个, 内部代码做简单优化(在C-spy中看看汇编就知道了)
u16_t CalcChecksum(...)
{
最开始
u32_t Sum = 0;
...

最后
Sum = (Sum >> 16) + (Sum & 0xffff);     // add hi 16 to low 16
Sum += (Sum >> 16);                     // add carry
return ~Sum;
}

5. BROADCAST功能支持的扩展

6. UDP的扩展(很容易的,见:http://www.faqs.org/rfcs/rfc768.html)

7. 系统在线升级:
   基本流程(直到旧系统擦除前,随时可以Cancel)
   a.模式切换(权限验证)
   b.代码dump(由于接收缓冲区小,这是最耗时间的地方,目前12K的新系统代码dump所需时间大概15秒)
   c.代码验证
   d.全部FLASH擦除(除了系统升级代码区和dump区).
   e.代码解析和复制
   f.reboot. #define REBOOT  {WDTCTL=0x1000;} //(PUC) is generated see slau049.pdf p146

   注:在d和e运行其间如果掉电的话,就只有到现场去取下设备来JXXX/BSL编程了.
   
8. 其他
   
   a. 转换程序:将msp430.txt格式的代码文件转为适合在线系统升级的数据包(编码前---保护版权哦)
   
int main(int argc, char* argv[])
{
FILE *fin,*fout;
char fout_name[80];
struXXXBlock block;
int version;

char line[80];
char line_bin[40];
char addr_str[5];
addr_str[4]=0;

printf("\n\t%s (%s)\n\t\t%s %s\n\n",__PRODUCT__,__PRODUCTVERSION__,__COMPANY__,__COPYRIGHT__);
if (argc<=2) {
  printf("\tformat error! usage: CCC input_file_name version\n\texample: CCC xxx.d43 101\n";
  return -1;
}

if( (fin= fopen( argv[1], "rt" )) == NULL )
{
  printf( "The file %s was not opened\n",argv[1]);
  return -1;
           }
if ((version=atoi(argv[2]))==0)
{
  printf( "\tversion should not be ZERO!\n";
  return -1;
           }

sprintf(fout_name,"XXX%04d.sys",version);
printf("\tinput:  \t%s\n\toutput:  \t%s\n",argv[1],fout_name);

int linecnt=0;
block.len=0;
block.addr=0;
while ( fgets( line, 100, fin) != NULL)
{
  if (line[0]=='@')
  {
          if (block.len>0) write_block(&block);
          memcpy(addr_str,&line[1],4);//get addr
          block.addr=hex2uint(addr_str);
          block.len=0;
  }
  else if (line[0]=='q')
  {
          if (block.len>0) write_block(&block);
          break; //end of code
  }
  else
  {
          int len=asc2char(&line[0],&line_bin[0]);
          if ((block.len+len)>=MAX_BLOCK_LEN)
          {
                  int num=MAX_BLOCK_LEN-block.len;
                  memcpy(&block.buff[block.len],&line_bin[0],num);
                  block.len=MAX_BLOCK_LEN;
                  write_block(&block);
                 
                  block.len=len-num;
                  memcpy(&block.buff[0],&line_bin[num-1],block.len);
                  block.addr+=MAX_BLOCK_LEN;
          }
          else
          {
                  memcpy(&block.buff[block.len],&line_bin[0],len);
                  block.len+=len;
          }
  }
}
//write end block (addr=len=0)
block.len=0;
block.addr=0;
write_block(&block);

u16_t checksum=CalcChecksum(&TotalBlock[0],TotalBlock_Len);
printf("\tlenght:  \t%d bytes\n\tchecksum:  \t%04x\n",TotalBlock_Len+2,checksum);
memcpy(&TotalBlock[TotalBlock_Len],&checksum,2);
TotalBlock_Len+=2;

fclose(fin);
//save to file
if ((fout=fopen(fout_name,"wb") ==NULL)
{
  printf( "The file %s can not be created\n",fout_name);
  return -1;
           }
fwrite(&TotalBlock[0],TotalBlock_Len,1,fout);
fflush(fout);
fclose(fout);
printf("\tdone.(OK)\n",argv[1],fout_name);
     
return 0;
}
   
   b. 升级程序:将新版文件通过socket通讯来在线升级(编码前---保护版权哦)
BOOL CSystemBurner::OnSocketReceive(int iErrorCode)
{
try
{
  if (iErrorCode)
  {
          printf("SocketReceive error\n";Close();return FALSE;
  }

  char cBuffer[1024];
  int iRecv=Receive(cBuffer,sizeof(cBuffer));

  struAnswerHead head;
  memcpy((unsigned char *)&head,cBuffer,sizeof(struAnswerHead));

  if (iRecv!=(head.len+sizeof(struAnswerHead)))
  {        printf("len is not matched.\n";
          return FALSE;
  }
 
  char TxBuffer[128];
  int len;

  struct struDumpBlk_XXX{
          union {
                  char full[SMALL_BLK_SIZE];
                  struct {
                          u16_t offset;
                          char code[SMALL_BLK_SIZE-2];
                  }S;
          }U;
  } dumpBlk;

  u16_t RxData;

  switch (head.id)
  {
          case PKTID_CHANGE_MODE:
                  m_status=CSystemBurner:UMP;
                  len=CreatePacketOrder(TxBuffer, PKTID_SYS_DUMP, NULL,0);
                  Send(TxBuffer,len);
                  printf("change mode OK.\nstart dumping....% 3d/% 3d",m_small_blk_cnt+1,m_small_blk_num);
                  m_small_blk_cnt++;
                  m_CodeOffset+=SMALL_BLK_SIZE-2;
                  break;

          //keep dump or do next step-checksum
          case PKTID_SYS_DUMP:
                  if (m_small_blk_cnt>=m_small_blk_num) { //finish dump
                          printf("\ndump done(OK).\n";
                          m_status=CSystemBurner::CHECKSUM;
                          len=CreatePacketOrder(TxBuffer, PKTID_SYS_CHECKSUM, NULL,0);
                          Send(TxBuffer,len);
                          printf("do check ...\t";
                  }
                  else {
                          dumpBlk.U.S.offset=m_small_blk_cnt;
                          memcpy(dumpBlk.U.S.code,m_pCode+m_CodeOffset,SMALL_BLK_SIZE-2);
                          m_status=CSystemBurner:UMP;
                          len=CreatePacketOrder(TxBuffer, PKTID_SYS_DUMP, dumpBlk.U.full,SMALL_BLK_SIZE);
                          Send(TxBuffer,len);
                          printf("\b\b\b\b\b\b\b% 3d/% 3d",m_small_blk_cnt+1,m_small_blk_num);
                          m_small_blk_cnt++;
                          m_CodeOffset+=SMALL_BLK_SIZE-2;
                  }
                  break;

          //checksum correct then do BURN
          case PKTID_SYS_CHECKSUM:
                  memcpy((unsigned char *)&RxData,cBuffer+sizeof(struAnswerHead),sizeof(u16_t));
                  printf("checksum OK.  ----- value=%04x\n",RxData);
                  m_status=CSystemBurner::BURN;
                  len=CreatePacketOrder(TxBuffer, PKTID_SYS_BURN, NULL,0);
                  Send(TxBuffer,len);
                  printf("do burn ...\t";
                  break;

          //last receive before burning!
          case PKTID_SYS_BURN:
                  m_status=CSystemBurner::BURN_CONFIRMED;
                  printf("received PKTID_SYS_BURN.\n";
                  break;
        
          //cancel command be confirmed.
          case PKTID_SYS_CANCEL:
                  m_status=CSystemBurner::CANCEL_CONFIRMED;
                  break;

          default:
                  printf("unknown echo: %08x\n",head.id);
                  break;
  }
  return TRUE;
}
ERROR_HANDLER_RETURN("OnSocketReceive",TRUE)
}

[COLOR=#0000ff]欢迎发贴分享设计心得、开源DIY...[/COLOR]
在线情况
2
  • 头像
  • 级别
    • 积分3
    • 经验183
    • 文章4
    • 注册2006-12-14
    先收下了,谢谢!
    微控网感谢您的参与
    Powered by LeadBBS 9.2 .
    Page created in 0.2500 seconds with 5 queries.