2 * Copyright 2018 Jonathan McDowell <noodles@earth.li>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include <user_interface.h>
25 #include "project_config.h"
36 static void ICACHE_FLASH_ATTR ota_finish(struct ota_status *upgrade)
38 espconn_disconnect(&upgrade->conn);
40 if (system_upgrade_flag_check() == UPGRADE_FLAG_FINISH) {
41 os_printf("Rebooting into new ROM.\n");
42 system_upgrade_reboot();
44 system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
50 static void ICACHE_FLASH_ATTR ota_receive(void *arg, char *buf,
55 char *lenhdr, *data, *ptr;
56 struct ota_status *upgrade = arg;
59 if (!upgrade->do_update) {
60 if ((os_strncmp(buf + 9, "200", 3) != 0)) {
61 os_printf("Failed to fetch version info: %.3s\n",
65 /* We're checking if we need an update; look for the version */
66 verstr = os_strstr(buf, "ESP8266-Upgrade-Version: ");
68 os_printf("Couldn't find version. Got data: %s\n",
72 verstr += strlen("ESP8266-Upgrade-Version: ");
74 maj = strtol(verstr, &verstr, 10);
76 os_printf("Parsed major version %d, "
77 "but unexpected %c\n",
81 min = strtol(verstr, NULL, 10);
83 os_printf("Got version %d.%d; I have version %d.%d\n",
84 maj, min, VER_MAJ, VER_MIN);
85 if (maj > VER_MAJ || (maj == VER_MAJ && min > VER_MIN)) {
86 os_printf("Need upgrade.\n");
87 upgrade->do_update = true;
90 /* Trying to read the rom image */
93 if (upgrade->content_len == 0) {
94 if ((lenhdr = os_strstr(buf, "Content-Length: ")) &&
95 (data = os_strstr(lenhdr, "\r\n\r\n")) &&
96 (os_strncmp(buf + 9, "200", 3) == 0)) {
101 lenhdr += 16; /* Content-Length:<sp> */
102 ptr = os_strstr(lenhdr, "\r\n");
104 upgrade->content_len = atoi(lenhdr);
105 os_printf("Reading %d bytes of image.\n,",
106 upgrade->content_len);
108 if (upgrade->content_len > 0x6B000) {
109 os_printf("Image too large.\n");
110 upgrade->do_update = false;
115 sectors = (upgrade->content_len +
116 SPI_FLASH_SEC_SIZE - 1) >> 12;
118 spi_flash_erase_sector(sectors +
119 (upgrade->slot ? 129 : 1));
123 (upgrade->slot ? 0x81000 : 0x1000),
125 upgrade->rcvd_len = len;
128 ptr = os_strstr(buf, "\r\n");
130 os_printf("Error getting ROM data: %s\n", buf);
131 upgrade->do_update = false;
136 spi_flash_write((upgrade->slot ? 0x81000 : 0x1000) +
137 upgrade->rcvd_len, (void *) buf, len);
138 upgrade->rcvd_len += len;
141 if (upgrade->rcvd_len == upgrade->content_len) {
142 upgrade->do_update = false;
143 system_upgrade_flag_set(UPGRADE_FLAG_FINISH);
149 static void ICACHE_FLASH_ATTR ota_sent(void *arg)
151 /* Callback when all data sent by us down TCP connection */
154 static void ICACHE_FLASH_ATTR ota_connect(void *arg)
156 struct ota_status *upgrade = arg;
160 espconn_regist_recvcb(&upgrade->conn, ota_receive);
161 espconn_regist_sentcb(&upgrade->conn, ota_sent);
163 if (upgrade->do_update) {
164 os_printf("Sending rom image request header.\n");
165 len = os_sprintf(buf, "GET %srom%d.bin HTTP/1.0\r\n"
167 "Connection: close\r\n"
168 "User-Agent: ESP8266 " PROJECT "\r\n"
175 os_printf("Sending version check request header.\n");
176 len = os_sprintf(buf, "GET %s%s HTTP/1.1\r\n"
178 "Connection: close\r\n"
179 "User-Agent: ESP8266 " PROJECT "\r\n"
187 espconn_send(&upgrade->conn, (uint8_t *) buf, len);
190 static void ICACHE_FLASH_ATTR ota_disconnect(void *arg)
192 struct ota_status *upgrade = arg;
194 if (upgrade == NULL) {
198 espconn_delete(&upgrade->conn);
200 if (!upgrade->do_update) {
201 if (upgrade->conn.proto.tcp != NULL) {
202 os_free(upgrade->conn.proto.tcp);
205 system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
209 /* Reuse conn for the rom download */
210 upgrade->conn.state = ESPCONN_NONE;
212 espconn_connect(&upgrade->conn);
215 static void ICACHE_FLASH_ATTR ota_error(void *arg, sint8 err)
217 os_printf("Upgrade disconnected with error: %d.\n", err);
221 static void ICACHE_FLASH_ATTR ota_got_dns(const char *name, ip_addr_t *ip,
224 struct ota_status *upgrade = arg;
227 os_printf("Upgrade DNS request failed.\n");
229 system_upgrade_flag_set(UPGRADE_FLAG_IDLE);
233 upgrade->conn.type = ESPCONN_TCP;
234 upgrade->conn.state = ESPCONN_NONE;
235 upgrade->conn.proto.tcp = (esp_tcp *)os_malloc(sizeof(esp_tcp));
236 upgrade->conn.proto.tcp->local_port = espconn_port();
237 upgrade->conn.proto.tcp->remote_port = 80; /* FIXME; HTTPS */
239 os_memcpy(upgrade->conn.proto.tcp->remote_ip, &ip->addr, 4);
241 espconn_regist_connectcb(&upgrade->conn, ota_connect);
242 espconn_regist_disconcb(&upgrade->conn, ota_disconnect);
243 espconn_regist_reconcb(&upgrade->conn, ota_error);
245 espconn_connect(&upgrade->conn);
248 bool ICACHE_FLASH_ATTR ota_check()
250 struct ota_status *upgrade = NULL;
252 /* Don't start an upgrade if one is in progress */
253 if (system_upgrade_flag_check() == UPGRADE_FLAG_START) {
257 upgrade = (struct ota_status *) os_zalloc(sizeof(struct ota_status));
259 os_printf("Couldn't allocate memory for upgrade structure.\n");
263 system_upgrade_flag_set(UPGRADE_FLAG_START);
265 upgrade->slot = system_upgrade_userbin_check() ? 0 : 1;
267 /* Kick off the DNS lookup to start */
268 espconn_gethostbyname(&upgrade->conn, UPGRADE_HOST,