2323 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2424 * THE SOFTWARE.
2525 */
26+ #include <string.h>
27+
2628#include "py/obj.h"
2729#include "py/runtime.h"
2830#include "py/reload.h"
31+ #include "py/objstr.h"
2932
3033#include "lib/utils/interrupt_char.h"
3134#include "supervisor/shared/autoreload.h"
@@ -109,6 +112,87 @@ STATIC mp_obj_t supervisor_set_next_stack_limit(mp_obj_t size_obj) {
109112}
110113MP_DEFINE_CONST_FUN_OBJ_1 (supervisor_set_next_stack_limit_obj , supervisor_set_next_stack_limit );
111114
115+ //| def set_next_code_file(filename: Optional[str], *, reload_on_success : bool = False, reload_on_error: bool = False, sticky_on_success: bool = False, sticky_on_error: bool = False, sticky_on_reload: bool = False) -> None:
116+ //| """Set what file to run on the next vm run.
117+ //|
118+ //| When not ``None``, the given ``filename`` is inserted at the front of the usual ['code.py',
119+ //| 'main.py'] search sequence.
120+ //|
121+ //| The optional keyword arguments specify what happens after the specified file has run:
122+ //|
123+ //| ``sticky_on_…`` determine whether the newly set filename and options stay in effect: If
124+ //| True, further runs will continue to run that file (unless it says otherwise by calling
125+ //| ``set_next_code_filename()`` itself). If False, the settings will only affect one run and
126+ //| revert to the standard code.py/main.py afterwards.
127+ //|
128+ //| ``reload_on_…`` determine how to continue: If False, wait in the usual "Code done running.
129+ //| Waiting for reload. / Press any key to enter the REPL. Use CTRL-D to reload." state. If
130+ //| True, reload immediately as if CTRL-D was pressed.
131+ //|
132+ //| ``…_on_success`` take effect when the program runs to completion or calls ``sys.exit()``.
133+ //|
134+ //| ``…_on_error`` take effect when the program exits with an exception, including the
135+ //| KeyboardInterrupt caused by CTRL-C.
136+ //|
137+ //| ``…_on_reload`` take effect when the program is interrupted by files being written to the USB
138+ //| drive (auto-reload) or when it calls ``supervisor.reload()``.
139+ //|
140+ //| These settings are stored in RAM, not in persistent memory, and will therefore only affect
141+ //| soft reloads. Powering off or resetting the device will always revert to standard settings.
142+ //|
143+ //| When called multiple times in the same run, only the last call takes effect, replacing any
144+ //| settings made by previous ones. This is the main use of passing ``None`` as a filename: to
145+ //| reset to the standard search sequence."""
146+ //| ...
147+ //|
148+ STATIC mp_obj_t supervisor_set_next_code_file (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
149+ static const mp_arg_t allowed_args [] = {
150+ { MP_QSTR_filename , MP_ARG_REQUIRED | MP_ARG_OBJ , {.u_rom_obj = mp_const_none } },
151+ { MP_QSTR_reload_on_success , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
152+ { MP_QSTR_reload_on_error , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
153+ { MP_QSTR_sticky_on_success , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
154+ { MP_QSTR_sticky_on_error , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
155+ { MP_QSTR_sticky_on_reload , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
156+ };
157+ struct {
158+ mp_arg_val_t filename ;
159+ mp_arg_val_t reload_on_success ;
160+ mp_arg_val_t reload_on_error ;
161+ mp_arg_val_t sticky_on_success ;
162+ mp_arg_val_t sticky_on_error ;
163+ mp_arg_val_t sticky_on_reload ;
164+ } args ;
165+ mp_arg_parse_all (n_args , pos_args , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , (mp_arg_val_t * )& args );
166+ if (!MP_OBJ_IS_STR_OR_BYTES (args .filename .u_obj ) && args .filename .u_obj != mp_const_none ) {
167+ mp_raise_TypeError (translate ("argument has wrong type" ));
168+ }
169+ if (args .filename .u_obj == mp_const_none ) args .filename .u_obj = mp_const_empty_bytes ;
170+ uint8_t options = 0 ;
171+ if (args .reload_on_success .u_bool ) options |= SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_SUCCESS ;
172+ if (args .reload_on_error .u_bool ) options |= SUPERVISOR_NEXT_CODE_OPT_RELOAD_ON_ERROR ;
173+ if (args .sticky_on_success .u_bool ) options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_SUCCESS ;
174+ if (args .sticky_on_error .u_bool ) options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_ERROR ;
175+ if (args .sticky_on_reload .u_bool ) options |= SUPERVISOR_NEXT_CODE_OPT_STICKY_ON_RELOAD ;
176+ size_t len ;
177+ const char * filename = mp_obj_str_get_data (args .filename .u_obj , & len );
178+ free_memory (next_code_allocation );
179+ if (options != 0 || len != 0 ) {
180+ next_code_allocation = allocate_memory (align32_size (sizeof (next_code_info_t ) + len + 1 ), false, true);
181+ if (next_code_allocation == NULL ) {
182+ m_malloc_fail (sizeof (next_code_info_t ) + len + 1 );
183+ }
184+ next_code_info_t * next_code = (next_code_info_t * )next_code_allocation -> ptr ;
185+ next_code -> options = options | SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET ;
186+ memcpy (& next_code -> filename , filename , len );
187+ next_code -> filename [len ] = '\0' ;
188+ }
189+ else {
190+ next_code_allocation = NULL ;
191+ }
192+ return mp_const_none ;
193+ }
194+ MP_DEFINE_CONST_FUN_OBJ_KW (supervisor_set_next_code_file_obj , 0 , supervisor_set_next_code_file );
195+
112196STATIC const mp_rom_map_elem_t supervisor_module_globals_table [] = {
113197 { MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_supervisor ) },
114198 { MP_OBJ_NEW_QSTR (MP_QSTR_enable_autoreload ), MP_ROM_PTR (& supervisor_enable_autoreload_obj ) },
@@ -117,7 +201,7 @@ STATIC const mp_rom_map_elem_t supervisor_module_globals_table[] = {
117201 { MP_ROM_QSTR (MP_QSTR_runtime ), MP_ROM_PTR (& common_hal_supervisor_runtime_obj ) },
118202 { MP_ROM_QSTR (MP_QSTR_reload ), MP_ROM_PTR (& supervisor_reload_obj ) },
119203 { MP_ROM_QSTR (MP_QSTR_set_next_stack_limit ), MP_ROM_PTR (& supervisor_set_next_stack_limit_obj ) },
120-
204+ { MP_ROM_QSTR ( MP_QSTR_set_next_code_file ), MP_ROM_PTR ( & supervisor_set_next_code_file_obj ) },
121205};
122206
123207STATIC MP_DEFINE_CONST_DICT (supervisor_module_globals , supervisor_module_globals_table );
0 commit comments