3030#include "compiler.h"
3131#include "validation.h"
3232
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+
3343typedef enum {
3444 STREAM_STATE_CLOSED ,
3545 STREAM_STATE_OPEN ,
@@ -75,9 +85,15 @@ static error_t open_hex(void *state);
7585static error_t write_hex (void * state , const uint8_t * data , uint32_t size );
7686static error_t close_hex (void * state );
7787
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 [] = {
7994 {detect_bin , open_bin , write_bin , close_bin }, // STREAM_TYPE_BIN
8095 {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
8197};
8298COMPILER_ASSERT (ARRAY_SIZE (stream ) == STREAM_TYPE_COUNT );
8399// 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)
104120
105121 for (i = STREAM_TYPE_START ; i < STREAM_TYPE_COUNT ; i ++ ) {
106122 if (stream [i ].detect (data , size )) {
123+ stream_printf ("file_stream start_identify stream=%i\r\n" , i );
107124 return i ;
108125 }
109126 }
@@ -118,12 +135,48 @@ stream_type_t stream_type_from_name(const vfs_filename_t filename)
118135 if (0 == strncmp ("BIN" , & filename [8 ], 3 )) {
119136 return STREAM_TYPE_BIN ;
120137 } else if (0 == strncmp ("HEX" , & filename [8 ], 3 )) {
121- return STREAM_TYPE_HEX ;
138+ return STREAM_TYPE_HEX_OR_UHEX ;
122139 } else {
123140 return STREAM_TYPE_NONE ;
124141 }
125142}
126143
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+
127180error_t stream_open (stream_type_t stream_type )
128181{
129182 error_t status ;
@@ -147,6 +200,7 @@ error_t stream_open(stream_type_t stream_type)
147200 current_stream = & stream [stream_type ];
148201 // Initialize the specified stream
149202 status = current_stream -> open (& shared_state );
203+ stream_printf ("file_stream stream_open(type=%d); open ret=%d\r\n" , stream_type , status );
150204
151205 if (ERROR_SUCCESS != status ) {
152206 state = STREAM_STATE_ERROR ;
@@ -170,6 +224,7 @@ error_t stream_write(const uint8_t *data, uint32_t size)
170224 stream_thread_assert ();
171225 // Write to stream
172226 status = current_stream -> write (& shared_state , data , size );
227+ stream_printf ("file_stream stream_write(size=%d); write ret=%d\r\n" , size , status );
173228
174229 if (ERROR_SUCCESS_DONE == status ) {
175230 state = STREAM_STATE_END ;
@@ -198,6 +253,7 @@ error_t stream_close(void)
198253 stream_thread_assert ();
199254 // Close stream
200255 status = current_stream -> close (& shared_state );
256+ stream_printf ("file_stream stream_close; close ret=%d\r\n" , status );
201257 state = STREAM_STATE_CLOSED ;
202258 return status ;
203259}
@@ -289,6 +345,13 @@ static error_t close_bin(void *state)
289345
290346static bool detect_hex (const uint8_t * data , uint32_t size )
291347{
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+ }
292355 return 1 == validate_hexfile (data );
293356}
294357
@@ -315,6 +378,7 @@ static error_t write_hex(void *state, const uint8_t *data, uint32_t size)
315378 while (1 ) {
316379 // try to decode a block of hex data into bin data
317380 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 );
318382
319383 // the entire block of hex was decoded. This is a simple state
320384 if (HEX_PARSE_OK == parse_status ) {
@@ -364,3 +428,35 @@ static error_t close_hex(void *state)
364428 status = flash_decoder_close ();
365429 return status ;
366430}
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