34
34
#include "esp_ota_ops.h"
35
35
36
36
// esp_partition_read and esp_partition_write can operate on arbitrary bytes
37
- // but esp_partition_erase_range operates on 4k blocks. But to make a partition
38
- // implement the standard block protocol all operations are done on 4k blocks.
39
- #define BLOCK_SIZE_BYTES (4096)
37
+ // but esp_partition_erase_range operates on 4k blocks. The default block size
38
+ // for a Partition object is therefore 4k, to make writes efficient, and also
39
+ // make it work well with filesystems like littlefs. The Partition object also
40
+ // supports smaller block sizes, in which case a cache is used and writes may
41
+ // be less efficient.
42
+ #define NATIVE_BLOCK_SIZE_BYTES (4096)
40
43
41
44
enum {
42
45
ESP32_PARTITION_BOOT ,
@@ -46,15 +49,23 @@ enum {
46
49
typedef struct _esp32_partition_obj_t {
47
50
mp_obj_base_t base ;
48
51
const esp_partition_t * part ;
52
+ uint8_t * cache ;
53
+ uint16_t block_size ;
49
54
} esp32_partition_obj_t ;
50
55
51
- STATIC esp32_partition_obj_t * esp32_partition_new (const esp_partition_t * part ) {
56
+ STATIC esp32_partition_obj_t * esp32_partition_new (const esp_partition_t * part , uint16_t block_size ) {
52
57
if (part == NULL ) {
53
58
mp_raise_OSError (MP_ENOENT );
54
59
}
55
60
esp32_partition_obj_t * self = m_new_obj (esp32_partition_obj_t );
56
61
self -> base .type = & esp32_partition_type ;
57
62
self -> part = part ;
63
+ self -> block_size = block_size ;
64
+ if (self -> block_size < NATIVE_BLOCK_SIZE_BYTES ) {
65
+ self -> cache = m_new (uint8_t , NATIVE_BLOCK_SIZE_BYTES );
66
+ } else {
67
+ self -> cache = NULL ;
68
+ }
58
69
return self ;
59
70
}
60
71
@@ -69,7 +80,7 @@ STATIC void esp32_partition_print(const mp_print_t *print, mp_obj_t self_in, mp_
69
80
70
81
STATIC mp_obj_t esp32_partition_make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * all_args ) {
71
82
// Check args
72
- mp_arg_check_num (n_args , n_kw , 1 , 1 , false);
83
+ mp_arg_check_num (n_args , n_kw , 1 , 2 , false);
73
84
74
85
// Get requested partition
75
86
const esp_partition_t * part ;
@@ -94,17 +105,24 @@ STATIC mp_obj_t esp32_partition_make_new(const mp_obj_type_t *type, size_t n_arg
94
105
}
95
106
}
96
107
108
+ // Get block size if given
109
+ uint16_t block_size = NATIVE_BLOCK_SIZE_BYTES ;
110
+ if (n_args == 2 ) {
111
+ block_size = mp_obj_get_int (all_args [1 ]);
112
+ }
113
+
97
114
// Return new object
98
- return MP_OBJ_FROM_PTR (esp32_partition_new (part ));
115
+ return MP_OBJ_FROM_PTR (esp32_partition_new (part , block_size ));
99
116
}
100
117
101
118
STATIC mp_obj_t esp32_partition_find (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
102
119
// Parse args
103
- enum { ARG_type , ARG_subtype , ARG_label };
120
+ enum { ARG_type , ARG_subtype , ARG_label , ARG_block_size };
104
121
static const mp_arg_t allowed_args [] = {
105
122
{ MP_QSTR_type , MP_ARG_INT , {.u_int = ESP_PARTITION_TYPE_APP } },
106
123
{ MP_QSTR_subtype , MP_ARG_INT , {.u_int = ESP_PARTITION_SUBTYPE_ANY } },
107
124
{ MP_QSTR_label , MP_ARG_OBJ , {.u_rom_obj = MP_ROM_NONE } },
125
+ { MP_QSTR_block_size , MP_ARG_INT , {.u_int = NATIVE_BLOCK_SIZE_BYTES } },
108
126
};
109
127
mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
110
128
mp_arg_parse_all (n_args , pos_args , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
@@ -115,11 +133,14 @@ STATIC mp_obj_t esp32_partition_find(size_t n_args, const mp_obj_t *pos_args, mp
115
133
label = mp_obj_str_get_str (args [ARG_label ].u_obj );
116
134
}
117
135
136
+ // Get block size
137
+ uint16_t block_size = args [ARG_block_size ].u_int ;
138
+
118
139
// Build list of matching partitions
119
140
mp_obj_t list = mp_obj_new_list (0 , NULL );
120
141
esp_partition_iterator_t iter = esp_partition_find (args [ARG_type ].u_int , args [ARG_subtype ].u_int , label );
121
142
while (iter != NULL ) {
122
- mp_obj_list_append (list , MP_OBJ_FROM_PTR (esp32_partition_new (esp_partition_get (iter ))));
143
+ mp_obj_list_append (list , MP_OBJ_FROM_PTR (esp32_partition_new (esp_partition_get (iter ), block_size )));
123
144
iter = esp_partition_next (iter );
124
145
}
125
146
esp_partition_iterator_release (iter );
@@ -145,7 +166,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_info_obj, esp32_partition_info)
145
166
146
167
STATIC mp_obj_t esp32_partition_readblocks (size_t n_args , const mp_obj_t * args ) {
147
168
esp32_partition_obj_t * self = MP_OBJ_TO_PTR (args [0 ]);
148
- uint32_t offset = mp_obj_get_int (args [1 ]) * BLOCK_SIZE_BYTES ;
169
+ uint32_t offset = mp_obj_get_int (args [1 ]) * self -> block_size ;
149
170
mp_buffer_info_t bufinfo ;
150
171
mp_get_buffer_raise (args [2 ], & bufinfo , MP_BUFFER_WRITE );
151
172
if (n_args == 4 ) {
@@ -158,12 +179,36 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(esp32_partition_readblocks_obj, 3, 4,
158
179
159
180
STATIC mp_obj_t esp32_partition_writeblocks (size_t n_args , const mp_obj_t * args ) {
160
181
esp32_partition_obj_t * self = MP_OBJ_TO_PTR (args [0 ]);
161
- uint32_t offset = mp_obj_get_int (args [1 ]) * BLOCK_SIZE_BYTES ;
182
+ uint32_t offset = mp_obj_get_int (args [1 ]) * self -> block_size ;
162
183
mp_buffer_info_t bufinfo ;
163
184
mp_get_buffer_raise (args [2 ], & bufinfo , MP_BUFFER_READ );
164
185
if (n_args == 3 ) {
165
- check_esp_err (esp_partition_erase_range (self -> part , offset , bufinfo .len ));
186
+ // A simple write, which requires erasing first.
187
+ if (self -> block_size >= NATIVE_BLOCK_SIZE_BYTES ) {
188
+ // Block size is at least native erase-page size, so do an efficient erase.
189
+ check_esp_err (esp_partition_erase_range (self -> part , offset , bufinfo .len ));
190
+ } else {
191
+ // Block size is less than native erase-page size, so do erase in sections.
192
+ uint32_t addr = (offset / NATIVE_BLOCK_SIZE_BYTES ) * NATIVE_BLOCK_SIZE_BYTES ;
193
+ uint32_t o = offset % NATIVE_BLOCK_SIZE_BYTES ;
194
+ uint32_t top_addr = offset + bufinfo .len ;
195
+ while (addr < top_addr ) {
196
+ if (o > 0 || top_addr < addr + NATIVE_BLOCK_SIZE_BYTES ) {
197
+ check_esp_err (esp_partition_read (self -> part , addr , self -> cache , NATIVE_BLOCK_SIZE_BYTES ));
198
+ }
199
+ check_esp_err (esp_partition_erase_range (self -> part , addr , NATIVE_BLOCK_SIZE_BYTES ));
200
+ if (o > 0 ) {
201
+ check_esp_err (esp_partition_write (self -> part , addr , self -> cache , o ));
202
+ }
203
+ if (top_addr < addr + NATIVE_BLOCK_SIZE_BYTES ) {
204
+ check_esp_err (esp_partition_write (self -> part , top_addr , self -> cache , addr + NATIVE_BLOCK_SIZE_BYTES - top_addr ));
205
+ }
206
+ o = 0 ;
207
+ addr += NATIVE_BLOCK_SIZE_BYTES ;
208
+ }
209
+ }
166
210
} else {
211
+ // An extended write, erasing must have been done explicitly before this write.
167
212
offset += mp_obj_get_int (args [3 ]);
168
213
}
169
214
check_esp_err (esp_partition_write (self -> part , offset , bufinfo .buf , bufinfo .len ));
@@ -182,12 +227,15 @@ STATIC mp_obj_t esp32_partition_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_
182
227
case MP_BLOCKDEV_IOCTL_SYNC :
183
228
return MP_OBJ_NEW_SMALL_INT (0 );
184
229
case MP_BLOCKDEV_IOCTL_BLOCK_COUNT :
185
- return MP_OBJ_NEW_SMALL_INT (self -> part -> size / BLOCK_SIZE_BYTES );
230
+ return MP_OBJ_NEW_SMALL_INT (self -> part -> size / self -> block_size );
186
231
case MP_BLOCKDEV_IOCTL_BLOCK_SIZE :
187
- return MP_OBJ_NEW_SMALL_INT (BLOCK_SIZE_BYTES );
232
+ return MP_OBJ_NEW_SMALL_INT (self -> block_size );
188
233
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE : {
189
- uint32_t offset = mp_obj_get_int (arg_in ) * BLOCK_SIZE_BYTES ;
190
- check_esp_err (esp_partition_erase_range (self -> part , offset , BLOCK_SIZE_BYTES ));
234
+ if (self -> block_size != NATIVE_BLOCK_SIZE_BYTES ) {
235
+ return MP_OBJ_NEW_SMALL_INT (- MP_EINVAL );
236
+ }
237
+ uint32_t offset = mp_obj_get_int (arg_in ) * NATIVE_BLOCK_SIZE_BYTES ;
238
+ check_esp_err (esp_partition_erase_range (self -> part , offset , NATIVE_BLOCK_SIZE_BYTES ));
191
239
return MP_OBJ_NEW_SMALL_INT (0 );
192
240
}
193
241
default :
@@ -205,7 +253,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp32_partition_set_boot_obj, esp32_partition_s
205
253
206
254
STATIC mp_obj_t esp32_partition_get_next_update (mp_obj_t self_in ) {
207
255
esp32_partition_obj_t * self = MP_OBJ_TO_PTR (self_in );
208
- return MP_OBJ_FROM_PTR (esp32_partition_new (esp_ota_get_next_update_partition (self -> part )));
256
+ return MP_OBJ_FROM_PTR (esp32_partition_new (esp_ota_get_next_update_partition (self -> part ), NATIVE_BLOCK_SIZE_BYTES ));
209
257
}
210
258
STATIC MP_DEFINE_CONST_FUN_OBJ_1 (esp32_partition_get_next_update_obj , esp32_partition_get_next_update );
211
259
0 commit comments