Chip-cn-dat/Espressif-dat/ESP32-S3-DAT/ESP32-S3-SDK-dat/ESP32-S3-SDK-dat.md
... ...
@@ -3,7 +3,7 @@
3 3
4 4
- [[ESP32-S3-dat]]
5 5
6
-- [[ESP-SDK-dat]]
6
+- [[ESP-SDK-dat]] - [[ESP32-SDK-dat]]
7 7
8 8
- [[micropython-dat]] - [[circuitpython-dat]] - [[circuitpython-ESP32-s3-dat]]
9 9
SDK-dat/ESP-SDK-dat/ESP32-SDK-dat/ESP32-SDK-dat.md
... ...
@@ -8,7 +8,11 @@
8 8
9 9
- [[esptool-dat]]
10 10
11
-- [[data-storage-dat]] - [[USB-MSC-dat]]
11
+- [[data-storage-dat]] - [[USB-MSC-dat]] - [[SPIFF-dat]] - [[memory-dat]]
12
+
13
+- [[partition-table-dat]]
14
+
15
+
12 16
13 17
14 18
## other reference
... ...
@@ -18,6 +22,9 @@
18 22
19 23
20 24
25
+## arduino
26
+
27
+- C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32
21 28
22 29
23 30
Tech-dat/memory-dat/SPIFF-dat/SPIFF-dat.md
... ...
@@ -1,6 +1,37 @@
1 1
2 2
# SPIFF-dat
3 3
4
+- [[spiffsgen-dat]]
5
+
6
+
7
+
8
+## arduino read and print partition table
9
+
10
+
11
+code
12
+
13
+ void printPartitionTable() {
14
+ Serial.println("\n--- Partition Table ---");
15
+ esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
16
+
17
+ while (it != NULL) {
18
+ const esp_partition_t* part = esp_partition_get(it);
19
+ Serial.printf("Label: %-10s Type: 0x%02x SubType: 0x%02x Address: 0x%06x Size: 0x%06x\n",
20
+ part->label, part->type, part->subtype, part->address, part->size);
21
+ it = esp_partition_next(it);
22
+ }
23
+ esp_partition_iterator_release(it);
24
+ }
25
+
26
+output
27
+
28
+ --- Partition Table ---
29
+ Label: nvs Type: 0x01 SubType: 0x02 Address: 0x009000 Size: 0x005000
30
+ Label: otadata Type: 0x01 SubType: 0x00 Address: 0x00e000 Size: 0x002000
31
+ Label: app0 Type: 0x00 SubType: 0x10 Address: 0x010000 Size: 0x140000
32
+ Label: app1 Type: 0x00 SubType: 0x11 Address: 0x150000 Size: 0x140000
33
+ Label: spiffs Type: 0x01 SubType: 0x82 Address: 0x290000 Size: 0x160000
34
+ Label: coredump Type: 0x01 SubType: 0x03 Address: 0x3f0000 Size: 0x010000
4 35
5 36
6 37
Tech-dat/memory-dat/SPIFF-dat/spiffsgen-dat/spiffs_files_in/test.txt
... ...
@@ -0,0 +1,3 @@
1
+123
2
+321
3
+abc
... ...
\ No newline at end of file
Tech-dat/memory-dat/SPIFF-dat/spiffsgen-dat/spiffs_image.bin
... ...
Binary files /dev/null and b/Tech-dat/memory-dat/SPIFF-dat/spiffsgen-dat/spiffs_image.bin differ
Tech-dat/memory-dat/SPIFF-dat/spiffsgen-dat/spiffsgen-dat.md
... ...
@@ -0,0 +1,122 @@
1
+
2
+# spiffsgen-dat.md
3
+
4
+https://github.com/espressif/esp-idf/blob/v5.5.1/components/spiffs/spiffsgen.py
5
+
6
+
7
+ python spiffsgen.py <image_size> <base_dir> <output_file>
8
+
9
+Use an image size that is a multiple of the block size (commonly 4096, 40960, 524288, etc.).
10
+
11
+Example (for 1MB image, block size 4096):
12
+
13
+ python spiffsgen.py 1048576 . spiffs_image.bin
14
+
15
+1048576 / 4096 (4 KB) = 256 blocks
16
+
17
+ python spiffsgen.py 40960 test.txt spiffs_image.bin
18
+
19
+To include multiple files in the SPIFFS image, specify a directory (not individual files) as the <base_dir> argument. All files and subdirectories inside that directory will be included in the image.
20
+
21
+Example:
22
+
23
+Suppose you have a folder called spiffs_files containing several files:
24
+
25
+ spiffs_files/
26
+ file1.txt
27
+ file2.txt
28
+ config.json
29
+
30
+
31
+
32
+run: python spiffsgen.py 40960 ./spiffs_files_in spiffs_image.bin
33
+
34
+ python spiffsgen.py 0x160000 ./spiffs_files_in spiffs_image.bin
35
+
36
+## extract (not working )
37
+
38
+ python spiffsgen.py 40960 ./spiffs_files spiffs_image.bin --extract <output_dir>
39
+
40
+ python spiffsgen.py 40960 dummy_dir spiffs_image.bin --extract extracted_files
41
+
42
+ python spiffsgen.py 40960 ./spiffs_files spiffs_image.bin --extract spiffs_files_out
43
+
44
+ python spiffsgen.py 40960 ./spiffs_files spiffs_image.bin --extract spiffs_files_out
45
+
46
+
47
+## flash it
48
+
49
+- [[ESPtool-dat]]
50
+
51
+ python esptool.py --chip esp32 --port [port] --baud [baud] write_flash -z 0x110000 spiffs.bin
52
+
53
+ esptool --chip esp32-s3 --port COM16 --baud 921600 write_flash -z 0x290000 spiffs_image.bin
54
+
55
+
56
+## test result
57
+
58
+```
59
+ ESP32 SPIFFS Reader
60
+
61
+ --- Partition Table ---
62
+ Label: nvs Type: 0x01 SubType: 0x02 Address: 0x009000 Size: 0x005000
63
+ Label: otadata Type: 0x01 SubType: 0x00 Address: 0x00e000 Size: 0x002000
64
+ Label: app0 Type: 0x00 SubType: 0x10 Address: 0x010000 Size: 0x140000
65
+ Label: app1 Type: 0x00 SubType: 0x11 Address: 0x150000 Size: 0x140000
66
+ Label: spiffs Type: 0x01 SubType: 0x82 Address: 0x290000 Size: 0x160000
67
+ Label: coredump Type: 0x01 SubType: 0x03 Address: 0x3f0000 Size: 0x010000
68
+ SPIFFS partition found at: 0x290000, size: 0x160000
69
+ SPIFFS mounted successfully
70
+ SPIFFS Total: 1318001 bytes, Used: 502 bytes
71
+
72
+ --- File and Folder List ---
73
+ Listing directory: /
74
+ FILE: test.txt SIZE: 13
75
+
76
+ --- Reading test.txt ---
77
+ Reading file: /test.txt
78
+ - read from file:
79
+ 123
80
+ 321
81
+ abc
82
+ Done reading SPIFFS image.
83
+
84
+```
85
+
86
+
87
+
88
+## options:
89
+
90
+**
91
+ -h, --help show this help message and exit
92
+ --page-size PAGE_SIZE
93
+ Logical page size. Set to value same as CONFIG_SPIFFS_PAGE_SIZE. (default: 256)
94
+ --block-size BLOCK_SIZE
95
+ Logical block size. Set to the same value as the flash chip's sector size
96
+ (g_rom_flashchip.sector_size). (default: 4096)
97
+ --obj-name-len OBJ_NAME_LEN
98
+ File full path maximum length. Set to value same as CONFIG_SPIFFS_OBJ_NAME_LEN. (default: 32)
99
+ --meta-len META_LEN File metadata length. Set to value same as CONFIG_SPIFFS_META_LENGTH. (default: 4)
100
+ --use-magic Use magic number to create an identifiable SPIFFS image. Specify if CONFIG_SPIFFS_USE_MAGIC.
101
+ (default: True)
102
+ --no-magic Inverse of --use-magic (default: --use-magic is enabled)
103
+ --use-magic-len Use position in memory to create different magic numbers for each block. Specify if
104
+ CONFIG_SPIFFS_USE_MAGIC_LENGTH. (default: True)
105
+ --no-magic-len Inverse of --use-magic-len (default: --use-magic-len is enabled)
106
+ --follow-symlinks Take into account symbolic links during partition image creation. (default: False)
107
+ --big-endian Specify if the target architecture is big-endian. If not specified, little-endian is assumed.
108
+ (default: False)
109
+ --aligned-obj-ix-tables
110
+ Use aligned object index tables. Specify if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES is set.
111
+ (default: False)
112
+
113
+
114
+
115
+
116
+
117
+
118
+## ref
119
+
120
+- [[SPIFF-dat]]
121
+
122
+- [[SPIFF]] - [[memory]]
... ...
\ No newline at end of file
Tech-dat/memory-dat/SPIFF-dat/spiffsgen-dat/spiffsgen.py
... ...
@@ -0,0 +1,590 @@
1
+#!/usr/bin/env python
2
+#
3
+# spiffsgen is a tool used to generate a spiffs image from a directory
4
+#
5
+# SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
6
+# SPDX-License-Identifier: Apache-2.0
7
+import argparse
8
+import io
9
+import math
10
+import os
11
+import struct
12
+
13
+try:
14
+ import typing
15
+
16
+ TSP = typing.TypeVar('TSP', bound='SpiffsObjPageWithIdx')
17
+ ObjIdsItem = typing.Tuple[int, typing.Type[TSP]]
18
+except ImportError:
19
+ pass
20
+
21
+
22
+SPIFFS_PH_FLAG_USED_FINAL_INDEX = 0xF8
23
+SPIFFS_PH_FLAG_USED_FINAL = 0xFC
24
+
25
+SPIFFS_PH_FLAG_LEN = 1
26
+SPIFFS_PH_IX_SIZE_LEN = 4
27
+SPIFFS_PH_IX_OBJ_TYPE_LEN = 1
28
+SPIFFS_TYPE_FILE = 1
29
+
30
+# Based on typedefs under spiffs_config.h
31
+SPIFFS_OBJ_ID_LEN = 2 # spiffs_obj_id
32
+SPIFFS_SPAN_IX_LEN = 2 # spiffs_span_ix
33
+SPIFFS_PAGE_IX_LEN = 2 # spiffs_page_ix
34
+SPIFFS_BLOCK_IX_LEN = 2 # spiffs_block_ix
35
+
36
+
37
+class SpiffsBuildConfig(object):
38
+ def __init__(self,
39
+ page_size, # type: int
40
+ page_ix_len, # type: int
41
+ block_size, # type: int
42
+ block_ix_len, # type: int
43
+ meta_len, # type: int
44
+ obj_name_len, # type: int
45
+ obj_id_len, # type: int
46
+ span_ix_len, # type: int
47
+ packed, # type: bool
48
+ aligned, # type: bool
49
+ endianness, # type: str
50
+ use_magic, # type: bool
51
+ use_magic_len, # type: bool
52
+ aligned_obj_ix_tables # type: bool
53
+ ):
54
+ if block_size % page_size != 0:
55
+ raise RuntimeError('block size should be a multiple of page size')
56
+
57
+ self.page_size = page_size
58
+ self.block_size = block_size
59
+ self.obj_id_len = obj_id_len
60
+ self.span_ix_len = span_ix_len
61
+ self.packed = packed
62
+ self.aligned = aligned
63
+ self.obj_name_len = obj_name_len
64
+ self.meta_len = meta_len
65
+ self.page_ix_len = page_ix_len
66
+ self.block_ix_len = block_ix_len
67
+ self.endianness = endianness
68
+ self.use_magic = use_magic
69
+ self.use_magic_len = use_magic_len
70
+ self.aligned_obj_ix_tables = aligned_obj_ix_tables
71
+
72
+ self.PAGES_PER_BLOCK = self.block_size // self.page_size
73
+ self.OBJ_LU_PAGES_PER_BLOCK = int(math.ceil(self.block_size / self.page_size * self.obj_id_len / self.page_size))
74
+ self.OBJ_USABLE_PAGES_PER_BLOCK = self.PAGES_PER_BLOCK - self.OBJ_LU_PAGES_PER_BLOCK
75
+
76
+ self.OBJ_LU_PAGES_OBJ_IDS_LIM = self.page_size // self.obj_id_len
77
+
78
+ self.OBJ_DATA_PAGE_HEADER_LEN = self.obj_id_len + self.span_ix_len + SPIFFS_PH_FLAG_LEN
79
+
80
+ pad = 4 - (4 if self.OBJ_DATA_PAGE_HEADER_LEN % 4 == 0 else self.OBJ_DATA_PAGE_HEADER_LEN % 4)
81
+
82
+ self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED = self.OBJ_DATA_PAGE_HEADER_LEN + pad
83
+ self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD = pad
84
+ self.OBJ_DATA_PAGE_CONTENT_LEN = self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN
85
+
86
+ self.OBJ_INDEX_PAGES_HEADER_LEN = (self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED + SPIFFS_PH_IX_SIZE_LEN +
87
+ SPIFFS_PH_IX_OBJ_TYPE_LEN + self.obj_name_len + self.meta_len)
88
+ if aligned_obj_ix_tables:
89
+ self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = (self.OBJ_INDEX_PAGES_HEADER_LEN + SPIFFS_PAGE_IX_LEN - 1) & ~(SPIFFS_PAGE_IX_LEN - 1)
90
+ self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED - self.OBJ_INDEX_PAGES_HEADER_LEN
91
+ else:
92
+ self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = self.OBJ_INDEX_PAGES_HEADER_LEN
93
+ self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = 0
94
+
95
+ self.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM = (self.page_size - self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED) // self.block_ix_len
96
+ self.OBJ_INDEX_PAGES_OBJ_IDS_LIM = (self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED) // self.block_ix_len
97
+
98
+
99
+class SpiffsFullError(RuntimeError):
100
+ pass
101
+
102
+
103
+class SpiffsPage(object):
104
+ _endianness_dict = {
105
+ 'little': '<',
106
+ 'big': '>'
107
+ }
108
+
109
+ _len_dict = {
110
+ 1: 'B',
111
+ 2: 'H',
112
+ 4: 'I',
113
+ 8: 'Q'
114
+ }
115
+
116
+ def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None
117
+ self.build_config = build_config
118
+ self.bix = bix
119
+
120
+ def to_binary(self): # type: () -> bytes
121
+ raise NotImplementedError()
122
+
123
+
124
+class SpiffsObjPageWithIdx(SpiffsPage):
125
+ def __init__(self, obj_id, build_config): # type: (int, SpiffsBuildConfig) -> None
126
+ super(SpiffsObjPageWithIdx, self).__init__(0, build_config)
127
+ self.obj_id = obj_id
128
+
129
+ def to_binary(self): # type: () -> bytes
130
+ raise NotImplementedError()
131
+
132
+
133
+class SpiffsObjLuPage(SpiffsPage):
134
+ def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None
135
+ SpiffsPage.__init__(self, bix, build_config)
136
+
137
+ self.obj_ids_limit = self.build_config.OBJ_LU_PAGES_OBJ_IDS_LIM
138
+ self.obj_ids = list() # type: typing.List[ObjIdsItem]
139
+
140
+ def _calc_magic(self, blocks_lim): # type: (int) -> int
141
+ # Calculate the magic value mirroring computation done by the macro SPIFFS_MAGIC defined in
142
+ # spiffs_nucleus.h
143
+ magic = 0x20140529 ^ self.build_config.page_size
144
+ if self.build_config.use_magic_len:
145
+ magic = magic ^ (blocks_lim - self.bix)
146
+ # narrow the result to build_config.obj_id_len bytes
147
+ mask = (2 << (8 * self.build_config.obj_id_len)) - 1
148
+ return magic & mask
149
+
150
+ def register_page(self, page): # type: (TSP) -> None
151
+ if not self.obj_ids_limit > 0:
152
+ raise SpiffsFullError()
153
+
154
+ obj_id = (page.obj_id, page.__class__)
155
+ self.obj_ids.append(obj_id)
156
+ self.obj_ids_limit -= 1
157
+
158
+ def to_binary(self): # type: () -> bytes
159
+ img = b''
160
+
161
+ for (obj_id, page_type) in self.obj_ids:
162
+ if page_type == SpiffsObjIndexPage:
163
+ obj_id ^= (1 << ((self.build_config.obj_id_len * 8) - 1))
164
+ img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
165
+ SpiffsPage._len_dict[self.build_config.obj_id_len], obj_id)
166
+
167
+ assert len(img) <= self.build_config.page_size
168
+
169
+ img += b'\xFF' * (self.build_config.page_size - len(img))
170
+
171
+ return img
172
+
173
+ def magicfy(self, blocks_lim): # type: (int) -> None
174
+ # Only use magic value if no valid obj id has been written to the spot, which is the
175
+ # spot taken up by the last obj id on last lookup page. The parent is responsible
176
+ # for determining which is the last lookup page and calling this function.
177
+ remaining = self.obj_ids_limit
178
+ empty_obj_id_dict = {
179
+ 1: 0xFF,
180
+ 2: 0xFFFF,
181
+ 4: 0xFFFFFFFF,
182
+ 8: 0xFFFFFFFFFFFFFFFF
183
+ }
184
+ if remaining >= 2:
185
+ for i in range(remaining):
186
+ if i == remaining - 2:
187
+ self.obj_ids.append((self._calc_magic(blocks_lim), SpiffsObjDataPage))
188
+ break
189
+ else:
190
+ self.obj_ids.append((empty_obj_id_dict[self.build_config.obj_id_len], SpiffsObjDataPage))
191
+ self.obj_ids_limit -= 1
192
+
193
+
194
+class SpiffsObjIndexPage(SpiffsObjPageWithIdx):
195
+ def __init__(self, obj_id, span_ix, size, name, build_config
196
+ ): # type: (int, int, int, str, SpiffsBuildConfig) -> None
197
+ super(SpiffsObjIndexPage, self).__init__(obj_id, build_config)
198
+ self.span_ix = span_ix
199
+ self.name = name
200
+ self.size = size
201
+
202
+ if self.span_ix == 0:
203
+ self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM
204
+ else:
205
+ self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_LIM
206
+
207
+ self.pages = list() # type: typing.List[int]
208
+
209
+ def register_page(self, page): # type: (SpiffsObjDataPage) -> None
210
+ if not self.pages_lim > 0:
211
+ raise SpiffsFullError
212
+
213
+ self.pages.append(page.offset)
214
+ self.pages_lim -= 1
215
+
216
+ def to_binary(self): # type: () -> bytes
217
+ obj_id = self.obj_id ^ (1 << ((self.build_config.obj_id_len * 8) - 1))
218
+ img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
219
+ SpiffsPage._len_dict[self.build_config.obj_id_len] +
220
+ SpiffsPage._len_dict[self.build_config.span_ix_len] +
221
+ SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN],
222
+ obj_id,
223
+ self.span_ix,
224
+ SPIFFS_PH_FLAG_USED_FINAL_INDEX)
225
+
226
+ # Add padding before the object index page specific information
227
+ img += b'\xFF' * self.build_config.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD
228
+
229
+ # If this is the first object index page for the object, add filename, type
230
+ # and size information
231
+ if self.span_ix == 0:
232
+ img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
233
+ SpiffsPage._len_dict[SPIFFS_PH_IX_SIZE_LEN] +
234
+ SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN],
235
+ self.size,
236
+ SPIFFS_TYPE_FILE)
237
+
238
+ img += self.name.encode() + (b'\x00' * (
239
+ (self.build_config.obj_name_len - len(self.name))
240
+ + self.build_config.meta_len
241
+ + self.build_config.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD))
242
+
243
+ # Finally, add the page index of data pages
244
+ for page in self.pages:
245
+ page = page >> int(math.log(self.build_config.page_size, 2))
246
+ img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
247
+ SpiffsPage._len_dict[self.build_config.page_ix_len], page)
248
+
249
+ assert len(img) <= self.build_config.page_size
250
+
251
+ img += b'\xFF' * (self.build_config.page_size - len(img))
252
+
253
+ return img
254
+
255
+
256
+class SpiffsObjDataPage(SpiffsObjPageWithIdx):
257
+ def __init__(self, offset, obj_id, span_ix, contents, build_config
258
+ ): # type: (int, int, int, bytes, SpiffsBuildConfig) -> None
259
+ super(SpiffsObjDataPage, self).__init__(obj_id, build_config)
260
+ self.span_ix = span_ix
261
+ self.contents = contents
262
+ self.offset = offset
263
+
264
+ def to_binary(self): # type: () -> bytes
265
+ img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] +
266
+ SpiffsPage._len_dict[self.build_config.obj_id_len] +
267
+ SpiffsPage._len_dict[self.build_config.span_ix_len] +
268
+ SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN],
269
+ self.obj_id,
270
+ self.span_ix,
271
+ SPIFFS_PH_FLAG_USED_FINAL)
272
+
273
+ img += self.contents
274
+
275
+ assert len(img) <= self.build_config.page_size
276
+
277
+ img += b'\xFF' * (self.build_config.page_size - len(img))
278
+
279
+ return img
280
+
281
+
282
+class SpiffsBlock(object):
283
+ def _reset(self): # type: () -> None
284
+ self.cur_obj_index_span_ix = 0
285
+ self.cur_obj_data_span_ix = 0
286
+ self.cur_obj_id = 0
287
+ self.cur_obj_idx_page = None # type: typing.Optional[SpiffsObjIndexPage]
288
+
289
+ def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None
290
+ self.build_config = build_config
291
+ self.offset = bix * self.build_config.block_size
292
+ self.remaining_pages = self.build_config.OBJ_USABLE_PAGES_PER_BLOCK
293
+ self.pages = list() # type: typing.List[SpiffsPage]
294
+ self.bix = bix
295
+
296
+ lu_pages = list()
297
+ for i in range(self.build_config.OBJ_LU_PAGES_PER_BLOCK):
298
+ page = SpiffsObjLuPage(self.bix, self.build_config)
299
+ lu_pages.append(page)
300
+
301
+ self.pages.extend(lu_pages)
302
+
303
+ self.lu_page_iter = iter(lu_pages)
304
+ self.lu_page = next(self.lu_page_iter)
305
+
306
+ self._reset()
307
+
308
+ def _register_page(self, page): # type: (TSP) -> None
309
+ if isinstance(page, SpiffsObjDataPage):
310
+ assert self.cur_obj_idx_page is not None
311
+ self.cur_obj_idx_page.register_page(page) # can raise SpiffsFullError
312
+
313
+ try:
314
+ self.lu_page.register_page(page)
315
+ except SpiffsFullError:
316
+ self.lu_page = next(self.lu_page_iter)
317
+ try:
318
+ self.lu_page.register_page(page)
319
+ except AttributeError: # no next lookup page
320
+ # Since the amount of lookup pages is pre-computed at every block instance,
321
+ # this should never occur
322
+ raise RuntimeError('invalid attempt to add page to a block when there is no more space in lookup')
323
+
324
+ self.pages.append(page)
325
+
326
+ def begin_obj(self, obj_id, size, name, obj_index_span_ix=0, obj_data_span_ix=0
327
+ ): # type: (int, int, str, int, int) -> None
328
+ if not self.remaining_pages > 0:
329
+ raise SpiffsFullError()
330
+ self._reset()
331
+
332
+ self.cur_obj_id = obj_id
333
+ self.cur_obj_index_span_ix = obj_index_span_ix
334
+ self.cur_obj_data_span_ix = obj_data_span_ix
335
+
336
+ page = SpiffsObjIndexPage(obj_id, self.cur_obj_index_span_ix, size, name, self.build_config)
337
+ self._register_page(page)
338
+
339
+ self.cur_obj_idx_page = page
340
+
341
+ self.remaining_pages -= 1
342
+ self.cur_obj_index_span_ix += 1
343
+
344
+ def update_obj(self, contents): # type: (bytes) -> None
345
+ if not self.remaining_pages > 0:
346
+ raise SpiffsFullError()
347
+ page = SpiffsObjDataPage(self.offset + (len(self.pages) * self.build_config.page_size),
348
+ self.cur_obj_id, self.cur_obj_data_span_ix, contents, self.build_config)
349
+
350
+ self._register_page(page)
351
+
352
+ self.cur_obj_data_span_ix += 1
353
+ self.remaining_pages -= 1
354
+
355
+ def end_obj(self): # type: () -> None
356
+ self._reset()
357
+
358
+ def is_full(self): # type: () -> bool
359
+ return self.remaining_pages <= 0
360
+
361
+ def to_binary(self, blocks_lim): # type: (int) -> bytes
362
+ img = b''
363
+
364
+ if self.build_config.use_magic:
365
+ for (idx, page) in enumerate(self.pages):
366
+ if idx == self.build_config.OBJ_LU_PAGES_PER_BLOCK - 1:
367
+ assert isinstance(page, SpiffsObjLuPage)
368
+ page.magicfy(blocks_lim)
369
+ img += page.to_binary()
370
+ else:
371
+ for page in self.pages:
372
+ img += page.to_binary()
373
+
374
+ assert len(img) <= self.build_config.block_size
375
+
376
+ img += b'\xFF' * (self.build_config.block_size - len(img))
377
+ return img
378
+
379
+
380
+class SpiffsFS(object):
381
+ def __init__(self, img_size, build_config): # type: (int, SpiffsBuildConfig) -> None
382
+ if img_size % build_config.block_size != 0:
383
+ raise RuntimeError('image size should be a multiple of block size')
384
+
385
+ self.img_size = img_size
386
+ self.build_config = build_config
387
+
388
+ self.blocks = list() # type: typing.List[SpiffsBlock]
389
+ self.blocks_lim = self.img_size // self.build_config.block_size
390
+ self.remaining_blocks = self.blocks_lim
391
+ self.cur_obj_id = 1 # starting object id
392
+
393
+ def _create_block(self): # type: () -> SpiffsBlock
394
+ if self.is_full():
395
+ raise SpiffsFullError('the image size has been exceeded')
396
+
397
+ block = SpiffsBlock(len(self.blocks), self.build_config)
398
+ self.blocks.append(block)
399
+ self.remaining_blocks -= 1
400
+ return block
401
+
402
+ def is_full(self): # type: () -> bool
403
+ return self.remaining_blocks <= 0
404
+
405
+ def create_file(self, img_path, file_path): # type: (str, str) -> None
406
+ if len(img_path) > self.build_config.obj_name_len:
407
+ raise RuntimeError("object name '%s' too long" % img_path)
408
+
409
+ name = img_path
410
+
411
+ with open(file_path, 'rb') as obj:
412
+ contents = obj.read()
413
+
414
+ stream = io.BytesIO(contents)
415
+
416
+ try:
417
+ block = self.blocks[-1]
418
+ block.begin_obj(self.cur_obj_id, len(contents), name)
419
+ except (IndexError, SpiffsFullError):
420
+ block = self._create_block()
421
+ block.begin_obj(self.cur_obj_id, len(contents), name)
422
+
423
+ contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN)
424
+
425
+ while contents_chunk:
426
+ try:
427
+ block = self.blocks[-1]
428
+ try:
429
+ # This can fail because either (1) all the pages in block have been
430
+ # used or (2) object index has been exhausted.
431
+ block.update_obj(contents_chunk)
432
+ except SpiffsFullError:
433
+ # If its (1), use the outer exception handler
434
+ if block.is_full():
435
+ raise SpiffsFullError
436
+ # If its (2), write another object index page
437
+ block.begin_obj(self.cur_obj_id, len(contents), name,
438
+ obj_index_span_ix=block.cur_obj_index_span_ix,
439
+ obj_data_span_ix=block.cur_obj_data_span_ix)
440
+ continue
441
+ except (IndexError, SpiffsFullError):
442
+ # All pages in the block have been exhausted. Create a new block, copying
443
+ # the previous state of the block to a new one for the continuation of the
444
+ # current object
445
+ prev_block = block
446
+ block = self._create_block()
447
+ block.cur_obj_id = prev_block.cur_obj_id
448
+ block.cur_obj_idx_page = prev_block.cur_obj_idx_page
449
+ block.cur_obj_data_span_ix = prev_block.cur_obj_data_span_ix
450
+ block.cur_obj_index_span_ix = prev_block.cur_obj_index_span_ix
451
+ continue
452
+
453
+ contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN)
454
+
455
+ block.end_obj()
456
+
457
+ self.cur_obj_id += 1
458
+
459
+ def to_binary(self): # type: () -> bytes
460
+ img = b''
461
+ all_blocks = []
462
+ for block in self.blocks:
463
+ all_blocks.append(block.to_binary(self.blocks_lim))
464
+ bix = len(self.blocks)
465
+ if self.build_config.use_magic:
466
+ # Create empty blocks with magic numbers
467
+ while self.remaining_blocks > 0:
468
+ block = SpiffsBlock(bix, self.build_config)
469
+ all_blocks.append(block.to_binary(self.blocks_lim))
470
+ self.remaining_blocks -= 1
471
+ bix += 1
472
+ else:
473
+ # Just fill remaining spaces FF's
474
+ all_blocks.append(b'\xFF' * (self.img_size - len(all_blocks) * self.build_config.block_size))
475
+ img += b''.join([blk for blk in all_blocks])
476
+ return img
477
+
478
+
479
+class CustomHelpFormatter(argparse.HelpFormatter):
480
+ """
481
+ Similar to argparse.ArgumentDefaultsHelpFormatter, except it
482
+ doesn't add the default value if "(default:" is already present.
483
+ This helps in the case of options with action="store_false", like
484
+ --no-magic or --no-magic-len.
485
+ """
486
+ def _get_help_string(self, action): # type: (argparse.Action) -> str
487
+ if action.help is None:
488
+ return ''
489
+ if '%(default)' not in action.help and '(default:' not in action.help:
490
+ if action.default is not argparse.SUPPRESS:
491
+ defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE]
492
+ if action.option_strings or action.nargs in defaulting_nargs:
493
+ return action.help + ' (default: %(default)s)'
494
+ return action.help
495
+
496
+
497
+def main(): # type: () -> None
498
+ parser = argparse.ArgumentParser(description='SPIFFS Image Generator',
499
+ formatter_class=CustomHelpFormatter)
500
+
501
+ parser.add_argument('image_size',
502
+ help='Size of the created image')
503
+
504
+ parser.add_argument('base_dir',
505
+ help='Path to directory from which the image will be created')
506
+
507
+ parser.add_argument('output_file',
508
+ help='Created image output file path')
509
+
510
+ parser.add_argument('--page-size',
511
+ help='Logical page size. Set to value same as CONFIG_SPIFFS_PAGE_SIZE.',
512
+ type=int,
513
+ default=256)
514
+
515
+ parser.add_argument('--block-size',
516
+ help="Logical block size. Set to the same value as the flash chip's sector size (g_rom_flashchip.sector_size).",
517
+ type=int,
518
+ default=4096)
519
+
520
+ parser.add_argument('--obj-name-len',
521
+ help='File full path maximum length. Set to value same as CONFIG_SPIFFS_OBJ_NAME_LEN.',
522
+ type=int,
523
+ default=32)
524
+
525
+ parser.add_argument('--meta-len',
526
+ help='File metadata length. Set to value same as CONFIG_SPIFFS_META_LENGTH.',
527
+ type=int,
528
+ default=4)
529
+
530
+ parser.add_argument('--use-magic',
531
+ dest='use_magic',
532
+ help='Use magic number to create an identifiable SPIFFS image. Specify if CONFIG_SPIFFS_USE_MAGIC.',
533
+ action='store_true')
534
+
535
+ parser.add_argument('--no-magic',
536
+ dest='use_magic',
537
+ help='Inverse of --use-magic (default: --use-magic is enabled)',
538
+ action='store_false')
539
+
540
+ parser.add_argument('--use-magic-len',
541
+ dest='use_magic_len',
542
+ help='Use position in memory to create different magic numbers for each block. Specify if CONFIG_SPIFFS_USE_MAGIC_LENGTH.',
543
+ action='store_true')
544
+
545
+ parser.add_argument('--no-magic-len',
546
+ dest='use_magic_len',
547
+ help='Inverse of --use-magic-len (default: --use-magic-len is enabled)',
548
+ action='store_false')
549
+
550
+ parser.add_argument('--follow-symlinks',
551
+ help='Take into account symbolic links during partition image creation.',
552
+ action='store_true')
553
+
554
+ parser.add_argument('--big-endian',
555
+ help='Specify if the target architecture is big-endian. If not specified, little-endian is assumed.',
556
+ action='store_true')
557
+
558
+ parser.add_argument('--aligned-obj-ix-tables',
559
+ action='store_true',
560
+ help='Use aligned object index tables. Specify if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES is set.')
561
+
562
+ parser.set_defaults(use_magic=True, use_magic_len=True)
563
+
564
+ args = parser.parse_args()
565
+
566
+ if not os.path.exists(args.base_dir):
567
+ raise RuntimeError('given base directory %s does not exist' % args.base_dir)
568
+
569
+ with open(args.output_file, 'wb') as image_file:
570
+ image_size = int(args.image_size, 0)
571
+ spiffs_build_default = SpiffsBuildConfig(args.page_size, SPIFFS_PAGE_IX_LEN,
572
+ args.block_size, SPIFFS_BLOCK_IX_LEN, args.meta_len,
573
+ args.obj_name_len, SPIFFS_OBJ_ID_LEN, SPIFFS_SPAN_IX_LEN,
574
+ True, True, 'big' if args.big_endian else 'little',
575
+ args.use_magic, args.use_magic_len, args.aligned_obj_ix_tables)
576
+
577
+ spiffs = SpiffsFS(image_size, spiffs_build_default)
578
+
579
+ for root, dirs, files in os.walk(args.base_dir, followlinks=args.follow_symlinks):
580
+ for f in files:
581
+ full_path = os.path.join(root, f)
582
+ spiffs.create_file('/' + os.path.relpath(full_path, args.base_dir).replace('\\', '/'), full_path)
583
+
584
+ image = spiffs.to_binary()
585
+
586
+ image_file.write(image)
587
+
588
+
589
+if __name__ == '__main__':
590
+ main()
Tech-dat/memory-dat/partition-table-dat/partition-table-dat.md
... ...
@@ -0,0 +1,18 @@
1
+# partition-table-dat
2
+
3
+https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/partition-tables.html
4
+
5
+Here is the summary printed for the "Factory app, two OTA definitions" configuration:
6
+
7
+
8
+| Name | Type | SubType | Offset | Size | Flags |
9
+|----------|------|---------|-----------|---------|-------|
10
+| nvs | data | nvs | 0x9000 | 0x4000 | |
11
+| otadata | data | ota | 0xd000 | 0x2000 | |
12
+| phy_init | data | phy | 0xf000 | 0x1000 | |
13
+| factory | app | factory | 0x10000 | 1M | |
14
+| ota_0 | app | ota_0 | 0x110000 | 1M | |
15
+| ota_1 | app | ota_1 | 0x210000 | 1M | |
16
+
17
+
18
+