99#include <esp_flash_partitions.h>
1010#include <esp_partition.h>
1111#include <esp_spi_flash.h>
12+ #include <esp_ota_ops.h>
1213
1314#ifdef RG_UPDATER_DOWNLOAD_LOCATION
1415#define DOWNLOAD_LOCATION RG_UPDATER_DOWNLOAD_LOCATION
@@ -33,37 +34,36 @@ typedef struct
3334 char reserved [180 ];
3435} img_info_t ;
3536
36- #define CONFIRM ( title , message ...) \
37- { \
38- snprintf(message_buffer, sizeof(message_buffer), message); \
39- if (!rg_gui_confirm(_(title), message_buffer , false)) \
40- return false; \
41- rg_display_clear(C_BLACK); \
37+ #define FORMAT ( message ...) ({snprintf(message_buffer, sizeof(message_buffer), message); message_buffer; })
38+ #define CONFIRM ( title , message ...) \
39+ { \
40+ if (!rg_gui_confirm(_(title), FORMAT(message) , false)) \
41+ return false; \
42+ rg_display_clear(C_BLACK); \
4243 }
43- #define ALERT ( title , message ...) \
44- { \
45- snprintf(message_buffer, sizeof(message_buffer), message); \
46- rg_gui_alert(_(title ), message_buffer); \
47- rg_display_clear(C_BLACK); \
44+ #define TRY ( cond , error_message ) \
45+ if (!(cond)) \
46+ { \
47+ rg_gui_alert(_("Error" ), error_message); \
48+ return false; \
4849 }
49- #define ERROR (message ...) \
50- { \
51- ALERT("Error", message); \
52- return false; \
53- }
54- #define TRY (cond , error_message ) \
55- if (!(cond)) \
56- ERROR(error_message);
50+
51+ typedef struct
52+ {
53+ const esp_partition_info_t * src ;
54+ const esp_partition_t * dst ;
55+ } partition_pair_t ;
5756
5857static rg_app_t * app ;
59- static esp_partition_info_t device_partition_table [ESP_PARTITION_TABLE_MAX_ENTRIES ];
60- static char message_buffer [256 ];
58+ // static esp_partition_info_t device_partition_table[ESP_PARTITION_TABLE_MAX_ENTRIES];
6159
6260static bool do_update (const char * filename )
6361{
62+ char message_buffer [256 ];
6463 esp_partition_info_t partition_table [16 ]; // ESP_PARTITION_TABLE_MAX_ENTRIES
6564 int num_partitions = 0 ;
6665 img_info_t img_info ;
66+ void * buffer ;
6767 int filesize = 0 ;
6868 FILE * fp ;
6969
@@ -101,16 +101,86 @@ static bool do_update(const char *filename)
101101 // TODO: Also support images that truncate the first 0x1000, just in case
102102 TRY (fseek (fp , ESP_PARTITION_TABLE_OFFSET , SEEK_SET ) == 0 , "File seek failed" );
103103 TRY (fread (& partition_table , sizeof (partition_table ), 1 , fp ), "File read failed" );
104+ TRY (esp_partition_table_verify (partition_table , true, & num_partitions ) == ESP_OK , "File is not a valid ESP32 image.\nCannot continue." );
105+
106+ const char * current_partition = esp_ota_get_running_partition ()-> label ;
107+ partition_pair_t queue [num_partitions ];
108+ size_t queue_count = 0 ;
109+
110+ // At this time we only flash partitions of type app and subtype ota_X
111+ for (int i = 0 ; i < num_partitions ; ++ i )
112+ {
113+ const esp_partition_info_t * src = & partition_table [i ];
114+ const esp_partition_t * dst = esp_partition_find_first (src -> type , ESP_PARTITION_SUBTYPE_ANY , (char * )src -> label );
115+
116+ if (src -> type != PART_TYPE_APP || (src -> subtype & 0xF0 ) != PART_SUBTYPE_OTA_FLAG )
117+ RG_LOGW ("Skipping partition %.15s: Unsupported type." , (char * )src -> label );
118+ else if (!dst )
119+ RG_LOGW ("Skipping partition %.15s: No match found." , (char * )src -> label );
120+ else if ((dst -> subtype & 0xF0 ) != PART_SUBTYPE_OTA_FLAG )
121+ RG_LOGW ("Skipping partition %.15s: Not an OTA partition." , (char * )src -> label );
122+ else if (strncmp (current_partition , dst -> label , 16 ) == 0 )
123+ RG_LOGW ("Skipping partition %.15s: Currently running." , (char * )src -> label );
124+ else if (dst -> size < src -> pos .size )
125+ RG_LOGW ("Skipping partition %.15s: New partition is bigger." , (char * )src -> label );
126+ else
127+ {
128+ queue [queue_count ].src = src ;
129+ queue [queue_count ].dst = dst ;
130+ queue_count ++ ;
131+ }
132+ }
133+
134+ TRY (queue_count > 0 , "Found no updatable partition!" );
104135
105- if (esp_partition_table_verify (partition_table , true, & num_partitions ) != ESP_OK )
106- ERROR ("File is not a valid esp32 image.\nCannot continue." );
136+ int pos = 0 ;
137+ for (size_t i = 0 ; i < queue_count ; ++ i )
138+ pos += snprintf (message_buffer + pos , sizeof (message_buffer ) - pos , "- %s\n" , queue [i ].dst -> label );
139+ pos += snprintf (message_buffer + pos , sizeof (message_buffer ) - pos , "\nProceed?" );
107140
108- ALERT ("Info" , "Image contains %d partitions." , num_partitions );
141+ if (!rg_gui_confirm ("Partitions to be updated:" , message_buffer , false))
142+ return false;
109143
110- // We can work around this, this is for debugging purposes
111- if (memcmp (& device_partition_table , & partition_table , sizeof (partition_table )))
112- ALERT ("Error" , "Partition table mismatch." );
144+ TRY (buffer = malloc (2 * 1024 * 1024 ), "Memory allocation failed" );
113145
146+ // TODO: Implement scrolling. Maybe on rg_gui side?
147+ // Or at least support continue writing on the same line. "... Complete"
148+ int y_pos = 9999 ;
149+ #define SCREEN_PRINTF (color , message ...) \
150+ if (y_pos + 16 > rg_display_get_height()) \
151+ rg_display_clear(C_BLACK), y_pos = 0; \
152+ y_pos += rg_gui_draw_text(0, y_pos, 0, FORMAT(message), color, C_BLACK, 0).height;
153+
154+ SCREEN_PRINTF (C_WHITE , "Starting..." );
155+
156+ for (size_t i = 0 ; i < queue_count ; ++ i )
157+ {
158+ const esp_partition_info_t * src = queue [i ].src ;
159+ const esp_partition_t * dst = queue [i ].dst ;
160+ esp_ota_handle_t ota_handle ;
161+ esp_err_t ret ;
162+ if ((ret = esp_ota_begin (queue [i ].dst , 0 , & ota_handle )) != ESP_OK )
163+ {
164+ SCREEN_PRINTF (C_RED , "Skipping %s: %s" , dst -> label , esp_err_to_name (ret ));
165+ continue ;
166+ }
167+ SCREEN_PRINTF (C_WHITE , "Reading %s from file..." , dst -> label );
168+ if (fseek (fp , src -> pos .offset , SEEK_SET ) != 0 || !fread (buffer , src -> pos .size , 1 , fp ))
169+ {
170+ SCREEN_PRINTF (C_RED , "File read error" );
171+ continue ;
172+ }
173+ SCREEN_PRINTF (C_WHITE , "Writing %s to flash..." , dst -> label );
174+ if ((ret = esp_ota_write (ota_handle , buffer , src -> pos .size )) == ESP_OK ) {
175+ SCREEN_PRINTF (C_GREEN , "Complete!" );
176+ } else {
177+ SCREEN_PRINTF (C_RED , "Failed: %s" , esp_err_to_name (ret ));
178+ }
179+ esp_ota_end (ota_handle );
180+ }
181+ free (buffer );
182+
183+ rg_gui_alert (_ ("All done" ), "The process is complete" );
114184 return true;
115185}
116186
@@ -123,28 +193,25 @@ void app_main(void)
123193
124194 if (!rg_storage_ready ())
125195 {
126- ALERT ( "Error" , "Storage mount failed.\nMake sure the card is FAT32." );
196+ rg_gui_alert ( _ ( "Error" ) , "Storage mount failed.\nMake sure the card is FAT32." );
127197 rg_system_exit ();
128198 }
129199
130- if (spi_flash_read (ESP_PARTITION_TABLE_OFFSET , & device_partition_table , sizeof (device_partition_table )) != ESP_OK )
131- {
132- ALERT ( "Error" , "Failed to read device's partition table!" );
133- rg_system_exit ();
134- }
200+ // if (spi_flash_read(ESP_PARTITION_TABLE_OFFSET, &device_partition_table, sizeof(device_partition_table)) != ESP_OK)
201+ // {
202+ // rg_gui_alert(_( "Error") , "Failed to read device's partition table!");
203+ // rg_system_exit();
204+ // }
135205
136- const char * filename = app -> romPath ;
206+ // const char *filename = app->romPath;
137207 while (true)
138208 {
209+ char * filename = rg_gui_file_picker ("Select update" , DOWNLOAD_LOCATION , NULL , true, true);
139210 if (!filename || !* filename )
140- {
141- filename = rg_gui_file_picker ("Select update" , DOWNLOAD_LOCATION , NULL , true, true);
142- if (!filename || !* filename )
143- break ;
144- }
211+ break ;
145212 if (do_update (filename ))
146213 break ;
147- filename = NULL ;
214+ free ( filename ) ;
148215 }
149216
150217 rg_system_exit ();
0 commit comments