原创 基于AVR-BootLoader,通过霜蝉远程串口可实现单片机的远程升级

2018-7-9 20:39 1380 13 13 分类: MCU/ 嵌入式

最近一直利用业余时间写自己的“基于AVR-BootLoader”,启发是由于一次在ourAVR论坛看到了绍子阳的bootloader,联想到公司在用AVR MCU,但每次升级程序都要花费很大的力气车马劳顿的跑到工程现场,而且很多机器还安装在国外,为了升级一次程序发费了很多的人力物力财力,加上公司的机器目前大部分都配有远程监控系统,所以本人决定写一个具有自有产权的“AVR-BootLoader”。

      
特别说明:本“AVR-BootLoad”软件代码属上海霜蝉版权所有,在此贡献发布,仅限于个人免费使用不得用于商业用途,本人也不保证代码的严谨性,如在升级中出现任何问题与本人无关,本人已测试过Atmega64A与Atmega128。话不多说了上源代码,网友们和AVR爱好者可以拷贝到CodeWizardAVR V2.03.9编译器下编译。
需要讨论或有遇到BUG的网友们可以联系我:QQ:285247488  mail:shw@scicala.com 

上位机截图:

远程升级DTU:

远程升级连接云平台虚拟串口:

//          关于上海霜蝉-AVR_BootLoade_V1.00
// 1、软件版本V1.00 编译环境CodeWizardAVR V2.03.9 Standard;
// 2、支持本公司常用的三种AVR芯片;
// 3、支持标准Xmodem和扩展Xmodem_1K协议;
// 4、联机握手密码为"00",握手成功手的等待文件超时为1分钟;
// 5、默认复位等待3S退出boot到用户程序或循环运行boot;
// 6、支持1分钟以内的断网续传;
// 7、支持连续10帧以内数据错误的重传;
// 8、支持下载过程中的取消超作;
// 9、支持当收到包时,接收过程中每个字符的超时间隔为 1 秒;
// 10、支持所有的超时及错误事件至少重试 10 次;
// 11、支持数等待超时6S的请求;
// 12、Boot Loader - Size:1024words;
// 13、支持传输速度:38.400KB/S~2.400KB/S;
// 14、支持公司常用最多的三个型号ATMEGA32,64,128。
// 15、支持开门狗自定义开关,自定义时钟频率


/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.9 Standard
Automatic Program Generator
?Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
Project      : AVR_BootLoader
Version     : V1.00
Date         : 2014-7-19
Author      : Sui Hongwei
Company : SCICALA
Comments:
Chip type                   : ATmega64L
Program type             : Boot Loader - Size:1024words
AVR Core Clock frequency: 16.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size           : 1024
*****************************************************/
#include "AVR_boot.h"   // 
//--------------------------------------------------//
//
#define CONNECTCNT         7
//
uchar KEY_Data[10] = {"SCICALA"};
// Declare your global variables here
//--------------------------------------------------//
// 
uchar     RX_buff[BUFSIZE];                          // 
uchar   Frame_State,SOH_Wait_cnt;            // 
uint    Time_cnt,Error_cnt;                             // 
uint    buffptr,buffptr_old,buffptr_New;            // 1024
ulong   FlashAddr;                                          // Flash
uchar   UpdatedSta;                                        // 
//-----------------------------------------------//
//(code=0x03)(code=0x05)Flash
void boot_page_ew(ulong p_address,char code)
{
    #asm
     ldd  r26,y+1       ; R26 LSB
     ldd r27,y+2        ; R27 MSB
    #endasm
    SPM_REG = code;                 // SPMCSR
    #asm
     mov r30,r26
     mov r31,r27
    #endasm
    #ifdef  ATMEGA128
     RAMPZ=(p_address>>16);     // RAMPZ0 = 1: ELPM/SPM 访$8000 - $FFFF ( 64K )
    #endif
    #asm("spm");                // Flash
}
//Flash
void boot_page_fill(uint A_address,uint data)
{
      #asm
        LDD R30,Y+2     ; R30 LSB
        LDD R31,Y+3     ; R31 MSB
        LD  R26,Y
        LDD R27,Y+1
        MOV R0,R26
        MOV R1,R27
        MOV R26,R30
        MOV R27,R31
      #endasm
        SPM_REG =0x01;           //SPMCSR
      #asm
        mov r30,r26
        mov r31,r27
      #endasm
        #asm("spm");            //Flash
}
//Flash
void wait_page_rw_ok(void)
{
      while(SPM_REG & 0x40)
     {
         while(SPM_REG & 0x01);
         SPM_REG = 0x11;
         #asm("spm");
         while(SPM_REG & 0x01);
     }
}
//-----------------------------------------------//
//Flash
void write_one_page(uchar data[])
{
    uint i;
    boot_page_ew(FlashAddr,0x03);         //Flash
    wait_page_rw_ok();                    //
    for(i=0;i<SPM_PAGESIZE;i+=2)          //Flash  
    {
        boot_page_fill(i,(uint)data[i]+(data[i+1]<<8));
        wait_page_rw_ok();
    }
    boot_page_ew(FlashAddr,0x05);         //Flash
    wait_page_rw_ok();                    //
}
//--------------------------------------------------//
//1S
unsigned char Wait1S_UART()
{
uchar i=0;
  do
  {
    #if WDGEn
    Watchdog_Reset();                       // 
    #endif
    if(TIFR&0x10)                           // OCF1A: T/C1  A 
    {
        TIFR|=0x10;                         // Time1
        i++;
        if(i>=4)                            // 1S 250ms*4=1S
        {   Frame_State=0x06; break;    }   // 
    }
    if(UCSRAREG(COMPORTNo) & 0x80)
    {
        UCSRAREG(COMPORTNo)|=0x80;          // 
        #if Run_LEDEn
        Run_LED;                            // LED
        #endif
        i=100;
        return UDRREG(COMPORTNo);           // UDR0
    }
  }
  while(100!=i);                            // ||退
}
//***************************************************//
//===================================================//
void main(void)
{
uchar   packNO,packNO_old;  // 
uint    crc16;              // CRC
uint    li;                 // 
uchar   ch, cl;             // 
    PORT_Init();            // 
    UART_Init();            // 
    Time1_Init();           //  250ms
    #if WDGEn
    WatchDog_Enable();      // (2S)
    #else
    WatchDog_Disenable();   // 
    #endif
    #if Wait_BootTime
    Time_cnt=EEPROM_Read(EE_TimeAddr);  // boot
    #endif
    #if SafeUpdated_En
    UpdatedSta=EEPROM_Read(EE_SafeAddr);// 
    #endif
    #asm("cli")             // 
    #if Delay_En            // 
    for(li=0;li<5000;li++)
    {   #asm("nop") }
    #endif
//-----------------------------------------------//
//""退Bootloader0x0000
    Time_cnt += WiteTimeCnt;
    cl = 0;
    while(1)
    {
        if(TIFR&0x10)                   // OCF1A: T/C1  A 
        {
            TIFR|=0x10;                 // Time1
            #if Run_LEDEn
            Run_LED;                    // LED
            #endif
            Time_cnt--;
            if(Time_cnt==0)             // 
            {
                #if SafeUpdated_En
                if(UpdatedSta)              // 
                {   while(1);           }   // boot
                else
                #endif
                {   quit_boot();    }       // 
            }
            if(UCSRAREG(COMPORTNo) & 0x80)
            {
                ch=Wait_UART();
                if(ch== KEY_Data[cl])
                {   cl++;   }
                else
                {   cl = 0; }
                //WriteCom(ch);         // 
            }
            if(cl == CONNECTCNT)break;
        }
        #if WDGEn
        Watchdog_Reset();               // 
        #endif
    }
//-----------------------------------------------//
//Xmodex CRC=“C”soh
    Time_cnt = TimeOutCntC;
    while(1)
    {
        if(TIFR&0x10)                   // OCF1A: T/C1  A 
        {
            TIFR|=0x10;                 // Time1
            #if Run_LEDEn
            Run_LED;                    // LED
            #endif
            Send_UART(XMODEM_RWC) ;     // "C"
            Time_cnt--;
            if(Time_cnt == 0)           // 
            {
                #if SafeUpdated_En
                if(UpdatedSta)                  // 
                {   while(1);       }   // boot
                else
                #endif
                {   quit_boot();    }           // 
            }       // 
        }
        if(UCSRAREG(COMPORTNo) & 0x80)  // 
        {
            #ifdef  Xmodem
            if( Wait_UART()== XMODEM_SOH)  //XMODEM  0x01
            #else   // Xmodem_1K
            if( Wait_UART()== XMODEM_STX)  //XMODEM  0x02
            #endif
            break;
        }
        #if WDGEn
        Watchdog_Reset();               // 
        #endif
    }
//-----------------------------------------------//
// Xmodem
// 10*6S
// 10*6S=1min
    packNO = 1;         // Xmodem  0x01
    packNO_old=0;
    buffptr = 0;
    buffptr_old=0;
    Error_cnt = 0;
    FlashAddr = 0;
    Frame_State=0x01;   // 
    while(1)
    {
        switch (Frame_State)    // 
        {
            case 0x00:  //  
            {
                ch=XMODEM_NUL;                  // 
                if(UCSRAREG(COMPORTNo) & 0x80)  // 
                { ch=Wait_UART();   }           // 
                if(TIFR&0x10)                   // OCF1A: T/C1  A 
                {
                    TIFR|=0x10;                 // Time1
                    SOH_Wait_cnt++;             //  250ms
                    if(SOH_Wait_cnt>=24)        // (6S*10=1min)
                    {
                        Frame_State=0x06;       // 
                        SOH_Wait_cnt=0;         // 
                        #if Run_LEDEn
                        Run_LED;                    // LED
                        #endif
                    }
                }
                //------------------------------
                if(ch== XMODEM_EOT) // 
                {
                    for(li=(buffptr_New-128);li<buffptr_New;)   // 16
                    {
                        if((RX_buff[li++])!=0xff)break;         // EOT FF CF
                        {
                            if((RX_buff[li++])!=0xcf)break;     // EOT FF CF
                        }
                    }
                    if(li==buffptr_New)
                    {   Send_UART(XMODEM_ACK);          // 
                        Frame_State=0x0ff;              // 退boot
                    }
                    else
                    {
                        Frame_State=0x06;               // 
                        SOH_Wait_cnt=0;                 // 
                    }
                }
                #ifdef  Xmodem
                if(ch== XMODEM_SOH) // Xmodem
                #else   // Xmodem_1K
                if(ch== XMODEM_STX) // Xmodem_1K
                #endif
                {
                    Frame_State=0x01;          // 
                    SOH_Wait_cnt=0;            // 
                }
            }
            break;
            case 0x01:  //
            {
                ch =  Wait1S_UART();             // 
                cl = ~Wait1S_UART();
                if(ch == cl)                     // 
                {   Frame_State=0x02;
                    packNO=ch;                   // 
                }
                else
                {   Frame_State=0x06;       }   // ANK
            }
            break;
            case 0x02:  // CRC
            {
                for(li = 0; li < BUFFER_SIZE; li++)             //  (128)
                {
                    RX_buff[buffptr++] = Wait1S_UART();     // 
                    // 1S退for21S+2S
                    if(Frame_State==0x06)break;
                }
                crc16 = Wait1S_UART();
                crc16=crc16<<8;
                crc16 += Wait1S_UART();                     // 2CRC
                if(CRC16_Word(&RX_buff[buffptr - BUFFER_SIZE],BUFFER_SIZE)==crc16)  // CRC
                {
                    if(packNO==packNO_old)          // flash
                    {   Frame_State=0x05;           // ACK
                        buffptr=buffptr_old;
                    }
                    else
                    {   Frame_State=0x03;          // 
                        buffptr_New=buffptr;       // 
                    }
                }
                else
                {   Frame_State=0x06;               // NAK
                    buffptr=buffptr_old;            // 
                }
            }
            break;
            case 0x03:  // ,
            {
                if(FlashAddr < BootStart)           //Boot
                {
                    #if BUFFER_SIZE < SPM_PAGESIZE  // ---
                    if(buffptr >= SPM_PAGESIZE)     //
                    {                               //,
                        write_one_page(&RX_buff[0]);    //Flash
                        FlashAddr += SPM_PAGESIZE;  //Flash
                        buffptr = 0;
                    }
                    #else     //----------------------
                    while(buffptr > 0)              //,
                    {
                        write_one_page(&RX_buff[BUFSIZE - buffptr]);
                        FlashAddr += SPM_PAGESIZE;   //Flash
                        buffptr -= SPM_PAGESIZE;
                    }
                    #endif   //-----------------------
                }
                else                                //BootStart
                { buffptr = 0;  }                   //
                Frame_State=0x04;
            }
            break;
            case 0x04:  //Flash
            {
                Frame_State=0x05;                   // 
                buffptr_old=buffptr;                // 
            }
            break;
            case 0x05:  // ACK
            {
                packNO_old=packNO;                  // 
                Send_UART(XMODEM_ACK);              // 
                //WriteCom(packNO);         // 
                //WriteCom(FlashAddr);      // 
                //WriteCom(FlashAddr>>8);   // 
                Error_cnt = 0;                      // 
                Frame_State=0x00;                   // ()
            }
            break;
            case 0x06: // =ANK
            {
                Send_UART(XMODEM_NAK);              // 
                Error_cnt++;                        // 
                Frame_State=0x00;                   // 
            }
            break;
            default: // 退
            {
                #if SafeUpdated_En
                EEPROM_Write(EE_SafeAddr,0);//  0
                #endif
                quit_boot();                        //退Bootloader
            }
            break;
        } // switch End
        if(Error_cnt>10) // 10退
        {
            Send_UART(XMODEM_CAN);      // ()
            #if SafeUpdated_En
            EEPROM_Write(EE_SafeAddr,1);//  1
            #endif
            while(1);                   // 
        }
        #if WDGEn
        Watchdog_Reset();                           // 
        #endif
    } // while end
//-------------------------------------------------//
}   // main end
//-----------------------------------------------//
#include "AVR_boot.h"  // 
//-----------------------------------------------//
//-----------------------------------------//
// 
void PORT_Init()
{
// 
// 
    #if Run_LEDEn
    DDRREG(LEDPORT)|=(1 << LEDPORTNo); // 
    #endif
}
//-----------------------------------------------//
// 
void UART_Init()
{
    #if RS485_En
    DDRREG(RS485PORT)|=(1 << RS485TXEn);    // (PC5)RS485
    RX485DE_RX;                             // 
    #endif
    UCSRAREG(COMPORTNo) = 0x00;
    UCSRBREG(COMPORTNo) = 0x18;             // Enable Receiver and Transmitter
    UCSRCREG(COMPORTNo) = 0x0E;             // Set frame. format: 8data, 2stop bit
    // 
    UBRRHREG(COMPORTNo) = BAUD_H;            // 0X00
    UBRRLREG(COMPORTNo) = BAUD_L;            // Set baud rate   16M 9600 0x0067
}
// 250msTime1
//-----------------------------------------------//
//使11024CTC4
void Time1_Init()
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 16MHz
   TCCR1A=0x00;                             // CTC4
   TCCR1B=0x08;                             // CTC4
   TCCR1B|=0x03;                            // clkI/O/64 ( ) 16M=4us
   OCR1A=T1_TCNT;                           // 250MS
}
//-----------------------------------------------//
//  2s
void WatchDog_Enable(void)
{
// Watchdog Timer initialization
// Watchdog Timer Prescaler: OSC/2048k
   MCUCSR=0x00;                 // 
   WDTCR=0x1F;                  // 使 500ms(D)1.0S(E) 2.0S(F)
   WDTCR=0x0F;
}
// 
void WatchDog_Disenable(void)   // 
{
   MCUCSR=0x00;                 // 
   WDTCR=0b00011111;            //  使 使(B4=1) 2.0S(F)
   WDTCR=0b00000111;            //  2.0S(7)
}
// 
void Watchdog_Reset(void)
{   #asm("wdr")     }           // 
//-----------------------------------------------//
//-----------------------------------------//
//
void Send_UART(unsigned char dat)
{
 uchar i;
#if RS485_En
  RX485DE_TX;                               // 使RS485
#endif
  UDRREG(COMPORTNo) = dat;   // UDR0
  //
  while(!(UCSRAREG(COMPORTNo) & 0x40));     //  Bit 6 – TXC: USART 
  UCSRAREG(COMPORTNo)|=0x40;                // 
#if RS485_En
  RX485DE_RX;                               // 使RS485
#endif
}
//-----------------------------------------------//
//
unsigned char Wait_UART()
{
    while(!(UCSRAREG(COMPORTNo) & 0x80));   //  Bit 7 – RXC: USART 
    UCSRAREG(COMPORTNo)|=0x80;              // 
    #if Run_LEDEn
    Run_LED;                                // LED
    #endif
    return UDRREG(COMPORTNo);
}
//-----------------------------------------------//
//CRC
int CRC16_Word(char *ptr, int count)
{
    int crc = 0;
    char i;
    while (--count >= 0)
    {
        crc = crc ^ (int) *ptr++ << 8;
        i = 8;
        do
        {
        if (crc & 0x8000)
            crc = crc << 1 ^ 0x1021;
        else
            crc = crc << 1;
        } while(--i);
    }
    return (crc);
}
//-----------------------------------------------//
//退Bootloader0x0000
void quit_boot(void)
{
     MCUCR = 0x00;                  //IVSEL "0“ Flash 
     #ifdef ATMEGA128
     RAMPZ = 0x00;                  //0: ELPM/SPM 访$0000 - $7FFF ( 64K )
     #endif
     #asm("jmp 0x0000")             //Flash0x0000
}
//-----------------------------------------------//
// EEPROM
uchar EEPROM_Read(uint Addr)            // EEPROM1   0
{
    while(EECR & 0x02);                 // 
    EEAR = Addr;                        // 
    EECR |= 0x01;                       // EERE  b0
    return(EEDR);                       // 
}
// EEPROM
void EEPROM_Write(uint Addr,char Data)  // EEPROM 1
{
    EEAR = Addr;                        // 
    EEDR = Data;                        // 
  //    #asm("cli")                     // EEMPE1,EEPE1,4
    EECR |= 0x04;                       // EEMWE            b2
    EECR |= 0x02;                       // EEWE b1
    //#asm("sei")
}
//-----------------------------------------------//
//-------------------------------------------------------//
#ifndef _AVR_BOOT_H_
#define _AVR_BOOT_H_      1
// 
#include "Config.h"
//------------------------------------------------------//
#ifdef    ATMEGA32
#include 
#endif
#ifdef  ATMEGA64
#include 
#endif
#ifdef  ATMEGA128
#include 
#endif
//---------------------------------------------------//
typedef signed char     schar;
typedef signed int      sint;
typedef signed long     slong;
typedef unsigned char   uchar;
typedef unsigned int    uint;
typedef unsigned long   ulong;
//--------------------------------------------------//
// 
void UART_Init();
void PORT_Init();
void Time1_Init();
void Send_UART(unsigned char dat);
unsigned char Wait_UART();
unsigned char Wait1S_UART();
void WatchDog_Disenable(void);
void quit_boot(void);
int CRC16_Word(char *ptr, int count);
void write_one_page(uchar data[]);
void WatchDog_Enable(void);
void Watchdog_Reset(void);
uchar EEPROM_Read(uint Addr);
void EEPROM_Write(uint Addr,char Data);
//--------------------------------------------------//
//使
#define CONCAT(a, b)       a ## b
#define CONCAT3(a, b, c)   a ## b ## c
//
#define PORTREG(No)        CONCAT(PORT, No)
#define PINREG(No)         CONCAT(PIN, No)
#define DDRREG(No)         CONCAT(DDR, No)
#define UDRREG(No)         CONCAT(UDR, No)
//
#define UCSRAREG(No)       CONCAT3(UCSR, No, A)
#define UCSRBREG(No)       CONCAT3(UCSR, No, B)
#define UCSRCREG(No)       CONCAT3(UCSR, No, C)
#define UBRRHREG(No)       CONCAT3(UBRR, No, H)
#define UBRRLREG(No)       CONCAT3(UBRR, No, L)
//---------------------------------------------------//
// 
#define     RX485DE_RX      PORTREG(RS485PORT)&=~(1 << RS485TXEn);  // SCI使
#define     RX485DE_TX      PORTREG(RS485PORT)|=(1 << RS485TXEn);   // SCI使
#define     Run_LED         PORTREG(LEDPORT)^= (1 << LEDPORTNo);    // bootLED
//---------------------------------------------------//
//Xmoden
#define XMODEM_NUL          0x00        // null
#define XMODEM_SOH          0x01        // Xmodem
#define XMODEM_STX          0x02        // Xmodem_1K
#define XMODEM_EOT          0x04        // 
#define XMODEM_ACK          0x06        // 
#define XMODEM_NAK          0x15        // 
#define XMODEM_CAN          0x18        // 
#define XMODEM_EOF          0x1A        // 
#define XMODEM_RWC          'C'         // CRC16-128
//-------------------------------------------------------//
#ifdef  Xmodem_1K
#define BUFFER_SIZE         1024
#else  // Xmodem
#define BUFFER_SIZE         128
#endif
//-----------------------------------------------------//
#ifdef  ATMEGA32
#define SPM_PAGESIZE        128         // SPM 
#define BootStart           0x3C00*2    // 
#define SPM_REG             SPMCR       // SPM
#endif
#ifdef  ATMEGA64
#define SPM_PAGESIZE        256         // SPM 
#define BootStart           0x7C00*2    // 
#define SPM_REG             SPMCSR      // SPM
#endif
#ifdef  ATMEGA128
#define SPM_PAGESIZE        256         // SPM 
#define BootStart           0xFC00*2    // 
#define SPM_REG             SPMCSR      // SPM
#endif
// SPM_PAGESIZE
#if BUFFER_SIZE < SPM_PAGESIZE
#define BUFSIZE SPM_PAGESIZE            // UART
#else
#define BUFSIZE BUFFER_SIZE             // UART
#endif
//
#define BAUD_SETTING (unsigned char)((unsigned long)CRYSTAL/(16*(unsigned long)BAUDRATE)-1)
#define BAUD_H ((unsigned char)(BAUD_SETTING>>8))
#define BAUD_L (unsigned char)BAUD_SETTING
//T1
#define T1_TCNT (unsigned int)((unsigned long)CRYSTAL*250/(64 * 1000));
//--------------------------------------------------------//
#endif // _AVR_BOOT_H_
#ifndef _CONFIG_H_
#define _CONFIG_H_      1
//*********************************************************//
//               上海霜蝉-AVR_bootV1.00
// 1V1.00 CodeWizardAVR V2.03.9 Standard;
// 2AVR;
// 3XmodemXmodem_1K;
// 4"00",1;
// 53S退bootboot;
// 61;
// 710;
// 8;
// 9 1 ;
// 10 10 ;
// 116S;
// 12Boot Loader - Size:1024words;
// 1338.400KB/S2.400KB/S;
// 14持上海霜蝉ATMEGA32,64,128
// 15,
//*********************************************************//
//  (char to int;char is unsigned)
// >=256
// 
// 
//#define   ATMEGA32
#define ATMEGA64                // Atmgea64L
//#define   ATMEGA128
// XmodemXmodem_1K
#define Xmodem             // Xmodex 128(CRC16)
//#define Xmodem_1K            // Xmodem 1024(CRC16)
//-----------------------------------------------//
// MHz
#ifndef CRYSTAL
#define CRYSTAL            16000000         // 16M
#endif
//  38400~2400
#define BAUDRATE           9600
//  = WiteTimeCnt * 250ms
// 
#define WiteTimeCnt        10               // 10=2.5s
// boot(1=250ms)+2.5S(WiteTimeCnt)
#define Wait_BootTime      40               // (1=250ms)+2.5S
//  = TimeOutCntC * 250ms
// 'C'
#define TimeOutCntC        40               // 40=1min
// (ATMEA32 )
#define COMPORTNo          0                // UART0
// 使
#define WDGEn              1                // 使
// 使485
#define RS485_En           1                // 使485使
// 485
#define RS485PORT          E                // PORTE
#define RS485TXEn          2                // PORTE2
// 使LED
#define Run_LEDEn          1                // 使bootLED
// LED
#define LEDPORT            B                // PORTB
#define LEDPORTNo          6                // PORTB6
// 
#define Delay_En           0
// boot(1=250ms)+2.5S(WiteTimeCnt)
// 使EEPROM
#define Wait_BootTime      40               // (40*250ms)+2.5S
#define EE_TimeAddr         0               // 使EEPROM 1
// ()
// 使EEPROM
#define SafeUpdated_En     1
#define EE_SafeAddr        1               // 使EEPROM 1
//-----------------------------------------------//
#endif  // _CONFIG_H_
//End of file: bootcfg.h

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
13
关闭 站长推荐上一条 /3 下一条