2018年4月5日 星期四

ESP8266 RTOS : Device Firmware Update Over the Air (DFU-OTA) via the Private Server

      ESP8266 is a very popular micro-controller featuring WIFI with its bargaining price. There are some product based on ESP8266/ESP8285 (ESP8285 = ESP8266 embedded 1 MB flash) for home IoT using. The makers enjoy remolding the firmware of the products to fix their personal purposes.
      In most case, the maker re-program ESP8266 in the framework of Arduino, thus, there are lots post and discussion about how to deal with DFU-OTA based on ESP8266 Arduino. However, The information about the same goal but the ESP8266 based on RTOS framework is limited, undocument or incomplete. This post wants to fill the gap.
   By default, DFU-OTA server is based on Espressif: It forces the ESP8266 to be on internet. But some use case the ESP8266 would not be connected with internet (maybe for the security issue). Therefore, private DFU-OTA is very necessary. In here I assume your DFU-OTA server is linux based, But it is easy to port the DFU-OTA function to the other platform, for the DFU-OTA working principle is typical TCP-IP.

Note: this example assumes your esp8266 is within 1MB flash!  It may work in otherwise size or not I am not sure.


零. Download the requisite library:
     In here, You should download the include/upgrade.h,  user/upgrade_lib.c and user/fota_crc32.c., and move them into your ESP8266 project folder. I assume the files place under the sub-folder, dfu-ota, of your project folder.
   
一. Create a c file,  named  dfu_ota.c, under the same sub-folder, the code be :

#include "esp_common.h"
#include "espconn.h"


#include "dfu_ota.h"
#include "upgrade.h"



#define LOCAL     static

LOCAL struct espconn g_tcp_client;
LOCAL esp_tcp g_tcp;
LOCAL int g_firmware_length = 0;

enum 
{
 TCP_CONNECTING   = 0x00,
 SENT_TARGET_SECTION  = 0x01,
 RECEIVED_LENGTH   = 0x02,
 KEEP_RECEIVING_DATA  = 0x03,
 RECEIVED_DATA   = 0x04,

 TCP_DISCONNECTED = 0xff,
};


LOCAL int g_sending_state = TCP_DISCONNECTED;


int firmware_upgrading_fail(void)
{ 
 printf("upgrading fail\r\n");
 espconn_disconnect(&g_tcp_client);

 printf("reboot the system\r\n");
 system_restart();
}/*firmware_upgrading_fail*/


//LOCAL uint8_t g_tcp_server_ip[4] = {0};
LOCAL uint8_t g_tcp_retry_connection_count = 0;

LOCAL void tcp_connection_error_callback(void *arg, int8_t err)
{
 struct espconn *p_tcp_server;
 p_tcp_server = arg;

 printf("tcp connection err = %d\r\n", err);

 if(ESPCONN_OK != err)
 {
#define MAX_RETRY_CONNECTION_COUNT   (5)

  if(MAX_RETRY_CONNECTION_COUNT > g_tcp_retry_connection_count)
  {
   printf("retry the tcp connection...\r\n");
   delay_ms(1000);
   g_tcp_retry_connection_count++;
   espconn_connect(&g_tcp_client);
  }
  else
  {
   printf("relinquish this upgrading\r\n");
   g_tcp_retry_connection_count = 0;
   firmware_upgrading_fail();
  }/*if */
 }/*if ESPCONN_OK */

}/*tcp_connection_error_callback*/


LOCAL void tcp_connect_callback(void *arg)
{
 struct espconn *p_tcp_server;
 uint8_t tcp_state;
 uint8_t target_section;
 p_tcp_server = arg;

 if(USER_BIN1 == system_upgrade_userbin_check())
 {
  target_section = 2;
  printf("current firmware in user1\r\n");
 }
 else
 {
  target_section = 1;
  printf("current firmware in user2\r\n");
 }

 printf("fetch firmware%d\r\n", target_section);

 tcp_state = espconn_send(p_tcp_server, &target_section, sizeof(uint8_t));
 printf("target_section sending\r\n");
 g_sending_state = SENT_TARGET_SECTION;
#define INTERVAL_BETWEEN_PACKETS_IN_MSEC  (10)

 delay_ms(INTERVAL_BETWEEN_PACKETS_IN_MSEC);
}/*tcp_connect_callback*/


LOCAL void tcp_sent_to_buffer_callback(void *arg)
{
 struct espconn *p_tcp_server;
 uint8_t tcp_state;

 p_tcp_server = arg;
}/*tcp_sent_to_buffer_callback*/


#define OTA_PACKET_SIZE     (1280)
LOCAL int g_remained_firmware_length = 0;

LOCAL void tcp_received_callback(void *arg, char *p_data, unsigned short len)
{
 struct espconn *p_tcp_server;
 uint8_t tcp_state;
 uint8_t data_buffer[OTA_PACKET_SIZE];

 p_tcp_server = arg;

 switch(g_sending_state)
 {
  case SENT_TARGET_SECTION:
  if(sizeof(int) != len)
  {
   printf("received length error\r\n");
   goto Flag_Error_Occurring;
  }/*if */

  g_sending_state = RECEIVED_LENGTH;
  memcpy(&g_firmware_length, p_data, sizeof(int));
  printf("firmware size = %d\r\n", g_firmware_length);

  if(g_firmware_length < 0)
  {
   printf("firmware_length error\r\n");
   goto Flag_Error_Occurring;
  }
  g_remained_firmware_length = g_firmware_length;
  break;


  case RECEIVED_LENGTH:
  case KEEP_RECEIVING_DATA:

  memcpy(&data_buffer[0], p_data, len);
  g_remained_firmware_length -= len;

  if(0 > g_remained_firmware_length)
  {
   printf("received data size is not marched\r\n");
   goto Flag_Error_Occurring;
  }

  printf("received firmware data %d bytes, remain %d bytes...\r\n", 
   g_firmware_length - g_remained_firmware_length, g_remained_firmware_length);

  if(false == system_upgrade(&data_buffer[0], len))
  {
   printf("\r\nsystem_upgrade error\r\n");
   goto Flag_Error_Occurring;
  }/*if false == system_upgrade*/


  if(0 == g_remained_firmware_length)
  {
   printf("\r\n firmware has been downloaded done\r\n");
   g_sending_state = RECEIVED_DATA;

   if( false == upgrade_crc_check(system_get_fw_start_sec(), g_firmware_length))
   {
    printf("firmware upgrading FAIL : CRC is not consisted!!\r\n");
    system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
    espconn_disconnect(&g_tcp_client);
   }
   else
   {
    printf("firmware upgrading is successful.\r\n");
    system_upgrade_flag_set(UPGRADE_FLAG_FINISH);
    espconn_disconnect(&g_tcp_client);
   }/* check crc*/
  }
  else
  {
   system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
   g_sending_state = KEEP_RECEIVING_DATA;
  }
  break;
 default:
  break;
 }
 return;


Flag_Error_Occurring:
 firmware_upgrading_fail();
 return;
}/*tcp_received_callback*/


LOCAL void tcp_disconnect_callback(void* arg)
{
 printf("ota server disconnected\r\n");
 g_sending_state = TCP_DISCONNECTED;

 system_upgrade_deinit();
 if (UPGRADE_FLAG_FINISH == system_upgrade_flag_check())
 {
  printf("reboot the system for new firmware\r\n");
  system_upgrade_reboot();
 }
 else
 {
  printf("upgrade firmware fail\r\n");
  system_restart();
 }

}/*tcp_disconnect_callback*/



int device_firmware_upgrade_over_the_air(uint8_t *p_server_ip)
{
 uint8_t con_status;
 uint8_t tcp_state;

 printf("start device firmware upgrading over the air...\r\n");


 con_status = wifi_station_get_connect_status();
 
 if (con_status != STATION_GOT_IP) 
 {
  printf("error, this endpoint has not be connected with router.\r\n");
  printf("relinquish this firmware upgrading.\r\n");
  firmware_upgrading_fail();
  return -1;
 }/*if*/


#define TCP_SERVER_REMOTE_PORT       (5555)
 g_tcp.remote_port = (TCP_SERVER_REMOTE_PORT);
 g_tcp_client.type = ESPCONN_TCP;
 g_tcp_client.proto.tcp = &g_tcp;

 memcpy(g_tcp.remote_ip, p_server_ip, 4*sizeof(uint8_t));

 espconn_regist_reconcb(&g_tcp_client, tcp_connection_error_callback);
 espconn_regist_connectcb(&g_tcp_client, tcp_connect_callback);
 espconn_regist_sentcb(&g_tcp_client, tcp_sent_to_buffer_callback);
  espconn_regist_recvcb(&g_tcp_client, tcp_received_callback);
 espconn_regist_disconcb(&g_tcp_client, tcp_disconnect_callback);

 system_upgrade_flag_set(UPGRADE_FLAG_START);
 system_upgrade_init();


#define RELATIVE_END_SECTOR_NUM     (0x80 - 0x0c)
 {
  uint16_t begin_sector;
  uint16_t i;
  printf("erasing flash sector to store new firmware, it takes a while...\r\n");
  begin_sector = system_get_fw_start_sec();
  printf("erasing flash sector from 0x%02x to 0x%02x\r\n", begin_sector, 
   begin_sector + RELATIVE_END_SECTOR_NUM - 1);

  for(i = 0; i< RELATIVE_END_SECTOR_NUM; i++)
   spi_flash_erase_sector(begin_sector + i);
 }/*erase flash*/


 tcp_state = espconn_connect(&g_tcp_client);
 g_sending_state = TCP_CONNECTING;

 if(0 != tcp_state)
 {
  g_sending_state = TCP_DISCONNECTED;
  printf("espconn_connect error, give up this connection\r\n");
  firmware_upgrading_fail();
 }/*if 0*/

 return 0;
}/*device_firmware_upgrade_over_the_air*/


The corresponding header dfu_ota.h placed in the same folder, is,

#ifndef _DFU_OTA_H_
#define _DFU_OTA_H_


int device_firmware_upgrade_over_the_air(uint8_t *p_server_ip);

#endif

To here, the content under dfu_ota folder  be :

$ ls dfu_ota/
dfu_ota.c  dfu_ota.h  fota_crc32.c  Makefile  upgrade.h  upgrade_lib.c

The Makefile under dfu_ota folder, copied from common sub-folder, is with the modification, about line 14:


ifndef PDIR
GEN_LIBS = libdfu_ota.a
endif

The Makefile under your project's root folder, Should be added the dfu_ota content:

SUBDIRS=    \
        user    \
        :
        dfu_ota
:
:
COMPONENTS_eagle.app.v6 = \
        user/libuser.a  \
        :
        dfu_ota/libdfu_ota.a


二. DFU-OUA server code.

The DFU-OTA server would be responding the DFU requesting, the code, dfu_ota_server.c be:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#include <linux/limits.h>

//#include <inttypes.h>

 #include <errno.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#include <signal.h> 

#include <sys/stat.h>

/*for show ip*/
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>

#include <pthread.h>

#ifdef __mips__
 #include <byteswap.h>
#endif

#include <sys/time.h>


#define PORT_NUMBER       (5555)

#define ONE_PACKET_MAX_SIZE     (4*1024)

#define LOCAL         static

#define INVALID_SOCKET      (int)(~0)
#define MAX_CLIENT_NUMER     (32)



void delay_micro_sec(unsigned int delay_time_in_us)
{
 struct timeval now;
 struct timeval period;
 struct timeval end;

 gettimeofday(&now, NULL);

 period.tv_sec = delay_time_in_us / 1000000;
 period.tv_usec = delay_time_in_us % 1000000;

 timeradd(&now, &period, &end);

 while(timercmp(&now, &end, < ))
  gettimeofday(&now, NULL);

}/*delay_micro_sec*/


LOCAL int g_master_socket;
LOCAL int g_client_socket;

int esp8266_ota_server_start(char **pp_firmware_location)
{
 int i;
 struct sockaddr_in server_addr;

 if(NULL == pp_firmware_location[0] || NULL == pp_firmware_location[1])
 {
  return -1;
 }

 g_master_socket = socket(AF_INET , SOCK_STREAM , 0);

 if(-1 == g_master_socket)
 {
  printf("Could not create socket\r\n");
  return -1;
 }/*if*/

 //Prepare the sockaddr_in structure
 server_addr.sin_family = AF_INET;
 server_addr.sin_addr.s_addr = INADDR_ANY;
 server_addr.sin_port = htons(PORT_NUMBER);

 {
  int reuseaddr;
  int reuseaddr_len;
  reuseaddr = 1;
  reuseaddr_len = sizeof(reuseaddr);
  setsockopt(g_master_socket, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, reuseaddr_len);
 }/*local variabe */

 //Bind
 if(0 > bind(g_master_socket,(struct sockaddr *)&server_addr , sizeof(server_addr)) )
 {
  perror("bind failed. Error\r\n");
  return -2;
 }/*if bind*/
 printf("ota server is ready to be connected\r\n\r\n");


#define MAX_PENDING_CONNECTION_NUMBER   (3)

 listen(g_master_socket , MAX_PENDING_CONNECTION_NUMBER);

 while(1)
 {
  struct sockaddr_in client_addr;
  int socket_len;

  int written_len;
  unsigned int firmware_size;
  int is_succ_sent;

  unsigned char target_firmware_section;

  g_client_socket = accept(g_master_socket, 
   (struct sockaddr *)&client_addr, (socklen_t*)&socket_len);

  if(INVALID_SOCKET == g_client_socket)
  {
   printf("accepted ERROR\r\n");
   continue;
  }/*if */

  printf("\r\n\r\n%s connected\r\n", inet_ntoa(client_addr.sin_addr));

  is_succ_sent = 0;
  {
   socklen_t addr_len;

   addr_len = sizeof(client_addr);
   getpeername(g_client_socket, (struct sockaddr*)&client_addr, &addr_len);
  }/*local variable*/


  {
   struct timeval timeout_val;

#define MAX_ONE_PACKET_TIMEOUT_IN_SEC    (10)
   timeout_val.tv_sec = MAX_ONE_PACKET_TIMEOUT_IN_SEC;
   timeout_val.tv_usec = 0;

   setsockopt(g_client_socket, SOL_SOCKET, SO_SNDTIMEO, 
    &timeout_val, sizeof(timeout_val));

   setsockopt(g_client_socket, SOL_SOCKET, SO_RCVTIMEO, 
    &timeout_val, sizeof(timeout_val));
  }/*local variables*/

  {

   unsigned char read_buffer[16];
   int read_size;

   read_size = read(g_client_socket, &read_buffer[0], sizeof(read_buffer));
   if(1 != read_size)
   {
    printf("received firmware region index size error\r\n");
    goto Flag_end_connection;
   }
   target_firmware_section = 0;
   memcpy(&target_firmware_section, &read_buffer[0], sizeof(unsigned char));


   if(!(1 == target_firmware_section || 2 == target_firmware_section) )
   {
    printf("received firmware region index is not valid\r\n");
    printf("firmware_region_index = %d\r\n", (int)target_firmware_section);
    goto Flag_end_connection;
   }/*if*/

   printf("firmware%d would be transmitted to endpoint\r\n", (int)target_firmware_section);
  }/*local variable*/

  {
   struct stat fw_dir_st = {0};

   if(-1 == stat(pp_firmware_location[target_firmware_section - 1], &fw_dir_st))
   {
    printf("ERROR :: %s does not exist!\r\n", 
     pp_firmware_location[target_firmware_section - 1]);

    goto Flag_end_connection;
   }/*if */

   firmware_size = (int)fw_dir_st.st_size;
   printf("firmware%d size = %3.1f KB\r\n", target_firmware_section, firmware_size/1024.0);
  }/*local variable*/

  {
   unsigned int firmware_size_le;
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
   firmware_size_le = __bswap_32(firmware_size);
#else
   firmware_size_le = firmware_size;
#endif
   written_len = write(g_client_socket, &firmware_size_le, sizeof(unsigned int));

   if(sizeof(unsigned int) != written_len)
   {
    printf("\r\nsend firmware length error\r\n");
    goto Flag_end_connection;
   }/*if */
  }/*send data length*/

 {
  unsigned int remain_firmware_size;
  FILE *fp;

  remain_firmware_size = firmware_size;

  fp = fopen(pp_firmware_location[target_firmware_section - 1], "rb");

  if(NULL == fp)
  {
   printf("open file %s error\r\n", 
    pp_firmware_location[target_firmware_section - 1]);
   goto Flag_end_connection;
  }/*if */

  while(remain_firmware_size > 0)
  {
#define OTA_PACKET_SIZE       (1280)
   unsigned char data_buffer[OTA_PACKET_SIZE];
   unsigned int sending_size;

   sending_size = fread(&data_buffer[0], 1, sizeof(data_buffer), fp);
   written_len = write(g_client_socket, &data_buffer[0], sending_size);

   if(sending_size != written_len)
   {
    printf("\r\nsend firmware data error\r\n");
    goto Flag_end_connection;
   }/*if*/

   remain_firmware_size -= written_len;

   printf("\rfirmware data has sent %3.1f KB, remain %3.1f KB   ", 
    (firmware_size - remain_firmware_size)/1024.0, remain_firmware_size/1024.0);
   fflush(stdout);

#define PACKET_INTERVAL_IN_MSEC     (400)
   delay_micro_sec(PACKET_INTERVAL_IN_MSEC*1000);
  }/*while*/

  fclose(fp); fp = NULL;
  printf("\r\n");

  is_succ_sent = 1;
 }/*send data */

 printf("firmware %3.1f KB has been sent successfully    \r\n", firmware_size/1024.0);

Flag_end_connection:
 if(0 == is_succ_sent)
  printf("WARNING:: firmware upgrading has been FAIL\r\n");

 close(g_client_socket); g_client_socket = INVALID_SOCKET;
 }/*while*/

 close(g_master_socket);
 return 0;
}/*esp8266_ota_server_start*/


int esp8266_ota_server_end(void)
{
 if( INVALID_SOCKET != g_client_socket)
  close(g_client_socket);
 g_client_socket = INVALID_SOCKET;

 if(INVALID_SOCKET != g_master_socket)
  close(g_master_socket);
 g_master_socket = INVALID_SOCKET;

 return 0;
}/*esp8266_ota_server_end*/


void InterruptHandler(int sig)
{
 printf("\r\n__FUNCTION__ = %s\r\n", __FUNCTION__);
 esp8266_ota_server_end();

 exit(0);
}/*InterruptHandler*/


int main(int argc, char *argv[])
{
 extern char *__progname;
 int k;
 char firmware_location[2][PATH_MAX];
 char *p_firmware_location[2];

 signal(SIGINT, InterruptHandler); 

 printf("\r\n%s\r\n", __progname);

 for(k = 0; k < 2; k++){
  memset(&firmware_location[k][0], 0, PATH_MAX);
  p_firmware_location[k] = NULL;
 }/*for k*/

 k = 1;
 while(k < argc)
 {
  if(0 == strncmp("-fw1", argv[k], strlen("-fw1")) 
   || 0 == strncmp("--user1", argv[k], strlen("-user1")) )
  {
   if(k + 1 < argc)
   {
    strncpy(&firmware_location[0][0], argv[k + 1], PATH_MAX);
    p_firmware_location[0] = &firmware_location[0][0];
   }
   else
   {
    printf("ERROR :: -fw1/--user1 should be followed by firmware location.\r\n");
    return -1;
   }/*if */
  }/*if */

  if(0 == strncmp("-fw2", argv[k], strlen("-fw1")) 
   || 0 == strncmp("--user2", argv[k], strlen("-user1")) )
  {
   if(k + 1 < argc)
   {
    strncpy(&firmware_location[1][0], argv[k + 1], PATH_MAX);
    p_firmware_location[1] = &firmware_location[1][0];
   }
   else
   {
    printf("ERROR :: -fw1/--user2 should be followed by firmware location.\r\n");
    return -1;
   }/*if */
  }/*if */

  k++;
 }/*while*/


 if(NULL == p_firmware_location[0])
 {
  printf("-fw1 should be specified\r\n");
  return -1;
 }/*if non specified fw1 location*/

 if(NULL == p_firmware_location[1])
 {
  printf("-fw2 should be specified\r\n");
  return -1;
 }/*if non specified fw2 location*/


 for(k = 0; k < 2; k++)
 {
  struct stat fw_dir_st = {0};

  if(-1 == stat(p_firmware_location[k], &fw_dir_st))
  {
   printf("ERROR :: %s does not exist!\r\n", p_firmware_location[k]);
   return -1;
  }/*if */

  {
   char firmware_absolute_location[PATH_MAX];
   char *p;

   p = realpath(p_firmware_location[k], &firmware_absolute_location[0]);
   if(NULL == p)
   {
    printf("realpath error :: %s\r\n", strerror(errno));
    return -1;
   }/*if*/

   printf("firmware%d : %s\r\n", k + 1, firmware_absolute_location);
  }
  //printf("firmware%d size = %3.1f KB\r\n", k + 1, fw_dir_st.st_size/1024.0);
  
 }/*local variable*/


 printf("\r\nip address of this server:\r\n");
 {
  struct ifaddrs *ifaddr, *ifa;
  int s;
  char host[NI_MAXHOST];

  if (getifaddrs(&ifaddr) == -1)
  {
   perror("getifaddrs");
   exit(EXIT_FAILURE);
  }

  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
  {
   if (ifa->ifa_addr == NULL)
    continue;

   s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), 
     &host[0], NI_MAXHOST, NULL, 0, NI_NUMERICHOST);

   if( AF_INET == ifa->ifa_addr->sa_family)
   {
    if (s != 0)
    {
     printf("getnameinfo() failed: %s\n", gai_strerror(s));
     exit(EXIT_FAILURE);
    }
    //printf("\tInterface : <%s>\n",ifa->ifa_name );
    //printf("\t  Address : <%s>\n", host);
    printf("\t<%s> : %s\r\n", ifa->ifa_name, &host[0]);
   }
  }/*for ifa*/

  freeifaddrs(ifaddr);
 }/*local variabes*/
 printf("\r\n");
 esp8266_ota_server_start(&p_firmware_location[0]);

 return 0;
}/*main*/

And Build the dfu-ota server :

gcc dfu_ota_server.c -o dfu_ota_server


三. Modify your working project and call the function int  device_firmware_upgrade_over_the_air(uint8_t *p_server_ip) while it is time for DFU-OTA.
   Build the binary twice,  one for user1 (the common binary for being downloaded to ESP8266 via USB-UART), one for user2. (while the scrip gen_misc.sh has been executed, "STEP 2: choose bin generate" would determine this build is for user1 or user2), Once the user1 has been build, you should clean the whole output, especially the .o files, before building user2.

 四. Move the built binaries, user1.1024.new.2.bin and user2.1024.new.2.bin to your OTA server and run the dfu_ota_server commnad:

./dfu_ota_server -fw1 user1.1024.new.2.bin -fw2 user2.1024.new.2.bin


五. Before you download the user1 binary to ESP8266 via UART (USB),  It is necessary to ERASE the whole flash. In linux it is very easy, 


sudo python ~/.local/lib/python2.7/site-packages/esptool.py --port /dev/ttyUSB0 erase_flash

But if you are in Windows, as my knowing, the flashing tool would not erase the flash thoroughly, instead it only cleans the beginning flag. How to erase the flash in Windows authentically I do not know.



It is all, once it is in DFU-OTA, the server would send the Binary to the ESP8266, then ESP8266 would write the binary to the non-current working zone. If the CRC-checking is passed, ESP8266 would reboot from the other zone which contain the binary just downloaded.


※ In my case, I assume the flash size of the ESP8266 device is 1MB, if your device size is greater than it, your downloading firmware command may be need to be modified as :

sudo python ~/.local/lib/python2.7/site-packages/esptool.py --port /dev/ttyUSB0  write_flash --flash_size=1MB 0x00000 ../ESP8266_RTOS_SDK-1.5.X/bin/boot_v1.7.bin 0x01000 upgrade/user1.1024.new.2.bin  0xFE000 ../ESP8266_RTOS_SDK-1.5.X/bin/blank.bin 0xFC000  esp_init_data_default.bin --flash_mode dout


The hexadecimal codes are the addresses where the following binaries should be locates. The address of esp_init_data_default.bin is flashing-size depending.
for the common esp8266 modules:

    0x7c000 for 512 kB, modules like most ESP-01, -03, -07 etc.
    0xfc000 for 1 MB, modules like ESP8285, PSF-A85, some ESP-01, -03 etc.
    0x1fc000 for 2 MB
    0x3fc000 for 4 MB, modules like ESP-12E, NodeMCU devkit 1.0, WeMos D1 mini
    0x7fc000 for 8 MB
    0xffc000 for 16 MB, modules like WeMos D1 mini pro

      The command  --flash_size=1MB  is to compel esptool treating  the esp8266 module acting as 1 MB flash, thus the esp_init_data_default.bin would be written in addrress 0xFC000.

    If you would not like the esptool treat your module as 1MB flash only,  you should fill the correct address of  esp_init_data_default.bin. But that might lead my DFU-OTA code non-workable.

   Addition : esp_init_data_default.bin is for the configuration of esp8266.In which, it is able to set some configuration which is unable be set via APIs, e.g. configure the ADC function to measure the system voltage. More detail about the configuration, please refer to this document,  section 3.9.