-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Change main filename to run next #1084
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
My similar discussion: https://forums.adafruit.com/viewtopic.php?f=60&t=150016 (#737 gets mentioned in that). |
Mentioned this awhile ago on Discord, but thought I'd chime in here. I'm working on a tutorial and have a bunch of example scripts all stored on the CIRCUITPY drive. Switching between them requires manually renaming or copying files to code.py/main.py. This gets tedious so I wrote a menu script that lists the available other scripts on the CIRCUITPY drive. Selecting one runs it using Import. This works, in general. The problem is that larger scripts can overflow the heap when imported even though they work fine on their own. There might be a more general solution, but for me, it would be great to have something like sys.exit('next.py') that would restart the vm with the named script. No need for this to disrupt any existing behavior. e.g. ctrl-D from the REPL and sys.exit() could still load code.py/main.py by default. The way this would work for my case is that the menu would be code.py/main.py and use sys.exit('next.py') to run the chosen script. All the example scripts would act normally, you'd use ctrl-C,ctrl-D to restart the menu, no special hooks to get back to the menu. Of course, if you wanted to chain several scripts, each one could use sys.exit('next.py'). |
I have exactly the same use case for my game consoles. |
We would not enhance |
Adding it to supervisor.reload() would be perfect. |
Note that the hardest part of this is storing the filename because the heap gets reinitialized before running the file. |
Good point. Is this same issue handled in |
Ya, it is similar but stack size is a fixed size so it's easy to just statically allocate it. We could simply have a char* array with a limit to start. If folks hit the limit often we could either increase it or make the allocation dynamic. |
Ah ha. I see the issue. Picking a good limit is key (though, no matter what you pick, someone will have a use case for more :) ). |
If the heap memory is not touched when the VM shuts down, then I think the following would work. It relies on being to able to use the stale data in the old heap.
|
I just realized there is one more piece of the puzzle missing — after the code finishes running, it would be best if the device restarted again, with the default |
@deshipu If each of the alternate programs did a |
Yes, ideally it would be the same kind of programs that you normally run as Right now, when we run the programs by importing them, this is not a problem, as the control returns to the menu program after the import. But if we switched to this new way, we would probably want some way of resetting the device afterwards. Granted, most of those programs will be infinite loops, and the users will simply press reset to get back to the menu. |
[started to reply and then saw your edited reply] It would be possible to set a flag that says to reload on exit, either via |
Also, you probably don't want to restart if there was an error, only if it was a normal end of the program. I might be overthinking this. |
I don't think you are overcomplicating it. I think it is complicated. Another aspect is what file should be run on reload. We don't know what file has been changed when the FS is written. My guess is that we want the currently running file reloaded (and therefore we need to preserve the filename past start up into the new heap.) A related use to this would be doing OTA file updates over wifi. We'll want a known good code.py to allow for writing new files even when the loaded file crashes. |
So, I might be misunderstanding, but are you suggesting that |
I think we'll want a separate function rather than putting it in Then we can have multiple kwargs for different reload reasons or separate functions. I imagine you want: reload, exception, safe mode and completion as reasons. |
This sounds like a good general approach. As I envision my current use case, I just need to reload with a specific file without affecting any of the defaults. Though, with more options, my use case might evolve. |
After some thought, I think that just setting the file name for the next run would solve 90% of my case as well — the users always can reset the device to get back to the menu, and an "exit the game" option can be provided by the library, which would then do the correct thing. |
My loader for the OSHWA 2020 badge would appreciate this functionality. I assume that since the proposed mechanism is simply designating which file to run, there would be no need to make sure pins are released/de-initialized? As you suggested previously @tannewt , this will mean we (I ) will need to handle the "don't reinit already initialized stuff" case for libraries. Since the libraries will need to know the 'commanded reload' vs 'default start' state, it would/could be exposed by |
@siddacious I was thinking it would be a full reload that would reset everything. What is an example of things you don't want to reset? |
For my use case, I think a full reload/reset would be optimal. |
@tannewt I was referring to our previous convo where you suggested thinking about how sensors libs should handle a restart, though in that context I think you were talking about waking up from a sleep that was entered for power saving purposes so I may have crossed the streams. It sounds like this is a related but different issue as there are certainly use cases where you would want a complete reset, sensors included ie: running an app that wants different configurations for a sensor. |
One thing that just occurred to me is that, if possible, it might be useful to support |
@robertgallup I am not sure what you mean. Do you mean you can't have code.mpy? If something.py and something.mpy both exist, then something.py will take precedence. |
This is fine for a prototype here but I wouldn't want to merge it in the "maximally configurable" state because removing APIs is much harder than adding more. For the PR, please do the limited API needed for the game case.
We only need to worry about 6.0.0 if we want to remove/rename APIs. Adding APIs can be done after 6.0.0. (Removing/renaming would have to wait for 7.0.0) I think the PR is blocked on getting an adequate but minimal API set, implemented and documented. |
Agreed. The “maximally configurable” state was never meant to be merged as is, it’s just a prototype for people to play with to figure out what we need. I was making progress on the “retrieve last exception” front when the supervisor heap bug distracted me, so as far as I’m concerned, we’re closing in on that. |
I’m unfamiliar with USB and don’t know what a descriptor is, so I can’t comment in detail, but one thing to note is that the more pieces of information we save using this approach, the more carefully we need to think about their interaction. If one needs to be cleared and another one is newly set and a third one needs to be preserved, and not all of this is known at the same time, in what order do we do what so we don't leave holes and waste memory? I‘m actually working on planning that through between “next code“ and “traceback” right now. |
I think I have a generic solution that will work for any number of items (as long as they all fit on the stack at once). Implementing and testing it will probably take me a few days though. |
I can imagine that the memory exceptions are going to be particularly difficult to handle. especially when they happen with a small allocation and there is little memory left to process it. |
@cwalther Sorry to distract on this. A USB descriptor defines what type of a USB device something is such as keyboard vs audio. It's similar to this because we'd construct it in |
OK, just so I get a rough idea to keep in the back of my mind while I implement the generic system, to make sure it will be ready for it:
|
I think it needs to live forever because the host could ask for it at any time.
If I had to guess it's 500 - 1000.
I would just have them raise an exception. But maybe it'd be ok if the USB is unconnected. |
In other news, taking a closer look at |
Quick status update: Iteration 3 of the generic movable allocation system, built on top of the existing supervisor heap, works (as far as tested with the terminal tilegrid, more thorough tests still to be done), but adds a fair bit of code. Now working on iteration 4 to see if redesigning the supervisor heap to intrinsically support movable allocations will achieve the same goals with less code. |
Sounds good @cwalther. Don't lose sight of how much added code is too much. Running the CI will build all the boards and tell you if any are out of space. |
I am wondering how does this interact with deep-sleep. |
In the current implementation, no, it’s all stored in RAM, which is powered down during deep sleep. Moving it to any kind of non-volatile memory (I’m not familiar with what the ESP32-S2 offers in that regard) would be a new requirement. There will probably be other things to discuss though regarding interactions with deep sleep, as I discovered today while fixing merge conflicts. |
Resolved (as described originally) by #3454. Deep sleep same-file restart support is not in that PR but should be added soon. |
@deshipu or anyone interested in sample code: Now that the prerequisites ( The error dialog part is still mostly mockup. Here is the program I’ve been testing it with. It‘s currently hampered by #5057. |
Add the ability to set the next main filename before triggering a reload. This can be used to switch between games on a system or between memory heavy animation scripts. https://forums.adafruit.com/viewtopic.php?f=60&t=139041
The text was updated successfully, but these errors were encountered: