1+ #include "ota.h"
2+
3+ #include <esp_err.h>
4+ #include <esp_log.h>
5+ #include <esp_ota_ops.h>
6+ #include <esp_timer.h>
7+ #include <string.h>
8+ #include <zlib.h>
9+
10+ bool zlib_init = false;
11+ static const esp_partition_t * s_ota_partition = NULL ;
12+ static esp_ota_handle_t s_ota_handle = 0 ;
13+ z_stream zlib_stream ;
14+
15+ uint8_t ota_header [6 ];
16+ size_t ota_header_len = 0 ;
17+ bool ota_upgrade_subelement = false;
18+ size_t ota_data_len = 0 ;
19+ uint64_t ota_last_receive_us = 0 ;
20+ size_t ota_receive_not_logged = 0 ;
21+
22+ void ota_reset ()
23+ {
24+ if (s_ota_partition ) {
25+ esp_ota_abort (s_ota_handle );
26+ s_ota_partition = NULL ;
27+ }
28+
29+ if (zlib_init ) {
30+ inflateEnd (& zlib_stream );
31+ zlib_init = false;
32+ }
33+ }
34+
35+ bool ota_start ()
36+ {
37+ zlib_init = false;
38+ s_ota_partition = NULL ;
39+ s_ota_handle = 0 ;
40+
41+ memset (& zlib_stream , 0 , sizeof (zlib_stream ));
42+ int ret = inflateInit (& zlib_stream );
43+ if (ret == Z_OK ) {
44+ zlib_init = true;
45+ } else {
46+ ESP_LOGE (__func__ , "zlib init failed: %d" , ret );
47+ return false;
48+ }
49+
50+ s_ota_partition = esp_ota_get_next_update_partition (NULL );
51+ if (!s_ota_partition ) {
52+ ESP_LOGE (__func__ , "No next OTA partition" );
53+ return false;
54+ }
55+
56+ esp_err_t err = esp_ota_begin (s_ota_partition , OTA_WITH_SEQUENTIAL_WRITES , & s_ota_handle );
57+ if (err != ESP_OK ) {
58+ ESP_LOGE (__func__ , "Error starting OTA: %d" , err );
59+ s_ota_partition = NULL ;
60+ return false;
61+ }
62+
63+ return true;
64+ }
65+
66+ bool ota_write (const uint8_t * data , size_t size , bool flush )
67+ {
68+ uint8_t buf [256 ];
69+
70+ if (!s_ota_partition ) {
71+ return false;
72+ }
73+
74+ zlib_stream .avail_in = size ;
75+ zlib_stream .next_in = data ;
76+
77+ do {
78+ zlib_stream .avail_out = sizeof (buf );
79+ zlib_stream .next_out = buf ;
80+
81+ int ret = inflate (& zlib_stream , flush ? Z_FINISH : Z_NO_FLUSH );
82+ if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR ) {
83+ ESP_LOGE (__func__ , "zlib error: %d" , ret );
84+ esp_ota_abort (s_ota_handle );
85+ s_ota_partition = NULL ;
86+ return false;
87+ }
88+
89+ size_t available = sizeof (buf ) - zlib_stream .avail_out ;
90+ if (available > 0 ) {
91+ esp_err_t err = esp_ota_write (s_ota_handle , buf , available );
92+ if (err != ESP_OK ) {
93+ ESP_LOGE (__func__ , "Error writing OTA: %d" , err );
94+ esp_ota_abort (s_ota_handle );
95+ s_ota_partition = NULL ;
96+ return false;
97+ }
98+ }
99+ } while (zlib_stream .avail_in > 0 || zlib_stream .avail_out == 0 );
100+
101+ return true;
102+ }
103+
104+ bool ota_finish ()
105+ {
106+ if (!s_ota_partition ) {
107+ ESP_LOGE (__func__ , "OTA not running" );
108+ return false;
109+ }
110+
111+ if (!ota_write (NULL , 0 , true)) {
112+ return false;
113+ }
114+
115+ esp_err_t err = esp_ota_end (s_ota_handle );
116+ if (err != ESP_OK ) {
117+ ESP_LOGE (__func__ , "Error ending OTA: %d" , err );
118+ s_ota_partition = NULL ;
119+ return false;
120+ }
121+
122+ inflateEnd (& zlib_stream );
123+ zlib_init = false;
124+
125+ err = esp_ota_set_boot_partition (s_ota_partition );
126+ if (err != ESP_OK ) {
127+ ESP_LOGE (__func__ , "Error setting boot partition: %d" , err );
128+ s_ota_partition = NULL ;
129+ return false;
130+ }
131+
132+ s_ota_partition = NULL ;
133+ return true;
134+ }
135+
136+ esp_err_t zb_ota_upgrade_status_handler (esp_zb_zcl_ota_upgrade_value_message_t message )
137+ {
138+ esp_err_t ret = ESP_OK ;
139+
140+ if (message .info .status == ESP_ZB_ZCL_STATUS_SUCCESS ) {
141+ if (message .upgrade_status != ESP_ZB_ZCL_OTA_UPGRADE_STATUS_RECEIVE ) {
142+ if (ota_receive_not_logged ) {
143+ ESP_LOGD (__func__ , "OTA (%zu receive data messages suppressed)" ,
144+ ota_receive_not_logged );
145+ ota_receive_not_logged = 0 ;
146+ }
147+ ota_last_receive_us = 0 ;
148+ }
149+
150+ switch (message .upgrade_status ) {
151+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_START :
152+ ESP_LOGI (__func__ , "OTA start" );
153+ ota_reset ();
154+ ota_header_len = 0 ;
155+ ota_upgrade_subelement = false;
156+ ota_data_len = 0 ;
157+ if (!ota_start ()) {
158+ ota_reset ();
159+ ret = ESP_FAIL ;
160+ }
161+ break ;
162+
163+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_RECEIVE :
164+ const uint8_t * payload = message .payload ;
165+ size_t payload_size = message .payload_size ;
166+
167+ // Read and process the first sub-element, ignoring everything else
168+ while (ota_header_len < 6 && payload_size > 0 ) {
169+ ota_header [ota_header_len ++ ] = payload [0 ];
170+ payload ++ ;
171+ payload_size -- ;
172+ }
173+
174+ if (!ota_upgrade_subelement && ota_header_len == 6 ) {
175+ if (ota_header [0 ] == 0 && ota_header [1 ] == 0 ) {
176+ ota_upgrade_subelement = true;
177+ ota_data_len =
178+ (((int )ota_header [5 ] & 0xFF ) << 24 )
179+ | (((int )ota_header [4 ] & 0xFF ) << 16 )
180+ | (((int )ota_header [3 ] & 0xFF ) << 8 )
181+ | ((int )ota_header [2 ] & 0xFF );
182+ ESP_LOGD (__func__ , "OTA sub-element size %zu" , ota_data_len );
183+ } else {
184+ ESP_LOGE (__func__ , "OTA sub-element type %02x%02x not supported" , ota_header [0 ], ota_header [1 ]);
185+ ota_reset ();
186+ ret = ESP_FAIL ;
187+ }
188+ }
189+
190+ if (ota_data_len ) {
191+ if (payload_size > ota_data_len )
192+ payload_size = ota_data_len ;
193+ ota_data_len -= payload_size ;
194+
195+ if (ota_write (payload , payload_size , false)) {
196+ uint64_t now_us = esp_timer_get_time ();
197+ if (!ota_last_receive_us
198+ || now_us - ota_last_receive_us >= 30 * 1000 * 1000 ) {
199+ ESP_LOGD (__func__ , "OTA receive data (%zu messages suppressed)" ,
200+ ota_receive_not_logged );
201+ ota_last_receive_us = now_us ;
202+ ota_receive_not_logged = 0 ;
203+ } else {
204+ ota_receive_not_logged ++ ;
205+ }
206+ } else {
207+ ota_reset ();
208+ ret = ESP_FAIL ;
209+ }
210+ }
211+ break ;
212+
213+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_APPLY :
214+ ESP_LOGI (__func__ , "OTA apply" );
215+ break ;
216+
217+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_CHECK :
218+ ESP_LOGI (__func__ , "OTA data complete" );
219+ break ;
220+
221+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_FINISH :
222+ ESP_LOGI (__func__ , "OTA finished" );
223+ bool ok = ota_finish ();
224+ ota_reset ();
225+ if (ok )
226+ esp_restart ();
227+ break ;
228+
229+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_ABORT :
230+ ESP_LOGI (__func__ , "OTA aborted" );
231+ ota_reset ();
232+ break ;
233+
234+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_OK :
235+ ESP_LOGI (__func__ , "OTA data ok" );
236+ break ;
237+
238+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_ERROR :
239+ ESP_LOGI (__func__ , "OTA data error" );
240+ ota_reset ();
241+ break ;
242+
243+ case ESP_ZB_ZCL_OTA_UPGRADE_IMAGE_STATUS_NORMAL :
244+ ESP_LOGI (__func__ , "OTA image accepted" );
245+ break ;
246+
247+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_BUSY :
248+ ESP_LOGI (__func__ , "OTA busy" );
249+ ota_reset ();
250+ break ;
251+
252+ case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_SERVER_NOT_FOUND :
253+ ESP_LOGI (__func__ , "OTA server not found" );
254+ ota_reset ();
255+ break ;
256+
257+ default :
258+ ESP_LOGI (__func__ , "OTA status: %d" , message .upgrade_status );
259+ break ;
260+ }
261+ }
262+
263+ return ret ;
264+ }
0 commit comments