-
-
Notifications
You must be signed in to change notification settings - Fork 61
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
Move program download to pbsys #109
Conversation
b924017
to
b963765
Compare
This is done now, in the form below.
Curious to hear if this should perhaps be done differently. int main(int argc, char **argv) {
pbio_error_t err;
pbio_init();
pbsys_init();
// Keep loading and running user programs until shutdown flag is set.
while (!pbsys_status_test(PBIO_PYBRICKS_STATUS_SHUTDOWN)) {
// Run program receive thread until completion. It cancels on shutdown.
static pbsys_main_program_t program;
pbsys_program_load_receive_start();
while ((err = pbsys_program_load_receive_end(&program)) == PBIO_ERROR_AGAIN) {
pbio_do_one_event();
}
// On a successful transfer, run the main application. The application
// must register the appropriate callbacks in sys/user_program so that
// it can be canceled on shutdown.
if (err == PBIO_SUCCESS) {
pbsys_main_application(&program);
}
}
// shutdown stuff ...
Making (program data + heap) constant would be fine, so that growing I wouldn't limit the program data / heap individually more than needed though. Until now, users could balance between large programs and large amounts of user variables. It would be nice to keep it that way. |
b963765
to
d2d1e2a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious to hear if this should perhaps be done differently.
We could combine the start and end functions into a single function and move event loop inside of that function.
Making (program data + heap) constant would be fine, so that growing bss won't change anything for users.
Agreed. User program binary + MicroPython heap is what I meant by "heap". Maybe a better/more generic short name for the combined memory area is "user RAM"?
Done. Some fixes are pushed as a separate commit to make it easier to review what changed. I'll squash it later. |
I have now cleaned it up as follows:
I don't have strong opinion on this one, so maybe we could defer it to a separate issue to expedite this PR? For what it's worth, I think it's OK to use what is available rather than disabling an arbitrary amount of RAM, especially on the smaller hubs. Keeping an eye on bss could be a good way to encourage ourselves to make it smaller like we've done with build size. We've discussed making some infrequently used objects dynamic (e.g. the drivebases). |
9180ce4
to
aabdd5f
Compare
This makes it clearer which is main and which is the application being run on top.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix #526 by avoiding a full pbsys reset when dropping from a user program into the REPL. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix #526 by avoiding a full pbsys reset when dropping from a user program into the REPL. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
aabdd5f
to
9132488
Compare
Just like starting and stopping the program, (down)loading a program is a task for pbsys. Using a protothread, the download procedure is now much easier to follow. Program data is preserved, so that it can be restarted with the button. This paves the way for supporting persistent programs on all hubs. By cleaning up the way timeouts work, the user is now less likely to see a message about an incompatible mpy file when accidentally typing something in the I/O pane of Pybricks Code. This also drops the shutdown longjmp. The download thread is cancellable, and the user program was already cancellable, so we don't need this anymore. This simplifies the main code and it saves about 500 bytes on Move Hub, which turns this commit into a slight decrease in code size.
9132488
to
b218d76
Compare
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109, the main application (MicroPython) ran in an infinite loop (goto), so special hooks were needed to reset and init pbsys prior to running a new program. Now, MicroPython runs once before yielding back to pbsys, so these hooks are no longer needed. Instead, the application can provide a program stop and stdin event handler alongside the program runner. This makes the code easier to follow and it makes it possible to fix pybricks/support#526 by avoiding a full pbsys reset when dropping from a user program into the REPL. This also fixes an issue introduced in #109 where the program would not be stopped on shutdown if the stop button was disabled. The only code remaining in pbsys/user_program is about stopping programs, so this is renamed to program_stop, to be consistent with program_load.
Before #109 and related commits, the user script size was limited to about 25% of RAM. The limit on storage was not explicitly defined. With the aforementioned updates, the amount of space is explicitly defined and constrained by the size of the user flash. This commit updates the size of those regions to make them the same or larger than the previous program size limit limit, to ensure there are no regressions in the user experience. The size could be made a bit larger, but we'll keep the values on the lower end so we'll still have room for the firmware to grow. See pybricks/support#713 for an overview and the full consideration.
Before #109 and related commits, the user script size was limited to about 25% of RAM. The limit on storage was not explicitly defined. With the aforementioned updates, the amount of space is explicitly defined and constrained by the size of the user flash. This commit updates the size of those regions to make them the same or larger than the previous program size limit limit, to ensure there are no regressions in the user experience. The size could be made a bit larger, but we'll keep the values on the lower end so we'll still have room for the firmware to grow. See pybricks/support#713 for an overview and the full consideration. For powered up hubs, this means that the user data partially overlaps with the region scanned by the bootloader to compute the checksum. This commit adds a checksum complement to the user data map to compensate.
Before #109 and related commits, the user script size was limited to about 25% of RAM. The limit on storage was not explicitly defined. With the aforementioned updates, the amount of space is explicitly defined and constrained by the size of the user flash. This commit updates the size of those regions to make them the same or larger than the previous program size limit limit, to ensure there are no regressions in the user experience. The size could be made a bit larger, but we'll keep the values on the lower end so we'll still have room for the firmware to grow. See pybricks/support#713 for an overview and the full consideration. For powered up hubs, this means that the user data partially overlaps with the region scanned by the bootloader to compute the checksum. This commit adds a checksum complement to the user data map to compensate.
Before #109 and related commits, the user script size was limited to about 25% of RAM. The limit on storage was not explicitly defined. With the aforementioned updates, the amount of space is explicitly defined and constrained by the size of the user flash. This commit updates the size of those regions to make them the same or larger than the previous program size limit limit, to ensure there are no regressions in the user experience. The size could be made a bit larger, but we'll keep the values on the lower end so we'll still have room for the firmware to grow. See pybricks/support#713 for an overview and the full consideration. For powered up hubs, this means that the user data partially overlaps with the region scanned by the bootloader to compute the checksum. This commit adds a checksum complement to the user data map to compensate.
#106 is too big to review in one go, so I'm splitting it up in several smaller pull requests. I'm running out of time for today, so I'll mark it as a draft for now. I'd still need to review some of the comments on this part from #106 as well.
pbsys: Move program download out of MicroPython.
Just like starting and stopping the program, (down)loading a program is
a task for pbsys. Using a protothread, the download procedure is now
much easier to follow.
Program data is preserved, so that it can be restarted with the button.
This paves the way for supporting persistent programs on all hubs.
By cleaning up the way timeouts work, the user is now less likely to see
a message about an incompatible mpy file when accidentally typing
something in the I/O pane of Pybricks Code.
This also drops the shutdown longjmp. The download thread is cancellable,
and the user program was already cancellable, so we don't need this anymore.
This simplifies the main code and it saves about 500 bytes on Move Hub,
which turns this commit into a slight decrease in code size.
This PR aims to keep almost everything working as it did before. Since this contains only a portion of #106, there are two main regressions that will be addressed in future work: