Stm32F4以太网远程固件升级BootLoader踩过官方的坑

历时5个工作日,总算把以太网远程远程固件升级功能完成,期间踩了不少的坑。最初设计的时候参照stm32官方1.26.1标准固件HAL库,新建一个工程,把官方对应的驱动移植到新的工程底下。

因为使用以太网方式BootLoader,由于以太网占用内存及ROM空间比较大,故从0x08000000—0x08020000处128KROM空间分配给BootLoader程序,从0x08020000—0x080FFFFF处896KROM空间分配给用户程序。

分配空间,下载BootLoader程序到主板上,使用http登陆到下载程序界面,点击下载,然后复位,结果用户程序未执行,未能成功。

使用烧录器烧录用户程序到0x08020000处,使用BootLoader引导对比测试,发现跳转以后用户程序正常运行。说明跳转过程没有问题,BootLoader程序跳转正常。通过汇编单步调试,定位到跳转到HardFault_Handler错误中断前代码地址0x080209C0处。同时在同一地址处,比较BootLoader烧录代码与烧录器烧录代码差异,发现在0x080209DA地址处发生了代码差异。故此现象由于FLASH存储的代码差异引起,可能原因如下:

  1. BootLoader程序接收http传输bin文件发生了错误
  2. BootLoader程序写FLASH发生了错误
  3. 编译器生成bin文件发生了错误

最容易排查的是http传输问题。测试使用http接收数据转发网络日志存储,通过存储发现,发送6000多字节,实际接收2000多个字节,判定接收异常。

       同时对比使用http调试助手模拟http服务器,测试发现,模拟服务器能够接收完整的数据,判定web客户端发送正常。

同步通过日志打印,最终发现,官方的例程驱动移植过来,连续接收网络数据存在网络丢包现象,故官方的网络驱动接收存在bug,然后重新设计网络驱动程序。最终完美完成远程web方式固件升级。关键代码如下:

#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "fsdata.h"
#include "fsdata.c"
#include "main.h"
#include "flash_if.h"
#include <string.h>
#include <stdio.h>


struct fs_file {
  char *data;
  int len;
};

struct http_state
{
  char *file;
  u32_t left;
};

typedef enum 
{
  LoginPage = 0,
  FileUploadPage,
  UploadDonePage,
  ResetDonePage
}htmlpageState;
  
htmlpageState htmlpage;
 
static const char http_crnl_2[4] = 
/* "\r\n--" */
{0xd, 0xa,0x2d,0x2d};
static const char octet_stream[14] = 
/* "octet-stream" */
{0x6f, 0x63, 0x74, 0x65, 0x74, 0x2d, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,0x0d, };
static const char Content_Length[17] = 
/* Content Length */
{0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67,0x74, 0x68, 0x3a, 0x20, };

static __IO uint32_t DataFlag=0;
static __IO uint32_t size =0;
__IO uint32_t FlashWriteAddress;
static uint32_t TotalReceived=0;
static char LeftBytesTab[4];
static uint8_t LeftBytes=0;
static __IO uint8_t resetpage=0;
static uint32_t ContentLengthOffset =0,BrowserFlag=0;
static __IO uint32_t TotalData=0, checklogin=0; 
void IAP_HTTP_writedata(char * ptr, uint32_t len);


#if LWIP_TCP
static struct tcp_pcb *tcp_echoserver_pcb;

/* ECHO protocol states */
enum tcp_echoserver_states
{
  ES_NONE = 0,
  ES_ACCEPTED,
  ES_RECEIVED,
  ES_CLOSING
};

/* structure for maintaing connection infos to be passed as argument 
   to LwIP callbacks*/
struct tcp_echoserver_struct
{
  u8_t state;             /* current connection state */
  u8_t retries;
  struct tcp_pcb *pcb;    /* pointer on the current tcp_pcb */
  struct pbuf *p;         /* pointer on the received/to be transmitted pbuf */
};

static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err);
static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
static void tcp_echoserver_error(void *arg, err_t err);
static err_t tcp_echoserver_poll(void *arg, struct tcp_pcb *tpcb);
static err_t tcp_echoserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void tcp_echoserver_send(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es);
static void tcp_echoserver_connection_close(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es);


static int fs_open(char *name, struct fs_file *file)
{
    struct fsdata_file_noconst *f;
    for (f = (struct fsdata_file_noconst *)FS_ROOT; f != NULL; f = (struct fsdata_file_noconst *)f->next)
    {
        if (!strcmp(name, f->name))
        {
            file->data = f->data;
            file->len = f->len;
            return 1;
        }
    }
    return 0;
}
static uint32_t Parse_Content_Length(char *data, uint32_t len)
{
    uint32_t i=0,size=0, S=1;
    int32_t j=0;
    char sizestring[6], *ptr;

    ContentLengthOffset =0;

    /* find Content-Length data in packet buffer */
    for (i=0;i<len;i++)
    {
        if (strncmp ((char*)(data+i), Content_Length, 16)==0)
        {
            ContentLengthOffset = i+16;
            break;
        }
    }
    /* read Content-Length value */
    if (ContentLengthOffset)
    {
        i=0;
        ptr = (char*)(data + ContentLengthOffset);
        while(*(ptr+i)!=0x0d)
        {
            sizestring[i] = *(ptr+i);
            i++;
            ContentLengthOffset++; 
        }
        if (i>0)
        {
            /* transform string data into numeric format */
            for(j=i-1;j>=0;j--)
            {
                size += (sizestring[j]-'0')*S;
                S=S*10;
            }
        }
    }
    return size;
}

void tcp_echoserver_init(void)
{
    err_t err;
    tcp_echoserver_pcb = tcp_new();                                /* create new tcp pcb */
    if (tcp_echoserver_pcb != NULL)
    {    
        err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 80);        /* bind echo_pcb to port 7 (ECHO protocol) */
        if (err == ERR_OK)
        {        
            tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb);    /* start tcp listening for echo_pcb */            
            tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);    /* initialize LwIP tcp_accept callback function */
        }    
        else 
        {        
            memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb);            /* deallocate the pcb */
        }
    }
}

static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
{
    err_t ret_err;
    struct tcp_echoserver_struct *es;

    LWIP_UNUSED_ARG(arg);
    LWIP_UNUSED_ARG(err);
    tcp_setprio(newpcb, TCP_PRIO_MIN);            /* set priority for the newly accepted tcp connection newpcb */
    /* allocate structure es to maintain tcp connection informations */
    es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_echoserver_struct));
    if (es != NULL)
    {
        es->state = ES_ACCEPTED;
        es->pcb = newpcb;
        es->retries = 0;
        es->p = NULL;        
        tcp_arg(newpcb, es);                        /* pass newly allocated es structure as argument to newpcb */    
        tcp_recv(newpcb, tcp_echoserver_recv);        /* initialize lwip tcp_recv callback function for newpcb  */         
        tcp_err(newpcb, tcp_echoserver_error);        /* initialize lwip tcp_err callback function for newpcb  */        
        tcp_poll(newpcb, tcp_echoserver_poll, 0);    /* initialize lwip tcp_poll callback function for newpcb */
        ret_err = ERR_OK;
    }
    else
    {        
        tcp_echoserver_connection_close(newpcb, es);    /*  close tcp connection */        
        ret_err = ERR_MEM;                                /* return memory error */
    }
    return ret_err;  
}

static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
    struct tcp_echoserver_struct *es;
    err_t ret_err;
    struct pbuf *ptr;
    LWIP_ASSERT("arg != NULL",arg != NULL);
    es = (struct tcp_echoserver_struct *)arg;
    /* if we receive an empty tcp frame from client => close connection */
    if (p == NULL)
    {        
        es->state = ES_CLOSING;                            /* remote host closed connection */
        if(es->p == NULL)
        {        
            tcp_echoserver_connection_close(tpcb, es);    /* we're done sending, close connection */
        }
        else
        {                                                /* we're not done yet */        
            tcp_sent(tpcb, tcp_echoserver_sent);        /* acknowledge received packet */            
            tcp_echoserver_send(tpcb, es);                /* send remaining data*/
        }
        ret_err = ERR_OK;
    }   
    /* else : a non empty frame was received from client but for some reason err != ERR_OK */
    else if(err != ERR_OK)
    {        
        if (p != NULL)                                    /* free received pbuf*/
        {
            es->p = NULL;
            pbuf_free(p);
        }
        ret_err = err;
    }
    else if(es->state == ES_ACCEPTED)
    {        
        es->state = ES_RECEIVED;                        /* first data chunk in p->payload */        
        es->p = p;                                        /* store reference to incoming pbuf (chain) */        
        tcp_sent(tpcb, tcp_echoserver_sent);            /* initialize LwIP tcp_sent callback function */        
        tcp_echoserver_send(tpcb, es);                    /* send back the received data (echo) */
        ret_err = ERR_OK;
    }
    else if (es->state == ES_RECEIVED)
    {
        /* more data received from client and previous data has been already sent*/
        if(es->p == NULL)
        {
            es->p = p;            
            tcp_echoserver_send(tpcb, es);                /* send back received data */
        }
        else
        {            
            ptr = es->p;                                /* chain pbufs to the end of what we recv'ed previously  */
            pbuf_chain(ptr,p);
        }
        ret_err = ERR_OK;
    }
    else if(es->state == ES_CLOSING)
    {    
        tcp_recved(tpcb, p->tot_len);                    /* odd case, remote side closing twice, trash data */
        es->p = NULL;
        pbuf_free(p);
        ret_err = ERR_OK;
    }
    else
    {        
        tcp_recved(tpcb, p->tot_len);                    /* unkown es->state, trash data  */
        es->p = NULL;
        pbuf_free(p);
        ret_err = ERR_OK;
    }
    return ret_err;
}

static void tcp_echoserver_error(void *arg, err_t err)
{
    struct tcp_echoserver_struct *es;
    LWIP_UNUSED_ARG(err);
    es = (struct tcp_echoserver_struct *)arg;
    if (es != NULL)
    {        
        mem_free(es);                                /*  free es structure */
    }
}

static err_t tcp_echoserver_poll(void *arg, struct tcp_pcb *tpcb)
{
    err_t ret_err;
    struct tcp_echoserver_struct *es;
    es = (struct tcp_echoserver_struct *)arg;
    if (es != NULL)
    {
        if (es->p != NULL)
        {
            tcp_sent(tpcb, tcp_echoserver_sent);        
            tcp_echoserver_send(tpcb, es);            /* there is a remaining pbuf (chain) , try to send data */
        }
        else
        {        
            if(es->state == ES_CLOSING)                /* no remaining pbuf (chain)  */
            {            
                tcp_echoserver_connection_close(tpcb, es);    /*  close tcp connection */
            }
        }
        ret_err = ERR_OK;
    }
    else
    {    
        tcp_abort(tpcb);                                /* nothing to be done */
        ret_err = ERR_ABRT;
    }
    return ret_err;
}

static err_t tcp_echoserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
    struct tcp_echoserver_struct *es;
    LWIP_UNUSED_ARG(len);
    es = (struct tcp_echoserver_struct *)arg;
    es->retries = 0;
    if(es->p != NULL)
    {
        /* still got pbufs to send */
        tcp_sent(tpcb, tcp_echoserver_sent);
        tcp_echoserver_send(tpcb, es);
    }
    else
    {
        /* if no more data to send and client closed connection*/
        if(es->state == ES_CLOSING)
            tcp_echoserver_connection_close(tpcb, es);
    }
    return ERR_OK;
}

err_t TcpSend(unsigned char *pData,int len);
void TcpPrintf(const char *format, ...);
u8_t  g_recvBuff[1500];
unsigned int g_len = 0;
unsigned int g_bootBytes=0;
unsigned char g_recvData[10240];
void WebAnalysis(char *data,int len,struct tcp_pcb *tpcb)
{
    uint32_t DataOffset, FilenameOffset;
    char  *ptr,filename[40], login[LOGIN_SIZE+1];
    struct fs_file file = {0, 0};
    struct http_state *hs;
    struct pbuf *ptrData;
    int i;
        
    if (strncmp(data, "GET / HTTP", 10) == 0)                //首页登陆界面
    {
        htmlpage = LoginPage;
        fs_open("/index.html", &file);
        tcp_write(tpcb, file.data, file.len, 1);
    }
    else if ((strncmp(data, "GET /resetmcu.cgi", 17) ==0)&&(htmlpage == UploadDonePage))    //复位界面
    {
        htmlpage = ResetDonePage;
        fs_open("/reset.html", &file);
        tcp_write(tpcb, file.data, file.len, 1);
        resetpage = 1;
    }
    else if ((strncmp(data, "POST /checklogin.cgi",20)==0)&&(htmlpage== LoginPage))
    {
        ptr = strstr(data,"username=");
        if(ptr != NULL)
        {
            sprintf((char *)login,"username=%s&password=%s",USERID,PASSWORD);
            if (strncmp(ptr, (char *)login ,LOGIN_SIZE)==0)
            {
                htmlpage = FileUploadPage;
                fs_open("/upload.html", &file);
            }
            else
            {
                htmlpage = LoginPage;
                fs_open("/index.html", &file);
            }
            tcp_write(tpcb, file.data, file.len, 1);
        }   
    }
    else if (strncmp(data, "POST /upload.cgi",16)==0||DataFlag >=1)
    { 
        DataOffset =0;
        if (DataFlag ==0)
        { 
            BrowserFlag=0;
            TotalReceived =0;
            size = Parse_Content_Length(data, len);        
            ptr = strstr(data,octet_stream);
            if(ptr != NULL)
            {
                DataOffset = ptr - data + 16;
            }
            if (DataOffset==0)
            {
                DataFlag++;
                BrowserFlag = 1;
                return;
            }
            else
            {
                TotalReceived = len - (ContentLengthOffset + 4);
            }
        }
        if (((DataFlag ==1)&&(BrowserFlag==1)) || ((DataFlag ==0)&&(BrowserFlag==0)))
        { 
            if ((DataFlag ==0)&&(BrowserFlag==0)) 
            {
                DataFlag++;
            }
            else if ((DataFlag ==1)&&(BrowserFlag==1))
            {            
                ptr = strstr(data,octet_stream);
                if(ptr != NULL)
                {
                    DataOffset = ptr - data + 16;
                }
                TotalReceived+=len;
                DataFlag++;
            }  
            FilenameOffset = 0;
            ptr = strstr(data,"filename=");
            if(ptr != NULL)
            {
                FilenameOffset = ptr - data + 16;
            }         
            i =0;
            if (FilenameOffset)
            {
                while((*(data+FilenameOffset + i)!=0x22 )&&(i < 40))
                {
                    filename[i] = *(data+FilenameOffset + i);
                    i++;
                }
                filename[i] = 0x0;
            }
            if (i==0)
            {
                htmlpage = FileUploadPage;
                fs_open("/upload.html", &file);
                tcp_write(tpcb, file.data, file.len, 1);
                DataFlag=0;
                return;
            }
            TotalData =0;
            FLASH_If_Init();
            FLASH_If_Erase(USER_FLASH_FIRST_PAGE_ADDRESS);
            FlashWriteAddress = USER_FLASH_FIRST_PAGE_ADDRESS;
//            TcpPrintf("  State: Programming...\n");
            g_bootBytes = 0;
        }
        else 
        {
            TotalReceived +=len;
        }
        ptr = (char*)(data + DataOffset);
        len-= DataOffset;
        TotalData +=len;
        if (TotalReceived == size)
        {
            i=4; 
            while (strncmp ((char*)(data+ len -i),http_crnl_2 , 4) && (len -i > 0))
            {
                i++;
            }
            len-=i;
            TotalData-=i;
            if (len)
            {
                memcpy(g_recvData+g_bootBytes,ptr, len);
                g_bootBytes += len;
                IAP_HTTP_writedata(ptr,len);
            }
            DataFlag=0;
//            TcpPrintf(" State: Prog Finished %d\r\n",g_bootBytes);
            htmlpage = UploadDonePage;
            fs_open("/uploaddone.html", &file);
            tcp_write(tpcb, file.data, file.len, 1);
        }
        else
        {
            if(len)
            {
                memcpy(g_recvData+g_bootBytes,ptr, len);
                g_bootBytes += len;
                IAP_HTTP_writedata(ptr,len);
            }
        }
    }
    else
    {
//        close_conn(pcb, hs);
    }

}

static void tcp_echoserver_send(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es)
{
    struct pbuf *ptr;
    err_t wr_err = ERR_OK;
    u16_t plen;
    u8_t freed;    
    char *data;
    int len;
    plen = ptr->len;
    len = 0;
    memset(g_recvBuff,0,sizeof(g_recvBuff));
    while ((wr_err == ERR_OK) && (es->p != NULL) && (es->p->len <= tcp_sndbuf(tpcb)))
    {    
        g_len += ptr->len;        
        ptr = es->p;                                            /* get pointer on pbuf from es structure */
        if(ptr->len > (1500-len))
        {
            data = (char *)&g_recvBuff[0];
            WebAnalysis(data,len,tpcb);
            memset(g_recvBuff,0,sizeof(g_recvBuff));
            len = 0;
        }
        memcpy(g_recvBuff+len,ptr->payload, ptr->len);
        len += ptr->len;
        es->p = ptr->next;                                        /* continue with next pbuf in chain (if any) */
        if(es->p != NULL)
        {            
            pbuf_ref(es->p);                                    /* increment reference count for es->p */
        }            
        do                                                        /* chop first pbuf from chain */
        {            
            freed = pbuf_free(ptr);                                /* try hard to free pbuf */
        }
        while(freed == 0);
        tcp_recved(tpcb, plen);                                    /* we can read more data now */    
    }
    data = (char *)&g_recvBuff[0];
    WebAnalysis(data,len,tpcb);
}

static void tcp_echoserver_connection_close(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es)
{
    /* remove all callbacks */
    tcp_arg(tpcb, NULL);
    tcp_sent(tpcb, NULL);
    tcp_recv(tpcb, NULL);
    tcp_err(tpcb, NULL);
    tcp_poll(tpcb, NULL, 10);
    /* delete es structure */
    if (es != NULL)
    {
        mem_free(es);
    }  
    /* close tcp connection */
    tcp_close(tpcb);
}

void IAP_HTTP_writedata(char * ptr, uint32_t len)            
{
    uint32_t count, i=0, j=0;
    /* check if any left bytes from previous packet transfer*/
    /* if it is the case do a concat with new data to create a 32-bit word */
    if (LeftBytes)
    {
        while(LeftBytes<=3)
        {
            if(len>(j+1))
            {
                LeftBytesTab[LeftBytes++] = *(ptr+j);
            }
            else
            {
                LeftBytesTab[LeftBytes++] = 0xFF;
            }
            j++;
        }
        FLASH_If_Write(&FlashWriteAddress, (uint32_t*)(LeftBytesTab),1);
        LeftBytes =0;

        /* update data pointer */
        ptr = (char*)(ptr+j);
        len = len -j;
    }

    /* write received bytes into flash */
    count = len/4;

    /* check if remaining bytes < 4 */
    i= len%4;
    if (i>0)
    {
        if (TotalReceived != size)
        {
            /* store bytes in LeftBytesTab */
            LeftBytes=0;
            for(;i>0;i--)
                LeftBytesTab[LeftBytes++] = *(char*)(ptr+ len-i);  
        }
        else count++;
    }
    FLASH_If_Write(&FlashWriteAddress, (uint32_t*)ptr ,count);
}

#endif

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值