30
30
#include "compiler.h"
31
31
#include "validation.h"
32
32
33
+ // Set to 1 to enable debugging
34
+ #define DEBUG_FILE_STREAM 0
35
+
36
+ #if DEBUG_FILE_STREAM
37
+ #include "daplink_debug.h"
38
+ #define stream_printf debug_msg
39
+ #else
40
+ #define stream_printf (...)
41
+ #endif
42
+
33
43
typedef enum {
34
44
STREAM_STATE_CLOSED ,
35
45
STREAM_STATE_OPEN ,
@@ -75,9 +85,15 @@ static error_t open_hex(void *state);
75
85
static error_t write_hex (void * state , const uint8_t * data , uint32_t size );
76
86
static error_t close_hex (void * state );
77
87
78
- stream_t stream [] = {
88
+ static bool detect_uhex_blocks (const uint8_t * data , uint32_t size );
89
+ static error_t open_uhex_blocks (void * state );
90
+ static error_t write_uhex_blocks (void * state , const uint8_t * data , uint32_t size );
91
+ static error_t close_uhex_blocks (void * state );
92
+
93
+ static stream_t stream [] = {
79
94
{detect_bin , open_bin , write_bin , close_bin }, // STREAM_TYPE_BIN
80
95
{detect_hex , open_hex , write_hex , close_hex }, // STREAM_TYPE_HEX
96
+ {detect_uhex_blocks , open_uhex_blocks , write_uhex_blocks , close_uhex_blocks }, // STREAM_TYPE_UHEX_BLOCKS
81
97
};
82
98
COMPILER_ASSERT (ARRAY_SIZE (stream ) == STREAM_TYPE_COUNT );
83
99
// STREAM_TYPE_NONE must not be included in count
@@ -104,6 +120,7 @@ stream_type_t stream_start_identify(const uint8_t *data, uint32_t size)
104
120
105
121
for (i = STREAM_TYPE_START ; i < STREAM_TYPE_COUNT ; i ++ ) {
106
122
if (stream [i ].detect (data , size )) {
123
+ stream_printf ("file_stream start_identify stream=%i\r\n" , i );
107
124
return i ;
108
125
}
109
126
}
@@ -118,12 +135,48 @@ stream_type_t stream_type_from_name(const vfs_filename_t filename)
118
135
if (0 == strncmp ("BIN" , & filename [8 ], 3 )) {
119
136
return STREAM_TYPE_BIN ;
120
137
} else if (0 == strncmp ("HEX" , & filename [8 ], 3 )) {
121
- return STREAM_TYPE_HEX ;
138
+ return STREAM_TYPE_HEX_OR_UHEX ;
122
139
} else {
123
140
return STREAM_TYPE_NONE ;
124
141
}
125
142
}
126
143
144
+ bool stream_compatible (stream_type_t type_left , stream_type_t type_right )
145
+ {
146
+ if (type_left == type_right ) {
147
+ return true;
148
+ }
149
+
150
+ if ((type_left == STREAM_TYPE_HEX_OR_UHEX &&
151
+ (type_right == STREAM_TYPE_HEX || type_right == STREAM_TYPE_UHEX_BLOCKS )) ||
152
+ (type_right == STREAM_TYPE_HEX_OR_UHEX &&
153
+ (type_left == STREAM_TYPE_HEX || type_left == STREAM_TYPE_UHEX_BLOCKS ))) {
154
+ return true;
155
+ }
156
+
157
+ return false;
158
+ }
159
+
160
+ bool stream_self_contained_block (stream_type_t type , const uint8_t * data , uint32_t size )
161
+ {
162
+ switch (type ) {
163
+ case STREAM_TYPE_BIN :
164
+ return false;
165
+
166
+ case STREAM_TYPE_HEX :
167
+ // A hex stream can also be a Universal Hex stream
168
+ return validate_uhex_block (data , size ) ? true : false;
169
+
170
+ case STREAM_TYPE_UHEX_BLOCKS :
171
+ // The Universal Hex stream can be ordered (sectors) or unordered (blocks)
172
+ return validate_uhex_block (data , size ) ? true : false;
173
+
174
+ default :
175
+ util_assert (0 );
176
+ return false;
177
+ }
178
+ }
179
+
127
180
error_t stream_open (stream_type_t stream_type )
128
181
{
129
182
error_t status ;
@@ -147,6 +200,7 @@ error_t stream_open(stream_type_t stream_type)
147
200
current_stream = & stream [stream_type ];
148
201
// Initialize the specified stream
149
202
status = current_stream -> open (& shared_state );
203
+ stream_printf ("file_stream stream_open(type=%d); open ret=%d\r\n" , stream_type , status );
150
204
151
205
if (ERROR_SUCCESS != status ) {
152
206
state = STREAM_STATE_ERROR ;
@@ -170,6 +224,7 @@ error_t stream_write(const uint8_t *data, uint32_t size)
170
224
stream_thread_assert ();
171
225
// Write to stream
172
226
status = current_stream -> write (& shared_state , data , size );
227
+ stream_printf ("file_stream stream_write(size=%d); write ret=%d\r\n" , size , status );
173
228
174
229
if (ERROR_SUCCESS_DONE == status ) {
175
230
state = STREAM_STATE_END ;
@@ -198,6 +253,7 @@ error_t stream_close(void)
198
253
stream_thread_assert ();
199
254
// Close stream
200
255
status = current_stream -> close (& shared_state );
256
+ stream_printf ("file_stream stream_close; close ret=%d\r\n" , status );
201
257
state = STREAM_STATE_CLOSED ;
202
258
return status ;
203
259
}
@@ -289,6 +345,13 @@ static error_t close_bin(void *state)
289
345
290
346
static bool detect_hex (const uint8_t * data , uint32_t size )
291
347
{
348
+ // Both Universal Hex formats will pass the normal hex file validation,
349
+ // but a Universal Hex in block format needs to be processed with the
350
+ // STREAM_TYPE_UHEX_BLOCKS stream.
351
+ // A Universal Hex in segment format can be be processed as a normal hex.
352
+ if (1 == validate_uhex_block (data , size )) {
353
+ return false;
354
+ }
292
355
return 1 == validate_hexfile (data );
293
356
}
294
357
@@ -315,6 +378,7 @@ static error_t write_hex(void *state, const uint8_t *data, uint32_t size)
315
378
while (1 ) {
316
379
// try to decode a block of hex data into bin data
317
380
parse_status = parse_hex_blob (data , size , & block_amt_parsed , hex_state -> bin_buffer , sizeof (hex_state -> bin_buffer ), & bin_start_address , & bin_buf_written );
381
+ stream_printf ("file_stream write_hex; parse_hex_blob ret=%d, bin_buf_written=%d\r\n" , parse_status , bin_buf_written );
318
382
319
383
// the entire block of hex was decoded. This is a simple state
320
384
if (HEX_PARSE_OK == parse_status ) {
@@ -364,3 +428,35 @@ static error_t close_hex(void *state)
364
428
status = flash_decoder_close ();
365
429
return status ;
366
430
}
431
+
432
+ /* Universal Hex, block format, file processing */
433
+ /* https://tech.microbit.org/software/spec-universal-hex/ */
434
+ /* The Universal Hex segment format is processed by the Intel Hex parser. */
435
+ /* This stream is for the Universal Hex block format only. */
436
+
437
+ static bool detect_uhex_blocks (const uint8_t * data , uint32_t size )
438
+ {
439
+ return 1 == validate_uhex_block (data , size );
440
+ }
441
+
442
+ static inline error_t open_uhex_blocks (void * state )
443
+ {
444
+ return open_hex (state );
445
+ }
446
+
447
+ static inline error_t write_uhex_blocks (void * state , const uint8_t * data , uint32_t size )
448
+ {
449
+ error_t status = write_hex (state , data , size );
450
+
451
+ // The block containing the EoF record could arrive at any point
452
+ if (ERROR_SUCCESS_DONE == status || ERROR_SUCCESS == status ) {
453
+ status = ERROR_SUCCESS_DONE_OR_CONTINUE ;
454
+ }
455
+
456
+ return status ;
457
+ }
458
+
459
+ static inline error_t close_uhex_blocks (void * state )
460
+ {
461
+ return close_hex (state );
462
+ }
0 commit comments