|
|
|
@@ -43,8 +43,12 @@ const char *manifest_url = MANIFEST_URL_EON;
|
|
|
|
|
|
|
|
|
|
#define UPDATE_DIR "/data/neoupdate"
|
|
|
|
|
|
|
|
|
|
extern const uint8_t bin_courbd[] asm("_binary_courbd_ttf_start");
|
|
|
|
|
extern const uint8_t bin_courbd_end[] asm("_binary_courbd_ttf_end");
|
|
|
|
|
extern const uint8_t bin_opensans_regular[] asm("_binary_opensans_regular_ttf_start");
|
|
|
|
|
extern const uint8_t bin_opensans_regular_end[] asm("_binary_opensans_regular_ttf_end");
|
|
|
|
|
extern const uint8_t bin_opensans_semibold[] asm("_binary_opensans_semibold_ttf_start");
|
|
|
|
|
extern const uint8_t bin_opensans_semibold_end[] asm("_binary_opensans_semibold_ttf_end");
|
|
|
|
|
extern const uint8_t bin_opensans_bold[] asm("_binary_opensans_bold_ttf_start");
|
|
|
|
|
extern const uint8_t bin_opensans_bold_end[] asm("_binary_opensans_bold_ttf_end");
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
@@ -148,7 +152,9 @@ struct Updater {
|
|
|
|
|
|
|
|
|
|
FramebufferState *fb = NULL;
|
|
|
|
|
NVGcontext *vg = NULL;
|
|
|
|
|
int font;
|
|
|
|
|
int font_regular;
|
|
|
|
|
int font_semibold;
|
|
|
|
|
int font_bold;
|
|
|
|
|
|
|
|
|
|
std::thread update_thread_handle;
|
|
|
|
|
|
|
|
|
@@ -182,14 +188,21 @@ struct Updater {
|
|
|
|
|
|
|
|
|
|
vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG);
|
|
|
|
|
assert(vg);
|
|
|
|
|
font = nvgCreateFontMem(vg, "courbd", (unsigned char*)bin_courbd, (bin_courbd_end - bin_courbd), 0);
|
|
|
|
|
assert(font >= 0);
|
|
|
|
|
|
|
|
|
|
b_w = 600;
|
|
|
|
|
font_regular = nvgCreateFontMem(vg, "opensans_regular", (unsigned char*)bin_opensans_regular, (bin_opensans_regular_end - bin_opensans_regular), 0);
|
|
|
|
|
assert(font_regular >= 0);
|
|
|
|
|
|
|
|
|
|
font_semibold = nvgCreateFontMem(vg, "opensans_semibold", (unsigned char*)bin_opensans_semibold, (bin_opensans_semibold_end - bin_opensans_semibold), 0);
|
|
|
|
|
assert(font_semibold >= 0);
|
|
|
|
|
|
|
|
|
|
font_bold = nvgCreateFontMem(vg, "opensans_bold", (unsigned char*)bin_opensans_bold, (bin_opensans_bold_end - bin_opensans_bold), 0);
|
|
|
|
|
assert(font_bold >= 0);
|
|
|
|
|
|
|
|
|
|
b_w = 640;
|
|
|
|
|
balt_x = 200;
|
|
|
|
|
b_x = fb_w-b_w-200;
|
|
|
|
|
b_y = 700;
|
|
|
|
|
b_h = 250;
|
|
|
|
|
b_y = 720;
|
|
|
|
|
b_h = 220;
|
|
|
|
|
|
|
|
|
|
state = CONFIRMATION;
|
|
|
|
|
|
|
|
|
@@ -286,14 +299,14 @@ struct Updater {
|
|
|
|
|
std::string stage_download(std::string url, std::string hash, std::string name) {
|
|
|
|
|
std::string out_fn = UPDATE_DIR "/" + util::base_name(url);
|
|
|
|
|
|
|
|
|
|
set_progress("downloading " + name + "...");
|
|
|
|
|
set_progress("Downloading " + name + "...");
|
|
|
|
|
bool r = download_file(url, out_fn);
|
|
|
|
|
if (!r) {
|
|
|
|
|
set_error("failed to download " + name);
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set_progress("verifying " + name + "...");
|
|
|
|
|
set_progress("Verifying " + name + "...");
|
|
|
|
|
std::string fn_hash = sha256_file(out_fn);
|
|
|
|
|
printf("got %s hash: %s\n", name.c_str(), hash.c_str());
|
|
|
|
|
if (fn_hash != hash) {
|
|
|
|
@@ -323,7 +336,7 @@ struct Updater {
|
|
|
|
|
|
|
|
|
|
const int EON = (access("/EON", F_OK) != -1);
|
|
|
|
|
|
|
|
|
|
set_progress("finding latest version...");
|
|
|
|
|
set_progress("Finding latest version...");
|
|
|
|
|
std::string manifest_s;
|
|
|
|
|
if (EON) {
|
|
|
|
|
manifest_s = download_string(curl, manifest_url);
|
|
|
|
@@ -364,10 +377,10 @@ struct Updater {
|
|
|
|
|
|
|
|
|
|
std::string recovery_fn;
|
|
|
|
|
if (recovery_url.empty() || recovery_hash.empty() || recovery_len == 0) {
|
|
|
|
|
set_progress("skipping recovery flash...");
|
|
|
|
|
set_progress("Skipping recovery flash...");
|
|
|
|
|
} else {
|
|
|
|
|
// only download the recovery if it differs from what's flashed
|
|
|
|
|
set_progress("checking recovery...");
|
|
|
|
|
set_progress("Checking recovery...");
|
|
|
|
|
std::string existing_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len);
|
|
|
|
|
printf("existing recovery hash: %s\n", existing_recovery_hash.c_str());
|
|
|
|
|
|
|
|
|
@@ -393,7 +406,7 @@ struct Updater {
|
|
|
|
|
|
|
|
|
|
if (!recovery_fn.empty()) {
|
|
|
|
|
// flash recovery
|
|
|
|
|
set_progress("flashing recovery...");
|
|
|
|
|
set_progress("Flashing recovery...");
|
|
|
|
|
|
|
|
|
|
FILE *flash_file = fopen(recovery_fn.c_str(), "rb");
|
|
|
|
|
if (!flash_file) {
|
|
|
|
@@ -427,7 +440,7 @@ struct Updater {
|
|
|
|
|
fclose(recovery_dev);
|
|
|
|
|
fclose(flash_file);
|
|
|
|
|
|
|
|
|
|
set_progress("verifying flash...");
|
|
|
|
|
set_progress("Verifying flash...");
|
|
|
|
|
std::string new_recovery_hash = sha256_file(RECOVERY_DEV, recovery_len);
|
|
|
|
|
printf("new recovery hash: %s\n", new_recovery_hash.c_str());
|
|
|
|
|
|
|
|
|
@@ -447,7 +460,7 @@ struct Updater {
|
|
|
|
|
fprintf(cmd_file, "--update_package=%s\n", ota_fn.c_str());
|
|
|
|
|
fclose(cmd_file);
|
|
|
|
|
|
|
|
|
|
set_progress("rebooting");
|
|
|
|
|
set_progress("Rebooting");
|
|
|
|
|
|
|
|
|
|
// remove the continue.sh so we come back into the setup.
|
|
|
|
|
// maybe we should go directly into the installer, but what if we don't come back with internet? :/
|
|
|
|
@@ -462,25 +475,32 @@ struct Updater {
|
|
|
|
|
// set_error("failed to reboot into recovery");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void draw_ack_screen(const char *message, const char *button, const char *altbutton) {
|
|
|
|
|
nvgFontSize(vg, 96.0f);
|
|
|
|
|
void draw_ack_screen(const char *title, const char *message, const char *button, const char *altbutton) {
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(255,255,255,255));
|
|
|
|
|
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE);
|
|
|
|
|
nvgTextBox(vg, 50, 100, fb_w-100, message, NULL);
|
|
|
|
|
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
|
|
|
|
|
|
|
|
|
|
nvgFontFace(vg, "opensans_bold");
|
|
|
|
|
nvgFontSize(vg, 120.0f);
|
|
|
|
|
nvgTextBox(vg, 110, 220, fb_w-240, title, NULL);
|
|
|
|
|
|
|
|
|
|
nvgFontFace(vg, "opensans_regular");
|
|
|
|
|
nvgFontSize(vg, 86.0f);
|
|
|
|
|
nvgTextBox(vg, 130, 380, fb_w-260, message, NULL);
|
|
|
|
|
|
|
|
|
|
// draw button
|
|
|
|
|
if (button) {
|
|
|
|
|
nvgBeginPath(vg);
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(0, 0, 0, 255));
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(8, 8, 8, 255));
|
|
|
|
|
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20);
|
|
|
|
|
nvgFill(vg);
|
|
|
|
|
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(255, 255, 255, 255));
|
|
|
|
|
nvgFontFace(vg, "opensans_semibold");
|
|
|
|
|
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
|
|
|
|
nvgText(vg, b_x+b_w/2, b_y+b_h/2, button, NULL);
|
|
|
|
|
|
|
|
|
|
nvgBeginPath(vg);
|
|
|
|
|
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 255));
|
|
|
|
|
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 50));
|
|
|
|
|
nvgStrokeWidth(vg, 5);
|
|
|
|
|
nvgRoundedRect(vg, b_x, b_y, b_w, b_h, 20);
|
|
|
|
|
nvgStroke(vg);
|
|
|
|
@@ -489,16 +509,17 @@ struct Updater {
|
|
|
|
|
// draw button
|
|
|
|
|
if (altbutton) {
|
|
|
|
|
nvgBeginPath(vg);
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(0, 0, 0, 255));
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(8, 8, 8, 255));
|
|
|
|
|
nvgRoundedRect(vg, balt_x, b_y, b_w, b_h, 20);
|
|
|
|
|
nvgFill(vg);
|
|
|
|
|
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(255, 255, 255, 255));
|
|
|
|
|
nvgFontFace(vg, "opensans_semibold");
|
|
|
|
|
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
|
|
|
|
nvgText(vg, balt_x+b_w/2, b_y+b_h/2, altbutton, NULL);
|
|
|
|
|
|
|
|
|
|
nvgBeginPath(vg);
|
|
|
|
|
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 255));
|
|
|
|
|
nvgStrokeColor(vg, nvgRGBA(255, 255, 255, 50));
|
|
|
|
|
nvgStrokeWidth(vg, 5);
|
|
|
|
|
nvgRoundedRect(vg, balt_x, b_y, b_w, b_h, 20);
|
|
|
|
|
nvgStroke(vg);
|
|
|
|
@@ -510,23 +531,27 @@ struct Updater {
|
|
|
|
|
nvgFontSize(vg, 64.0f);
|
|
|
|
|
nvgFillColor(vg, nvgRGBA(255,255,255,255));
|
|
|
|
|
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE);
|
|
|
|
|
nvgTextBox(vg, 0, 700, fb_w, progress_text.c_str(), NULL);
|
|
|
|
|
nvgFontFace(vg, "opensans_bold");
|
|
|
|
|
nvgFontSize(vg, 86.0f);
|
|
|
|
|
nvgTextBox(vg, 0, 380, fb_w, progress_text.c_str(), NULL);
|
|
|
|
|
|
|
|
|
|
// draw progress bar
|
|
|
|
|
{
|
|
|
|
|
int progress_width = 800;
|
|
|
|
|
int progress_width = 1000;
|
|
|
|
|
int progress_x = fb_w/2-progress_width/2;
|
|
|
|
|
int progress_y = 768;
|
|
|
|
|
int progress_height = 15;
|
|
|
|
|
int progress_y = 520;
|
|
|
|
|
int progress_height = 50;
|
|
|
|
|
|
|
|
|
|
int powerprompt_y = 512;
|
|
|
|
|
nvgText(vg, fb_w/2, powerprompt_y, "Ensure EON is connected to power", NULL);
|
|
|
|
|
int powerprompt_y = 312;
|
|
|
|
|
nvgFontFace(vg, "opensans_regular");
|
|
|
|
|
nvgFontSize(vg, 64.0f);
|
|
|
|
|
nvgText(vg, fb_w/2, 740, "Ensure EON is connected to power.", NULL);
|
|
|
|
|
|
|
|
|
|
NVGpaint paint = nvgBoxGradient(
|
|
|
|
|
vg, progress_x + 1, progress_y + 1,
|
|
|
|
|
progress_width - 2, progress_height, 3, 4, nvgRGB(0, 32, 0), nvgRGB(0, 92, 0));
|
|
|
|
|
progress_width - 2, progress_height, 3, 4, nvgRGB(27, 27, 27), nvgRGB(27, 27, 27));
|
|
|
|
|
nvgBeginPath(vg);
|
|
|
|
|
nvgRoundedRect(vg, progress_x, progress_y, progress_width, progress_height, 3);
|
|
|
|
|
nvgRoundedRect(vg, progress_x, progress_y, progress_width, progress_height, 12);
|
|
|
|
|
nvgFillPaint(vg, paint);
|
|
|
|
|
nvgFill(vg);
|
|
|
|
|
|
|
|
|
@@ -536,12 +561,12 @@ struct Updater {
|
|
|
|
|
paint = nvgBoxGradient(
|
|
|
|
|
vg, progress_x, progress_y,
|
|
|
|
|
bar_pos+1.5f, progress_height-1, 3, 4,
|
|
|
|
|
nvgRGB(220, 100, 0), nvgRGB(128, 100, 0));
|
|
|
|
|
nvgRGB(245, 245, 245), nvgRGB(105, 105, 105));
|
|
|
|
|
|
|
|
|
|
nvgBeginPath(vg);
|
|
|
|
|
nvgRoundedRect(
|
|
|
|
|
vg, progress_x+1, progress_y+1,
|
|
|
|
|
bar_pos, progress_height-2, 3);
|
|
|
|
|
bar_pos, progress_height-2, 12);
|
|
|
|
|
nvgFillPaint(vg, paint);
|
|
|
|
|
nvgFill(vg);
|
|
|
|
|
}
|
|
|
|
@@ -554,16 +579,16 @@ struct Updater {
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
|
case CONFIRMATION:
|
|
|
|
|
draw_ack_screen("An upgrade to NEOS is required.\n\n"
|
|
|
|
|
"Your device will now be reset and upgraded. You may want to connect to wifi as download is around 1 GB\nData on device shouldn't be lost.",
|
|
|
|
|
"continue",
|
|
|
|
|
"wifi");
|
|
|
|
|
draw_ack_screen("An update to NEOS is required.",
|
|
|
|
|
"Your device will now be reset and upgraded. You may want to connect to wifi as download is around 1 GB. Existing data on device should not be lost.",
|
|
|
|
|
"Continue",
|
|
|
|
|
"Connect to WiFi");
|
|
|
|
|
break;
|
|
|
|
|
case RUNNING:
|
|
|
|
|
draw_progress_screen();
|
|
|
|
|
break;
|
|
|
|
|
case ERROR:
|
|
|
|
|
draw_ack_screen(("ERROR: " + error_text + "\n\nYou will need to retry").c_str(), NULL, "exit");
|
|
|
|
|
draw_ack_screen("There was an error.", ("ERROR: " + error_text + "\n\nYou will need to retry").c_str(), NULL, "exit");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -604,9 +629,17 @@ struct Updater {
|
|
|
|
|
while (!do_exit) {
|
|
|
|
|
ui_update();
|
|
|
|
|
|
|
|
|
|
glClearColor(0.19, 0.09, 0.2, 1.0);
|
|
|
|
|
glClearColor(0.08, 0.08, 0.08, 1.0);
|
|
|
|
|
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
|
|
// background
|
|
|
|
|
nvgBeginPath(vg);
|
|
|
|
|
NVGpaint bg = nvgLinearGradient(vg, fb_w, 0, fb_w, fb_h,
|
|
|
|
|
nvgRGBA(0, 0, 0, 0), nvgRGBA(0, 0, 0, 255));
|
|
|
|
|
nvgFillPaint(vg, bg);
|
|
|
|
|
nvgRect(vg, 0, 0, fb_w, fb_h);
|
|
|
|
|
nvgFill(vg);
|
|
|
|
|
|
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
|
|